690328:1547 Fixing Refactor uuid by Kimi #10
CI / CD Pipeline / build (push) Successful in 6m16s
CI / CD Pipeline / deploy (push) Failing after 7m15s

This commit is contained in:
2026-03-28 15:47:07 +07:00
parent 3f78f0ec00
commit 57a3ed2d37
29 changed files with 162 additions and 143 deletions
@@ -113,7 +113,7 @@ export default function UsersPage() {
return ( return (
<div className="flex flex-wrap gap-1"> <div className="flex flex-wrap gap-1">
{roles.map((r) => ( {roles.map((r) => (
<Badge key={r.roleId} variant="outline" className="text-xs"> <Badge key={r.publicId} variant="outline" className="text-xs">
{r.roleName} {r.roleName}
</Badge> </Badge>
))} ))}
@@ -42,7 +42,7 @@ export default function WorkflowsPage() {
) : ( ) : (
<div className="grid gap-4"> <div className="grid gap-4">
{workflowList.map((workflow: Workflow) => ( {workflowList.map((workflow: Workflow) => (
<Card key={workflow.workflowId} className="p-6"> <Card key={workflow.publicId} className="p-6">
<div className="flex justify-between items-start"> <div className="flex justify-between items-start">
<div className="flex-1"> <div className="flex-1">
<div className="flex items-center gap-3 mb-2"> <div className="flex items-center gap-3 mb-2">
@@ -64,7 +64,7 @@ export default function WorkflowsPage() {
</div> </div>
<div className="flex gap-2"> <div className="flex gap-2">
<Link href={`/admin/doc-control/workflows/${workflow.workflowId}/edit`}> <Link href={`/admin/doc-control/workflows/${workflow.publicId}/edit`}>
<Button variant="outline" size="sm"> <Button variant="outline" size="sm">
<Edit className="mr-2 h-4 w-4" /> <Edit className="mr-2 h-4 w-4" />
Edit Edit
@@ -26,12 +26,12 @@ export default function AuditLogsPage() {
<div className="text-center text-muted-foreground py-10">No logs found</div> <div className="text-center text-muted-foreground py-10">No logs found</div>
) : ( ) : (
logs.map((log: import('@/lib/services/audit-log.service').AuditLog) => ( logs.map((log: import('@/lib/services/audit-log.service').AuditLog) => (
<Card key={log.auditId} className="p-4"> <Card key={log.publicId} className="p-4">
<div className="flex items-start justify-between"> <div className="flex items-start justify-between">
<div className="flex-1"> <div className="flex-1">
<div className="flex items-center gap-3 mb-2"> <div className="flex items-center gap-3 mb-2">
<span className="font-medium text-sm"> <span className="font-medium text-sm">
{log.user?.fullName || log.user?.username || `User #${log.userId || 'System'}`} {log.user?.fullName || log.user?.username || `User #${log.user?.userId || 'System'}`}
</span> </span>
<Badge <Badge
variant={log.severity === 'ERROR' ? 'destructive' : 'outline'} variant={log.severity === 'ERROR' ? 'destructive' : 'outline'}
@@ -64,7 +64,7 @@ export function OrganizationDialog({ open, onOpenChange, organization }: Organiz
reset({ reset({
organizationCode: organization.organizationCode, organizationCode: organization.organizationCode,
organizationName: organization.organizationName, organizationName: organization.organizationName,
roleId: organization.roleId?.toString() || '', roleId: organization.publicId?.toString() || '',
isActive: organization.isActive, isActive: organization.isActive,
}); });
} else { } else {
@@ -80,7 +80,7 @@ export function OrganizationDialog({ open, onOpenChange, organization }: Organiz
const onSubmit = (data: OrganizationFormData) => { const onSubmit = (data: OrganizationFormData) => {
const submitData = { const submitData = {
...data, ...data,
roleId: data.roleId ? Number(data.roleId) : undefined, roleId: data.roleId ? String(data.roleId) : undefined,
}; };
if (organization) { if (organization) {
@@ -137,7 +137,7 @@ export function RbacMatrix() {
<TableRow> <TableRow>
<TableHead className="w-[300px]">Permission</TableHead> <TableHead className="w-[300px]">Permission</TableHead>
{roleList.map((role) => ( {roleList.map((role) => (
<TableHead key={role.roleId} className="text-center min-w-[100px]"> <TableHead key={role.publicId} className="text-center min-w-[100px]">
{role.roleName} {role.roleName}
</TableHead> </TableHead>
))} ))}
@@ -153,14 +153,14 @@ export function RbacMatrix() {
{roleList.map((role) => { {roleList.map((role) => {
// Assume role.permissions is populated // Assume role.permissions is populated
const currentRolePerms = role.permissions?.map((p) => p.permissionId) || []; const currentRolePerms = role.permissions?.map((p) => p.permissionId) || [];
const activePerms = pendingChanges[role.roleId] || currentRolePerms; const activePerms = pendingChanges[role.publicId] || currentRolePerms;
const isChecked = activePerms.includes(perm.permissionId); const isChecked = activePerms.includes(perm.permissionId);
return ( return (
<TableCell key={`${role.roleId}-${perm.permissionId}`} className="text-center"> <TableCell key={`${role.publicId}-${perm.permissionId}`} className="text-center">
<Checkbox <Checkbox
checked={isChecked} checked={isChecked}
onCheckedChange={() => handleToggle(role.roleId, perm.permissionId, currentRolePerms)} onCheckedChange={() => handleToggle(role.publicId, perm.permissionId, currentRolePerms)}
/> />
</TableCell> </TableCell>
); );
+8 -8
View File
@@ -108,7 +108,7 @@ export function UserDialog({ open, onOpenChange, user }: UserDialogProps) {
isActive: user.isActive, isActive: user.isActive,
lineId: user.lineId || '', lineId: user.lineId || '',
primaryOrganizationId: user.primaryOrganizationId?.toString() || ALL_ORGANIZATIONS_VALUE, primaryOrganizationId: user.primaryOrganizationId?.toString() || ALL_ORGANIZATIONS_VALUE,
roleIds: user.roles?.map((r: { roleId: number }) => r.roleId) || [], roleIds: user.roles?.map((r: { publicId: string }) => r.publicId) || [],
password: '', password: '',
confirmPassword: '', confirmPassword: '',
}); });
@@ -297,26 +297,26 @@ export function UserDialog({ open, onOpenChange, user }: UserDialogProps) {
<p className="text-sm text-muted-foreground">Loading roles...</p> <p className="text-sm text-muted-foreground">Loading roles...</p>
)} )}
{Array.isArray(roles) && {Array.isArray(roles) &&
roles.map((role: { roleId: number; roleName: string; description?: string }) => ( roles.map((role: { publicId: string; roleName: string; description?: string }) => (
<div key={role.roleId} className="flex items-start space-x-2"> <div key={role.publicId} className="flex items-start space-x-2">
<Checkbox <Checkbox
id={`role-${role.roleId}`} id={`role-${role.publicId}`}
checked={selectedRoleIds.includes(role.roleId)} checked={selectedRoleIds.includes(role.publicId)}
onCheckedChange={(checked) => { onCheckedChange={(checked) => {
const current = selectedRoleIds; const current = selectedRoleIds;
if (checked) { if (checked) {
setValue('roleIds', [...current, role.roleId]); setValue('roleIds', [...current, role.publicId]);
} else { } else {
setValue( setValue(
'roleIds', 'roleIds',
current.filter((id) => id !== role.roleId) current.filter((id) => id !== role.publicId)
); );
} }
}} }}
/> />
<div className="grid gap-1.5 leading-none"> <div className="grid gap-1.5 leading-none">
<label <label
htmlFor={`role-${role.roleId}`} htmlFor={`role-${role.publicId}`}
className="text-sm font-medium leading-none cursor-pointer" className="text-sm font-medium leading-none cursor-pointer"
> >
{role.roleName} {role.roleName}
@@ -30,14 +30,14 @@ export function TagManager({ uuid, canEdit }: TagManagerProps) {
const assigned: Tag[] = Array.isArray(assignedRaw) ? (assignedRaw as Tag[]) : []; const assigned: Tag[] = Array.isArray(assignedRaw) ? (assignedRaw as Tag[]) : [];
const allTags: Tag[] = Array.isArray(allTagsRaw) ? (allTagsRaw as Tag[]) : []; const allTags: Tag[] = Array.isArray(allTagsRaw) ? (allTagsRaw as Tag[]) : [];
const assignedIds = new Set(assigned.map((t) => t.id)); const assignedIds = new Set(assigned.map((t) => t.publicId));
const available = allTags.filter((t) => !assignedIds.has(t.id)); const available = allTags.filter((t) => !assignedIds.has(t.publicId));
const handleAdd = (tagId: number) => { const handleAdd = (tagId: number | string) => {
addMutation.mutate({ uuid, tagId }); addMutation.mutate({ uuid, tagId });
}; };
const handleRemove = (tagId: number) => { const handleRemove = (tagId: number | string) => {
removeMutation.mutate({ uuid, tagId }); removeMutation.mutate({ uuid, tagId });
}; };
@@ -71,7 +71,7 @@ export function TagManager({ uuid, canEdit }: TagManagerProps) {
<div className="flex flex-wrap gap-1.5"> <div className="flex flex-wrap gap-1.5">
{assigned.map((tag) => ( {assigned.map((tag) => (
<span <span
key={tag.id} key={tag.publicId}
className="inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-xs font-medium border" className="inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-xs font-medium border"
style={{ style={{
backgroundColor: `${getTagColor(tag.colorCode)}22`, backgroundColor: `${getTagColor(tag.colorCode)}22`,
@@ -86,7 +86,7 @@ export function TagManager({ uuid, canEdit }: TagManagerProps) {
{tag.tagName} {tag.tagName}
{canEdit && ( {canEdit && (
<button <button
onClick={() => handleRemove(tag.id)} onClick={() => handleRemove(tag.publicId)}
disabled={removeMutation.isPending} disabled={removeMutation.isPending}
className="ml-0.5 opacity-60 hover:opacity-100 transition-opacity" className="ml-0.5 opacity-60 hover:opacity-100 transition-opacity"
> >
@@ -110,9 +110,9 @@ export function TagManager({ uuid, canEdit }: TagManagerProps) {
) : ( ) : (
available.map((tag) => ( available.map((tag) => (
<button <button
key={tag.id} key={tag.publicId}
className="w-full flex items-center gap-2 p-2 text-xs hover:bg-muted/60 transition-colors text-left" className="w-full flex items-center gap-2 p-2 text-xs hover:bg-muted/60 transition-colors text-left"
onClick={() => { handleAdd(tag.id); setIsOpen(false); }} onClick={() => { handleAdd(tag.publicId); setIsOpen(false); }}
disabled={addMutation.isPending} disabled={addMutation.isPending}
> >
<span <span
@@ -14,7 +14,7 @@ export function RevisionHistory({ revisions }: { revisions: DrawingRevision[] })
<div className="space-y-3"> <div className="space-y-3">
{revisions.map((rev) => ( {revisions.map((rev) => (
<div key={rev.revisionId} className="flex items-center justify-between p-3 bg-muted/30 rounded-lg border"> <div key={rev.publicId} className="flex items-center justify-between p-3 bg-muted/30 rounded-lg border">
<div className="flex-1"> <div className="flex-1">
<div className="flex items-center gap-3 mb-1"> <div className="flex items-center gap-3 mb-1">
<Badge variant={rev.isCurrent ? 'default' : 'outline'}>Rev. {rev.revisionNumber}</Badge> <Badge variant={rev.isCurrent ? 'default' : 'outline'}>Rev. {rev.revisionNumber}</Badge>
@@ -120,7 +120,7 @@ export function TemplateEditor({
<SelectItem value="__default__">Default (All Types)</SelectItem> <SelectItem value="__default__">Default (All Types)</SelectItem>
{correspondenceTypes.map((type) => { {correspondenceTypes.map((type) => {
return ( return (
<SelectItem key={type.id} value={type.id.toString()}> <SelectItem key={type.publicId} value={type.publicId.toString()}>
{type.typeCode} - {type.typeName} {type.typeCode} - {type.typeName}
</SelectItem> </SelectItem>
); );
@@ -142,7 +142,7 @@ export function TemplateEditor({
<SelectContent> <SelectContent>
<SelectItem value="0">All Disciplines</SelectItem> <SelectItem value="0">All Disciplines</SelectItem>
{disciplines.map((d) => ( {disciplines.map((d) => (
<SelectItem key={d.id} value={d.id.toString()}> <SelectItem key={d.publicId} value={d.publicId.toString()}>
{d.disciplineCode} - {d.codeNameEn || d.codeNameTh} {d.disciplineCode} - {d.codeNameEn || d.codeNameTh}
</SelectItem> </SelectItem>
))} ))}
@@ -158,7 +158,7 @@ export function TemplateTester({ open, onOpenChange, template }: TemplateTesterP
<SelectContent> <SelectContent>
<SelectItem value="0">Default (All Types)</SelectItem> <SelectItem value="0">Default (All Types)</SelectItem>
{(correspondenceTypes as CorrespondenceType[])?.map((type) => ( {(correspondenceTypes as CorrespondenceType[])?.map((type) => (
<SelectItem key={type.id} value={type.id.toString()}> <SelectItem key={type.publicId} value={type.publicId.toString()}>
{type.typeCode} - {type.typeName} {type.typeCode} - {type.typeName}
</SelectItem> </SelectItem>
))} ))}
@@ -179,7 +179,7 @@ export function TemplateTester({ open, onOpenChange, template }: TemplateTesterP
<SelectContent> <SelectContent>
<SelectItem value="0">None</SelectItem> <SelectItem value="0">None</SelectItem>
{(disciplines as Discipline[])?.map((disc) => ( {(disciplines as Discipline[])?.map((disc) => (
<SelectItem key={disc.id} value={disc.id.toString()}> <SelectItem key={disc.publicId} value={disc.publicId.toString()}>
{disc.disciplineCode} {disc.disciplineCode}
</SelectItem> </SelectItem>
))} ))}
+20 -18
View File
@@ -26,7 +26,7 @@ const rfaSchema = z.object({
projectId: z.string().min(1, 'Project is required'), // ADR-019: UUID projectId: z.string().min(1, 'Project is required'), // ADR-019: UUID
contractId: z.string().min(1, 'Contract is required'), contractId: z.string().min(1, 'Contract is required'),
disciplineId: z.number({ message: 'Discipline is required' }).min(1, 'Discipline is required'), disciplineId: z.number({ message: 'Discipline is required' }).min(1, 'Discipline is required'),
rfaTypeId: z.number().min(1, 'Type is required'), rfaTypeId: z.string().min(1, 'Type is required'), // ADR-019: UUID
subject: z.string().min(5, 'Subject must be at least 5 characters'), subject: z.string().min(5, 'Subject must be at least 5 characters'),
description: z.string().optional(), description: z.string().optional(),
body: z.string().optional(), body: z.string().optional(),
@@ -53,14 +53,16 @@ type ContractOption = {
}; };
type DisciplineOption = { type DisciplineOption = {
id: number; publicId: string; // ADR-019: public identifier
id?: number; // Internal INT
disciplineCode: string; disciplineCode: string;
codeNameEn?: string; codeNameEn?: string;
codeNameTh?: string; codeNameTh?: string;
}; };
type RfaTypeOption = { type RfaTypeOption = {
id: number; publicId: string; // ADR-019: public identifier
id?: number; // Internal INT
typeCode?: string; typeCode?: string;
typeName?: string; typeName?: string;
typeNameEn?: string; typeNameEn?: string;
@@ -68,7 +70,7 @@ type RfaTypeOption = {
}; };
type CorrespondenceTypeOption = { type CorrespondenceTypeOption = {
id: number; publicId: string; // ADR-019: public identifier
typeCode?: string; typeCode?: string;
typeName?: string; typeName?: string;
}; };
@@ -164,7 +166,7 @@ export function RFAForm() {
projectId: '', projectId: '',
contractId: '', contractId: '',
disciplineId: 0, disciplineId: 0,
rfaTypeId: 0, rfaTypeId: '',
subject: '', subject: '',
description: '', description: '',
body: '', body: '',
@@ -185,13 +187,13 @@ export function RFAForm() {
const selectedContractId = watch('contractId'); const selectedContractId = watch('contractId');
const { data: disciplinesData, isLoading: isLoadingDisciplines } = useDisciplines(selectedContractId); const { data: disciplinesData, isLoading: isLoadingDisciplines } = useDisciplines(selectedContractId);
const disciplines = dedupeByKey(extractArrayData<DisciplineOption>(disciplinesData), (discipline) => discipline.id); const disciplines = dedupeByKey(extractArrayData<DisciplineOption>(disciplinesData), (discipline) => discipline.publicId);
const { data: rfaTypesData, isLoading: isLoadingRfaTypes } = useRfaTypes(selectedContractId); const { data: rfaTypesData, isLoading: isLoadingRfaTypes } = useRfaTypes(selectedContractId);
const rfaTypes = dedupeByKey(extractArrayData<RfaTypeOption>(rfaTypesData), (rfaType) => rfaType.id); const rfaTypes = dedupeByKey(extractArrayData<RfaTypeOption>(rfaTypesData), (rfaType) => rfaType.publicId);
const [shopDrawingSearch, setShopDrawingSearch] = useState(''); const [shopDrawingSearch, setShopDrawingSearch] = useState('');
const [shopDrawingPage, setShopDrawingPage] = useState(1); const [shopDrawingPage, setShopDrawingPage] = useState(1);
const { data: shopDrawingsData, isLoading: isLoadingShopDrawings } = useDrawings('SHOP', { const { data: shopDrawingsData, isLoading: isLoadingShopDrawings } = useDrawings('SHOP', {
projectPublicId: selectedProjectId || '', projectUuid: selectedProjectId || '',
search: shopDrawingSearch, search: shopDrawingSearch,
page: shopDrawingPage, page: shopDrawingPage,
limit: 10, limit: 10,
@@ -204,7 +206,7 @@ export function RFAForm() {
const [asBuiltDrawingSearch, setAsBuiltDrawingSearch] = useState(''); const [asBuiltDrawingSearch, setAsBuiltDrawingSearch] = useState('');
const [asBuiltDrawingPage, setAsBuiltDrawingPage] = useState(1); const [asBuiltDrawingPage, setAsBuiltDrawingPage] = useState(1);
const { data: asBuiltDrawingsData, isLoading: isLoadingAsBuiltDrawings } = useDrawings('AS_BUILT', { const { data: asBuiltDrawingsData, isLoading: isLoadingAsBuiltDrawings } = useDrawings('AS_BUILT', {
projectPublicId: selectedProjectId || '', projectUuid: selectedProjectId || '',
search: asBuiltDrawingSearch, search: asBuiltDrawingSearch,
page: asBuiltDrawingPage, page: asBuiltDrawingPage,
limit: 10, limit: 10,
@@ -220,7 +222,7 @@ export function RFAForm() {
const toOrganizationId = watch('toOrganizationId'); const toOrganizationId = watch('toOrganizationId');
const selectedShopDrawingRevisionIds = watch('shopDrawingRevisionIds') ?? []; const selectedShopDrawingRevisionIds = watch('shopDrawingRevisionIds') ?? [];
const selectedAsBuiltDrawingRevisionIds = watch('asBuiltDrawingRevisionIds') ?? []; const selectedAsBuiltDrawingRevisionIds = watch('asBuiltDrawingRevisionIds') ?? [];
const selectedRfaType = rfaTypes.find((rfaType) => rfaType.id === rfaTypeId); const selectedRfaType = rfaTypes.find((rfaType) => rfaType.publicId === rfaTypeId);
const selectedRfaTypeCode = selectedRfaType?.typeCode?.toUpperCase(); const selectedRfaTypeCode = selectedRfaType?.typeCode?.toUpperCase();
const requiresShopDrawings = selectedRfaTypeCode === 'DDW' || selectedRfaTypeCode === 'SDW'; const requiresShopDrawings = selectedRfaTypeCode === 'DDW' || selectedRfaTypeCode === 'SDW';
const requiresAsBuiltDrawings = selectedRfaTypeCode === 'ADW'; const requiresAsBuiltDrawings = selectedRfaTypeCode === 'ADW';
@@ -254,7 +256,7 @@ export function RFAForm() {
const [preview, setPreview] = useState<{ number: string; isDefaultTemplate: boolean } | null>(null); const [preview, setPreview] = useState<{ number: string; isDefaultTemplate: boolean } | null>(null);
useEffect(() => { useEffect(() => {
if (!selectedProjectId || !rfaCorrespondenceType?.id || !rfaTypeId || !disciplineId || !toOrganizationId) { if (!selectedProjectId || !rfaCorrespondenceType?.publicId || !rfaTypeId || !disciplineId || !toOrganizationId) {
setPreview(null); setPreview(null);
return; return;
} }
@@ -263,7 +265,7 @@ export function RFAForm() {
try { try {
const res = await correspondenceService.previewNumber({ const res = await correspondenceService.previewNumber({
projectId: selectedProjectId, projectId: selectedProjectId,
typeId: rfaCorrespondenceType.id, typeId: rfaCorrespondenceType.publicId,
disciplineId, disciplineId,
recipients: [{ organizationId: toOrganizationId, type: 'TO' }], recipients: [{ organizationId: toOrganizationId, type: 'TO' }],
subject: watch('subject') || 'Preview Subject', subject: watch('subject') || 'Preview Subject',
@@ -276,7 +278,7 @@ export function RFAForm() {
const timer = setTimeout(fetchPreview, 500); const timer = setTimeout(fetchPreview, 500);
return () => clearTimeout(timer); return () => clearTimeout(timer);
}, [rfaTypeId, disciplineId, toOrganizationId, selectedProjectId, rfaCorrespondenceType?.id, watch]); }, [rfaTypeId, disciplineId, toOrganizationId, selectedProjectId, rfaCorrespondenceType?.publicId, watch]);
const onSubmit = (data: RFAFormData) => { const onSubmit = (data: RFAFormData) => {
if (requiresShopDrawings && data.shopDrawingRevisionIds?.length === 0) { if (requiresShopDrawings && data.shopDrawingRevisionIds?.length === 0) {
@@ -365,7 +367,7 @@ export function RFAForm() {
setValue('projectId', val); setValue('projectId', val);
setValue('contractId', ''); setValue('contractId', '');
setValue('disciplineId', 0); setValue('disciplineId', 0);
setValue('rfaTypeId', 0); setValue('rfaTypeId', '');
setValue('shopDrawingRevisionIds', []); setValue('shopDrawingRevisionIds', []);
setValue('asBuiltDrawingRevisionIds', []); setValue('asBuiltDrawingRevisionIds', []);
}} }}
@@ -441,7 +443,7 @@ export function RFAForm() {
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
{disciplines.map((d) => ( {disciplines.map((d) => (
<SelectItem key={d.id} value={String(d.id)}> <SelectItem key={d.publicId} value={String(d.publicId)}>
{`${d.codeNameEn || d.codeNameTh || d.disciplineCode} (${d.disciplineCode})`} {`${d.codeNameEn || d.codeNameTh || d.disciplineCode} (${d.disciplineCode})`}
</SelectItem> </SelectItem>
))} ))}
@@ -460,9 +462,9 @@ export function RFAForm() {
<div> <div>
<Label>RFA Type *</Label> <Label>RFA Type *</Label>
<Select <Select
value={rfaTypeId > 0 ? String(rfaTypeId) : undefined} value={rfaTypeId || undefined}
onValueChange={(val) => { onValueChange={(val) => {
setValue('rfaTypeId', Number(val)); setValue('rfaTypeId', val);
setValue('shopDrawingRevisionIds', []); setValue('shopDrawingRevisionIds', []);
setValue('asBuiltDrawingRevisionIds', []); setValue('asBuiltDrawingRevisionIds', []);
}} }}
@@ -473,7 +475,7 @@ export function RFAForm() {
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
{rfaTypes.map((rfaType) => ( {rfaTypes.map((rfaType) => (
<SelectItem key={rfaType.id} value={String(rfaType.id)}> <SelectItem key={rfaType.publicId} value={String(rfaType.publicId)}>
{`${rfaType.typeCode || 'RFA'} - ${rfaType.typeName || rfaType.typeNameEn || rfaType.typeNameTh || 'Unnamed Type'}`} {`${rfaType.typeCode || 'RFA'} - ${rfaType.typeName || rfaType.typeNameEn || rfaType.typeNameTh || 'Unnamed Type'}`}
</SelectItem> </SelectItem>
))} ))}
+2 -2
View File
@@ -141,7 +141,7 @@ export function useAddTag() {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
return useMutation({ return useMutation({
mutationFn: ({ uuid, tagId }: { uuid: string; tagId: number }) => mutationFn: ({ uuid, tagId }: { uuid: string; tagId: number | string }) =>
correspondenceService.addTag(uuid, tagId), correspondenceService.addTag(uuid, tagId),
onSuccess: (_, { uuid }) => { onSuccess: (_, { uuid }) => {
toast.success('Tag added'); toast.success('Tag added');
@@ -159,7 +159,7 @@ export function useRemoveTag() {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
return useMutation({ return useMutation({
mutationFn: ({ uuid, tagId }: { uuid: string; tagId: number }) => mutationFn: ({ uuid, tagId }: { uuid: string; tagId: number | string }) =>
correspondenceService.removeTag(uuid, tagId), correspondenceService.removeTag(uuid, tagId),
onSuccess: (_, { uuid }) => { onSuccess: (_, { uuid }) => {
toast.success('Tag removed'); toast.success('Tag removed');
+8 -4
View File
@@ -1,11 +1,13 @@
export interface Role { export interface Role {
roleId: number; publicId: string; // ADR-019: public identifier
roleId?: number; // Internal INT (excluded from API)
roleName: string; roleName: string;
description: string; description: string;
} }
export interface User { export interface User {
userId: number; publicId: string; // ADR-019: public identifier
userId?: number; // Internal INT (excluded from API)
username: string; username: string;
email: string; email: string;
firstName: string; firstName: string;
@@ -25,7 +27,8 @@ export interface CreateUserDto {
} }
export interface Organization { export interface Organization {
orgId: number; publicId: string; // ADR-019: public identifier
orgId?: number; // Internal INT (excluded from API)
orgCode: string; orgCode: string;
orgName: string; orgName: string;
orgNameTh?: string; orgNameTh?: string;
@@ -33,7 +36,8 @@ export interface Organization {
} }
export interface AuditLog { export interface AuditLog {
auditLogId: number; publicId: string; // ADR-019: public identifier
auditLogId?: number; // Internal INT (excluded from API)
userName: string; userName: string;
action: string; action: string;
entityType: string; entityType: string;
@@ -4,14 +4,14 @@ export interface CreateCorrespondenceDto {
/** ID or UUID ของโครงการ */ /** ID or UUID ของโครงการ */
projectId: number | string; projectId: number | string;
/** ID ของประเภทเอกสาร (เช่น RFA, LETTER) */ /** ID ของประเภทเอกสาร (เช่น RFA, LETTER) - ADR-019: Accept UUID */
typeId: number; typeId: number | string;
/** [Req 6B] สาขางาน (เช่น GEN, STR) */ /** [Req 6B] สาขางาน (เช่น GEN, STR) - ADR-019: Accept UUID */
disciplineId?: number; disciplineId?: number | string;
/** [Req 6B] ประเภทย่อย (เช่น MAT, SHP สำหรับ Transmittal/RFA) */ /** [Req 6B] ประเภทย่อย (เช่น MAT, SHP สำหรับ Transmittal/RFA) - ADR-019: Accept UUID */
subTypeId?: number; subTypeId?: number | string;
/** หัวข้อเอกสาร */ /** หัวข้อเอกสาร */
subject: string; subject: string;
@@ -2,9 +2,9 @@
export interface SearchCorrespondenceDto { export interface SearchCorrespondenceDto {
search?: string; // ค้นหาจาก Title หรือ Number search?: string; // ค้นหาจาก Title หรือ Number
typeId?: number; // กรองตามประเภทเอกสาร typeId?: number | string; // ADR-019: Accept UUID - กรองตามประเภทเอกสาร
projectId?: number; // กรองตามโครงการ projectId?: number | string; // ADR-019: Accept UUID - กรองตามโครงการ
statusId?: number; // กรองตามสถานะ (จาก Revision ปัจจุบัน) statusId?: number | string; // ADR-019: Accept UUID - กรองตามสถานะ (จาก Revision ปัจจุบัน)
status?: string; // กรองตามสถานะ code string (เช่น DRAFT, IN_REVIEW) status?: string; // กรองตามสถานะ code string (เช่น DRAFT, IN_REVIEW)
revisionStatus?: 'CURRENT' | 'ALL' | 'OLD'; // กรองตามสถานะ Revision revisionStatus?: 'CURRENT' | 'ALL' | 'OLD'; // กรองตามสถานะ Revision
@@ -2,10 +2,10 @@
// --- Create New As Built Drawing --- // --- Create New As Built Drawing ---
export interface CreateAsBuiltDrawingDto { export interface CreateAsBuiltDrawingDto {
projectId: number; projectId: number | string; // ADR-019: Accept UUID
drawingNumber: string; drawingNumber: string;
mainCategoryId: number; mainCategoryId: number | string; // ADR-019: Accept UUID
subCategoryId: number; subCategoryId: number | string; // ADR-019: Accept UUID
// First Revision Data // First Revision Data
revisionLabel?: string; revisionLabel?: string;
@@ -14,8 +14,8 @@ export interface CreateAsBuiltDrawingDto {
revisionDate?: string; // ISO Date String revisionDate?: string; // ISO Date String
description?: string; description?: string;
shopDrawingRevisionIds?: number[]; // Reference to Shop Drawing Revisions shopDrawingRevisionIds?: (number | string)[]; // ADR-019: Accept UUID - Reference to Shop Drawing Revisions
attachmentIds?: number[]; attachmentIds?: (number | string)[]; // ADR-019: Accept UUID
} }
// --- Create New Revision --- // --- Create New Revision ---
@@ -26,8 +26,8 @@ export interface CreateAsBuiltDrawingRevisionDto {
revisionDate?: string; revisionDate?: string;
description?: string; description?: string;
shopDrawingRevisionIds?: number[]; shopDrawingRevisionIds?: (number | string)[]; // ADR-019: Accept UUID
attachmentIds?: number[]; attachmentIds?: (number | string)[]; // ADR-019: Accept UUID
} }
// --- Search --- // --- Search ---
@@ -2,8 +2,8 @@
// --- Create --- // --- Create ---
export interface CreateContractDrawingDto { export interface CreateContractDrawingDto {
/** ID ของโครงการ */ /** ID ของโครงการ - ADR-019: Accept UUID */
projectId: number; projectId: number | string;
/** เลขที่แบบสัญญา */ /** เลขที่แบบสัญญา */
contractDrawingNo: string; contractDrawingNo: string;
@@ -11,17 +11,17 @@ export interface CreateContractDrawingDto {
/** ชื่อแบบ */ /** ชื่อแบบ */
title: string; title: string;
/** ID หมวดหมู่ย่อย (Mapping) */ /** ID หมวดหมู่ย่อย (Mapping) - ADR-019: Accept UUID */
mapCatId?: number; mapCatId?: number | string;
/** ID เล่มของแบบ */ /** ID เล่มของแบบ - ADR-019: Accept UUID */
volumeId?: number; volumeId?: number | string;
/** เลขหน้าในเล่ม */ /** เลขหน้าในเล่ม */
volumePage?: number; volumePage?: number;
/** รายการ ID ของไฟล์แนบ (PDF/DWG) */ /** รายการ ID ของไฟล์แนบ (PDF/DWG) - ADR-019: Accept UUID */
attachmentIds?: number[]; attachmentIds?: (number | string)[];
} }
// --- Update (Partial) --- // --- Update (Partial) ---
@@ -32,8 +32,8 @@ export interface SearchContractDrawingDto {
/** จำเป็นต้องระบุ Project UUID เสมอ */ /** จำเป็นต้องระบุ Project UUID เสมอ */
projectUuid: string; projectUuid: string;
volumeId?: number; volumeId?: number | string; // ADR-019: Accept UUID
mapCatId?: number; mapCatId?: number | string; // ADR-019: Accept UUID
search?: string; // ค้นหาจาก Title หรือ Number search?: string; // ค้นหาจาก Title หรือ Number
page?: number; // Default: 1 page?: number; // Default: 1
@@ -2,19 +2,19 @@
// --- Create New Shop Drawing --- // --- Create New Shop Drawing ---
export interface CreateShopDrawingDto { export interface CreateShopDrawingDto {
projectId: number; projectId: number | string; // ADR-019: Accept UUID
drawingNumber: string; drawingNumber: string;
title: string; title: string;
mainCategoryId: number; mainCategoryId: number | string; // ADR-019: Accept UUID
subCategoryId: number; subCategoryId: number | string; // ADR-019: Accept UUID
// First Revision Data (Optional) // First Revision Data (Optional)
revisionLabel?: string; revisionLabel?: string;
revisionDate?: string; // ISO Date String revisionDate?: string; // ISO Date String
description?: string; description?: string;
legacyDrawingNumber?: string; // Legacy number for the first revision legacyDrawingNumber?: string; // Legacy number for the first revision
contractDrawingIds?: number[]; // อ้างอิงแบบสัญญา contractDrawingIds?: (number | string)[]; // ADR-019: Accept UUID - อ้างอิงแบบสัญญา
attachmentIds?: number[]; attachmentIds?: (number | string)[]; // ADR-019: Accept UUID
} }
// --- Create New Revision --- // --- Create New Revision ---
@@ -24,15 +24,15 @@ export interface CreateShopDrawingRevisionDto {
legacyDrawingNumber?: string; legacyDrawingNumber?: string;
revisionDate?: string; revisionDate?: string;
description?: string; description?: string;
contractDrawingIds?: number[]; contractDrawingIds?: (number | string)[]; // ADR-019: Accept UUID
attachmentIds?: number[]; attachmentIds?: (number | string)[]; // ADR-019: Accept UUID
} }
// --- Search --- // --- Search ---
export interface SearchShopDrawingDto { export interface SearchShopDrawingDto {
projectUuid: string; projectUuid: string;
mainCategoryId?: number; mainCategoryId?: number | string; // ADR-019: Accept UUID
subCategoryId?: number; subCategoryId?: number | string; // ADR-019: Accept UUID
search?: string; search?: string;
page?: number; // Default: 1 page?: number; // Default: 1
+1 -1
View File
@@ -1,7 +1,7 @@
// File: src/types/dto/master/discipline.dto.ts // File: src/types/dto/master/discipline.dto.ts
export interface CreateDisciplineDto { export interface CreateDisciplineDto {
contractId: number; contractId: number | string; // ADR-019: Accept UUID
/** รหัสสาขา (เช่น 'STR', 'ARC') */ /** รหัสสาขา (เช่น 'STR', 'ARC') */
disciplineCode: string; disciplineCode: string;
+4 -4
View File
@@ -1,8 +1,8 @@
// File: src/types/dto/master/tag.dto.ts // File: src/types/dto/master/tag.dto.ts
export interface CreateTagDto { export interface CreateTagDto {
/** ID โครงการ (NULL = Global) */ /** ID โครงการ (NULL = Global) - ADR-019: Accept UUID */
projectId?: number | null; projectId?: number | string | null;
/** ชื่อ Tag (เช่น 'URGENT') */ /** ชื่อ Tag (เช่น 'URGENT') */
tagName: string; tagName: string;
@@ -17,8 +17,8 @@ export interface CreateTagDto {
export type UpdateTagDto = Partial<CreateTagDto>; export type UpdateTagDto = Partial<CreateTagDto>;
export interface SearchTagDto { export interface SearchTagDto {
/** ID โครงการ (ใช้กรอง Tag ของแต่ละโปรเจกต์) */ /** ID โครงการ (ใช้กรอง Tag ของแต่ละโปรเจกต์) - ADR-019: Accept UUID */
projectId?: number; projectId?: number | string;
/** คำค้นหา (ชื่อ Tag หรือ คำอธิบาย) */ /** คำค้นหา (ชื่อ Tag หรือ คำอธิบาย) */
search?: string; search?: string;
+12 -11
View File
@@ -8,7 +8,8 @@ export interface AuditErrorRecord {
} }
export interface NumberingAuditLog { export interface NumberingAuditLog {
id: number; publicId: string; // ADR-019: public identifier
id?: number; // Internal INT (excluded from API)
documentNumber: string; documentNumber: string;
operation: string; operation: string;
status: string; status: string;
@@ -22,13 +23,13 @@ export interface NumberingMetrics {
} }
export interface ManualOverrideDto { export interface ManualOverrideDto {
projectId: number; projectId: number | string; // ADR-019: Accept UUID
originatorOrganizationId: number; originatorOrganizationId: number | string; // ADR-019: Accept UUID
recipientOrganizationId: number; recipientOrganizationId: number | string; // ADR-019: Accept UUID
correspondenceTypeId: number; correspondenceTypeId: number | string; // ADR-019: Accept UUID
subTypeId?: number; subTypeId?: number | string; // ADR-019: Accept UUID
rfaTypeId?: number; rfaTypeId?: number | string; // ADR-019: Accept UUID
disciplineId?: number; disciplineId?: number | string; // ADR-019: Accept UUID
resetScope: string; resetScope: string;
newLastNumber: number; newLastNumber: number;
reason: string; reason: string;
@@ -38,16 +39,16 @@ export interface VoidReplaceDto {
documentNumber: string; documentNumber: string;
reason: string; reason: string;
replace: boolean; replace: boolean;
projectId: number; projectId: number | string; // ADR-019: Accept UUID
} }
export interface CancelNumberDto { export interface CancelNumberDto {
documentNumber: string; documentNumber: string;
reason: string; reason: string;
projectId?: number; projectId?: number | string; // ADR-019: Accept UUID
} }
export interface AuditQueryParams { export interface AuditQueryParams {
projectId?: number; projectId?: number | string; // ADR-019: Accept UUID
limit?: number; limit?: number;
} }
@@ -4,20 +4,20 @@
export interface CreateOrganizationDto { export interface CreateOrganizationDto {
organizationCode: string; organizationCode: string;
organizationName: string; organizationName: string;
roleId?: number; roleId?: number | string; // ADR-019: Accept UUID
isActive?: boolean; isActive?: boolean;
} }
export interface UpdateOrganizationDto { export interface UpdateOrganizationDto {
organizationCode?: string; organizationCode?: string;
organizationName?: string; organizationName?: string;
roleId?: number; roleId?: number | string; // ADR-019: Accept UUID
isActive?: boolean; isActive?: boolean;
} }
export interface SearchOrganizationDto { export interface SearchOrganizationDto {
search?: string; search?: string;
projectId?: number; projectId?: number | string; // ADR-019: Accept UUID
page?: number; page?: number;
limit?: number; limit?: number;
isActive?: boolean; isActive?: boolean;
+8 -8
View File
@@ -5,11 +5,11 @@ export interface CreateRfaDto {
/** ID or UUID ของโครงการ */ /** ID or UUID ของโครงการ */
projectId: number | string; // ADR-019: Accept UUID projectId: number | string; // ADR-019: Accept UUID
/** ประเภท RFA (เช่น DWG, MAT) */ /** ประเภท RFA (เช่น DWG, MAT) - ADR-019: Accept UUID */
rfaTypeId: number; rfaTypeId: number | string;
/** [Req 6B] สาขางาน (จำเป็นสำหรับการรันเลข RFA) */ /** [Req 6B] สาขางาน (จำเป็นสำหรับการรันเลข RFA) - ADR-019: Accept UUID */
disciplineId?: number; disciplineId?: number | string;
/** หัวข้อเรื่อง */ /** หัวข้อเรื่อง */
subject: string; subject: string;
@@ -50,11 +50,11 @@ export interface SearchRfaDto {
/** Filter by Project ID or UUID (optional to allow cross-project search) */ /** Filter by Project ID or UUID (optional to allow cross-project search) */
projectId?: number | string; // ADR-019: Accept UUID projectId?: number | string; // ADR-019: Accept UUID
/** กรองตามประเภท RFA */ /** กรองตามประเภท RFA - ADR-019: Accept UUID */
rfaTypeId?: number; rfaTypeId?: number | string;
/** กรองตามสถานะ (เช่น Draft, For Approve) */ /** กรองตามสถานะ (เช่น Draft, For Approve) - ADR-019: Accept UUID */
statusId?: number; statusId?: number | string;
/** กรองตามสถานะ code โดยตรง (เช่น 'DFT', 'FAP', 'FRE') */ /** กรองตามสถานะ code โดยตรง (เช่น 'DFT', 'FAP', 'FRE') */
statusCode?: string; statusCode?: string;
@@ -20,7 +20,7 @@ export interface CreateTransmittalDto {
export interface CreateTransmittalItemDto { export interface CreateTransmittalItemDto {
itemType: string; itemType: string;
itemId: number; itemId: number | string; // ADR-019: Accept UUID
description?: string; description?: string;
} }
+6 -6
View File
@@ -17,13 +17,13 @@ export type UpdateUserDto = Partial<CreateUserDto>;
// --- Assign Role --- // --- Assign Role ---
export interface AssignRoleDto { export interface AssignRoleDto {
userId: number; userId: number | string; // ADR-019: Accept UUID
roleId: number; roleId: number | string; // ADR-019: Accept UUID
// Scope (Optional) // Scope (Optional) - ADR-019: Accept UUID
organizationId?: number; organizationId?: number | string;
projectId?: number; projectId?: number | string;
contractId?: number; contractId?: number | string;
} }
// --- Update Preferences --- // --- Update Preferences ---
+18 -10
View File
@@ -3,7 +3,8 @@
*/ */
export interface CorrespondenceType { export interface CorrespondenceType {
id: number; publicId: string; // ADR-019: public identifier
id?: number; // Internal INT (excluded from API)
typeCode: string; typeCode: string;
typeName: string; typeName: string;
isActive: boolean; isActive: boolean;
@@ -11,7 +12,8 @@ export interface CorrespondenceType {
} }
export interface Discipline { export interface Discipline {
id: number; publicId: string; // ADR-019: public identifier
id?: number; // Internal INT (excluded from API)
disciplineCode: string; disciplineCode: string;
codeNameEn: string; codeNameEn: string;
codeNameTh?: string; codeNameTh?: string;
@@ -21,11 +23,12 @@ export interface Discipline {
contractCode: string; contractCode: string;
contractName: string; contractName: string;
}; };
contractId?: number | string; contractId?: number | string; // ADR-019: Accept UUID
} }
export interface RfaType { export interface RfaType {
id: number; publicId: string; // ADR-019: public identifier
id?: number; // Internal INT (excluded from API)
typeCode: string; typeCode: string;
typeNameTh: string; typeNameTh: string;
typeNameEn?: string; typeNameEn?: string;
@@ -36,25 +39,28 @@ export interface RfaType {
contractCode: string; contractCode: string;
contractName: string; contractName: string;
}; };
contractId?: number | string; contractId?: number | string; // ADR-019: Accept UUID
} }
export interface Tag { export interface Tag {
id: number; publicId: string; // ADR-019: public identifier
id?: number; // Internal INT (excluded from API)
tagName: string; tagName: string;
colorCode?: string; colorCode?: string;
description?: string; description?: string;
} }
export interface DrawingCategory { export interface DrawingCategory {
id: number; publicId: string; // ADR-019: public identifier
id?: number; // Internal INT (excluded from API)
subTypeCode: string; subTypeCode: string;
subTypeName: string; subTypeName: string;
subTypeNumber?: string; subTypeNumber?: string;
} }
export interface ShopMainCategory { export interface ShopMainCategory {
id: number; publicId: string; // ADR-019: public identifier
id?: number; // Internal INT (excluded from API)
mainCategoryCode: string; mainCategoryCode: string;
mainCategoryName: string; mainCategoryName: string;
name?: string; // Fallback for legacy data name?: string; // Fallback for legacy data
@@ -62,7 +68,8 @@ export interface ShopMainCategory {
} }
export interface ShopSubCategory { export interface ShopSubCategory {
id: number; publicId: string; // ADR-019: public identifier
id?: number; // Internal INT (excluded from API)
subCategoryCode: string; subCategoryCode: string;
subCategoryName: string; subCategoryName: string;
name?: string; // Fallback for legacy data name?: string; // Fallback for legacy data
@@ -70,7 +77,8 @@ export interface ShopSubCategory {
} }
export interface ContractDrawingCategory { export interface ContractDrawingCategory {
id: number; publicId: string; // ADR-019: public identifier
id?: number; // Internal INT (excluded from API)
catCode: string; catCode: string;
catName: string; catName: string;
name?: string; // Fallback for legacy data name?: string; // Fallback for legacy data
+8 -6
View File
@@ -5,7 +5,8 @@ export enum MigrationReviewStatus {
} }
export interface MigrationReviewQueueItem { export interface MigrationReviewQueueItem {
id: number; publicId: string; // ADR-019: public identifier
id?: number; // Internal INT (excluded from API)
documentNumber: string; documentNumber: string;
title?: string; title?: string;
originalTitle?: string; originalTitle?: string;
@@ -17,15 +18,15 @@ export interface MigrationReviewQueueItem {
reviewedBy?: string; reviewedBy?: string;
reviewedAt?: string; reviewedAt?: string;
createdAt: string; createdAt: string;
projectId?: number; projectId?: number | string; // ADR-019: Accept UUID
senderOrganizationId?: number; senderOrganizationId?: number | string; // ADR-019: Accept UUID
receiverOrganizationId?: number; receiverOrganizationId?: number | string; // ADR-019: Accept UUID
receivedDate?: string; receivedDate?: string;
issuedDate?: string; issuedDate?: string;
remarks?: string; remarks?: string;
aiSummary?: string; aiSummary?: string;
extractedTags?: Record<string, unknown>; extractedTags?: Record<string, unknown>;
tempAttachmentId?: number; tempAttachmentId?: number | string; // ADR-019: Accept UUID
} }
export interface CommitBatchItemDto { export interface CommitBatchItemDto {
@@ -48,7 +49,8 @@ export enum MigrationErrorType {
} }
export interface MigrationErrorItem { export interface MigrationErrorItem {
id: number; publicId: string; // ADR-019: public identifier
id?: number; // Internal INT (excluded from API)
batchId?: string; batchId?: string;
documentNumber?: string; documentNumber?: string;
errorType?: MigrationErrorType; errorType?: MigrationErrorType;
+4 -2
View File
@@ -1,7 +1,8 @@
export type WorkflowType = 'CORRESPONDENCE' | 'RFA' | 'DRAWING'; export type WorkflowType = 'CORRESPONDENCE' | 'RFA' | 'DRAWING';
export interface WorkflowStep { export interface WorkflowStep {
stepId?: string; publicId: string; // ADR-019: public identifier
stepId?: string; // Internal ID (excluded from API)
stepName: string; stepName: string;
stepType: 'APPROVAL' | 'REVIEW' | 'ENDORSEMENT'; stepType: 'APPROVAL' | 'REVIEW' | 'ENDORSEMENT';
approverRoleId?: number; approverRoleId?: number;
@@ -11,7 +12,8 @@ export interface WorkflowStep {
} }
export interface Workflow { export interface Workflow {
workflowId: string | number; publicId: string; // ADR-019: public identifier
workflowId?: string | number; // Internal ID (excluded from API)
workflowName: string; workflowName: string;
description: string; description: string;
workflowType: WorkflowType; workflowType: WorkflowType;