215 lines
6.3 KiB
TypeScript
215 lines
6.3 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useState } from "react";
|
|
import { DataTableLayout, ColumnDef } from "ikoncomponents";
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
} from "ikoncomponents";
|
|
import { Plus, SquarePenIcon, Trash } from "lucide-react";
|
|
|
|
import { RiskData } from "@/app/utils/interface/risk";
|
|
import RiskForm from "./components/riskModal";
|
|
import { IconTextButtonWithTooltip } from "ikoncomponents";
|
|
import EditRiskModal from "./components/editRisk";
|
|
import {
|
|
createRiskApi,
|
|
risksApi,
|
|
updateRiskApi,
|
|
} from "@/app/utils/api/riskApi";
|
|
import { useAppCache } from "@/app/utils/context/AppCacheContext";
|
|
|
|
interface RiskComponentProps {
|
|
projectIdentifier: string;
|
|
}
|
|
|
|
export default function RiskComponent({
|
|
projectIdentifier,
|
|
}: RiskComponentProps) {
|
|
const { userNameMap } = useAppCache();
|
|
|
|
// ── State ─────────────────────────────────────────────────────
|
|
const [createOpen, setCreateOpen] = useState(false);
|
|
const [editOpen, setEditOpen] = useState(false);
|
|
const [selectedRisk, setSelectedRisk] = useState<RiskData | null>(null);
|
|
const [data, setData] = useState<RiskData[]>([]);
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
// ── Fetch Risks from API ──────────────────────────────────────
|
|
const fetchRisks = async () => {
|
|
try {
|
|
setLoading(true);
|
|
const response = await risksApi();
|
|
|
|
console.log("Risk list response -----> ", response);
|
|
|
|
// Adjust this depending on your API structure
|
|
setData(response?.data || response || []);
|
|
} catch (error) {
|
|
console.error("Error fetching risks:", error);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
fetchRisks();
|
|
}, []);
|
|
|
|
// ── Handlers ───────────────────────────────────────────────────
|
|
const openForCreate = () => setCreateOpen(true);
|
|
|
|
const openForEdit = (risk: RiskData) => {
|
|
setSelectedRisk(risk);
|
|
setEditOpen(true);
|
|
};
|
|
|
|
const handleCreateSubmit = async (formData: RiskData) => {
|
|
try {
|
|
const response = await createRiskApi(formData);
|
|
console.log("Risk created -----> ", response);
|
|
|
|
setCreateOpen(false);
|
|
fetchRisks();
|
|
} catch (error) {
|
|
console.error("Error creating risk:", error);
|
|
}
|
|
};
|
|
|
|
// const handleEditSave = async (updated: RiskData) => {
|
|
// console.log("Updated Risk:", updated);
|
|
// const response = await updateRiskApi(updated);
|
|
// console.log(response);
|
|
// setEditOpen(false);
|
|
// setSelectedRisk(null);
|
|
|
|
// fetchRisks(); //
|
|
// };
|
|
|
|
const handleEditSave = async (updatedValues: RiskData) => {
|
|
if (!selectedRisk?.riskIdentifier) {
|
|
console.error("No risk selected for update");
|
|
return;
|
|
}
|
|
|
|
console.log("Updated Risk:", updatedValues);
|
|
|
|
const response = await updateRiskApi(
|
|
selectedRisk.riskIdentifier,
|
|
updatedValues,
|
|
);
|
|
|
|
console.log(response);
|
|
|
|
setEditOpen(false);
|
|
setSelectedRisk(null);
|
|
fetchRisks();
|
|
};
|
|
// ── Table Columns ─────────────────────────────────────────────
|
|
const columns: ColumnDef<RiskData>[] = [
|
|
{
|
|
accessorKey: "riskDescription",
|
|
header: () => <div className="text-center">Description</div>,
|
|
},
|
|
{
|
|
accessorKey: "riskProbability",
|
|
header: () => <div className="text-center">Probability (%)</div>,
|
|
cell: (row) => <span>{row.riskProbability}%</span>,
|
|
},
|
|
{
|
|
accessorKey: "riskImpact",
|
|
header: () => <div className="text-center">Impact</div>,
|
|
},
|
|
{
|
|
accessorKey: "probableRiskValue",
|
|
header: () => <div className="text-center">Score</div>,
|
|
},
|
|
{
|
|
accessorKey: "riskOwner",
|
|
header: () => <div className="text-center">Owner</div>,
|
|
cell: (row) => (
|
|
<span>
|
|
{row.riskOwner ? userMap[row.riskOwner] : "N/A"}
|
|
</span>
|
|
),
|
|
},
|
|
{
|
|
accessorKey: "riskStatus",
|
|
header: () => <div className="text-center">Status</div>,
|
|
},
|
|
{
|
|
header: () => <div className="text-center">Actions</div>,
|
|
cell: (row) => (
|
|
<div className="flex items-center gap-1">
|
|
<IconTextButtonWithTooltip
|
|
tooltipContent="Edit"
|
|
variant="ghost"
|
|
onClick={() => openForEdit(row)}
|
|
>
|
|
<SquarePenIcon />
|
|
</IconTextButtonWithTooltip>
|
|
<IconTextButtonWithTooltip
|
|
tooltipContent="Delete"
|
|
variant="ghost"
|
|
onClick={() => console.log("Delete", row.riskIdentifier)}
|
|
>
|
|
<Trash />
|
|
</IconTextButtonWithTooltip>
|
|
</div>
|
|
),
|
|
},
|
|
];
|
|
|
|
// ── Render ────────────────────────────────────────────────────
|
|
return (
|
|
<>
|
|
<DataTableLayout
|
|
columns={columns}
|
|
data={data}
|
|
extraTools={{
|
|
keyExtractor: (row: RiskData) => row.riskIdentifier ?? row.riskDescription,
|
|
totalPages: 0,
|
|
currentPage: 0,
|
|
isLoading: loading,
|
|
actionNode: (
|
|
<IconTextButtonWithTooltip
|
|
key="create-risk"
|
|
tooltipContent="Add new risk"
|
|
variant="outline"
|
|
onClick={openForCreate}
|
|
>
|
|
<Plus />
|
|
</IconTextButtonWithTooltip>
|
|
),
|
|
}}
|
|
/>
|
|
|
|
{selectedRisk && (
|
|
<EditRiskModal
|
|
open={editOpen}
|
|
onClose={() => {
|
|
setEditOpen(false);
|
|
setSelectedRisk(null);
|
|
}}
|
|
riskData={selectedRisk}
|
|
onSave={handleEditSave}
|
|
/>
|
|
)}
|
|
|
|
<Dialog open={createOpen} onOpenChange={setCreateOpen}>
|
|
<DialogContent className="max-w-6xl! w-full">
|
|
<DialogHeader>
|
|
<DialogTitle>Add New Risk</DialogTitle>
|
|
</DialogHeader>
|
|
<RiskForm
|
|
projectIdentifier={projectIdentifier}
|
|
onSubmit={handleCreateSubmit}
|
|
/>
|
|
</DialogContent>
|
|
</Dialog>
|
|
</>
|
|
);
|
|
}
|