Overview
Quality Hub GINEZ is built with TypeScript for type safety. This reference documents all major type definitions.
All type definitions are extracted from lib/types.ts
Raw Materials (Materia Prima)
RawMaterial Interface
interface RawMaterial {
code: string
name: string
cas: string | null
transport_name: string | null
functional_category: string
chemical_family: string
disposition: string
provider: string | null
provider_code: string | null
lead_time_days: number | null
// Document links (generated from FILE_IDs)
tds_view_url: string | null
tds_download_url: string | null
sds_view_url: string | null
sds_download_url: string | null
coa_cedis_view_url: string | null
coa_cedis_download_url: string | null
coa_branches_view_url: string | null
coa_branches_download_url: string | null
label_view_url: string | null
label_download_url: string | null
}
Source: lib/types.ts:2-24
Fields
Unique material code identifier
CAS Registry Number for chemical identification
Official transport/shipping name
Functional category (e.g., “Surfactant”, “Preservative”)
Chemical family classification
Current disposition/status
Provider’s internal code for this material
Lead time in days for procurement
Finished Products (Producto Terminado)
FinishedProduct Interface
interface FinishedProduct {
family: string
family_slug: string
category: string
category_slug: string
sku_code: string
name: string
base_product: string
variant: string
status: "Activo" | "Inactivo"
updated_at: string
// Document links
tds_view_url: string | null
tds_download_url: string | null
sds_view_url: string | null
sds_download_url: string | null
coa_view_url: string | null
coa_download_url: string | null
label_view_url: string | null
label_download_url: string | null
}
Source: lib/types.ts:27-47
Fields
Product family name (e.g., “Cuidado del Hogar”)
URL-safe family identifier
URL-safe category identifier
Product SKU/code (e.g., “LIMLIM”, “TRALIM”)
Product variant specification
status
'Activo' | 'Inactivo'
required
Current product status
Last update timestamp (ISO format)
Product Organization
interface FinishedProductsData {
families: FamilyGroup[]
}
interface FamilyGroup {
name: string
slug: string
categories: CategoryGroup[]
products?: FinishedProduct[]
}
interface CategoryGroup {
name: string
slug: string
products: FinishedProduct[]
}
Source: lib/types.ts:50-65
Family and Category Mappings
FAMILIES Constant
const FAMILIES: Record<string, string[]> = {
"Cuidado del Hogar": [
"Limpiador Líquido Multiusos",
"Detergente líquido para Trates",
"Especialidad Cuidado del Hogar",
"Aromatizantes Ambientales",
"Base de Limpiador Líquido Multiusos",
"Base de Aromatizantes Ambientales",
],
"Lavandería": [
"Detergente Líquido para Ropa",
"Suavizantes Líquidos para Telas",
"Especialidad Lavandería",
],
"Línea Automotriz": ["Automotriz"],
"Línea Antibacterial": ["Antibacterial"],
"Cuidado Personal": [
"Jabón Líquido para Manos",
"Shampoo Capilar",
"Enjuague Capilar",
"Crema Corporal",
],
}
Source: lib/types.ts:68-90
This constant maps product families to their constituent categories.
Validation Schemas
All validation schemas use Zod for runtime type checking.
LoginSchema
const LoginSchema = z.object({
email: z
.string()
.min(1, "El correo es obligatorio")
.email("Formato de correo inválido")
.max(255, "El correo no puede exceder 255 caracteres"),
password: z
.string()
.min(6, "La contraseña debe tener al menos 6 caracteres")
.max(128, "La contraseña no puede exceder 128 caracteres"),
})
type LoginInput = z.infer<typeof LoginSchema>
Source: lib/validations.ts:8-18
RegisterSchema
const RegisterSchema = LoginSchema.extend({
full_name: z
.string()
.min(2, "El nombre debe tener al menos 2 caracteres")
.max(100, "El nombre no puede exceder 100 caracteres")
.regex(
/^[a-zA-ZáéíóúÁÉÍÓÚñÑüÜ\s]+$/,
"El nombre solo puede contener letras y espacios"
),
role: z.enum(
[
"preparador",
"gerente_sucursal",
"director_operaciones",
"gerente_calidad",
"mostrador",
"cajera",
"director_compras",
],
{ errorMap: () => ({ message: "Selecciona un rol válido" }) }
),
sucursal: z
.string()
.min(1, "La sucursal es obligatoria")
.refine(
(val) => SUCURSALES.includes(val),
"Selecciona una sucursal válida"
),
})
type RegisterInput = z.infer<typeof RegisterSchema>
Source: lib/validations.ts:20-34
BitacoraSchema
const BitacoraSchema = z.object({
sucursal: z
.string()
.min(1, "La sucursal es obligatoria")
.refine(
(val) => SUCURSALES.includes(val),
"Selecciona una sucursal válida"
),
nombre_preparador: z
.string()
.min(1, "El nombre del preparador es obligatorio")
.max(200, "El nombre no puede exceder 200 caracteres"),
fecha_fabricacion: z
.string()
.min(1, "La fecha de fabricación es obligatoria")
.regex(/^\d{4}-\d{2}-\d{2}$/, "Formato de fecha inválido (YYYY-MM-DD)"),
codigo_producto: z
.string()
.min(1, "El código del producto es obligatorio")
.max(20, "Código de producto inválido")
.regex(
/^[A-Z0-9-]+$/,
"El código solo puede contener letras mayúsculas, números y guiones"
),
tamano_lote: z
.string()
.min(1, "El tamaño de lote es obligatorio")
.refine(
(val) => !isNaN(parseFloat(val)) && parseFloat(val) > 0,
"El tamaño de lote debe ser un número positivo"
),
ph: z
.string()
.refine(
(val) => {
if (val === "") return true // Optional when empty
const num = parseFloat(val)
return !isNaN(num) && num >= 0 && num <= 14
},
"El pH debe estar entre 0 y 14"
)
.default(""),
solidos_medicion_1: z
.string()
.refine(
(val) => {
if (val === "") return true
const num = parseFloat(val)
return !isNaN(num) && num >= 0 && num <= 55
},
"El % de sólidos debe estar entre 0 y 55"
)
.default(""),
solidos_medicion_2: z
.string()
.refine(
(val) => {
if (val === "") return true
const num = parseFloat(val)
return !isNaN(num) && num >= 0 && num <= 55
},
"El % de sólidos debe estar entre 0 y 55"
)
.default(""),
temp_med1: z.string().default(""),
temp_med2: z.string().default(""),
viscosidad_seg: z.string().default(""),
temperatura: z.string().default(""),
color: z.enum(["CONFORME", "NO CONFORME"], {
errorMap: () => ({ message: "Selecciona conformidad del color" }),
}),
apariencia: z.string().min(1, "La apariencia es obligatoria"),
aroma: z.enum(["CONFORME", "NO CONFORME"], {
errorMap: () => ({ message: "Selecciona conformidad del aroma" }),
}),
contaminacion_microbiologica: z.enum(["SIN PRESENCIA", "CON PRESENCIA"], {
errorMap: () => ({
message: "Selecciona estado de contaminación",
}),
}),
observaciones: z
.string()
.max(1000, "Las observaciones no pueden exceder 1000 caracteres")
.default(""),
})
type BitacoraInput = z.infer<typeof BitacoraSchema>
Source: lib/validations.ts:60-115
Validation Helpers
function validateForm<T>(
schema: z.ZodSchema<T>,
data: unknown
):
| { success: true; data: T }
| { success: false; errors: Record<string, string> }
Source: lib/validations.ts:133-151
Validates data against a Zod schema and returns either the parsed data or formatted errors.
getFirstError Function
function getFirstError(errors: Record<string, string>): string
Source: lib/validations.ts:158-161
Returns the first error message from a validation result, useful for toast notifications.
Usage Example
import { BitacoraSchema, validateForm } from '@/lib/validations'
const result = validateForm(BitacoraSchema, formData)
if (result.success) {
// Use result.data (type-safe BitacoraInput)
await saveToDatabase(result.data)
} else {
// Display result.errors
console.error(result.errors)
}
Source Files
- Type Definitions:
lib/types.ts
- Validation Schemas:
lib/validations.ts
- Production Constants:
lib/production-constants.ts