"use client"; import { useEffect, useState } from "react"; import axios from "axios"; import { Database, Download, RefreshCw, AlertTriangle, Check, Loader2, } from "lucide-react"; import { Button } from "@/components/ui/button"; import { useUser } from "@clerk/nextjs"; interface Backup { name: string; size: number; createdAt: string; } interface Gym { id: string; name: string; location?: string | null; status: "active" | "inactive"; adminUserId: string; } export default function SettingsPage() { const { user } = useUser(); const [backups, setBackups] = useState([]); const [loading, setLoading] = useState(true); const [creatingBackup, setCreatingBackup] = useState(false); const [restoring, setRestoring] = useState(null); const [message, setMessage] = useState<{ type: "success" | "error"; text: string; } | null>(null); // Gym picker state const [gyms, setGyms] = useState([]); const [gymsLoading, setGymsLoading] = useState(true); const [gymMessage, setGymMessage] = useState<{ type: "success" | "error"; text: string; } | null>(null); // Create Gym modal state const [showCreateGym, setShowCreateGym] = useState(false); const [gymName, setGymName] = useState(""); const [gymLocation, setGymLocation] = useState(""); const [creatingGym, setCreatingGym] = useState(false); const fetchBackups = async () => { try { const response = await axios.get("/api/admin/backups"); setBackups(response.data); } catch (error) { console.error("Failed to fetch backups:", error); } finally { setLoading(false); } }; const fetchGyms = async () => { setGymsLoading(true); setGymMessage(null); try { const res = await axios.get("/api/gyms"); setGyms(Array.isArray(res.data) ? res.data : []); } catch (error) { console.error("Failed to fetch gyms:", error); setGymMessage({ type: "error", text: "Failed to load gyms" }); } finally { setGymsLoading(false); } }; useEffect(() => { fetchBackups(); fetchGyms(); }, []); const handleCreateBackup = async () => { setCreatingBackup(true); setMessage(null); try { await axios.post("/api/admin/backups"); await fetchBackups(); setMessage({ type: "success", text: "Backup created successfully" }); } catch (error) { console.error("Failed to create backup:", error); setMessage({ type: "error", text: "Failed to create backup" }); } finally { setCreatingBackup(false); } }; const handleRestore = async (filename: string) => { if ( !window.confirm( `Are you sure you want to restore from ${filename}? This will overwrite the current database.`, ) ) { return; } setRestoring(filename); setMessage(null); try { await axios.post("/api/admin/backups/restore", { filename }); setMessage({ type: "success", text: "Database restored successfully" }); // Optional: Refresh page or force re-login if session is invalidated } catch (error) { console.error("Failed to restore backup:", error); setMessage({ type: "error", text: "Failed to restore backup" }); } finally { setRestoring(null); } }; const formatSize = (bytes: number) => { const units = ["B", "KB", "MB", "GB"]; let size = bytes; let unitIndex = 0; while (size >= 1024 && unitIndex < units.length - 1) { size /= 1024; unitIndex++; } return `${size.toFixed(2)} ${units[unitIndex]}`; }; const formatDate = (dateString: string) => { return new Date(dateString).toLocaleString(); }; const handleSelectGym = async (gymId: string | null) => { setGymMessage(null); try { // Update current user's gym selection await axios.patch("/api/users/gym", { gymId }); setGymMessage({ type: "success", text: gymId ? "Gym selected successfully" : "Proceeding without gym", }); } catch (error) { console.error("Failed to set gym:", error); setGymMessage({ type: "error", text: "Failed to set gym" }); } }; return (

Settings

Manage your application settings and database.

{/* Gym Picker */}

Gym Selection

Select your gym or proceed without a gym

{user ? ( <> Current role:{" "} {String(user.publicMetadata?.role ?? "unknown")} {" • "} Gym ID:{" "} {String(user.publicMetadata?.gymId ?? "none")} ) : ( "Loading user metadata..." )}

{gymMessage && (
{gymMessage.type === "success" ? ( ) : ( )} {gymMessage.text}
)} {showCreateGym && (

Create Gym

{ e.preventDefault(); try { setCreatingGym(true); await axios.post("/api/gyms", { name: gymName.trim(), location: gymLocation.trim() || undefined, }); setGymMessage({ type: "success", text: "Gym created successfully", }); setShowCreateGym(false); setGymName(""); setGymLocation(""); fetchGyms(); } catch (error) { console.error("Failed to create gym:", error); setGymMessage({ type: "error", text: "Failed to create gym", }); } finally { setCreatingGym(false); } }} >
setGymName(e.target.value)} className="w-full border border-gray-300 rounded px-3 py-2" required />
setGymLocation(e.target.value)} className="w-full border border-gray-300 rounded px-3 py-2" placeholder="Enter location" />
)}

Proceed without gym

You can select a gym later.

{gymsLoading ? (
Loading gyms...
) : gyms.length === 0 ? (
No active gyms found.
) : ( gyms.map((gym) => (

{gym.name}

{gym.location || "No location provided"}

)) )}

Database Management

Create backups and restore your database

{message && (
{message.type === "success" ? ( ) : ( )} {message.text}
)}
{loading ? ( ) : backups.length === 0 ? ( ) : ( backups.map((backup) => ( )) )}
Filename Size Created At Actions
Loading backups...
No backups found
{backup.name} {formatSize(backup.size)} {formatDate(backup.createdAt)}
); }