Files
edr-platform/apps/edr-freight-web/backoffice/src/pages/UnitConfigurationPage.tsx
yaschalew 697799b00d fix
2026-07-10 14:24:58 +03:00

1938 lines
70 KiB
TypeScript

import React, { useEffect, useState } from "react";
import { Edit2Icon, Settings } from "lucide-react";
import {
Select,
SelectTrigger,
SelectValue,
SelectContent,
SelectItem,
} from "@/shared/common/ui/select";
import { useMyAdminOrganizations } from "@/user-management/hooks/useOrgAdminOrganizations";
import { useUnit } from "@/user-management/hooks/useUnit";
import { useUnitConfiguration } from "@/shared/hooks/useUnitConfiguration";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/shared/common/ui/table";
import {
ERecordSenderInformationScope,
prefixSuffixService,
} from "@/user-management/services/api/prefixSuffixService";
import type { UnitConfigurationItem } from "@/user-management/services/api/prefixSuffixService";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from "@/shared/common/ui/dialog";
import { Button } from "@/shared/common/ui/button";
import {
PositionScopeToFetch,
positionScopeValues,
} from "./PositionConfigurationPage";
import { t } from "i18next";
import { useLocalizedName } from "@/shared/common/localizedName";
import { Switch } from "@/shared/common/ui/switch";
import { toast } from "sonner";
import type { UnitDto } from "@/user-management/dto/unit/unitDto";
const configurationCardShell =
"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";
const UnitConfigurationPage = () => {
const queryClient = useQueryClient();
const localizedName = useLocalizedName();
const { getAccessibleList } = useUnit();
// Org admin: fetch only the orgs they administer
const { organizations, isLoading: isLoadingOrgs } = useMyAdminOrganizations();
const [selectedOrgId, setSelectedOrgId] = useState("");
const [selectedUnitId, setSelectedUnitId] = useState("");
// Auto-select the first org on load
useEffect(() => {
if (organizations.length > 0 && !selectedOrgId) {
setSelectedOrgId(organizations[0].id);
}
}, [organizations, selectedOrgId]);
// Organization admins see all units; unit admins see only units they administer.
const { data: unitsResponse, isLoading: isLoadingUnits } = getAccessibleList(
selectedOrgId,
{ take: 1000, skip: 0 },
);
const units = (unitsResponse?.data?.items ?? []) as UnitDto[];
// Reset unit selection when org changes
useEffect(() => {
setSelectedUnitId("");
}, [selectedOrgId]);
// Auto-select first unit once units load
useEffect(() => {
if (units.length > 0 && !selectedUnitId) {
setSelectedUnitId(units[0].id);
}
}, [units, selectedUnitId]);
const [open, setOpen] = useState(false);
const [newScope, setNewScope] = useState("");
const [recordSenderInformationScope, setRecordSenderInformationScope] =
useState<ERecordSenderInformationScope>(ERecordSenderInformationScope.NAME);
const [canAssignCustomReferenceNumber, setCanAssignCustomReferenceNumber] =
useState(false);
const [canUseNewInternalMemoFormat, setCanUseNewInternalMemoFormat] =
useState(false);
const [canHaveTagBasedReferenceNumber, setCanHaveTagBasedReferenceNumber] =
useState(false);
const [referenceNumberCountFirst, setReferenceNumberCountFirst] =
useState(false);
const [canUserSkipLevel, setCanUserSkipLevel] = useState(false);
const [canSendToBranch, setCanSendToBranch] = useState(false);
const [
canRecordDateLabelHasLocalization,
setCanRecordDateLabelHasLocalization,
] = useState(false);
const [canRecordDateHaveTime, setCanRecordDateHaveTime] = useState(false);
const [includeSignatureAssign, setIncludeSignatureAssign] = useState(false);
const [waitForAllCollaborators, setWaitForAllCollaborators] = useState(false);
const [shouldCollaboratorAlwaysSign, setShouldCollaboratorAlwaysSign] =
useState(false);
const [
shouldIncludeForYourReferenceInCC,
setShouldIncludeForYourReferenceInCC,
] = useState(false);
const [canCollaborationBeCreatedForAll, setCanCollaborationBeCreatedForAll] =
useState(false);
const [canCreateDirectRecord, setCanCreateDirectRecord] = useState(false);
const [canCreateBankRecord, setCanCreateBankRecord] = useState(false);
const [
isApprovalRequiredForPositionChange,
setIsApprovalRequiredForPositionChange,
] = useState(false);
const [
canPositionBasedRecordsBeCreated,
setCanPositionBasedRecordsBeCreated,
] = useState(false);
const [
canPositionBasedReferenceBeUsedForAllTypes,
setCanPositionBasedReferenceBeUsedForAllTypes,
] = useState(false);
const [
canInternalMemoRequirePositionBasedReferenceNumber,
setCanInternalMemoRequirePositionBasedReferenceNumber,
] = useState(false);
const [
shouldDirectRecordHaveHeaderAndFooter,
setShouldDirectRecordHaveHeaderAndFooter,
] = useState(false);
const [
canRecordBeEditedByCollaborators,
setCanRecordBeEditedByCollaborators,
] = useState(false);
const [canRecordHaveCollaboratorsName, setCanRecordHaveCollaboratorsName] =
useState(false);
const [canRecordBeEditedOnWorkflow, setCanRecordBeEditedOnWorkflow] =
useState(false);
const [
canIncomingAssignmentsBeSeparated,
setcanIncomingAssignmentsBeSeparated,
] = useState(false);
const [canROReturn, setCanROReturn] = useState(false);
const [internalMemoHasReferenceNumber, setInternalMemoHasReferenceNumber] =
useState(false);
const [attachSignatureOnAttachment, setAttachSignatureOnAttachment] =
useState(false);
const { data, isLoading, error } = useUnitConfiguration(selectedUnitId, {
enabled: !!selectedUnitId,
});
const config: UnitConfigurationItem | undefined = data?.data?.items?.[0];
const [IsLoading, setIsLoading] = useState(false);
useEffect(() => {
if (config) {
setCanAssignCustomReferenceNumber(
config.canAssignCustomReferenceNumber || false,
);
setRecordSenderInformationScope(
(config.recordSenderInformationScope as ERecordSenderInformationScope) ||
ERecordSenderInformationScope.NAME,
);
setCanUseNewInternalMemoFormat(
config.canInternalMemosHaveSenderInformation || false,
);
setCanRecordDateLabelHasLocalization(
config.canRecordDateLabelHasLocalization || false,
);
setCanRecordDateHaveTime(config.canRecordDateHaveTime || false);
setIncludeSignatureAssign(config.forwardWithTeeterSignature || false);
setWaitForAllCollaborators(
config.waitAllCollaboratorsBeforeAction || false,
);
setShouldCollaboratorAlwaysSign(
config.shouldCollaboratorAlwaysSign || false,
);
setShouldIncludeForYourReferenceInCC(
config.shouldIncludeForYourReferenceInCC || false,
);
setCanCollaborationBeCreatedForAll(
config.canCollaborationBeCreatedForAll || false,
);
setCanCreateDirectRecord(config.canCreateDirectRecord || false);
setCanCreateBankRecord(config.canCreateBankRelatedRecords || false);
setIsApprovalRequiredForPositionChange(
config.isApprovalRequiredForPositionChange || false,
);
setCanPositionBasedRecordsBeCreated(
config.canPositionBasedRecordsBeCreated || false,
);
setCanPositionBasedReferenceBeUsedForAllTypes(
config.canPositionBasedReferenceBeUsedForAllTypes || false,
);
setShouldDirectRecordHaveHeaderAndFooter(
config.shouldDirectRecordHaveHeaderAndFooter || false,
);
setCanInternalMemoRequirePositionBasedReferenceNumber(
config.canInternalMemoRequirePositionBasedReferenceNumber || false,
);
setCanRecordBeEditedByCollaborators(
config.canRecordBeEditedByCollaborators || false,
);
setCanRecordHaveCollaboratorsName(
config.canRecordHaveCollaboratorsName || false,
);
setCanRecordBeEditedOnWorkflow(
config.canRecordBeEditedOnWorkflow || false,
);
setcanIncomingAssignmentsBeSeparated(
config.canIncomingAssignmentsBeSeparated || false,
);
setCanROReturn(config.canROReturn || false);
setInternalMemoHasReferenceNumber(
config.internalMemoHasReferenceNumber || false,
);
setAttachSignatureOnAttachment(
config.attachSignatureOnAttachment || false,
);
setCanHaveTagBasedReferenceNumber(
config.canHaveTagBasedReferenceNumber || false,
);
setReferenceNumberCountFirst(config.referenceNumberCountFirst || false);
setCanUserSkipLevel(config.canUserSkipLevel || false);
setCanSendToBranch(config.canSendToBranch || false);
}
}, [config]);
const handleCanHaveTagBasedReferenceNumberToggle = (checked: boolean) => {
if (!config?.id) return;
setCanHaveTagBasedReferenceNumber(checked);
updateCanHaveTagBasedReferenceNumber({
id: config.id,
value: checked,
});
};
const handleReferenceNumberCountFirstToggle = (checked: boolean) => {
if (!config?.id) return;
setReferenceNumberCountFirst(checked);
updateReferenceNumberCountFirst({
id: config.id,
value: checked,
});
};
const handleCanUserSkipLevelToggle = (checked: boolean) => {
if (!config?.id) return;
setCanUserSkipLevel(checked);
updateCanUserSkipLevel({
id: config.id,
value: checked,
});
};
const handleCanSendToBranchToggle = (checked: boolean) => {
if (!config?.id) return;
setCanSendToBranch(checked);
updateCanSendToBranch({
id: config.id,
value: checked,
});
};
const {
mutate: updateCanHaveTagBasedReferenceNumber,
isPending: isUpdatingCanHaveTagBasedReferenceNumber,
} = useMutation({
mutationFn: ({ id, value }: { id: string; value: boolean }) =>
prefixSuffixService.updateInternalPrefixSuffix(
{ canHaveTagBasedReferenceNumber: value, unitId: selectedUnitId },
id,
),
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["unitConfig", selectedUnitId],
});
toast.success(
`${t("setting.canHaveTagBasedReferenceNumber", "Can Have Tag Based Reference Number")} ${
canHaveTagBasedReferenceNumber ? "enabled" : "disabled"
}`,
);
},
onError: (err) => console.error("Failed to update", err),
});
const {
mutate: updateReferenceNumberCountFirst,
isPending: isUpdatingReferenceNumberCountFirst,
} = useMutation({
mutationFn: ({ id, value }: { id: string; value: boolean }) =>
prefixSuffixService.updateInternalPrefixSuffix(
{ referenceNumberCountFirst: value, unitId: selectedUnitId },
id,
),
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["unitConfig", selectedUnitId],
});
toast.success(
`${t(
"setting.referenceNumberCountFirst",
"Should The Number Count Come First On The Reference Number",
)} ${referenceNumberCountFirst ? "enabled" : "disabled"}`,
);
},
onError: (err) => console.error("Failed to update", err),
});
const {
mutate: updateCanUserSkipLevel,
isPending: isUpdatingCanUserSkipLevel,
} = useMutation({
mutationFn: ({ id, value }: { id: string; value: boolean }) =>
prefixSuffixService.updateInternalPrefixSuffix(
{ canUserSkipLevel: value, unitId: selectedUnitId },
id,
),
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["unitConfig", selectedUnitId],
});
toast.success(
`${t("setting.canUserSkipLevel", "User Can Skip Level")} ${
canUserSkipLevel ? "enabled" : "disabled"
}`,
);
},
onError: (err) => console.error("Failed to update", err),
});
const {
mutate: updateCanSendToBranch,
isPending: isUpdatingCanSendToBranch,
} = useMutation({
mutationFn: ({ id, value }: { id: string; value: boolean }) =>
prefixSuffixService.updateInternalPrefixSuffix(
{ canSendToBranch: value, unitId: selectedUnitId },
id,
),
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["unitConfig", selectedUnitId],
});
toast.success(
`${t("setting.canSendToBranch", "Can Send to Branch")} ${
canSendToBranch ? "enabled" : "disabled"
}`,
);
},
onError: (err) => console.error("Failed to update", err),
});
const {
mutate: updateRecordSenderInformationScope,
isPending: isUpdatingRecordSenderInformationScope,
} = useMutation({
mutationFn: ({
id,
scope,
}: {
id: string;
scope: ERecordSenderInformationScope;
}) =>
prefixSuffixService.updateInternalPrefixSuffix(
{ recordSenderInformationScope: scope, unitId: selectedUnitId },
id,
),
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["unitConfig", selectedUnitId],
});
toast.success(
`${t("setting.recordSenderInformationScope", "Record Sender Information Scope")} updated`,
);
},
onError: (err) => console.error("Failed to update", err),
});
const {
mutate: updateCanAssignCustomReferenceNumber,
isPending: isUpdatingCanAssignCustomReferenceNumber,
} = useMutation({
mutationFn: ({ id, value }: { id: string; value: boolean }) =>
prefixSuffixService.updateInternalPrefixSuffix(
{ canAssignCustomReferenceNumber: value, unitId: selectedUnitId },
id,
),
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["unitConfig", selectedUnitId],
});
toast.success(
`${t("setting.canAssignCustomReferenceNumber")} ${
canAssignCustomReferenceNumber ? "enabled" : "disabled"
}`,
);
},
onError: (err) => console.error("Failed to update", err),
});
const {
mutate: updateCanUseNewInternalMemoFormat,
isPending: isUpdatingCanUseNewInternalMemoFormat,
} = useMutation({
mutationFn: ({ id, value }: { id: string; value: boolean }) =>
prefixSuffixService.updateInternalPrefixSuffix(
{
canInternalMemosHaveSenderInformation: value,
unitId: selectedUnitId,
},
id,
),
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["unitConfig", selectedUnitId],
});
toast.success(
`${t("setting.canUseNewInternalMemoFormat")} ${
canUseNewInternalMemoFormat ? "enabled" : "disabled"
}`,
);
},
onError: (err) => console.error("Failed to update", err),
});
const {
mutate: updateCanRecordDateLabelHasLocalization,
isPending: isUpdatingCanRecordDateLabelHasLocalization,
} = useMutation({
mutationFn: ({ id, value }: { id: string; value: boolean }) =>
prefixSuffixService.updateInternalPrefixSuffix(
{
canRecordDateLabelHasLocalization: value,
unitId: selectedUnitId,
},
id,
),
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["unitConfig", selectedUnitId],
});
toast.success(
`${t("setting.canRecordDateLabelHasLocalization")} ${
canRecordDateLabelHasLocalization ? "enabled" : "disabled"
}`,
);
},
onError: (err) => console.error("Failed to update", err),
});
const {
mutate: updateCanRecordDateHaveTime,
isPending: isUpdatingCanRecordDateHaveTime,
} = useMutation({
mutationFn: ({ id, value }: { id: string; value: boolean }) =>
prefixSuffixService.updateInternalPrefixSuffix(
{
canRecordDateHaveTime: value,
unitId: selectedUnitId,
},
id,
),
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["unitConfig", selectedUnitId],
});
toast.success(
`${t("setting.canRecordDateHaveTime", "Record Date Can Have Time")} ${
canRecordDateHaveTime ? "enabled" : "disabled"
}`,
);
},
onError: (err) => console.error("Failed to update", err),
});
// mutation for updating scope
const { mutate: updateScope, isPending: isUpdating } = useMutation({
mutationFn: ({ id, scope }: { id: string; scope: string }) =>
prefixSuffixService.updateInternalPrefixSuffix(
{ positionScopeToFetch: scope, unitId: selectedUnitId },
id,
),
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["unitConfig", selectedUnitId],
});
setOpen(false); // close modal
},
onError: (err) => {
console.error("Failed to update scope", err);
},
});
// mutation for updating signature
const { mutate: updateSignature, isPending: isUpdatingSignature } =
useMutation({
mutationFn: ({ id, signature }: { id: string; signature: boolean }) =>
prefixSuffixService.updateInternalPrefixSuffix(
{ forwardWithTeeterSignature: signature, unitId: selectedUnitId },
id,
),
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["unitConfig", selectedUnitId],
});
toast.success(
`Signature & Teeter ${includeSignatureAssign ? "enabled" : "disabled"}`,
);
},
onError: (err) => {
console.error("Failed to update signature", err);
},
});
const {
mutate: updateCollaboratorWait,
isPending: isUpdatingCollaboratorWait,
} = useMutation({
mutationFn: ({ id, wait }: { id: string; wait: boolean }) =>
prefixSuffixService.updateInternalPrefixSuffix(
{
waitAllCollaboratorsBeforeAction: wait,
unitId: selectedUnitId,
},
id,
),
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["unitConfig", selectedUnitId],
});
toast.success(
`${t("setting.title6")} ${waitForAllCollaborators ? "enabled" : "disabled"}`,
);
},
onError: (err) => {
console.error("Failed to update collaborator wait setting", err);
},
});
// Open modal and pre-fill value
const handleEdit = () => {
if (!config?.id) return;
setNewScope(config.positionScopeToFetch as PositionScopeToFetch);
setOpen(true);
};
const handleSave = () => {
if (!config?.id) return;
if (newScope && newScope !== config.positionScopeToFetch) {
updateScope({ id: config.id, scope: newScope });
}
};
const handleToggle = (checked: boolean) => {
if (!config?.id) return;
setIncludeSignatureAssign(checked);
updateSignature({ id: config.id, signature: checked });
};
const handleCanAssignCustomReferenceNumberToggle = (checked: boolean) => {
if (!config?.id) return;
setCanAssignCustomReferenceNumber(checked);
updateCanAssignCustomReferenceNumber({
id: config.id,
value: checked,
});
};
const handleCanUseNewInternalMemoFormatToggle = (checked: boolean) => {
if (!config?.id) return;
setCanUseNewInternalMemoFormat(checked);
updateCanUseNewInternalMemoFormat({
id: config.id,
value: checked,
});
};
const handleCanRecordDateLabelHasLocalizationToggle = (checked: boolean) => {
if (!config?.id) return;
setCanRecordDateLabelHasLocalization(checked);
updateCanRecordDateLabelHasLocalization({
id: config.id,
value: checked,
});
};
const handleCanRecordDateHaveTimeToggle = (checked: boolean) => {
if (!config?.id) return;
setCanRecordDateHaveTime(checked);
updateCanRecordDateHaveTime({
id: config.id,
value: checked,
});
};
const handleCollaboratorWaitToggle = (checked: boolean) => {
if (!config?.id) return;
setWaitForAllCollaborators(checked);
updateCollaboratorWait({ id: config.id, wait: checked });
};
const {
mutate: updateCollaboratorAlwaysSign,
isPending: isUpdatingCollaboratorAlwaysSign,
} = useMutation({
mutationFn: ({ id, value }: { id: string; value: boolean }) =>
prefixSuffixService.updateInternalPrefixSuffix(
{ shouldCollaboratorAlwaysSign: value, unitId: selectedUnitId },
id,
),
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["unitConfig", selectedUnitId],
});
toast.success(
`${t("setting.shouldCollaboratorAlwaysSign")} ${shouldCollaboratorAlwaysSign ? "enabled" : "disabled"}`,
);
},
onError: (err) => console.error("Failed to update", err),
});
const {
mutate: updateIncludeForYourReference,
isPending: isUpdatingIncludeForYourReference,
} = useMutation({
mutationFn: ({ id, value }: { id: string; value: boolean }) =>
prefixSuffixService.updateInternalPrefixSuffix(
{ shouldIncludeForYourReferenceInCC: value, unitId: selectedUnitId },
id,
),
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["unitConfig", selectedUnitId],
});
toast.success(
`${t("setting.shouldIncludeForYourReferenceInCC")} ${shouldIncludeForYourReferenceInCC ? "enabled" : "disabled"}`,
);
},
onError: (err) => console.error("Failed to update", err),
});
const handleCollaboratorAlwaysSignToggle = (checked: boolean) => {
if (!config?.id) return;
setShouldCollaboratorAlwaysSign(checked);
updateCollaboratorAlwaysSign({ id: config.id, value: checked });
};
const handleRecordSenderInformationScopeToggle = (
scope: ERecordSenderInformationScope,
) => {
if (!config?.id) return;
setRecordSenderInformationScope(scope);
updateRecordSenderInformationScope({ id: config.id, scope });
};
const handleIncludeForYourReferenceToggle = (checked: boolean) => {
if (!config?.id) return;
setShouldIncludeForYourReferenceInCC(checked);
updateIncludeForYourReference({ id: config.id, value: checked });
};
const {
mutate: updateCanCollaborationBeCreatedForAll,
isPending: isUpdatingCanCollaborationBeCreatedForAll,
} = useMutation({
mutationFn: ({ id, value }: { id: string; value: boolean }) =>
prefixSuffixService.updateInternalPrefixSuffix(
{ canCollaborationBeCreatedForAll: value, unitId: selectedUnitId },
id,
),
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["unitConfig", selectedUnitId],
});
toast.success(
`${t("setting.canCollaborationBeCreatedForAll")} ${
canCollaborationBeCreatedForAll ? "enabled" : "disabled"
}`,
);
},
onError: (err) => console.error("Failed to update", err),
});
const handleCanCollaborationBeCreatedForAllToggle = (checked: boolean) => {
if (!config?.id) return;
setCanCollaborationBeCreatedForAll(checked);
updateCanCollaborationBeCreatedForAll({ id: config.id, value: checked });
};
const {
mutate: updateCanCreateDirectRecord,
isPending: isUpdatingCanCreateDirectRecord,
} = useMutation({
mutationFn: ({ id, value }: { id: string; value: boolean }) =>
prefixSuffixService.updateInternalPrefixSuffix(
{ canCreateDirectRecord: value, unitId: selectedUnitId },
id,
),
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["unitConfig", selectedUnitId],
});
toast.success(
`${t("setting.canCreateDirectRecord")} ${canCreateDirectRecord ? "enabled" : "disabled"}`,
);
},
onError: (err) =>
console.error("Failed to update direct record creation setting", err),
});
const handleCanCreateDirectRecordToggle = (checked: boolean) => {
if (!config?.id) return;
setCanCreateDirectRecord(checked);
updateCanCreateDirectRecord({ id: config.id, value: checked });
};
const {
mutate: updateCanCreateBankRecord,
isPending: isUpdatingCanCreateBankRecord,
} = useMutation({
mutationFn: ({ id, value }: { id: string; value: boolean }) =>
prefixSuffixService.updateInternalPrefixSuffix(
{ canCreateBankRelatedRecords: value, unitId: selectedUnitId },
id,
),
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["unitConfig", selectedUnitId],
});
toast.success(
`${t("setting.canCreateBankRecord")} ${canCreateBankRecord ? "enabled" : "disabled"}`,
);
},
onError: (err) =>
console.error("Failed to update bank record creation setting", err),
});
const handleCanCreateBankRecordToggle = (checked: boolean) => {
if (!config?.id) return;
setCanCreateBankRecord(checked);
updateCanCreateBankRecord({ id: config.id, value: checked });
};
const {
mutate: updateIsApprovalRequiredForPositionChange,
isPending: isUpdatingIsApprovalRequiredForPositionChange,
} = useMutation({
mutationFn: ({ id, value }: { id: string; value: boolean }) =>
prefixSuffixService.updateInternalPrefixSuffix(
{ isApprovalRequiredForPositionChange: value, unitId: selectedUnitId },
id,
),
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["unitConfig", selectedUnitId],
});
toast.success(
`${t("setting.isApprovalRequiredForPositionChange")} ${
isApprovalRequiredForPositionChange ? "enabled" : "disabled"
}`,
);
},
onError: (err) =>
console.error("Failed to update position change approval setting", err),
});
const handleIsApprovalRequiredForPositionChangeToggle = (
checked: boolean,
) => {
if (!config?.id) return;
setIsApprovalRequiredForPositionChange(checked);
updateIsApprovalRequiredForPositionChange({
id: config.id,
value: checked,
});
};
const {
mutate: updateCanPositionBasedRecordsBeCreated,
isPending: isUpdatingCanPositionBasedRecordsBeCreated,
} = useMutation({
mutationFn: ({ id, value }: { id: string; value: boolean }) =>
prefixSuffixService.updateInternalPrefixSuffix(
{ canPositionBasedRecordsBeCreated: value, unitId: selectedUnitId },
id,
),
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["unitConfig", selectedUnitId],
});
toast.success(
`${t("setting.canPositionBasedRecordsBeCreated")} ${
canPositionBasedRecordsBeCreated ? "enabled" : "disabled"
}`,
);
},
onError: (err) =>
console.error(
"Failed to update position-based record creation setting",
err,
),
});
const handleCanPositionBasedRecordsBeCreatedToggle = (checked: boolean) => {
if (!config?.id) return;
setCanPositionBasedRecordsBeCreated(checked);
updateCanPositionBasedRecordsBeCreated({ id: config.id, value: checked });
};
const {
mutate: updateCanPositionBasedReferenceBeUsedForAllTypes,
isPending: isUpdatingCanPositionBasedReferenceBeUsedForAllTypes,
} = useMutation({
mutationFn: ({ id, value }: { id: string; value: boolean }) =>
prefixSuffixService.updateInternalPrefixSuffix(
{
canPositionBasedReferenceBeUsedForAllTypes: value,
unitId: selectedUnitId,
},
id,
),
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["unitConfig", selectedUnitId],
});
toast.success(
`${t("setting.canPositionBasedReferenceBeUsedForAllTypes")} ${
canPositionBasedReferenceBeUsedForAllTypes ? "enabled" : "disabled"
}`,
);
},
onError: (err) =>
console.error(
"Failed to update position-based reference usage setting",
err,
),
});
const handleCanPositionBasedReferenceBeUsedForAllTypesToggle = (
checked: boolean,
) => {
if (!config?.id) return;
setCanPositionBasedReferenceBeUsedForAllTypes(checked);
updateCanPositionBasedReferenceBeUsedForAllTypes({
id: config.id,
value: checked,
});
};
const {
mutate: updateShouldDirectRecordHaveHeaderAndFooter,
isPending: isUpdatingShouldDirectRecordHaveHeaderAndFooter,
} = useMutation({
mutationFn: ({ id, value }: { id: string; value: boolean }) =>
prefixSuffixService.updateInternalPrefixSuffix(
{
shouldDirectRecordHaveHeaderAndFooter: value,
unitId: selectedUnitId,
},
id,
),
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["unitConfig", selectedUnitId],
});
toast.success(
`${t("setting.shouldDirectRecordHaveHeaderAndFooter")} ${
shouldDirectRecordHaveHeaderAndFooter
? t("setting.enabled")
: t("setting.disabled")
}`,
);
},
onError: (err) => console.error("Failed to update", err),
});
const handleShouldDirectRecordHaveHeaderAndFooterToggle = (
checked: boolean,
) => {
if (!config?.id) return;
setShouldDirectRecordHaveHeaderAndFooter(checked);
updateShouldDirectRecordHaveHeaderAndFooter({
id: config.id,
value: checked,
});
};
const {
mutate: updateCanRecordBeEditedByCollaborators,
isPending: isUpdatingCanRecordBeEditedByCollaborators,
} = useMutation({
mutationFn: ({ id, value }: { id: string; value: boolean }) =>
prefixSuffixService.updateInternalPrefixSuffix(
{ canRecordBeEditedByCollaborators: value, unitId: selectedUnitId },
id,
),
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["unitConfig", selectedUnitId],
});
toast.success(
`${t("setting.canRecordBeEditedByCollaborators")} ${canRecordBeEditedByCollaborators ? "enabled" : "disabled"}`,
);
},
onError: (err) => console.error("Failed to update", err),
});
const handleCanRecordBeEditedByCollaboratorsToggle = (checked: boolean) => {
if (!config?.id) return;
setCanRecordBeEditedByCollaborators(checked);
updateCanRecordBeEditedByCollaborators({ id: config.id, value: checked });
};
const {
mutate: updateCanRecordHaveCollaboratorsName,
isPending: isUpdatingCanRecordHaveCollaboratorsName,
} = useMutation({
mutationFn: ({ id, value }: { id: string; value: boolean }) =>
prefixSuffixService.updateInternalPrefixSuffix(
{ canRecordHaveCollaboratorsName: value, unitId: selectedUnitId },
id,
),
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["unitConfig", selectedUnitId],
});
toast.success(
`${t("setting.canRecordHaveCollaboratorsName")} ${canRecordHaveCollaboratorsName ? "enabled" : "disabled"}`,
);
},
onError: (err) => console.error("Failed to update", err),
});
const handleCanRecordHaveCollaboratorsNameToggle = (checked: boolean) => {
if (!config?.id) return;
setCanRecordHaveCollaboratorsName(checked);
updateCanRecordHaveCollaboratorsName({ id: config.id, value: checked });
};
const {
mutate: updateCanRecordBeEditedOnWorkflow,
isPending: isUpdatingCanRecordBeEditedOnWorkflow,
} = useMutation({
mutationFn: ({ id, value }: { id: string; value: boolean }) =>
prefixSuffixService.updateInternalPrefixSuffix(
{ canRecordBeEditedOnWorkflow: value, unitId: selectedUnitId },
id,
),
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["unitConfig", selectedUnitId],
});
toast.success(
`${t("setting.canRecordBeEditedOnWorkflow")} ${canRecordBeEditedOnWorkflow ? "enabled" : "disabled"}`,
);
},
onError: (err) => console.error("Failed to update", err),
});
const {
mutate: updatecanIncomingAssignmentsBeSeparated,
isPending: isUpdatingcanIncomingAssignmentsBeSeparated,
} = useMutation({
mutationFn: ({ id, value }: { id: string; value: boolean }) =>
prefixSuffixService.updateInternalPrefixSuffix(
{ canIncomingAssignmentsBeSeparated: value, unitId: selectedUnitId },
id,
),
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["unitConfig", selectedUnitId],
});
toast.success(
`${t("setting.canIncomingAssignmentsBeSeparated")} ${canIncomingAssignmentsBeSeparated ? "enabled" : "disabled"}`,
);
},
onError: (err) => console.error("Failed to update", err),
});
const handleCanRecordBeEditedOnWorkflowToggle = (checked: boolean) => {
if (!config?.id) return;
setCanRecordBeEditedOnWorkflow(checked);
updateCanRecordBeEditedOnWorkflow({ id: config.id, value: checked });
};
const handlecanIncomingAssignmentsBeSeparatedToggle = (checked: boolean) => {
if (!config?.id) return;
setcanIncomingAssignmentsBeSeparated(checked);
updatecanIncomingAssignmentsBeSeparated({ id: config.id, value: checked });
};
const { mutate: updateCanROReturn, isPending: isUpdatingCanROReturn } =
useMutation({
mutationFn: ({ id, value }: { id: string; value: boolean }) =>
prefixSuffixService.updateInternalPrefixSuffix(
{ canROReturn: value, unitId: selectedUnitId },
id,
),
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["unitConfig", selectedUnitId],
});
toast.success(
`${t("setting.canROReturn")} ${canROReturn ? "enabled" : "disabled"}`,
);
},
onError: (err) => console.error("Failed to update", err),
});
const handleCanROReturnToggle = (checked: boolean) => {
if (!config?.id) return;
setCanROReturn(checked);
updateCanROReturn({ id: config.id, value: checked });
};
const {
mutate: updateInternalMemoHasReferenceNumber,
isPending: isUpdatingInternalMemoHasReferenceNumber,
} = useMutation({
mutationFn: ({ id, value }: { id: string; value: boolean }) =>
prefixSuffixService.updateInternalPrefixSuffix(
{ internalMemoHasReferenceNumber: value, unitId: selectedUnitId },
id,
),
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["unitConfig", selectedUnitId],
});
toast.success(
`${t("setting.internalMemoHasReferenceNumber")} ${
internalMemoHasReferenceNumber ? "enabled" : "disabled"
}`,
);
},
onError: (err) => console.error("Failed to update", err),
});
const {
mutate: updateCanInternalMemoRequirePositionBasedReferenceNumber,
isPending: isUpdatingCanInternalMemoRequirePositionBasedReferenceNumber,
} = useMutation({
mutationFn: ({ id, value }: { id: string; value: boolean }) =>
prefixSuffixService.updateInternalPrefixSuffix(
{
canInternalMemoRequirePositionBasedReferenceNumber: value,
unitId: selectedUnitId,
},
id,
),
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["unitConfig", selectedUnitId],
});
toast.success(
`${t(
"setting.canInternalMemoRequirePositionBasedReferenceNumber",
"Internal Memo Require Position Based Reference Number",
)} ${
canInternalMemoRequirePositionBasedReferenceNumber
? "enabled"
: "disabled"
}`,
);
},
onError: (err) => console.error("Failed to update", err),
});
const handleCanInternalMemoRequirePositionBasedReferenceNumberToggle = (
checked: boolean,
) => {
if (!config?.id) return;
setCanInternalMemoRequirePositionBasedReferenceNumber(checked);
updateCanInternalMemoRequirePositionBasedReferenceNumber({
id: config.id,
value: checked,
});
};
const handleInternalMemoHasReferenceNumberToggle = (checked: boolean) => {
if (!config?.id) return;
setInternalMemoHasReferenceNumber(checked);
updateInternalMemoHasReferenceNumber({ id: config.id, value: checked });
};
const {
mutate: updateAttachSignatureOnAttachment,
isPending: isUpdatingAttachSignatureOnAttachment,
} = useMutation({
mutationFn: ({ id, value }: { id: string; value: boolean }) =>
prefixSuffixService.updateInternalPrefixSuffix(
{ attachSignatureOnAttachment: value, unitId: selectedUnitId },
id,
),
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["unitConfig", selectedUnitId],
});
toast.success(
`${t("setting.attachSignatureOnAttachment", "Attach Signature On Attachment")} ${
attachSignatureOnAttachment ? "enabled" : "disabled"
}`,
);
},
onError: (err) => console.error("Failed to update", err),
});
const handleAttachSignatureOnAttachmentToggle = (checked: boolean) => {
if (!config?.id) return;
setAttachSignatureOnAttachment(checked);
updateAttachSignatureOnAttachment({ id: config.id, value: checked });
};
const { mutate: createConfig, isPending: isCreatingConfig } = useMutation({
mutationFn: (unitId: string) =>
prefixSuffixService.createInternalPrefixSuffix({ unitId }),
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["unitConfig", selectedUnitId],
});
},
onError: (err) => {
console.error("Failed to create unit configuration", err);
},
});
// Auto-create an empty configuration when a unit has none, so the settings
// table renders immediately with all toggles off instead of an empty state.
useEffect(() => {
if (
!config &&
!isLoading &&
!error &&
selectedUnitId &&
!isCreatingConfig
) {
createConfig(selectedUnitId);
}
}, [
config,
isLoading,
error,
selectedUnitId,
isCreatingConfig,
createConfig,
]);
return (
<div className={configurationCardShell}>
<div className="mb-5 flex flex-col gap-4 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">
<h1 className="flex items-center gap-2 text-2xl font-bold text-slate-900 sm:text-3xl dark:text-slate-100">
<Settings className="h-8 w-8 text-primary" />
{t("setting.title1")}
</h1>
<p className="text-sm text-slate-600 dark:text-slate-400">
{t("setting.title2")}
</p>
</div>
<div className="flex flex-col gap-2 sm:ml-auto sm:flex-row sm:items-center">
{/* Organization selector */}
<Select
value={selectedOrgId}
onValueChange={(value) => setSelectedOrgId(value)}
>
<SelectTrigger className="h-10 w-full bg-white/90 dark:border-slate-700 dark:bg-slate-900 sm:w-36 [&>span]:truncate">
<SelectValue
placeholder={
t("organization.selectOrganization") || "Select organization"
}
/>
</SelectTrigger>
<SelectContent
position="popper"
align="end"
className="dark:border-slate-700 dark:bg-slate-900"
>
{isLoadingOrgs ? (
<SelectItem value="loading" disabled>
{t("setting.loading")}
</SelectItem>
) : organizations.length > 0 ? (
organizations.map((org) => (
<SelectItem key={org.id} value={org.id}>
<span className="block truncate max-w-70">
{localizedName(org.name as { am: string; en: string })}
</span>
</SelectItem>
))
) : (
<SelectItem value="no-orgs" disabled>
{t("organization.noOrganizationsFound") ||
"No organizations found"}
</SelectItem>
)}
</SelectContent>
</Select>
{/* Unit selector */}
<Select
value={selectedUnitId}
onValueChange={(value) => setSelectedUnitId(value)}
disabled={!selectedOrgId}
>
<SelectTrigger className="h-10 w-full bg-white/90 dark:border-slate-700 dark:bg-slate-900 sm:w-36 [&>span]:truncate">
<SelectValue
placeholder={t("organization.selectUnit") || "Select a unit"}
/>
</SelectTrigger>
<SelectContent
position="popper"
align="end"
className="dark:border-slate-700 dark:bg-slate-900"
>
{isLoadingUnits ? (
<SelectItem value="loading" disabled>
{t("setting.loading")}
</SelectItem>
) : units.length > 0 ? (
units.map((unit) => (
<SelectItem key={unit.id} value={unit.id}>
<span className="block truncate max-w-70">
{localizedName(unit.name as { am: string; en: string })}
</span>
</SelectItem>
))
) : (
<SelectItem value="no-units" disabled>
{t("setting.noUnit")}
</SelectItem>
)}
</SelectContent>
</Select>
</div>
</div>
<div className="space-y-3">
{isLoading && (
<p className="text-sm text-slate-600 dark:text-slate-300">
Loading configuration...
</p>
)}
{error && (
<p className="text-sm text-red-600 dark:text-red-400">
Failed to load configuration
</p>
)}
{!config && !isLoading && !error && (
<p className="text-sm text-slate-600 dark:text-slate-300">
{isCreatingConfig
? t(
"setting.preparingDefaults",
"Preparing default configuration...",
)
: t("setting.loading", "Loading...")}
</p>
)}
{config && (
<div className="max-h-128 overflow-x-auto overflow-y-auto rounded-xl border border-slate-200 bg-white/90 dark:border-slate-700 dark:bg-slate-900/70">
<Table>
<TableHeader className="sticky top-0 z-10 bg-white/95 backdrop-blur dark:bg-slate-900/95">
<TableRow className="dark:border-slate-700">
<TableHead className="text-slate-600 dark:text-slate-300">
{t("setting.Name")}
</TableHead>
<TableHead className="text-slate-600 dark:text-slate-300">
{t("setting.Value")}
</TableHead>
<TableHead className="text-right text-slate-600 dark:text-slate-300">
{t("setting.Action")}
</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow className="dark:border-slate-700">
<TableCell className="font-medium text-slate-900 dark:text-slate-100">
{t("setting.title3")}
</TableCell>
<TableCell className="text-slate-700 dark:text-slate-300">
{config.positionScopeToFetch}
</TableCell>
<TableCell className="text-right">
<Button
onClick={handleEdit}
variant="outline"
size="sm"
className="dark:border-slate-700 dark:bg-slate-900 dark:hover:bg-slate-800"
>
<Edit2Icon className="h-4 w-4" />
</Button>
</TableCell>
</TableRow>
<TableRow className="dark:border-slate-700">
<TableCell className="font-medium text-slate-900 dark:text-slate-100">
{t("setting.title5")}
</TableCell>
<TableCell className="text-slate-700 dark:text-slate-300">
{config.forwardWithTeeterSignature ? "Yes" : "No"}
</TableCell>
<TableCell className="text-right">
<Switch
id="add-teeter-assign"
checked={includeSignatureAssign}
onCheckedChange={handleToggle}
disabled={isUpdatingSignature}
/>
</TableCell>
</TableRow>
<TableRow className="dark:border-slate-700">
<TableCell className="font-medium text-slate-900 dark:text-slate-100">
{t("setting.title6")}
</TableCell>
<TableCell className="text-slate-700 dark:text-slate-300">
{config.waitAllCollaboratorsBeforeAction ? "Yes" : "No"}
</TableCell>
<TableCell className="text-right">
<Switch
id="wait-for-all-collaborators-before-action"
checked={waitForAllCollaborators}
onCheckedChange={handleCollaboratorWaitToggle}
disabled={isUpdatingCollaboratorWait}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell className="font-medium">
{t(
"setting.canAssignCustomReferenceNumber",
"Can Assign Custom Reference Number",
)}
</TableCell>
<TableCell>
{config.canAssignCustomReferenceNumber ? "Yes" : "No"}
</TableCell>
<TableCell className="text-right">
<Switch
id="can-assign-custom-reference-number"
checked={canAssignCustomReferenceNumber}
onCheckedChange={
handleCanAssignCustomReferenceNumberToggle
}
disabled={isUpdatingCanAssignCustomReferenceNumber}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell className="font-medium">
{t(
"setting.canUseNewInternalMemoFormat",
"New Internal Memo Format",
)}
</TableCell>
<TableCell>
{config.canInternalMemosHaveSenderInformation
? "Yes"
: "No"}
</TableCell>
<TableCell className="text-right">
<Switch
id="can-use-new-internal-memo-format"
checked={canUseNewInternalMemoFormat}
onCheckedChange={handleCanUseNewInternalMemoFormatToggle}
disabled={isUpdatingCanUseNewInternalMemoFormat}
/>
</TableCell>
</TableRow>
{canUseNewInternalMemoFormat && (
<TableRow>
<TableCell className="font-medium">
{t(
"setting.recordSenderInformationScope",
"Record Sender Information Scope",
)}
</TableCell>
<TableCell>
{config.recordSenderInformationScope || "NAME"}
</TableCell>
<TableCell className="text-right">
<Select
value={recordSenderInformationScope}
onValueChange={(value) =>
handleRecordSenderInformationScopeToggle(
value as ERecordSenderInformationScope,
)
}
disabled={isUpdatingRecordSenderInformationScope}
>
<SelectTrigger className="w-40 dark:border-slate-700 dark:bg-slate-900">
<SelectValue />
</SelectTrigger>
<SelectContent className="dark:border-slate-700 dark:bg-slate-900">
<SelectItem
value={ERecordSenderInformationScope.NAME}
>
Name
</SelectItem>
<SelectItem
value={ERecordSenderInformationScope.SIGNATURE}
>
Signature
</SelectItem>
<SelectItem
value={ERecordSenderInformationScope.STAMP}
>
Stamp
</SelectItem>
<SelectItem
value={
ERecordSenderInformationScope.NAME_AND_SIGNATURE
}
>
Name & Signature
</SelectItem>
<SelectItem
value={ERecordSenderInformationScope.NAME_AND_STAMP}
>
Name & Stamp
</SelectItem>
<SelectItem
value={
ERecordSenderInformationScope.SIGNATURE_AND_STAMP
}
>
SIGNATURE & Stamp
</SelectItem>
<SelectItem value={ERecordSenderInformationScope.ALL}>
All
</SelectItem>
</SelectContent>
</Select>
</TableCell>
</TableRow>
)}
<TableRow>
<TableCell className="font-medium">
{t(
"setting.canRecordDateLabelHasLocalization",
"Does Record Date Label Have Localization?",
)}
</TableCell>
<TableCell>
{config.canRecordDateLabelHasLocalization ? "Yes" : "No"}
</TableCell>
<TableCell className="text-right">
<Switch
id="can-record-date-label-has-localization"
checked={canRecordDateLabelHasLocalization}
onCheckedChange={
handleCanRecordDateLabelHasLocalizationToggle
}
disabled={isUpdatingCanRecordDateLabelHasLocalization}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell className="font-medium">
{t(
"setting.canRecordDateHaveTime",
"Record Date Can Have Time",
)}
</TableCell>
<TableCell>
{config.canRecordDateHaveTime ? "Yes" : "No"}
</TableCell>
<TableCell className="text-right">
<Switch
id="can-record-date-have-time"
checked={canRecordDateHaveTime}
onCheckedChange={handleCanRecordDateHaveTimeToggle}
disabled={isUpdatingCanRecordDateHaveTime}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell className="font-medium">
{t("setting.canCreateDirectRecord")}
</TableCell>
<TableCell>
{config.canCreateDirectRecord
? t("common.yes")
: t("common.no")}
</TableCell>
<TableCell className="text-right">
<Switch
id="can-create-direct-record"
checked={canCreateDirectRecord}
onCheckedChange={handleCanCreateDirectRecordToggle}
disabled={isUpdatingCanCreateDirectRecord}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell className="font-medium">
{t("setting.canCreateBankRecord")}
</TableCell>
<TableCell>
{config.canCreateBankRelatedRecords
? t("common.yes")
: t("common.no")}
</TableCell>
<TableCell className="text-right">
<Switch
id="can-create-bank-record"
checked={canCreateBankRecord}
onCheckedChange={handleCanCreateBankRecordToggle}
disabled={isUpdatingCanCreateBankRecord}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell className="font-medium">
{t("setting.isApprovalRequiredForPositionChange")}
</TableCell>
<TableCell>
{config.isApprovalRequiredForPositionChange
? t("common.yes")
: t("common.no")}
</TableCell>
<TableCell className="text-right">
<Switch
id="is-approval-required-for-position-change"
checked={isApprovalRequiredForPositionChange}
onCheckedChange={
handleIsApprovalRequiredForPositionChangeToggle
}
disabled={isUpdatingIsApprovalRequiredForPositionChange}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell className="font-medium">
{t("setting.canPositionBasedRecordsBeCreated")}
</TableCell>
<TableCell>
{config.canPositionBasedRecordsBeCreated
? t("common.yes")
: t("common.no")}
</TableCell>
<TableCell className="text-right">
<Switch
id="can-position-based-records-be-created"
checked={canPositionBasedRecordsBeCreated}
onCheckedChange={
handleCanPositionBasedRecordsBeCreatedToggle
}
disabled={isUpdatingCanPositionBasedRecordsBeCreated}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell className="font-medium">
{t("setting.canPositionBasedReferenceBeUsedForAllTypes")}
</TableCell>
<TableCell>
{config.canPositionBasedReferenceBeUsedForAllTypes
? t("common.yes")
: t("common.no")}
</TableCell>
<TableCell className="text-right">
<Switch
id="can-position-based-reference-be-used-for-all-types"
checked={canPositionBasedReferenceBeUsedForAllTypes}
onCheckedChange={
handleCanPositionBasedReferenceBeUsedForAllTypesToggle
}
disabled={
isUpdatingCanPositionBasedReferenceBeUsedForAllTypes
}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell className="font-medium">
{t(
"setting.canInternalMemoRequirePositionBasedReferenceNumber",
"Internal Memo Require Position Based Reference Number",
)}
</TableCell>
<TableCell>
{config.canInternalMemoRequirePositionBasedReferenceNumber
? "Yes"
: "No"}
</TableCell>
<TableCell className="text-right">
<Switch
id="can-internal-memo-require-position-based-reference-number"
checked={
canInternalMemoRequirePositionBasedReferenceNumber
}
onCheckedChange={
handleCanInternalMemoRequirePositionBasedReferenceNumberToggle
}
disabled={
isUpdatingCanInternalMemoRequirePositionBasedReferenceNumber
}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell className="font-medium">
{t("setting.shouldDirectRecordHaveHeaderAndFooter")}
</TableCell>
<TableCell>
{config.shouldDirectRecordHaveHeaderAndFooter
? t("common.yes")
: t("common.no")}
</TableCell>
<TableCell className="text-right">
<Switch
id="should-direct-record-have-header-and-footer"
checked={shouldDirectRecordHaveHeaderAndFooter}
onCheckedChange={
handleShouldDirectRecordHaveHeaderAndFooterToggle
}
disabled={isUpdatingShouldDirectRecordHaveHeaderAndFooter}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell className="font-medium">
{t("setting.shouldCollaboratorAlwaysSign")}
</TableCell>
<TableCell>
{config.shouldCollaboratorAlwaysSign ? "Yes" : "No"}
</TableCell>
<TableCell className="text-right">
<Switch
id="should-collaborator-always-sign"
checked={shouldCollaboratorAlwaysSign}
onCheckedChange={handleCollaboratorAlwaysSignToggle}
disabled={isUpdatingCollaboratorAlwaysSign}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell className="font-medium">
{t("setting.shouldIncludeForYourReferenceInCC")}
</TableCell>
<TableCell>
{config.shouldIncludeForYourReferenceInCC ? "Yes" : "No"}
</TableCell>
<TableCell className="text-right">
<Switch
id="should-include-for-your-reference"
checked={shouldIncludeForYourReferenceInCC}
onCheckedChange={handleIncludeForYourReferenceToggle}
disabled={isUpdatingIncludeForYourReference}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell className="font-medium">
{t("setting.canCollaborationBeCreatedForAll")}
</TableCell>
<TableCell>
{config.canCollaborationBeCreatedForAll ? "Yes" : "No"}
</TableCell>
<TableCell className="text-right">
<Switch
id="can-collaboration-be-created-for-all"
checked={canCollaborationBeCreatedForAll}
onCheckedChange={
handleCanCollaborationBeCreatedForAllToggle
}
disabled={isUpdatingCanCollaborationBeCreatedForAll}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell className="font-medium">
{t("setting.canRecordBeEditedByCollaborators")}
</TableCell>
<TableCell>
{config.canRecordBeEditedByCollaborators ? "Yes" : "No"}
</TableCell>
<TableCell className="text-right">
<Switch
id="can-record-be-edited-by-collaborators"
checked={canRecordBeEditedByCollaborators}
onCheckedChange={
handleCanRecordBeEditedByCollaboratorsToggle
}
disabled={isUpdatingCanRecordBeEditedByCollaborators}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell className="font-medium">
{t("setting.canRecordHaveCollaboratorsName")}
</TableCell>
<TableCell>
{config.canRecordHaveCollaboratorsName ? "Yes" : "No"}
</TableCell>
<TableCell className="text-right">
<Switch
id="can-record-have-collaborators-name"
checked={canRecordHaveCollaboratorsName}
onCheckedChange={
handleCanRecordHaveCollaboratorsNameToggle
}
disabled={isUpdatingCanRecordHaveCollaboratorsName}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell className="font-medium">
{t("setting.canRecordBeEditedOnWorkflow")}
</TableCell>
<TableCell>
{config.canRecordBeEditedOnWorkflow ? "Yes" : "No"}
</TableCell>
<TableCell className="text-right">
<Switch
id="can-record-be-edited-on-workflow"
checked={canRecordBeEditedOnWorkflow}
onCheckedChange={handleCanRecordBeEditedOnWorkflowToggle}
disabled={isUpdatingCanRecordBeEditedOnWorkflow}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell className="font-medium">
{t("setting.canIncomingAssignmentsBeSeparated")}
</TableCell>
<TableCell>
{config.canIncomingAssignmentsBeSeparated ? "Yes" : "No"}
</TableCell>
<TableCell className="text-right">
<Switch
id="can-incoming-assignements-be-separated"
checked={canIncomingAssignmentsBeSeparated}
onCheckedChange={
handlecanIncomingAssignmentsBeSeparatedToggle
}
disabled={isUpdatingcanIncomingAssignmentsBeSeparated}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell className="font-medium">
{t("setting.canROReturn")}
</TableCell>
<TableCell>{config.canROReturn ? "Yes" : "No"}</TableCell>
<TableCell className="text-right">
<Switch
id="can-ro-return"
checked={canROReturn}
onCheckedChange={handleCanROReturnToggle}
disabled={isUpdatingCanROReturn}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell className="font-medium">
{t("setting.internalMemoHasReferenceNumber")}
</TableCell>
<TableCell>
{config.internalMemoHasReferenceNumber ? "Yes" : "No"}
</TableCell>
<TableCell className="text-right">
<Switch
id="internal-memo-has-reference-number"
checked={internalMemoHasReferenceNumber}
onCheckedChange={
handleInternalMemoHasReferenceNumberToggle
}
disabled={isUpdatingInternalMemoHasReferenceNumber}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell className="font-medium">
{t(
"setting.attachSignatureOnAttachment",
"Attach Signature On Attachment",
)}
</TableCell>
<TableCell>
{config.attachSignatureOnAttachment ? "Yes" : "No"}
</TableCell>
<TableCell className="text-right">
<Switch
id="attach-signature-on-attachment"
checked={attachSignatureOnAttachment}
onCheckedChange={handleAttachSignatureOnAttachmentToggle}
disabled={isUpdatingAttachSignatureOnAttachment}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell className="font-medium">
{t(
"setting.canHaveTagBasedReferenceNumber",
"Can Have Tag Based Reference Number",
)}
</TableCell>
<TableCell>
{config.canHaveTagBasedReferenceNumber ? "Yes" : "No"}
</TableCell>
<TableCell className="text-right">
<Switch
id="can-have-tag-based-reference-number"
checked={canHaveTagBasedReferenceNumber}
onCheckedChange={
handleCanHaveTagBasedReferenceNumberToggle
}
disabled={isUpdatingCanHaveTagBasedReferenceNumber}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell className="font-medium">
{t(
"setting.referenceNumberCountFirst",
"Should The Number Count Come First On The Reference Number",
)}
</TableCell>
<TableCell>
{config.referenceNumberCountFirst ? "Yes" : "No"}
</TableCell>
<TableCell className="text-right">
<Switch
id="reference-number-count-first"
checked={referenceNumberCountFirst}
onCheckedChange={handleReferenceNumberCountFirstToggle}
disabled={isUpdatingReferenceNumberCountFirst}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell className="font-medium">
{t("setting.canUserSkipLevel", "User Can Skip Level")}
</TableCell>
<TableCell>
{config.canUserSkipLevel ? "Yes" : "No"}
</TableCell>
<TableCell className="text-right">
<Switch
id="can-user-skip-level"
checked={canUserSkipLevel}
onCheckedChange={handleCanUserSkipLevelToggle}
disabled={isUpdatingCanUserSkipLevel}
/>
</TableCell>
</TableRow>
<TableRow>
<TableCell className="font-medium">
{t(
"setting.canSendToBranch",
"User Can Send to Branch Departments Directly",
)}
</TableCell>
<TableCell>
{config.canUserSkipLevel ? "Yes" : "No"}
</TableCell>
<TableCell className="text-right">
<Switch
id="can-send-to-branch"
checked={canSendToBranch}
onCheckedChange={handleCanSendToBranchToggle}
disabled={isUpdatingCanSendToBranch}
/>
</TableCell>
</TableRow>
</TableBody>
</Table>
</div>
)}
</div>
{/* Modal for editing */}
<Dialog open={open} onOpenChange={setOpen}>
<DialogContent className="dark:border-slate-700 dark:bg-slate-900">
<DialogHeader>
<DialogTitle className="dark:text-slate-100">
{t("setting.editTitle")}
</DialogTitle>
<DialogDescription className="dark:text-slate-400">
{t("setting.editMsg")}
</DialogDescription>
</DialogHeader>
<div className="my-4">
<Select
value={newScope}
onValueChange={(value) =>
setNewScope(value as PositionScopeToFetch)
}
>
<SelectTrigger className="w-full dark:border-slate-700 dark:bg-slate-900">
<SelectValue placeholder="Select scope" />
</SelectTrigger>
<SelectContent className="dark:border-slate-700 dark:bg-slate-900">
{positionScopeValues.map((scope) => (
<SelectItem key={scope} value={scope}>
{scope.replace(/_/g, " ").toUpperCase()}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<DialogFooter className="flex justify-end gap-2">
<Button
variant="secondary"
onClick={() => setOpen(false)}
className="dark:bg-slate-800 dark:text-slate-100 dark:hover:bg-slate-700"
>
{t("common.Cancel")}
</Button>
<Button
onClick={handleSave}
disabled={isUpdating}
className="bg-primary hover:bg-primary/90 text-primary-foreground"
>
{isUpdating
? t("contentManagement.saving")
: t("delegation.save")}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</div>
);
};
export default UnitConfigurationPage;