204 lines
5.8 KiB
TypeScript
204 lines
5.8 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useState } from "react";
|
|
import { DataTable } from "ikoncomponents";
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
} from "ikoncomponents";
|
|
import { ColumnDef } from "@tanstack/react-table";
|
|
import { Plus, SquarePenIcon, Trash } from "lucide-react";
|
|
|
|
import IssueForm from "./components/issueModal";
|
|
import { IconTextButtonWithTooltip } from "ikoncomponents";
|
|
import { DTExtraParamsProps } from "ikoncomponents";
|
|
import EditIssueModal from "./components/editIssue";
|
|
import {
|
|
createIssueApi,
|
|
issuesApi,
|
|
updateIssueApi,
|
|
} from "@/app/utils/api/issueApi";
|
|
import { IssueData } from "@/app/utils/interface/issue";
|
|
import { useAppCache } from "@/app/utils/context/AppCacheContext";
|
|
|
|
interface IssueComponentProps {
|
|
projectIdentifier: string;
|
|
}
|
|
|
|
export default function IssueComponent({
|
|
projectIdentifier,
|
|
}: IssueComponentProps) {
|
|
const { userNameMap } = useAppCache();
|
|
|
|
// ── State ─────────────────────────────────────────────────────
|
|
const [createOpen, setCreateOpen] = useState(false);
|
|
const [editOpen, setEditOpen] = useState(false);
|
|
const [selectedIssue, setSelectedIssue] = useState<IssueData | null>(null);
|
|
const [data, setData] = useState<IssueData[]>([]);
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
// ── Fetch Issues from API ──────────────────────────────────────
|
|
const fetchIssues = async () => {
|
|
try {
|
|
setLoading(true);
|
|
const response = await issuesApi(projectIdentifier);
|
|
|
|
console.log("Issue list response -----> ", response);
|
|
|
|
setData(response?.data || response || []);
|
|
} catch (error) {
|
|
console.error("Error fetching issues:", error);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
fetchIssues();
|
|
}, []);
|
|
|
|
// ── Handlers ───────────────────────────────────────────────────
|
|
const openForCreate = () => setCreateOpen(true);
|
|
|
|
const openForEdit = (issue: IssueData) => {
|
|
setSelectedIssue(issue);
|
|
setEditOpen(true);
|
|
};
|
|
|
|
const handleCreateSubmit = async (formData: IssueData) => {
|
|
try {
|
|
const response = await createIssueApi(formData);
|
|
console.log("Issue created -----> ", response);
|
|
|
|
setCreateOpen(false);
|
|
fetchIssues();
|
|
} catch (error) {
|
|
console.error("Error creating issue:", error);
|
|
}
|
|
};
|
|
|
|
const handleEditSave = async (updatedValues: IssueData) => {
|
|
if (!selectedIssue?.issueId) {
|
|
console.error("No issue selected for update");
|
|
return;
|
|
}
|
|
|
|
console.log("Updated Issue:", updatedValues);
|
|
|
|
const response = await updateIssueApi(
|
|
selectedIssue.issueId,
|
|
updatedValues
|
|
);
|
|
|
|
console.log(response);
|
|
|
|
setEditOpen(false);
|
|
setSelectedIssue(null);
|
|
fetchIssues();
|
|
};
|
|
|
|
// ── Table Columns ─────────────────────────────────────────────
|
|
const columns: ColumnDef<IssueData>[] = [
|
|
{
|
|
accessorKey: "issueDescription",
|
|
header: () => <div className="text-center">Description</div>,
|
|
},
|
|
{
|
|
accessorKey: "issueProbability",
|
|
header: () => <div className="text-center">Probability (%)</div>,
|
|
cell: ({ row }) => <span>{row.original.issueProbability}%</span>,
|
|
},
|
|
{
|
|
accessorKey: "issueImpact",
|
|
header: () => <div className="text-center">Impact</div>,
|
|
},
|
|
{
|
|
accessorKey: "probableIssueValue",
|
|
header: () => <div className="text-center">Score</div>,
|
|
},
|
|
{
|
|
accessorKey: "issueOwner",
|
|
header: () => <div className="text-center">Owner</div>,
|
|
cell: ({ row }) => (
|
|
<span>
|
|
{row.original.issueOwner
|
|
? userNameMap.get(row.original.issueOwner)
|
|
: "N/A"}
|
|
</span>
|
|
),
|
|
},
|
|
{
|
|
accessorKey: "issueStatus",
|
|
header: () => <div className="text-center">Status</div>,
|
|
},
|
|
];
|
|
|
|
// ── DataTable Extra Params ────────────────────────────────────
|
|
const extraParams: DTExtraParamsProps = {
|
|
extraTools: [
|
|
<IconTextButtonWithTooltip
|
|
key="create-issue"
|
|
tooltipContent="Add new issue"
|
|
variant="outline"
|
|
onClick={openForCreate}
|
|
>
|
|
<Plus />
|
|
</IconTextButtonWithTooltip>,
|
|
],
|
|
|
|
actionMenu: {
|
|
items: [
|
|
{
|
|
label: "Edit",
|
|
icon: SquarePenIcon,
|
|
onClick: (row: IssueData) => openForEdit(row),
|
|
},
|
|
{
|
|
label: "Delete",
|
|
icon: Trash,
|
|
onClick: (row: IssueData) => {
|
|
console.log("Delete", row.issueId);
|
|
},
|
|
},
|
|
],
|
|
},
|
|
};
|
|
|
|
// ── Render ────────────────────────────────────────────────────
|
|
return (
|
|
<>
|
|
<DataTable
|
|
columns={columns}
|
|
data={data}
|
|
extraParams={extraParams}
|
|
loading={loading}
|
|
/>
|
|
|
|
{selectedIssue && (
|
|
<EditIssueModal
|
|
open={editOpen}
|
|
onClose={() => {
|
|
setEditOpen(false);
|
|
setSelectedIssue(null);
|
|
}}
|
|
issueData={selectedIssue}
|
|
onSave={handleEditSave}
|
|
/>
|
|
)}
|
|
|
|
<Dialog open={createOpen} onOpenChange={setCreateOpen}>
|
|
<DialogContent className="max-w-6xl! w-full">
|
|
<DialogHeader>
|
|
<DialogTitle>Add New Issue</DialogTitle>
|
|
</DialogHeader>
|
|
<IssueForm
|
|
projectIdentifier={projectIdentifier}
|
|
onSubmit={handleCreateSubmit}
|
|
/>
|
|
</DialogContent>
|
|
</Dialog>
|
|
</>
|
|
);
|
|
} |