"use client"; import type { CSSProperties } from "react"; import { useEffect, useMemo, useRef } from "react"; import Image from "next/image"; import { Camera, ImageIcon, LockKeyhole, MessageCircle, RefreshCw, Sparkles, } from "lucide-react"; import type { PrivateRoomMoment } from "@/data/dto/private-room"; import { MobileShell } from "@/app/_components/core"; import { useGuestLoginBootstrap } from "@/hooks/use-guest-login-bootstrap"; import { ROUTES } from "@/router/routes"; import { useAppNavigator } from "@/router/use-app-navigator"; import { useAuthDispatch, useAuthState } from "@/stores/auth/auth-context"; import { usePrivateRoomDispatch, usePrivateRoomState, } from "@/stores/private-room"; import { useUserDispatch } from "@/stores/user/user-context"; import styles from "./private-room-screen.module.css"; const FALLBACK_PROFILE = { name: "Elio Silvestri", handle: "@elio.private", avatar: "/images/chat/pic-chat-elio.png", title: "Elio Private room", subtitle: "Join me, unlock my private room", bio: "Soft moments, private photos, and a little sweetness just for you.", } as const; export function PrivateRoomScreen() { const navigator = useAppNavigator(); const authState = useAuthState(); const authDispatch = useAuthDispatch(); const userDispatch = useUserDispatch(); const state = usePrivateRoomState(); const dispatch = usePrivateRoomDispatch(); const previousLoginStatusRef = useRef(authState.loginStatus); const lastUnlockSuccessNonceRef = useRef(0); useGuestLoginBootstrap({ dispatch: authDispatch, hasInitialized: authState.hasInitialized, isLoading: authState.isLoading, loginStatus: authState.loginStatus, }); useEffect(() => { if (!authState.hasInitialized || authState.isLoading) return; if (authState.loginStatus === "notLoggedIn") return; const previousLoginStatus = previousLoginStatusRef.current; previousLoginStatusRef.current = authState.loginStatus; if (state.status === "idle") { dispatch({ type: "PrivateRoomInit" }); return; } if ( previousLoginStatus !== authState.loginStatus && state.status !== "loading" ) { dispatch({ type: "PrivateRoomRefresh" }); } }, [ authState.hasInitialized, authState.isLoading, authState.loginStatus, dispatch, state.status, ]); useEffect(() => { const request = state.unlockPaywallRequest; if (!request) return; if ( authState.loginStatus === "guest" || authState.loginStatus === "notLoggedIn" ) { navigator.openAuth(ROUTES.privateRoom); } else { navigator.openSubscription({ type: "topup" }); } dispatch({ type: "PrivateRoomUnlockPaywallConsumed" }); }, [ authState.loginStatus, dispatch, navigator, state.unlockPaywallRequest, ]); useEffect(() => { if (state.unlockSuccessNonce <= lastUnlockSuccessNonceRef.current) return; lastUnlockSuccessNonceRef.current = state.unlockSuccessNonce; userDispatch({ type: "UserFetch" }); }, [state.unlockSuccessNonce, userDispatch]); const profile = state.profile; const displayName = profile?.displayName || profile?.authorName || FALLBACK_PROFILE.name; const avatarUrl = profile?.avatarUrl || FALLBACK_PROFILE.avatar; const title = profile?.title || FALLBACK_PROFILE.title; const subtitle = profile?.subtitle || FALLBACK_PROFILE.subtitle; const pendingMoment = useMemo( () => state.items.find( (item) => item.momentId === state.pendingConfirmMomentId, ) ?? null, [state.items, state.pendingConfirmMomentId], ); const handleTopUpClick = () => { if ( authState.loginStatus === "guest" || authState.loginStatus === "notLoggedIn" ) { navigator.openAuth(ROUTES.privateRoom); return; } navigator.openSubscription({ type: "topup" }); }; return (
{displayName}

{displayName}

{title}

{subtitle || FALLBACK_PROFILE.bio}

Posts

Private moments

{state.items.length}
{state.errorMessage ? ( dispatch({ type: "PrivateRoomRefresh" })} /> ) : null} {state.isLoading && state.items.length === 0 ? ( ) : null} {!state.isLoading && state.items.length === 0 && !state.errorMessage ? ( dispatch({ type: "PrivateRoomRefresh" })} /> ) : null}
{state.items.map((moment, index) => ( dispatch({ type: "PrivateRoomUnlockRequested", momentId: moment.momentId, }) } /> ))}
{state.hasMore ? ( ) : null}
{pendingMoment ? ( dispatch({ type: "PrivateRoomUnlockCancelled" })} onConfirm={() => dispatch({ type: "PrivateRoomUnlockConfirmed" })} /> ) : state.unlockErrorMessage ? (
{state.unlockErrorMessage}
) : null}
); } function PrivateRoomPostCard({ moment, displayName, avatarUrl, index, isUnlocking, onUnlock, }: { moment: PrivateRoomMoment; displayName: string; avatarUrl: string; index: number; isUnlocking: boolean; onUnlock: () => void; }) { const isLocked = moment.locked || moment.lockDetail.locked; const imageUrls = moment.images .filter((image) => !image.locked && image.url) .map((image) => image.url as string); const photoCount = moment.mediaCount || moment.images.length || 1; return (

{moment.author.name || displayName}

{moment.title || "Private room drop"}

{moment.text || moment.content ? (

{moment.text || moment.content}

) : null} {isLocked ? ( ) : (
{imageUrls.map((url, imageIndex) => ( ))}
)}
); } function UnlockConfirmDialog({ moment, isUnlocking, errorMessage, onCancel, onConfirm, }: { moment: PrivateRoomMoment; isUnlocking: boolean; errorMessage: string | null; onCancel: () => void; onConfirm: () => void; }) { return (

Unlock private moment?

This will use {moment.unlockCost} credits.

{errorMessage ? (

{errorMessage}

) : null}
); } function StatusCard({ message, actionLabel, onAction, }: { message: string; actionLabel?: string; onAction?: () => void; }) { return (

{message}

{actionLabel && onAction ? ( ) : null}
); } function formatMomentTime(value: string | null): string { if (!value) return ""; const date = new Date(value); if (Number.isNaN(date.getTime())) return ""; return date.toLocaleDateString(undefined, { month: "short", day: "numeric", }); }