mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-30 02:58:11 +00:00
247 lines
8.8 KiB
TypeScript
247 lines
8.8 KiB
TypeScript
// PrefixSuffixTable.tsx
|
|
import React, { useState } from "react";
|
|
import { Button } from "@/shared/common/ui/button";
|
|
import { Pencil, Trash2, X } from "lucide-react";
|
|
import { t } from "i18next";
|
|
import { Input } from "@/shared/common/ui/input";
|
|
import { Label } from "@/shared/common/ui/label";
|
|
import { prefixSuffixService } from "@/user-management/services/api/prefixSuffixService";
|
|
import { useQueryClient } from "@tanstack/react-query";
|
|
|
|
interface PrefixSuffixTableProps {
|
|
items: any[];
|
|
isLoading: boolean;
|
|
onEdit: (item: any) => void;
|
|
onDelete: (id: string, type: string, recordType: string) => void;
|
|
showPositionColumn?: boolean;
|
|
showCountColumn?: boolean;
|
|
positions?: any[];
|
|
}
|
|
|
|
export const PrefixSuffixTable = ({
|
|
items,
|
|
isLoading,
|
|
onEdit,
|
|
onDelete,
|
|
showPositionColumn = false,
|
|
showCountColumn = false,
|
|
positions = [],
|
|
}: PrefixSuffixTableProps) => {
|
|
const queryClient = useQueryClient();
|
|
const getPositionName = (positionId: string) => {
|
|
const pos = positions.find((p) => p.id === positionId);
|
|
return pos?.name?.en || pos?.name?.am || positionId;
|
|
};
|
|
const [countPopup, setCountPopup] = useState<{
|
|
itemId: string;
|
|
currentCount: number;
|
|
} | null>(null);
|
|
const [countValue, setCountValue] = useState("");
|
|
|
|
// 1. Helper to get count from either source
|
|
const getCount = (item: any): number | undefined => {
|
|
return item.recordSequences?.[0]?.count ?? item.count ?? undefined;
|
|
};
|
|
|
|
// 2. Helper to get sequence ID from either source
|
|
const getSequenceId = (item: any): string | undefined => {
|
|
return item.recordSequences?.[0]?.id ?? item.sequenceId ?? undefined;
|
|
};
|
|
|
|
// 3. Updated openCountPopup
|
|
const openCountPopup = (item: any) => {
|
|
const currentCount = getCount(item) ?? 0;
|
|
const sequenceId = getSequenceId(item);
|
|
|
|
if (!sequenceId) {
|
|
console.error("No sequence ID found for item:", item);
|
|
return;
|
|
}
|
|
|
|
setCountPopup({ itemId: sequenceId, currentCount });
|
|
setCountValue(String(currentCount));
|
|
};
|
|
const closeCountPopup = () => {
|
|
setCountPopup(null);
|
|
setCountValue("");
|
|
queryClient.invalidateQueries({
|
|
queryKey: ["prefixes-by-position"],
|
|
});
|
|
queryClient.invalidateQueries({
|
|
queryKey: ["unit-reference-numbers"],
|
|
});
|
|
};
|
|
|
|
const handleCountSubmit = (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
if (!countPopup) return;
|
|
const newCount = parseInt(countValue, 10);
|
|
if (isNaN(newCount) || newCount < 0) return;
|
|
prefixSuffixService.updateCount(countPopup.itemId, newCount).then(() => {
|
|
closeCountPopup();
|
|
});
|
|
};
|
|
return (
|
|
<div className="overflow-x-auto border rounded-lg dark:border-gray-600">
|
|
<table className="min-w-full text-sm text-left">
|
|
<thead className="bg-gray-50 dark:bg-gray-700 border-b dark:border-gray-600">
|
|
<tr>
|
|
<th className="px-4 py-3 dark:text-white">#</th>
|
|
<th className="px-4 py-3 dark:text-white">{t("header.amharic")}</th>
|
|
<th className="px-4 py-3 dark:text-white">{t("header.english")}</th>
|
|
<th className="px-4 py-3 dark:text-white">
|
|
{t("contentManagement.type")}
|
|
</th>
|
|
{showPositionColumn && (
|
|
<th className="px-4 py-3 dark:text-white">
|
|
{t("contentManagement.position")}
|
|
</th>
|
|
)}
|
|
{showCountColumn && (
|
|
<th className="px-4 py-3 dark:text-white">
|
|
{t("contentManagement.count")}
|
|
</th>
|
|
)}
|
|
<th className="px-4 py-3 dark:text-white">
|
|
{t("userRecord.Actions")}
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{isLoading ? (
|
|
<tr>
|
|
<td
|
|
colSpan={showPositionColumn ? 6 : 5}
|
|
className="text-center py-8 text-gray-500 dark:text-gray-400">
|
|
{t("contentManagement.loading")}
|
|
</td>
|
|
</tr>
|
|
) : items.length === 0 ? (
|
|
<tr>
|
|
<td
|
|
colSpan={showPositionColumn ? 6 : 5}
|
|
className="text-center py-8 text-gray-500 dark:text-gray-400">
|
|
{t("contentManagement.noRec")}
|
|
</td>
|
|
</tr>
|
|
) : (
|
|
items.map((item, idx) => {
|
|
return (
|
|
<tr
|
|
key={item.id}
|
|
className="border-b hover:bg-gray-50 dark:hover:bg-gray-700 dark:border-gray-600">
|
|
<td className="px-4 py-3 dark:text-gray-300">{idx + 1}</td>
|
|
<td className="px-4 py-3 dark:text-gray-300">
|
|
{item.name?.am || "-"}
|
|
</td>
|
|
<td className="px-4 py-3 dark:text-gray-300">
|
|
{item.name?.en || "-"}
|
|
</td>
|
|
<td className="px-4 py-3 capitalize dark:text-gray-300">
|
|
{item.type}
|
|
{item.isForCC && (
|
|
<span className="ml-1 text-xs text-purple-600 dark:text-purple-400">
|
|
(CC)
|
|
</span>
|
|
)}
|
|
</td>
|
|
|
|
{showPositionColumn && (
|
|
<td className="px-4 py-3 dark:text-gray-300">
|
|
{item.positionId ? getPositionName(item.positionId) : "-"}
|
|
</td>
|
|
)}
|
|
{showCountColumn && (
|
|
<td className="px-4 py-3 dark:text-gray-300">
|
|
{(() => {
|
|
const count = getCount(item);
|
|
if (count === undefined) return "-";
|
|
|
|
return (
|
|
<button
|
|
onClick={() => openCountPopup(item)}
|
|
className="text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300 underline cursor-pointer">
|
|
{count}
|
|
</button>
|
|
);
|
|
})()}
|
|
</td>
|
|
)}
|
|
|
|
<td className="px-4 py-3">
|
|
<div className="flex gap-2">
|
|
<Button
|
|
variant="ghost"
|
|
size="sm"
|
|
onClick={() => onEdit(item)}>
|
|
<Pencil className="h-4 w-4" />
|
|
</Button>
|
|
<Button
|
|
variant="ghost"
|
|
size="sm"
|
|
className="text-red-600 hover:text-red-800 dark:text-red-400 dark:hover:text-red-300"
|
|
onClick={() =>
|
|
onDelete(item.id, item.type, item.recordTypeKey)
|
|
}>
|
|
<Trash2 className="h-4 w-4" />
|
|
</Button>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
);
|
|
})
|
|
)}
|
|
</tbody>
|
|
</table>
|
|
{/* Count Update Popup */}
|
|
{countPopup && (
|
|
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50">
|
|
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-lg p-6 w-80">
|
|
<div className="flex justify-between items-center mb-4">
|
|
<h3 className="text-lg font-semibold dark:text-white">
|
|
{t("contentManagement.updateCount")}
|
|
</h3>
|
|
<button
|
|
onClick={closeCountPopup}
|
|
className="text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200">
|
|
<X className="h-5 w-5" />
|
|
</button>
|
|
</div>
|
|
|
|
<form onSubmit={handleCountSubmit}>
|
|
<div className="space-y-2 mb-4">
|
|
<Label htmlFor="countValue" className="dark:text-gray-200">
|
|
{t("contentManagement.value")} *
|
|
</Label>
|
|
<Input
|
|
id="countValue"
|
|
type="number"
|
|
min="0"
|
|
value={countValue}
|
|
onChange={(e) => setCountValue(e.target.value)}
|
|
placeholder={t("contentManagement.enterValue")}
|
|
className="dark:bg-gray-700 dark:border-gray-600 dark:text-white"
|
|
/>
|
|
<p className="text-xs text-gray-500 dark:text-gray-400">
|
|
{t("contentManagement.currentCount")}:{" "}
|
|
{countPopup.currentCount}
|
|
</p>
|
|
</div>
|
|
|
|
<div className="flex gap-2 justify-end">
|
|
<Button
|
|
type="button"
|
|
variant="outline"
|
|
onClick={closeCountPopup}>
|
|
{t("common.cancel")}
|
|
</Button>
|
|
<Button type="submit">{t("common.submit")}</Button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
};
|