Files
edr-platform/apps/edr-freight-web/backoffice/src/pages/SettingsPage.tsx
2026-08-05 09:46:39 +00:00

225 lines
10 KiB
TypeScript

import { useState } from "react";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/shared/common/ui/card";
import {
Tabs,
TabsContent,
TabsList,
TabsTrigger,
} from "@/shared/common/ui/tabs";
import { Input } from "@/shared/common/ui/input";
import { Button } from "@/shared/common/ui/button";
import { Shield, Save, Trash2, Plus, Edit2 } from "lucide-react";
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/shared/common/ui/dialog";
import PasswordSettingsForm from "@/super-admin/components/settings/PasswordSettingsForm";
import { usePasswordSettingsQuery, usePasswordSettingsMutations } from "@/super-admin/hooks/usePasswordSettings";
import {
AlertDialog,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogHeader,
AlertDialogTitle,
} from "@/shared/common/ui/alert-dialog";
import { toast } from "sonner";
export default function SettingsPage() {
const [createDialogOpen, setCreateDialogOpen] = useState(false);
const [editDialogOpen, setEditDialogOpen] = useState(false);
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
const { data: passwordSettings, refetch: refetchPasswordSettings } = usePasswordSettingsQuery();
const { delete: deleteMutation } = usePasswordSettingsMutations();
const handleDeletePasswordSettings = async () => {
if (!passwordSettings?.id) {
toast.error("No password settings to delete");
return;
}
try {
console.log("Attempting to delete password settings with ID:", passwordSettings.id);
await deleteMutation.mutateAsync(passwordSettings.id);
console.log("Delete successful, closing dialog");
setDeleteDialogOpen(false);
} catch (error) {
console.error("Delete error:", error);
toast.error("Failed to delete password settings");
}
};
const handleEditPasswordSettings = () => {
if (passwordSettings?.id) {
setEditDialogOpen(true);
}
};
const handleCreateSuccess = () => {
setCreateDialogOpen(false);
refetchPasswordSettings();
};
const handleEditSuccess = () => {
setEditDialogOpen(false);
refetchPasswordSettings();
};
return (
<div className="p-6 space-y-6">
<Card className="shadow-lg border-gray-200 dark:border-gray-700">
<CardHeader>
<CardTitle className="text-xl font-semibold">
System Settings
</CardTitle>
<CardDescription>
Configure system-wide settings for your organization
</CardDescription>
</CardHeader>
<CardContent>
<Tabs defaultValue="security" className="w-full">
{/* Only Security Tab */}
{/* Security Settings */}
<TabsContent value="security" className="space-y-4">
<div className="flex justify-between items-center mb-4">
<h3 className="text-lg font-semibold">Password Settings</h3>
</div>
{!passwordSettings ? (
<Card>
<CardContent className="pt-6">
<p className="text-center text-gray-600 dark:text-gray-400 mb-4">
No password settings configured yet
</p>
<div className="flex justify-center">
<Dialog open={createDialogOpen} onOpenChange={setCreateDialogOpen}>
<DialogTrigger asChild>
<Button className="bg-primary hover:bg-primary/90">
<Plus className="h-4 w-4 mr-2" />
Create Password Settings
</Button>
</DialogTrigger>
<DialogContent className="max-w-2xl max-h-[90vh] overflow-y-auto">
<DialogHeader>
<DialogTitle>Create Password Settings</DialogTitle>
</DialogHeader>
<PasswordSettingsForm
onSuccessCallback={handleCreateSuccess}
isDialogForm={true}
/>
</DialogContent>
</Dialog>
</div>
</CardContent>
</Card>
) : (
<Card>
<CardContent className="pt-6">
<div className="border rounded-lg overflow-hidden">
<div className="overflow-x-auto">
<table className="w-full">
<thead>
<tr className="bg-gray-50 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700">
<th className="px-6 py-3 text-left text-sm font-semibold text-gray-900 dark:text-white">Setting</th>
<th className="px-6 py-3 text-left text-sm font-semibold text-gray-900 dark:text-white">Value</th>
<th className="px-6 py-3 text-right text-sm font-semibold text-gray-900 dark:text-white">Actions</th>
</tr>
</thead>
<tbody>
<tr className="border-b border-gray-200 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-800/50">
<td className="px-6 py-4 text-sm font-medium text-gray-900 dark:text-white">Minimum Password Length</td>
<td className="px-6 py-4 text-sm text-gray-600 dark:text-gray-400">{passwordSettings.minimumPasswordLength}</td>
<td rowSpan={5} className="px-6 py-4 text-right">
<div className="flex justify-end gap-2">
<Dialog open={editDialogOpen} onOpenChange={setEditDialogOpen}>
<DialogTrigger asChild>
<Button variant="outline" size="sm" onClick={handleEditPasswordSettings}>
<Edit2 className="h-4 w-4 mr-2" />
Update
</Button>
</DialogTrigger>
<DialogContent className="max-w-2xl max-h-[90vh] overflow-y-auto">
<DialogHeader>
<DialogTitle>Update Password Settings</DialogTitle>
</DialogHeader>
<PasswordSettingsForm
onSuccessCallback={handleEditSuccess}
isDialogForm={true}
/>
</DialogContent>
</Dialog>
<Button
variant="destructive"
size="sm"
onClick={() => setDeleteDialogOpen(true)}>
<Trash2 className="h-4 w-4 mr-2" />
Delete
</Button>
</div>
</td>
</tr>
<tr className="border-b border-gray-200 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-800/50">
<td className="px-6 py-4 text-sm font-medium text-gray-900 dark:text-white">Maximum Password Length</td>
<td className="px-6 py-4 text-sm text-gray-600 dark:text-gray-400">{passwordSettings.maximumPasswordLength}</td>
</tr>
<tr className="border-b border-gray-200 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-800/50">
<td className="px-6 py-4 text-sm font-medium text-gray-900 dark:text-white">Password Expiry (Days)</td>
<td className="px-6 py-4 text-sm text-gray-600 dark:text-gray-400">{passwordSettings.passwordExpiry}</td>
</tr>
<tr className="border-b border-gray-200 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-800/50">
<td className="px-6 py-4 text-sm font-medium text-gray-900 dark:text-white">Session Timeout (Minutes)</td>
<td className="px-6 py-4 text-sm text-gray-600 dark:text-gray-400">{passwordSettings.sessionTimeout}</td>
</tr>
<tr className="hover:bg-gray-50 dark:hover:bg-gray-800/50">
<td className="px-6 py-4 text-sm font-medium text-gray-900 dark:text-white">Default Password Enabled</td>
<td className="px-6 py-4 text-sm text-gray-600 dark:text-gray-400">
{passwordSettings.isDefaultPasswordEnabled ? "Yes" : "No"}
</td>
</tr>
</tbody>
</table>
</div>
</div>
</CardContent>
</Card>
)}
</TabsContent>
</Tabs>
</CardContent>
</Card>
{/* Delete Confirmation Dialog */}
<AlertDialog open={deleteDialogOpen} onOpenChange={setDeleteDialogOpen}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Delete Password Settings</AlertDialogTitle>
<AlertDialogDescription>
Are you sure you want to delete the password settings? This action cannot be undone.
</AlertDialogDescription>
</AlertDialogHeader>
<div className="flex justify-end gap-3">
<AlertDialogCancel>Cancel</AlertDialogCancel>
<Button
onClick={handleDeletePasswordSettings}
className="bg-red-600 hover:bg-red-700"
disabled={deleteMutation.isPending}>
{deleteMutation.isPending ? "Deleting..." : "Delete"}
</Button>
</div>
</AlertDialogContent>
</AlertDialog>
</div>
);
}