front end configuration ui enhanced
This commit is contained in:
parent
6b7837540b
commit
1b903dc56b
@ -158,9 +158,12 @@ export function ConfigurationManager({ onConfigUpdate }: ConfigurationManagerPro
|
|||||||
|
|
||||||
if (!config.isEditable) {
|
if (!config.isEditable) {
|
||||||
return (
|
return (
|
||||||
<div className="p-3 bg-gray-100 rounded-lg">
|
<div className="p-3 bg-slate-100 border border-slate-200 rounded-md">
|
||||||
<p className="text-sm text-gray-600 font-mono">{config.configValue}</p>
|
<p className="text-sm text-slate-700 font-mono">{config.configValue}</p>
|
||||||
<p className="text-xs text-gray-500 mt-1">This setting cannot be modified</p>
|
<p className="text-xs text-slate-500 mt-1.5 flex items-center gap-1">
|
||||||
|
<AlertCircle className="w-3 h-3" />
|
||||||
|
This setting cannot be modified
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -168,10 +171,13 @@ export function ConfigurationManager({ onConfigUpdate }: ConfigurationManagerPro
|
|||||||
switch (config.uiComponent || config.valueType.toLowerCase()) {
|
switch (config.uiComponent || config.valueType.toLowerCase()) {
|
||||||
case 'toggle':
|
case 'toggle':
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center justify-between p-3 bg-gray-50 rounded-lg">
|
<div className="flex items-center justify-between p-3 bg-slate-50 border border-slate-200 rounded-md hover:bg-slate-100 transition-colors">
|
||||||
<span className="text-sm font-medium">
|
<div className="flex items-center gap-2">
|
||||||
{currentValue === 'true' ? 'Enabled' : 'Disabled'}
|
<div className={`w-2 h-2 rounded-full ${currentValue === 'true' ? 'bg-green-500' : 'bg-slate-400'}`}></div>
|
||||||
</span>
|
<span className={`text-sm font-medium ${currentValue === 'true' ? 'text-green-700' : 'text-slate-600'}`}>
|
||||||
|
{currentValue === 'true' ? 'Enabled' : 'Disabled'}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
<Switch
|
<Switch
|
||||||
checked={currentValue === 'true'}
|
checked={currentValue === 'true'}
|
||||||
onCheckedChange={(checked) =>
|
onCheckedChange={(checked) =>
|
||||||
@ -187,10 +193,10 @@ export function ConfigurationManager({ onConfigUpdate }: ConfigurationManagerPro
|
|||||||
const min = config.validationRules?.min || 0;
|
const min = config.validationRules?.min || 0;
|
||||||
const max = config.validationRules?.max || 100;
|
const max = config.validationRules?.max || 100;
|
||||||
return (
|
return (
|
||||||
<div className="space-y-2">
|
<div className="space-y-3 p-3 bg-slate-50 border border-slate-200 rounded-md">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<span className="text-sm font-medium">{numValue}%</span>
|
<span className="text-lg font-semibold text-slate-900">{numValue}%</span>
|
||||||
<span className="text-xs text-gray-500">Range: {min}-{max}</span>
|
<span className="text-xs text-slate-500 bg-slate-100 px-2 py-1 rounded-sm border border-slate-200">Range: {min}-{max}</span>
|
||||||
</div>
|
</div>
|
||||||
<Slider
|
<Slider
|
||||||
value={[numValue]}
|
value={[numValue]}
|
||||||
@ -213,7 +219,7 @@ export function ConfigurationManager({ onConfigUpdate }: ConfigurationManagerPro
|
|||||||
disabled={isSaving}
|
disabled={isSaving}
|
||||||
min={config.validationRules?.min}
|
min={config.validationRules?.min}
|
||||||
max={config.validationRules?.max}
|
max={config.validationRules?.max}
|
||||||
className="font-mono"
|
className="font-mono border-slate-300 focus:border-blue-500 focus:ring-2 focus:ring-blue-500/20 rounded-md transition-all shadow-sm"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -226,7 +232,7 @@ export function ConfigurationManager({ onConfigUpdate }: ConfigurationManagerPro
|
|||||||
value={currentValue}
|
value={currentValue}
|
||||||
onChange={(e) => handleValueChange(config.configKey, e.target.value)}
|
onChange={(e) => handleValueChange(config.configKey, e.target.value)}
|
||||||
disabled={isSaving}
|
disabled={isSaving}
|
||||||
className="font-mono"
|
className="font-mono border-slate-300 focus:border-blue-500 focus:ring-2 focus:ring-blue-500/20 rounded-md transition-all shadow-sm"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -289,11 +295,13 @@ export function ConfigurationManager({ onConfigUpdate }: ConfigurationManagerPro
|
|||||||
|
|
||||||
if (configurations.length === 0) {
|
if (configurations.length === 0) {
|
||||||
return (
|
return (
|
||||||
<Card>
|
<Card className="shadow-lg border-0 rounded-md">
|
||||||
<CardContent className="p-12 text-center">
|
<CardContent className="p-12 text-center">
|
||||||
<Settings className="w-12 h-12 text-gray-400 mx-auto mb-4" />
|
<div className="p-4 bg-slate-100 rounded-full w-20 h-20 flex items-center justify-center mx-auto mb-4">
|
||||||
<p className="text-gray-600">No configurations found</p>
|
<Settings className="w-10 h-10 text-slate-400" />
|
||||||
<p className="text-sm text-gray-500 mt-2">
|
</div>
|
||||||
|
<p className="text-slate-700 font-medium text-lg">No configurations found</p>
|
||||||
|
<p className="text-sm text-slate-500 mt-2 max-w-md mx-auto">
|
||||||
System configurations will appear here once they are initialized
|
System configurations will appear here once they are initialized
|
||||||
</p>
|
</p>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
@ -307,22 +315,26 @@ export function ConfigurationManager({ onConfigUpdate }: ConfigurationManagerPro
|
|||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
{/* Success Message */}
|
{/* Success Message */}
|
||||||
{successMessage && (
|
{successMessage && (
|
||||||
<div className="p-4 bg-green-50 border border-green-200 rounded-lg flex items-center gap-3">
|
<div className="p-4 bg-gradient-to-r from-green-50 to-emerald-50 border border-green-300 rounded-md shadow-sm flex items-center gap-3 animate-in fade-in slide-in-from-top-2 duration-300">
|
||||||
<CheckCircle className="w-5 h-5 text-green-600 shrink-0" />
|
<div className="p-1.5 bg-green-500 rounded-md">
|
||||||
<p className="text-sm text-green-800">{successMessage}</p>
|
<CheckCircle className="w-4 h-4 text-white shrink-0" />
|
||||||
|
</div>
|
||||||
|
<p className="text-sm font-medium text-green-900">{successMessage}</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Error Message */}
|
{/* Error Message */}
|
||||||
{error && (
|
{error && (
|
||||||
<div className="p-4 bg-red-50 border border-red-200 rounded-lg flex items-center gap-3">
|
<div className="p-4 bg-gradient-to-r from-red-50 to-rose-50 border border-red-300 rounded-md shadow-sm flex items-center gap-3 animate-in fade-in slide-in-from-top-2 duration-300">
|
||||||
<AlertCircle className="w-5 h-5 text-red-600 shrink-0" />
|
<div className="p-1.5 bg-red-500 rounded-md">
|
||||||
<p className="text-sm text-red-800">{error}</p>
|
<AlertCircle className="w-4 h-4 text-white shrink-0" />
|
||||||
|
</div>
|
||||||
|
<p className="text-sm font-medium text-red-900">{error}</p>
|
||||||
<Button
|
<Button
|
||||||
size="sm"
|
size="sm"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
onClick={() => setError(null)}
|
onClick={() => setError(null)}
|
||||||
className="ml-auto"
|
className="ml-auto hover:bg-red-100"
|
||||||
>
|
>
|
||||||
Dismiss
|
Dismiss
|
||||||
</Button>
|
</Button>
|
||||||
@ -331,58 +343,64 @@ export function ConfigurationManager({ onConfigUpdate }: ConfigurationManagerPro
|
|||||||
|
|
||||||
{/* Configurations by Category */}
|
{/* Configurations by Category */}
|
||||||
<Tabs defaultValue={categories[0]} className="w-full">
|
<Tabs defaultValue={categories[0]} className="w-full">
|
||||||
<TabsList className="grid w-full" style={{ gridTemplateColumns: `repeat(${Math.min(categories.length, 5)}, 1fr)` }}>
|
<TabsList className="flex flex-wrap w-full bg-slate-100/80 backdrop-blur-sm p-1 gap-1 rounded-md h-auto border border-slate-200 shadow-sm">
|
||||||
{categories.map(category => (
|
{categories.map(category => (
|
||||||
<TabsTrigger key={category} value={category} className="text-xs sm:text-sm">
|
<TabsTrigger
|
||||||
{category.replace(/_/g, ' ')}
|
key={category}
|
||||||
|
value={category}
|
||||||
|
className="flex-1 min-w-[120px] text-[10px] xs:text-xs sm:text-sm font-medium py-2 sm:py-2.5 px-2 sm:px-3 rounded-sm data-[state=active]:bg-white data-[state=active]:shadow-sm data-[state=active]:text-slate-900 transition-all"
|
||||||
|
>
|
||||||
|
<span className="truncate block">
|
||||||
|
{category.replace(/_/g, ' ')}
|
||||||
|
</span>
|
||||||
</TabsTrigger>
|
</TabsTrigger>
|
||||||
))}
|
))}
|
||||||
</TabsList>
|
</TabsList>
|
||||||
|
|
||||||
{categories.map(category => (
|
{categories.map(category => (
|
||||||
<TabsContent key={category} value={category} className="space-y-4 mt-6">
|
<TabsContent key={category} value={category} className="space-y-4 mt-6">
|
||||||
<Card>
|
<Card className="shadow-lg border-0 rounded-md">
|
||||||
<CardHeader className="pb-4">
|
<CardHeader className="pb-4 border-b border-slate-100">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<div className={`p-3 rounded-lg ${getCategoryColor(category)}`}>
|
<div className={`p-2.5 rounded-md shadow-sm ${getCategoryColor(category)}`}>
|
||||||
{getCategoryIcon(category)}
|
{getCategoryIcon(category)}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<CardTitle className="text-lg">
|
<CardTitle className="text-lg font-semibold text-slate-900">
|
||||||
{category.replace(/_/g, ' ')}
|
{category.replace(/_/g, ' ')}
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
<CardDescription>
|
<CardDescription className="text-sm">
|
||||||
{groupedConfigs[category].length} setting{groupedConfigs[category].length !== 1 ? 's' : ''}
|
{groupedConfigs[category].length} setting{groupedConfigs[category].length !== 1 ? 's' : ''} available
|
||||||
</CardDescription>
|
</CardDescription>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="space-y-6">
|
<CardContent className="space-y-6">
|
||||||
{groupedConfigs[category].map(config => (
|
{groupedConfigs[category].map(config => (
|
||||||
<div key={config.configKey} className="space-y-3 pb-6 border-b last:border-b-0 last:pb-0">
|
<div key={config.configKey} className="space-y-3 pb-6 border-b border-slate-100 last:border-b-0 last:pb-0 hover:bg-slate-50/50 -mx-6 px-6 py-4 rounded-md transition-colors">
|
||||||
<div className="flex items-start justify-between gap-4">
|
<div className="flex items-start justify-between gap-4">
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<div className="flex items-center gap-2 mb-1">
|
<div className="flex items-center gap-2 mb-1.5 flex-wrap">
|
||||||
<Label className="text-sm font-semibold text-gray-900">
|
<Label className="text-sm font-semibold text-slate-900">
|
||||||
{config.displayName}
|
{config.displayName}
|
||||||
</Label>
|
</Label>
|
||||||
{hasChanges(config) && (
|
{hasChanges(config) && (
|
||||||
<Badge variant="outline" className="text-xs bg-yellow-50 text-yellow-700 border-yellow-300">
|
<Badge variant="outline" className="text-xs bg-gradient-to-r from-yellow-50 to-amber-50 text-yellow-800 border-yellow-400 font-medium shadow-sm">
|
||||||
Modified
|
Modified
|
||||||
</Badge>
|
</Badge>
|
||||||
)}
|
)}
|
||||||
{config.requiresRestart && (
|
{config.requiresRestart && (
|
||||||
<Badge variant="outline" className="text-xs bg-orange-50 text-orange-700 border-orange-300">
|
<Badge variant="outline" className="text-xs bg-gradient-to-r from-orange-50 to-red-50 text-orange-800 border-orange-400 font-medium shadow-sm">
|
||||||
Requires Restart
|
Requires Restart
|
||||||
</Badge>
|
</Badge>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{config.description && (
|
{config.description && (
|
||||||
<p className="text-xs text-gray-600 mt-1">{config.description}</p>
|
<p className="text-xs text-slate-600 mt-1 leading-relaxed">{config.description}</p>
|
||||||
)}
|
)}
|
||||||
{config.defaultValue && (
|
{config.defaultValue && (
|
||||||
<p className="text-xs text-gray-500 mt-1">
|
<p className="text-xs text-slate-500 mt-2">
|
||||||
Default: <code className="px-1.5 py-0.5 bg-gray-100 rounded">{config.defaultValue}</code>
|
Default: <code className="px-2 py-0.5 bg-slate-100 text-slate-700 rounded-sm font-mono text-xs border border-slate-200">{config.defaultValue}</code>
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@ -391,12 +409,12 @@ export function ConfigurationManager({ onConfigUpdate }: ConfigurationManagerPro
|
|||||||
{renderConfigInput(config)}
|
{renderConfigInput(config)}
|
||||||
|
|
||||||
{config.isEditable && (
|
{config.isEditable && (
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2 flex-wrap">
|
||||||
<Button
|
<Button
|
||||||
size="sm"
|
size="sm"
|
||||||
onClick={() => handleSave(config)}
|
onClick={() => handleSave(config)}
|
||||||
disabled={!hasChanges(config) || saving === config.configKey}
|
disabled={!hasChanges(config) || saving === config.configKey}
|
||||||
className="gap-2"
|
className="gap-2 bg-gradient-to-r from-blue-600 to-blue-700 hover:from-blue-700 hover:to-blue-800 shadow-sm disabled:opacity-50 disabled:cursor-not-allowed"
|
||||||
>
|
>
|
||||||
{saving === config.configKey ? (
|
{saving === config.configKey ? (
|
||||||
<>
|
<>
|
||||||
@ -406,7 +424,7 @@ export function ConfigurationManager({ onConfigUpdate }: ConfigurationManagerPro
|
|||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<Save className="w-4 h-4" />
|
<Save className="w-4 h-4" />
|
||||||
Save
|
Save Changes
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
@ -416,7 +434,7 @@ export function ConfigurationManager({ onConfigUpdate }: ConfigurationManagerPro
|
|||||||
variant="outline"
|
variant="outline"
|
||||||
onClick={() => handleReset(config)}
|
onClick={() => handleReset(config)}
|
||||||
disabled={saving === config.configKey}
|
disabled={saving === config.configKey}
|
||||||
className="gap-2"
|
className="gap-2 border-slate-300 hover:bg-slate-50 hover:border-slate-400 shadow-sm"
|
||||||
>
|
>
|
||||||
<RotateCcw className="w-4 h-4" />
|
<RotateCcw className="w-4 h-4" />
|
||||||
Reset to Default
|
Reset to Default
|
||||||
|
|||||||
@ -135,13 +135,13 @@ export function HolidayManager() {
|
|||||||
const getTypeColor = (type: Holiday['holidayType']) => {
|
const getTypeColor = (type: Holiday['holidayType']) => {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'NATIONAL':
|
case 'NATIONAL':
|
||||||
return 'bg-red-100 text-red-800 border-red-200';
|
return 'bg-gradient-to-r from-red-50 to-rose-50 text-red-800 border-red-300';
|
||||||
case 'REGIONAL':
|
case 'REGIONAL':
|
||||||
return 'bg-blue-100 text-blue-800 border-blue-200';
|
return 'bg-gradient-to-r from-blue-50 to-cyan-50 text-blue-800 border-blue-300';
|
||||||
case 'ORGANIZATIONAL':
|
case 'ORGANIZATIONAL':
|
||||||
return 'bg-purple-100 text-purple-800 border-purple-200';
|
return 'bg-gradient-to-r from-purple-50 to-violet-50 text-purple-800 border-purple-300';
|
||||||
case 'OPTIONAL':
|
case 'OPTIONAL':
|
||||||
return 'bg-gray-100 text-gray-800 border-gray-200';
|
return 'bg-gradient-to-r from-slate-50 to-gray-50 text-slate-700 border-slate-300';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -168,22 +168,26 @@ export function HolidayManager() {
|
|||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
{/* Success Message */}
|
{/* Success Message */}
|
||||||
{successMessage && (
|
{successMessage && (
|
||||||
<div className="p-4 bg-green-50 border border-green-200 rounded-lg flex items-center gap-3">
|
<div className="p-4 bg-gradient-to-r from-green-50 to-emerald-50 border border-green-300 rounded-md shadow-sm flex items-center gap-3 animate-in fade-in slide-in-from-top-2 duration-300">
|
||||||
<CheckCircle className="w-5 h-5 text-green-600 shrink-0" />
|
<div className="p-1.5 bg-green-500 rounded-md">
|
||||||
<p className="text-sm text-green-800">{successMessage}</p>
|
<CheckCircle className="w-4 h-4 text-white shrink-0" />
|
||||||
|
</div>
|
||||||
|
<p className="text-sm font-medium text-green-900">{successMessage}</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Error Message */}
|
{/* Error Message */}
|
||||||
{error && (
|
{error && (
|
||||||
<div className="p-4 bg-red-50 border border-red-200 rounded-lg flex items-center gap-3">
|
<div className="p-4 bg-gradient-to-r from-red-50 to-rose-50 border border-red-300 rounded-md shadow-sm flex items-center gap-3 animate-in fade-in slide-in-from-top-2 duration-300">
|
||||||
<AlertCircle className="w-5 h-5 text-red-600 shrink-0" />
|
<div className="p-1.5 bg-red-500 rounded-md">
|
||||||
<p className="text-sm text-red-800">{error}</p>
|
<AlertCircle className="w-4 h-4 text-white shrink-0" />
|
||||||
|
</div>
|
||||||
|
<p className="text-sm font-medium text-red-900">{error}</p>
|
||||||
<Button
|
<Button
|
||||||
size="sm"
|
size="sm"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
onClick={() => setError(null)}
|
onClick={() => setError(null)}
|
||||||
className="ml-auto"
|
className="ml-auto hover:bg-red-100"
|
||||||
>
|
>
|
||||||
Dismiss
|
Dismiss
|
||||||
</Button>
|
</Button>
|
||||||
@ -191,26 +195,26 @@ export function HolidayManager() {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<Card>
|
<Card className="shadow-lg border-0 rounded-md">
|
||||||
<CardHeader>
|
<CardHeader className="border-b border-slate-100 py-4 sm:py-5">
|
||||||
<div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4">
|
<div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3 sm:gap-4">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<div className="p-3 bg-blue-100 rounded-lg">
|
<div className="p-2.5 bg-gradient-to-br from-blue-500 to-blue-600 rounded-md shadow-md">
|
||||||
<Calendar className="w-6 h-6 text-blue-600" />
|
<Calendar className="w-5 h-5 text-white" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<CardTitle className="text-xl">Holiday Calendar</CardTitle>
|
<CardTitle className="text-lg sm:text-xl font-semibold text-slate-900">Holiday Calendar</CardTitle>
|
||||||
<CardDescription>
|
<CardDescription className="text-sm">
|
||||||
Manage organization holidays for TAT calculations
|
Manage organization holidays for TAT calculations
|
||||||
</CardDescription>
|
</CardDescription>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-2 sm:gap-3 w-full sm:w-auto">
|
||||||
<Select value={selectedYear.toString()} onValueChange={(v) => setSelectedYear(parseInt(v))}>
|
<Select value={selectedYear.toString()} onValueChange={(v) => setSelectedYear(parseInt(v))}>
|
||||||
<SelectTrigger className="w-32">
|
<SelectTrigger className="w-24 sm:w-32 border-slate-300 focus:border-blue-500 focus:ring-2 focus:ring-blue-500/20 rounded-md transition-all shadow-sm">
|
||||||
<SelectValue />
|
<SelectValue />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent className="rounded-md">
|
||||||
{years.map(year => (
|
{years.map(year => (
|
||||||
<SelectItem key={year} value={year.toString()}>
|
<SelectItem key={year} value={year.toString()}>
|
||||||
{year}
|
{year}
|
||||||
@ -218,9 +222,13 @@ export function HolidayManager() {
|
|||||||
))}
|
))}
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
<Button onClick={handleAdd} className="gap-2">
|
<Button
|
||||||
|
onClick={handleAdd}
|
||||||
|
className="gap-2 bg-gradient-to-r from-blue-600 to-blue-700 hover:from-blue-700 hover:to-blue-800 shadow-sm flex-1 sm:flex-initial"
|
||||||
|
>
|
||||||
<Plus className="w-4 h-4" />
|
<Plus className="w-4 h-4" />
|
||||||
Add Holiday
|
<span className="hidden xs:inline">Add Holiday</span>
|
||||||
|
<span className="xs:hidden">Add</span>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -233,69 +241,83 @@ export function HolidayManager() {
|
|||||||
<Loader2 className="w-8 h-8 animate-spin text-gray-400" />
|
<Loader2 className="w-8 h-8 animate-spin text-gray-400" />
|
||||||
</div>
|
</div>
|
||||||
) : holidays.length === 0 ? (
|
) : holidays.length === 0 ? (
|
||||||
<Card>
|
<Card className="shadow-lg border-0 rounded-md">
|
||||||
<CardContent className="p-12 text-center">
|
<CardContent className="p-12 text-center">
|
||||||
<Calendar className="w-12 h-12 text-gray-400 mx-auto mb-4" />
|
<div className="p-4 bg-slate-100 rounded-full w-20 h-20 flex items-center justify-center mx-auto mb-4">
|
||||||
<p className="text-gray-600">No holidays found for {selectedYear}</p>
|
<Calendar className="w-10 h-10 text-slate-400" />
|
||||||
<Button onClick={handleAdd} variant="outline" className="mt-4 gap-2">
|
</div>
|
||||||
|
<p className="text-slate-700 font-medium text-lg">No holidays found for {selectedYear}</p>
|
||||||
|
<p className="text-sm text-slate-500 mt-2 mb-6">Add holidays to exclude them from TAT calculations</p>
|
||||||
|
<Button
|
||||||
|
onClick={handleAdd}
|
||||||
|
variant="outline"
|
||||||
|
className="gap-2 border-slate-300 hover:bg-slate-50 hover:border-slate-400 shadow-sm"
|
||||||
|
>
|
||||||
<Plus className="w-4 h-4" />
|
<Plus className="w-4 h-4" />
|
||||||
Add First Holiday
|
Add First Holiday
|
||||||
</Button>
|
</Button>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
) : (
|
) : (
|
||||||
<div className="space-y-6">
|
<div className="space-y-4 sm:space-y-6">
|
||||||
{sortedMonths.map(month => (
|
{sortedMonths.map(month => (
|
||||||
<Card key={month}>
|
<Card key={month} className="shadow-lg border-0 rounded-md">
|
||||||
<CardHeader className="pb-4">
|
<CardHeader className="pb-3 sm:pb-4 border-b border-slate-100">
|
||||||
<CardTitle className="text-lg">{month} {selectedYear}</CardTitle>
|
<div className="flex items-center justify-between">
|
||||||
<CardDescription>
|
<div>
|
||||||
{holidaysByMonth[month].length} holiday{holidaysByMonth[month].length !== 1 ? 's' : ''}
|
<CardTitle className="text-base sm:text-lg font-semibold text-slate-900">{month} {selectedYear}</CardTitle>
|
||||||
</CardDescription>
|
<CardDescription className="text-xs sm:text-sm">
|
||||||
|
{holidaysByMonth[month].length} holiday{holidaysByMonth[month].length !== 1 ? 's' : ''}
|
||||||
|
</CardDescription>
|
||||||
|
</div>
|
||||||
|
<div className="p-2 bg-blue-50 rounded-md">
|
||||||
|
<Calendar className="w-4 h-4 text-blue-600" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="space-y-3">
|
<CardContent className="space-y-3 pt-4">
|
||||||
{holidaysByMonth[month].map(holiday => (
|
{holidaysByMonth[month].map(holiday => (
|
||||||
<div
|
<div
|
||||||
key={holiday.holidayId}
|
key={holiday.holidayId}
|
||||||
className="flex items-center justify-between p-4 bg-gray-50 rounded-lg hover:bg-gray-100 transition-colors"
|
className="flex flex-col sm:flex-row sm:items-center justify-between gap-3 sm:gap-4 p-3 sm:p-4 bg-slate-50 border border-slate-200 rounded-md hover:bg-slate-100 hover:border-slate-300 transition-all shadow-sm"
|
||||||
>
|
>
|
||||||
<div className="flex-1">
|
<div className="flex-1 min-w-0">
|
||||||
<div className="flex items-center gap-3 mb-2">
|
<div className="flex items-center gap-2 mb-2 flex-wrap">
|
||||||
<p className="font-semibold text-gray-900">{holiday.holidayName}</p>
|
<p className="font-semibold text-slate-900 text-sm sm:text-base truncate">{holiday.holidayName}</p>
|
||||||
<Badge variant="outline" className={getTypeColor(holiday.holidayType)}>
|
<Badge variant="outline" className={`${getTypeColor(holiday.holidayType)} text-[10px] sm:text-xs font-medium shadow-sm`}>
|
||||||
{holiday.holidayType}
|
{holiday.holidayType}
|
||||||
</Badge>
|
</Badge>
|
||||||
{holiday.isRecurring && (
|
{holiday.isRecurring && (
|
||||||
<Badge variant="outline" className="bg-indigo-50 text-indigo-700 border-indigo-200">
|
<Badge variant="outline" className="bg-gradient-to-r from-indigo-50 to-purple-50 text-indigo-700 border-indigo-300 text-[10px] sm:text-xs font-medium shadow-sm">
|
||||||
Recurring
|
Recurring
|
||||||
</Badge>
|
</Badge>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<p className="text-sm text-gray-600">
|
<p className="text-xs sm:text-sm text-slate-600 font-medium">
|
||||||
{formatDateShort(holiday.holidayDate)}
|
{formatDateShort(holiday.holidayDate)}
|
||||||
</p>
|
</p>
|
||||||
{holiday.description && (
|
{holiday.description && (
|
||||||
<p className="text-xs text-gray-500 mt-1">{holiday.description}</p>
|
<p className="text-xs text-slate-500 mt-1.5 line-clamp-2">{holiday.description}</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2 sm:gap-2 self-end sm:self-auto">
|
||||||
<Button
|
<Button
|
||||||
size="sm"
|
size="sm"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
onClick={() => handleEdit(holiday)}
|
onClick={() => handleEdit(holiday)}
|
||||||
className="gap-2"
|
className="gap-1.5 hover:bg-blue-50 border border-transparent hover:border-blue-200 text-xs sm:text-sm"
|
||||||
>
|
>
|
||||||
<Edit2 className="w-4 h-4" />
|
<Edit2 className="w-3.5 h-3.5 sm:w-4 sm:h-4" />
|
||||||
Edit
|
<span className="hidden xs:inline">Edit</span>
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
size="sm"
|
size="sm"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
onClick={() => handleDelete(holiday)}
|
onClick={() => handleDelete(holiday)}
|
||||||
className="gap-2 text-red-600 hover:text-red-700 hover:bg-red-50"
|
className="gap-1.5 text-red-600 hover:text-red-700 hover:bg-red-50 border border-transparent hover:border-red-200 text-xs sm:text-sm"
|
||||||
>
|
>
|
||||||
<Trash2 className="w-4 h-4" />
|
<Trash2 className="w-3.5 h-3.5 sm:w-4 sm:h-4" />
|
||||||
Delete
|
<span className="hidden xs:inline">Delete</span>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -308,59 +330,62 @@ export function HolidayManager() {
|
|||||||
|
|
||||||
{/* Add/Edit Dialog */}
|
{/* Add/Edit Dialog */}
|
||||||
<Dialog open={showAddDialog} onOpenChange={setShowAddDialog}>
|
<Dialog open={showAddDialog} onOpenChange={setShowAddDialog}>
|
||||||
<DialogContent className="sm:max-w-[500px]">
|
<DialogContent className="sm:max-w-[500px] rounded-md">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>
|
<DialogTitle className="text-lg sm:text-xl font-semibold text-slate-900">
|
||||||
{editingHoliday ? 'Edit Holiday' : 'Add New Holiday'}
|
{editingHoliday ? 'Edit Holiday' : 'Add New Holiday'}
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogDescription>
|
<DialogDescription className="text-sm text-slate-600">
|
||||||
{editingHoliday ? 'Update holiday information' : 'Add a new holiday to the calendar'}
|
{editingHoliday ? 'Update holiday information' : 'Add a new holiday to the calendar'}
|
||||||
</DialogDescription>
|
</DialogDescription>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
|
|
||||||
<div className="space-y-4 py-4">
|
<div className="space-y-4 py-4">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label htmlFor="date">Date *</Label>
|
<Label htmlFor="date" className="text-sm font-medium text-slate-900">Date *</Label>
|
||||||
<Input
|
<Input
|
||||||
id="date"
|
id="date"
|
||||||
type="date"
|
type="date"
|
||||||
value={formData.holidayDate}
|
value={formData.holidayDate}
|
||||||
onChange={(e) => setFormData({ ...formData, holidayDate: e.target.value })}
|
onChange={(e) => setFormData({ ...formData, holidayDate: e.target.value })}
|
||||||
|
className="border-slate-300 focus:border-blue-500 focus:ring-2 focus:ring-blue-500/20 rounded-md transition-all shadow-sm"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label htmlFor="name">Holiday Name *</Label>
|
<Label htmlFor="name" className="text-sm font-medium text-slate-900">Holiday Name *</Label>
|
||||||
<Input
|
<Input
|
||||||
id="name"
|
id="name"
|
||||||
placeholder="e.g., Diwali, Republic Day"
|
placeholder="e.g., Diwali, Republic Day"
|
||||||
value={formData.holidayName}
|
value={formData.holidayName}
|
||||||
onChange={(e) => setFormData({ ...formData, holidayName: e.target.value })}
|
onChange={(e) => setFormData({ ...formData, holidayName: e.target.value })}
|
||||||
|
className="border-slate-300 focus:border-blue-500 focus:ring-2 focus:ring-blue-500/20 rounded-md transition-all shadow-sm"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label htmlFor="description">Description</Label>
|
<Label htmlFor="description" className="text-sm font-medium text-slate-900">Description</Label>
|
||||||
<Input
|
<Input
|
||||||
id="description"
|
id="description"
|
||||||
placeholder="Optional description"
|
placeholder="Optional description"
|
||||||
value={formData.description}
|
value={formData.description}
|
||||||
onChange={(e) => setFormData({ ...formData, description: e.target.value })}
|
onChange={(e) => setFormData({ ...formData, description: e.target.value })}
|
||||||
|
className="border-slate-300 focus:border-blue-500 focus:ring-2 focus:ring-blue-500/20 rounded-md transition-all shadow-sm"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label htmlFor="type">Holiday Type</Label>
|
<Label htmlFor="type" className="text-sm font-medium text-slate-900">Holiday Type</Label>
|
||||||
<Select
|
<Select
|
||||||
value={formData.holidayType}
|
value={formData.holidayType}
|
||||||
onValueChange={(value: Holiday['holidayType']) =>
|
onValueChange={(value: Holiday['holidayType']) =>
|
||||||
setFormData({ ...formData, holidayType: value })
|
setFormData({ ...formData, holidayType: value })
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<SelectTrigger id="type">
|
<SelectTrigger id="type" className="border-slate-300 focus:border-blue-500 focus:ring-2 focus:ring-blue-500/20 rounded-md transition-all shadow-sm">
|
||||||
<SelectValue />
|
<SelectValue />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent className="rounded-md">
|
||||||
<SelectItem value="NATIONAL">National</SelectItem>
|
<SelectItem value="NATIONAL">National</SelectItem>
|
||||||
<SelectItem value="REGIONAL">Regional</SelectItem>
|
<SelectItem value="REGIONAL">Regional</SelectItem>
|
||||||
<SelectItem value="ORGANIZATIONAL">Organizational</SelectItem>
|
<SelectItem value="ORGANIZATIONAL">Organizational</SelectItem>
|
||||||
@ -369,25 +394,32 @@ export function HolidayManager() {
|
|||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center gap-2 p-3 bg-slate-50 border border-slate-200 rounded-md hover:bg-slate-100 transition-colors">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
id="recurring"
|
id="recurring"
|
||||||
checked={formData.isRecurring}
|
checked={formData.isRecurring}
|
||||||
onChange={(e) => setFormData({ ...formData, isRecurring: e.target.checked })}
|
onChange={(e) => setFormData({ ...formData, isRecurring: e.target.checked })}
|
||||||
className="rounded border-gray-300"
|
className="rounded border-slate-300 text-blue-600 focus:ring-2 focus:ring-blue-500/20 focus:ring-offset-0 w-4 h-4 cursor-pointer"
|
||||||
/>
|
/>
|
||||||
<Label htmlFor="recurring" className="font-normal cursor-pointer">
|
<Label htmlFor="recurring" className="font-normal cursor-pointer text-sm text-slate-700">
|
||||||
This holiday recurs annually
|
This holiday recurs annually
|
||||||
</Label>
|
</Label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<DialogFooter>
|
<DialogFooter className="gap-2">
|
||||||
<Button variant="outline" onClick={() => setShowAddDialog(false)}>
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
onClick={() => setShowAddDialog(false)}
|
||||||
|
className="border-slate-300 hover:bg-slate-50 hover:border-slate-400 shadow-sm"
|
||||||
|
>
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
<Button onClick={handleSave}>
|
<Button
|
||||||
|
onClick={handleSave}
|
||||||
|
className="bg-gradient-to-r from-blue-600 to-blue-700 hover:from-blue-700 hover:to-blue-800 shadow-sm"
|
||||||
|
>
|
||||||
{editingHoliday ? 'Update' : 'Add'} Holiday
|
{editingHoliday ? 'Update' : 'Add'} Holiday
|
||||||
</Button>
|
</Button>
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
|
|||||||
@ -18,73 +18,207 @@ import { HolidayManager } from '@/components/admin/HolidayManager';
|
|||||||
|
|
||||||
export function Settings() {
|
export function Settings() {
|
||||||
const { user } = useAuth();
|
const { user } = useAuth();
|
||||||
return (
|
const isAdmin = (user as any)?.isAdmin;
|
||||||
<div className="space-y-6 max-w-7xl mx-auto">
|
|
||||||
{/* Header Card */}
|
|
||||||
<Card className="relative overflow-hidden shadow-xl border-0">
|
|
||||||
<div className="absolute inset-0 bg-gradient-to-br from-slate-900 via-slate-800 to-slate-900"></div>
|
|
||||||
|
|
||||||
<CardContent className="relative z-10 p-8 lg:p-12">
|
return (
|
||||||
<div className="flex flex-col md:flex-row items-start md:items-center justify-between gap-6">
|
<div className="min-h-screen pb-8">
|
||||||
<div className="text-white">
|
<div className="max-w-7xl mx-auto space-y-6">
|
||||||
<div className="flex items-center gap-4 mb-4">
|
{/* Header Card */}
|
||||||
<div className="w-16 h-16 bg-yellow-400 rounded-xl flex items-center justify-center shadow-lg">
|
<Card className="relative overflow-hidden shadow-2xl border-0 rounded-2xl">
|
||||||
<SettingsIcon className="w-8 h-8 text-slate-900" />
|
<div className="absolute inset-0 bg-gradient-to-br from-slate-900 via-slate-800 to-slate-900"></div>
|
||||||
</div>
|
<div className="absolute inset-0 bg-[radial-gradient(ellipse_at_top_right,_var(--tw-gradient-stops))] from-yellow-400/20 via-transparent to-transparent"></div>
|
||||||
<div>
|
|
||||||
<h1 className="text-3xl font-bold mb-2 text-white">Settings</h1>
|
<CardContent className="relative z-10 p-6 sm:p-8 lg:p-12">
|
||||||
<p className="text-lg text-gray-200">Manage your account settings and preferences</p>
|
<div className="flex items-center gap-4 sm:gap-6">
|
||||||
</div>
|
<div className="w-14 h-14 sm:w-16 sm:h-16 bg-gradient-to-br from-yellow-400 to-yellow-500 rounded-2xl flex items-center justify-center shadow-xl transform hover:scale-105 transition-transform">
|
||||||
|
<SettingsIcon className="w-7 h-7 sm:w-8 sm:h-8 text-slate-900" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h1 className="text-2xl sm:text-3xl lg:text-4xl font-bold text-white mb-1 sm:mb-2">Settings</h1>
|
||||||
|
<p className="text-sm sm:text-base lg:text-lg text-gray-300">Manage your account and preferences</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</CardContent>
|
||||||
</CardContent>
|
</Card>
|
||||||
</Card>
|
|
||||||
|
|
||||||
{/* Check if user is admin */}
|
{/* Tabs for Admin, Cards for Non-Admin */}
|
||||||
{(user as any)?.isAdmin ? (
|
{isAdmin ? (
|
||||||
<Tabs defaultValue="user" className="w-full">
|
<Tabs defaultValue="user" className="w-full">
|
||||||
<TabsList className="grid w-full grid-cols-3 mb-6">
|
<TabsList className="grid w-full grid-cols-3 mb-8 bg-slate-100 p-1 rounded-xl h-auto">
|
||||||
<TabsTrigger value="user" className="flex items-center gap-2">
|
<TabsTrigger
|
||||||
<SettingsIcon className="w-4 h-4" />
|
value="user"
|
||||||
User Settings
|
className="flex items-center justify-center gap-2 py-3 rounded-lg data-[state=active]:bg-white data-[state=active]:shadow-md transition-all"
|
||||||
</TabsTrigger>
|
>
|
||||||
<TabsTrigger value="system" className="flex items-center gap-2">
|
<SettingsIcon className="w-4 h-4" />
|
||||||
<Sliders className="w-4 h-4" />
|
<span className="hidden sm:inline">User Settings</span>
|
||||||
System Configuration
|
<span className="sm:hidden">User</span>
|
||||||
</TabsTrigger>
|
</TabsTrigger>
|
||||||
<TabsTrigger value="holidays" className="flex items-center gap-2">
|
<TabsTrigger
|
||||||
<Calendar className="w-4 h-4" />
|
value="system"
|
||||||
Holiday Calendar
|
className="flex items-center justify-center gap-2 py-3 rounded-lg data-[state=active]:bg-white data-[state=active]:shadow-md transition-all"
|
||||||
</TabsTrigger>
|
>
|
||||||
</TabsList>
|
<Sliders className="w-4 h-4" />
|
||||||
|
<span className="hidden sm:inline">Configuration</span>
|
||||||
|
<span className="sm:hidden">Config</span>
|
||||||
|
</TabsTrigger>
|
||||||
|
<TabsTrigger
|
||||||
|
value="holidays"
|
||||||
|
className="flex items-center justify-center gap-2 py-3 rounded-lg data-[state=active]:bg-white data-[state=active]:shadow-md transition-all"
|
||||||
|
>
|
||||||
|
<Calendar className="w-4 h-4" />
|
||||||
|
<span className="hidden sm:inline">Holidays</span>
|
||||||
|
<span className="sm:hidden">Holidays</span>
|
||||||
|
</TabsTrigger>
|
||||||
|
</TabsList>
|
||||||
|
|
||||||
{/* User Settings Tab */}
|
{/* Fixed width container to prevent layout shifts */}
|
||||||
<TabsContent value="user" className="space-y-6">
|
<div className="w-full min-h-[600px]">
|
||||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
{/* User Settings Tab */}
|
||||||
|
<TabsContent value="user" className="mt-0 space-y-0">
|
||||||
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4 sm:gap-6">
|
||||||
|
{/* Notification Settings */}
|
||||||
|
<Card className="shadow-lg hover:shadow-xl transition-all duration-300 border-0 rounded-md group">
|
||||||
|
<CardHeader className="pb-4">
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<div className="p-3 bg-gradient-to-br from-blue-500 to-blue-600 rounded-md shadow-md group-hover:shadow-lg transition-shadow">
|
||||||
|
<Bell className="h-5 w-5 text-white" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<CardTitle className="text-lg font-semibold text-gray-900">Notifications</CardTitle>
|
||||||
|
<CardDescription className="text-sm text-gray-600">Manage notification preferences</CardDescription>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="space-y-4">
|
||||||
|
<Button
|
||||||
|
onClick={async () => {
|
||||||
|
try {
|
||||||
|
await setupPushNotifications();
|
||||||
|
alert('Notifications enabled');
|
||||||
|
} catch (e) {
|
||||||
|
alert('Failed to enable notifications');
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
className="w-full bg-gradient-to-r from-blue-500 to-blue-600 hover:from-blue-600 hover:to-blue-700 text-white shadow-md hover:shadow-lg transition-all"
|
||||||
|
>
|
||||||
|
<Bell className="w-4 h-4 mr-2" />
|
||||||
|
Enable Push Notifications
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
{/* Security Settings */}
|
||||||
|
<Card className="shadow-lg hover:shadow-xl transition-all duration-300 border-0 rounded-md group">
|
||||||
|
<CardHeader className="pb-4">
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<div className="p-3 bg-gradient-to-br from-red-500 to-red-600 rounded-md shadow-md group-hover:shadow-lg transition-shadow">
|
||||||
|
<Lock className="h-5 w-5 text-white" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<CardTitle className="text-lg font-semibold text-gray-900">Security</CardTitle>
|
||||||
|
<CardDescription className="text-sm text-gray-600">Password and security settings</CardDescription>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="space-y-4">
|
||||||
|
<div className="p-4 bg-gradient-to-br from-gray-50 to-gray-100 rounded-md border border-gray-200">
|
||||||
|
<p className="text-sm text-gray-600 text-center">Security settings will be available soon</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
{/* Appearance Settings */}
|
||||||
|
<Card className="shadow-lg hover:shadow-xl transition-all duration-300 border-0 rounded-md group">
|
||||||
|
<CardHeader className="pb-4">
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<div className="p-3 bg-gradient-to-br from-purple-500 to-purple-600 rounded-md shadow-md group-hover:shadow-lg transition-shadow">
|
||||||
|
<Palette className="h-5 w-5 text-white" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<CardTitle className="text-lg font-semibold text-gray-900">Appearance</CardTitle>
|
||||||
|
<CardDescription className="text-sm text-gray-600">Theme and display preferences</CardDescription>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="space-y-4">
|
||||||
|
<div className="p-4 bg-gradient-to-br from-gray-50 to-gray-100 rounded-md border border-gray-200">
|
||||||
|
<p className="text-sm text-gray-600 text-center">Appearance settings will be available soon</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
{/* Preferences */}
|
||||||
|
<Card className="shadow-lg hover:shadow-xl transition-all duration-300 border-0 rounded-md group">
|
||||||
|
<CardHeader className="pb-4">
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<div className="p-3 bg-gradient-to-br from-emerald-500 to-emerald-600 rounded-md shadow-md group-hover:shadow-lg transition-shadow">
|
||||||
|
<Shield className="h-5 w-5 text-white" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<CardTitle className="text-lg font-semibold text-gray-900">Preferences</CardTitle>
|
||||||
|
<CardDescription className="text-sm text-gray-600">Application preferences</CardDescription>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="space-y-4">
|
||||||
|
<div className="p-4 bg-gradient-to-br from-gray-50 to-gray-100 rounded-xl border border-gray-200">
|
||||||
|
<p className="text-sm text-gray-600 text-center">User preferences will be available soon</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
</TabsContent>
|
||||||
|
|
||||||
|
{/* System Configuration Tab (Admin Only) */}
|
||||||
|
<TabsContent value="system" className="mt-0">
|
||||||
|
<ConfigurationManager />
|
||||||
|
</TabsContent>
|
||||||
|
|
||||||
|
{/* Holiday Calendar Tab (Admin Only) */}
|
||||||
|
<TabsContent value="holidays" className="mt-0">
|
||||||
|
<HolidayManager />
|
||||||
|
</TabsContent>
|
||||||
|
</div>
|
||||||
|
</Tabs>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
{/* Non-Admin User Settings Only */}
|
||||||
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4 sm:gap-6">
|
||||||
{/* Notification Settings */}
|
{/* Notification Settings */}
|
||||||
<Card className="shadow-lg hover:shadow-xl transition-shadow">
|
<Card className="shadow-lg hover:shadow-xl transition-all duration-300 border-0 rounded-md group">
|
||||||
<CardHeader className="pb-4">
|
<CardHeader className="pb-4">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<div className="p-3 bg-blue-100 rounded-lg">
|
<div className="p-3 bg-gradient-to-br from-blue-500 to-blue-600 rounded-md shadow-md group-hover:shadow-lg transition-shadow">
|
||||||
<Bell className="h-5 w-5 text-blue-600" />
|
<Bell className="h-5 w-5 text-white" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<CardTitle className="text-lg text-gray-900">Notifications</CardTitle>
|
<CardTitle className="text-lg font-semibold text-gray-900">Notifications</CardTitle>
|
||||||
<CardDescription className="text-gray-600">Manage notification preferences</CardDescription>
|
<CardDescription className="text-sm text-gray-600">Manage notification preferences</CardDescription>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<Button onClick={async () => {
|
<Button
|
||||||
try {
|
onClick={async () => {
|
||||||
await setupPushNotifications();
|
try {
|
||||||
alert('Notifications enabled');
|
await setupPushNotifications();
|
||||||
} catch (e) {
|
alert('Notifications enabled');
|
||||||
alert('Failed to enable notifications');
|
} catch (e) {
|
||||||
}
|
alert('Failed to enable notifications');
|
||||||
}}>
|
}
|
||||||
|
}}
|
||||||
|
className="w-full bg-gradient-to-r from-blue-500 to-blue-600 hover:from-blue-600 hover:to-blue-700 text-white shadow-md hover:shadow-lg transition-all"
|
||||||
|
>
|
||||||
|
<Bell className="w-4 h-4 mr-2" />
|
||||||
Enable Push Notifications
|
Enable Push Notifications
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
@ -92,197 +226,89 @@ export function Settings() {
|
|||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
{/* Security Settings */}
|
{/* Security Settings */}
|
||||||
<Card className="shadow-lg hover:shadow-xl transition-shadow">
|
<Card className="shadow-lg hover:shadow-xl transition-all duration-300 border-0 rounded-md group">
|
||||||
<CardHeader className="pb-4">
|
<CardHeader className="pb-4">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<div className="p-3 bg-red-100 rounded-lg">
|
<div className="p-3 bg-gradient-to-br from-red-500 to-red-600 rounded-md shadow-md group-hover:shadow-lg transition-shadow">
|
||||||
<Lock className="h-5 w-5 text-red-600" />
|
<Lock className="h-5 w-5 text-white" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<CardTitle className="text-lg text-gray-900">Security</CardTitle>
|
<CardTitle className="text-lg font-semibold text-gray-900">Security</CardTitle>
|
||||||
<CardDescription className="text-gray-600">Password and security settings</CardDescription>
|
<CardDescription className="text-sm text-gray-600">Password and security settings</CardDescription>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<div className="p-4 bg-gray-50 rounded-lg">
|
<div className="p-4 bg-gradient-to-br from-gray-50 to-gray-100 rounded-md border border-gray-200">
|
||||||
<p className="text-sm text-gray-600">Security settings will be available soon</p>
|
<p className="text-sm text-gray-600 text-center">Security settings will be available soon</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
{/* Appearance Settings */}
|
{/* Appearance Settings */}
|
||||||
<Card className="shadow-lg hover:shadow-xl transition-shadow">
|
<Card className="shadow-lg hover:shadow-xl transition-all duration-300 border-0 rounded-md group">
|
||||||
<CardHeader className="pb-4">
|
<CardHeader className="pb-4">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<div className="p-3 bg-purple-100 rounded-lg">
|
<div className="p-3 bg-gradient-to-br from-purple-500 to-purple-600 rounded-md shadow-md group-hover:shadow-lg transition-shadow">
|
||||||
<Palette className="h-5 w-5 text-purple-600" />
|
<Palette className="h-5 w-5 text-white" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<CardTitle className="text-lg text-gray-900">Appearance</CardTitle>
|
<CardTitle className="text-lg font-semibold text-gray-900">Appearance</CardTitle>
|
||||||
<CardDescription className="text-gray-600">Theme and display preferences</CardDescription>
|
<CardDescription className="text-sm text-gray-600">Theme and display preferences</CardDescription>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<div className="p-4 bg-gray-50 rounded-lg">
|
<div className="p-4 bg-gradient-to-br from-gray-50 to-gray-100 rounded-md border border-gray-200">
|
||||||
<p className="text-sm text-gray-600">Appearance settings will be available soon</p>
|
<p className="text-sm text-gray-600 text-center">Appearance settings will be available soon</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
{/* Preferences */}
|
{/* Preferences */}
|
||||||
<Card className="shadow-lg hover:shadow-xl transition-shadow">
|
<Card className="shadow-lg hover:shadow-xl transition-all duration-300 border-0 rounded-md group">
|
||||||
<CardHeader className="pb-4">
|
<CardHeader className="pb-4">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<div className="p-3 bg-emerald-100 rounded-lg">
|
<div className="p-3 bg-gradient-to-br from-emerald-500 to-emerald-600 rounded-md shadow-md group-hover:shadow-lg transition-shadow">
|
||||||
<Shield className="h-5 w-5 text-emerald-600" />
|
<Shield className="h-5 w-5 text-white" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<CardTitle className="text-lg text-gray-900">Preferences</CardTitle>
|
<CardTitle className="text-lg font-semibold text-gray-900">Preferences</CardTitle>
|
||||||
<CardDescription className="text-gray-600">Application preferences</CardDescription>
|
<CardDescription className="text-sm text-gray-600">Application preferences</CardDescription>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<div className="p-4 bg-gray-50 rounded-lg">
|
<div className="p-4 bg-gradient-to-br from-gray-50 to-gray-100 rounded-md border border-gray-200">
|
||||||
<p className="text-sm text-gray-600">User preferences will be available soon</p>
|
<p className="text-sm text-gray-600 text-center">User preferences will be available soon</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
</TabsContent>
|
|
||||||
|
|
||||||
{/* System Configuration Tab (Admin Only) */}
|
{/* Info: Admin features not available */}
|
||||||
<TabsContent value="system">
|
<Card className="shadow-xl border-0 rounded-md bg-gradient-to-br from-blue-50 to-blue-100/50">
|
||||||
<ConfigurationManager />
|
<CardContent className="p-5 sm:p-6">
|
||||||
</TabsContent>
|
<div className="flex items-start sm:items-center gap-3 sm:gap-4">
|
||||||
|
<div className="p-2 sm:p-2.5 bg-blue-500 rounded-lg shrink-0">
|
||||||
{/* Holiday Calendar Tab (Admin Only) */}
|
<AlertCircle className="w-5 h-5 text-white" />
|
||||||
<TabsContent value="holidays">
|
|
||||||
<HolidayManager />
|
|
||||||
</TabsContent>
|
|
||||||
</Tabs>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
{/* Non-Admin User Settings Only */}
|
|
||||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
|
||||||
{/* Notification Settings */}
|
|
||||||
<Card className="shadow-lg hover:shadow-xl transition-shadow">
|
|
||||||
<CardHeader className="pb-4">
|
|
||||||
<div className="flex items-center gap-3">
|
|
||||||
<div className="p-3 bg-blue-100 rounded-lg">
|
|
||||||
<Bell className="h-5 w-5 text-blue-600" />
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className="flex-1">
|
||||||
<CardTitle className="text-lg text-gray-900">Notifications</CardTitle>
|
<p className="text-sm font-semibold text-gray-900 mb-1">Admin Features Not Accessible</p>
|
||||||
<CardDescription className="text-gray-600">Manage notification preferences</CardDescription>
|
<p className="text-xs text-gray-700">System configuration and holiday management require admin privileges. Contact your administrator for access.</p>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</CardHeader>
|
|
||||||
<CardContent>
|
|
||||||
<div className="space-y-4">
|
|
||||||
<Button onClick={async () => {
|
|
||||||
try {
|
|
||||||
await setupPushNotifications();
|
|
||||||
alert('Notifications enabled');
|
|
||||||
} catch (e) {
|
|
||||||
alert('Failed to enable notifications');
|
|
||||||
}
|
|
||||||
}}>
|
|
||||||
Enable Push Notifications
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
|
|
||||||
{/* Security Settings */}
|
|
||||||
<Card className="shadow-lg hover:shadow-xl transition-shadow">
|
|
||||||
<CardHeader className="pb-4">
|
|
||||||
<div className="flex items-center gap-3">
|
|
||||||
<div className="p-3 bg-red-100 rounded-lg">
|
|
||||||
<Lock className="h-5 w-5 text-red-600" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<CardTitle className="text-lg text-gray-900">Security</CardTitle>
|
|
||||||
<CardDescription className="text-gray-600">Password and security settings</CardDescription>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</CardHeader>
|
|
||||||
<CardContent>
|
|
||||||
<div className="space-y-4">
|
|
||||||
<div className="p-4 bg-gray-50 rounded-lg">
|
|
||||||
<p className="text-sm text-gray-600">Security settings will be available soon</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
</>
|
||||||
{/* Appearance Settings */}
|
)}
|
||||||
<Card className="shadow-lg hover:shadow-xl transition-shadow">
|
</div>
|
||||||
<CardHeader className="pb-4">
|
|
||||||
<div className="flex items-center gap-3">
|
|
||||||
<div className="p-3 bg-purple-100 rounded-lg">
|
|
||||||
<Palette className="h-5 w-5 text-purple-600" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<CardTitle className="text-lg text-gray-900">Appearance</CardTitle>
|
|
||||||
<CardDescription className="text-gray-600">Theme and display preferences</CardDescription>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</CardHeader>
|
|
||||||
<CardContent>
|
|
||||||
<div className="space-y-4">
|
|
||||||
<div className="p-4 bg-gray-50 rounded-lg">
|
|
||||||
<p className="text-sm text-gray-600">Appearance settings will be available soon</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
|
|
||||||
{/* Preferences */}
|
|
||||||
<Card className="shadow-lg hover:shadow-xl transition-shadow">
|
|
||||||
<CardHeader className="pb-4">
|
|
||||||
<div className="flex items-center gap-3">
|
|
||||||
<div className="p-3 bg-emerald-100 rounded-lg">
|
|
||||||
<Shield className="h-5 w-5 text-emerald-600" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<CardTitle className="text-lg text-gray-900">Preferences</CardTitle>
|
|
||||||
<CardDescription className="text-gray-600">Application preferences</CardDescription>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</CardHeader>
|
|
||||||
<CardContent>
|
|
||||||
<div className="space-y-4">
|
|
||||||
<div className="p-4 bg-gray-50 rounded-lg">
|
|
||||||
<p className="text-sm text-gray-600">User preferences will be available soon</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Info: Admin features not available */}
|
|
||||||
<Card className="shadow-lg border-blue-200 bg-blue-50">
|
|
||||||
<CardContent className="p-6">
|
|
||||||
<div className="flex items-center gap-3">
|
|
||||||
<AlertCircle className="w-5 h-5 text-blue-600 shrink-0" />
|
|
||||||
<div>
|
|
||||||
<p className="text-sm font-medium text-gray-900">Admin features not accessible</p>
|
|
||||||
<p className="text-xs text-gray-600 mt-1">System configuration and holiday management require admin privileges.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user