1579 lines
55 KiB
TypeScript
1579 lines
55 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';
|
|
|
|
// const PRODUCTIVE_ACTIVITIES = [
|
|
// 'Agricola',
|
|
// 'Textil',
|
|
// 'Bloquera',
|
|
// 'Carpinteria',
|
|
// 'Unidad de suministro',
|
|
// ];
|
|
|
|
const ECO_SECTORS = ['Primario', 'Secundario', 'Terciario'];
|
|
|
|
// const ECO_SECTORS_PRIMARIO = ['Agropecuario', 'Pesca', 'Minería', 'Forestal'];
|
|
// const ECO_SECTORS_SECUNDARIO = ['Manufactura', 'Construcción', 'Energía'];
|
|
|
|
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 PRODUCTIVE_SECTORS_PRIMARIO = ['Agricola'];
|
|
// const PRODUCTIVE_SECTORS_SECUNDARIO = ['Manufactura'];
|
|
// const PRODUCTIVE_SECTORS_TERCIARIO = ['Servicios', 'Comercio', 'Turismo'];
|
|
|
|
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 || '',
|
|
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
|
|
},
|
|
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 tipo" />
|
|
</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 tipo" />
|
|
</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 tipo" />
|
|
</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</FormLabel>
|
|
<Select
|
|
onValueChange={field.onChange}
|
|
defaultValue={field.value}
|
|
>
|
|
<FormControl>
|
|
<SelectTrigger className="w-full">
|
|
<SelectValue placeholder="Seleccione tipo" />
|
|
</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>
|
|
)}
|
|
/> */}
|
|
|
|
{/* Tipo de equipamiento */}
|
|
<hr className="col-span-2" />
|
|
<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" />
|
|
|
|
{/* Productos Terminados */}
|
|
<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" />
|
|
|
|
<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="productCount"
|
|
render={({ field }) => (
|
|
<FormItem>
|
|
<FormLabel>Cantidad de Productos</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="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>
|
|
)}
|
|
/>
|
|
|
|
<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>
|
|
)}
|
|
/>
|
|
</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>
|
|
</>
|
|
);
|
|
}
|