Files
sistema_base/apps/web/feactures/training/components/form.tsx

1814 lines
64 KiB
TypeScript

'use client';
import { zodResolver } from '@hookform/resolvers/zod';
import { Button } from '@repo/shadcn/button';
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@repo/shadcn/form';
import { Input } from '@repo/shadcn/input';
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@repo/shadcn/select';
import { Textarea } from '@repo/shadcn/textarea';
import { useForm } from 'react-hook-form';
import { useCreateTraining, useUpdateTraining } from '../hooks/use-training';
import { TrainingSchema, trainingSchema } from '../schemas/training';
import {
useMunicipalityQuery,
useParishQuery,
useStateQuery,
} from '@/feactures/location/hooks/use-query-location';
import {
Card,
CardContent,
CardHeader,
CardTitle,
} from '@repo/shadcn/components/ui/card';
import { SelectSearchable } from '@repo/shadcn/select-searchable';
import React from 'react';
import { COUNTRY_OPTIONS } from '@/constants/countries';
// const PRODUCTIVE_ACTIVITIES = [
// 'Agricola',
// 'Textil',
// 'Bloquera',
// 'Carpinteria',
// 'Unidad de suministro',
// ];
const ECO_SECTORS = ['Primario', 'Secundario', 'Terciario'];
const PRODUCTIVE_SECTORS = ['Agricola', 'Manufactura', 'Servicios', 'Comercio', 'Turismo'];
const CENTRAL_PRODUCTIVE_ACTIVITY = [
'Produción Vegetal',
'Produción Animal',
'Produción Animal y Vegetal',
'INDUSTRIAL',
'SERVICIOS',
'TURISMO',
'COMERCIO'
];
const MAIN_PRODUCTIVE_ACTIVITY = [
'AGRICULTURA ',
'CRIA ',
'PATIOS PRODUCTIVOS O CONUCOS ',
'TRANSFORMACION DE LA MATERIA PRIMA',
'TALLER DE COFECCION TEXTIL ',
'CONSTRUCION ',
'OFRECER PRODUCTOS DE BIENES Y SERVICIOS',
'VISITAS GUIADAS ',
'ALOJAMIENTO ',
'TURISMO',
'COMERCIO'
];
const PRODUCTIVE_ACTIVITIES = [
'SIEMBRA DE MAIZ ',
'SIEMBRA DE AJI',
'SIEMBRA DE CAFÉ ',
'SIEMBRA DE PLATANO',
'SIEMBRA DE CAMBUR ',
'SIEMBRA DE AGUACATE',
'SIEMBRA DE FRUTAS',
'SIEMBRA DE HORTALIZAS ',
'SIEMBRA DE TOMATE ',
'SIEMBRA DE CACAO',
'SIEMBRA DE PIMENTON ',
'SIEMBRA DE YUCA ',
'SIEMBRA DE CAÑA DE AZUCAR ',
'SIEMBRA DE GRANOS (CARAOTAS, FRIJOLES)',
'SIEMBRA DE ARROZ',
'SIEMBRA DE CEREALES (CEBADA, LINAZA, SOYA)',
'ELABORACION DE BIO-INSUMO (ABONO ORGANICO) ',
'BOVINO ',
'PORCINO',
'CAPRINO',
'CUNICULTURA',
'AVICOLA',
'PISCICULA',
'SIEMBRA Y CRIA ',
'ELABORACION DE PRODUCTOS QUIMICOS (LIMPIEZA E HIGIENE PERSONAL)',
'PANADERIAS',
'RESPOSTERIA ',
'ELABORACION DE HARINAS PRECOCIDA ',
'PLANTA ABA (ELABORACION DE ALIMENTOS BALANCEADOS PARA ANIMALES)',
'ELABORACION DE PRODUCTOS DERIVADO DE LA LECHE (VACA, CABRA, BUFFALA)',
'EMPAQUETADORAS DE GRANOS Y POLVOS ',
'ELABORACION DE ACEITE COMESTIBLE ',
'FABRICA DE HIELO',
'ELABORACION DE PAPELON',
'ARTESANIAS',
'ELABORACION DE UNIFORME ESCOLARES Y PRENDA DE VESTIR ',
'ELABORACION DE PRENDAS INTIMAS ',
'ELABORACION DE LENCERIA ',
'SUBLIMACION DE TEJIDOS ',
'ELABORACION DE CALZADOS ',
'BLOQUERAS ',
'PLANTA PREMEZCLADORA DE CEMENTO',
'CARPINTERIAS',
'HERRERIAS',
'MERCADOS COMUNALES',
'CENTROS DE ACOPIOS Y DISTRIBUCION',
'UNIDAD DE SUMINISTRO',
'MATADERO (SALA DE MATANZA DE ANIMALES)',
'PELUQUERIA',
'BARBERIA',
'AGENCIAS DE FESTEJOS',
'LAVANDERIAS',
'REPARACION DE CALZADOS',
'TALLER DE MECANICA',
'TRANSPORTES',
'RUTAS TURISTICAS',
'POSADAS',
'HOTELES',
'AGENCIAS DE VIAJES',
'VENTA DE VIVERES',
'VENTAS DE PRENDAS DE VESTIR',
'VENTA DE PRODUCTOS QUIMICOS Y DERIVADOS',
'BODEGAS COMUNALES',
'FRIGORIFICOS Y CARNICOS'
]
const OSP_TYPES = ['EPSIC', 'EPSDC', 'UPF', 'OTROS', 'COOPERATIVA'];
const STATUS_OPTIONS = ['ACTIVA', 'INACTIVA'];
const CIVIL_STATE_OPTIONS = ['Soltero', 'Casado'];
interface CreateTrainingFormProps {
onSuccess?: () => void;
onCancel?: () => void;
defaultValues?: Partial<TrainingSchema>;
}
export function CreateTrainingForm({
onSuccess,
onCancel,
defaultValues,
}: CreateTrainingFormProps) {
const { mutate: createTraining, isPending: isCreating } = useCreateTraining();
const { mutate: updateTraining, isPending: isUpdating } = useUpdateTraining();
const isSaving = isCreating || isUpdating;
const [state, setState] = React.useState(0);
const [municipality, setMunicipality] = React.useState(0);
const [disabledMunicipality, setDisabledMunicipality] = React.useState(true);
const [disabledParish, setDisabledParish] = React.useState(true);
const [coorState, setcoorState] = React.useState(0);
const [coorMunicipality, setcoorMunicipality] = React.useState(0);
const [disabledCoorMunicipality, setDisabledCoorMunicipality] = React.useState(true);
const [disabledCoorParish, setDisabledCoorParish] = React.useState(true);
const [selectedFiles, setSelectedFiles] = React.useState<File[]>([]);
const { data: dataState } = useStateQuery();
const { data: dataMunicipality } = useMunicipalityQuery(state);
const { data: dataParish } = useParishQuery(municipality);
const { data: dataCoorState } = useStateQuery();
const { data: dataCoorMunicipality } = useMunicipalityQuery(coorState);
const { data: dataCoorParish } = useParishQuery(coorMunicipality);
const coorStateOptions = dataCoorState?.data || [{ id: 0, name: 'Sin estados' }];
const coorMunicipalityOptions =
Array.isArray(dataCoorMunicipality?.data) && dataCoorMunicipality.data.length > 0
? dataCoorMunicipality.data
: [{ id: 0, stateId: 0, name: 'Sin Municipios' }];
const coorParishOptions =
Array.isArray(dataCoorParish?.data) && dataCoorParish.data.length > 0
? dataCoorParish.data
: [{ id: 0, stateId: 0, name: 'Sin Parroquias' }];
const stateOptions = dataState?.data || [{ id: 0, name: 'Sin estados' }];
const municipalityOptions =
Array.isArray(dataMunicipality?.data) && dataMunicipality.data.length > 0
? dataMunicipality.data
: [{ id: 0, stateId: 0, name: 'Sin Municipios' }];
const parishOptions =
Array.isArray(dataParish?.data) && dataParish.data.length > 0
? dataParish.data
: [{ id: 0, stateId: 0, name: 'Sin Parroquias' }];
// No local state needed for existing photos, we use form values
React.useEffect(() => {
if (defaultValues) {
if (defaultValues.state) {
setState(Number(defaultValues.state));
setDisabledMunicipality(false);
}
if (defaultValues.municipality) {
setMunicipality(Number(defaultValues.municipality));
setDisabledParish(false);
}
if (defaultValues.coorState) {
setcoorState(Number(defaultValues.coorState));
setDisabledCoorMunicipality(false);
}
if (defaultValues.coorMunicipality) {
setcoorMunicipality(Number(defaultValues.coorMunicipality));
setDisabledCoorParish(false);
}
}
}, [defaultValues]);
const formatToLocalISO = (dateStr?: string | Date) => {
const date = dateStr ? new Date(dateStr) : new Date();
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
return `${year}-${month}-${day}T${hours}:${minutes}`;
};
const form = useForm<TrainingSchema>({
resolver: zodResolver(trainingSchema),
defaultValues: {
firstname: defaultValues?.firstname || '',
lastname: defaultValues?.lastname || '',
coorState: defaultValues?.coorState || undefined,
coorMunicipality: defaultValues?.coorMunicipality || undefined,
coorParish: defaultValues?.coorParish || undefined,
coorPhone: defaultValues?.coorPhone || '',
visitDate: formatToLocalISO(defaultValues?.visitDate),
productiveActivity: defaultValues?.productiveActivity || '',
ecoSector: defaultValues?.ecoSector || undefined,
productiveSector: defaultValues?.productiveSector || undefined,
centralProductiveActivity: defaultValues?.centralProductiveActivity || '',
mainProductiveActivity: defaultValues?.mainProductiveActivity || '',
typesOfEquipment: defaultValues?.typesOfEquipment || '',
equipmentCount: defaultValues?.equipmentCount || 0,
equipmentDescription: defaultValues?.equipmentDescription || '',
rawMaterial: defaultValues?.rawMaterial || '',
materialType: defaultValues?.materialType || '',
rawMaterialCount: defaultValues?.rawMaterialCount || 0,
productCountDaily: defaultValues?.productCountDaily || 0,
productCountWeekly: defaultValues?.productCountWeekly || 0,
productCountMonthly: defaultValues?.productCountMonthly || 0,
// financialRequirementDescription:
// defaultValues?.financialRequirementDescription || '',
siturCodeCommune: defaultValues?.siturCodeCommune || '',
communeName: defaultValues?.communeName || '',
communeRif: defaultValues?.communeRif || '',
communeSpokespersonName: defaultValues?.communeSpokespersonName || '',
communeSpokespersonCedula: defaultValues?.communeSpokespersonCedula || '',
communeSpokespersonRif: defaultValues?.communeSpokespersonRif || '',
communeSpokespersonPhone: defaultValues?.communeSpokespersonPhone || '',
communeEmail: defaultValues?.communeEmail || '',
communalCouncil: defaultValues?.communalCouncil || '',
siturCodeCommunalCouncil: defaultValues?.siturCodeCommunalCouncil || '',
communalCouncilRif: defaultValues?.communalCouncilRif || '',
communalCouncilSpokespersonName: defaultValues?.communalCouncilSpokespersonName || '',
communalCouncilSpokespersonCedula: defaultValues?.communalCouncilSpokespersonCedula || '',
communalCouncilSpokespersonRif: defaultValues?.communalCouncilSpokespersonRif || '',
communalCouncilSpokespersonPhone: defaultValues?.communalCouncilSpokespersonPhone || '',
communalCouncilEmail: defaultValues?.communalCouncilEmail || '',
ospGoogleMapsLink: defaultValues?.ospGoogleMapsLink || '',
ospName: defaultValues?.ospName || '',
ospAddress: defaultValues?.ospAddress || '',
ospRif: defaultValues?.ospRif || '',
ospType: defaultValues?.ospType || '',
currentStatus: defaultValues?.currentStatus || 'ACTIVA',
companyConstitutionYear:
defaultValues?.companyConstitutionYear || new Date().getFullYear(),
producerCount: defaultValues?.producerCount || 0,
// productCount: defaultValues?.productCount || 0,
productDescription: defaultValues?.productDescription || '',
prodDescriptionInternal: defaultValues?.prodDescriptionInternal || '',
installedCapacity: defaultValues?.installedCapacity || '',
operationalCapacity: defaultValues?.operationalCapacity || '',
ospResponsibleFullname: defaultValues?.ospResponsibleFullname || '',
ospResponsibleCedula: defaultValues?.ospResponsibleCedula || '',
ospResponsibleRif: defaultValues?.ospResponsibleRif || '',
ospResponsiblePhone: defaultValues?.ospResponsiblePhone || '',
civilState: defaultValues?.civilState || '',
familyBurden: defaultValues?.familyBurden || 0,
numberOfChildren: defaultValues?.numberOfChildren || 0,
generalObservations: defaultValues?.generalObservations || '',
ospResponsibleEmail: defaultValues?.ospResponsibleEmail || '',
photo1: defaultValues?.photo1 || '',
photo2: defaultValues?.photo2 || '',
photo3: defaultValues?.photo3 || '',
paralysisReason: defaultValues?.paralysisReason || '',
state: defaultValues?.state || undefined,
municipality: defaultValues?.municipality || undefined,
parish: defaultValues?.parish || undefined,
internalCount: defaultValues?.internalCount || 0,
externalCount: defaultValues?.externalCount || 0,
prodDescriptionExternal: defaultValues?.prodDescriptionExternal || '',
country: defaultValues?.country || undefined,
city: defaultValues?.city || undefined,
menCount: defaultValues?.menCount || 0,
womenCount: defaultValues?.womenCount || 0,
},
mode: 'onChange',
});
const onSubmit = async (formData: TrainingSchema) => {
const data = new FormData();
Object.entries(formData).forEach(([key, value]) => {
if (key !== 'files' && value !== undefined && value !== null) {
data.append(key, value.toString());
}
});
if (defaultValues?.id) {
data.append('id', defaultValues.id.toString());
}
selectedFiles.forEach((file) => {
data.append('files', file);
});
const mutation = defaultValues?.id ? updateTraining : createTraining;
mutation(data as any, {
onSuccess: () => {
form.reset();
setSelectedFiles([]);
onSuccess?.();
},
onError: (e) => {
console.error(e);
form.setError('root', {
type: 'manual',
message: 'Error al guardar el registro',
});
},
});
};
return (
<>
<div className="flex items-start justify-between mb-2">
<div className="ml-2">
<h2 className="text-3xl font-bold tracking-tight">
Formulario de Registro de Organizaciones Socioproductivas
</h2>
<p className="text-sm text-muted-foreground">
Complete el Formulario para guardar la organización
</p>
</div>
</div>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6 mt-4">
{form.formState.errors.root && (
<div className="text-destructive text-sm font-medium p-3 bg-destructive/10 rounded-md">
{form.formState.errors.root.message}
</div>
)}
{/* 1. Datos de la visita */}
<Card>
<CardHeader>
<CardTitle>1. Datos de la visita</CardTitle>
</CardHeader>
<CardContent className="grid grid-cols-1 md:grid-cols-2 gap-4">
<FormField
control={form.control}
name="firstname"
render={({ field }) => (
<FormItem>
<FormLabel>Nombre del Coordinador Estadal</FormLabel>
<FormControl>
<Input {...field} placeholder="Ej. Juan" />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="lastname"
render={({ field }) => (
<FormItem>
<FormLabel>Apellido del coordinador Estadal</FormLabel>
<FormControl>
<Input {...field} placeholder="Ej. Pérez" />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="coorPhone"
render={({ field }) => (
<FormItem>
<FormLabel>Telefono del coordinador Estadal</FormLabel>
<FormControl>
<Input type="number" {...field} placeholder="Ej. 04121234567" value={field.value ?? ''} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="coorState"
render={({ field }) => (
<FormItem>
<FormLabel>Estado</FormLabel>
<SelectSearchable
options={coorStateOptions.map((item) => ({
value: item.id.toString(),
label: item.name,
}))}
onValueChange={(value) => {
field.onChange(Number(value));
setcoorState(Number(value));
setDisabledCoorMunicipality(false);
setDisabledCoorParish(true);
}}
placeholder="Selecciona un estado"
defaultValue={field.value?.toString()}
/>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="coorMunicipality"
render={({ field }) => (
<FormItem>
<FormLabel>Municipio</FormLabel>
<SelectSearchable
options={coorMunicipalityOptions.map((item) => ({
value: item.id.toString(),
label: item.name,
}))}
onValueChange={(value) => {
field.onChange(Number(value));
setcoorMunicipality(Number(value));
setDisabledCoorParish(false);
}}
placeholder="Selecciona un municipio"
disabled={disabledCoorMunicipality}
defaultValue={field.value?.toString()}
/>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="coorParish"
render={({ field }) => (
<FormItem>
<FormLabel>Parroquia</FormLabel>
<SelectSearchable
options={coorParishOptions.map((item) => ({
value: item.id.toString(),
label: item.name,
}))}
onValueChange={(value) => field.onChange(Number(value))}
placeholder="Selecciona una parroquia"
disabled={disabledCoorParish}
defaultValue={field.value?.toString()}
/>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="visitDate"
render={({ field }) => (
<FormItem>
<FormLabel>Fecha y hora de la visita</FormLabel>
<FormControl>
<Input
type="datetime-local"
{...field}
value={field.value || ''}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</CardContent>
</Card>
{/* 2. Datos de la OSP */}
<Card>
<CardHeader>
<CardTitle>
2. Datos de la Organización Socioproductiva (OSP)
</CardTitle>
</CardHeader>
<CardContent className="grid grid-cols-1 md:grid-cols-2 gap-4">
<FormField
control={form.control}
name="ospType"
render={({ field }) => (
<FormItem>
<FormLabel>Tipos de Organización</FormLabel>
<Select
onValueChange={field.onChange}
defaultValue={field.value}
>
<FormControl>
<SelectTrigger className="w-full">
<SelectValue placeholder="Seleccione tipo" />
</SelectTrigger>
</FormControl>
<SelectContent>
{OSP_TYPES.map((type) => (
<SelectItem key={type} value={type}>
{type}
</SelectItem>
))}
</SelectContent>
</Select>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="ecoSector"
render={({ field }) => (
<FormItem>
<FormLabel>Sector Económico</FormLabel>
<Select
onValueChange={field.onChange}
defaultValue={field.value}
>
<FormControl>
<SelectTrigger className="w-full">
<SelectValue placeholder="Seleccione sector económico" />
</SelectTrigger>
</FormControl>
<SelectContent>
{ECO_SECTORS.map((type) => (
<SelectItem key={type} value={type}>
{type}
</SelectItem>
))}
</SelectContent>
</Select>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="productiveSector"
render={({ field }) => (
<FormItem>
<FormLabel>Sector Productivo</FormLabel>
<Select
onValueChange={field.onChange}
defaultValue={field.value}
>
<FormControl>
<SelectTrigger className="w-full">
<SelectValue placeholder="Seleccione sector productivo" />
</SelectTrigger>
</FormControl>
<SelectContent>
{PRODUCTIVE_SECTORS.map((type) => (
<SelectItem key={type} value={type}>
{type}
</SelectItem>
))}
</SelectContent>
</Select>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="centralProductiveActivity"
render={({ field }) => (
<FormItem>
<FormLabel>Actividad Central Productivo</FormLabel>
<Select
onValueChange={field.onChange}
defaultValue={field.value}
>
<FormControl>
<SelectTrigger className="w-full">
<SelectValue placeholder="Seleccione actividad central productiva" />
</SelectTrigger>
</FormControl>
<SelectContent>
{CENTRAL_PRODUCTIVE_ACTIVITY.map((type) => (
<SelectItem key={type} value={type}>
{type}
</SelectItem>
))}
</SelectContent>
</Select>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="mainProductiveActivity"
render={({ field }) => (
<FormItem>
<FormLabel>Actividad Productiva Principal</FormLabel>
<Select
onValueChange={field.onChange}
defaultValue={field.value}
>
<FormControl>
<SelectTrigger className="w-full">
<SelectValue placeholder="Seleccione actividad productiva principal" />
</SelectTrigger>
</FormControl>
<SelectContent>
{MAIN_PRODUCTIVE_ACTIVITY.map((type) => (
<SelectItem key={type} value={type}>
{type}
</SelectItem>
))}
</SelectContent>
</Select>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="productiveActivity"
render={({ field }) => (
<FormItem>
<FormLabel>Actividad Productiva</FormLabel>
<Select
onValueChange={field.onChange}
defaultValue={field.value}
>
<FormControl>
<SelectTrigger className="w-full">
<SelectValue placeholder="Seleccione actividad productiva" />
</SelectTrigger>
</FormControl>
<SelectContent>
{PRODUCTIVE_ACTIVITIES.map((type) => (
<SelectItem key={type} value={type}>
{type}
</SelectItem>
))}
</SelectContent>
</Select>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="ospRif"
render={({ field }) => (
<FormItem>
<FormLabel>RIF de la Organización</FormLabel>
<FormControl>
<Input {...field} placeholder="J-12345678-9" />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="ospName"
render={({ field }) => (
<FormItem>
<FormLabel>Nombre de la Organización</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
{/* <FormField
control={form.control}
name="productiveActivity"
render={({ field }) => (
<FormItem>
<FormLabel>Actividad Productiva</FormLabel>
<Select
onValueChange={field.onChange}
defaultValue={field.value}
>
<FormControl>
<SelectTrigger className="w-full">
<SelectValue placeholder="Seleccione actividad" />
</SelectTrigger>
</FormControl>
<SelectContent>
{PRODUCTIVE_ACTIVITIES.map((activity) => (
<SelectItem key={activity} value={activity}>
{activity}
</SelectItem>
))}
</SelectContent>
</Select>
<FormMessage />
</FormItem>
)}
/> */}
<FormField
control={form.control}
name="companyConstitutionYear"
render={({ field }) => (
<FormItem>
<FormLabel>Año de constitución</FormLabel>
<FormControl>
<Input type="number" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="currentStatus"
render={({ field }) => (
<FormItem>
<FormLabel>Estatus</FormLabel>
<Select
onValueChange={field.onChange}
defaultValue={field.value}
>
<FormControl>
<SelectTrigger>
<SelectValue placeholder="Seleccione estatus" />
</SelectTrigger>
</FormControl>
<SelectContent>
{STATUS_OPTIONS.map((status) => (
<SelectItem key={status} value={status}>
{status}
</SelectItem>
))}
</SelectContent>
</Select>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="paralysisReason"
render={({ field }) => (
<FormItem className="col-span-2">
<FormLabel>Razones de paralización (si aplica)</FormLabel>
<FormControl>
<Textarea {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<hr className="col-span-2" />
{/* Tipo de equipamiento */}
<h3 className="text-lg font-semibold col-span-2">Tipo de equipamiento:</h3>
<FormField
control={form.control}
name="typesOfEquipment"
render={({ field }) => (
<FormItem>
<FormLabel>Maquinarias</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="equipmentCount"
render={({ field }) => (
<FormItem>
<FormLabel>Cantidad</FormLabel>
<FormControl>
<Input type="number" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="equipmentDescription"
render={({ field }) => (
<FormItem className="col-span-2">
<FormLabel>Descripción</FormLabel>
<FormControl>
<Textarea {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<hr className="col-span-2" />
{/* Datos de Producción de la Organización Socio Productivo */}
<h3 className="text-lg font-semibold col-span-2">Datos de Producción de la Organización Socio Productivo:</h3>
<FormField
control={form.control}
name="rawMaterial"
render={({ field }) => (
<FormItem>
<FormLabel>Materia prima requerida (mensual)</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="materialType"
render={({ field }) => (
<FormItem>
<FormLabel>Tipo de Insumo/Rubro</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="rawMaterialCount"
render={({ field }) => (
<FormItem>
<FormLabel>Cantidad</FormLabel>
<FormControl>
<Input type="number" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<hr className="col-span-2" />
{/* Productos Terminados */}
<h3 className="text-lg font-semibold col-span-2">Productos Terminados</h3>
<FormField
control={form.control}
name="productDescription"
render={({ field }) => (
<FormItem className="col-span-2">
<FormLabel>Descripción del producto</FormLabel>
<FormControl>
<Textarea {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="productCountDaily"
render={({ field }) => (
<FormItem>
<FormLabel>Diario</FormLabel>
<FormControl>
<Input type="number" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="productCountWeekly"
render={({ field }) => (
<FormItem>
<FormLabel>Semanal</FormLabel>
<FormControl>
<Input type="number" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="productCountMonthly"
render={({ field }) => (
<FormItem>
<FormLabel>Mensual</FormLabel>
<FormControl>
<Input type="number" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<hr className="col-span-2" />
{/* Distribución Interna */}
<h3 className="text-lg font-semibold col-span-2">Distribución Interna</h3>
<FormField
control={form.control}
name="state"
render={({ field }) => (
<FormItem>
<FormLabel>Estado</FormLabel>
<SelectSearchable
options={stateOptions.map((item) => ({
value: item.id.toString(),
label: item.name,
}))}
onValueChange={(value) => {
field.onChange(Number(value));
setState(Number(value));
setDisabledMunicipality(false);
setDisabledParish(true);
}}
placeholder="Selecciona un estado"
defaultValue={field.value?.toString()}
/>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="municipality"
render={({ field }) => (
<FormItem>
<FormLabel>Municipio</FormLabel>
<SelectSearchable
options={municipalityOptions.map((item) => ({
value: item.id.toString(),
label: item.name,
}))}
onValueChange={(value) => {
field.onChange(Number(value));
setMunicipality(Number(value));
setDisabledParish(false);
}}
placeholder="Selecciona un municipio"
disabled={disabledMunicipality}
defaultValue={field.value?.toString()}
/>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="parish"
render={({ field }) => (
<FormItem>
<FormLabel>Parroquia</FormLabel>
<SelectSearchable
options={parishOptions.map((item) => ({
value: item.id.toString(),
label: item.name,
}))}
onValueChange={(value) => field.onChange(Number(value))}
placeholder="Selecciona una parroquia"
disabled={disabledParish}
defaultValue={field.value?.toString()}
/>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="internalCount"
render={({ field }) => (
<FormItem>
<FormLabel>Cantidad</FormLabel>
<FormControl>
<Input type="number" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="prodDescriptionInternal"
render={({ field }) => (
<FormItem className="col-span-2">
<FormLabel>Breve descripción</FormLabel>
<FormControl>
<Textarea {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<hr className='col-span-2' />
{/* Distribución Externa */}
<h3 className="text-lg font-semibold col-span-2">Distribución Externa (Exportación)</h3>
<FormField
control={form.control}
name="country"
render={({ field }) => (
<FormItem>
<FormLabel>País</FormLabel>
<Select
onValueChange={field.onChange}
defaultValue={field.value}
>
<FormControl>
<SelectTrigger className="w-full">
<SelectValue placeholder="Seleccione tipo" />
</SelectTrigger>
</FormControl>
<SelectContent>
{COUNTRY_OPTIONS.map((type) => (
<SelectItem key={type} value={type}>
{type}
</SelectItem>
))}
</SelectContent>
</Select>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="city"
render={({ field }) => (
<FormItem>
<FormLabel>Ciudad</FormLabel>
<FormControl>
<Input type="number" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="externalCount"
render={({ field }) => (
<FormItem>
<FormLabel>Cantidad (Kg, TON, UNID. LT)</FormLabel>
<FormControl>
<Input type="number" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="prodDescriptionExternal"
render={({ field }) => (
<FormItem>
<FormLabel>Breve descripción</FormLabel>
<FormControl>
<Textarea {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<hr className='col-span-2' />
<h3 className="text-lg font-semibold col-span-2">Cantidad Mano de Obra</h3>
<FormField
control={form.control}
name="menCount"
render={({ field }) => (
<FormItem>
<FormLabel>Hombres</FormLabel>
<FormControl>
<Input type="number" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="womenCount"
render={({ field }) => (
<FormItem>
<FormLabel>Mujeres</FormLabel>
<FormControl>
<Input type="number" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
{/* <FormField
control={form.control}
name="productCount"
render={({ field }) => (
<FormItem>
<FormLabel>Cantidad de Productos</FormLabel>
<FormControl>
<Input type="number" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/> */}
{/* <FormField
control={form.control}
name="productDescription"
render={({ field }) => (
<FormItem className="col-span-2">
<FormLabel>
Breve descripción del producto o servicio
</FormLabel>
<FormControl>
<Textarea {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/> */}
{/* <FormField
control={form.control}
name="installedCapacity"
render={({ field }) => (
<FormItem>
<FormLabel>Capacidad Instalada</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/> */}
{/* <FormField
control={form.control}
name="operationalCapacity"
render={({ field }) => (
<FormItem>
<FormLabel>Capacidad Operativa</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/> */}
{/* <FormField
control={form.control}
name="financialRequirementDescription"
render={({ field }) => (
<FormItem className="col-span-2">
<FormLabel>
Descripción del Requerimiento Financiero
</FormLabel>
<FormControl>
<Textarea {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/> */}
</CardContent>
</Card>
{/* 3. Detalles de la ubicación */}
<Card>
<CardHeader>
<CardTitle>3. Detalles de la ubicación</CardTitle>
</CardHeader>
<CardContent className="grid grid-cols-1 md:grid-cols-2 gap-4">
<FormField
control={form.control}
name="ospAddress"
render={({ field }) => (
<FormItem className="col-span-2">
<FormLabel>Dirección de la Organización Socio Productivo</FormLabel>
<FormControl>
<Textarea {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="ospGoogleMapsLink"
render={({ field }) => (
<FormItem className="col-span-2">
<FormLabel>Dirección Link Google Maps</FormLabel>
<FormControl>
<Input {...field} placeholder="https://maps.google.com/..." />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<div className="col-span-2">
<h4 className="font-semibold mb-2">Datos de la Comuna</h4>
</div>
<FormField
control={form.control}
name="communeName"
render={({ field }) => (
<FormItem>
<FormLabel>Nombre de la Comuna</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="siturCodeCommune"
render={({ field }) => (
<FormItem>
<FormLabel>Código SITUR de la Comuna</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="communeRif"
render={({ field }) => (
<FormItem>
<FormLabel>Rif de la Comuna</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="communeSpokespersonName"
render={({ field }) => (
<FormItem>
<FormLabel>Nombre del Vocero o Vocera</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="communeSpokespersonCedula"
render={({ field }) => (
<FormItem>
<FormLabel>Cédula de Identidad del Vocero</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="communeSpokespersonRif"
render={({ field }) => (
<FormItem>
<FormLabel>RIF del Vocero</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="communeSpokespersonPhone"
render={({ field }) => (
<FormItem>
<FormLabel>Número de Teléfono del Vocero</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="communeEmail"
render={({ field }) => (
<FormItem>
<FormLabel>Correo Electrónico de la Comuna</FormLabel>
<FormControl>
<Input type="email" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<div className="col-span-2">
<h4 className="font-semibold mb-2">Datos del Consejo Comunal</h4>
</div>
<FormField
control={form.control}
name="communalCouncil"
render={({ field }) => (
<FormItem>
<FormLabel>Nombre del Consejo Comunal</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="siturCodeCommunalCouncil"
render={({ field }) => (
<FormItem>
<FormLabel>Código SITUR del Consejo Comunal</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="communalCouncilRif"
render={({ field }) => (
<FormItem>
<FormLabel>Rif del Consejo Comunal</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="communalCouncilSpokespersonName"
render={({ field }) => (
<FormItem>
<FormLabel>Nombre del Vocero o Vocera</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="communalCouncilSpokespersonCedula"
render={({ field }) => (
<FormItem>
<FormLabel>Cédula de Identidad del Vocero</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="communalCouncilSpokespersonRif"
render={({ field }) => (
<FormItem>
<FormLabel>RIF del Vocero</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="communalCouncilSpokespersonPhone"
render={({ field }) => (
<FormItem>
<FormLabel>Número de Teléfono del Vocero</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="communalCouncilEmail"
render={({ field }) => (
<FormItem>
<FormLabel>Correo Electrónico del Consejo Comunal</FormLabel>
<FormControl>
<Input type="email" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</CardContent>
</Card>
{/* 4. Datos del Responsable OSP */}
<Card>
<CardHeader>
<CardTitle>4. Datos del Responsable OSP</CardTitle>
</CardHeader>
<CardContent className="grid grid-cols-1 md:grid-cols-2 gap-4">
<FormField
control={form.control}
name="ospResponsibleCedula"
render={({ field }) => (
<FormItem>
<FormLabel>Cédula</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="ospResponsibleFullname"
render={({ field }) => (
<FormItem>
<FormLabel>Nombre y apellido</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="ospResponsibleRif"
render={({ field }) => (
<FormItem>
<FormLabel>RIF</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="civilState"
render={({ field }) => (
<FormItem>
<FormLabel>Estado Civil</FormLabel>
<Select
onValueChange={field.onChange}
defaultValue={field.value}
>
<FormControl>
<SelectTrigger className="w-full">
<SelectValue placeholder="Seleccione estado civil" />
</SelectTrigger>
</FormControl>
<SelectContent>
{CIVIL_STATE_OPTIONS.map((state) => (
<SelectItem key={state} value={state}>
{state}
</SelectItem>
))}
</SelectContent>
</Select>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="ospResponsiblePhone"
render={({ field }) => (
<FormItem>
<FormLabel>Teléfono</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="ospResponsibleEmail"
render={({ field }) => (
<FormItem>
<FormLabel>Correo Electrónico</FormLabel>
<FormControl>
<Input type="email" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="familyBurden"
render={({ field }) => (
<FormItem>
<FormLabel>Carga Familiar</FormLabel>
<FormControl>
<Input type="number" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="numberOfChildren"
render={({ field }) => (
<FormItem>
<FormLabel>Número de Hijos</FormLabel>
<FormControl>
<Input type="number" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</CardContent>
</Card>
{/* 5. Datos adicionales */}
<Card>
<CardHeader>
<CardTitle>5. Datos adicionales</CardTitle>
</CardHeader>
<CardContent>
<FormField
control={form.control}
name="generalObservations"
render={({ field }) => (
<FormItem>
<FormLabel>Observaciones Generales</FormLabel>
<FormControl>
<Textarea {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</CardContent>
</Card>
{/* 6. Registro fotográfico */}
<Card>
<CardHeader>
<CardTitle>6. Registro fotográfico</CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-4">
<div className="space-y-2">
{['photo1', 'photo2', 'photo3'].some((field) =>
form.watch(field as any),
) && <FormLabel>Imágenes actuales</FormLabel>}
<div className="grid grid-cols-3 gap-2">
{(['photo1', 'photo2', 'photo3'] as const).map(
(field, idx) => {
const photoUrl = form.watch(field);
if (!photoUrl) return null;
return (
<div
key={field}
className="relative aspect-square rounded-md overflow-hidden bg-muted group"
>
<img
src={`${process.env.NEXT_PUBLIC_API_URL}${photoUrl}`}
alt={`Existing ${idx + 1}`}
className="object-cover w-full h-full"
/>
<button
type="button"
onClick={() => {
form.setValue(field, '');
}}
className="absolute top-1 right-1 bg-destructive text-destructive-foreground rounded-full p-1 opacity-0 group-hover:opacity-100 transition-opacity"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<line x1="18" y1="6" x2="6" y2="18"></line>
<line x1="6" y1="6" x2="18" y2="18"></line>
</svg>
</button>
</div>
);
},
)}
</div>
</div>
<div className="flex flex-col gap-2">
<FormLabel>
Subir nuevas imágenes (máximo 3 en total)
</FormLabel>
<Input
type="file"
multiple
accept="image/*"
onChange={(e) => {
const files = Array.from(e.target.files || []);
const existingCount = [
form.watch('photo1'),
form.watch('photo2'),
form.watch('photo3'),
].filter(Boolean).length;
if (files.length + existingCount > 3) {
alert('Máximo 3 imágenes en total');
e.target.value = '';
return;
}
setSelectedFiles(files);
}}
/>
</div>
{selectedFiles.length > 0 && (
<div className="space-y-2">
<FormLabel>Nuevas imágenes seleccionadas</FormLabel>
<div className="grid grid-cols-3 gap-2 mt-2">
{selectedFiles.map((file, idx) => (
<div
key={idx}
className="relative aspect-square rounded-md overflow-hidden bg-muted"
>
<img
src={URL.createObjectURL(file)}
alt={`Preview ${idx + 1}`}
className="object-cover w-full h-full"
/>
</div>
))}
</div>
</div>
)}
{selectedFiles.length === 0 &&
!['photo1', 'photo2', 'photo3'].some((f) =>
form.watch(f as any),
) && (
<p className="text-sm text-muted-foreground">
Debe subir al menos una imagen o mantener una existente.
</p>
)}
</div>
</CardContent>
</Card>
<div className="flex justify-end gap-4 mt-8">
<Button
variant="outline"
type="button"
onClick={onCancel}
className="w-32"
>
Cancelar
</Button>
<Button
type="submit"
disabled={
isSaving ||
(selectedFiles.length === 0 &&
!['photo1', 'photo2', 'photo3'].some((f) =>
form.watch(f as any),
))
}
className="w-32"
>
{isSaving
? 'Guardando...'
: defaultValues?.id
? 'Actualizar'
: 'Guardar'}
</Button>
</div>
</form>
</Form>
</>
);
}