286 lines
9.7 KiB
TypeScript
286 lines
9.7 KiB
TypeScript
'use client';
|
|
|
|
import { Badge } from '@repo/shadcn/badge';
|
|
import { Button } from '@repo/shadcn/button';
|
|
import {
|
|
Card,
|
|
CardContent,
|
|
CardHeader,
|
|
CardTitle,
|
|
} from '@repo/shadcn/components/ui/card';
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogDescription,
|
|
DialogFooter,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
} from '@repo/shadcn/components/ui/dialog';
|
|
import { X } from 'lucide-react';
|
|
import React, { useState } from 'react';
|
|
import { TrainingSchema } from '../schemas/training';
|
|
|
|
interface TrainingViewModalProps {
|
|
data: TrainingSchema | null;
|
|
isOpen: boolean;
|
|
onClose: () => void;
|
|
}
|
|
|
|
export function TrainingViewModal({
|
|
data,
|
|
isOpen,
|
|
onClose,
|
|
}: TrainingViewModalProps) {
|
|
const [selectedImage, setSelectedImage] = useState<string | null>(null);
|
|
|
|
if (!data) return null;
|
|
|
|
const DetailItem = ({ label, value }: { label: string; value: any }) => (
|
|
<div className="space-y-1">
|
|
<p className="text-sm font-medium text-muted-foreground">{label}</p>
|
|
<p className="text-sm font-semibold">{value || 'N/A'}</p>
|
|
</div>
|
|
);
|
|
|
|
const Section = ({
|
|
title,
|
|
children,
|
|
}: {
|
|
title: string;
|
|
children: React.ReactNode;
|
|
}) => (
|
|
<Card className="mb-4">
|
|
<CardHeader className="py-3">
|
|
<CardTitle className="text-lg">{title}</CardTitle>
|
|
</CardHeader>
|
|
<CardContent className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
{children}
|
|
</CardContent>
|
|
</Card>
|
|
);
|
|
|
|
return (
|
|
<>
|
|
<Dialog open={isOpen} onOpenChange={onClose}>
|
|
<DialogContent className="sm:max-w-[800px] overflow-y-auto [&>button:last-child]:hidden">
|
|
<DialogHeader>
|
|
<DialogTitle className="text-2xl font-bold">
|
|
Detalle de la Organización Socioproductiva
|
|
</DialogTitle>
|
|
<DialogDescription className="sr-only">
|
|
Resumen detallado de la información de la organización
|
|
socioproductiva incluyendo ubicación, responsable y registro
|
|
fotográfico.
|
|
</DialogDescription>
|
|
</DialogHeader>
|
|
|
|
<div className="mt-4 space-y-6">
|
|
{/* 1. Datos de la visita */}
|
|
<Section title="1. Datos de la visita">
|
|
<DetailItem
|
|
label="Nombre del Coordinador"
|
|
value={data.firstname}
|
|
/>
|
|
<DetailItem
|
|
label="Apellido del Coordinador"
|
|
value={data.lastname}
|
|
/>
|
|
<DetailItem
|
|
label="Fecha y hora de la visita"
|
|
value={
|
|
data.visitDate
|
|
? new Date(data.visitDate).toLocaleString()
|
|
: 'N/A'
|
|
}
|
|
/>
|
|
</Section>
|
|
|
|
{/* 2. Datos de la OSP */}
|
|
<Section title="2. Datos de la OSP">
|
|
<DetailItem label="Nombre" value={data.ospName} />
|
|
<DetailItem label="RIF" value={data.ospRif} />
|
|
<DetailItem label="Tipo" value={data.ospType} />
|
|
<DetailItem
|
|
label="Actividad Productiva"
|
|
value={data.productiveActivity}
|
|
/>
|
|
<DetailItem
|
|
label="Estatus"
|
|
value={
|
|
<Badge
|
|
variant={
|
|
data.currentStatus === 'ACTIVA' ? 'default' : 'secondary'
|
|
}
|
|
>
|
|
{data.currentStatus}
|
|
</Badge>
|
|
}
|
|
/>
|
|
<DetailItem
|
|
label="Año de Constitución"
|
|
value={data.companyConstitutionYear}
|
|
/>
|
|
<DetailItem
|
|
label="Cant. Productores"
|
|
value={data.producerCount}
|
|
/>
|
|
<DetailItem label="Cant. Productos" value={data.productCount} />
|
|
<div className="col-span-1 md:col-span-2 lg:col-span-3">
|
|
<DetailItem
|
|
label="Descripción del Producto"
|
|
value={data.productDescription}
|
|
/>
|
|
</div>
|
|
<DetailItem
|
|
label="Capacidad Instalada"
|
|
value={data.installedCapacity}
|
|
/>
|
|
<DetailItem
|
|
label="Capacidad Operativa"
|
|
value={data.operationalCapacity}
|
|
/>
|
|
<div className="col-span-1 md:col-span-2 lg:col-span-3">
|
|
<DetailItem
|
|
label="Requerimiento Financiero"
|
|
value={data.financialRequirementDescription}
|
|
/>
|
|
</div>
|
|
{data.paralysisReason && (
|
|
<div className="col-span-1 md:col-span-2 lg:col-span-3">
|
|
<DetailItem
|
|
label="Razones de paralización"
|
|
value={data.paralysisReason}
|
|
/>
|
|
</div>
|
|
)}
|
|
</Section>
|
|
|
|
{/* 3. Ubicación */}
|
|
<Section title="3. Detalles de la ubicación">
|
|
<DetailItem
|
|
label="Código SITUR Comuna"
|
|
value={data.siturCodeCommune}
|
|
/>
|
|
<DetailItem
|
|
label="Consejo Comunal"
|
|
value={data.communalCouncil}
|
|
/>
|
|
<DetailItem
|
|
label="Código SITUR Consejo Comunal"
|
|
value={data.siturCodeCommunalCouncil}
|
|
/>
|
|
<div className="col-span-1 md:col-span-2 lg:col-span-3">
|
|
<DetailItem label="Dirección OSP" value={data.ospAddress} />
|
|
</div>
|
|
</Section>
|
|
|
|
{/* 4. Responsable */}
|
|
<Section title="4. Datos del Responsable">
|
|
<DetailItem
|
|
label="Nombre Completo"
|
|
value={data.ospResponsibleFullname}
|
|
/>
|
|
<DetailItem label="Cédula" value={data.ospResponsibleCedula} />
|
|
<DetailItem label="RIF" value={data.ospResponsibleRif} />
|
|
<DetailItem label="Estado Civil" value={data.civilState} />
|
|
<DetailItem label="Teléfono" value={data.ospResponsiblePhone} />
|
|
<DetailItem label="Email" value={data.ospResponsibleEmail} />
|
|
<DetailItem label="Carga Familiar" value={data.familyBurden} />
|
|
<DetailItem
|
|
label="Número de Hijos"
|
|
value={data.numberOfChildren}
|
|
/>
|
|
</Section>
|
|
|
|
{/* 5. Observaciones */}
|
|
<Card>
|
|
<CardHeader className="py-3">
|
|
<CardTitle className="text-lg">
|
|
5. Observaciones Generales
|
|
</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<p className="text-sm whitespace-pre-wrap">
|
|
{data.generalObservations || 'Sin observaciones'}
|
|
</p>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* 6. Registro fotográfico */}
|
|
<Card>
|
|
<CardHeader className="py-3">
|
|
<CardTitle className="text-lg">
|
|
6. Registro fotográfico
|
|
</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-4">
|
|
{[data.photo1, data.photo2, data.photo3].map(
|
|
(photo, idx) =>
|
|
photo && (
|
|
<div
|
|
key={idx}
|
|
className="relative aspect-video rounded-md overflow-hidden cursor-pointer hover:opacity-90 transition-opacity bg-muted"
|
|
onClick={() => setSelectedImage(photo)}
|
|
>
|
|
<img
|
|
src={`${process.env.NEXT_PUBLIC_API_URL}${photo}`}
|
|
alt={`Registro ${idx + 1}`}
|
|
className="object-cover w-full h-full"
|
|
/>
|
|
</div>
|
|
),
|
|
)}
|
|
{![data.photo1, data.photo2, data.photo3].some(Boolean) && (
|
|
<p className="text-sm text-muted-foreground">
|
|
No hay registro fotográfico
|
|
</p>
|
|
)}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
|
|
<DialogFooter className="mt-6">
|
|
<Button onClick={onClose} variant="outline" className="w-32">
|
|
Cerrar
|
|
</Button>
|
|
</DialogFooter>
|
|
</DialogContent>
|
|
</Dialog>
|
|
|
|
{/* Lightbox */}
|
|
<Dialog
|
|
open={!!selectedImage}
|
|
onOpenChange={() => setSelectedImage(null)}
|
|
>
|
|
<DialogContent className="max-w-[95vw] max-h-[95vh] p-0 overflow-hidden bg-black/90 border-none [&>button:last-child]:hidden">
|
|
<DialogHeader className="sr-only">
|
|
<DialogTitle>Vista ampliada de la imagen</DialogTitle>
|
|
<DialogDescription>
|
|
Imagen ampliada del registro fotográfico de la organización.
|
|
</DialogDescription>
|
|
</DialogHeader>
|
|
<div className="relative w-full h-full flex items-center justify-center p-4">
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
className="absolute top-2 right-2 text-white hover:bg-white/20 z-10"
|
|
onClick={() => setSelectedImage(null)}
|
|
>
|
|
<X className="h-6 w-6" />
|
|
</Button>
|
|
{selectedImage && (
|
|
<img
|
|
src={`${process.env.NEXT_PUBLIC_API_URL}${selectedImage}`}
|
|
alt="Expanded view"
|
|
className="max-w-full max-h-[90vh] object-contain"
|
|
/>
|
|
)}
|
|
</div>
|
|
</DialogContent>
|
|
</Dialog>
|
|
</>
|
|
);
|
|
}
|