260322:1648 Correct Coresspondence / Doing RFA / Correct CI
CI Pipeline / build (push) Failing after 12m41s
Build and Deploy / deploy (push) Failing after 2m44s

This commit is contained in:
admin
2026-03-22 16:48:12 +07:00
parent e5deedb42e
commit 11984bfa29
683 changed files with 105251 additions and 29068 deletions
@@ -1,25 +1,25 @@
"use client";
'use client';
import { use, useState } from "react";
import { notFound, useRouter, useSearchParams } from "next/navigation";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Textarea } from "@/components/ui/textarea";
import { Label } from "@/components/ui/label";
import { ArrowLeft, Download, FileText, Loader2, Pencil, Upload, X } from "lucide-react";
import Link from "next/link";
import { Badge } from "@/components/ui/badge";
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 { useQuery, useQueryClient } from "@tanstack/react-query";
import { contractDrawingService } from "@/lib/services/contract-drawing.service";
import { shopDrawingService } from "@/lib/services/shop-drawing.service";
import { asBuiltDrawingService } from "@/lib/services/asbuilt-drawing.service";
import { useUpdateContractDrawing, useUploadRevision } from "@/hooks/use-drawing";
import { use, useState } from 'react';
import { notFound, useRouter, useSearchParams } from 'next/navigation';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Textarea } from '@/components/ui/textarea';
import { Label } from '@/components/ui/label';
import { ArrowLeft, Download, FileText, Loader2, Pencil, Upload, X } from 'lucide-react';
import Link from 'next/link';
import { Badge } from '@/components/ui/badge';
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 { useQuery, useQueryClient } from '@tanstack/react-query';
import { contractDrawingService } from '@/lib/services/contract-drawing.service';
import { shopDrawingService } from '@/lib/services/shop-drawing.service';
import { asBuiltDrawingService } from '@/lib/services/asbuilt-drawing.service';
import { useUpdateContractDrawing, useUploadRevision } from '@/hooks/use-drawing';
type DrawingType = "CONTRACT" | "SHOP" | "AS_BUILT";
type DrawingType = 'CONTRACT' | 'SHOP' | 'AS_BUILT';
interface FetchedDrawing {
_type: DrawingType;
@@ -31,41 +31,56 @@ interface FetchedDrawing {
createdAt?: string;
updatedAt?: string;
currentRevision?: { title?: string; revisionNumber?: string; legacyDrawingNumber?: string };
revisions?: { revisionId?: number; uuid: string; revisionNumber: string; title?: string; legacyDrawingNumber?: string; revisionDate: string; revisionDescription?: string; revisedByName: string; fileUrl: string; isCurrent: boolean | null; createdBy?: number; updatedBy?: number }[];
revisions?: {
revisionId?: number;
uuid: string;
revisionNumber: string;
title?: string;
legacyDrawingNumber?: string;
revisionDate: string;
revisionDescription?: string;
revisedByName: string;
fileUrl: string;
isCurrent: boolean | null;
createdBy?: number;
updatedBy?: number;
}[];
}
async function fetchDrawingByUuid(uuid: string): Promise<FetchedDrawing | null> {
try {
const result = await contractDrawingService.getByUuid(uuid);
if (result?.data) return { ...result.data, _type: "CONTRACT" as const };
} catch { /* not found */ }
if (result?.data) return { ...result.data, _type: 'CONTRACT' as const };
} catch {
/* not found */
}
try {
const result = await shopDrawingService.getByUuid(uuid);
if (result?.data) return { ...result.data, _type: "SHOP" as const };
} catch { /* not found */ }
if (result?.data) return { ...result.data, _type: 'SHOP' as const };
} catch {
/* not found */
}
try {
const result = await asBuiltDrawingService.getByUuid(uuid);
if (result?.data) return { ...result.data, _type: "AS_BUILT" as const };
} catch { /* not found */ }
if (result?.data) return { ...result.data, _type: 'AS_BUILT' as const };
} catch {
/* not found */
}
return null;
}
export default function DrawingDetailPage({
params,
}: {
params: Promise<{ uuid: string }>;
}) {
export default function DrawingDetailPage({ params }: { params: Promise<{ uuid: string }> }) {
const { uuid } = use(params);
const router = useRouter();
const searchParams = useSearchParams();
const isEditMode = searchParams.get("edit") === "true";
const isUploadMode = searchParams.get("upload") === "true";
const isEditMode = searchParams.get('edit') === 'true';
const isUploadMode = searchParams.get('upload') === 'true';
const { data: drawing, isLoading } = useQuery({
queryKey: ["drawing-detail", uuid],
queryKey: ['drawing-detail', uuid],
queryFn: () => fetchDrawingByUuid(uuid),
enabled: !!uuid,
});
@@ -100,8 +115,8 @@ export default function DrawingDetailPage({
);
}
const drawingNumber = drawing.contractDrawingNo || drawing.drawingNumber || "N/A";
const title = drawing.title || drawing.currentRevision?.title || "Untitled";
const drawingNumber = drawing.contractDrawingNo || drawing.drawingNumber || 'N/A';
const title = drawing.title || drawing.currentRevision?.title || 'Untitled';
const revisions = drawing.revisions || [];
return (
@@ -129,7 +144,7 @@ export default function DrawingDetailPage({
Edit Detail
</Link>
</Button>
{drawing._type !== "CONTRACT" && (
{drawing._type !== 'CONTRACT' && (
<Button variant="outline" asChild>
<Link href={`/drawings/${uuid}?upload=true`}>
<Upload className="mr-2 h-4 w-4" />
@@ -155,12 +170,10 @@ export default function DrawingDetailPage({
</div>
{/* Edit Detail Form */}
{isEditMode && (
<EditDetailForm drawing={drawing} uuid={uuid} onDone={() => router.push(`/drawings/${uuid}`)} />
)}
{isEditMode && <EditDetailForm drawing={drawing} uuid={uuid} onDone={() => router.push(`/drawings/${uuid}`)} />}
{/* Upload Revision Form */}
{isUploadMode && drawing._type !== "CONTRACT" && (
{isUploadMode && drawing._type !== 'CONTRACT' && (
<UploadRevisionForm drawingType={drawing._type} uuid={uuid} onDone={() => router.push(`/drawings/${uuid}`)} />
)}
@@ -194,7 +207,7 @@ export default function DrawingDetailPage({
<div>
<p className="text-sm font-medium text-muted-foreground">Created</p>
<p className="font-medium mt-1">
{drawing.createdAt ? format(new Date(drawing.createdAt), "dd MMM yyyy") : "N/A"}
{drawing.createdAt ? format(new Date(drawing.createdAt), 'dd MMM yyyy') : 'N/A'}
</p>
</div>
</div>
@@ -224,36 +237,28 @@ export default function DrawingDetailPage({
}
/* ─── Edit Detail Form ─── */
function EditDetailForm({
drawing,
uuid,
onDone,
}: {
drawing: FetchedDrawing;
uuid: string;
onDone: () => void;
}) {
function EditDetailForm({ drawing, uuid, onDone }: { drawing: FetchedDrawing; uuid: string; onDone: () => void }) {
const updateMutation = useUpdateContractDrawing();
const queryClient = useQueryClient();
const [formTitle, setFormTitle] = useState(drawing.title || drawing.currentRevision?.title || "");
const [formDrawingNo, setFormDrawingNo] = useState(drawing.contractDrawingNo || drawing.drawingNumber || "");
const [formVolumePage, setFormVolumePage] = useState(drawing.volumePage?.toString() || "");
const [formTitle, setFormTitle] = useState(drawing.title || drawing.currentRevision?.title || '');
const [formDrawingNo, setFormDrawingNo] = useState(drawing.contractDrawingNo || drawing.drawingNumber || '');
const [formVolumePage, setFormVolumePage] = useState(drawing.volumePage?.toString() || '');
const handleSave = () => {
if (drawing._type === "CONTRACT") {
if (drawing._type === 'CONTRACT') {
updateMutation.mutate(
{
uuid,
data: {
title: formTitle,
contractDrawingNo: formDrawingNo,
volumePage: formVolumePage ? parseInt(formVolumePage, 10) : undefined,
volumePage: formVolumePage ? Number(formVolumePage) : undefined,
},
},
{
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["drawing-detail", uuid] });
queryClient.invalidateQueries({ queryKey: ['drawing-detail', uuid] });
onDone();
},
}
@@ -273,7 +278,7 @@ function EditDetailForm({
<Label>Title</Label>
<Input value={formTitle} onChange={(e) => setFormTitle(e.target.value)} />
</div>
{drawing._type === "CONTRACT" && (
{drawing._type === 'CONTRACT' && (
<div>
<Label>Volume Page</Label>
<Input type="number" value={formVolumePage} onChange={(e) => setFormVolumePage(e.target.value)} />
@@ -306,10 +311,10 @@ function UploadRevisionForm({
const uploadMutation = useUploadRevision(drawingType);
const queryClient = useQueryClient();
const [revisionLabel, setRevisionLabel] = useState("");
const [revTitle, setRevTitle] = useState("");
const [description, setDescription] = useState("");
const [legacyNo, setLegacyNo] = useState("");
const [revisionLabel, setRevisionLabel] = useState('');
const [revTitle, setRevTitle] = useState('');
const [description, setDescription] = useState('');
const [legacyNo, setLegacyNo] = useState('');
const handleUpload = () => {
if (!revisionLabel || !revTitle) return;
@@ -327,7 +332,7 @@ function UploadRevisionForm({
},
{
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["drawing-detail", uuid] });
queryClient.invalidateQueries({ queryKey: ['drawing-detail', uuid] });
onDone();
},
}
@@ -341,7 +346,11 @@ function UploadRevisionForm({
<div className="grid grid-cols-2 gap-4">
<div>
<Label>Revision Label *</Label>
<Input placeholder="e.g. A, B, 1, 2" value={revisionLabel} onChange={(e) => setRevisionLabel(e.target.value)} />
<Input
placeholder="e.g. A, B, 1, 2"
value={revisionLabel}
onChange={(e) => setRevisionLabel(e.target.value)}
/>
</div>
<div>
<Label>Legacy Drawing No.</Label>
@@ -354,7 +363,12 @@ function UploadRevisionForm({
</div>
<div>
<Label>Description</Label>
<Textarea placeholder="What changed in this revision?" value={description} onChange={(e) => setDescription(e.target.value)} rows={3} />
<Textarea
placeholder="What changed in this revision?"
value={description}
onChange={(e) => setDescription(e.target.value)}
rows={3}
/>
</div>
<div className="flex gap-3 pt-2">
<Button onClick={handleUpload} disabled={uploadMutation.isPending || !revisionLabel || !revTitle}>