108 lines
4.4 KiB
TypeScript
108 lines
4.4 KiB
TypeScript
import React, { useState, useRef, useEffect } from "react";
|
|
import { useWorkspace } from "../context/WorkspaceContext";
|
|
import { useTranslation } from "../hooks/useTranslation";
|
|
import { Check, ChevronDown, Plus, Briefcase } from "lucide-react";
|
|
import { CreateWorkspaceModal } from "./CreateWorkspaceModal"; // Adjust path if needed
|
|
|
|
export const WorkspaceSelector: React.FC = () => {
|
|
const [isOpen, setIsOpen] = useState(false);
|
|
const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);
|
|
const dropdownRef = useRef<HTMLDivElement>(null);
|
|
|
|
const { workspaces, activeWorkspace, setActiveWorkspace, addWorkspace } = useWorkspace();
|
|
const { t, lang } = useTranslation();
|
|
const isFa = lang === "fa";
|
|
|
|
useEffect(() => {
|
|
const handleClickOutside = (event: MouseEvent) => {
|
|
if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
|
|
setIsOpen(false);
|
|
}
|
|
};
|
|
document.addEventListener("mousedown", handleClickOutside);
|
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
}, []);
|
|
|
|
const handleCreateWorkspace = async (data: { name: string; description: string; members: any[] }) => {
|
|
await addWorkspace(data);
|
|
setIsCreateModalOpen(false);
|
|
};
|
|
|
|
return (
|
|
<div className="relative" ref={dropdownRef}>
|
|
{/* Selector Button */}
|
|
<button
|
|
type="button"
|
|
onClick={() => setIsOpen(!isOpen)}
|
|
className="flex items-center gap-2 px-3 py-2 text-sm font-medium text-slate-700 dark:text-slate-200 rounded-lg hover:bg-slate-100 dark:hover:bg-slate-800 transition-colors"
|
|
>
|
|
<div className="w-6 h-6 flex items-center justify-center bg-blue-100 dark:bg-blue-900/50 text-blue-600 dark:text-blue-400 rounded-md">
|
|
{activeWorkspace?.name?.charAt(0) || <Briefcase className="w-4 h-4" />}
|
|
</div>
|
|
<span className="max-w-30 truncate">
|
|
{activeWorkspace?.name || t.workspace?.title || "Workspaces"}
|
|
</span>
|
|
<ChevronDown className="w-4 h-4 text-slate-400" />
|
|
</button>
|
|
|
|
{/* Dropdown Menu */}
|
|
{isOpen && (
|
|
<div
|
|
className={`absolute top-full mt-2 w-64 bg-white dark:bg-slate-900 rounded-xl shadow-lg border border-slate-200 dark:border-slate-800 py-2 z-40 ${
|
|
isFa ? "left-0" : "right-0"
|
|
}`}
|
|
>
|
|
<div className="px-3 py-2 text-xs font-semibold text-slate-500 uppercase tracking-wider">
|
|
{t.workspace?.title || "Workspaces"}
|
|
</div>
|
|
|
|
<div className="max-h-60 overflow-y-auto">
|
|
{workspaces.map((ws) => (
|
|
<button
|
|
key={ws.id}
|
|
type="button"
|
|
onClick={() => {
|
|
setActiveWorkspace(ws);
|
|
setIsOpen(false);
|
|
}}
|
|
className="w-full flex items-center justify-between px-3 py-2 text-sm text-slate-700 dark:text-slate-200 hover:bg-slate-100 dark:hover:bg-slate-800 transition-colors"
|
|
>
|
|
<div className="flex items-center gap-2 truncate">
|
|
<div className="w-6 h-6 flex items-center justify-center bg-slate-100 dark:bg-slate-800 rounded-md font-medium">
|
|
{ws.name.charAt(0)}
|
|
</div>
|
|
<span className="truncate">{ws.name}</span>
|
|
</div>
|
|
{activeWorkspace?.id === ws.id && (
|
|
<Check className="w-4 h-4 text-blue-500 shrink-0" />
|
|
)}
|
|
</button>
|
|
))}
|
|
</div>
|
|
|
|
<div className="h-px bg-slate-200 dark:bg-slate-800 my-2" />
|
|
|
|
<button
|
|
type="button"
|
|
onClick={() => {
|
|
setIsOpen(false);
|
|
setIsCreateModalOpen(true);
|
|
}}
|
|
className="w-full flex items-center gap-2 px-3 py-2 text-sm text-blue-600 dark:text-blue-400 hover:bg-blue-50 dark:hover:bg-blue-500/10 transition-colors"
|
|
>
|
|
<Plus className="w-4 h-4" />
|
|
{t.workspace?.createNew || "Create New Workspace"}
|
|
</button>
|
|
</div>
|
|
)}
|
|
|
|
{/* Advanced Create Workspace Modal */}
|
|
<CreateWorkspaceModal
|
|
isOpen={isCreateModalOpen}
|
|
onClose={() => setIsCreateModalOpen(false)}
|
|
onSubmit={handleCreateWorkspace}
|
|
/>
|
|
</div>
|
|
);
|
|
};
|