mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-29 01:20:55 +00:00
231 lines
9.2 KiB
TypeScript
231 lines
9.2 KiB
TypeScript
import React, { useEffect, useId, useState } from "react";
|
|
import { Building2, PenLine, Settings, ShieldCheck } from "lucide-react";
|
|
import { useAuth } from "@/shared/context/AuthContext";
|
|
import { useLocalizedName } from "@/shared/common/localizedName";
|
|
import { useUnit } from "@/user-management/hooks/useUnit";
|
|
import { useUnitConfiguration } from "@/shared/hooks/useUnitConfiguration";
|
|
import { prefixSuffixService } from "@/user-management/services/api/prefixSuffixService";
|
|
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
|
import {
|
|
Select,
|
|
SelectContent,
|
|
SelectItem,
|
|
SelectTrigger,
|
|
SelectValue,
|
|
} from "@/shared/common/ui/select";
|
|
import { Switch } from "@/shared/common/ui/switch";
|
|
import { Label } from "@/shared/common/ui/label";
|
|
import { t } from "i18next";
|
|
|
|
type UnitOption = {
|
|
id: string;
|
|
name?: { am: string; en: string };
|
|
};
|
|
|
|
type UnitConfigurationItem = {
|
|
id: string;
|
|
unitId: string;
|
|
attachSignatureOnAttachment?: boolean;
|
|
};
|
|
|
|
const AttachmentSignature = () => {
|
|
const { user } = useAuth();
|
|
const queryClient = useQueryClient();
|
|
const organizationId = user?.employee?.[0]?.organizationId || "";
|
|
const localizedName = useLocalizedName();
|
|
const switchId = useId();
|
|
|
|
const { getList: getUnitList } = useUnit();
|
|
const { data: units, isLoading: isLoadingUnits } = getUnitList(
|
|
organizationId,
|
|
{ take: 1000 },
|
|
);
|
|
|
|
const [selectedUnitId, setSelectedUnitId] = useState("");
|
|
const [localAttachSignatureValue, setLocalAttachSignatureValue] = useState<
|
|
boolean | null
|
|
>(null);
|
|
|
|
useEffect(() => {
|
|
if (!selectedUnitId && units?.data?.items?.length) {
|
|
setSelectedUnitId(units.data.items[0].id);
|
|
}
|
|
}, [selectedUnitId, units]);
|
|
|
|
const unitItems = (units?.data?.items ?? []) as UnitOption[];
|
|
const hasUnits = unitItems.length > 0;
|
|
const selectedUnitName = unitItems.find(
|
|
(unit) => unit.id === selectedUnitId,
|
|
)?.name;
|
|
|
|
const { data: unitConfigResponse, isLoading: isLoadingConfig } =
|
|
useUnitConfiguration(selectedUnitId);
|
|
|
|
const unitConfigurations =
|
|
(unitConfigResponse?.data?.items as UnitConfigurationItem[] | undefined) ||
|
|
[];
|
|
const filteredConfig =
|
|
unitConfigurations.find((item) => item.unitId === selectedUnitId) ||
|
|
unitConfigurations[0];
|
|
|
|
const configValue = Boolean(filteredConfig?.attachSignatureOnAttachment);
|
|
const isSwitchEnabled = Boolean(filteredConfig?.id);
|
|
const switchValue =
|
|
localAttachSignatureValue === null ? configValue : localAttachSignatureValue;
|
|
|
|
useEffect(() => {
|
|
setLocalAttachSignatureValue(null);
|
|
}, [selectedUnitId, configValue]);
|
|
|
|
const { mutate: updateEscalationField, isPending: isUpdatingSignature } =
|
|
useMutation({
|
|
mutationFn: ({ id, value }: { id: string; value: boolean }) =>
|
|
prefixSuffixService.updateInternalPrefixSuffix(
|
|
{
|
|
attachSignatureOnAttachment: value,
|
|
unitId: selectedUnitId,
|
|
},
|
|
id,
|
|
),
|
|
onSuccess: () => {
|
|
queryClient.invalidateQueries({
|
|
queryKey: ["unitConfig", selectedUnitId],
|
|
});
|
|
},
|
|
onError: () => {
|
|
setLocalAttachSignatureValue(null);
|
|
},
|
|
});
|
|
|
|
const handleToggleSignature = (checked: boolean) => {
|
|
if (!filteredConfig?.id || isUpdatingSignature) return;
|
|
setLocalAttachSignatureValue(checked);
|
|
updateEscalationField({
|
|
id: filteredConfig.id,
|
|
value: checked,
|
|
});
|
|
};
|
|
|
|
return (
|
|
<section className="w-full">
|
|
<div className="relative overflow-hidden rounded-2xl border border-slate-200/80 bg-gradient-to-br from-white via-slate-50 to-slate-100/60 p-4 shadow-sm sm:p-6 dark:border-slate-700/80 dark:bg-gradient-to-br dark:from-slate-950 dark:via-slate-900 dark:to-slate-900">
|
|
<div className="relative space-y-5">
|
|
<header className="flex flex-col gap-2 border-b border-slate-200 pb-4 dark:border-slate-700 sm:flex-row sm:items-start sm:justify-between">
|
|
<div className="space-y-1">
|
|
<p className="inline-flex w-fit items-center gap-2 rounded-full bg-white/80 px-3 py-1 text-xs font-medium text-slate-700 ring-1 ring-slate-200 dark:bg-slate-800 dark:text-slate-300 dark:ring-slate-700">
|
|
<ShieldCheck className="h-3.5 w-3.5" />
|
|
{t("setting.attachmentSignature.badge")}
|
|
</p>
|
|
<h2 className="text-xl font-semibold tracking-tight text-slate-900 dark:text-slate-100 sm:text-2xl flex gap-2">
|
|
<Settings className="h-8 w-8 text-primary" />
|
|
{t("setting.attachmentSignature.title")}
|
|
</h2>
|
|
<p className="max-w-2xl text-sm text-slate-600 dark:text-slate-400">
|
|
{t("setting.attachmentSignature.description")}
|
|
</p>
|
|
</div>
|
|
</header>
|
|
|
|
<div className="grid grid-cols-1 gap-4 lg:grid-cols-2">
|
|
<div className="space-y-2 rounded-xl border border-slate-200/80 bg-white/80 p-4 backdrop-blur-sm dark:border-slate-700 dark:bg-slate-900/70">
|
|
<Label className="text-sm font-medium text-slate-800 dark:text-slate-200">
|
|
{t("setting.attachmentSignature.unit")}
|
|
</Label>
|
|
<Select
|
|
value={selectedUnitId}
|
|
onValueChange={(value) => setSelectedUnitId(value)}
|
|
>
|
|
<SelectTrigger
|
|
className="h-11 w-full bg-white/90 dark:border-slate-700 dark:bg-slate-900"
|
|
aria-label={t("setting.attachmentSignature.unit")}
|
|
>
|
|
<SelectValue
|
|
placeholder={t("setting.attachmentSignature.selectUnit")}
|
|
/>
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
{isLoadingUnits ? (
|
|
<SelectItem value="loading" disabled>
|
|
{t("setting.attachmentSignature.loadingUnits")}
|
|
</SelectItem>
|
|
) : hasUnits ? (
|
|
unitItems.map((unit) => (
|
|
<SelectItem key={unit.id} value={unit.id}>
|
|
{localizedName(unit.name)}
|
|
</SelectItem>
|
|
))
|
|
) : (
|
|
<SelectItem value="no-units" disabled>
|
|
{t("setting.attachmentSignature.noUnitsFound")}
|
|
</SelectItem>
|
|
)}
|
|
</SelectContent>
|
|
</Select>
|
|
<p className="text-xs text-slate-500 dark:text-slate-400">
|
|
{t("setting.attachmentSignature.unitHint")}
|
|
</p>
|
|
</div>
|
|
|
|
<div className="space-y-3 rounded-xl border border-slate-200/80 bg-white/80 p-4 backdrop-blur-sm dark:border-slate-700 dark:bg-slate-900/70">
|
|
<div className="flex items-start justify-between gap-3">
|
|
<div className="space-y-1">
|
|
<Label
|
|
htmlFor={switchId}
|
|
className="text-sm font-medium text-slate-800 dark:text-slate-200"
|
|
>
|
|
{t("setting.attachmentSignature.toggleLabel")}
|
|
</Label>
|
|
<p
|
|
id={`${switchId}-description`}
|
|
className="text-xs text-slate-500 dark:text-slate-400"
|
|
>
|
|
{t("setting.attachmentSignature.toggleDescription")}
|
|
</p>
|
|
</div>
|
|
<Switch
|
|
id={switchId}
|
|
checked={switchValue}
|
|
onCheckedChange={handleToggleSignature}
|
|
aria-describedby={`${switchId}-description`}
|
|
disabled={!isSwitchEnabled || isLoadingConfig || isUpdatingSignature}
|
|
/>
|
|
</div>
|
|
|
|
<div className="flex items-center gap-2 rounded-lg border border-dashed border-slate-300/80 bg-slate-50/80 px-3 py-2 text-sm text-slate-600 dark:border-slate-700 dark:bg-slate-800/80 dark:text-slate-300">
|
|
<PenLine className="h-4 w-4 text-indigo-600 dark:text-indigo-400" />
|
|
<span>
|
|
{t("setting.attachmentSignature.status")}{" "}
|
|
<span className="font-semibold">
|
|
{switchValue
|
|
? t("profile.enabled")
|
|
: t("profile.disabled")}
|
|
</span>
|
|
</span>
|
|
</div>
|
|
{!isSwitchEnabled && !isLoadingConfig && (
|
|
<p className="text-xs text-amber-600 dark:text-amber-400">
|
|
{t("setting.noConfigFound")}
|
|
</p>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
<footer className="flex flex-wrap items-center gap-2 rounded-lg border border-slate-200/80 bg-white/70 px-3 py-2 text-xs text-slate-600 dark:border-slate-700 dark:bg-slate-900/70 dark:text-slate-300">
|
|
<Building2 className="h-3.5 w-3.5 text-slate-500 dark:text-slate-400" />
|
|
<span>
|
|
{t("setting.attachmentSignature.activeUnit")}{" "}
|
|
<strong className="font-semibold">
|
|
{selectedUnitName
|
|
? localizedName(selectedUnitName)
|
|
: t("common.None")}
|
|
</strong>
|
|
</span>
|
|
</footer>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
);
|
|
};
|
|
|
|
export default AttachmentSignature;
|