Compare commits

...

5 Commits

13 changed files with 2372 additions and 1191 deletions

View File

@@ -0,0 +1 @@
ALTER TABLE "training_surveys" ADD COLUMN "survey_status" text DEFAULT 'PUBLICADO' NOT NULL;

File diff suppressed because it is too large Load Diff

View File

@@ -190,6 +190,13 @@
"when": 1774379641691, "when": 1774379641691,
"tag": "0026_last_vampiro", "tag": "0026_last_vampiro",
"breakpoints": true "breakpoints": true
},
{
"idx": 27,
"version": "7",
"when": 1775675160189,
"tag": "0027_concerned_captain_flint",
"breakpoints": true
} }
] ]
} }

View File

@@ -158,6 +158,7 @@ export const trainingSurveys = t.pgTable(
updatedBy: t updatedBy: t
.integer('updated_by') .integer('updated_by')
.references(() => users.id, { onDelete: 'cascade' }), .references(() => users.id, { onDelete: 'cascade' }),
surveyStatus: t.text('survey_status').notNull().default('PUBLICADO'),
...timestamps, ...timestamps,
}, },
(trainingSurveys) => ({ (trainingSurveys) => ({

View File

@@ -1673,415 +1673,5 @@ export const Municipalities = [
id: 335, id: 335,
name: 'MP. VARGAS', name: 'MP. VARGAS',
stateId: 24, stateId: 24,
}, }
{
id: 336,
name: 'ALEMANIA',
stateId: 99,
},
{
id: 337,
name: 'ANGOLA',
stateId: 99,
},
{
id: 338,
name: 'ANTIGUA Y BARBUDA',
stateId: 99,
},
{
id: 339,
name: 'ARABIA SAUDITA',
stateId: 99,
},
{
id: 340,
name: 'ARGELIA',
stateId: 99,
},
{
id: 341,
name: 'ARGENTINA',
stateId: 99,
},
{
id: 342,
name: 'AUSTRALIA',
stateId: 99,
},
{
id: 343,
name: 'AUSTRIA',
stateId: 99,
},
{
id: 344,
name: 'BARBADOS',
stateId: 99,
},
{
id: 345,
name: 'BELGICA',
stateId: 99,
},
{
id: 346,
name: 'BELICE',
stateId: 99,
},
{
id: 347,
name: 'BENIN',
stateId: 99,
},
{
id: 348,
name: 'BIELORRUSIA',
stateId: 99,
},
{
id: 349,
name: 'BOLIVIA',
stateId: 99,
},
{
id: 350,
name: 'BRASIL',
stateId: 99,
},
{
id: 351,
name: 'CHILE',
stateId: 99,
},
{
id: 352,
name: 'CHINA',
stateId: 99,
},
{
id: 353,
name: 'COLOMBIA',
stateId: 99,
},
{
id: 354,
name: 'CONGO',
stateId: 99,
},
{
id: 355,
name: 'COREA',
stateId: 99,
},
{
id: 356,
name: 'COSTA RICA',
stateId: 99,
},
{
id: 357,
name: 'CUBA',
stateId: 99,
},
{
id: 358,
name: 'DOMINICA',
stateId: 99,
},
{
id: 359,
name: 'ECUADOR',
stateId: 99,
},
{
id: 360,
name: 'EGIPTO',
stateId: 99,
},
{
id: 361,
name: 'EMIRATOS ARABES UNID',
stateId: 99,
},
{
id: 362,
name: 'ESPAÑA',
stateId: 99,
},
{
id: 363,
name: 'ETIOPIA',
stateId: 99,
},
{
id: 364,
name: 'FILIPINAS',
stateId: 99,
},
{
id: 365,
name: 'FRANCIA',
stateId: 99,
},
{
id: 366,
name: 'GRAN BRETAÑA',
stateId: 99,
},
{
id: 367,
name: 'GRECIA',
stateId: 99,
},
{
id: 368,
name: 'GRENADA',
stateId: 99,
},
{
id: 369,
name: 'GUAYANA',
stateId: 99,
},
{
id: 370,
name: 'GUINEA ECUATORIAL',
stateId: 99,
},
{
id: 371,
name: 'HAITI',
stateId: 99,
},
{
id: 372,
name: 'HONDURAS',
stateId: 99,
},
{
id: 373,
name: 'HUNGRIA',
stateId: 99,
},
{
id: 374,
name: 'INDIA',
stateId: 99,
},
{
id: 375,
name: 'INDONESIA',
stateId: 99,
},
{
id: 376,
name: 'IRAK',
stateId: 99,
},
{
id: 377,
name: 'IRAN',
stateId: 99,
},
{
id: 378,
name: 'ITALIA',
stateId: 99,
},
{
id: 379,
name: 'JAMAICA',
stateId: 99,
},
{
id: 380,
name: 'JAPON',
stateId: 99,
},
{
id: 381,
name: 'JORDANIA',
stateId: 99,
},
{
id: 382,
name: 'KENIA',
stateId: 99,
},
{
id: 383,
name: 'KUWAIT',
stateId: 99,
},
{
id: 384,
name: 'LIBANO',
stateId: 99,
},
{
id: 385,
name: 'MALASIA',
stateId: 99,
},
{
id: 386,
name: 'MALI',
stateId: 99,
},
{
id: 387,
name: 'MARRUECOS',
stateId: 99,
},
{
id: 388,
name: 'MEXICO',
stateId: 99,
},
{
id: 389,
name: 'MOZAMBIQUE',
stateId: 99,
},
{
id: 390,
name: 'NAMIBIA',
stateId: 99,
},
{
id: 391,
name: 'NICARAGUA',
stateId: 99,
},
{
id: 392,
name: 'NIGERIA',
stateId: 99,
},
{
id: 393,
name: 'NORUEGA',
stateId: 99,
},
{
id: 394,
name: 'PAISES BAJOS',
stateId: 99,
},
{
id: 395,
name: 'PALESTINA',
stateId: 99,
},
{
id: 396,
name: 'PANAMA',
stateId: 99,
},
{
id: 397,
name: 'PERU',
stateId: 99,
},
{
id: 398,
name: 'POLONIA',
stateId: 99,
},
{
id: 399,
name: 'PORTUGAL',
stateId: 99,
},
{
id: 400,
name: 'QATAR',
stateId: 99,
},
{
id: 401,
name: 'REPUBLICA DOMINICANA',
stateId: 99,
},
{
id: 402,
name: 'RUMANIA',
stateId: 99,
},
{
id: 403,
name: 'RUSIA',
stateId: 99,
},
{
id: 404,
name: 'SAN KITTS Y NEVIS',
stateId: 99,
},
{
id: 405,
name: 'SANTA LUCIA',
stateId: 99,
},
{
id: 406,
name: 'SAN VICENTE Y LAS GR',
stateId: 99,
},
{
id: 407,
name: 'SENEGAL',
stateId: 99,
},
{
id: 408,
name: 'SERBIA',
stateId: 99,
},
{
id: 409,
name: 'SINGAPUR',
stateId: 99,
},
{
id: 410,
name: 'SIRIA',
stateId: 99,
},
{
id: 411,
name: 'SUDAFRICA',
stateId: 99,
},
{
id: 412,
name: 'SUIZA',
stateId: 99,
},
{
id: 413,
name: 'SURINAME',
stateId: 99,
},
{
id: 414,
name: 'TRINIDAD Y TOBAGO',
stateId: 99,
},
{
id: 415,
name: 'TURQUIA',
stateId: 99,
},
{
id: 416,
name: 'URUGUAY',
stateId: 99,
},
{
id: 417,
name: 'VIETNAM',
stateId: 99,
},
]; ];

View File

@@ -5703,515 +5703,5 @@ export const Parishes = [
id: 1141, id: 1141,
name: "PQ. URIMARE", name: "PQ. URIMARE",
municipalityId: 335, municipalityId: 335,
}, }
{
id: 1142,
name: "BERLIN",
municipalityId: 336,
},
{
id: 1143,
name: "FRANKFURT",
municipalityId: 336,
},
{
id: 1144,
name: "LUANDA",
municipalityId: 337,
},
{
id: 1145,
name: "ST. JOHN'S",
municipalityId: 338,
},
{
id: 1146,
name: "RIYADH",
municipalityId: 339,
},
{
id: 1147,
name: "ARGEL",
municipalityId: 340,
},
{
id: 1148,
name: "BUENOS AIRES",
municipalityId: 341,
},
{
id: 1149,
name: "CABERRA",
municipalityId: 342,
},
{
id: 1150,
name: "VIENA",
municipalityId: 343,
},
{
id: 1151,
name: "BRIDGETOWN",
municipalityId: 344,
},
{
id: 1152,
name: "BRUSELA",
municipalityId: 345,
},
{
id: 1153,
name: "BELMONPAN",
municipalityId: 346,
},
{
id: 1154,
name: "COTONOU",
municipalityId: 347,
},
{
id: 1155,
name: "MINSK",
municipalityId: 348,
},
{
id: 1156,
name: "LA PAZ",
municipalityId: 349,
},
{
id: 1157,
name: "BRASILIA",
municipalityId: 350,
},
{
id: 1158,
name: "SANTIAGO",
municipalityId: 351,
},
{
id: 1159,
name: "BEIJING",
municipalityId: 352,
},
{
id: 1160,
name: "HONG KONG",
municipalityId: 352,
},
{
id: 1161,
name: "NEW",
municipalityId: 352,
},
{
id: 1162,
name: "SHANGHAI",
municipalityId: 352,
},
{
id: 1163,
name: "BARRANQUILLA",
municipalityId: 353,
},
{
id: 1164,
name: "BOGOTA",
municipalityId: 353,
},
{
id: 1165,
name: "CARTAGENA",
municipalityId: 353,
},
{
id: 1166,
name: "CUCUTA",
municipalityId: 353,
},
{
id: 1167,
name: "MEDELLIN",
municipalityId: 353,
},
{
id: 1168,
name: "RIOHACHA",
municipalityId: 353,
},
{
id: 1169,
name: "BRAZAVILLE",
municipalityId: 354,
},
{
id: 1170,
name: "SEUL",
municipalityId: 355,
},
{
id: 1171,
name: "SAN JOSE",
municipalityId: 356,
},
{
id: 1172,
name: "LA HABANA",
municipalityId: 357,
},
{
id: 1173,
name: "ROSEAU",
municipalityId: 358,
},
{
id: 1174,
name: "GUAYAQUIL",
municipalityId: 359,
},
{
id: 1175,
name: "QUITO",
municipalityId: 359,
},
{
id: 1176,
name: "EL CAIRO",
municipalityId: 360,
},
{
id: 1177,
name: "ABU DHABI",
municipalityId: 361,
},
{
id: 1178,
name: "BARCELONA",
municipalityId: 362,
},
{
id: 1179,
name: "BILBAO",
municipalityId: 362,
},
{
id: 1180,
name: "MADRID",
municipalityId: 362,
},
{
id: 1181,
name: "SANTA CRUZ DE TENERIFE",
municipalityId: 362,
},
{
id: 1182,
name: "VIGO",
municipalityId: 362,
},
{
id: 1183,
name: "ETIOPIA",
municipalityId: 363,
},
{
id: 1184,
name: "MANILA",
municipalityId: 364,
},
{
id: 1185,
name: "PARIS",
municipalityId: 365,
},
{
id: 1186,
name: "LONDRES",
municipalityId: 366,
},
{
id: 1187,
name: "ATENAS",
municipalityId: 367,
},
{
id: 1188,
name: "ST. GEORGES",
municipalityId: 368,
},
{
id: 1189,
name: "GEORGETOWN",
municipalityId: 369,
},
{
id: 1190,
name: "MALABO",
municipalityId: 370,
},
{
id: 1191,
name: "PUERTO PRINCIPE",
municipalityId: 371,
},
{
id: 1192,
name: "TEGUCIGALPA",
municipalityId: 372,
},
{
id: 1193,
name: "BUDAPEST",
municipalityId: 373,
},
{
id: 1194,
name: "NUEVA DELHI",
municipalityId: 374,
},
{
id: 1195,
name: "JAKARTA",
municipalityId: 375,
},
{
id: 1196,
name: "BAGDAD",
municipalityId: 376,
},
{
id: 1197,
name: "TEHERAN",
municipalityId: 377,
},
{
id: 1198,
name: "MILAN",
municipalityId: 378,
},
{
id: 1199,
name: "NAPOLES",
municipalityId: 378,
},
{
id: 1200,
name: "ROMA",
municipalityId: 378,
},
{
id: 1201,
name: "KINGSTON",
municipalityId: 379,
},
{
id: 1202,
name: "TOKIO",
municipalityId: 380,
},
{
id: 1203,
name: "AMMAN",
municipalityId: 381,
},
{
id: 1204,
name: "NAIROBI",
municipalityId: 382,
},
{
id: 1205,
name: "KUWAIT",
municipalityId: 383,
},
{
id: 1206,
name: "BEIRUT",
municipalityId: 384,
},
{
id: 1207,
name: "KUALA LUMPUR",
municipalityId: 385,
},
{
id: 1208,
name: "MALI",
municipalityId: 386,
},
{
id: 1209,
name: "RABAT",
municipalityId: 387,
},
{
id: 1210,
name: "MEXICO",
municipalityId: 388,
},
{
id: 1211,
name: "MAPUTO",
municipalityId: 389,
},
{
id: 1212,
name: "WINDHOEK",
municipalityId: 390,
},
{
id: 1213,
name: "MANAGUA",
municipalityId: 391,
},
{
id: 1214,
name: "LAGOS",
municipalityId: 392,
},
{
id: 1215,
name: "OSLO",
municipalityId: 393,
},
{
id: 1216,
name: "ARUBA",
municipalityId: 394,
},
{
id: 1217,
name: "CURAZAO",
municipalityId: 394,
},
{
id: 1218,
name: "LA HAYA",
municipalityId: 394,
},
{
id: 1219,
name: "PALESTINA",
municipalityId: 395,
},
{
id: 1220,
name: "PANAMA",
municipalityId: 396,
},
{
id: 1221,
name: "LIMA",
municipalityId: 397,
},
{
id: 1222,
name: "VARSOVIA",
municipalityId: 398,
},
{
id: 1223,
name: "FUNCHAL MADEIRA",
municipalityId: 399,
},
{
id: 1224,
name: "LISBOA",
municipalityId: 399,
},
{
id: 1225,
name: "DOHA",
municipalityId: 400,
},
{
id: 1226,
name: "SANTO DOMINGO",
municipalityId: 401,
},
{
id: 1227,
name: "BUCAREST",
municipalityId: 402,
},
{
id: 1228,
name: "MOSCU",
municipalityId: 403,
},
{
id: 1229,
name: "BASSETERRE",
municipalityId: 404,
},
{
id: 1230,
name: "CASTRIES",
municipalityId: 405,
},
{
id: 1231,
name: "KINGSTOWN",
municipalityId: 406,
},
{
id: 1232,
name: "SENEGAL",
municipalityId: 407,
},
{
id: 1233,
name: "BELGRADO",
municipalityId: 408,
},
{
id: 1234,
name: "SINGAPUR",
municipalityId: 409,
},
{
id: 1235,
name: "DAMASCO",
municipalityId: 410,
},
{
id: 1236,
name: "PETRORIA",
municipalityId: 411,
},
{
id: 1237,
name: "BERNA",
municipalityId: 412,
},
{
id: 1238,
name: "PARAMARIBO",
municipalityId: 413,
},
{
id: 1239,
name: "PUERTO ESPA A",
municipalityId: 414,
},
{
id: 1240,
name: "ANKARA",
municipalityId: 415,
},
{
id: 1241,
name: "NEW",
municipalityId: 415,
},
{
id: 1242,
name: "MONTEVIDEO",
municipalityId: 416,
},
{
id: 1243,
name: "VIETNAM",
municipalityId: 417,
},
]; ];

View File

@@ -94,9 +94,5 @@ export const States = [
{ {
id: 21, id: 21,
name: "EDO. ZULIA", name: "EDO. ZULIA",
}, }
{
id: 99,
name: "EMBAJADA",
},
]; ];

View File

@@ -7,6 +7,7 @@ import {
IsEmail, IsEmail,
IsInt, IsInt,
IsOptional, IsOptional,
isString,
IsString, IsString,
ValidateIf, ValidateIf,
} from 'class-validator'; } from 'class-validator';
@@ -332,4 +333,8 @@ export class CreateTrainingDto {
@IsString() @IsString()
@IsOptional() @IsOptional()
photo3?: string; photo3?: string;
@ApiProperty()
@IsString()
surveyStatus: string
} }

View File

@@ -28,7 +28,7 @@ import { TrainingService } from './training.service';
@ApiTags('training') @ApiTags('training')
@Controller('training') @Controller('training')
export class TrainingController { export class TrainingController {
constructor(private readonly trainingService: TrainingService) {} constructor(private readonly trainingService: TrainingService) { }
// @Public() // @Public()
// @Get('export/:id') // @Get('export/:id')
@@ -48,6 +48,7 @@ export class TrainingController {
// return new StreamableFile(data); // return new StreamableFile(data);
// } // }
// ========== //
@Get() @Get()
@ApiOperation({ @ApiOperation({
summary: 'Get all training records with pagination and filters', summary: 'Get all training records with pagination and filters',
@@ -56,8 +57,10 @@ export class TrainingController {
status: 200, status: 200,
description: 'Return paginated training records.', description: 'Return paginated training records.',
}) })
async findAll(@Query() paginationDto: PaginationDto) { async findAll(@Req() req: Request, @Query() paginationDto: PaginationDto) {
const result = await this.trainingService.findAll(paginationDto); const user = (req as any).user;
const result = await this.trainingService.findAll(paginationDto, { role: user?.roles[0], id: user?.id });
return { return {
message: 'Training records fetched successfully', message: 'Training records fetched successfully',
data: result.data, data: result.data,
@@ -65,6 +68,7 @@ export class TrainingController {
}; };
} }
// ========== //
@Get('statistics') @Get('statistics')
@ApiOperation({ summary: 'Get training statistics' }) @ApiOperation({ summary: 'Get training statistics' })
@ApiResponse({ status: 200, description: 'Return training statistics.' }) @ApiResponse({ status: 200, description: 'Return training statistics.' })
@@ -73,6 +77,7 @@ export class TrainingController {
return { message: 'Training statistics fetched successfully', data }; return { message: 'Training statistics fetched successfully', data };
} }
// ========== //
@Get(':id') @Get(':id')
@ApiOperation({ summary: 'Get a training record by ID' }) @ApiOperation({ summary: 'Get a training record by ID' })
@ApiResponse({ status: 200, description: 'Return the training record.' }) @ApiResponse({ status: 200, description: 'Return the training record.' })
@@ -82,6 +87,7 @@ export class TrainingController {
return { message: 'Training record fetched successfully', data }; return { message: 'Training record fetched successfully', data };
} }
// ========== //
@Post() @Post()
@UseInterceptors(FilesInterceptor('files', 3)) @UseInterceptors(FilesInterceptor('files', 3))
@ApiConsumes('multipart/form-data') @ApiConsumes('multipart/form-data')
@@ -104,6 +110,7 @@ export class TrainingController {
return { message: 'Training record created successfully', data }; return { message: 'Training record created successfully', data };
} }
// ========== //
@Patch(':id') @Patch(':id')
@UseInterceptors(FilesInterceptor('files', 3)) @UseInterceptors(FilesInterceptor('files', 3))
@ApiConsumes('multipart/form-data') @ApiConsumes('multipart/form-data')
@@ -129,6 +136,7 @@ export class TrainingController {
return { message: 'Training record updated successfully', data }; return { message: 'Training record updated successfully', data };
} }
// ========== //
@Delete(':id') @Delete(':id')
@ApiOperation({ summary: 'Delete a training record' }) @ApiOperation({ summary: 'Delete a training record' })
@ApiResponse({ @ApiResponse({

View File

@@ -11,6 +11,16 @@ import { CreateTrainingDto } from './dto/create-training.dto';
import { TrainingStatisticsFilterDto } from './dto/training-statistics-filter.dto'; import { TrainingStatisticsFilterDto } from './dto/training-statistics-filter.dto';
import { UpdateTrainingDto } from './dto/update-training.dto'; import { UpdateTrainingDto } from './dto/update-training.dto';
// TRUE: para mostrar los logs de errores en la api
// Actualmente estás solo en crear registro. Despues lo implemento en los demas
const debug = false;
type User = {
role: string;
id: number;
};
@Injectable() @Injectable()
export class TrainingService { export class TrainingService {
constructor( constructor(
@@ -18,7 +28,8 @@ export class TrainingService {
private readonly minioService: MinioService, private readonly minioService: MinioService,
) { } ) { }
async findAll(paginationDto?: PaginationDto) {
async findAll(paginationDto?: PaginationDto, user?: User) {
const { const {
page = 1, page = 1,
limit = 10, limit = 10,
@@ -34,6 +45,10 @@ export class TrainingService {
searchCondition = or(ilike(trainingSurveys.ospName, `%${search}%`)); searchCondition = or(ilike(trainingSurveys.ospName, `%${search}%`));
} }
if (user?.role == 'coordinators') {
searchCondition = eq(trainingSurveys.createdBy, user.id)
}
const orderBy = const orderBy =
sortOrder === 'asc' sortOrder === 'asc'
? sql`${trainingSurveys[sortBy as keyof typeof trainingSurveys]} asc` ? sql`${trainingSurveys[sortBy as keyof typeof trainingSurveys]} asc`
@@ -257,50 +272,57 @@ export class TrainingService {
} }
} }
// ========== Guardar registro ========== //
async create( async create(
createTrainingDto: CreateTrainingDto, createTrainingDto: CreateTrainingDto,
files: Express.Multer.File[], files: Express.Multer.File[],
userId: number, userId: number,
) { ) {
// 1. Guardar fotos try {
// 1. Guardar fotos
const photoPaths = await this.saveFiles(files);
// const photoPaths = [];
const photoPaths = await this.saveFiles(files); // 2. Extraer solo visitDate para formatearlo.
// Ya NO extraemos state, municipality, etc. porque no vienen en el DTO.
const { visitDate, state, municipality, parish, productiveActivityOther, ...rest } =
createTrainingDto;
// 2. Extraer solo visitDate para formatearlo. const [newRecord] = await this.drizzle
// Ya NO extraemos state, municipality, etc. porque no vienen en el DTO. .insert(trainingSurveys)
const { visitDate, state, municipality, parish, productiveActivityOther, ...rest } = .values({
createTrainingDto; // Insertamos el resto de datos planos y las listas (arrays)
...rest,
const [newRecord] = await this.drizzle // Conversión de fecha
.insert(trainingSurveys) visitDate: new Date(visitDate),
.values({
// Insertamos el resto de datos planos y las listas (arrays)
...rest,
// Conversión de fecha // Borra las tildes y cambia el texto a mayusculas
visitDate: new Date(visitDate), productiveActivityOther: productiveActivityOther ? productiveActivityOther.toUpperCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "") : '',
// Borra las tildes y cambia el texto a mayusculas // 3. Asignar fotos de forma segura
productiveActivityOther: productiveActivityOther.toUpperCase().normalize("NFD").replace(/[\u0300-\u036f]/g, ""), photo1: photoPaths[0] ?? null,
photo2: photoPaths[1] ?? null,
photo3: photoPaths[2] ?? null,
state: Number(state) ?? null,
municipality: Number(municipality) ?? null,
parish: Number(parish) ?? null,
hasTransport: rest.hasTransport === 'true' ? true : false,
isOpenSpace: rest.isOpenSpace === 'true' ? true : false,
isExporting: rest.isExporting === 'true' ? true : false,
createdBy: userId,
updatedBy: userId,
})
.returning();
// 3. Asignar fotos de forma segura return newRecord;
photo1: photoPaths[0] ?? null, } catch (e) {
photo2: photoPaths[1] ?? null, if (debug) console.log(e);
photo3: photoPaths[2] ?? null, return null // null para que de error
state: Number(state) ?? null, }
municipality: Number(municipality) ?? null,
parish: Number(parish) ?? null,
hasTransport: rest.hasTransport === 'true' ? true : false,
isOpenSpace: rest.isOpenSpace === 'true' ? true : false,
isExporting: rest.isExporting === 'true' ? true : false,
createdBy: userId,
updatedBy: userId,
})
.returning();
return newRecord;
} }
// ========== Actualizar registro ========== //
async update( async update(
id: number, id: number,
updateTrainingDto: UpdateTrainingDto, updateTrainingDto: UpdateTrainingDto,
@@ -376,6 +398,7 @@ export class TrainingService {
return updatedRecord; return updatedRecord;
} }
// ========== Eliminar registro ========== //
async remove(id: number) { async remove(id: number) {
const record = await this.findOne(id); const record = await this.findOne(id);

View File

@@ -151,7 +151,7 @@ export function CreateTrainingForm({
generalObservations: defaultValues?.generalObservations || '', generalObservations: defaultValues?.generalObservations || '',
ospResponsibleEmail: defaultValues?.ospResponsibleEmail || '', ospResponsibleEmail: defaultValues?.ospResponsibleEmail || '',
paralysisReason: defaultValues?.paralysisReason || '', paralysisReason: defaultValues?.paralysisReason || '',
infrastructureMt2: defaultValues?.infrastructureMt2 || undefined, infrastructureMt2: defaultValues?.infrastructureMt2 || '',
hasTransport: defaultValues?.hasTransport || false, hasTransport: defaultValues?.hasTransport || false,
structureType: defaultValues?.structureType || undefined, structureType: defaultValues?.structureType || undefined,
isOpenSpace: defaultValues?.isOpenSpace || false, isOpenSpace: defaultValues?.isOpenSpace || false,
@@ -172,6 +172,7 @@ export function CreateTrainingForm({
womenCount: defaultValues?.womenCount || 0, womenCount: defaultValues?.womenCount || 0,
menCount: defaultValues?.menCount || 0, menCount: defaultValues?.menCount || 0,
surveyStatus: defaultValues?.surveyStatus || 'BORRADOR'
}, },
mode: 'onChange', mode: 'onChange',
}); });
@@ -208,6 +209,11 @@ export function CreateTrainingForm({
name: 'productiveActivity', name: 'productiveActivity',
}); });
const structureType = useWatch({
control: form.control,
name: 'structureType',
});
const productiveSectorOptions = ecoSector const productiveSectorOptions = ecoSector
? SECTOR_PRODUCTIVO_MAP[ecoSector] || [] ? SECTOR_PRODUCTIVO_MAP[ecoSector] || []
: []; : [];
@@ -222,6 +228,7 @@ export function CreateTrainingForm({
: []; : [];
const other = productiveActivity == 'OTRO' ? true : false; const other = productiveActivity == 'OTRO' ? true : false;
const showInfrastructure = structureType && structureType !== 'NINGUNA';
// Reset dependent fields when parent changes // Reset dependent fields when parent changes
React.useEffect(() => { React.useEffect(() => {
@@ -371,7 +378,7 @@ export function CreateTrainingForm({
<Input <Input
{...field} {...field}
placeholder="Ej. 04121234567" placeholder="Ej. 04121234567"
value={field.value ?? ''} value={field.value}
onChange={(e) => { onChange={(e) => {
const val = e.target.value.replace(/\D/g, ''); const val = e.target.value.replace(/\D/g, '');
field.onChange(val.slice(0, 11)); field.onChange(val.slice(0, 11));
@@ -393,7 +400,7 @@ export function CreateTrainingForm({
<Input <Input
type="datetime-local" type="datetime-local"
{...field} {...field}
value={field.value || ''} value={field.value}
/> />
</FormControl> </FormControl>
<FormMessage /> <FormMessage />
@@ -491,7 +498,7 @@ export function CreateTrainingForm({
</FormLabel> </FormLabel>
<Select <Select
onValueChange={field.onChange} onValueChange={field.onChange}
defaultValue={field.value ?? undefined} defaultValue={field.value}
> >
<FormControl> <FormControl>
<SelectTrigger className="w-full"> <SelectTrigger className="w-full">
@@ -527,7 +534,7 @@ export function CreateTrainingForm({
form.setValue('mainProductiveActivity', ''); form.setValue('mainProductiveActivity', '');
form.setValue('productiveActivity', ''); form.setValue('productiveActivity', '');
}} }}
defaultValue={field.value ?? undefined} defaultValue={field.value}
> >
<FormControl> <FormControl>
<SelectTrigger className="w-full"> <SelectTrigger className="w-full">
@@ -562,7 +569,7 @@ export function CreateTrainingForm({
form.setValue('mainProductiveActivity', ''); form.setValue('mainProductiveActivity', '');
form.setValue('productiveActivity', ''); form.setValue('productiveActivity', '');
}} }}
defaultValue={field.value ?? undefined} defaultValue={field.value}
disabled={!ecoSector} disabled={!ecoSector}
> >
<FormControl> <FormControl>
@@ -597,7 +604,7 @@ export function CreateTrainingForm({
form.setValue('mainProductiveActivity', ''); form.setValue('mainProductiveActivity', '');
form.setValue('productiveActivity', ''); form.setValue('productiveActivity', '');
}} }}
defaultValue={field.value ?? undefined} defaultValue={field.value}
disabled={!productiveSector} disabled={!productiveSector}
> >
<FormControl> <FormControl>
@@ -631,7 +638,7 @@ export function CreateTrainingForm({
field.onChange(val); field.onChange(val);
form.setValue('productiveActivity', ''); form.setValue('productiveActivity', '');
}} }}
defaultValue={field.value ?? undefined} defaultValue={field.value}
disabled={!centralProductiveActivity} disabled={!centralProductiveActivity}
> >
<FormControl> <FormControl>
@@ -662,7 +669,7 @@ export function CreateTrainingForm({
</FormLabel> </FormLabel>
<Select <Select
onValueChange={field.onChange} onValueChange={field.onChange}
defaultValue={field.value ?? undefined} defaultValue={field.value}
disabled={!mainProductiveActivity} disabled={!mainProductiveActivity}
> >
<FormControl> <FormControl>
@@ -695,7 +702,7 @@ export function CreateTrainingForm({
<FormControl> <FormControl>
<Input <Input
{...field} {...field}
value={field.value ?? ''} value={field.value}
/> />
</FormControl> </FormControl>
<FormMessage /> <FormMessage />
@@ -715,7 +722,7 @@ export function CreateTrainingForm({
<FormControl> <FormControl>
<Input <Input
{...field} {...field}
value={field.value ?? ''} value={field.value}
placeholder="J-12345678-9" placeholder="J-12345678-9"
/> />
</FormControl> </FormControl>
@@ -733,7 +740,7 @@ export function CreateTrainingForm({
Nombre de la organización (opcional) Nombre de la organización (opcional)
</FormLabel> </FormLabel>
<FormControl> <FormControl>
<Input {...field} value={field.value ?? ''} /> <Input {...field} value={field.value} />
</FormControl> </FormControl>
<FormMessage /> <FormMessage />
</FormItem> </FormItem>
@@ -752,7 +759,7 @@ export function CreateTrainingForm({
<Input <Input
type="number" type="number"
{...field} {...field}
value={field.value ?? ''} value={field.value}
/> />
</FormControl> </FormControl>
<FormMessage /> <FormMessage />
@@ -770,7 +777,7 @@ export function CreateTrainingForm({
</FormLabel> </FormLabel>
<Select <Select
onValueChange={field.onChange} onValueChange={field.onChange}
defaultValue={field.value ?? undefined} defaultValue={field.value}
> >
<FormControl> <FormControl>
<SelectTrigger> <SelectTrigger>
@@ -792,24 +799,56 @@ export function CreateTrainingForm({
<FormField <FormField
control={form.control} control={form.control}
name="infrastructureMt2" name="structureType"
render={({ field }) => ( render={({ field }) => (
<FormItem className="w-full flex flex-col space-y-3"> <FormItem className="w-full flex flex-col space-y-3">
<FormLabel className="whitespace-normal leading-tight font-semibold"> <FormLabel className="whitespace-normal leading-tight font-semibold">
infraestrutura (MT2) Tipo Estructura
</FormLabel> </FormLabel>
<FormControl> <Select
<Input onValueChange={field.onChange}
{...field} defaultValue={field.value}
value={field.value ?? ''} >
placeholder="e.g. 500" <FormControl>
/> <SelectTrigger>
</FormControl> <SelectValue placeholder="Seleccione tipo" />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem value="CASA">CASA</SelectItem>
<SelectItem value="GALPÓN">GALPÓN</SelectItem>
<SelectItem value="LOCAL">LOCAL</SelectItem>
<SelectItem value="ALMACÉN">ALMACÉN</SelectItem>
<SelectItem value="NINGUNA">NINGUNA</SelectItem>
</SelectContent>
</Select>
<FormMessage /> <FormMessage />
</FormItem> </FormItem>
)} )}
/> />
{showInfrastructure && (
<FormField
control={form.control}
name="infrastructureMt2"
render={({ field }) => (
<FormItem className="w-full flex flex-col space-y-3">
<FormLabel className="whitespace-normal leading-tight font-semibold">
infraestrutura (MT2)
</FormLabel>
<FormControl>
<Input
{...field}
value={field.value}
placeholder="e.g. 500"
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
)}
<FormField <FormField
control={form.control} control={form.control}
name="hasTransport" name="hasTransport"
@@ -837,35 +876,6 @@ export function CreateTrainingForm({
)} )}
/> />
<FormField
control={form.control}
name="structureType"
render={({ field }) => (
<FormItem className="w-full flex flex-col space-y-3">
<FormLabel className="whitespace-normal leading-tight font-semibold">
Tipo Estructura
</FormLabel>
<Select
onValueChange={field.onChange}
defaultValue={field.value ?? undefined}
>
<FormControl>
<SelectTrigger>
<SelectValue placeholder="Seleccione tipo" />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem value="CASA">CASA</SelectItem>
<SelectItem value="GALPÓN">GALPÓN</SelectItem>
<SelectItem value="LOCAL">LOCAL</SelectItem>
<SelectItem value="ALMACÉN">ALMACÉN</SelectItem>
</SelectContent>
</Select>
<FormMessage />
</FormItem>
)}
/>
<FormField <FormField
control={form.control} control={form.control}
name="isOpenSpace" name="isOpenSpace"
@@ -903,7 +913,7 @@ export function CreateTrainingForm({
Razones de paralización (opcional) Razones de paralización (opcional)
</FormLabel> </FormLabel>
<FormControl> <FormControl>
<Textarea {...field} value={field.value ?? ''} /> <Textarea {...field} value={field.value} />
</FormControl> </FormControl>
<FormMessage /> <FormMessage />
</FormItem> </FormItem>
@@ -943,7 +953,7 @@ export function CreateTrainingForm({
render={({ field }) => ( render={({ field }) => (
<FormItem> <FormItem>
<FormLabel> <FormLabel>
Breve Descripción de la Zona de Distribución Breve Descripción de la Zona de Distribución (Opcional)
</FormLabel> </FormLabel>
<FormControl> <FormControl>
<Input <Input
@@ -992,7 +1002,7 @@ export function CreateTrainingForm({
<FormLabel>País</FormLabel> <FormLabel>País</FormLabel>
<Select <Select
onValueChange={field.onChange} onValueChange={field.onChange}
defaultValue={field.value ?? undefined} defaultValue={field.value}
> >
<FormControl> <FormControl>
<SelectTrigger className="w-full"> <SelectTrigger className="w-full">
@@ -1019,7 +1029,7 @@ export function CreateTrainingForm({
<FormItem> <FormItem>
<FormLabel>Ciudad</FormLabel> <FormLabel>Ciudad</FormLabel>
<FormControl> <FormControl>
<Input {...field} value={field.value ?? ''} /> <Input {...field} value={field.value} />
</FormControl> </FormControl>
<FormMessage /> <FormMessage />
</FormItem> </FormItem>
@@ -1035,12 +1045,13 @@ export function CreateTrainingForm({
<FormItem> <FormItem>
<FormLabel>Breve Descripción</FormLabel> <FormLabel>Breve Descripción</FormLabel>
<FormControl> <FormControl>
<Input {...field} value={field.value ?? ''} /> <Input {...field} value={field.value} />
</FormControl> </FormControl>
<FormMessage /> <FormMessage />
</FormItem> </FormItem>
)} )}
/> />
<div className="grid grid-cols-2 gap-2"> <div className="grid grid-cols-2 gap-2">
<FormField <FormField
control={form.control} control={form.control}
@@ -1052,7 +1063,7 @@ export function CreateTrainingForm({
<Input <Input
type="number" type="number"
{...field} {...field}
value={field.value ?? ''} value={field.value}
/> />
</FormControl> </FormControl>
<FormMessage /> <FormMessage />
@@ -1067,7 +1078,7 @@ export function CreateTrainingForm({
<FormLabel>Unidad</FormLabel> <FormLabel>Unidad</FormLabel>
<Select <Select
onValueChange={field.onChange} onValueChange={field.onChange}
defaultValue={field.value ?? undefined} defaultValue={field.value}
> >
<FormControl> <FormControl>
<SelectTrigger className="w-full"> <SelectTrigger className="w-full">
@@ -1142,12 +1153,12 @@ export function CreateTrainingForm({
<CardHeader> <CardHeader>
<CardTitle>3. Detalles de la ubicación</CardTitle> <CardTitle>3. Detalles de la ubicación</CardTitle>
</CardHeader> </CardHeader>
<CardContent className="grid grid-cols-1 lg:grid-cols-2 gap-6 items-start"> <CardContent className="grid grid-cols-1 md:grid-cols-2 gap-6 items-start">
<FormField <FormField
control={form.control} control={form.control}
name="ospAddress" name="ospAddress"
render={({ field }) => ( render={({ field }) => (
<FormItem className="col-span-1 lg:col-span-2 flex flex-col space-y-2"> <FormItem className="md:col-span-2 flex flex-col space-y-2">
<FormLabel> <FormLabel>
Dirección de la Organización Socio Productivo Dirección de la Organización Socio Productivo
</FormLabel> </FormLabel>
@@ -1163,14 +1174,14 @@ export function CreateTrainingForm({
control={form.control} control={form.control}
name="ospGoogleMapsLink" name="ospGoogleMapsLink"
render={({ field }) => ( render={({ field }) => (
<FormItem className="col-span-1 lg:col-span-2 flex flex-col space-y-2"> <FormItem className="md:col-span-2 flex flex-col space-y-2">
<FormLabel> <FormLabel>
Coordenadas de la Ubicación (Google Maps. Opcional) Coordenadas de la Ubicación (Google Maps. Opcional)
</FormLabel> </FormLabel>
<FormControl> <FormControl>
<Input <Input
{...field} {...field}
value={field.value ?? ''} value={field.value}
placeholder="10.123456, -66.123456" placeholder="10.123456, -66.123456"
/> />
</FormControl> </FormControl>
@@ -1179,7 +1190,7 @@ export function CreateTrainingForm({
)} )}
/> />
<div className="col-span-1 lg:col-span-2 border-b pb-2 mt-4 hidden md:inline"> <div className="col-span-2 border-b pb-2 mt-4 hidden md:inline">
<h4 className="font-semibold mb-2">Datos de la Comuna</h4> <h4 className="font-semibold mb-2">Datos de la Comuna</h4>
</div> </div>
@@ -1192,7 +1203,7 @@ export function CreateTrainingForm({
Nombre de la Comuna Nombre de la Comuna
</FormLabel> </FormLabel>
<FormControl> <FormControl>
<Input {...field} value={field.value ?? ''} /> <Input {...field} value={field.value} />
</FormControl> </FormControl>
<FormMessage /> <FormMessage />
</FormItem> </FormItem>
@@ -1208,7 +1219,7 @@ export function CreateTrainingForm({
Código SITUR de la Comuna Código SITUR de la Comuna
</FormLabel> </FormLabel>
<FormControl> <FormControl>
<Input {...field} value={field.value ?? ''} /> <Input {...field} value={field.value} />
</FormControl> </FormControl>
<FormMessage /> <FormMessage />
</FormItem> </FormItem>
@@ -1224,7 +1235,7 @@ export function CreateTrainingForm({
Rif de la Comuna Rif de la Comuna
</FormLabel> </FormLabel>
<FormControl> <FormControl>
<Input {...field} value={field.value ?? ''} /> <Input {...field} value={field.value} />
</FormControl> </FormControl>
<FormMessage /> <FormMessage />
</FormItem> </FormItem>
@@ -1240,7 +1251,7 @@ export function CreateTrainingForm({
Nombre del Vocero o Vocera Nombre del Vocero o Vocera
</FormLabel> </FormLabel>
<FormControl> <FormControl>
<Input {...field} value={field.value ?? ''} /> <Input {...field} value={field.value} />
</FormControl> </FormControl>
<FormMessage /> <FormMessage />
</FormItem> </FormItem>
@@ -1258,7 +1269,7 @@ export function CreateTrainingForm({
<FormControl> <FormControl>
<Input <Input
{...field} {...field}
value={field.value ?? ''} value={field.value}
placeholder="Ej. 04121234567" placeholder="Ej. 04121234567"
onChange={(e) => { onChange={(e) => {
const val = e.target.value.replace(/\D/g, ''); const val = e.target.value.replace(/\D/g, '');
@@ -1283,7 +1294,7 @@ export function CreateTrainingForm({
<Input <Input
type="email" type="email"
{...field} {...field}
value={field.value ?? ''} value={field.value}
/> />
</FormControl> </FormControl>
<FormMessage /> <FormMessage />
@@ -1322,7 +1333,7 @@ export function CreateTrainingForm({
Código SITUR del Consejo Comunal Código SITUR del Consejo Comunal
</FormLabel> </FormLabel>
<FormControl> <FormControl>
<Input {...field} value={field.value ?? ''} /> <Input {...field} value={field.value} />
</FormControl> </FormControl>
<FormMessage /> <FormMessage />
</FormItem> </FormItem>
@@ -1338,7 +1349,7 @@ export function CreateTrainingForm({
Rif del Consejo Comunal Rif del Consejo Comunal
</FormLabel> </FormLabel>
<FormControl> <FormControl>
<Input {...field} value={field.value ?? ''} /> <Input {...field} value={field.value} />
</FormControl> </FormControl>
<FormMessage /> <FormMessage />
</FormItem> </FormItem>
@@ -1354,7 +1365,7 @@ export function CreateTrainingForm({
Nombre del Vocero o Vocera Nombre del Vocero o Vocera
</FormLabel> </FormLabel>
<FormControl> <FormControl>
<Input {...field} value={field.value ?? ''} /> <Input {...field} value={field.value} />
</FormControl> </FormControl>
<FormMessage /> <FormMessage />
</FormItem> </FormItem>
@@ -1372,7 +1383,7 @@ export function CreateTrainingForm({
<FormControl> <FormControl>
<Input <Input
{...field} {...field}
value={field.value ?? ''} value={field.value}
placeholder="Ej. 04121234567" placeholder="Ej. 04121234567"
onChange={(e) => { onChange={(e) => {
const val = e.target.value.replace(/\D/g, ''); const val = e.target.value.replace(/\D/g, '');
@@ -1397,7 +1408,7 @@ export function CreateTrainingForm({
<Input <Input
type="email" type="email"
{...field} {...field}
value={field.value ?? ''} value={field.value}
/> />
</FormControl> </FormControl>
<FormMessage /> <FormMessage />
@@ -1436,7 +1447,7 @@ export function CreateTrainingForm({
<FormControl> <FormControl>
<Input <Input
{...field} {...field}
value={field.value ?? ''} value={field.value}
placeholder="Ej. 04121234567" placeholder="Ej. 04121234567"
onChange={(e) => { onChange={(e) => {
const val = e.target.value.replace(/\D/g, ''); const val = e.target.value.replace(/\D/g, '');
@@ -1453,7 +1464,7 @@ export function CreateTrainingForm({
control={form.control} control={form.control}
name="ospResponsibleFullname" name="ospResponsibleFullname"
render={({ field }) => ( render={({ field }) => (
<FormItem className="col-span-2"> <FormItem className="md:col-span-2">
<FormLabel>Nombre y apellido</FormLabel> <FormLabel>Nombre y apellido</FormLabel>
<FormControl> <FormControl>
<Input {...field} /> <Input {...field} />
@@ -1462,102 +1473,6 @@ export function CreateTrainingForm({
</FormItem> </FormItem>
)} )}
/> />
{/* <FormField
control={form.control}
name="ospResponsibleRif"
render={({ field }) => (
<FormItem>
<FormLabel>RIF (Opcional)</FormLabel>
<FormControl>
<Input {...field} value={field.value ?? ''} />
</FormControl>
<FormMessage />
</FormItem>
)}
/> */}
{/* <FormField
control={form.control}
name="civilState"
render={({ field }) => (
<FormItem>
<FormLabel>Estado Civil (Opcional)</FormLabel>
<Select
onValueChange={field.onChange}
defaultValue={field.value ?? undefined}
>
<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="ospResponsibleEmail"
render={({ field }) => (
<FormItem>
<FormLabel>Correo Electrónico (Opcional)</FormLabel>
<FormControl>
<Input
type="email"
{...field}
value={field.value ?? ''}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/> */}
{/* <FormField
control={form.control}
name="familyBurden"
render={({ field }) => (
<FormItem>
<FormLabel>Carga Familiar (Opcional)</FormLabel>
<FormControl>
<Input
type="number"
{...field}
value={field.value ?? ''}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/> */}
{/* <FormField
control={form.control}
name="numberOfChildren"
render={({ field }) => (
<FormItem>
<FormLabel>Número de Hijos (Opcional)</FormLabel>
<FormControl>
<Input
type="number"
{...field}
value={field.value ?? ''}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/> */}
</CardContent> </CardContent>
</Card> </Card>
@@ -1574,7 +1489,7 @@ export function CreateTrainingForm({
<FormItem> <FormItem>
<FormLabel>Observaciones Generales (Opcional)</FormLabel> <FormLabel>Observaciones Generales (Opcional)</FormLabel>
<FormControl> <FormControl>
<Textarea {...field} value={field.value ?? ''} /> <Textarea {...field} value={field.value} />
</FormControl> </FormControl>
<FormMessage /> <FormMessage />
</FormItem> </FormItem>
@@ -1641,7 +1556,7 @@ export function CreateTrainingForm({
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
<FormLabel> <FormLabel>
Subir nuevas imágenes (máximo 3 en total) Subir imágenes (Máximo 3 y opcional)
</FormLabel> </FormLabel>
<Input <Input
type="file" type="file"
@@ -1728,23 +1643,49 @@ export function CreateTrainingForm({
</CardContent> </CardContent>
</Card> </Card>
<div className="flex justify-end gap-4 mt-8"> <div className="grid grid-cols-2 md:grid-cols-3 justify-items-end gap-3 mt-8">
<Button <Button
variant="outline" variant="outline"
type="button" type="button"
onClick={onCancel} onClick={onCancel}
className="w-32" className="w-32 col-span-2 md:col-span-1"
> >
Cancelar Cancelar
</Button> </Button>
<FormField
control={form.control}
name="surveyStatus"
render={({ field }) => (
<FormItem>
<Select
onValueChange={field.onChange}
defaultValue={field.value}
>
<FormControl>
<SelectTrigger>
<SelectValue placeholder="Seleccione tipo" />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem defaultChecked value="BORRADOR">BORRADOR</SelectItem>
<SelectItem value="PUBLICADO">PUBLICADO</SelectItem>
</SelectContent>
</Select>
<FormMessage />
</FormItem>
)}
/>
<Button <Button
type="submit" type="submit"
disabled={ disabled={
isSaving || isSaving
(selectedFiles.length === 0 && // ||
!['photo1', 'photo2', 'photo3'].some((f) => // (selectedFiles.length === 0 &&
form.watch(f as any), // !['photo1', 'photo2', 'photo3'].some((f) =>
)) // form.watch(f as any),
// ))
} }
className="w-32" className="w-32"
> >

View File

@@ -22,18 +22,9 @@ export function columns({ apiUrl }: ColumnsProps): ColumnDef<TrainingSchema>[] {
accessorKey: 'ospType', accessorKey: 'ospType',
header: 'Tipo', header: 'Tipo',
}, },
{
accessorKey: 'created_at',
header: 'Fecha de creación',
cell: ({ row }) => {
// console.log(row.getValue('created_at'));
const date = row.getValue('created_at') as string;
return date ? new Date(date).toLocaleString() : 'N/A';
},
},
{ {
accessorKey: 'currentStatus', accessorKey: 'currentStatus',
header: 'Estatus', header: 'Estatus OSP',
cell: ({ row }) => { cell: ({ row }) => {
const status = row.getValue('currentStatus') as string; const status = row.getValue('currentStatus') as string;
return ( return (
@@ -43,6 +34,16 @@ export function columns({ apiUrl }: ColumnsProps): ColumnDef<TrainingSchema>[] {
); );
}, },
}, },
{
accessorKey: 'created_at',
header: 'Fecha de creación',
cell: ({ row }) => {
// console.log(row.getValue('created_at'));
const date = row.getValue('created_at') as string;
return date ? new Date(date).toLocaleString() : 'N/A';
},
},
{ {
accessorKey: 'visitDate', accessorKey: 'visitDate',
header: 'Fecha Visita', header: 'Fecha Visita',
@@ -51,6 +52,18 @@ export function columns({ apiUrl }: ColumnsProps): ColumnDef<TrainingSchema>[] {
return date ? new Date(date).toLocaleString() : 'N/A'; return date ? new Date(date).toLocaleString() : 'N/A';
}, },
}, },
{
accessorKey: 'surveyStatus',
header: '',
cell: ({ row }) => {
const status = row.getValue('surveyStatus') as string;
return (
<Badge variant={status === 'PUBLICADO' ? 'default' : 'secondary'}>
{status}
</Badge>
);
},
},
{ {
id: 'actions', id: 'actions',
header: 'Acciones', header: 'Acciones',

View File

@@ -46,18 +46,17 @@ export const trainingSchema = z.object({
productiveActivity: z.string({ productiveActivity: z.string({
message: 'Actividad Productiva es requerida', message: 'Actividad Productiva es requerida',
}), }),
productiveActivityOther: z.string().min(1, { message: 'Este campo es requerido' }).optional(), productiveActivityOther: z.string().min(1, { message: 'Otra actividad productiva es requerida' }).optional(),
ospRif: z.string().optional().or(z.literal('')).nullable(), ospRif: z.string().optional(),
ospName: z.string().optional().or(z.literal('')).nullable(), ospName: z.string().optional(),
companyConstitutionYear: z.coerce companyConstitutionYear: z.coerce
.number() .number()
.min(1900, { message: 'Año inválido' }) .min(1900, { message: 'Año inválido' }),
.nullable(),
currentStatus: z currentStatus: z
.string() .string()
.min(1, { message: 'Estatus actual es requerido' }) .min(1, { message: 'Estatus actual es requerido' })
.default('ACTIVA'), .default('ACTIVA'),
infrastructureMt2: z.string({ message: 'Infraestructura es requerida' }), infrastructureMt2: z.string({ message: 'Infraestructura es requerida' }).optional(),
hasTransport: z hasTransport: z
.preprocess( .preprocess(
(val) => val === 'true' || val === true || val === 1 || val === '1', (val) => val === 'true' || val === true || val === 1 || val === '1',
@@ -75,7 +74,7 @@ export const trainingSchema = z.object({
.optional() .optional()
.nullable() .nullable()
.default(false), .default(false),
paralysisReason: z.string().optional().nullable(), paralysisReason: z.string().optional(),
//Datos del Equipamiento //Datos del Equipamiento
equipmentList: z.array(equipmentItemSchema).optional().default([]), equipmentList: z.array(equipmentItemSchema).optional().default([]),
@@ -88,8 +87,7 @@ export const trainingSchema = z.object({
// Distribución y Exportación // Distribución y Exportación
internalDistributionZone: z internalDistributionZone: z
.string() .string(),
.min(1, { message: 'Zona de distribución es requerida' }),
isExporting: z isExporting: z
.preprocess( .preprocess(
(val) => val === 'true' || val === true || val === 1 || val === '1', (val) => val === 'true' || val === true || val === 1 || val === '1',
@@ -97,11 +95,11 @@ export const trainingSchema = z.object({
) )
.optional() .optional()
.default(false), .default(false),
externalCountry: z.string().optional().nullable(), externalCountry: z.string().optional(),
externalCity: z.string().optional().nullable(), externalCity: z.string().optional(),
externalDescription: z.string().optional().nullable(), externalDescription: z.string().optional(),
externalQuantity: z.coerce.string().or(z.number()).optional().nullable(), externalQuantity: z.coerce.string().or(z.number()).optional(),
externalUnit: z.string().optional().nullable(), externalUnit: z.string().optional(),
// Mano de obra // Mano de obra
womenCount: z.coerce womenCount: z.coerce
@@ -115,7 +113,7 @@ export const trainingSchema = z.object({
ospAddress: z ospAddress: z
.string() .string()
.min(1, { message: 'Dirección de la OSP es requerida' }), .min(1, { message: 'Dirección de la OSP es requerida' }),
ospGoogleMapsLink: z.string().optional().or(z.literal('')).nullable(), ospGoogleMapsLink: z.string().optional().or(z.literal('')),
communeName: z communeName: z
.string() .string()
.min(1, { message: 'Nombre de la comuna es requerida' }), .min(1, { message: 'Nombre de la comuna es requerida' }),
@@ -137,8 +135,7 @@ export const trainingSchema = z.object({
.string() .string()
.email({ message: 'Correo electrónico de la Comuna inválido' }) .email({ message: 'Correo electrónico de la Comuna inválido' })
.optional() .optional()
.or(z.literal('')) .or(z.literal('')),
.nullable(),
communalCouncil: z communalCouncil: z
.string() .string()
.min(1, { message: 'Consejo Comunal es requerido' }), .min(1, { message: 'Consejo Comunal es requerido' }),
@@ -162,8 +159,7 @@ export const trainingSchema = z.object({
.string() .string()
.email({ message: 'Correo electrónico del Consejo Comunal inválido' }) .email({ message: 'Correo electrónico del Consejo Comunal inválido' })
.optional() .optional()
.or(z.literal('')) .or(z.literal('')),
.nullable(),
//Datos del Responsable OSP //Datos del Responsable OSP
ospResponsibleCedula: z ospResponsibleCedula: z
@@ -191,7 +187,7 @@ export const trainingSchema = z.object({
numberOfChildren: z.coerce.number().optional(), numberOfChildren: z.coerce.number().optional(),
//Datos adicionales //Datos adicionales
generalObservations: z.string().optional().nullable(), generalObservations: z.string().optional(),
//IMAGENES //IMAGENES
files: z.any().optional(), files: z.any().optional(),
@@ -210,6 +206,7 @@ export const trainingSchema = z.object({
updatedBy: z.number().optional().nullable(), updatedBy: z.number().optional().nullable(),
created_at: z.string().optional().nullable(), created_at: z.string().optional().nullable(),
updated_at: z.string().optional().nullable(), updated_at: z.string().optional().nullable(),
surveyStatus: z.string()
}); });
export type TrainingSchema = z.infer<typeof trainingSchema>; export type TrainingSchema = z.infer<typeof trainingSchema>;
@@ -228,11 +225,11 @@ export const getTrainingSchema = z.object({
mainProductiveActivity: z.string(), mainProductiveActivity: z.string(),
productiveActivity: z.string(), productiveActivity: z.string(),
productiveActivityOther: z.string(), productiveActivityOther: z.string(),
ospRif: z.string().optional().or(z.literal('')).nullable(), ospRif: z.string().optional().or(z.literal('')),
ospName: z.string().optional().or(z.literal('')).nullable(), ospName: z.string().optional().or(z.literal('')),
companyConstitutionYear: z.coerce.number(), companyConstitutionYear: z.coerce.number(),
currentStatus: z.string(), currentStatus: z.string(),
infrastructureMt2: z.string(), infrastructureMt2: z.string().optional(),
hasTransport: z hasTransport: z
.preprocess( .preprocess(
(val) => val === 'true' || val === true || val === 1 || val === '1', (val) => val === 'true' || val === true || val === 1 || val === '1',
@@ -250,7 +247,7 @@ export const getTrainingSchema = z.object({
.optional() .optional()
.nullable() .nullable()
.default(false), .default(false),
paralysisReason: z.string().optional().nullable(), paralysisReason: z.string().optional(),
//Datos del Equipamiento //Datos del Equipamiento
equipmentList: z.array(equipmentItemSchema).optional().default([]), equipmentList: z.array(equipmentItemSchema).optional().default([]),
//Datos de Producción //Datos de Producción
@@ -266,23 +263,23 @@ export const getTrainingSchema = z.object({
) )
.optional() .optional()
.default(false), .default(false),
externalCountry: z.string().optional().nullable(), externalCountry: z.string().optional(),
externalCity: z.string().optional().nullable(), externalCity: z.string().optional(),
externalDescription: z.string().optional().nullable(), externalDescription: z.string().optional(),
externalQuantity: z.coerce.string().or(z.number()).optional().nullable(), externalQuantity: z.coerce.string().or(z.number()).optional(),
externalUnit: z.string().optional().nullable(), externalUnit: z.string().optional(),
// Mano de obra // Mano de obra
womenCount: z.coerce.number(), womenCount: z.coerce.number(),
menCount: z.coerce.number(), menCount: z.coerce.number(),
//Detalles de la ubicación //Detalles de la ubicación
ospAddress: z.string(), ospAddress: z.string(),
ospGoogleMapsLink: z.string().optional().or(z.literal('')).nullable(), ospGoogleMapsLink: z.string().optional().or(z.literal('')),
communeName: z.string(), communeName: z.string(),
siturCodeCommune: z.string(), siturCodeCommune: z.string(),
communeRif: z.string().or(z.literal('')).nullable(), communeRif: z.string().or(z.literal('')),
communeSpokespersonName: z.string().or(z.literal('')).nullable(), communeSpokespersonName: z.string().or(z.literal('')),
communeSpokespersonPhone: z.string(), communeSpokespersonPhone: z.string(),
communeEmail: z.string().optional().or(z.literal('')).nullable(), communeEmail: z.string().optional().or(z.literal('')),
communalCouncil: z.string(), communalCouncil: z.string(),
siturCodeCommunalCouncil: z.string(), siturCodeCommunalCouncil: z.string(),
communalCouncilRif: z.string().optional(), communalCouncilRif: z.string().optional(),
@@ -292,14 +289,14 @@ export const getTrainingSchema = z.object({
//Datos del Responsable OSP //Datos del Responsable OSP
ospResponsibleCedula: z.string(), ospResponsibleCedula: z.string(),
ospResponsibleFullname: z.string(), ospResponsibleFullname: z.string(),
ospResponsibleRif: z.string().optional().nullable(), ospResponsibleRif: z.string().optional(),
civilState: z.string().optional().nullable(), civilState: z.string().optional(),
ospResponsiblePhone: z.string(), ospResponsiblePhone: z.string(),
ospResponsibleEmail: z.string(), ospResponsibleEmail: z.string(),
familyBurden: z.coerce.number().optional(), familyBurden: z.coerce.number().optional(),
numberOfChildren: z.coerce.number().optional(), numberOfChildren: z.coerce.number().optional(),
//Datos adicionales //Datos adicionales
generalObservations: z.string().optional().nullable(), generalObservations: z.string().optional(),
//no se envia la backend al crear ni editar el formulario //no se envia la backend al crear ni editar el formulario
state: z.number().nullable(), state: z.number().nullable(),
municipality: z.number().nullable(), municipality: z.number().nullable(),
@@ -314,8 +311,10 @@ export const getTrainingSchema = z.object({
updatedBy: z.number().optional().nullable(), updatedBy: z.number().optional().nullable(),
created_at: z.string().optional().nullable(), created_at: z.string().optional().nullable(),
updated_at: z.string().optional().nullable(), updated_at: z.string().optional().nullable(),
surveyStatus: z.string()
}); });
// Para mostrar datos
export const trainingApiResponseSchema = z.object({ export const trainingApiResponseSchema = z.object({
message: z.string(), message: z.string(),
data: z.array(getTrainingSchema), data: z.array(getTrainingSchema),
@@ -331,7 +330,8 @@ export const trainingApiResponseSchema = z.object({
}), }),
}); });
//
export const TrainingMutate = z.object({ export const TrainingMutate = z.object({
message: z.string(), message: z.string(),
data: trainingSchema, data: getTrainingSchema,
}); });