"use client" import Link from "next/link"; import { Nav } from "../core/nav"; import { services } from "@/config/services"; import { TbArrowLeft, TbEye, TbLink, TbShieldLock, TbSend, TbExternalLink, TbLogin } from "react-icons/tb"; import { authClient } from "@/util/auth-client"; import { useEffect, useState } from "react"; import Altcha from "../core/altcha"; interface UserService { serviceId: string; serviceName: string; serviceDescription: string; priceStatus: string; joinLink?: string; grantedAt: string | null; isOpen: boolean; } interface ServiceRequest { id: string; reason: string; status: 'pending' | 'approved' | 'denied'; adminNotes?: string; reviewedAt?: string; createdAt: string; serviceName: string; serviceDescription: string; } function HumanPriceStatus(priceStatus: "open" | "invite-only" | "by-request") { switch (priceStatus) { case "open": return "Open"; case "invite-only": return "Invite only"; case "by-request": return "By request"; } } function HumanPriceStatusColor(priceStatus: "open" | "invite-only" | "by-request") { switch (priceStatus) { case "open": return "bg-green-500"; case "invite-only": return "bg-yellow-500"; case "by-request": return "bg-red-500"; } } function getUserAccessStatusColor(hasAccess: boolean, requestStatus?: string) { if (hasAccess) return "bg-green-500"; if (requestStatus === 'pending') return "bg-yellow-500"; if (requestStatus === 'denied') return "bg-red-500"; return "bg-gray-500"; } function getUserAccessStatusText(hasAccess: boolean, requestStatus?: string) { if (hasAccess) return "You Have Access"; if (requestStatus === 'pending') return "Request Pending"; if (requestStatus === 'denied') return "Request Denied"; return "No Access"; } function PriceStatusDesc(priceStatus: "open" | "invite-only" | "by-request", serviceName: string) { switch (priceStatus) { case "open": return `${serviceName} is open for public, self-service registration.`; case "invite-only": return `${serviceName} is invite-only. Please request an invite from an admin.`; case "by-request": return `${serviceName} is by-request. You may request access from an admin.`; } } function getServiceButtonContent( service: { name: string; priceStatus: string; joinLink?: string } | undefined, session: { user: { id: string; email: string } } | null, hasAccess: boolean, joinLink: string | undefined, serviceRequest: ServiceRequest | undefined, setShowRequestForm: (show: boolean) => void ) { const isLoggedIn = !!session; if (isLoggedIn && hasAccess && joinLink) { return ( ); } if (isLoggedIn && !hasAccess && (service?.priceStatus === 'by-request' || service?.priceStatus === 'invite-only')) { if (service?.priceStatus === 'by-request' && !serviceRequest) { return ( ); } else { return ( ); } } if (isLoggedIn && service?.priceStatus === 'open' && joinLink) { return ( ); } if (!isLoggedIn && service?.priceStatus === 'open' && joinLink) { return ( ); } if (!isLoggedIn && (service?.priceStatus === 'invite-only' || service?.priceStatus === 'by-request')) { return ( ); } return null; } export function ServicesShell({ slug }: { slug: string }) { const { data: session, isPending } = authClient.useSession(); const [userAccess, setUserAccess] = useState([]); const [userRequests, setUserRequests] = useState([]); const [, setLoading] = useState(true); const [showRequestForm, setShowRequestForm] = useState(false); const [requestReason, setRequestReason] = useState(""); const [captchaToken, setCaptchaToken] = useState(""); const [submitting, setSubmitting] = useState(false); const service = services.find((service) => service.name === slug); const Icon = service?.icon; useEffect(() => { if (session) { fetchUserData(); } else if (!isPending) { setLoading(false); } }, [session, isPending]); const fetchUserData = async () => { try { const [accessResponse, requestsResponse] = await Promise.all([ fetch("/api/user-services"), fetch("/api/service-requests") ]); if (accessResponse.ok) { const accessData = await accessResponse.json(); setUserAccess(accessData.services); } if (requestsResponse.ok) { const requestsData = await requestsResponse.json(); setUserRequests(requestsData.requests); } } catch (error) { console.error("Error fetching user data:", error); } finally { setLoading(false); } }; const submitRequest = async () => { if (!requestReason.trim() || !captchaToken) return; setSubmitting(true); try { const response = await fetch("/api/service-requests", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ serviceId: service?.name, reason: requestReason, captchaToken }), }); if (response.ok) { setShowRequestForm(false); setRequestReason(""); setCaptchaToken(""); fetchUserData(); } else { const error = await response.json(); console.error("Request failed:", error.error); } } catch (error) { console.error("Error submitting request:", error); } finally { setSubmitting(false); } }; const hasAccess = userAccess.some(access => access.serviceName === service?.name); const userService = userAccess.find(access => access.serviceName === service?.name); const isOpen = userService?.isOpen || false; const serviceRequest = userRequests.find(request => request.serviceName === service?.name); const joinLink = hasAccess ? userAccess.find(access => access.serviceName === service?.name)?.joinLink || service?.joinLink : service?.joinLink; return (