This commit is contained in:
@@ -63,7 +63,7 @@ export default function OrganizationsPage() {
|
||||
|
||||
const confirmDelete = () => {
|
||||
if (orgToDelete) {
|
||||
deleteOrg.mutate(orgToDelete.id, {
|
||||
deleteOrg.mutate(orgToDelete.uuid, {
|
||||
onSuccess: () => {
|
||||
setDeleteDialogOpen(false);
|
||||
setOrgToDelete(null);
|
||||
|
||||
@@ -64,7 +64,7 @@ export default function UsersPage() {
|
||||
|
||||
const confirmDelete = () => {
|
||||
if (userToDelete) {
|
||||
deleteMutation.mutate(userToDelete.userId, {
|
||||
deleteMutation.mutate(userToDelete.uuid, {
|
||||
onSuccess: () => {
|
||||
setDeleteDialogOpen(false);
|
||||
setUserToDelete(null);
|
||||
@@ -186,7 +186,7 @@ export default function UsersPage() {
|
||||
<SelectContent>
|
||||
<SelectItem value="all">All Organizations</SelectItem>
|
||||
{Array.isArray(organizations) && (organizations as Organization[]).map((org) => (
|
||||
<SelectItem key={org.id} value={org.id.toString()}>
|
||||
<SelectItem key={org.uuid} value={(org.id ?? org.uuid).toString()}>
|
||||
{org.organizationCode} - {org.organizationName}
|
||||
</SelectItem>
|
||||
))}
|
||||
|
||||
@@ -56,7 +56,8 @@ interface Project {
|
||||
}
|
||||
|
||||
interface Contract {
|
||||
id: number;
|
||||
uuid: string;
|
||||
id?: number; // Excluded from API responses (ADR-019)
|
||||
contractCode: string;
|
||||
contractName: string;
|
||||
projectId: number;
|
||||
@@ -112,7 +113,7 @@ export default function ContractsPage() {
|
||||
});
|
||||
|
||||
const updateContract = useMutation({
|
||||
mutationFn: ({ id, data }: { id: number, data: UpdateContractDto }) => apiClient.patch(`/contracts/${id}`, data).then(res => res.data),
|
||||
mutationFn: ({ uuid, data }: { uuid: string, data: UpdateContractDto }) => apiClient.patch(`/contracts/${uuid}`, data).then(res => res.data),
|
||||
onSuccess: () => {
|
||||
toast.success("Contract updated successfully");
|
||||
queryClient.invalidateQueries({ queryKey: ['contracts'] });
|
||||
@@ -122,7 +123,7 @@ export default function ContractsPage() {
|
||||
});
|
||||
|
||||
const deleteContract = useMutation({
|
||||
mutationFn: (id: number) => apiClient.delete(`/contracts/${id}`).then(res => res.data),
|
||||
mutationFn: (uuid: string) => apiClient.delete(`/contracts/${uuid}`).then(res => res.data),
|
||||
onSuccess: () => {
|
||||
toast.success("Contract deleted successfully");
|
||||
queryClient.invalidateQueries({ queryKey: ['contracts'] });
|
||||
@@ -131,7 +132,7 @@ export default function ContractsPage() {
|
||||
});
|
||||
|
||||
const [dialogOpen, setDialogOpen] = useState(false);
|
||||
const [editingId, setEditingId] = useState<number | null>(null);
|
||||
const [editingUuid, setEditingUuid] = useState<string | null>(null);
|
||||
|
||||
// Stats for Delete Dialog
|
||||
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
|
||||
@@ -144,7 +145,7 @@ export default function ContractsPage() {
|
||||
|
||||
const confirmDelete = () => {
|
||||
if (contractToDelete) {
|
||||
deleteContract.mutate(contractToDelete.id, {
|
||||
deleteContract.mutate(contractToDelete.uuid, {
|
||||
onSuccess: () => {
|
||||
setDeleteDialogOpen(false);
|
||||
setContractToDelete(null);
|
||||
@@ -212,7 +213,7 @@ export default function ContractsPage() {
|
||||
];
|
||||
|
||||
const handleEdit = (contract: Contract) => {
|
||||
setEditingId(contract.id);
|
||||
setEditingUuid(contract.uuid);
|
||||
reset({
|
||||
contractCode: contract.contractCode,
|
||||
contractName: contract.contractName,
|
||||
@@ -225,7 +226,7 @@ export default function ContractsPage() {
|
||||
};
|
||||
|
||||
const handleCreate = () => {
|
||||
setEditingId(null);
|
||||
setEditingUuid(null);
|
||||
reset({
|
||||
contractCode: "",
|
||||
contractName: "",
|
||||
@@ -243,8 +244,8 @@ export default function ContractsPage() {
|
||||
projectId: parseInt(data.projectId),
|
||||
};
|
||||
|
||||
if (editingId) {
|
||||
updateContract.mutate({ id: editingId, data: submitData });
|
||||
if (editingUuid) {
|
||||
updateContract.mutate({ uuid: editingUuid, data: submitData });
|
||||
} else {
|
||||
createContract.mutate(submitData);
|
||||
}
|
||||
@@ -289,7 +290,7 @@ export default function ContractsPage() {
|
||||
<Dialog open={dialogOpen} onOpenChange={setDialogOpen}>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>{editingId ? "Edit Contract" : "New Contract"}</DialogTitle>
|
||||
<DialogTitle>{editingUuid ? "Edit Contract" : "New Contract"}</DialogTitle>
|
||||
</DialogHeader>
|
||||
<form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
|
||||
|
||||
@@ -363,7 +364,7 @@ export default function ContractsPage() {
|
||||
Cancel
|
||||
</Button>
|
||||
<Button type="submit" disabled={createContract.isPending || updateContract.isPending}>
|
||||
{editingId ? "Save Changes" : "Create Contract"}
|
||||
{editingUuid ? "Save Changes" : "Create Contract"}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</form>
|
||||
|
||||
@@ -44,7 +44,8 @@ import {
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
|
||||
interface Project {
|
||||
id: number;
|
||||
uuid: string;
|
||||
id?: number; // Excluded from API responses (ADR-019)
|
||||
projectCode: string;
|
||||
projectName: string;
|
||||
isActive: boolean;
|
||||
@@ -69,7 +70,7 @@ export default function ProjectsPage() {
|
||||
const deleteProject = useDeleteProject();
|
||||
|
||||
const [dialogOpen, setDialogOpen] = useState(false);
|
||||
const [editingId, setEditingId] = useState<number | null>(null);
|
||||
const [editingUuid, setEditingUuid] = useState<string | null>(null);
|
||||
|
||||
// Stats for Delete Dialog
|
||||
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
|
||||
@@ -82,7 +83,7 @@ export default function ProjectsPage() {
|
||||
|
||||
const confirmDelete = () => {
|
||||
if (projectToDelete) {
|
||||
deleteProject.mutate(projectToDelete.id, {
|
||||
deleteProject.mutate(projectToDelete.uuid, {
|
||||
onSuccess: () => {
|
||||
setDeleteDialogOpen(false);
|
||||
setProjectToDelete(null);
|
||||
@@ -156,7 +157,7 @@ export default function ProjectsPage() {
|
||||
];
|
||||
|
||||
const handleEdit = (project: Project) => {
|
||||
setEditingId(project.id);
|
||||
setEditingUuid(project.uuid);
|
||||
reset({
|
||||
projectCode: project.projectCode,
|
||||
projectName: project.projectName,
|
||||
@@ -166,7 +167,7 @@ export default function ProjectsPage() {
|
||||
};
|
||||
|
||||
const handleCreate = () => {
|
||||
setEditingId(null);
|
||||
setEditingUuid(null);
|
||||
reset({
|
||||
projectCode: "",
|
||||
projectName: "",
|
||||
@@ -176,9 +177,9 @@ export default function ProjectsPage() {
|
||||
};
|
||||
|
||||
const onSubmit = (data: ProjectFormData) => {
|
||||
if (editingId) {
|
||||
if (editingUuid) {
|
||||
updateProject.mutate(
|
||||
{ id: editingId, data },
|
||||
{ uuid: editingUuid, data },
|
||||
{
|
||||
onSuccess: () => setDialogOpen(false),
|
||||
}
|
||||
@@ -232,7 +233,7 @@ export default function ProjectsPage() {
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>
|
||||
{editingId ? "Edit Project" : "New Project"}
|
||||
{editingUuid ? "Edit Project" : "New Project"}
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
<form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
|
||||
@@ -241,7 +242,7 @@ export default function ProjectsPage() {
|
||||
<Input
|
||||
placeholder="e.g. LCBP3"
|
||||
{...register("projectCode")}
|
||||
disabled={!!editingId} // Code is immutable after creation usually
|
||||
disabled={!!editingUuid} // Code is immutable after creation usually
|
||||
/>
|
||||
{errors.projectCode && (
|
||||
<p className="text-sm text-red-500">{errors.projectCode.message}</p>
|
||||
@@ -280,7 +281,7 @@ export default function ProjectsPage() {
|
||||
type="submit"
|
||||
disabled={createProject.isPending || updateProject.isPending}
|
||||
>
|
||||
{editingId ? "Save Changes" : "Create Project"}
|
||||
{editingUuid ? "Save Changes" : "Create Project"}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</form>
|
||||
|
||||
+7
-8
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { useParams, useRouter } from "next/navigation";
|
||||
import { useParams } from "next/navigation";
|
||||
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import { circulationService } from "@/lib/services/circulation.service";
|
||||
import { Circulation, UpdateCirculationRoutingDto } from "@/types/circulation";
|
||||
@@ -42,14 +42,13 @@ function getStatusVariant(status: string): "default" | "secondary" | "destructiv
|
||||
|
||||
export default function CirculationDetailPage() {
|
||||
const params = useParams();
|
||||
const router = useRouter();
|
||||
const queryClient = useQueryClient();
|
||||
const id = params.id as string;
|
||||
const uuid = params.uuid as string;
|
||||
|
||||
const { data: circulation, isLoading, error } = useQuery<Circulation>({
|
||||
queryKey: ["circulation", id],
|
||||
queryFn: () => circulationService.getById(id),
|
||||
enabled: !!id,
|
||||
queryKey: ["circulation", uuid],
|
||||
queryFn: () => circulationService.getByUuid(uuid),
|
||||
enabled: !!uuid,
|
||||
});
|
||||
|
||||
const completeMutation = useMutation({
|
||||
@@ -57,7 +56,7 @@ export default function CirculationDetailPage() {
|
||||
circulationService.updateRouting(routingId, data),
|
||||
onSuccess: () => {
|
||||
toast.success("Task completed successfully");
|
||||
queryClient.invalidateQueries({ queryKey: ["circulation", id] });
|
||||
queryClient.invalidateQueries({ queryKey: ["circulation", uuid] });
|
||||
},
|
||||
onError: () => {
|
||||
toast.error("Failed to update task status");
|
||||
@@ -146,7 +145,7 @@ export default function CirculationDetailPage() {
|
||||
<div>
|
||||
<p className="text-sm text-muted-foreground">Linked Document</p>
|
||||
<Link
|
||||
href={`/correspondences/${circulation.correspondenceId}`}
|
||||
href={`/correspondences/${circulation.correspondence.uuid}`}
|
||||
className="font-medium text-primary hover:underline"
|
||||
>
|
||||
{circulation.correspondence.correspondence_number}
|
||||
@@ -83,7 +83,7 @@ export default function CreateCirculationPage() {
|
||||
mutationFn: (data: CreateCirculationDto) => circulationService.create(data),
|
||||
onSuccess: (result) => {
|
||||
toast.success("Circulation created successfully");
|
||||
router.push(`/circulation/${result.id}`);
|
||||
router.push(`/circulation/${result.uuid}`);
|
||||
},
|
||||
onError: () => {
|
||||
toast.error("Failed to create circulation");
|
||||
@@ -232,7 +232,7 @@ export default function CreateCirculationPage() {
|
||||
<div className="flex flex-wrap gap-1">
|
||||
{selectedAssignees.map((userId) => {
|
||||
const user = users.find(
|
||||
(u: { userId: number }) => u.userId === userId
|
||||
(u) => u.userId === userId
|
||||
);
|
||||
return user ? (
|
||||
<Badge
|
||||
@@ -267,16 +267,16 @@ export default function CreateCirculationPage() {
|
||||
<CommandList>
|
||||
<CommandEmpty>No user found.</CommandEmpty>
|
||||
<CommandGroup>
|
||||
{users.map((user: { userId: number; username: string; firstName?: string; lastName?: string }) => (
|
||||
{users.map((user) => (
|
||||
<CommandItem
|
||||
key={user.userId}
|
||||
key={user.userId ?? user.uuid}
|
||||
value={user.username}
|
||||
onSelect={() => toggleAssignee(user.userId)}
|
||||
onSelect={() => user.userId && toggleAssignee(user.userId)}
|
||||
>
|
||||
<Check
|
||||
className={cn(
|
||||
"mr-2 h-4 w-4",
|
||||
selectedAssignees.includes(user.userId)
|
||||
user.userId != null && selectedAssignees.includes(user.userId)
|
||||
? "opacity-100"
|
||||
: "opacity-0"
|
||||
)}
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import { CorrespondenceForm } from "@/components/correspondences/form";
|
||||
import { useCorrespondence } from "@/hooks/use-correspondence";
|
||||
import { Loader2 } from "lucide-react";
|
||||
import { useParams } from "next/navigation";
|
||||
|
||||
export default function EditCorrespondencePage() {
|
||||
const params = useParams();
|
||||
const id = Number(params?.id);
|
||||
|
||||
const { data: correspondence, isLoading, isError } = useCorrespondence(id);
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="flex bg-muted/20 min-h-screen justify-center items-center">
|
||||
<Loader2 className="h-8 w-8 animate-spin" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (isError || !correspondence) {
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center min-h-screen">
|
||||
<h1 className="text-xl font-bold text-red-500">Failed to load correspondence</h1>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="max-w-4xl mx-auto py-6">
|
||||
<div className="mb-8">
|
||||
<h1 className="text-3xl font-bold">Edit Correspondence</h1>
|
||||
<p className="text-muted-foreground mt-1">
|
||||
{correspondence.correspondenceNumber}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="bg-card border rounded-lg p-6 shadow-sm">
|
||||
<CorrespondenceForm initialData={correspondence} id={id} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
+7
-13
@@ -3,27 +3,22 @@
|
||||
import { CorrespondenceDetail } from "@/components/correspondences/detail";
|
||||
import { useCorrespondence } from "@/hooks/use-correspondence";
|
||||
import { Loader2 } from "lucide-react";
|
||||
import { notFound, useParams } from "next/navigation";
|
||||
import { useParams } from "next/navigation";
|
||||
|
||||
export default function CorrespondenceDetailPage() {
|
||||
const params = useParams();
|
||||
const id = Number(params?.id); // useParams returns string | string[]
|
||||
const uuid = (params?.uuid as string) ?? '';
|
||||
|
||||
if (isNaN(id)) {
|
||||
// We can't use notFound() directly in client component render without breaking sometimes,
|
||||
// but typically it works. Better to handle gracefully or redirect.
|
||||
// For now, let's keep it or return 404 UI.
|
||||
// Actually notFound() is for server components mostly.
|
||||
// Let's just return our error UI if ID is invalid.
|
||||
const { data: correspondence, isLoading, isError } = useCorrespondence(uuid);
|
||||
|
||||
if (!uuid) {
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center min-h-screen">
|
||||
<h1 className="text-xl font-bold text-red-500">Invalid Correspondence ID</h1>
|
||||
<h1 className="text-xl font-bold text-red-500">Invalid Correspondence UUID</h1>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const { data: correspondence, isLoading, isError } = useCorrespondence(id);
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="flex bg-muted/20 min-h-screen justify-center items-center">
|
||||
@@ -33,11 +28,10 @@ export default function CorrespondenceDetailPage() {
|
||||
}
|
||||
|
||||
if (isError || !correspondence) {
|
||||
// Optionally handle 404 vs other errors differently, but for now simple handling
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center min-h-screen">
|
||||
<h1 className="text-xl font-bold text-red-500">Failed to load correspondence</h1>
|
||||
<p>Please try again later or verify the ID.</p>
|
||||
<p>Please try again later or verify the UUID.</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
+8
-6
@@ -1,4 +1,3 @@
|
||||
import { drawingApi } from "@/lib/api/drawings";
|
||||
import { notFound } from "next/navigation";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { ArrowLeft, Download, FileText, GitCompare } from "lucide-react";
|
||||
@@ -8,19 +7,22 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { RevisionHistory } from "@/components/drawings/revision-history";
|
||||
import { format } from "date-fns";
|
||||
import { drawingApi } from "@/lib/api/drawings";
|
||||
|
||||
export default async function DrawingDetailPage({
|
||||
params,
|
||||
}: {
|
||||
params: Promise<{ id: string }>;
|
||||
params: Promise<{ uuid: string }>;
|
||||
}) {
|
||||
const { id: rawId } = await params;
|
||||
const id = parseInt(rawId);
|
||||
if (isNaN(id)) {
|
||||
const { uuid } = await params;
|
||||
if (!uuid) {
|
||||
notFound();
|
||||
}
|
||||
|
||||
const drawing = await drawingApi.getById(id);
|
||||
// TODO: Replace mock drawingApi with real service call using UUID
|
||||
// For now, keep using the mock API with a numeric fallback
|
||||
const drawingId = parseInt(uuid);
|
||||
const drawing = !isNaN(drawingId) ? await drawingApi.getById(drawingId) : undefined;
|
||||
|
||||
if (!drawing) {
|
||||
notFound();
|
||||
Reference in New Issue
Block a user