This repository has been archived on 2026-04-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
KLC-Admin-Panel-Frontend-Fi…/src/components/pages/SectionConfigurationManager.tsx
2025-09-26 19:45:02 +05:30

953 lines
36 KiB
TypeScript

import React, { useState, useEffect } from 'react';
import { AuthenticatedLayout } from '../layout/AuthenticatedLayout';
import { Card, CardContent, CardHeader, CardTitle } from '../ui/card';
import { Button } from '../ui/button';
import { Badge } from '../ui/badge';
import { Input } from '../ui/input';
import { Label } from '../ui/label';
import { Textarea } from '../ui/textarea';
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '../ui/table';
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '../ui/select';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from '../ui/dropdown-menu';
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from '../ui/dialog';
import {
Sheet,
SheetContent,
SheetDescription,
SheetHeader,
SheetTitle,
} from '../ui/sheet';
import { Checkbox } from '../ui/checkbox';
import { Separator } from '../ui/separator';
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '../ui/tooltip';
import { toast } from "sonner@2.0.3";
import {
Plus,
Search,
MoreHorizontal,
Edit,
Settings,
Copy,
Trash2,
ArrowUpDown,
FileText,
Target,
CheckCircle,
XCircle,
AlertCircle,
Save,
X,
Info
} from 'lucide-react';
interface SectionConfigurationManagerProps {
onNavigate: (route: string) => void;
onLogout: () => void;
user: any;
}
// Mock section configuration templates
const sectionConfigTemplates = [
{
id: "template_leadership_360",
name: "Leadership 360 - Standard",
description: "Standard 360-degree leadership assessment configuration",
questionType: "Ipsative",
sections: [
{ name: "Strategic Thinking", numberOfStatements: 4, order: 1 },
{ name: "Communication Skills", numberOfStatements: 3, order: 2 },
{ name: "Team Leadership", numberOfStatements: 5, order: 3 },
{ name: "Results Orientation", numberOfStatements: 4, order: 4 }
],
usage: 12,
createdBy: "Dr. Rajesh Mehta",
createdAt: "2025-08-01T10:00:00Z"
},
{
id: "template_communication_likert",
name: "Communication Assessment - Likert",
description: "Comprehensive communication skills assessment using Likert scales",
questionType: "Likert",
sections: [
{ name: "Verbal Communication", numberOfOptions: 5, order: 1 },
{ name: "Written Communication", numberOfOptions: 7, order: 2 },
{ name: "Active Listening", numberOfOptions: 5, order: 3 },
{ name: "Non-verbal Communication", numberOfOptions: 5, order: 4 }
],
usage: 8,
createdBy: "Prof. Priya Sinha",
createdAt: "2025-08-05T14:30:00Z"
},
{
id: "template_innovation_tf",
name: "Innovation Mindset - True/False",
description: "Innovation capabilities assessment using binary choices",
questionType: "True/False",
sections: [
{ name: "Creative Thinking", order: 1 },
{ name: "Risk Taking", order: 2 },
{ name: "Problem Solving", order: 3 },
{ name: "Adaptability", order: 4 }
],
usage: 5,
createdBy: "Dr. Amit Sharma",
createdAt: "2025-08-10T09:15:00Z"
},
{
id: "template_strategy_matching",
name: "Strategic Thinking - Matching",
description: "Strategic capabilities assessment using matching exercises",
questionType: "Matching",
sections: [
{ name: "Strategic Analysis", order: 1 },
{ name: "Strategy Formulation", order: 2 },
{ name: "Strategy Implementation", order: 3 }
],
usage: 3,
createdBy: "Prof. Sunita Agarwal",
createdAt: "2025-08-12T16:45:00Z"
},
{
id: "template_culture_descriptive",
name: "Team Culture Survey - Descriptive",
description: "Open-ended team culture and engagement assessment",
questionType: "Descriptive",
sections: [
{ name: "Culture Anchors", order: 1 },
{ name: "Core Values", order: 2 },
{ name: "Team Communication", order: 3 },
{ name: "Collaboration", order: 4 },
{ name: "Employee Engagement", order: 5 }
],
usage: 7,
createdBy: "Dr. Neha Shah",
createdAt: "2025-08-15T11:20:00Z"
}
];
// Section configuration rules based on question type
const questionTypeConfig = {
"Ipsative": {
label: "Ipsative (Forced Choice)",
description: "Users choose between ranked statements",
configField: "numberOfStatements",
configLabel: "Number of Statements",
defaultValue: 4,
minValue: 2,
maxValue: 10,
helpText: "Statements users will rank in order of preference"
},
"Likert": {
label: "Likert Scale",
description: "Users rate items on a scale",
configField: "numberOfOptions",
configLabel: "Scale Points",
defaultValue: 5,
minValue: 3,
maxValue: 10,
helpText: "Number of points on the rating scale (e.g., 1-5, 1-7)"
},
"True/False": {
label: "True/False",
description: "Binary choice questions",
configField: null,
configLabel: "No additional configuration",
defaultValue: null,
helpText: "Binary questions don't require additional configuration"
},
"Matching": {
label: "Matching Exercise",
description: "Match items from different lists",
configField: null,
configLabel: "No additional configuration",
defaultValue: null,
helpText: "Matching exercises are configured per question"
},
"Descriptive": {
label: "Open Text",
description: "Free-form text responses",
configField: null,
configLabel: "No additional configuration",
defaultValue: null,
helpText: "Descriptive questions don't require section-level configuration"
}
};
export function SectionConfigurationManager({ onNavigate, onLogout, user }: SectionConfigurationManagerProps) {
// State management
const [searchTerm, setSearchTerm] = useState("");
const [questionTypeFilter, setQuestionTypeFilter] = useState("all");
const [selectedTemplates, setSelectedTemplates] = useState<string[]>([]);
// Dialog and drawer states
const [isCreateTemplateOpen, setIsCreateTemplateOpen] = useState(false);
const [isEditTemplateOpen, setIsEditTemplateOpen] = useState(false);
const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false);
const [isCloneTemplateOpen, setIsCloneTemplateOpen] = useState(false);
const [isBulkDeleteDialogOpen, setIsBulkDeleteDialogOpen] = useState(false);
// Template management states
const [editingTemplate, setEditingTemplate] = useState<any>(null);
const [deletingTemplate, setDeletingTemplate] = useState<any>(null);
const [cloningTemplate, setCloningTemplate] = useState<any>(null);
// Form states
const [newTemplate, setNewTemplate] = useState({
name: "",
description: "",
questionType: "",
sections: []
});
const [editSections, setEditSections] = useState<any[]>([]);
const breadcrumbs = [
{ label: "Admin", href: "/dashboard" },
{ label: "Content", href: "/content" },
{ label: "Profilers", href: "/profilers" },
{ label: "Section Configuration" }
];
// Filter templates
const filteredTemplates = sectionConfigTemplates.filter(template => {
const matchesSearch =
template.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
template.description.toLowerCase().includes(searchTerm.toLowerCase()) ||
template.createdBy.toLowerCase().includes(searchTerm.toLowerCase());
const matchesQuestionType = questionTypeFilter === "all" || template.questionType === questionTypeFilter;
return matchesSearch && matchesQuestionType;
});
// Question type filter options
const questionTypeOptions = [
{ value: "all", label: "All Question Types", count: sectionConfigTemplates.length },
{ value: "Ipsative", label: "Ipsative", count: sectionConfigTemplates.filter(t => t.questionType === "Ipsative").length },
{ value: "Likert", label: "Likert", count: sectionConfigTemplates.filter(t => t.questionType === "Likert").length },
{ value: "True/False", label: "True/False", count: sectionConfigTemplates.filter(t => t.questionType === "True/False").length },
{ value: "Matching", label: "Matching", count: sectionConfigTemplates.filter(t => t.questionType === "Matching").length },
{ value: "Descriptive", label: "Descriptive", count: sectionConfigTemplates.filter(t => t.questionType === "Descriptive").length }
];
// Utility functions
const getQuestionTypeConfig = (questionType: string) => {
return questionTypeConfig[questionType as keyof typeof questionTypeConfig] || questionTypeConfig["True/False"];
};
const addSection = () => {
const config = getQuestionTypeConfig(newTemplate.questionType);
const newSection: any = {
id: `section_${Date.now()}`,
name: "",
order: editSections.length + 1
};
if (config.configField) {
newSection[config.configField] = config.defaultValue;
}
setEditSections([...editSections, newSection]);
};
const updateSection = (index: number, field: string, value: any) => {
const updated = [...editSections];
updated[index] = { ...updated[index], [field]: value };
setEditSections(updated);
};
const removeSection = (index: number) => {
const updated = editSections.filter((_, i) => i !== index);
// Reorder sections
const reordered = updated.map((section, i) => ({ ...section, order: i + 1 }));
setEditSections(reordered);
};
const moveSection = (index: number, direction: 'up' | 'down') => {
if ((direction === 'up' && index === 0) || (direction === 'down' && index === editSections.length - 1)) {
return;
}
const updated = [...editSections];
const targetIndex = direction === 'up' ? index - 1 : index + 1;
// Swap sections
[updated[index], updated[targetIndex]] = [updated[targetIndex], updated[index]];
// Update order
updated[index].order = index + 1;
updated[targetIndex].order = targetIndex + 1;
setEditSections(updated);
};
// Action handlers
const handleCreateTemplate = () => {
setNewTemplate({
name: "",
description: "",
questionType: "",
sections: []
});
setEditSections([]);
setIsCreateTemplateOpen(true);
};
const handleEditTemplate = (template: any) => {
setEditingTemplate(template);
setNewTemplate({
name: template.name,
description: template.description,
questionType: template.questionType,
sections: template.sections
});
setEditSections([...template.sections]);
setIsEditTemplateOpen(true);
};
const handleCloneTemplate = (template: any) => {
setCloningTemplate(template);
setNewTemplate({
name: `${template.name} (Copy)`,
description: template.description,
questionType: template.questionType,
sections: template.sections
});
setEditSections([...template.sections]);
setIsCloneTemplateOpen(true);
};
const handleDeleteTemplate = (template: any) => {
setDeletingTemplate(template);
setIsDeleteDialogOpen(true);
};
const saveTemplate = () => {
if (!newTemplate.name.trim()) {
toast.error("Template name is required");
return;
}
if (!newTemplate.questionType) {
toast.error("Question type is required");
return;
}
if (editSections.length === 0) {
toast.error("At least one section is required");
return;
}
// Validate sections
for (const section of editSections) {
if (!section.name.trim()) {
toast.error("All sections must have names");
return;
}
}
const templateData = {
...newTemplate,
sections: editSections
};
if (isEditTemplateOpen) {
toast.success(`Template "${newTemplate.name}" updated successfully`);
setIsEditTemplateOpen(false);
} else {
toast.success(`Template "${newTemplate.name}" created successfully`);
setIsCreateTemplateOpen(false);
setIsCloneTemplateOpen(false);
}
// Reset form
setNewTemplate({ name: "", description: "", questionType: "", sections: [] });
setEditSections([]);
};
const confirmDelete = () => {
if (deletingTemplate) {
toast.success(`Template "${deletingTemplate.name}" deleted successfully`);
setIsDeleteDialogOpen(false);
setDeletingTemplate(null);
}
};
const handleBulkDelete = () => {
toast.success(`${selectedTemplates.length} templates deleted successfully`);
setSelectedTemplates([]);
setIsBulkDeleteDialogOpen(false);
};
// Filter chip component
const FilterChip = ({ label, count, active, onClick }: { label: string; count?: number; active: boolean; onClick: () => void }) => (
<button
onClick={onClick}
className={`inline-flex items-center gap-2 px-3 py-1.5 rounded-full border transition-colors min-h-[44px] ${
active
? 'bg-[var(--color-brand-primary)] text-white border-[var(--color-brand-primary)]'
: 'bg-white text-gray-700 border-gray-300 hover:bg-gray-50'
}`}
>
{label}
{count !== undefined && (
<span className={`px-1.5 py-0.5 rounded-full text-xs ${
active ? 'bg-white/20 text-white' : 'bg-gray-100 text-gray-600'
}`}>
{count}
</span>
)}
</button>
);
return (
<AuthenticatedLayout
currentRoute="/admin/section-configuration"
user={user}
onNavigate={onNavigate}
onLogout={onLogout}
breadcrumbs={breadcrumbs}
>
<div className="p-6 max-w-7xl mx-auto space-y-6">
{/* Header */}
<div className="flex items-center justify-between">
<div>
<h1 className="text-[var(--color-brand-black)]">Section Configuration Templates</h1>
<p className="text-gray-600 mt-1">
Manage reusable section configurations for profiler assessments
</p>
</div>
<div className="flex items-center gap-3">
<Button
variant="outline"
onClick={() => onNavigate('/profilers')}
className="min-h-[44px]"
>
Back to Profilers
</Button>
<Button
onClick={handleCreateTemplate}
className="min-h-[44px]"
style={{ backgroundColor: 'var(--color-brand-primary)' }}
>
<Plus className="h-4 w-4 mr-2" />
New Template
</Button>
</div>
</div>
{/* Filter Bar */}
<Card>
<CardContent className="p-6 space-y-4">
{/* Search */}
<div className="flex items-center gap-4">
<div className="flex-1 min-w-[300px]">
<div className="relative">
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-gray-400" />
<Input
placeholder="Search templates by name, description, or creator"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="pl-10 min-h-[44px]"
/>
</div>
</div>
</div>
{/* Filter Chips */}
<div>
<Label className="text-gray-700 mb-2 block">Question Type</Label>
<div className="flex flex-wrap gap-2">
{questionTypeOptions.map(option => (
<FilterChip
key={option.value}
label={option.label}
count={option.count}
active={questionTypeFilter === option.value}
onClick={() => setQuestionTypeFilter(option.value)}
/>
))}
</div>
</div>
</CardContent>
</Card>
{/* Bulk Action Bar */}
{selectedTemplates.length > 0 && (
<Card className="border-[var(--color-brand-primary)]">
<CardContent className="p-4">
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<span>
{selectedTemplates.length} template{selectedTemplates.length > 1 ? 's' : ''} selected
</span>
<Button
variant="ghost"
size="sm"
onClick={() => setSelectedTemplates([])}
className="text-gray-500"
>
Clear selection
</Button>
</div>
<div className="flex items-center gap-2">
<Button
variant="outline"
size="sm"
onClick={() => setIsBulkDeleteDialogOpen(true)}
className="min-h-[44px] text-red-600 hover:text-red-700"
>
<Trash2 className="h-4 w-4 mr-2" />
Delete Selected
</Button>
</div>
</div>
</CardContent>
</Card>
)}
{/* Templates Table */}
{filteredTemplates.length === 0 ? (
<Card>
<CardContent className="p-12">
<div className="text-center">
<Settings className="h-12 w-12 mx-auto mb-4 text-gray-400" />
<h3 className="mb-2">No section configuration templates found</h3>
<p className="text-gray-600 mb-6">
Create reusable section configurations to standardize your profiler assessments.
</p>
<Button
onClick={handleCreateTemplate}
style={{ backgroundColor: 'var(--color-brand-primary)' }}
className="min-h-[44px]"
>
<Plus className="h-4 w-4 mr-2" />
Create First Template
</Button>
</div>
</CardContent>
</Card>
) : (
<Card>
<CardContent className="p-0">
<div className="overflow-x-auto">
<Table>
<TableHeader className="bg-gray-50 sticky top-0">
<TableRow className="border-b">
<TableHead className="w-12">
<Checkbox
checked={selectedTemplates.length === filteredTemplates.length}
onCheckedChange={(checked) => {
if (checked) {
setSelectedTemplates(filteredTemplates.map(t => t.id));
} else {
setSelectedTemplates([]);
}
}}
/>
</TableHead>
<TableHead>Template Name</TableHead>
<TableHead>Question Type</TableHead>
<TableHead>Sections</TableHead>
<TableHead>Usage</TableHead>
<TableHead>Created By</TableHead>
<TableHead>Created</TableHead>
<TableHead className="w-12">Actions</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{filteredTemplates.map((template) => (
<TableRow key={template.id} className="border-b hover:bg-gray-50 min-h-[44px]">
<TableCell>
<Checkbox
checked={selectedTemplates.includes(template.id)}
onCheckedChange={(checked) => {
if (checked) {
setSelectedTemplates([...selectedTemplates, template.id]);
} else {
setSelectedTemplates(selectedTemplates.filter(id => id !== template.id));
}
}}
/>
</TableCell>
<TableCell>
<div>
<div className="font-medium">{template.name}</div>
<div className="text-sm text-gray-500">{template.description}</div>
</div>
</TableCell>
<TableCell>
<Badge variant="secondary" className="text-xs">
{template.questionType}
</Badge>
</TableCell>
<TableCell>
<TooltipProvider>
<Tooltip>
<TooltipTrigger>
<div className="text-sm">
{template.sections.length} section{template.sections.length > 1 ? 's' : ''}
</div>
</TooltipTrigger>
<TooltipContent>
<div className="space-y-1">
{template.sections.map((section, index) => (
<div key={index} className="text-sm">
{section.name}
{section.numberOfStatements && ` (${section.numberOfStatements} statements)`}
{section.numberOfOptions && ` (${section.numberOfOptions}-point scale)`}
</div>
))}
</div>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</TableCell>
<TableCell>
<div className="text-sm">
Used in {template.usage} profiler{template.usage > 1 ? 's' : ''}
</div>
</TableCell>
<TableCell>{template.createdBy}</TableCell>
<TableCell className="text-gray-600">
{new Date(template.createdAt).toLocaleDateString('en-GB', {
day: '2-digit',
month: 'short',
year: 'numeric'
})}
</TableCell>
<TableCell>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="sm" className="h-8 w-8 p-0">
<MoreHorizontal className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-48">
<DropdownMenuItem onClick={() => handleEditTemplate(template)}>
<Edit className="h-4 w-4 mr-2" />
Edit Template
</DropdownMenuItem>
<DropdownMenuItem onClick={() => handleCloneTemplate(template)}>
<Copy className="h-4 w-4 mr-2" />
Clone Template
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem
onClick={() => handleDeleteTemplate(template)}
className="text-red-600 hover:text-red-700"
>
<Trash2 className="h-4 w-4 mr-2" />
Delete Template
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
</CardContent>
</Card>
)}
{/* Create/Edit Template Dialog */}
<Dialog open={isCreateTemplateOpen || isEditTemplateOpen || isCloneTemplateOpen} onOpenChange={(open) => {
if (!open) {
setIsCreateTemplateOpen(false);
setIsEditTemplateOpen(false);
setIsCloneTemplateOpen(false);
setNewTemplate({ name: "", description: "", questionType: "", sections: [] });
setEditSections([]);
}
}}>
<DialogContent className="max-w-4xl max-h-[90vh] overflow-y-auto">
<DialogHeader>
<DialogTitle>
{isEditTemplateOpen ? 'Edit Template' : isCloneTemplateOpen ? 'Clone Template' : 'Create New Template'}
</DialogTitle>
<DialogDescription>
{isEditTemplateOpen ? 'Modify the section configuration template' :
isCloneTemplateOpen ? 'Create a copy of the section configuration template' :
'Create a reusable section configuration template for profiler assessments'}
</DialogDescription>
</DialogHeader>
<div className="space-y-6">
{/* Basic Information */}
<div className="grid grid-cols-2 gap-4">
<div>
<Label htmlFor="template-name">Template Name</Label>
<Input
id="template-name"
value={newTemplate.name}
onChange={(e) => setNewTemplate({ ...newTemplate, name: e.target.value })}
placeholder="Enter template name"
className="min-h-[44px]"
/>
</div>
<div>
<Label htmlFor="question-type">Question Type</Label>
<Select
value={newTemplate.questionType}
onValueChange={(value) => {
setNewTemplate({ ...newTemplate, questionType: value });
// Reset sections when question type changes
setEditSections([]);
}}
disabled={isEditTemplateOpen}
>
<SelectTrigger className="min-h-[44px]">
<SelectValue placeholder="Select question type" />
</SelectTrigger>
<SelectContent>
{Object.entries(questionTypeConfig).map(([type, config]) => (
<SelectItem key={type} value={type}>
<div>
<div>{config.label}</div>
<div className="text-sm text-gray-500">{config.description}</div>
</div>
</SelectItem>
))}
</SelectContent>
</Select>
</div>
</div>
<div>
<Label htmlFor="template-description">Description</Label>
<Textarea
id="template-description"
value={newTemplate.description}
onChange={(e) => setNewTemplate({ ...newTemplate, description: e.target.value })}
placeholder="Describe this template and its intended use"
rows={3}
/>
</div>
{/* Question Type Configuration Info */}
{newTemplate.questionType && (
<div className="bg-blue-50 border border-blue-200 rounded-lg p-4">
<div className="flex items-start gap-3">
<Info className="h-5 w-5 text-blue-600 mt-0.5 flex-shrink-0" />
<div>
<h4 className="font-medium text-blue-900">
{getQuestionTypeConfig(newTemplate.questionType).label} Configuration
</h4>
<p className="text-sm text-blue-700 mt-1">
{getQuestionTypeConfig(newTemplate.questionType).helpText}
</p>
</div>
</div>
</div>
)}
{/* Sections Configuration */}
{newTemplate.questionType && (
<div>
<div className="flex items-center justify-between mb-4">
<Label>Sections Configuration</Label>
<Button
onClick={addSection}
size="sm"
className="min-h-[44px]"
>
<Plus className="h-4 w-4 mr-2" />
Add Section
</Button>
</div>
{editSections.length === 0 ? (
<div className="text-center py-8 border-2 border-dashed border-gray-300 rounded-lg">
<FileText className="h-8 w-8 mx-auto mb-2 text-gray-400" />
<p className="text-gray-500">No sections added yet</p>
<p className="text-sm text-gray-400">Click "Add Section" to get started</p>
</div>
) : (
<div className="space-y-3">
{editSections.map((section, index) => {
const typeConfig = getQuestionTypeConfig(newTemplate.questionType);
return (
<div key={section.id || index} className="border rounded-lg p-4 bg-gray-50">
<div className="flex items-center gap-3 mb-3">
<div className="flex items-center gap-2">
<Button
variant="ghost"
size="sm"
onClick={() => moveSection(index, 'up')}
disabled={index === 0}
className="h-8 w-8 p-0"
>
<ArrowUpDown className="h-4 w-4" />
</Button>
<span className="text-sm font-medium text-gray-500">
Section {section.order}
</span>
</div>
<div className="flex-1">
<Input
value={section.name}
onChange={(e) => updateSection(index, 'name', e.target.value)}
placeholder="Section name"
className="min-h-[44px]"
/>
</div>
{typeConfig.configField && (
<div className="w-32">
<Input
type="number"
value={section[typeConfig.configField] || typeConfig.defaultValue}
onChange={(e) => updateSection(index, typeConfig.configField!, parseInt(e.target.value))}
min={typeConfig.minValue}
max={typeConfig.maxValue}
placeholder={typeConfig.configLabel}
className="min-h-[44px]"
/>
</div>
)}
<Button
variant="ghost"
size="sm"
onClick={() => removeSection(index)}
className="h-8 w-8 p-0 text-red-600 hover:text-red-700"
>
<X className="h-4 w-4" />
</Button>
</div>
{typeConfig.configField && (
<div className="text-xs text-gray-500">
{typeConfig.configLabel}: {section[typeConfig.configField] || typeConfig.defaultValue}
</div>
)}
</div>
);
})}
</div>
)}
</div>
)}
</div>
<DialogFooter>
<Button
variant="outline"
onClick={() => {
setIsCreateTemplateOpen(false);
setIsEditTemplateOpen(false);
setIsCloneTemplateOpen(false);
}}
className="min-h-[44px]"
>
Cancel
</Button>
<Button
onClick={saveTemplate}
className="min-h-[44px]"
style={{ backgroundColor: 'var(--color-brand-primary)' }}
>
<Save className="h-4 w-4 mr-2" />
{isEditTemplateOpen ? 'Update Template' : 'Save Template'}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
{/* Delete Confirmation Dialog */}
<Dialog open={isDeleteDialogOpen} onOpenChange={setIsDeleteDialogOpen}>
<DialogContent>
<DialogHeader>
<DialogTitle>Delete Template</DialogTitle>
<DialogDescription>
Are you sure you want to delete "{deletingTemplate?.name}"? This action cannot be undone.
{deletingTemplate?.usage > 0 && (
<div className="mt-2 p-3 bg-yellow-50 border border-yellow-200 rounded-lg">
<div className="flex items-center gap-2">
<AlertCircle className="h-4 w-4 text-yellow-600" />
<span className="text-sm text-yellow-800">
This template is currently used in {deletingTemplate.usage} profiler{deletingTemplate.usage > 1 ? 's' : ''}.
</span>
</div>
</div>
)}
</DialogDescription>
</DialogHeader>
<DialogFooter>
<Button
variant="outline"
onClick={() => setIsDeleteDialogOpen(false)}
className="min-h-[44px]"
>
Cancel
</Button>
<Button
variant="destructive"
onClick={confirmDelete}
className="min-h-[44px]"
>
<Trash2 className="h-4 w-4 mr-2" />
Delete Template
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
{/* Bulk Delete Confirmation Dialog */}
<Dialog open={isBulkDeleteDialogOpen} onOpenChange={setIsBulkDeleteDialogOpen}>
<DialogContent>
<DialogHeader>
<DialogTitle>Delete Selected Templates</DialogTitle>
<DialogDescription>
Are you sure you want to delete {selectedTemplates.length} selected template{selectedTemplates.length > 1 ? 's' : ''}?
This action cannot be undone.
</DialogDescription>
</DialogHeader>
<DialogFooter>
<Button
variant="outline"
onClick={() => setIsBulkDeleteDialogOpen(false)}
className="min-h-[44px]"
>
Cancel
</Button>
<Button
variant="destructive"
onClick={handleBulkDelete}
className="min-h-[44px]"
>
<Trash2 className="h-4 w-4 mr-2" />
Delete {selectedTemplates.length} Template{selectedTemplates.length > 1 ? 's' : ''}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</div>
</AuthenticatedLayout>
);
}