This commit is contained in:
@@ -53,7 +53,7 @@ export function TemplateTester({ open, onOpenChange, template }: TemplateTesterP
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
// Master Data Hooks
|
||||
const projectId = template?.projectId || 1;
|
||||
const projectId = (template as any)?.project?.id ?? (template as any)?.project?.uuid ?? template?.projectId ?? 1;
|
||||
const { data: organizations } = useOrganizations({ isActive: true });
|
||||
const { data: correspondenceTypes } = useCorrespondenceTypes();
|
||||
const { data: contracts } = useContracts(projectId);
|
||||
@@ -117,7 +117,7 @@ export function TemplateTester({ open, onOpenChange, template }: TemplateTesterP
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{(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>
|
||||
))}
|
||||
@@ -137,7 +137,7 @@ export function TemplateTester({ open, onOpenChange, template }: TemplateTesterP
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{(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>
|
||||
))}
|
||||
|
||||
@@ -30,7 +30,7 @@ export function RFADetail({ data }: RFADetailProps) {
|
||||
|
||||
processMutation.mutate(
|
||||
{
|
||||
id: data.rfaId,
|
||||
uuid: data.uuid,
|
||||
data: {
|
||||
action: apiAction,
|
||||
comments: comments,
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useCreateRFA } from "@/hooks/use-rfa";
|
||||
import { useDisciplines, useContracts } from "@/hooks/use-master-data";
|
||||
import { useProjects } from "@/hooks/use-projects";
|
||||
import { CreateRFADto } from "@/types/rfa";
|
||||
import { useState, useEffect } from "react";
|
||||
import { correspondenceService } from "@/lib/services/correspondence.service";
|
||||
@@ -30,6 +31,7 @@ const rfaItemSchema = z.object({
|
||||
unit: z.string().min(1, "Unit is required"),
|
||||
});
|
||||
const rfaSchema = z.object({
|
||||
projectId: z.string().min(1, "Project is required"), // ADR-019: UUID
|
||||
contractId: z.string().min(1, "Contract is required"),
|
||||
disciplineId: z.number().min(1, "Discipline is required"),
|
||||
rfaTypeId: z.number().min(1, "Type is required"),
|
||||
@@ -49,9 +51,9 @@ export function RFAForm() {
|
||||
const router = useRouter();
|
||||
const createMutation = useCreateRFA();
|
||||
|
||||
// Dynamic Contract Loading (Default Project Context: 1)
|
||||
const currentProjectId = 1;
|
||||
const { data: contracts, isLoading: isLoadingContracts } = useContracts(currentProjectId);
|
||||
// ADR-019: Dynamic project selection
|
||||
const { data: projectsData, isLoading: isLoadingProjects } = useProjects();
|
||||
const projects = projectsData?.data || projectsData || [];
|
||||
|
||||
const {
|
||||
register,
|
||||
@@ -63,6 +65,7 @@ export function RFAForm() {
|
||||
} = useForm<RFAFormData>({
|
||||
resolver: zodResolver(rfaSchema),
|
||||
defaultValues: {
|
||||
projectId: "",
|
||||
contractId: "",
|
||||
disciplineId: 0,
|
||||
rfaTypeId: 0,
|
||||
@@ -77,6 +80,9 @@ export function RFAForm() {
|
||||
},
|
||||
});
|
||||
|
||||
const selectedProjectId = watch("projectId");
|
||||
const { data: contracts, isLoading: isLoadingContracts } = useContracts(selectedProjectId);
|
||||
|
||||
const selectedContractId = watch("contractId");
|
||||
const { data: disciplines, isLoading: isLoadingDisciplines } = useDisciplines(selectedContractId);
|
||||
|
||||
@@ -97,7 +103,7 @@ export function RFAForm() {
|
||||
const fetchPreview = async () => {
|
||||
try {
|
||||
const res = await correspondenceService.previewNumber({
|
||||
projectId: currentProjectId,
|
||||
projectId: selectedProjectId,
|
||||
typeId: rfaTypeId, // RfaTypeId acts as TypeId
|
||||
disciplineId,
|
||||
// RFA uses 'TO' organization as recipient
|
||||
@@ -112,7 +118,7 @@ export function RFAForm() {
|
||||
|
||||
const timer = setTimeout(fetchPreview, 500);
|
||||
return () => clearTimeout(timer);
|
||||
}, [rfaTypeId, disciplineId, toOrganizationId, currentProjectId]);
|
||||
}, [rfaTypeId, disciplineId, toOrganizationId, selectedProjectId]);
|
||||
|
||||
const { fields, append, remove } = useFieldArray({
|
||||
control,
|
||||
@@ -122,7 +128,7 @@ export function RFAForm() {
|
||||
const onSubmit = (data: RFAFormData) => {
|
||||
const payload: CreateRFADto = {
|
||||
...data,
|
||||
projectId: currentProjectId,
|
||||
// ADR-019: projectId is already a UUID string from the form
|
||||
};
|
||||
createMutation.mutate(payload as any, {
|
||||
onSuccess: () => {
|
||||
@@ -178,19 +184,45 @@ export function RFAForm() {
|
||||
<Input id="description" {...register("description")} placeholder="Enter key description" />
|
||||
</div>
|
||||
|
||||
{/* ADR-019: Project selector */}
|
||||
<div>
|
||||
<Label>Project *</Label>
|
||||
<Select
|
||||
onValueChange={(val) => {
|
||||
setValue("projectId", val);
|
||||
setValue("contractId", ""); // Reset contract when project changes
|
||||
}}
|
||||
disabled={isLoadingProjects}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={isLoadingProjects ? "Loading..." : "Select Project"} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{(Array.isArray(projects) ? projects : []).map((p: { uuid: string; projectName?: string; projectCode?: string }) => (
|
||||
<SelectItem key={p.uuid} value={p.uuid}>
|
||||
{p.projectName || p.projectCode}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
{errors.projectId && (
|
||||
<p className="text-sm text-destructive mt-1">{errors.projectId.message}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<Label>Contract *</Label>
|
||||
<Select
|
||||
onValueChange={(val) => setValue("contractId", val)}
|
||||
disabled={isLoadingContracts}
|
||||
disabled={!selectedProjectId || isLoadingContracts}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={isLoadingContracts ? "Loading..." : "Select Contract"} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{contracts?.map((c: any) => (
|
||||
<SelectItem key={c.id} value={String(c.id)}>
|
||||
{contracts?.map((c: { uuid: string; contractName?: string; name?: string; contractCode?: string }) => (
|
||||
<SelectItem key={c.uuid} value={c.uuid}>
|
||||
{c.contractName || c.name || c.contractCode}
|
||||
</SelectItem>
|
||||
))}
|
||||
|
||||
@@ -89,7 +89,7 @@ export function RFAList({ data }: RFAListProps) {
|
||||
|
||||
return (
|
||||
<div className="flex gap-2">
|
||||
<Link href={`/rfas/${row.original.id}`}>
|
||||
<Link href={`/rfas/${row.original.uuid}`}>
|
||||
<Button variant="ghost" size="icon" title="View Details">
|
||||
<Eye className="h-4 w-4" />
|
||||
</Button>
|
||||
@@ -97,7 +97,7 @@ export function RFAList({ data }: RFAListProps) {
|
||||
<Button variant="ghost" size="icon" title="View File" onClick={handleViewFile}>
|
||||
<FileText className="h-4 w-4" />
|
||||
</Button>
|
||||
<Link href={`/rfas/${row.original.id}/edit`}>
|
||||
<Link href={`/rfas/${row.original.uuid}/edit`}>
|
||||
<Button variant="ghost" size="icon" title="Edit">
|
||||
<Edit className="h-4 w-4" />
|
||||
</Button>
|
||||
|
||||
@@ -9,6 +9,8 @@ import { z } from "zod";
|
||||
|
||||
import { transmittalService } from "@/lib/services/transmittal.service";
|
||||
import { correspondenceService } from "@/lib/services/correspondence.service";
|
||||
import { projectService } from "@/lib/services/project.service";
|
||||
import { organizationService } from "@/lib/services/organization.service";
|
||||
import { CreateTransmittalDto } from "@/types/dto/transmittal/transmittal.dto";
|
||||
|
||||
// UI Components
|
||||
@@ -59,6 +61,8 @@ const itemSchema = z.object({
|
||||
|
||||
// Main form schema
|
||||
const formSchema = z.object({
|
||||
projectId: z.string().min(1, "Project is required"), // ADR-019: UUID
|
||||
recipientOrganizationId: z.string().min(1, "Recipient is required"), // ADR-019: UUID
|
||||
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"]),
|
||||
@@ -75,6 +79,9 @@ export function TransmittalForm() {
|
||||
const form = useForm<FormData>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
projectId: "",
|
||||
recipientOrganizationId: "",
|
||||
correspondenceId: "",
|
||||
subject: "",
|
||||
purpose: "FOR_APPROVAL",
|
||||
remarks: "",
|
||||
@@ -89,6 +96,19 @@ export function TransmittalForm() {
|
||||
name: "items",
|
||||
});
|
||||
|
||||
// ADR-019: Fetch projects and organizations for UUID-based selectors
|
||||
const { data: projectsData, isLoading: isLoadingProjects } = useQuery({
|
||||
queryKey: ["projects-dropdown"],
|
||||
queryFn: () => projectService.getAll(),
|
||||
});
|
||||
const projectsList = projectsData?.data || projectsData || [];
|
||||
|
||||
const { data: orgsData, isLoading: isLoadingOrgs } = useQuery({
|
||||
queryKey: ["organizations-dropdown"],
|
||||
queryFn: () => organizationService.getAll(),
|
||||
});
|
||||
const orgsList = orgsData?.data || orgsData || [];
|
||||
|
||||
// Fetch correspondences (for header linkage)
|
||||
const { data: correspondences } = useQuery({
|
||||
queryKey: ["correspondences-dropdown"],
|
||||
@@ -99,7 +119,8 @@ export function TransmittalForm() {
|
||||
mutationFn: (data: CreateTransmittalDto) => transmittalService.create(data),
|
||||
onSuccess: (result) => {
|
||||
toast.success("Transmittal created successfully");
|
||||
router.push(`/transmittals/${result.id}`);
|
||||
// ADR-019: Navigate using UUID from correspondence
|
||||
router.push(`/transmittals/${result.correspondence?.uuid || result.uuid}`);
|
||||
},
|
||||
onError: () => {
|
||||
toast.error("Failed to create transmittal");
|
||||
@@ -107,13 +128,13 @@ export function TransmittalForm() {
|
||||
});
|
||||
|
||||
const onSubmit = (data: FormData) => {
|
||||
// Better fix: Add missing recipientOrganizationId mock
|
||||
// ADR-019: All IDs are now UUID strings from the form
|
||||
const cleanPayload: CreateTransmittalDto = {
|
||||
projectId: 1,
|
||||
recipientOrganizationId: 99, // Mock
|
||||
projectId: data.projectId,
|
||||
recipientOrganizationId: data.recipientOrganizationId,
|
||||
correspondenceId: data.correspondenceId,
|
||||
subject: data.subject,
|
||||
purpose: data.purpose as any,
|
||||
purpose: data.purpose as string,
|
||||
remarks: data.remarks,
|
||||
items: data.items.map(item => ({
|
||||
itemType: item.itemType,
|
||||
@@ -139,6 +160,59 @@ export function TransmittalForm() {
|
||||
<CardTitle>Transmittal Details</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-6">
|
||||
{/* ADR-019: Project & Recipient Organization selectors */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="projectId"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Project</FormLabel>
|
||||
<Select onValueChange={field.onChange} value={field.value} disabled={isLoadingProjects}>
|
||||
<FormControl>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={isLoadingProjects ? "Loading..." : "Select Project"} />
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
{(Array.isArray(projectsList) ? projectsList : []).map((p: { uuid: string; projectName?: string; projectCode?: string }) => (
|
||||
<SelectItem key={p.uuid} value={p.uuid}>
|
||||
{p.projectName || p.projectCode}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="recipientOrganizationId"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Recipient Organization</FormLabel>
|
||||
<Select onValueChange={field.onChange} value={field.value} disabled={isLoadingOrgs}>
|
||||
<FormControl>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={isLoadingOrgs ? "Loading..." : "Select Organization"} />
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
{(Array.isArray(orgsList) ? orgsList : []).map((o: { uuid: string; organizationName?: string; orgCode?: string }) => (
|
||||
<SelectItem key={o.uuid} value={o.uuid}>
|
||||
{o.organizationName || o.orgCode}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
{/* Linked Correspondence (Ref No) */}
|
||||
<FormField
|
||||
|
||||
@@ -59,7 +59,7 @@ export function TransmittalList({ data }: TransmittalListProps) {
|
||||
cell: ({ row }) => {
|
||||
const item = row.original;
|
||||
return (
|
||||
<Link href={`/transmittals/${item.id}`}>
|
||||
<Link href={`/transmittals/${item.uuid}`}>
|
||||
<Button variant="ghost" size="icon" title="View Details">
|
||||
<Eye className="h-4 w-4" />
|
||||
</Button>
|
||||
|
||||
Reference in New Issue
Block a user