feat: Sniffies-style map+profiles, guest age-verify without ID, limited access
This commit is contained in:
92
src/components/GuestUpgradeBanner.tsx
Normal file
92
src/components/GuestUpgradeBanner.tsx
Normal file
@@ -0,0 +1,92 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Lock, UserPlus, X, ShieldCheck } from "lucide-react";
|
||||
import { AuthModal } from "@/components/AuthModal";
|
||||
|
||||
interface GuestUpgradeBannerProps {
|
||||
reason?: "explicit" | "chat" | "media" | "general";
|
||||
compact?: boolean;
|
||||
onDismiss?: () => void;
|
||||
}
|
||||
|
||||
const MESSAGES = {
|
||||
explicit: {
|
||||
title: "Explicit photos are for members",
|
||||
body: "You verified your age — great. Create a free account to unlock x-rated photos, or complete ID verification in restricted states.",
|
||||
},
|
||||
chat: {
|
||||
title: "Sign up free to chat",
|
||||
body: "Guests can browse the map and profiles. Join free to message cruisers, save quick replies, and upload photos.",
|
||||
},
|
||||
media: {
|
||||
title: "Media gallery locked",
|
||||
body: "Register free to view full photo grids and share your own pics (up to 15).",
|
||||
},
|
||||
general: {
|
||||
title: "Limited guest access",
|
||||
body: "Age verified — no ID required to browse. Sign up free for chat, photos, and explicit content (ID may be required in your state).",
|
||||
},
|
||||
};
|
||||
|
||||
export function GuestUpgradeBanner({
|
||||
reason = "general",
|
||||
compact,
|
||||
onDismiss,
|
||||
}: GuestUpgradeBannerProps) {
|
||||
const [authOpen, setAuthOpen] = useState(false);
|
||||
const msg = MESSAGES[reason];
|
||||
|
||||
if (compact) {
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setAuthOpen(true)}
|
||||
className="flex items-center gap-2 w-full rounded-lg border border-horny-pink/30 bg-horny-pink/10 px-3 py-2 text-left touch-manipulation"
|
||||
>
|
||||
<Lock className="h-4 w-4 text-horny-pink shrink-0" />
|
||||
<span className="text-xs font-medium">{msg.title}</span>
|
||||
</button>
|
||||
<AuthModal open={authOpen} onClose={() => setAuthOpen(false)} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="rounded-xl border border-amber-500/25 bg-[#0a1628]/90 p-4 relative">
|
||||
{onDismiss && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={onDismiss}
|
||||
className="absolute top-2 right-2 p-1 text-muted-foreground hover:text-foreground"
|
||||
aria-label="Dismiss"
|
||||
>
|
||||
<X className="h-4 w-4" />
|
||||
</button>
|
||||
)}
|
||||
<div className="flex gap-3">
|
||||
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-blue-500/20">
|
||||
<ShieldCheck className="h-5 w-5 text-blue-400" />
|
||||
</div>
|
||||
<div className="flex-1 min-w-0 pr-6">
|
||||
<p className="text-sm font-semibold text-blue-100">{msg.title}</p>
|
||||
<p className="text-xs text-muted-foreground mt-1 leading-relaxed">{msg.body}</p>
|
||||
<Button
|
||||
variant="horny"
|
||||
size="sm"
|
||||
className="mt-3 gap-1.5"
|
||||
onClick={() => setAuthOpen(true)}
|
||||
>
|
||||
<UserPlus className="h-3.5 w-3.5" />
|
||||
Join Free — No Credit Card
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<AuthModal open={authOpen} onClose={() => setAuthOpen(false)} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user