"use client" import { useState, useMemo } from "react" import { cn } from "@lib/utils" import { dmSans125ClassName, dmSansClassName } from "@/lib/fonts" import { $fetch } from "@repo/lib/api" import { DEFAULT_PROJECT_ID } from "@repo/lib/constants" import { useQuery } from "@tanstack/react-query" import { ChevronsLeftRight, Plus, Trash2, XIcon, Loader2 } from "lucide-react" import type { Project } from "@repo/lib/types" import { AddSpaceModal } from "./add-space-modal" import { useProjectMutations } from "@/hooks/use-project-mutations" import { motion } from "motion/react" import * as DialogPrimitive from "@radix-ui/react-dialog" import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from "@ui/components/dropdown-menu" import { Dialog, DialogContent } from "@repo/ui/components/dialog" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@repo/ui/components/select" import { Button } from "@repo/ui/components/button" import { analytics } from "@/lib/analytics" export interface SpaceSelectorProps { value: string onValueChange: (containerTag: string) => void variant?: "default" | "insideOut" showChevron?: boolean triggerClassName?: string contentClassName?: string showNewSpace?: boolean enableDelete?: boolean compact?: boolean } const triggerVariants = { default: "px-3 py-2 rounded-md hover:bg-white/5", insideOut: "px-3 py-2 rounded-full bg-[#0D121A] shadow-inside-out", } export function SpaceSelector({ value, onValueChange, variant = "default", showChevron = false, triggerClassName, contentClassName, showNewSpace = true, enableDelete = false, compact = false, }: SpaceSelectorProps) { const [isOpen, setIsOpen] = useState(false) const [showCreateDialog, setShowCreateDialog] = useState(false) const [deleteDialog, setDeleteDialog] = useState<{ open: boolean project: { id: string; name: string; containerTag: string } | null action: "move" | "delete" targetProjectId: string }>({ open: false, project: null, action: "move", targetProjectId: "", }) const { deleteProjectMutation } = useProjectMutations() 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 selectedProject = useMemo(() => { if (value === DEFAULT_PROJECT_ID) return { name: "My Space", emoji: "📁" } const found = projects.find((p: Project) => p.containerTag === value) return found ? { name: found.name, emoji: found.emoji } : { name: value, emoji: undefined } }, [projects, value]) const selectedProjectName = selectedProject.name const selectedProjectEmoji = selectedProject.emoji || "📁" const handleSelect = (containerTag: string) => { if (containerTag !== value) { analytics.spaceSwitched({ space_id: containerTag }) } onValueChange(containerTag) setIsOpen(false) } const handleNewSpace = () => { setIsOpen(false) setShowCreateDialog(true) } const handleDeleteClick = ( e: React.MouseEvent, project: { id: string; name: string; containerTag: string }, ) => { e.stopPropagation() e.preventDefault() setDeleteDialog({ open: true, project, action: "move", targetProjectId: "", }) } const handleDeleteConfirm = () => { if (!deleteDialog.project) return deleteProjectMutation.mutate( { projectId: deleteDialog.project.id, action: deleteDialog.action, targetProjectId: deleteDialog.action === "move" ? deleteDialog.targetProjectId : undefined, }, { onSuccess: () => { setDeleteDialog({ open: false, project: null, action: "move", targetProjectId: "", }) setIsOpen(false) }, }, ) } const handleDeleteCancel = () => { setDeleteDialog({ open: false, project: null, action: "move", targetProjectId: "", }) } const availableTargetProjects = useMemo(() => { const filtered = projects.filter( (p: Project) => p.id !== deleteDialog.project?.id && p.containerTag !== deleteDialog.project?.containerTag, ) const defaultProject = projects.find( (p: Project) => p.containerTag === DEFAULT_PROJECT_ID, ) const isDefaultProjectBeingDeleted = deleteDialog.project?.containerTag === DEFAULT_PROJECT_ID if (defaultProject && !isDefaultProjectBeingDeleted) { const defaultProjectIncluded = filtered.some( (p: Project) => p.containerTag === DEFAULT_PROJECT_ID, ) if (!defaultProjectIncluded) { return [defaultProject, ...filtered] } } return filtered }, [projects, deleteDialog.project]) return ( <>
{/* Default Project - no delete allowed */} handleSelect(DEFAULT_PROJECT_ID)} className={cn( "flex items-center gap-2 px-3 py-2.5 rounded-md cursor-pointer text-white text-sm font-medium", value === DEFAULT_PROJECT_ID ? "bg-[#293952]/40" : "opacity-60 hover:opacity-100 hover:bg-[#293952]/40", )} > 📁 My Space {/* User Projects */} {projects .filter((p: Project) => p.containerTag !== DEFAULT_PROJECT_ID) .map((project: Project) => ( handleSelect(project.containerTag)} className={cn( "flex items-center gap-2 px-3 py-2.5 rounded-md cursor-pointer text-white text-sm font-medium group", value === project.containerTag ? "bg-[#293952]/40" : "opacity-60 hover:opacity-100 hover:bg-[#293952]/40", )} > {project.emoji || "📁"} {project.name} {enableDelete && ( )} ))}
{showNewSpace && ( )}
setShowCreateDialog(false)} /> {/* Delete Confirmation Dialog - matching /new design system */} { if (!open) { setDeleteDialog({ open: false, project: null, action: "move", targetProjectId: "", }) } }} >

Delete space

What would you like to do with the documents and memories in{" "} "{deleteDialog.project?.name}" ?

Close
{deleteDialog.action === "move" && ( )} {deleteDialog.action === "delete" && ( All documents and memories will be permanently deleted. )}
) }