251210:1709 Frontend: reeactor organization and run build
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
"use client";
|
||||
|
||||
import { CorrespondenceList } from "@/components/correspondences/list";
|
||||
import { Pagination } from "@/components/common/pagination";
|
||||
import { useCorrespondences } from "@/hooks/use-correspondence";
|
||||
import { useSearchParams } from "next/navigation";
|
||||
import { Loader2 } from "lucide-react";
|
||||
|
||||
export function CorrespondencesContent() {
|
||||
const searchParams = useSearchParams();
|
||||
const page = parseInt(searchParams.get("page") || "1");
|
||||
const status = searchParams.get("status") || undefined;
|
||||
const search = searchParams.get("search") || undefined;
|
||||
|
||||
const { data, isLoading, isError } = useCorrespondences({
|
||||
page,
|
||||
status,
|
||||
search,
|
||||
} as any);
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="flex justify-center py-8">
|
||||
<Loader2 className="h-8 w-8 animate-spin" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (isError) {
|
||||
return (
|
||||
<div className="text-red-500 text-center py-8">
|
||||
Failed to load correspondences.
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<CorrespondenceList data={data} />
|
||||
<div className="mt-4">
|
||||
<Pagination
|
||||
currentPage={data?.page || 1}
|
||||
totalPages={data?.totalPages || 1}
|
||||
total={data?.total || 0}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -26,8 +26,8 @@ export function CorrespondenceDetail({ data }: CorrespondenceDetailProps) {
|
||||
if (confirm("Are you sure you want to submit this correspondence?")) {
|
||||
// TODO: Implement Template Selection. Hardcoded to 1 for now.
|
||||
submitMutation.mutate({
|
||||
id: data.correspondence_id,
|
||||
data: { templateId: 1 }
|
||||
id: data.correspondenceId,
|
||||
data: {}
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -37,7 +37,7 @@ export function CorrespondenceDetail({ data }: CorrespondenceDetailProps) {
|
||||
|
||||
const action = actionState === "approve" ? "APPROVE" : "REJECT";
|
||||
processMutation.mutate({
|
||||
id: data.correspondence_id,
|
||||
id: data.correspondenceId,
|
||||
data: {
|
||||
action,
|
||||
comments
|
||||
@@ -61,9 +61,9 @@ export function CorrespondenceDetail({ data }: CorrespondenceDetailProps) {
|
||||
</Button>
|
||||
</Link>
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold">{data.document_number}</h1>
|
||||
<h1 className="text-2xl font-bold">{data.documentNumber}</h1>
|
||||
<p className="text-muted-foreground">
|
||||
Created on {format(new Date(data.created_at), "dd MMM yyyy HH:mm")}
|
||||
Created on {format(new Date(data.createdAt), "dd MMM yyyy HH:mm")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -200,14 +200,14 @@ export function CorrespondenceDetail({ data }: CorrespondenceDetailProps) {
|
||||
|
||||
<div>
|
||||
<p className="text-sm font-medium text-muted-foreground">From Organization</p>
|
||||
<p className="font-medium mt-1">{data.from_organization?.org_name}</p>
|
||||
<p className="text-xs text-muted-foreground">{data.from_organization?.org_code}</p>
|
||||
<p className="font-medium mt-1">{data.fromOrganization?.orgName}</p>
|
||||
<p className="text-xs text-muted-foreground">{data.fromOrganization?.orgCode}</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<p className="text-sm font-medium text-muted-foreground">To Organization</p>
|
||||
<p className="font-medium mt-1">{data.to_organization?.org_name}</p>
|
||||
<p className="text-xs text-muted-foreground">{data.to_organization?.org_code}</p>
|
||||
<p className="font-medium mt-1">{data.toOrganization?.orgName}</p>
|
||||
<p className="text-xs text-muted-foreground">{data.toOrganization?.orgCode}</p>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
@@ -25,10 +25,10 @@ import { CreateCorrespondenceDto } from "@/types/dto/correspondence/create-corre
|
||||
const correspondenceSchema = z.object({
|
||||
subject: z.string().min(5, "Subject must be at least 5 characters"),
|
||||
description: z.string().optional(),
|
||||
document_type_id: z.number().default(1),
|
||||
from_organization_id: z.number().min(1, "Please select From Organization"),
|
||||
to_organization_id: z.number().min(1, "Please select To Organization"),
|
||||
importance: z.enum(["NORMAL", "HIGH", "URGENT"]).default("NORMAL"),
|
||||
documentTypeId: z.number(),
|
||||
fromOrganizationId: z.number().min(1, "Please select From Organization"),
|
||||
toOrganizationId: z.number().min(1, "Please select To Organization"),
|
||||
importance: z.enum(["NORMAL", "HIGH", "URGENT"]),
|
||||
attachments: z.array(z.instanceof(File)).optional(),
|
||||
});
|
||||
|
||||
@@ -48,7 +48,7 @@ export function CorrespondenceForm() {
|
||||
resolver: zodResolver(correspondenceSchema),
|
||||
defaultValues: {
|
||||
importance: "NORMAL",
|
||||
document_type_id: 1,
|
||||
documentTypeId: 1,
|
||||
} as any, // Cast to any to handle partial defaults for required fields
|
||||
});
|
||||
|
||||
@@ -57,12 +57,12 @@ export function CorrespondenceForm() {
|
||||
// Note: projectId is hardcoded to 1 for now as per requirements/context
|
||||
const payload: CreateCorrespondenceDto = {
|
||||
projectId: 1,
|
||||
typeId: data.document_type_id,
|
||||
typeId: data.documentTypeId,
|
||||
title: data.subject,
|
||||
description: data.description,
|
||||
originatorId: data.from_organization_id, // Mapping From -> Originator (Impersonation)
|
||||
originatorId: data.fromOrganizationId, // Mapping From -> Originator (Impersonation)
|
||||
details: {
|
||||
to_organization_id: data.to_organization_id,
|
||||
to_organization_id: data.toOrganizationId,
|
||||
importance: data.importance
|
||||
},
|
||||
// create-correspondence DTO does not have 'attachments' field at root usually, often handled separate or via multipart
|
||||
@@ -102,7 +102,7 @@ export function CorrespondenceForm() {
|
||||
<div className="space-y-2">
|
||||
<Label>From Organization *</Label>
|
||||
<Select
|
||||
onValueChange={(v) => setValue("from_organization_id", parseInt(v))}
|
||||
onValueChange={(v) => setValue("fromOrganizationId", parseInt(v))}
|
||||
disabled={isLoadingOrgs}
|
||||
>
|
||||
<SelectTrigger>
|
||||
@@ -116,15 +116,15 @@ export function CorrespondenceForm() {
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
{errors.from_organization_id && (
|
||||
<p className="text-sm text-destructive">{errors.from_organization_id.message}</p>
|
||||
{errors.fromOrganizationId && (
|
||||
<p className="text-sm text-destructive">{errors.fromOrganizationId.message}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label>To Organization *</Label>
|
||||
<Select
|
||||
onValueChange={(v) => setValue("to_organization_id", parseInt(v))}
|
||||
onValueChange={(v) => setValue("toOrganizationId", parseInt(v))}
|
||||
disabled={isLoadingOrgs}
|
||||
>
|
||||
<SelectTrigger>
|
||||
@@ -138,8 +138,8 @@ export function CorrespondenceForm() {
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
{errors.to_organization_id && (
|
||||
<p className="text-sm text-destructive">{errors.to_organization_id.message}</p>
|
||||
{errors.toOrganizationId && (
|
||||
<p className="text-sm text-destructive">{errors.toOrganizationId.message}</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -21,10 +21,10 @@ interface CorrespondenceListProps {
|
||||
export function CorrespondenceList({ data }: CorrespondenceListProps) {
|
||||
const columns: ColumnDef<Correspondence>[] = [
|
||||
{
|
||||
accessorKey: "document_number",
|
||||
accessorKey: "documentNumber",
|
||||
header: "Document No.",
|
||||
cell: ({ row }) => (
|
||||
<span className="font-medium">{row.getValue("document_number")}</span>
|
||||
<span className="font-medium">{row.getValue("documentNumber")}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
@@ -37,17 +37,17 @@ export function CorrespondenceList({ data }: CorrespondenceListProps) {
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: "from_organization.org_name",
|
||||
accessorKey: "fromOrganization.orgName",
|
||||
header: "From",
|
||||
},
|
||||
{
|
||||
accessorKey: "to_organization.org_name",
|
||||
accessorKey: "toOrganization.orgName",
|
||||
header: "To",
|
||||
},
|
||||
{
|
||||
accessorKey: "created_at",
|
||||
header: "Date",
|
||||
cell: ({ row }) => format(new Date(row.getValue("created_at")), "dd MMM yyyy"),
|
||||
accessorKey: "createdAt",
|
||||
header: "Created",
|
||||
cell: ({ row }) => format(new Date(row.getValue("createdAt")), "dd MMM yyyy"),
|
||||
},
|
||||
{
|
||||
accessorKey: "status",
|
||||
@@ -60,13 +60,13 @@ export function CorrespondenceList({ data }: CorrespondenceListProps) {
|
||||
const item = row.original;
|
||||
return (
|
||||
<div className="flex gap-2">
|
||||
<Link href={`/correspondences/${item.correspondence_id}`}>
|
||||
<Link href={`/correspondences/${row.original.correspondenceId}`}>
|
||||
<Button variant="ghost" size="icon" title="View">
|
||||
<Eye className="h-4 w-4" />
|
||||
</Button>
|
||||
</Link>
|
||||
{item.status === "DRAFT" && (
|
||||
<Link href={`/correspondences/${item.correspondence_id}/edit`}>
|
||||
<Link href={`/correspondences/${row.original.correspondenceId}/edit`}>
|
||||
<Button variant="ghost" size="icon" title="Edit">
|
||||
<Edit className="h-4 w-4" />
|
||||
</Button>
|
||||
|
||||
Reference in New Issue
Block a user