v2: ID verification by state, 15 photos/5 albums, 20 quick replies, logo, mobile polish
This commit is contained in:
@@ -46,6 +46,9 @@ function mapDbProfile(row: Record<string, unknown>): Profile {
|
||||
lat: loc?.coordinates?.[1] ?? null,
|
||||
lng: loc?.coordinates?.[0] ?? null,
|
||||
city: (row.city as string) ?? null,
|
||||
state: (row.state as string) ?? null,
|
||||
id_verified: (row.id_verified as boolean) ?? false,
|
||||
id_verified_at: (row.id_verified_at as string) ?? null,
|
||||
vanilla_mode: (row.vanilla_mode as boolean) ?? false,
|
||||
created_at: (row.created_at as string) ?? new Date().toISOString(),
|
||||
};
|
||||
@@ -139,6 +142,9 @@ export function AuthProvider({ children }: { children: ReactNode }) {
|
||||
if (data.is_anonymous !== undefined) payload.is_anonymous = data.is_anonymous;
|
||||
if (data.status !== undefined) payload.status = data.status;
|
||||
if (data.city !== undefined) payload.city = data.city;
|
||||
if (data.state !== undefined) payload.state = data.state;
|
||||
if (data.id_verified !== undefined) payload.id_verified = data.id_verified;
|
||||
if (data.id_verified_at !== undefined) payload.id_verified_at = data.id_verified_at;
|
||||
const { error } = await supabase
|
||||
.from("profiles")
|
||||
.update(payload)
|
||||
|
||||
180
src/lib/canned-messages-store.ts
Normal file
180
src/lib/canned-messages-store.ts
Normal file
@@ -0,0 +1,180 @@
|
||||
import { createClient } from "@/lib/supabase/client";
|
||||
import { MAX_CANNED_MESSAGES, MAX_CANNED_MESSAGE_LENGTH } from "@/lib/limits";
|
||||
|
||||
export interface CannedMessage {
|
||||
id: string;
|
||||
title: string;
|
||||
content: string;
|
||||
sort_order: number;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
const LS_KEY = "eg_canned_messages";
|
||||
|
||||
export const DEFAULT_CANNED_MESSAGES: Omit<CannedMessage, "id" | "created_at" | "sort_order">[] = [
|
||||
{
|
||||
title: "Address",
|
||||
content: "I'm at 123 Example St, Wilton Manors. Buzzer #4.",
|
||||
},
|
||||
{
|
||||
title: "Directions",
|
||||
content: "Park in the back lot off NE 6th Ave. Walk through the gate on the left.",
|
||||
},
|
||||
{
|
||||
title: "Hosting now",
|
||||
content: "Hosting now — clean only, door unlocked. Text when you're outside.",
|
||||
},
|
||||
{
|
||||
title: "On my way",
|
||||
content: "On my way — ETA 10 min. Save my number.",
|
||||
},
|
||||
];
|
||||
|
||||
function uid() {
|
||||
return crypto.randomUUID();
|
||||
}
|
||||
|
||||
function readLocal(): CannedMessage[] {
|
||||
if (typeof window === "undefined") return [];
|
||||
try {
|
||||
const raw = localStorage.getItem(LS_KEY);
|
||||
if (raw) return JSON.parse(raw) as CannedMessage[];
|
||||
const seeded = DEFAULT_CANNED_MESSAGES.map((m, i) => ({
|
||||
...m,
|
||||
id: uid(),
|
||||
sort_order: i,
|
||||
created_at: new Date().toISOString(),
|
||||
}));
|
||||
localStorage.setItem(LS_KEY, JSON.stringify(seeded));
|
||||
return seeded;
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
function writeLocal(messages: CannedMessage[]) {
|
||||
localStorage.setItem(LS_KEY, JSON.stringify(messages));
|
||||
}
|
||||
|
||||
export async function loadCannedMessages(
|
||||
userId?: string | null
|
||||
): Promise<CannedMessage[]> {
|
||||
if (!userId) return readLocal();
|
||||
|
||||
const supabase = createClient();
|
||||
const { data, error } = await supabase
|
||||
.from("canned_messages")
|
||||
.select("*")
|
||||
.eq("user_id", userId)
|
||||
.order("sort_order");
|
||||
|
||||
if (error || !data?.length) {
|
||||
const local = readLocal();
|
||||
if (local.length && userId) {
|
||||
for (const msg of local) {
|
||||
await supabase.from("canned_messages").insert({
|
||||
user_id: userId,
|
||||
title: msg.title,
|
||||
content: msg.content,
|
||||
sort_order: msg.sort_order,
|
||||
});
|
||||
}
|
||||
const { data: synced } = await supabase
|
||||
.from("canned_messages")
|
||||
.select("*")
|
||||
.eq("user_id", userId)
|
||||
.order("sort_order");
|
||||
return (synced as CannedMessage[]) ?? local;
|
||||
}
|
||||
return local;
|
||||
}
|
||||
|
||||
return data as CannedMessage[];
|
||||
}
|
||||
|
||||
export async function saveCannedMessage(
|
||||
msg: { id?: string; title: string; content: string },
|
||||
userId?: string | null
|
||||
): Promise<{ message?: CannedMessage; error?: string }> {
|
||||
const title = msg.title.trim().slice(0, 40);
|
||||
const content = msg.content.trim().slice(0, MAX_CANNED_MESSAGE_LENGTH);
|
||||
if (!title || !content) return { error: "Title and message required." };
|
||||
|
||||
if (!userId) {
|
||||
const all = readLocal();
|
||||
if (!msg.id && all.length >= MAX_CANNED_MESSAGES) {
|
||||
return { error: `Maximum ${MAX_CANNED_MESSAGES} canned messages.` };
|
||||
}
|
||||
if (msg.id) {
|
||||
const updated = all.map((m) =>
|
||||
m.id === msg.id ? { ...m, title, content } : m
|
||||
);
|
||||
writeLocal(updated);
|
||||
return { message: updated.find((m) => m.id === msg.id) };
|
||||
}
|
||||
const newMsg: CannedMessage = {
|
||||
id: uid(),
|
||||
title,
|
||||
content,
|
||||
sort_order: all.length,
|
||||
created_at: new Date().toISOString(),
|
||||
};
|
||||
writeLocal([...all, newMsg]);
|
||||
return { message: newMsg };
|
||||
}
|
||||
|
||||
const supabase = createClient();
|
||||
if (msg.id) {
|
||||
const { data, error } = await supabase
|
||||
.from("canned_messages")
|
||||
.update({ title, content })
|
||||
.eq("id", msg.id)
|
||||
.eq("user_id", userId)
|
||||
.select()
|
||||
.single();
|
||||
if (error) return { error: error.message };
|
||||
return { message: data as CannedMessage };
|
||||
}
|
||||
|
||||
const { count } = await supabase
|
||||
.from("canned_messages")
|
||||
.select("*", { count: "exact", head: true })
|
||||
.eq("user_id", userId);
|
||||
|
||||
if ((count ?? 0) >= MAX_CANNED_MESSAGES) {
|
||||
return { error: `Maximum ${MAX_CANNED_MESSAGES} canned messages.` };
|
||||
}
|
||||
|
||||
const { data, error } = await supabase
|
||||
.from("canned_messages")
|
||||
.insert({
|
||||
user_id: userId,
|
||||
title,
|
||||
content,
|
||||
sort_order: count ?? 0,
|
||||
})
|
||||
.select()
|
||||
.single();
|
||||
|
||||
if (error) return { error: error.message };
|
||||
return { message: data as CannedMessage };
|
||||
}
|
||||
|
||||
export async function deleteCannedMessage(
|
||||
id: string,
|
||||
userId?: string | null
|
||||
): Promise<{ error?: string }> {
|
||||
if (!userId) {
|
||||
writeLocal(readLocal().filter((m) => m.id !== id));
|
||||
return {};
|
||||
}
|
||||
|
||||
const supabase = createClient();
|
||||
const { error } = await supabase
|
||||
.from("canned_messages")
|
||||
.delete()
|
||||
.eq("id", id)
|
||||
.eq("user_id", userId);
|
||||
|
||||
return error ? { error: error.message } : {};
|
||||
}
|
||||
251
src/lib/gallery-store.ts
Normal file
251
src/lib/gallery-store.ts
Normal file
@@ -0,0 +1,251 @@
|
||||
import { createClient } from "@/lib/supabase/client";
|
||||
import {
|
||||
MAX_ALBUMS_PER_USER,
|
||||
MAX_PHOTOS_PER_USER,
|
||||
MAX_ALBUM_NAME_LENGTH,
|
||||
} from "@/lib/limits";
|
||||
|
||||
export interface GalleryAlbum {
|
||||
id: string;
|
||||
name: string;
|
||||
is_default: boolean;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
export interface GalleryPhoto {
|
||||
id: string;
|
||||
album_id: string | null;
|
||||
url: string;
|
||||
is_explicit: boolean;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
const LS_ALBUMS = "eg_gallery_albums";
|
||||
const LS_PHOTOS = "eg_gallery_photos";
|
||||
|
||||
function uid() {
|
||||
return crypto.randomUUID();
|
||||
}
|
||||
|
||||
function readLocal<T>(key: string, fallback: T): T {
|
||||
if (typeof window === "undefined") return fallback;
|
||||
try {
|
||||
const raw = localStorage.getItem(key);
|
||||
return raw ? (JSON.parse(raw) as T) : fallback;
|
||||
} catch {
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
|
||||
function writeLocal<T>(key: string, data: T) {
|
||||
localStorage.setItem(key, JSON.stringify(data));
|
||||
}
|
||||
|
||||
export function getDefaultAlbums(): GalleryAlbum[] {
|
||||
return [
|
||||
{
|
||||
id: "main",
|
||||
name: "Main",
|
||||
is_default: true,
|
||||
created_at: new Date().toISOString(),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
export async function loadGallery(userId?: string | null): Promise<{
|
||||
albums: GalleryAlbum[];
|
||||
photos: GalleryPhoto[];
|
||||
}> {
|
||||
if (!userId) {
|
||||
const albums = readLocal<GalleryAlbum[]>(LS_ALBUMS, getDefaultAlbums());
|
||||
const photos = readLocal<GalleryPhoto[]>(LS_PHOTOS, []);
|
||||
return { albums: albums.length ? albums : getDefaultAlbums(), photos };
|
||||
}
|
||||
|
||||
const supabase = createClient();
|
||||
const [{ data: albums }, { data: photos }] = await Promise.all([
|
||||
supabase
|
||||
.from("gallery_albums")
|
||||
.select("*")
|
||||
.eq("user_id", userId)
|
||||
.order("created_at"),
|
||||
supabase
|
||||
.from("gallery_photos")
|
||||
.select("*")
|
||||
.eq("user_id", userId)
|
||||
.order("created_at"),
|
||||
]);
|
||||
|
||||
return {
|
||||
albums: (albums as GalleryAlbum[])?.length
|
||||
? (albums as GalleryAlbum[])
|
||||
: getDefaultAlbums(),
|
||||
photos: (photos as GalleryPhoto[]) ?? [],
|
||||
};
|
||||
}
|
||||
|
||||
export async function createAlbum(
|
||||
name: string,
|
||||
userId?: string | null
|
||||
): Promise<{ album?: GalleryAlbum; error?: string }> {
|
||||
const trimmed = name.trim().slice(0, MAX_ALBUM_NAME_LENGTH);
|
||||
if (!trimmed) return { error: "Album name required." };
|
||||
|
||||
if (!userId) {
|
||||
const albums = readLocal<GalleryAlbum[]>(LS_ALBUMS, getDefaultAlbums());
|
||||
if (albums.length >= MAX_ALBUMS_PER_USER) {
|
||||
return { error: `Maximum ${MAX_ALBUMS_PER_USER} albums allowed.` };
|
||||
}
|
||||
const album: GalleryAlbum = {
|
||||
id: uid(),
|
||||
name: trimmed,
|
||||
is_default: false,
|
||||
created_at: new Date().toISOString(),
|
||||
};
|
||||
writeLocal(LS_ALBUMS, [...albums, album]);
|
||||
return { album };
|
||||
}
|
||||
|
||||
const supabase = createClient();
|
||||
const { count } = await supabase
|
||||
.from("gallery_albums")
|
||||
.select("*", { count: "exact", head: true })
|
||||
.eq("user_id", userId);
|
||||
|
||||
if ((count ?? 0) >= MAX_ALBUMS_PER_USER) {
|
||||
return { error: `Maximum ${MAX_ALBUMS_PER_USER} albums allowed.` };
|
||||
}
|
||||
|
||||
const { data, error } = await supabase
|
||||
.from("gallery_albums")
|
||||
.insert({ user_id: userId, name: trimmed })
|
||||
.select()
|
||||
.single();
|
||||
|
||||
if (error) return { error: error.message };
|
||||
return { album: data as GalleryAlbum };
|
||||
}
|
||||
|
||||
export async function addPhoto(
|
||||
file: File,
|
||||
albumId: string | null,
|
||||
userId?: string | null
|
||||
): Promise<{ photo?: GalleryPhoto; error?: string }> {
|
||||
if (!userId) {
|
||||
const photos = readLocal<GalleryPhoto[]>(LS_PHOTOS, []);
|
||||
if (photos.length >= MAX_PHOTOS_PER_USER) {
|
||||
return { error: `Maximum ${MAX_PHOTOS_PER_USER} photos allowed.` };
|
||||
}
|
||||
const url = await fileToDataUrl(file);
|
||||
const photo: GalleryPhoto = {
|
||||
id: uid(),
|
||||
album_id: albumId,
|
||||
url,
|
||||
is_explicit: true,
|
||||
created_at: new Date().toISOString(),
|
||||
};
|
||||
writeLocal(LS_PHOTOS, [...photos, photo]);
|
||||
return { photo };
|
||||
}
|
||||
|
||||
const supabase = createClient();
|
||||
const { count } = await supabase
|
||||
.from("gallery_photos")
|
||||
.select("*", { count: "exact", head: true })
|
||||
.eq("user_id", userId);
|
||||
|
||||
if ((count ?? 0) >= MAX_PHOTOS_PER_USER) {
|
||||
return { error: `Maximum ${MAX_PHOTOS_PER_USER} photos allowed.` };
|
||||
}
|
||||
|
||||
const ext = file.name.split(".").pop() || "jpg";
|
||||
const path = `${userId}/${uid()}.${ext}`;
|
||||
|
||||
const { error: uploadError } = await supabase.storage
|
||||
.from("gallery")
|
||||
.upload(path, file, { upsert: false });
|
||||
|
||||
if (uploadError) return { error: uploadError.message };
|
||||
|
||||
const {
|
||||
data: { publicUrl },
|
||||
} = supabase.storage.from("gallery").getPublicUrl(path);
|
||||
|
||||
const { data, error } = await supabase
|
||||
.from("gallery_photos")
|
||||
.insert({
|
||||
user_id: userId,
|
||||
album_id: albumId === "main" ? null : albumId,
|
||||
url: publicUrl,
|
||||
is_explicit: true,
|
||||
})
|
||||
.select()
|
||||
.single();
|
||||
|
||||
if (error) return { error: error.message };
|
||||
return { photo: data as GalleryPhoto };
|
||||
}
|
||||
|
||||
export async function deletePhoto(
|
||||
photoId: string,
|
||||
userId?: string | null
|
||||
): Promise<{ error?: string }> {
|
||||
if (!userId) {
|
||||
const photos = readLocal<GalleryPhoto[]>(LS_PHOTOS, []);
|
||||
writeLocal(
|
||||
LS_PHOTOS,
|
||||
photos.filter((p) => p.id !== photoId)
|
||||
);
|
||||
return {};
|
||||
}
|
||||
|
||||
const supabase = createClient();
|
||||
const { error } = await supabase
|
||||
.from("gallery_photos")
|
||||
.delete()
|
||||
.eq("id", photoId)
|
||||
.eq("user_id", userId);
|
||||
|
||||
return error ? { error: error.message } : {};
|
||||
}
|
||||
|
||||
export async function deleteAlbum(
|
||||
albumId: string,
|
||||
userId?: string | null
|
||||
): Promise<{ error?: string }> {
|
||||
if (albumId === "main") return { error: "Cannot delete the Main album." };
|
||||
|
||||
if (!userId) {
|
||||
const albums = readLocal<GalleryAlbum[]>(LS_ALBUMS, getDefaultAlbums());
|
||||
const photos = readLocal<GalleryPhoto[]>(LS_PHOTOS, []);
|
||||
writeLocal(
|
||||
LS_ALBUMS,
|
||||
albums.filter((a) => a.id !== albumId)
|
||||
);
|
||||
writeLocal(
|
||||
LS_PHOTOS,
|
||||
photos.map((p) =>
|
||||
p.album_id === albumId ? { ...p, album_id: "main" } : p
|
||||
)
|
||||
);
|
||||
return {};
|
||||
}
|
||||
|
||||
const supabase = createClient();
|
||||
const { error } = await supabase
|
||||
.from("gallery_albums")
|
||||
.delete()
|
||||
.eq("id", albumId)
|
||||
.eq("user_id", userId);
|
||||
|
||||
return error ? { error: error.message } : {};
|
||||
}
|
||||
|
||||
function fileToDataUrl(file: File): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.onload = () => resolve(reader.result as string);
|
||||
reader.onerror = reject;
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
}
|
||||
124
src/lib/id-verification.ts
Normal file
124
src/lib/id-verification.ts
Normal file
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* US states requiring government-ID age verification to view explicit/nude content.
|
||||
* Updated for 2025–2026 age-verification statutes (HB/SB laws).
|
||||
*/
|
||||
export const ID_VERIFICATION_STATES = [
|
||||
"AL", // Alabama
|
||||
"AR", // Arkansas
|
||||
"AZ", // Arizona
|
||||
"FL", // Florida
|
||||
"GA", // Georgia
|
||||
"ID", // Idaho
|
||||
"IN", // Indiana
|
||||
"KS", // Kansas
|
||||
"KY", // Kentucky
|
||||
"LA", // Louisiana
|
||||
"MS", // Mississippi
|
||||
"MT", // Montana
|
||||
"NC", // North Carolina
|
||||
"ND", // North Dakota
|
||||
"NE", // Nebraska
|
||||
"OK", // Oklahoma
|
||||
"SC", // South Carolina
|
||||
"SD", // South Dakota
|
||||
"TN", // Tennessee
|
||||
"TX", // Texas
|
||||
"UT", // Utah
|
||||
"VA", // Virginia
|
||||
"WV", // West Virginia
|
||||
"WY", // Wyoming
|
||||
] as const;
|
||||
|
||||
export type IdVerificationState = (typeof ID_VERIFICATION_STATES)[number];
|
||||
|
||||
export const US_STATES: { code: string; name: string }[] = [
|
||||
{ code: "AL", name: "Alabama" },
|
||||
{ code: "AK", name: "Alaska" },
|
||||
{ code: "AZ", name: "Arizona" },
|
||||
{ code: "AR", name: "Arkansas" },
|
||||
{ code: "CA", name: "California" },
|
||||
{ code: "CO", name: "Colorado" },
|
||||
{ code: "CT", name: "Connecticut" },
|
||||
{ code: "DE", name: "Delaware" },
|
||||
{ code: "FL", name: "Florida" },
|
||||
{ code: "GA", name: "Georgia" },
|
||||
{ code: "HI", name: "Hawaii" },
|
||||
{ code: "ID", name: "Idaho" },
|
||||
{ code: "IL", name: "Illinois" },
|
||||
{ code: "IN", name: "Indiana" },
|
||||
{ code: "IA", name: "Iowa" },
|
||||
{ code: "KS", name: "Kansas" },
|
||||
{ code: "KY", name: "Kentucky" },
|
||||
{ code: "LA", name: "Louisiana" },
|
||||
{ code: "ME", name: "Maine" },
|
||||
{ code: "MD", name: "Maryland" },
|
||||
{ code: "MA", name: "Massachusetts" },
|
||||
{ code: "MI", name: "Michigan" },
|
||||
{ code: "MN", name: "Minnesota" },
|
||||
{ code: "MS", name: "Mississippi" },
|
||||
{ code: "MO", name: "Missouri" },
|
||||
{ code: "MT", name: "Montana" },
|
||||
{ code: "NE", name: "Nebraska" },
|
||||
{ code: "NV", name: "Nevada" },
|
||||
{ code: "NH", name: "New Hampshire" },
|
||||
{ code: "NJ", name: "New Jersey" },
|
||||
{ code: "NM", name: "New Mexico" },
|
||||
{ code: "NY", name: "New York" },
|
||||
{ code: "NC", name: "North Carolina" },
|
||||
{ code: "ND", name: "North Dakota" },
|
||||
{ code: "OH", name: "Ohio" },
|
||||
{ code: "OK", name: "Oklahoma" },
|
||||
{ code: "OR", name: "Oregon" },
|
||||
{ code: "PA", name: "Pennsylvania" },
|
||||
{ code: "RI", name: "Rhode Island" },
|
||||
{ code: "SC", name: "South Carolina" },
|
||||
{ code: "SD", name: "South Dakota" },
|
||||
{ code: "TN", name: "Tennessee" },
|
||||
{ code: "TX", name: "Texas" },
|
||||
{ code: "UT", name: "Utah" },
|
||||
{ code: "VT", name: "Vermont" },
|
||||
{ code: "VA", name: "Virginia" },
|
||||
{ code: "WA", name: "Washington" },
|
||||
{ code: "WV", name: "West Virginia" },
|
||||
{ code: "WI", name: "Wisconsin" },
|
||||
{ code: "WY", name: "Wyoming" },
|
||||
{ code: "DC", name: "Washington D.C." },
|
||||
];
|
||||
|
||||
export function requiresIdVerification(state: string | null | undefined): boolean {
|
||||
if (!state) return false;
|
||||
return (ID_VERIFICATION_STATES as readonly string[]).includes(state.toUpperCase());
|
||||
}
|
||||
|
||||
export function getUserState(): string | null {
|
||||
if (typeof window === "undefined") return null;
|
||||
return localStorage.getItem("eg_user_state");
|
||||
}
|
||||
|
||||
export function setUserState(state: string): void {
|
||||
localStorage.setItem("eg_user_state", state.toUpperCase());
|
||||
}
|
||||
|
||||
export function isIdVerified(profileVerified?: boolean): boolean {
|
||||
if (profileVerified) return true;
|
||||
if (typeof window === "undefined") return false;
|
||||
return localStorage.getItem("eg_id_verified") === "true";
|
||||
}
|
||||
|
||||
export function setIdVerified(verified: boolean): void {
|
||||
localStorage.setItem("eg_id_verified", String(verified));
|
||||
if (verified) {
|
||||
localStorage.setItem("eg_id_verified_at", new Date().toISOString());
|
||||
}
|
||||
}
|
||||
|
||||
/** True when explicit/nude photos must stay blurred */
|
||||
export function mustBlurExplicit(profileVerified?: boolean): boolean {
|
||||
const state = getUserState();
|
||||
if (!requiresIdVerification(state)) return false;
|
||||
return !isIdVerified(profileVerified);
|
||||
}
|
||||
|
||||
export function stateName(code: string): string {
|
||||
return US_STATES.find((s) => s.code === code)?.name ?? code;
|
||||
}
|
||||
7
src/lib/limits.ts
Normal file
7
src/lib/limits.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
/** Hard product limits — enforced in UI and DB triggers */
|
||||
export const MAX_PHOTOS_PER_USER = 15;
|
||||
export const MAX_ALBUMS_PER_USER = 5;
|
||||
export const MAX_CANNED_MESSAGES = 20;
|
||||
export const MAX_PHOTO_SIZE_MB = 8;
|
||||
export const MAX_CANNED_MESSAGE_LENGTH = 500;
|
||||
export const MAX_ALBUM_NAME_LENGTH = 40;
|
||||
@@ -25,6 +25,9 @@ export const MOCK_PROFILES: Profile[] = [
|
||||
lat: jitter(DEFAULT_LAT, 0.02),
|
||||
lng: jitter(DEFAULT_LNG, 0.02),
|
||||
city: "Fort Lauderdale",
|
||||
state: "FL",
|
||||
id_verified: false,
|
||||
id_verified_at: null,
|
||||
vanilla_mode: false,
|
||||
created_at: new Date().toISOString(),
|
||||
},
|
||||
@@ -45,6 +48,9 @@ export const MOCK_PROFILES: Profile[] = [
|
||||
lat: jitter(DEFAULT_LAT, 0.03),
|
||||
lng: jitter(DEFAULT_LNG, 0.03),
|
||||
city: "Fort Lauderdale",
|
||||
state: "FL",
|
||||
id_verified: false,
|
||||
id_verified_at: null,
|
||||
vanilla_mode: false,
|
||||
created_at: new Date().toISOString(),
|
||||
},
|
||||
@@ -65,6 +71,9 @@ export const MOCK_PROFILES: Profile[] = [
|
||||
lat: jitter(DEFAULT_LAT, 0.025),
|
||||
lng: jitter(DEFAULT_LNG, 0.025),
|
||||
city: "Fort Lauderdale",
|
||||
state: "FL",
|
||||
id_verified: false,
|
||||
id_verified_at: null,
|
||||
vanilla_mode: false,
|
||||
created_at: new Date().toISOString(),
|
||||
},
|
||||
@@ -85,6 +94,9 @@ export const MOCK_PROFILES: Profile[] = [
|
||||
lat: jitter(DEFAULT_LAT, 0.015),
|
||||
lng: jitter(DEFAULT_LNG, 0.015),
|
||||
city: "Fort Lauderdale",
|
||||
state: "FL",
|
||||
id_verified: false,
|
||||
id_verified_at: null,
|
||||
vanilla_mode: false,
|
||||
created_at: new Date().toISOString(),
|
||||
},
|
||||
@@ -105,6 +117,9 @@ export const MOCK_PROFILES: Profile[] = [
|
||||
lat: jitter(DEFAULT_LAT, 0.01),
|
||||
lng: jitter(DEFAULT_LNG, 0.01),
|
||||
city: "Fort Lauderdale",
|
||||
state: "FL",
|
||||
id_verified: false,
|
||||
id_verified_at: null,
|
||||
vanilla_mode: false,
|
||||
created_at: new Date().toISOString(),
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user