Files
eventify_command_center/src/features/settings/components/dialogs/CreateDepartmentDialog.tsx

116 lines
5.5 KiB
TypeScript

'use client';
import { useState } from 'react';
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Checkbox } from '@/components/ui/checkbox';
import { getScopesByCategory } from '@/lib/types/staff';
import { createDepartment } from '@/lib/actions/staff-management';
import { toast } from 'sonner';
import { Loader2, Plus } from 'lucide-react';
const DEPT_COLORS = ['#3B82F6', '#10B981', '#F59E0B', '#EF4444', '#8B5CF6', '#EC4899', '#06B6D4'];
interface CreateDepartmentDialogProps {
onCreated: () => void;
}
export function CreateDepartmentDialog({ onCreated }: CreateDepartmentDialogProps) {
const [open, setOpen] = useState(false);
const [loading, setLoading] = useState(false);
const [name, setName] = useState('');
const [description, setDescription] = useState('');
const [selectedScopes, setSelectedScopes] = useState<string[]>([]);
const [color, setColor] = useState(DEPT_COLORS[0]);
const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, '');
const scopesByCategory = getScopesByCategory();
const toggleScope = (scope: string) => {
setSelectedScopes(prev => prev.includes(scope) ? prev.filter(s => s !== scope) : [...prev, scope]);
};
const handleSubmit = async () => {
if (!name.trim()) { toast.error('Department name is required'); return; }
setLoading(true);
try {
const res = await createDepartment({ name, slug, baseScopes: selectedScopes, color, description });
if (res.success) {
toast.success(`Department "${name}" created`);
setOpen(false);
setName(''); setDescription(''); setSelectedScopes([]);
onCreated();
}
} catch { toast.error('Failed to create department'); }
finally { setLoading(false); }
};
return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>
<Button variant="outline" size="sm">
<Plus className="h-4 w-4 mr-1" /> New Department
</Button>
</DialogTrigger>
<DialogContent className="max-w-lg max-h-[85vh] overflow-y-auto">
<DialogHeader>
<DialogTitle>Create Department</DialogTitle>
<DialogDescription>Define a new organizational unit with base permissions.</DialogDescription>
</DialogHeader>
<div className="space-y-4 py-4">
<div className="space-y-2">
<Label>Department Name</Label>
<Input value={name} onChange={e => setName(e.target.value)} placeholder="e.g. Customer Support" />
{slug && <p className="text-xs text-muted-foreground">Slug: <code>{slug}</code></p>}
</div>
<div className="space-y-2">
<Label>Description</Label>
<Input value={description} onChange={e => setDescription(e.target.value)} placeholder="What does this department handle?" />
</div>
<div className="space-y-2">
<Label>Color</Label>
<div className="flex gap-2">
{DEPT_COLORS.map(c => (
<button key={c} onClick={() => setColor(c)}
className={`w-8 h-8 rounded-full border-2 transition-transform ${color === c ? 'border-foreground scale-110' : 'border-transparent'}`}
style={{ backgroundColor: c }} />
))}
</div>
</div>
<div className="space-y-3">
<Label>Base Permissions</Label>
<p className="text-xs text-muted-foreground">All members in this department will inherit these permissions.</p>
{Object.entries(scopesByCategory).map(([category, scopes]) => (
<div key={category} className="space-y-2">
<p className="text-sm font-medium text-muted-foreground">{category}</p>
<div className="grid grid-cols-2 gap-2">
{scopes.map(({ scope, label }) => (
<label key={scope} className="flex items-center gap-2 text-sm cursor-pointer p-1.5 rounded hover:bg-muted/50">
<Checkbox checked={selectedScopes.includes(scope)} onCheckedChange={() => toggleScope(scope)} />
{label}
</label>
))}
</div>
</div>
))}
</div>
</div>
<DialogFooter>
<Button variant="ghost" onClick={() => setOpen(false)}>Cancel</Button>
<Button onClick={handleSubmit} disabled={loading}>
{loading && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
Create Department
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}