260318:1237 Fix UUID #4
Build and Deploy / deploy (push) Successful in 11m17s

This commit is contained in:
admin
2026-03-18 12:37:29 +07:00
parent 5d89079c2a
commit ba642e7e42
71 changed files with 533 additions and 319 deletions
@@ -44,7 +44,7 @@ export default function UsersPage() {
const { data: users, isLoading } = useUsers({
search: search || undefined,
primaryOrganizationId: selectedOrgId ? parseInt(selectedOrgId) : undefined,
primaryOrganizationId: selectedOrgId ?? undefined,
});
const { data: organizations = [] } = useOrganizations();
@@ -94,7 +94,7 @@ export default function UsersPage() {
header: "Organization",
cell: ({ row }) => {
const orgId = row.original.primaryOrganizationId;
const org = (organizations as Organization[]).find((o) => o.id === orgId);
const org = (organizations as Organization[]).find((o) => (o.id ?? o.uuid) === orgId?.toString() || o.uuid === orgId?.toString());
return org ? org.organizationCode : "-";
},
},
@@ -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.uuid} value={(org.id ?? org.uuid).toString()}>
<SelectItem key={org.uuid} value={org.uuid}>
{org.organizationCode} - {org.organizationName}
</SelectItem>
))}
+1 -1
View File
@@ -14,7 +14,7 @@ function RFAsContent() {
const page = parseInt(searchParams.get('page') || '1');
const statusId = searchParams.get('status') ? parseInt(searchParams.get('status')!) : undefined;
const search = searchParams.get('search') || undefined;
const projectId = searchParams.get('projectId') ? parseInt(searchParams.get('projectId')!) : undefined;
const projectId = searchParams.get('projectId') || undefined; // ADR-019: Pass UUID string directly
const revisionStatus = (searchParams.get('revisionStatus') as 'CURRENT' | 'ALL' | 'OLD') || 'CURRENT';
+6 -9
View File
@@ -36,7 +36,7 @@ const userSchema = z.object({
confirmPassword: z.string().optional(),
isActive: z.boolean().optional(),
lineId: z.string().optional(),
primaryOrganizationId: z.number().optional(),
primaryOrganizationId: z.string().optional(),
roleIds: z.array(z.number()).optional(),
}).refine((data) => {
// If password is provided (creating or resetting), confirmPassword must match
@@ -107,7 +107,7 @@ export function UserDialog({ open, onOpenChange, user }: UserDialogProps) {
lastName: user.lastName,
isActive: user.isActive,
lineId: user.lineId || "",
primaryOrganizationId: user.primaryOrganizationId,
primaryOrganizationId: user.primaryOrganizationId?.toString(),
roleIds: user.roles?.map((r: any) => r.roleId) || [],
password: "",
confirmPassword: ""
@@ -221,22 +221,19 @@ export function UserDialog({ open, onOpenChange, user }: UserDialogProps) {
<div>
<Label>Primary Organization</Label>
<Select
value={watch("primaryOrganizationId")?.toString()}
value={watch("primaryOrganizationId") ?? undefined}
onValueChange={(val) =>
setValue("primaryOrganizationId", parseInt(val))
setValue("primaryOrganizationId", val)
}
>
<SelectTrigger>
<SelectValue placeholder="Select Organization" />
</SelectTrigger>
<SelectContent>
{/* TODO: ADR-019 — Backend DTO needs to accept UUID for primaryOrganization.
Currently using org.id which is excluded from API responses.
Temporary: org.id may still exist in some query responses. */}
{organizations?.map((org: any) => (
<SelectItem
key={org.uuid ?? org.id}
value={(org.id ?? 0).toString()}
key={org.uuid}
value={org.uuid}
>
{org.organizationCode} - {org.organizationName}
</SelectItem>
+6 -6
View File
@@ -80,7 +80,7 @@ export function DrawingUploadForm({ projectId = 1 }: DrawingUploadFormProps) {
const router = useRouter();
// Hooks
const { data: contractCategories } = useContractDrawingCategories();
const { data: contractCategories } = useContractDrawingCategories(projectId);
const { data: shopMainCats } = useShopMainCategories(projectId);
const [selectedShopMainCat, setSelectedShopMainCat] = useState<number | undefined>();
@@ -202,7 +202,7 @@ export function DrawingUploadForm({ projectId = 1 }: DrawingUploadFormProps) {
</SelectTrigger>
<SelectContent>
{contractCategories?.map((c: any) => (
<SelectItem key={c.id} value={String(c.id)}>{c.name}</SelectItem>
<SelectItem key={c.id} value={String(c.id)}>{c.catName || c.catCode || c.name}</SelectItem>
))}
</SelectContent>
</Select>
@@ -253,7 +253,7 @@ export function DrawingUploadForm({ projectId = 1 }: DrawingUploadFormProps) {
</SelectTrigger>
<SelectContent>
{shopMainCats?.map((c: any) => (
<SelectItem key={c.id} value={String(c.id)}>{c.name}</SelectItem>
<SelectItem key={c.id} value={String(c.id)}>{c.mainCategoryName || c.mainCategoryCode || c.name}</SelectItem>
))}
</SelectContent>
</Select>
@@ -269,7 +269,7 @@ export function DrawingUploadForm({ projectId = 1 }: DrawingUploadFormProps) {
</SelectTrigger>
<SelectContent>
{shopSubCats?.map((c: any) => (
<SelectItem key={c.id} value={String(c.id)}>{c.name}</SelectItem>
<SelectItem key={c.id} value={String(c.id)}>{c.subCategoryName || c.subCategoryCode || c.name}</SelectItem>
))}
</SelectContent>
</Select>
@@ -323,7 +323,7 @@ export function DrawingUploadForm({ projectId = 1 }: DrawingUploadFormProps) {
</SelectTrigger>
<SelectContent>
{shopMainCats?.map((c: any) => (
<SelectItem key={c.id} value={String(c.id)}>{c.name}</SelectItem>
<SelectItem key={c.id} value={String(c.id)}>{c.mainCategoryName || c.mainCategoryCode || c.name}</SelectItem>
))}
</SelectContent>
</Select>
@@ -339,7 +339,7 @@ export function DrawingUploadForm({ projectId = 1 }: DrawingUploadFormProps) {
</SelectTrigger>
<SelectContent>
{shopSubCats?.map((c: any) => (
<SelectItem key={c.id} value={String(c.id)}>{c.name}</SelectItem>
<SelectItem key={c.id} value={String(c.id)}>{c.subCategoryName || c.subCategoryCode || c.name}</SelectItem>
))}
</SelectContent>
</Select>
@@ -37,7 +37,7 @@ const VARIABLES = [
export interface TemplateEditorProps {
template?: NumberingTemplate;
projectId: number;
projectId: number | string;
projectName: string;
/* eslint-disable @typescript-eslint/no-explicit-any */
correspondenceTypes: any[];
+7 -7
View File
@@ -30,14 +30,14 @@ const rfaItemSchema = z.object({
unit: z.string().min(1, "Unit is required"),
});
const rfaSchema = z.object({
contractId: z.number().min(1, "Contract is required"),
contractId: z.string().min(1, "Contract is required"),
disciplineId: z.number().min(1, "Discipline is required"),
rfaTypeId: z.number().min(1, "Type is required"),
subject: z.string().min(5, "Subject must be at least 5 characters"),
description: z.string().optional(),
body: z.string().optional(),
remarks: z.string().optional(),
toOrganizationId: z.number().min(1, "Please select To Organization"),
toOrganizationId: z.string().min(1, "Please select To Organization"),
dueDate: z.string().optional(),
shopDrawingRevisionIds: z.array(z.number()).optional(),
items: z.array(rfaItemSchema).min(1, "At least one item is required"),
@@ -63,14 +63,14 @@ export function RFAForm() {
} = useForm<RFAFormData>({
resolver: zodResolver(rfaSchema),
defaultValues: {
contractId: 0,
contractId: "",
disciplineId: 0,
rfaTypeId: 0,
subject: "",
description: "",
body: "",
remarks: "",
toOrganizationId: 0,
toOrganizationId: "",
dueDate: "",
shopDrawingRevisionIds: [],
items: [{ itemNo: "1", description: "", quantity: 0, unit: "" }],
@@ -182,7 +182,7 @@ export function RFAForm() {
<div>
<Label>Contract *</Label>
<Select
onValueChange={(val) => setValue("contractId", Number(val))}
onValueChange={(val) => setValue("contractId", val)}
disabled={isLoadingContracts}
>
<SelectTrigger>
@@ -190,8 +190,8 @@ export function RFAForm() {
</SelectTrigger>
<SelectContent>
{contracts?.map((c: any) => (
<SelectItem key={c.id || c.contract_id} value={String(c.id || c.contract_id)}>
{c.name || c.contract_no}
<SelectItem key={c.id} value={String(c.id)}>
{c.contractName || c.name || c.contractCode}
</SelectItem>
))}
</SelectContent>
@@ -59,7 +59,7 @@ const itemSchema = z.object({
// Main form schema
const formSchema = z.object({
correspondenceId: z.number().min(1, "Correspondence is required"), // Linked correspondence (e.g. Originator Letter)
correspondenceId: z.string().min(1, "Correspondence is required"), // ADR-019: UUID string
subject: z.string().min(1, "Subject is required"),
purpose: z.enum(["FOR_APPROVAL", "FOR_INFORMATION", "FOR_REVIEW", "OTHER"]),
remarks: z.string().optional(),
@@ -127,7 +127,7 @@ export function TransmittalForm() {
const selectedDocId = form.watch("correspondenceId");
const selectedDoc = correspondences?.data?.find(
(c: { id: number }) => c.id === selectedDocId
(c: { uuid: string }) => c.uuid === selectedDocId
);
return (
@@ -172,19 +172,19 @@ export function TransmittalForm() {
<CommandEmpty>No document found.</CommandEmpty>
<CommandGroup>
{correspondences?.data?.map(
(doc: { id: number; correspondence_number: string }) => (
(doc: { uuid: string; correspondence_number: string }) => (
<CommandItem
key={doc.id}
key={doc.uuid}
value={doc.correspondence_number}
onSelect={() => {
form.setValue("correspondenceId", doc.id);
form.setValue("correspondenceId", doc.uuid);
setDocOpen(false);
}}
>
<Check
className={cn(
"mr-2 h-4 w-4",
doc.id === field.value
doc.uuid === field.value
? "opacity-100"
: "opacity-0"
)}
+4 -3
View File
@@ -104,10 +104,11 @@ export function useCorrespondenceTypes() {
// --- Drawing Categories Hooks ---
export function useContractDrawingCategories() {
export function useContractDrawingCategories(projectId?: number | string) {
return useQuery({
queryKey: ['contract-drawing-categories'],
queryFn: () => masterDataService.getContractDrawingCategories(),
queryKey: ['contract-drawing-categories', projectId],
queryFn: () => masterDataService.getContractDrawingCategories(projectId),
enabled: !!projectId,
});
}
+3 -2
View File
@@ -10,7 +10,7 @@ import apiClient from '@/lib/api/client';
*/
export interface NumberingTemplate {
id: number;
projectId: number;
projectId: number | string;
correspondenceTypeId: number | null; // null = Default Format for project
correspondenceType?: {
id: number;
@@ -18,9 +18,10 @@ export interface NumberingTemplate {
typeName: string;
} | null;
project?: {
id: number;
id: number | string;
projectCode: string;
projectName: string;
uuid?: string;
};
formatTemplate: string;
description?: string;
+4 -2
View File
@@ -187,8 +187,10 @@ export const masterDataService = {
// --- Drawing Categories ---
getContractDrawingCategories: async () => {
const response = await apiClient.get("/drawings/contract/categories");
getContractDrawingCategories: async (projectId?: number | string) => {
const response = await apiClient.get("/drawings/contract/categories", {
params: { projectId }
});
return response.data.data || response.data;
},
@@ -15,7 +15,7 @@ const mapWorkflow = (backendObj: any): Workflow => {
workflowId: backendObj.id,
workflowName: backendObj.dsl?.workflowName || backendObj.workflow_code,
description: backendObj.description || backendObj.dsl?.description || '',
workflowType: backendObj.workflow_code,
workflowType: backendObj.workflow_code?.toUpperCase() || backendObj.workflow_code,
version: backendObj.version || 1,
isActive: backendObj.is_active,
dslDefinition: typeof backendObj.dsl === 'string' ? backendObj.dsl : backendObj.dsl?.dslDefinition || JSON.stringify(backendObj.dsl, null, 2),
+8 -5
View File
@@ -2,8 +2,8 @@
// --- Create ---
export interface CreateRfaDto {
/** ID ของโครงการ */
projectId: number;
/** ID or UUID ของโครงการ */
projectId: number | string; // ADR-019: Accept UUID
/** ประเภท RFA (เช่น DWG, MAT) */
rfaTypeId: number;
@@ -20,8 +20,11 @@ export interface CreateRfaDto {
/** หมายเหตุ */
remarks?: string;
/** Contract UUID (optional) */
contractId?: string; // ADR-019: Contract UUID
/** ส่งถึงใคร (สำหรับ Routing Step 1) */
toOrganizationId: number;
toOrganizationId: number | string; // ADR-019: Accept UUID
/** รายละเอียดเพิ่มเติม */
description?: string;
@@ -41,8 +44,8 @@ export type UpdateRfaDto = Partial<CreateRfaDto>;
// --- Search ---
export interface SearchRfaDto {
/** Filter by Project ID (optional to allow cross-project search) */
projectId?: number;
/** Filter by Project ID or UUID (optional to allow cross-project search) */
projectId?: number | string; // ADR-019: Accept UUID
/** กรองตามประเภท RFA */
rfaTypeId?: number;
@@ -9,12 +9,12 @@ export enum TransmittalPurpose {
// --- Create ---
export interface CreateTransmittalDto {
projectId?: number;
recipientOrganizationId?: number;
projectId?: number | string; // ADR-019: Accept UUID
recipientOrganizationId?: number | string; // ADR-019: Accept UUID
subject: string;
purpose?: string;
remarks?: string;
correspondenceId: number; // For now linked correspondence
correspondenceId: number | string; // ADR-019: Accept UUID
items: CreateTransmittalItemDto[];
}
@@ -30,7 +30,7 @@ export type UpdateTransmittalDto = Partial<CreateTransmittalDto>;
// --- Search ---
export interface SearchTransmittalDto {
/** บังคับระบุ Project */
projectId: number;
projectId: number | string; // ADR-019: Accept UUID
purpose?: TransmittalPurpose;
+1 -1
View File
@@ -8,7 +8,7 @@ export interface CreateUserDto {
firstName?: string;
lastName?: string;
lineId?: string;
primaryOrganizationId?: number;
primaryOrganizationId?: number | string; // ADR-019: Accept UUID
isActive?: boolean;
}
+3 -1
View File
@@ -51,7 +51,9 @@ export interface RFA {
}
export interface CreateRFADto {
projectId: number;
projectId: number | string; // ADR-019: Accept UUID
contractId?: string; // ADR-019: Contract UUID
toOrganizationId?: number | string; // ADR-019: Recipient org UUID
rfaTypeId: number;
disciplineId?: number;
subject: string;
+3 -3
View File
@@ -20,7 +20,7 @@ export interface User {
lastName: string;
isActive: boolean;
lineId?: string;
primaryOrganizationId?: number;
primaryOrganizationId?: number | string; // ADR-019: May be INT or UUID
organization?: UserOrganization;
roles?: Role[];
@@ -42,7 +42,7 @@ export interface CreateUserDto {
password?: string;
isActive: boolean;
lineId?: string;
primaryOrganizationId?: number;
primaryOrganizationId?: number | string; // ADR-019: Accept UUID
roleIds: number[];
}
@@ -53,5 +53,5 @@ export interface SearchUserDto {
limit?: number;
search?: string;
roleId?: number;
primaryOrganizationId?: number;
primaryOrganizationId?: number | string; // ADR-019: Accept UUID
}