"use client"; import { useEffect, useRef, useState } from "react"; import { MdOutlineSwitchAccount, MdDragIndicator } from "react-icons/md"; import { IoClose, IoTrashOutline, IoKeyOutline } from "react-icons/io5"; import { getClientCookie, setClientCookie } from "@/lib/cookies"; import { setCachedMarriageEntryPath } from "@/lib/entry-route-cache"; export const FEMALE_TOKEN = "545f61bb3e061ccb9b19f84715eb1b1ed4740331"; export const MALE_TOKEN = "f3a7543b44ef0a713d1ee0d4f7866b3825cf1308"; export const MALE_2_TOKEN = "56cd0fceb93f7cecf7ffa84c590135026cf54a1d"; export const GUEST_MALE_1_TOKEN = "7490550734175c3935c54c808eba4933ee9c7633"; export const GUEST_MALE_2_TOKEN = "88813b0434f2207582f515f2c38de0cafd517fb7"; export const GUEST_FEMALE_1_TOKEN = "d9f0d61b2a7bbea89266eded6ad8d81a112f7ffe"; export const GUEST_FEMALE_2_TOKEN = "da44906159958b3f071096160b509e1479ccbc1a"; export const FEMALE_EMAIL = "m.a.ghorbani01@gmail.com"; export const MALE_EMAIL = "muhammadamin.ghorbani@gmail.com"; export const MALE_2_EMAIL = "habibwabackup@gmail.com"; const TOKEN_COOKIE_NAME = "HABIB_TOKEN"; const STORAGE_POS_KEY = "DEV_TOKEN_SWITCHER_POS"; type TokenSwitcherProps = { variant?: "default" | "transparent"; className?: string; isFloating?: boolean; }; export function TokenSwitcher({ variant = "default", className, isFloating = true, }: TokenSwitcherProps) { const [mounted, setMounted] = useState(false); const [isOpen, setIsOpen] = useState(false); const [currentToken, setCurrentToken] = useState(""); const [customTokenInput, setCustomTokenInput] = useState(""); const [position, setPosition] = useState<{ x: number; y: number } | null>(null); const [isDragging, setIsDragging] = useState(false); const containerRef = useRef(null); const dragStart = useRef<{ x: number; y: number; startX: number; startY: number; hasMoved: boolean; }>({ x: 0, y: 0, startX: 12, startY: 12, hasMoved: false }); useEffect(() => { setMounted(true); if (typeof window !== "undefined") { const token = (window as any).HABIB_TOKEN ?? getClientCookie(TOKEN_COOKIE_NAME) ?? getClientCookie("habib_token") ?? sessionStorage.getItem(TOKEN_COOKIE_NAME) ?? ""; setCurrentToken(token); if (isFloating) { try { const savedPos = localStorage.getItem(STORAGE_POS_KEY); if (savedPos) { const parsed = JSON.parse(savedPos); if (typeof parsed.x === "number" && typeof parsed.y === "number") { const clampedX = Math.max(10, Math.min(window.innerWidth - 180, parsed.x)); const clampedY = Math.max(10, Math.min(window.innerHeight - 50, parsed.y)); setPosition({ x: clampedX, y: clampedY }); return; } } } catch (e) { console.warn("Failed to load dev token switcher position:", e); } // Default initial position (top-left) setPosition({ x: 12, y: 12 }); } } }, [isFloating]); // Keep floating position bounded on window resize useEffect(() => { if (!isFloating) return; const handleResize = () => { setPosition((prev) => { if (!prev) return null; const width = containerRef.current?.offsetWidth || 180; const height = containerRef.current?.offsetHeight || 50; return { x: Math.max(10, Math.min(window.innerWidth - width - 10, prev.x)), y: Math.max(10, Math.min(window.innerHeight - height - 10, prev.y)), }; }); }; window.addEventListener("resize", handleResize); return () => window.removeEventListener("resize", handleResize); }, [isFloating]); const isMale = currentToken === MALE_TOKEN; const isMale2 = currentToken === MALE_2_TOKEN; const isFemale = currentToken === FEMALE_TOKEN; const isNoToken = currentToken === "NO_TOKEN" || !currentToken; const guestTokens = [ GUEST_MALE_1_TOKEN, GUEST_MALE_2_TOKEN, GUEST_FEMALE_1_TOKEN, GUEST_FEMALE_2_TOKEN, ]; const isGuestToken = guestTokens.includes(currentToken); const isCustomToken = !isMale && !isMale2 && !isFemale && !isNoToken && !isGuestToken; const handleSelectToken = (newToken: string) => { const trimmed = newToken.trim(); if (!trimmed) return; if (typeof window !== "undefined") { try { window.localStorage.clear(); window.sessionStorage.clear(); } catch (e) { console.error("Failed to clear storage", e); } setCachedMarriageEntryPath(null); setClientCookie(TOKEN_COOKIE_NAME, trimmed); setClientCookie("habib_token", trimmed); try { sessionStorage.setItem(TOKEN_COOKIE_NAME, trimmed); } catch (e) { console.warn("sessionStorage is not accessible:", e); } (window as any).HABIB_TOKEN = trimmed; setCurrentToken(trimmed); setIsOpen(false); window.location.replace("/"); } }; const handleResetUser = async (userId: number | null, label: string) => { const message = userId !== null ? `آیا از پاک کردن تمامی اطلاعات هویتی، پاسخ‌ها و پیشرفت این کاربر (${label}) و شروع مجدد از مرحله اول آنبوردینگ مطمئن هستید؟` : `آیا از پاک کردن تمامی اطلاعات محلی و کوکی‌های مربوط به این حالت (بدون توکن) و شروع مجدد مطمئن هستید؟`; if (!window.confirm(message)) { return; } try { if (typeof window !== "undefined") { try { window.localStorage.clear(); window.sessionStorage.clear(); } catch (e) { console.error("Failed to clear storage", e); } } if (userId !== null) { const response = await fetch("/api/dev-reset-profile", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ userId }), }); if (!response.ok) { const errData = await response.json(); alert(`خطا در ریست پروفایل: ${errData.error || response.statusText}`); return; } } const targetToken = userId === 17119 ? MALE_TOKEN : userId === 147714 ? FEMALE_TOKEN : userId === 146024 ? MALE_2_TOKEN : "NO_TOKEN"; setCachedMarriageEntryPath(null); setClientCookie(TOKEN_COOKIE_NAME, targetToken); setClientCookie("habib_token", targetToken); if (typeof window !== "undefined") { try { sessionStorage.setItem(TOKEN_COOKIE_NAME, targetToken); } catch (e) { console.warn("sessionStorage is not accessible:", e); } (window as any).HABIB_TOKEN = targetToken; setCurrentToken(targetToken); } setIsOpen(false); window.location.replace("/"); } catch (error) { console.error("Failed to reset user:", error); alert("خطایی در انجام عملیات رخ داد."); } }; const mainAccounts = [ { id: 17119, token: MALE_TOKEN, title: "حساب آقا", subtitle: MALE_EMAIL, emoji: "👨", isActive: isMale, }, { id: 146024, token: MALE_2_TOKEN, title: "حساب آقا ۲", subtitle: MALE_2_EMAIL, emoji: "👨", isActive: isMale2, }, { id: 147714, token: FEMALE_TOKEN, title: "حساب خانم", subtitle: FEMALE_EMAIL, emoji: "👩", isActive: isFemale, }, ]; const guestAccounts = [ { token: GUEST_MALE_1_TOKEN, title: "حساب مهمان آقا ۱", subtitle: "مهمان / بدون اطلاعات", emoji: "👨", isActive: currentToken === GUEST_MALE_1_TOKEN, }, { token: GUEST_MALE_2_TOKEN, title: "حساب مهمان آقا ۲", subtitle: "مهمان / بدون اطلاعات", emoji: "👨", isActive: currentToken === GUEST_MALE_2_TOKEN, }, { token: GUEST_FEMALE_1_TOKEN, title: "حساب مهمان خانم ۱", subtitle: "مهمان / بدون اطلاعات", emoji: "👩", isActive: currentToken === GUEST_FEMALE_1_TOKEN, }, { token: GUEST_FEMALE_2_TOKEN, title: "حساب مهمان خانم ۲", subtitle: "مهمان / بدون اطلاعات", emoji: "👩", isActive: currentToken === GUEST_FEMALE_2_TOKEN, }, ]; // Pointer drag handlers const handlePointerDown = (e: React.PointerEvent) => { if (!isFloating || isOpen) return; e.currentTarget.setPointerCapture(e.pointerId); setIsDragging(true); const startX = position?.x ?? 12; const startY = position?.y ?? 12; dragStart.current = { x: e.clientX, y: e.clientY, startX, startY, hasMoved: false, }; }; const handlePointerMove = (e: React.PointerEvent) => { if (!isDragging || !isFloating) return; const dx = e.clientX - dragStart.current.x; const dy = e.clientY - dragStart.current.y; if (Math.hypot(dx, dy) > 4) { dragStart.current.hasMoved = true; } const width = containerRef.current?.offsetWidth || 140; const height = containerRef.current?.offsetHeight || 40; const newX = Math.max( 10, Math.min(window.innerWidth - width - 10, dragStart.current.startX + dx) ); const newY = Math.max( 10, Math.min(window.innerHeight - height - 10, dragStart.current.startY + dy) ); setPosition({ x: newX, y: newY }); }; const handlePointerUp = (e: React.PointerEvent) => { if (!isDragging || !isFloating) return; try { e.currentTarget.releasePointerCapture(e.pointerId); } catch (err) {} setIsDragging(false); if (dragStart.current.hasMoved) { if (position) { try { localStorage.setItem(STORAGE_POS_KEY, JSON.stringify(position)); } catch (e) {} } } }; const handleBadgeClick = (e: React.MouseEvent) => { if (dragStart.current.hasMoved) { e.preventDefault(); e.stopPropagation(); return; } setIsOpen(true); }; const currentRoleLabel = isMale ? "آقا 👨" : isMale2 ? "آقا ۲ 👨" : isFemale ? "خانم 👩" : isGuestToken ? (guestAccounts.find((g) => g.token === currentToken)?.title ?? "مهمان 👤") : isNoToken ? "بدون توکن 👤" : "سفارشی 🔑"; if (!mounted && isFloating) { return null; } const badgeContent = (
setIsDragging(false)} onClick={handleBadgeClick} style={ isFloating ? { position: "fixed", left: position ? `${position.x}px` : "12px", top: position ? `${position.y}px` : "12px", zIndex: 99999, touchAction: "none", userSelect: "none", } : undefined } className={[ isFloating ? "fixed flex items-center gap-1.5 px-3 py-2 rounded-[15px] backdrop-blur-md shadow-md border select-none transition-shadow cursor-pointer" : "inline-flex items-center gap-1.5 rounded-[15px] px-3 py-2 shadow-md border backdrop-blur-md cursor-pointer", variant === "transparent" ? "bg-black/60 text-white border-white/20 hover:bg-black/70" : "bg-white/95 text-slate-800 border-slate-200/80 hover:bg-white dark:bg-slate-900/95 dark:text-slate-100 dark:border-slate-700/80", isDragging ? "cursor-grabbing shadow-2xl ring-2 ring-rose-500/50 scale-[1.02]" : "cursor-grab active:scale-95", className, ] .filter(Boolean) .join(" ")} title="تغییر توکن کاربر (تست) - برای جابجایی بکشید / برای انتخاب کلیک کنید" > {/* Drag handle */} {isFloating && (
)} {/* Role icon & selected account label */} {currentRoleLabel}
); return ( <> {badgeContent} {isOpen && (
setIsOpen(false)} >
e.stopPropagation()} > {/* Modal Header */}

انتخاب حساب کاربری (تست)

تغییر سریع پروفایل و توکن جهت تست

{/* Scrollable Account Cards */}
{/* Main Predefined Accounts */} {mainAccounts.map((acc) => (
handleSelectToken(acc.token)} className="flex-1 min-w-0 flex items-center gap-3 text-right cursor-pointer" >
{acc.emoji}
{acc.title} {acc.subtitle} {acc.token}
{acc.isActive && ( فعال )}
))} {/* Guest Accounts */} {guestAccounts.map((acc) => (
handleSelectToken(acc.token)} className="flex-1 min-w-0 flex items-center gap-3 text-right cursor-pointer" >
{acc.emoji}
{acc.title} {acc.subtitle} {acc.token}
{acc.isActive && ( فعال )}
))} {/* Custom Active Token Card (if any custom token is set) */} {isCustomToken && (
🔑
توکن سفارشی {currentToken}
فعال
)} {/* No Token Option Card */}
handleSelectToken("NO_TOKEN")} className="flex-1 min-w-0 flex items-center gap-3 text-right cursor-pointer" >
👤
کاربر بدون توکن حالت مهمان / بدون احراز هویت
{isNoToken && ( فعال )}
{/* Custom Token Input Section */}
افزودن یا تنظیم توکن دلخواه:
setCustomTokenInput(e.target.value)} placeholder="توکن ۳۲/۴۰ کاراکتری..." dir="ltr" className="flex-1 min-w-0 rounded-xl border border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-900 px-3 py-2 text-xs font-mono text-slate-800 dark:text-slate-200 outline-none focus:border-rose-500 focus:ring-1 focus:ring-rose-500/20 transition-all placeholder:text-slate-400 placeholder:text-[11px]" onKeyDown={(e) => { if (e.key === "Enter" && customTokenInput.trim()) { handleSelectToken(customTokenInput); } }} />
{/* Modal Footer */}
)} ); } export default TokenSwitcher;