"use client";
import { $fetch } from "@repo/lib/api";
import { DEFAULT_PROJECT_ID } from "@repo/lib/constants";
import { Button } from "@repo/ui/components/button";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from "@repo/ui/components/dialog";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@repo/ui/components/dropdown-menu";
import { Label } from "@repo/ui/components/label";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@repo/ui/components/select";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import {
ChevronDown,
FolderIcon,
Loader2,
MoreHorizontal,
MoreVertical,
Plus,
Trash2,
} from "lucide-react";
import { AnimatePresence, motion } from "motion/react";
import { useState } from "react";
import { toast } from "sonner";
import { useProjectMutations } from "@/hooks/use-project-mutations";
import { useProjectName } from "@/hooks/use-project-name";
import { useProject } from "@/stores";
import { CreateProjectDialog } from "./create-project-dialog";
interface Project {
id: string;
name: string;
containerTag: string;
createdAt: string;
updatedAt: string;
isExperimental?: boolean;
}
export function ProjectSelector() {
const queryClient = useQueryClient();
const [isOpen, setIsOpen] = useState(false);
const [showCreateDialog, setShowCreateDialog] = useState(false);
const { selectedProject } = useProject();
const projectName = useProjectName();
const { switchProject, deleteProjectMutation } = useProjectMutations();
const [deleteDialog, setDeleteDialog] = useState<{
open: boolean;
project: null | { id: string; name: string; containerTag: string };
action: "move" | "delete";
targetProjectId: string;
}>({
open: false,
project: null,
action: "move",
targetProjectId: DEFAULT_PROJECT_ID,
});
const [expDialog, setExpDialog] = useState<{
open: boolean;
projectId: string;
}>({
open: false,
projectId: "",
});
const { data: projects = [], isLoading } = useQuery({
queryKey: ["projects"],
queryFn: async () => {
const response = await $fetch("@get/projects");
if (response.error) {
throw new Error(response.error?.message || "Failed to load projects");
}
return response.data?.projects || [];
},
staleTime: 30 * 1000,
});
const enableExperimentalMutation = useMutation({
mutationFn: async (projectId: string) => {
const response = await $fetch(
`@post/projects/${projectId}/enable-experimental`,
);
if (response.error) {
throw new Error(
response.error?.message || "Failed to enable experimental mode",
);
}
return response.data;
},
onSuccess: () => {
toast.success("Experimental mode enabled for project");
queryClient.invalidateQueries({ queryKey: ["projects"] });
setExpDialog({ open: false, projectId: "" });
},
onError: (error) => {
toast.error("Failed to enable experimental mode", {
description: error instanceof Error ? error.message : "Unknown error",
});
},
});
const handleProjectSelect = (containerTag: string) => {
switchProject(containerTag);
setIsOpen(false);
};
const handleCreateNewProject = () => {
setIsOpen(false);
setShowCreateDialog(true);
};
return (
setIsOpen(!isOpen)}
whileHover={{ scale: 1.01 }}
whileTap={{ scale: 0.99 }}
>
{isLoading ? "..." : projectName}
{isOpen && (
<>
setIsOpen(false)}
/>
{/* Default Project */}
handleProjectSelect(DEFAULT_PROJECT_ID)}
>
Default
{/* User Projects */}
{projects
.filter((p: Project) => p.containerTag !== DEFAULT_PROJECT_ID)
.map((project: Project, index: number) => (
handleProjectSelect(project.containerTag)
}
>
{project.name}
e.stopPropagation()}
whileHover={{ scale: 1.1 }}
whileTap={{ scale: 0.9 }}
>
{/* Show experimental toggle only if NOT experimental and NOT default project */}
{!project.isExperimental &&
project.containerTag !== DEFAULT_PROJECT_ID && (
{
e.stopPropagation();
setExpDialog({
open: true,
projectId: project.id,
});
setIsOpen(false);
}}
>
Enable Experimental Mode
)}
{project.isExperimental && (
Experimental Mode Active
)}
{
e.stopPropagation();
setDeleteDialog({
open: true,
project: {
id: project.id,
name: project.name,
containerTag: project.containerTag,
},
action: "move",
targetProjectId: "",
});
setIsOpen(false);
}}
>
Delete Project
))}
New Project
>
)}
{/* Delete Project Dialog */}
{deleteDialog.open && deleteDialog.project && (
)}
{/* Experimental Mode Confirmation Dialog */}
{expDialog.open && (
)}
);
}