formulario de capacitacion

This commit is contained in:
2025-12-01 18:23:18 -04:00
parent 6f8a55b8fd
commit efa1726223
25 changed files with 3165 additions and 181 deletions

View File

@@ -1,19 +0,0 @@
import PageContainer from '@/components/layout/page-container';
const Page = () => {
return (
<PageContainer>
<div className="flex flex-1 flex-col gap-4 p-4 pt-0">
En mantenimiento
</div>
</PageContainer>
// <div className="flex min-h-svh flex-col items-center justify-center gap-6 bg-muted p-6 md:p-10">
// <div className="flex w-full max-w-sm flex-col gap-6">
// </div>
// </div>
);
};
export default Page;

View File

@@ -0,0 +1,15 @@
'use client';
import PageContainer from '@/components/layout/page-container';
import { CreateTrainingForm } from '@/feactures/training/components/form';
const Page = () => {
return (
<div className="flex flex-1 flex-col gap-4 p-4 pt-0">
<CreateTrainingForm />
</div>
);
};
export default Page;

View File

@@ -1,7 +1,7 @@
'use client';
import { NavMain as GeneralMain, NavMain as AdministrationMain, NavMain as StatisticsMain, } from '@/components/nav-main';
import { GeneralItems, AdministrationItems, StatisticsItems } from '@/constants/data';
import { NavMain as GeneralMain, NavMain as AdministrationMain, NavMain as StatisticsMain, } from '@/components/nav-main';
import { GeneralItems, AdministrationItems, StatisticsItems } from '@/constants/routes';
import {
Sidebar,
SidebarContent,
@@ -24,9 +24,9 @@ export const company = {
export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
const { data: session } = useSession();
const userRole = session?.user.role[0]?.rol ? session.user.role[0].rol :'';
const userRole = session?.user.role[0]?.rol ? session.user.role[0].rol : '';
// console.log(AdministrationItems[0]?.role);
return (
<Sidebar collapsible="icon" {...props}>
<SidebarHeader>
@@ -42,14 +42,14 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
</div>
</SidebarHeader>
<SidebarContent>
<GeneralMain titleGroup={'General'} items={GeneralItems} role={userRole}/>
<GeneralMain titleGroup={'General'} items={GeneralItems} role={userRole} />
{StatisticsItems[0]?.role?.includes(userRole) &&
<StatisticsMain titleGroup={'Estadisticas'} items={StatisticsItems} role={userRole}/>
<StatisticsMain titleGroup={'Estadisticas'} items={StatisticsItems} role={userRole} />
}
{AdministrationItems[0]?.role?.includes(userRole) &&
<AdministrationMain titleGroup={'Administracion'} items={AdministrationItems} role={userRole}/>
<AdministrationMain titleGroup={'Administracion'} items={AdministrationItems} role={userRole} />
}
{/* <NavProjects projects={data.projects} /> */}
</SidebarContent>

View File

@@ -18,6 +18,14 @@ export const GeneralItems: NavItem[] = [
isActive: false,
items: [], // No child items
},
{
title: 'Formulario',
url: '/dashboard/formulario/',
icon: 'notepadText',
shortcut: ['p', 'p'],
isActive: false,
items: [], // No child items
},
];
@@ -27,7 +35,7 @@ export const AdministrationItems: NavItem[] = [
url: '#', // Placeholder as there is no direct link for the parent
icon: 'settings2',
isActive: true,
role:['admin','superadmin','manager','user'], // sumatoria de los roles que si tienen acceso
role: ['admin', 'superadmin', 'manager', 'user'], // sumatoria de los roles que si tienen acceso
items: [
{
@@ -35,14 +43,14 @@ export const AdministrationItems: NavItem[] = [
url: '/dashboard/administracion/usuario',
icon: 'userPen',
shortcut: ['m', 'm'],
role:['admin','superadmin'],
role: ['admin', 'superadmin'],
},
{
title: 'Encuestas',
shortcut: ['l', 'l'],
url: '/dashboard/administracion/encuestas',
icon: 'login',
role:['admin','superadmin','manager','user'],
role: ['admin', 'superadmin', 'manager', 'user'],
},
],
},
@@ -54,7 +62,7 @@ export const StatisticsItems: NavItem[] = [
url: '#', // Placeholder as there is no direct link for the parent
icon: 'chartColumn',
isActive: true,
role:['admin','superadmin','autoridad'],
role: ['admin', 'superadmin', 'autoridad'],
items: [
// {
@@ -69,7 +77,7 @@ export const StatisticsItems: NavItem[] = [
shortcut: ['l', 'l'],
url: '/dashboard/estadisticas/encuestas',
icon: 'notepadText',
role:['admin','superadmin','autoridad'],
role: ['admin', 'superadmin', 'autoridad'],
},
],
},

View File

@@ -0,0 +1,148 @@
'use server';
import { safeFetchApi } from '@/lib/fetch.api';
import {
surveysApiResponseSchema,
CreateUser,
UsersMutate,
UpdateUser
} from '../schemas/users';
import { auth } from '@/lib/auth';
export const getProfileAction = async () => {
const session = await auth()
const id = session?.user?.id
const [error, response] = await safeFetchApi(
UsersMutate,
`/users/${id}`,
'GET'
);
if (error) throw new Error(error.message);
return response;
};
export const updateProfileAction = async (payload: UpdateUser) => {
const { id, ...payloadWithoutId } = payload;
const [error, data] = await safeFetchApi(
UsersMutate,
`/users/profile/${id}`,
'PATCH',
payloadWithoutId,
);
console.log(payload);
if (error) {
if (error.message === 'Email already exists') {
throw new Error('Ese correo ya está en uso');
}
// console.error('Error:', error);
throw new Error('Error al crear el usuario');
}
return data;
};
export const getUsersAction = async (params: {
page?: number;
limit?: number;
search?: string;
sortBy?: string;
sortOrder?: 'asc' | 'desc';
}) => {
const searchParams = new URLSearchParams({
page: (params.page || 1).toString(),
limit: (params.limit || 10).toString(),
...(params.search && { search: params.search }),
...(params.sortBy && { sortBy: params.sortBy }),
...(params.sortOrder && { sortOrder: params.sortOrder }),
});
const [error, response] = await safeFetchApi(
surveysApiResponseSchema,
`/users?${searchParams}`,
'GET',
);
if (error) throw new Error(error.message);
// const transformedData = response?.data ? transformSurvey(response?.data) : undefined;
return {
data: response?.data || [],
meta: response?.meta || {
page: 1,
limit: 10,
totalCount: 0,
totalPages: 1,
hasNextPage: false,
hasPreviousPage: false,
nextPage: null,
previousPage: null,
},
};
}
export const createUserAction = async (payload: CreateUser) => {
const { id, confirmPassword, ...payloadWithoutId } = payload;
const [error, data] = await safeFetchApi(
UsersMutate,
'/users',
'POST',
payloadWithoutId,
);
if (error) {
if (error.message === 'Username already exists') {
throw new Error('Ese usuario ya existe');
}
if (error.message === 'Email already exists') {
throw new Error('Ese correo ya está en uso');
}
// console.error('Error:', error);
throw new Error('Error al crear el usuario');
}
return payloadWithoutId;
};
export const updateUserAction = async (payload: UpdateUser) => {
try {
const { id, ...payloadWithoutId } = payload;
const [error, data] = await safeFetchApi(
UsersMutate,
`/users/${id}`,
'PATCH',
payloadWithoutId,
);
// console.log(data);
if (error) {
console.error(error);
throw new Error(error?.message || 'Error al actualizar el usuario');
}
return data;
} catch (error) {
console.error(error);
}
}
export const deleteUserAction = async (id: Number) => {
const [error] = await safeFetchApi(
UsersMutate,
`/users/${id}`,
'DELETE'
)
console.log(error);
// if (error) throw new Error(error.message || 'Error al eliminar el usuario')
return true;
}

View File

@@ -0,0 +1,94 @@
'use server';
import { safeFetchApi } from '@/lib/fetch.api';
import {
TrainingSchema,
TrainingMutate,
trainingApiResponseSchema
} from '../schemas/training';
export const getTrainingAction = async (params: {
page?: number;
limit?: number;
search?: string;
sortBy?: string;
sortOrder?: 'asc' | 'desc';
}) => {
const searchParams = new URLSearchParams({
page: (params.page || 1).toString(),
limit: (params.limit || 10).toString(),
...(params.search && { search: params.search }),
...(params.sortBy && { sortBy: params.sortBy }),
...(params.sortOrder && { sortOrder: params.sortOrder }),
});
const [error, response] = await safeFetchApi(
trainingApiResponseSchema,
`/training?${searchParams}`,
'GET',
);
if (error) throw new Error(error.message);
return {
data: response?.data || [],
meta: response?.meta || {
page: 1,
limit: 10,
totalCount: 0,
totalPages: 1,
hasNextPage: false,
hasPreviousPage: false,
nextPage: null,
previousPage: null,
},
};
}
export const createTrainingAction = async (payload: TrainingSchema) => {
const { id, ...payloadWithoutId } = payload;
const [error, data] = await safeFetchApi(
TrainingMutate,
'/training',
'POST',
payloadWithoutId,
);
if (error) {
throw new Error(error.message || 'Error al crear el registro');
}
return data;
};
export const updateTrainingAction = async (payload: TrainingSchema) => {
const { id, ...payloadWithoutId } = payload;
if (!id) throw new Error('ID es requerido para actualizar');
const [error, data] = await safeFetchApi(
TrainingMutate,
`/training/${id}`,
'PATCH',
payloadWithoutId,
);
if (error) {
throw new Error(error.message || 'Error al actualizar el registro');
}
return data;
};
export const deleteTrainingAction = async (id: number) => {
const [error] = await safeFetchApi(
TrainingMutate,
`/training/${id}`,
'DELETE'
)
if (error) throw new Error(error.message || 'Error al eliminar el registro');
return true;
}

View File

@@ -0,0 +1,431 @@
'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 { Textarea } from '@repo/shadcn/textarea';
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@repo/shadcn/select';
import { useForm } from 'react-hook-form';
import { useCreateTraining } from "../hooks/use-training";
import { TrainingSchema, trainingSchema } from '../schemas/training';
const PRODUCTIVE_ACTIVITIES = [
'Agricola',
'Textil',
'Bloquera',
'Carpinteria',
'Unidad de suministro'
];
interface CreateTrainingFormProps {
onSuccess?: () => void;
onCancel?: () => void;
defaultValues?: Partial<TrainingSchema>;
}
export function CreateTrainingForm({
onSuccess,
onCancel,
defaultValues,
}: CreateTrainingFormProps) {
const {
mutate: saveTraining,
isPending: isSaving,
} = useCreateTraining();
const form = useForm<TrainingSchema>({
resolver: zodResolver(trainingSchema),
defaultValues: {
firstname: defaultValues?.firstname || '',
lastname: defaultValues?.lastname || '',
visitDate: defaultValues?.visitDate || new Date().toISOString().split('T')[0],
productiveActivity: defaultValues?.productiveActivity || '',
financialRequirementDescription: defaultValues?.financialRequirementDescription || '',
siturCodeCommune: defaultValues?.siturCodeCommune || '',
communalCouncil: defaultValues?.communalCouncil || '',
siturCodeCommunalCouncil: defaultValues?.siturCodeCommunalCouncil || '',
ospName: defaultValues?.ospName || '',
ospAddress: defaultValues?.ospAddress || '',
ospRif: defaultValues?.ospRif || '',
ospType: defaultValues?.ospType || '',
currentStatus: defaultValues?.currentStatus || '',
companyConstitutionYear: defaultValues?.companyConstitutionYear || new Date().getFullYear(),
producerCount: defaultValues?.producerCount || 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 || '',
photo1: defaultValues?.photo1 || '',
photo2: defaultValues?.photo2 || '',
photo3: defaultValues?.photo3 || '',
paralysisReason: defaultValues?.paralysisReason || '',
state: defaultValues?.state || '',
municipality: defaultValues?.municipality || '',
parish: defaultValues?.parish || '',
},
mode: 'onChange',
});
const onSubmit = async (formData: TrainingSchema) => {
saveTraining(formData, {
onSuccess: () => {
form.reset();
onSuccess?.();
},
onError: (e) => {
console.error(e);
form.setError('root', {
type: 'manual',
message: 'Error al guardar el registro',
});
},
});
};
return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
{form.formState.errors.root && (
<div className="text-destructive text-sm">
{form.formState.errors.root.message}
</div>
)}
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
{/* Datos Personales */}
<div className="col-span-2">
<h3 className="text-lg font-medium mb-2">Datos Básicos</h3>
</div>
<FormField control={form.control} name="firstname" render={({ field }) => (
<FormItem>
<FormLabel>Nombre</FormLabel>
<FormControl><Input {...field} /></FormControl>
<FormMessage />
</FormItem>
)} />
<FormField control={form.control} name="lastname" render={({ field }) => (
<FormItem>
<FormLabel>Apellido</FormLabel>
<FormControl><Input {...field} /></FormControl>
<FormMessage />
</FormItem>
)} />
<FormField control={form.control} name="visitDate" render={({ field }) => (
<FormItem>
<FormLabel>Fecha de la visita</FormLabel>
<FormControl><Input type="date" {...field} value={field.value ? new Date(field.value).toISOString().split('T')[0] : ''} /></FormControl>
<FormMessage />
</FormItem>
)} />
{/* Ubicación */}
<div className="col-span-2">
<h3 className="text-lg font-medium mb-2 mt-4">Ubicación</h3>
</div>
<FormField control={form.control} name="state" render={({ field }) => (
<FormItem>
<FormLabel>Estado</FormLabel>
<FormControl><Input {...field} value={field.value || ''} /></FormControl>
<FormMessage />
</FormItem>
)} />
<FormField control={form.control} name="municipality" render={({ field }) => (
<FormItem>
<FormLabel>Municipio</FormLabel>
<FormControl><Input {...field} value={field.value || ''} /></FormControl>
<FormMessage />
</FormItem>
)} />
<FormField control={form.control} name="parish" render={({ field }) => (
<FormItem>
<FormLabel>Parroquia</FormLabel>
<FormControl><Input {...field} value={field.value || ''} /></FormControl>
<FormMessage />
</FormItem>
)} />
<FormField control={form.control} name="siturCodeCommune" render={({ field }) => (
<FormItem>
<FormLabel>Código SITUR Comuna</FormLabel>
<FormControl><Input {...field} /></FormControl>
<FormMessage />
</FormItem>
)} />
<FormField control={form.control} name="communalCouncil" render={({ field }) => (
<FormItem>
<FormLabel>Consejo Comunal</FormLabel>
<FormControl><Input {...field} /></FormControl>
<FormMessage />
</FormItem>
)} />
<FormField control={form.control} name="siturCodeCommunalCouncil" render={({ field }) => (
<FormItem>
<FormLabel>Código SITUR Consejo Comunal</FormLabel>
<FormControl><Input {...field} /></FormControl>
<FormMessage />
</FormItem>
)} />
{/* Datos de la OSP */}
<div className="col-span-2">
<h3 className="text-lg font-medium mb-2 mt-4">Datos de la Organización Socioproductiva (OSP)</h3>
</div>
<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="ospAddress" render={({ field }) => (
<FormItem>
<FormLabel>Dirección</FormLabel>
<FormControl><Input {...field} /></FormControl>
<FormMessage />
</FormItem>
)} />
<FormField control={form.control} name="ospRif" render={({ field }) => (
<FormItem>
<FormLabel>RIF</FormLabel>
<FormControl><Input {...field} /></FormControl>
<FormMessage />
</FormItem>
)} />
<FormField control={form.control} name="ospType" render={({ field }) => (
<FormItem>
<FormLabel>Tipo de 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>
<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="currentStatus" render={({ field }) => (
<FormItem>
<FormLabel>Estatus Actual</FormLabel>
<FormControl><Input {...field} /></FormControl>
<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="producerCount" render={({ field }) => (
<FormItem>
<FormLabel>Cantidad de Productores</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>
)} />
<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>
)} />
{/* Responsable */}
<div className="col-span-2">
<h3 className="text-lg font-medium mb-2 mt-4">Datos del Responsable</h3>
</div>
<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="ospResponsibleCedula" render={({ field }) => (
<FormItem>
<FormLabel>Cédula (sin puntos)</FormLabel>
<FormControl><Input {...field} /></FormControl>
<FormMessage />
</FormItem>
)} />
<FormField control={form.control} name="ospResponsibleRif" render={({ field }) => (
<FormItem>
<FormLabel>RIF (sin puntos)</FormLabel>
<FormControl><Input {...field} /></FormControl>
<FormMessage />
</FormItem>
)} />
<FormField control={form.control} name="ospResponsiblePhone" render={({ field }) => (
<FormItem>
<FormLabel>Teléfonos (2 números)</FormLabel>
<FormControl><Input {...field} /></FormControl>
<FormMessage />
</FormItem>
)} />
<FormField control={form.control} name="civilState" render={({ field }) => (
<FormItem>
<FormLabel>Estado Civil</FormLabel>
<FormControl><Input {...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>
)} />
<FormField control={form.control} name="generalObservations" render={({ field }) => (
<FormItem className="col-span-2">
<FormLabel>Observaciones Generales</FormLabel>
<FormControl><Textarea {...field} /></FormControl>
<FormMessage />
</FormItem>
)} />
{/* Fotos */}
<div className="col-span-2">
<h3 className="text-lg font-medium mb-2 mt-4">Registro Fotográfico (URLs)</h3>
</div>
<FormField control={form.control} name="photo1" render={({ field }) => (
<FormItem>
<FormLabel>Foto 1</FormLabel>
<FormControl><Input {...field} placeholder="URL de la imagen" /></FormControl>
<FormMessage />
</FormItem>
)} />
<FormField control={form.control} name="photo2" render={({ field }) => (
<FormItem>
<FormLabel>Foto 2</FormLabel>
<FormControl><Input {...field} placeholder="URL de la imagen" /></FormControl>
<FormMessage />
</FormItem>
)} />
<FormField control={form.control} name="photo3" render={({ field }) => (
<FormItem>
<FormLabel>Foto 3</FormLabel>
<FormControl><Input {...field} placeholder="URL de la imagen" /></FormControl>
<FormMessage />
</FormItem>
)} />
</div>
<div className="flex justify-end gap-4 mt-6">
<Button variant="outline" type="button" onClick={onCancel}>
Cancelar
</Button>
<Button type="submit" disabled={isSaving}>
{isSaving ? 'Guardando...' : 'Guardar'}
</Button>
</div>
</form>
</Form>
);
}

View File

@@ -0,0 +1,45 @@
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { CreateUser, UpdateUser } from "../schemas/users";
import { updateUserAction, createUserAction, deleteUserAction, updateProfileAction } from "../actions/actions";
// Create mutation
export function useCreateUser() {
const queryClient = useQueryClient();
const mutation = useMutation({
mutationFn: (data: CreateUser) => createUserAction(data),
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['users'] }),
// onError: (e) => console.error('Error:', e),
})
return mutation
}
// Update mutation
export function useUpdateUser() {
const queryClient = useQueryClient();
const mutation = useMutation({
mutationFn: (data: UpdateUser) => updateUserAction(data),
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['users'] }),
onError: (e) => console.error('Error:', e)
})
return mutation;
}
export function useUpdateProfile() {
const queryClient = useQueryClient();
const mutation = useMutation({
mutationFn: (data: UpdateUser) => updateProfileAction(data),
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['users'] }),
// onError: (e) => console.error('Error:', e)
})
return mutation;
}
// Delete mutation
export function useDeleteUser() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (id: number) => deleteUserAction(id),
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['users'] }),
onError: (e) => console.error('Error:', e)
})
}

View File

@@ -0,0 +1,29 @@
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { TrainingSchema } from "../schemas/training";
import { createTrainingAction, updateTrainingAction, deleteTrainingAction } from "../actions/training-actions";
export function useCreateTraining() {
const queryClient = useQueryClient();
const mutation = useMutation({
mutationFn: (data: TrainingSchema) => createTrainingAction(data),
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['training'] }),
})
return mutation
}
export function useUpdateTraining() {
const queryClient = useQueryClient();
const mutation = useMutation({
mutationFn: (data: TrainingSchema) => updateTrainingAction(data),
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['training'] }),
})
return mutation;
}
export function useDeleteTraining() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (id: number) => deleteTrainingAction(id),
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['training'] }),
})
}

View File

@@ -0,0 +1,60 @@
import { z } from 'zod';
export const trainingSchema = z.object({
id: z.number().optional(),
firstname: z.string().min(1, { message: "Nombre es requerido" }),
lastname: z.string().min(1, { message: "Apellido es requerido" }),
visitDate: z.string().or(z.date()).transform((val) => new Date(val).toISOString()),
productiveActivity: z.string().min(1, { message: "Actividad productiva es requerida" }),
financialRequirementDescription: z.string().min(1, { message: "Descripción es requerida" }),
siturCodeCommune: z.string().min(1, { message: "Código SITUR Comuna es requerido" }),
communalCouncil: z.string().min(1, { message: "Consejo Comunal es requerido" }),
siturCodeCommunalCouncil: z.string().min(1, { message: "Código SITUR Consejo Comunal es requerido" }),
ospName: z.string().min(1, { message: "Nombre de la OSP es requerido" }),
ospAddress: z.string().min(1, { message: "Dirección de la OSP es requerida" }),
ospRif: z.string().min(1, { message: "RIF de la OSP es requerido" }),
ospType: z.string().min(1, { message: "Tipo de OSP es requerido" }),
currentStatus: z.string().min(1, { message: "Estatus actual es requerido" }),
companyConstitutionYear: z.coerce.number().min(1900, { message: "Año inválido" }),
producerCount: z.coerce.number().min(1, { message: "Cantidad de productores requerida" }),
productDescription: z.string().min(1, { message: "Descripción del producto es requerida" }),
installedCapacity: z.string().min(1, { message: "Capacidad instalada es requerida" }),
operationalCapacity: z.string().min(1, { message: "Capacidad operativa es requerida" }),
ospResponsibleFullname: z.string().min(1, { message: "Nombre del responsable es requerido" }),
ospResponsibleCedula: z.string().min(1, { message: "Cédula del responsable es requerida" }),
ospResponsibleRif: z.string().min(1, { message: "RIF del responsable es requerido" }),
ospResponsiblePhone: z.string().min(1, { message: "Teléfono del responsable es requerido" }),
civilState: z.string().min(1, { message: "Estado civil es requerido" }),
familyBurden: z.coerce.number().min(0, { message: "Carga familiar requerida" }),
numberOfChildren: z.coerce.number().min(0, { message: "Número de hijos requerido" }),
generalObservations: z.string().optional().default(''),
photo1: z.string().optional().default(''),
photo2: z.string().optional().default(''),
photo3: z.string().optional().default(''),
paralysisReason: z.string().optional().default(''),
state: z.string().optional().nullable(),
municipality: z.string().optional().nullable(),
parish: z.string().optional().nullable(),
});
export type TrainingSchema = z.infer<typeof trainingSchema>;
export const trainingApiResponseSchema = z.object({
message: z.string(),
data: z.array(trainingSchema),
meta: z.object({
page: z.number(),
limit: z.number(),
totalCount: z.number(),
totalPages: z.number(),
hasNextPage: z.boolean(),
hasPreviousPage: z.boolean(),
nextPage: z.number().nullable(),
previousPage: z.number().nullable(),
}),
});
export const TrainingMutate = z.object({
message: z.string(),
data: trainingSchema,
});

View File

@@ -0,0 +1,67 @@
import { z } from 'zod';
export type SurveyTable = z.infer<typeof user>;
export type CreateUser = z.infer<typeof createUser>;
export type UpdateUser = z.infer<typeof updateUser>;
export const user = z.object({
id: z.number().optional(),
username: z.string(),
email: z.string(),
fullname: z.string(),
phone: z.string().nullable(),
isActive: z.boolean(),
role: z.string(),
state: z.string().optional().nullable(),
municipality: z.string().optional().nullable(),
parish: z.string().optional().nullable(),
});
export const createUser = z.object({
id: z.number().optional(),
username: z.string().min(5, { message: "Debe de tener 5 o más caracteres" }),
password: z.string().min(8, { message: "Debe de tener 8 o más caracteres" }),
email: z.string().email({ message: "Correo no válido" }),
fullname: z.string(),
phone: z.string(),
confirmPassword: z.string(),
role: z.number()
})
.refine((data) => data.password === data.confirmPassword, {
message: 'La contraseña no coincide',
path: ['confirmPassword'],
})
export const updateUser = z.object({
id: z.number(),
username: z.string().min(5, { message: "Debe de tener 5 o más caracteres" }).or(z.literal('')),
password: z.string().min(6, { message: "Debe de tener 6 o más caracteres" }).or(z.literal('')),
email: z.string().email({ message: "Correo no válido" }).or(z.literal('')),
fullname: z.string().optional(),
phone: z.string().optional(),
role: z.number().optional(),
isActive: z.boolean().optional(),
state: z.number().optional().nullable(),
municipality: z.number().optional().nullable(),
parish: z.number().optional().nullable(),
})
export const surveysApiResponseSchema = z.object({
message: z.string(),
data: z.array(user),
meta: z.object({
page: z.number(),
limit: z.number(),
totalCount: z.number(),
totalPages: z.number(),
hasNextPage: z.boolean(),
hasPreviousPage: z.boolean(),
nextPage: z.number().nullable(),
previousPage: z.number().nullable(),
}),
})
export const UsersMutate = z.object({
message: z.string(),
data: user,
})