Front completo :D

This commit is contained in:
Elizabeth 2024-05-01 15:10:23 -05:00
parent 77058335a3
commit 556a8a2848
27 changed files with 1244 additions and 138 deletions

View File

@ -37,8 +37,27 @@ const navigationConfig: FuseNavItemType[] = [
type: 'item',
icon: 'heroicons-outline:clipboard-check',
url: 'product/list'
},
{
id: 'cliente-component',
title: 'Cliente',
translate: 'Cliente',
type: 'item',
icon: 'heroicons-outline:user',
url: 'client/list'
},
{
id: 'firma-component',
title: 'signature',
translate: 'Firma',
type: 'item',
icon: 'heroicons-outline:pencil',
url: 'signature/form'
}
];
export default navigationConfig;

View File

@ -10,6 +10,8 @@ import Error404Page from '../main/404/Error404Page';
import ProjectDashboardAppConfig from '../main/dashboard/project/ProjectDashboardAppConfig';
import ProductoConfigs from '../main/producto/ProductoConfig';
import InvoiceConfigs from '../main/invoice/InvoiceConfig';
import ClientConfig from '../main/client/ClientConfig';
import firmaConfigs from '../main/firmaElectronica/FirmaConfig';
const routeConfigs: FuseRouteConfigsType = [
SignOutConfig,
@ -17,7 +19,9 @@ const routeConfigs: FuseRouteConfigsType = [
SignUpConfig,
ProjectDashboardAppConfig,
...ProductoConfigs,
...InvoiceConfigs
...InvoiceConfigs,
...ClientConfig,
...firmaConfigs
];
/**

View File

@ -0,0 +1,37 @@
import DemoContent from '@fuse/core/DemoContent';
import FusePageSimple from '@fuse/core/FusePageSimple';
import { useTranslation } from 'react-i18next';
import { styled } from '@mui/material/styles';
import ClientRender from './ClientRender';
const Root = styled(FusePageSimple)(({ theme }) => ({
'& .FusePageSimple-header': {
backgroundColor: theme.palette.background.paper,
borderBottomWidth: 1,
borderStyle: 'solid',
borderColor: theme.palette.divider
},
'& .FusePageSimple-content': {},
'& .FusePageSimple-sidebarHeader': {},
'& .FusePageSimple-sidebarContent': {}
}));
function Client() {
const { t } = useTranslation('clients');
return(
<Root
header={
<div className='p-24'>
<h4>{t('CLIENTES')}</h4>
</div>
}
content={
<ClientRender></ClientRender>
}
/>
)
}
export default Client;

View File

@ -0,0 +1,10 @@
import { FuseRouteConfigsType } from "@fuse/utils/FuseUtils";
import DetalleClienteConfig from "./detalleCliente/DetalleClienteConfig";
import FormularioClienteConfig from "./formularioCliente/FormularioClienteConfig";
const clientConfigs: FuseRouteConfigsType = [
DetalleClienteConfig,
FormularioClienteConfig
]
export default clientConfigs;

View File

@ -0,0 +1,11 @@
import DetalleCliente from "./detalleCliente/DetalleCliente"
const ClientRender = () => {
return (
<div className="w-full p-12 pt-16 sm:pt-24 lg:ltr:pr-0 lg:rtl:pl-0">
<DetalleCliente></DetalleCliente>
</div>
)
}
export default ClientRender;

View File

@ -0,0 +1,9 @@
import ListDetalleClienteRender from './DetalleClienteRender'
const DetalleCliente = () => {
return (
<ListDetalleClienteRender/>
)
}
export default DetalleCliente;

View File

@ -0,0 +1,19 @@
import {lazy} from 'react';
const Cliente = lazy(() => import('./DetalleCliente'));
const DetalleClienteConfig = {
settings: {
layout: {
config: {}
}
},
routes: [
{
path: 'client/list',
element: <Cliente/>
}
]
};
export default DetalleClienteConfig;

View File

@ -0,0 +1,185 @@
import FusePageSimple from '@fuse/core/FusePageSimple';
import FuseSvgIcon from '@fuse/core/FuseSvgIcon';
import {
Button,
IconButton,
Paper,
Table,
TableBody,
TableCell,
TableHead,
TablePagination,
TableRow,
Typography,
styled
} from "@mui/material";
import clsx from 'clsx';
import { format } from 'date-fns';
import { useTranslation } from 'react-i18next';
import { Link } from 'react-router-dom';
import ResponsiveDialog from 'src/components/widgets/DialogDelete';
const Root = styled(FusePageSimple)(({ theme }) => ({
'& .FusePageSimple-header': {
backgroundColor: theme.palette.background.paper,
boxShadow: `inset 0 0 0 1px ${theme.palette.divider}`
}
}));
function ListDetalleClienteRender() {
const { t } = useTranslation('clients');
const columns = [
'id',
'Nombre Comercial',
'Razon Social',
'Identificación',
'Teléfono',
'Correo Electrónico',
'Acciones',
];
const rows = [
{
id: 111,
nombreComercial:'Susana Noroña',
razonSocial: 'Susana Noroña',
identificacion: '1720336948',
telefono: '0984294253',
correo: 'cammmmm@test.com',
action:true,
},
{
id: 555,
nombreComercial:'Camila Morales',
razonSocial: 'Camila Morales',
identificacion: '1720336948',
telefono: '0984294253',
correo: 'cammmmm@test.com',
action:true,
},
{
id: 777,
nombreComercial:'Cristian Hernandez',
razonSocial: 'Cristian Hernandez',
identificacion: '1720336948',
telefono: '0984294253',
correo: 'cammmmm@test.com',
action:true,
},
];
return (
<Root
header={
<div className="p-24">
<h4>{t('CLIENTES')}</h4>
</div>
}
content={
<Paper className="flex flex-col flex-auto p-24 shadow rounded-2 overflow-hidden m-10">
<div className="flex md:flex-row justify-between flex-col">
<div>
<Typography className="mr-16 text-lg font-medium tracking-tight leading-6 truncate">
{t('Detalle de clientes')}
</Typography>
</div>
<div>
<Button
size='small'
variant='contained'
color='secondary'
component={Link}
to={'/client/form'}
startIcon={
<FuseSvgIcon
className='text-48 text-white'
size={24}
color='action'
>
heroicons-outline:plus
</FuseSvgIcon>
}
>
Registrar Cliente
</Button>
</div>
</div>
<div className="table-responsive mt-24">
<Table className='simple w-full min-w-full h-full'>
<TableHead>
<TableRow>
{columns.map((column, index) => (
<TableCell key={index}>
<Typography
color="text.secondary"
className="font-semibold text-12 whitespace-nowrap"
>
{column}
</Typography>
</TableCell>
))}
</TableRow>
</TableHead>
<TableBody>
{rows.map((row, index) => (
<TableRow key={index}>
{Object.entries(row).map(([key, value]) => {
switch (key) {
case 'action': {
return (
<TableCell
key={key}
component='th'
scope='row'
className='text-center'
>
<div className='flex items-center justify-left'>
<Typography>{value}</Typography>
<IconButton size='small' color='inherit'>
<FuseSvgIcon>
heroicons-outline:pencil-alt
</FuseSvgIcon>
</IconButton>
<ResponsiveDialog></ResponsiveDialog>
</div>
</TableCell>
);
}
default: {
return (
<TableCell key={key} component='th' scope='row'>
<Typography>{value}</Typography>
</TableCell>
);
}
}
})}
</TableRow>
))}
</TableBody>
</Table>
</div>
</Paper>
}
/>
);
}
export default ListDetalleClienteRender;

View File

@ -0,0 +1,73 @@
export interface Client{
nombreComercial: string;
razonSocial: string;
identificacion: string;
direccion: string;
telefono: string;
correoElectronico: string;
}
/* const FormularioClienteRender = () => {
return (
<Card className="m-20 p-24">
<CardHeader title="Registro cliente" className="text-16 font-bold" />
<Divider />
<Formik
initialValues={{
nombreComercial: "",
razonSocial: "",
identificacion: "",
direccion: "",
telefono: "",
correoElectronico: "",
}}
validationSchema={validationSchema}
onSubmit={(values, { setSubmitting }) => {
// Aquí manejas la lógica de envío del formulario
console.log(values);
setSubmitting(false);
}}
>
{({ isSubmitting }) => (
<Form>
<CardContent className="flex">
<Grid className="grid grid-cols-1 sm:grid-cols-6 gap-10 w-full min-w-0">
<Field
as={TextField}
className="sm:col-span-3 lg:col-span-3 mt-20"
required
label="Nombre Comercial"
id="nombreComercial"
name="nombreComercial"
variant="outlined"
fullWidth
size="small"
/>
<ErrorMessage
name="nombreComercial"
component="div"
className="text-red-500"
/>
{/* Agrega el resto de los campos y sus mensajes de error aquí */}
{/* <Button
className="w-320"
variant="contained"
size="small"
color="secondary"
type="submit"
disabled={isSubmitting}
>
Guardar
</Button>
</Grid>
</CardContent>
</Form>
)}
</Formik>
</Card>
);
};
*/}

View File

@ -0,0 +1,10 @@
import React from 'react'
import FormularioClienteRender from './FormularioClienteRender'
const FormularioCliente = () => {
return (
<FormularioClienteRender/>
)
}
export default FormularioCliente

View File

@ -0,0 +1,19 @@
import {lazy} from 'react';
const FormularioCliente = lazy(() => import('./FormularioCliente'));
const FormularioClienteConfig = {
settings: {
layout: {
config: {}
}
},
routes: [
{
path: 'client/form',
element: <FormularioCliente/>
}
]
};
export default FormularioClienteConfig;

View File

@ -0,0 +1,188 @@
import FusePageSimple from "@fuse/core/FusePageSimple";
import {
Autocomplete,
Card,
CardActions,
CardContent,
CardHeader,
Divider,
TextField,
styled,
Button,
Grid,
} from "@mui/material";
import { useState } from "react";
import { Formik, Form, Field, ErrorMessage } from "formik";
import * as Yup from "yup";
const FormularioClienteRender = () => {
const [datosCargados, setDatosCargados] = useState(false);
const validationSchema = Yup.object().shape({
nombreComercial: Yup.string().required('El nombre comercial es requerido'),
razonSocial: Yup.string().required('La razón social es requerida'),
identificacion: Yup.string()
.required('La cédula o RUC es requerida')
.min(10, 'La cédula debe tener 10 digitos')
.max(13, 'El RUC debe tener 13 digitos'),
direccion: Yup.string().required('La dirección es requerida'),
telefono: Yup.string()
.required('El teléfono es requerido')
.matches(/^[0-9]{10}$/, 'El teléfono debe ser un número de 10 dígitos'),
correoElectronico: Yup.string()
.required('El correo electrónico es requerido')
.email('Ingrese un correo electrónico válido'),
})
return (
<Card className="m-20 p-24">
<CardHeader title="Registro cliente" className="text-16 font-bold"/>
<Divider />
<Formik
initialValues = {{
nombreComercial: "",
razonSocial: "",
identificacion: "",
direccion:"",
telefono: "",
correoElectronico: "",
}}
validationSchema={validationSchema}
onSubmit={(values, { setSubmitting }) => {
console.log(values);
setSubmitting(false);
}}
>
{({ isSubmitting, touched, errors }) => (
<Form>
<CardContent className="flex">
<Grid className="grid grid-cols-1 sm:grid-cols-6 gap-10 w-full min-w-0">
<div className="mt-20 sm:col-span-3 lg:col-span-3">
<Field
as={TextField}
label="Nombre Comercial"
name="nombreComercial"
variant="outlined"
fullWidth
size="small"
error={touched.nombreComercial && !! errors.nombreComercial}
/>
<ErrorMessage
name="nombreComercial"
component ='div'
className="text-red-500 text-md ml-12 pt-4"
/>
</div>
<div className="mt-20 sm:col-span-3 lg:col-span-3">
<Field
as={TextField}
label="Razón Social"
name="razonSocial"
variant="outlined"
fullWidth
size="small"
error={touched.razonSocial && !! errors.razonSocial}
/>
<ErrorMessage
name="razonSocial"
component ='div'
className="text-red-500 text-md ml-12 pt-4"
/>
</div>
<div className="mt-10 sm:col-span-3 lg:col-span-3">
<Field
as={TextField}
label="Cédula o RUC"
name="identificacion"
variant="outlined"
fullWidth
size="small"
error={touched.identificacion && !!errors.identificacion}
/>
<ErrorMessage
name="identificacion"
component="div"
className="text-red-500 text-md ml-12 pt-4"
/>
</div>
<div className="mt-10 sm:col-span-3 lg:col-span-3">
<Field
as={TextField}
label="Dirección"
name="direccion"
variant="outlined"
fullWidth
size="small"
error={touched.direccion && !!errors.direccion}
/>
<ErrorMessage
name="direccion"
component="div"
className="text-red-500 text-md ml-12 pt-4"
/>
</div>
<div className="mt-10 sm:col-span-3 lg:col-span-3">
<Field
as={TextField}
label="Teléfono"
name="telefono"
variant="outlined"
fullWidth
size="small"
error={touched.telefono && !!errors.telefono}
/>
<ErrorMessage
name="telefono"
component="div"
className="text-red-500 text-md ml-12 pt-4"
/>
</div>
<div className="mt-10 sm:col-span-3 lg:col-span-3">
<Field
as={TextField}
label="Correo Electronico"
name="correoElectronico"
variant="outlined"
fullWidth
size="small"
error={touched.correoElectronico && !!errors.correoElectronico}
/>
<ErrorMessage
name="correoElectronico"
component="div"
className="text-red-500 text-md ml-12 pt-4"
/>
</div>
</Grid>
</CardContent>
<CardActions className="mt-15">
<Button
className="w-320"
variant="contained"
size="small"
color="secondary"
type="submit"
disabled={isSubmitting}
>
Guardar{" "}
</Button>
</CardActions>
</Form>
)}
</Formik>
</Card>
)
};
export default FormularioClienteRender;

View File

@ -0,0 +1,37 @@
import DemoContent from '@fuse/core/DemoContent';
import FusePageSimple from '@fuse/core/FusePageSimple';
import { useTranslation } from 'react-i18next';
import { styled } from '@mui/material/styles';
import FirmaRender from './FirmaRender';
const Root = styled(FusePageSimple)(({ theme }) => ({
'& .FusePageSimple-header': {
backgroundColor: theme.palette.background.paper,
borderBottomWidth: 1,
borderStyle: 'solid',
borderColor: theme.palette.divider
},
'& .FusePageSimple-content': {},
'& .FusePageSimple-sidebarHeader': {},
'& .FusePageSimple-sidebarContent': {}
}));
function Firma() {
const { t } = useTranslation('signature');
return(
<Root
header={
<div className='p-24'>
<h4>{t('FIRMA ELECTRONICA')}</h4>
</div>
}
content={
<FirmaRender></FirmaRender>
}
/>
)
}
export default Firma;

View File

@ -0,0 +1,8 @@
import { FuseRouteConfigsType } from "@fuse/utils/FuseUtils";
import FormularioFirmaConfig from "./formularioFirma/FormularioFirmaConfig";
const firmaConfigs: FuseRouteConfigsType = [
FormularioFirmaConfig
]
export default firmaConfigs;

View File

@ -0,0 +1,11 @@
import FormularioFirma from "./formularioFirma/FormularioFirma";
const ClientRender = () => {
return (
<div className="w-full p-12 pt-16 sm:pt-24 lg:ltr:pr-0 lg:rtl:pl-0">
<FormularioFirma></FormularioFirma>
</div>
)
}
export default ClientRender;

View File

@ -0,0 +1,10 @@
import React from 'react'
import FormularioFirmaRender from './FormularioFirmaRender'
const FormularioFirma = () => {
return (
<FormularioFirmaRender/>
)
}
export default FormularioFirma

View File

@ -0,0 +1,19 @@
import {lazy} from 'react';
const FormularioFirma = lazy(() => import('./FormularioFirma'));
const FormularioClienteConfig = {
settings: {
layout: {
config: {}
}
},
routes: [
{
path: 'signature/form',
element: <FormularioFirma/>
}
]
};
export default FormularioClienteConfig;

View File

@ -0,0 +1,200 @@
import { useState } from "react";
import { Formik, Form, Field, ErrorMessage } from "formik";
import * as Yup from "yup";
import { Card, CardActions, CardContent, CardHeader, Button, TextField } from "@mui/material";
const FormularioClienteRender = () => {
const [file, setFile] = useState(null);
const validationSchema = Yup.object().shape({
contrasena: Yup.string()
.required("La contraseña es requerida"),
/* .min(5, 'La contraseña debe tener como mínimo 8 caracteres')
.max(10, 'La contraseña debe tener como máximo 10 caracteres')
.matches(/[0-9]/, 'La contraseña requiere al menos un número')
.matches(/[a-z]/, 'La contraseña requiere al menos una letra minuscula')
.matches(/[A-Z]/, 'La contraseña requiere al menos una letra mayuscula'), */
validarContrasena: Yup.string()
.required("La verificación de la contraseña es requerida")
.oneOf([Yup.ref('contrasena'), null], 'La contraseña debe coincidir con la anterior'),
fechaCaducacion: Yup.date()
.required("La fecha de caducación es requerida")
.min(new Date(), "La fecha de caducación debe ser posterior a la fecha actual"),
archivo: Yup.mixed()
.required("El archivo es requerido")
.test("fileFormat", "Solo se permiten archivos PDF", (value) => {
if (value) {
return value.type === "application/pdf";
}
return true;
}),
});
const handleFileDrop = (event, setFieldValue) => {
event.preventDefault();
const droppedFile = event.dataTransfer.files[0];
setFile(droppedFile);
setFieldValue("archivo", droppedFile);
};
const handleFileChange = (event, setFieldValue) => {
const selectedFile = event.currentTarget.files[0];
setFile(selectedFile);
setFieldValue("archivo", selectedFile);
};
return (
<div className="p-52 ">
<h1 className="text-center">CONFIGURACIÓN DE LA FIRMA ELECTRÓNICA</h1>
<div className="flex justify-center items-center h-full">
<Card className="p-10 text-center w-2/3">
<CardHeader title="Subir Firma" className="text-16 font-bold" />
<h5>Para poder registrar su firma electrónica deberá</h5>
<h5>ingresar la siguiente información</h5>
<CardContent className="p-10">
<Formik
initialValues={{
contrasena: "",
validarContrasena:"",
fechaCaducacion: "",
archivo: "",
}}
validationSchema={validationSchema}
onSubmit={(values, { setSubmitting }) => {
console.log(values);
setSubmitting(false);
}}
>
{({ isSubmitting, touched, errors, setFieldValue }) => (
<Form>
<div className="pt-10">
<Field
as={TextField}
label="Contraseña"
name="contrasena"
variant="outlined"
fullWidth
size="small"
type="password"
error={touched.contrasena && !! errors.contrasena}
/>
<ErrorMessage
name="contrasena"
component="div"
className="text-red-500 text-md ml-12 pt-4 text-left"
/>
</div>
<div className="pt-14">
<Field
as={TextField}
label="Verificación Contraseña"
name="validarContrasena"
variant="outlined"
fullWidth
size="small"
type="password"
error={touched.validarContrasena && errors.validarContrasena}
/>
<ErrorMessage
name="validarContrasena"
component="div"
className="text-red-500 text-md ml-12 pt-4 text-left"
/>
</div>
<div className="pt-24">
<Field
as={TextField}
label="Fecha de caducidad"
name="fechaCaducacion"
variant="outlined"
fullWidth
size="small"
type="date"
error={touched.fechaCaducacion && !! errors.fechaCaducacion}
InputLabelProps={{
shrink: true,
}}
/>
<ErrorMessage
name="fechaCaducacion"
component="div"
className="text-red-500 text-md ml-12 pt-4 text-left"
/>
</div>
<div className="pt-20" onDrop={(event) => handleFileDrop(event, setFieldValue)} onDragOver={(event) => event.preventDefault()}>
<div className="w-full">
<label htmlFor="archivo" className="flex flex-col items-center justify-center w-full h-96 border-2 border-gray-300 border-dashed rounded-lg cursor-pointer bg-gray-50 dark:hover:bg-gray-800 dark:bg-gray-700 hover:bg-gray-100 dark:border-gray-600 dark:hover:border-gray-500">
<input
id="archivo"
name="archivo"
type="file"
accept=".pdf"
className="hidden"
onChange={(event) => handleFileChange(event, setFieldValue)}
/>
<div className="flex flex-col items-center justify-center pt-5 pb-6 h-96">
<svg
className="w-20 h-15 mb-1 text-gray-500 dark:text-gray-400"
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 20 16"
>
<path
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M13 13h3a3 3 0 0 0 0-6h-.025A5.56 5.56 0 0 0 16 6.5 5.5 5.5 0 0 0 5.207 5.021C5.137 5.017 5.071 5 5 5a4 4 0 0 0 0 8h2.167M10 15V6m0 0L8 8m2-2 2 2"
/>
</svg>
<p className="mb-2 text-sm text-gray-500 dark:text-gray-400 pt-8">
<span className="font-semibold">Haga clic para cargar o arrastre y suelte </span>
</p>
<p className="text-s text-gray-500 dark:text-gray-400" id="file-name-display">
{file ? file.name : "Solo se permiten archivos .pdf"}
</p>
</div>
</label>
</div>
<ErrorMessage
name="archivo"
component="div"
className="text-red-500 text-md ml-12 pt-4 text-left"
/>
</div>
<CardActions className="mt-15 justify-center p-8">
<Button
className="w-full sm:w-320"
variant="contained"
size="small"
color="secondary"
type="submit"
disabled={isSubmitting}
>
{isSubmitting ? "Subiendo..." : "Subir"}
</Button>
</CardActions>
</Form>
)}
</Formik>
</CardContent>
</Card>
</div>
</div>
);
};
export default FormularioClienteRender;

View File

@ -9,4 +9,4 @@ const invoiceConfigs: FuseRouteConfigsType = [
GenerateInvoiceConfig
]
export default invoiceConfigs;
export default invoiceConfigs;

View File

@ -19,13 +19,21 @@ function AddClient({ open, setOpen, handleSelectClient }: Props) {
telefono: '',
correo: ''
},
validationSchema: Yup.object({
nombreComercial: Yup.string().required('El campo es Obligatorio'),
razonSocial: Yup.string().required('El campo es Obligatorio'),
identificacion: Yup.string().required('El campo es Obligatorio'),
direccion: Yup.string().required('El campo es Obligatorio'),
telefono: Yup.string().required('El campo es Obligatorio'),
correo: Yup.string().required('El campo es Obligatorio').email('Correo no valido')
nombreComercial: Yup.string().required('El nombre comercial es requerido'),
razonSocial: Yup.string().required('La razón social es requerida'),
identificacion: Yup.string()
.required('La cédula o RUC es requerida')
.min(10, 'La cédula debe tener 10 digitos')
.max(13, 'El RUC debe tener 13 digitos'),
direccion: Yup.string().required('La dirección es requerida'),
telefono: Yup.string()
.required('El teléfono es requerido')
.matches(/^[0-9]{10}$/, 'El teléfono debe ser un número de 10 dígitos'),
correo: Yup.string()
.required('El correo electrónico es requerido')
.email('Ingrese un correo electrónico válido'),
}),
onSubmit: (value) => {
handleSaveClient(value);

View File

@ -73,7 +73,7 @@ function AddClientRender({ open, setOpen, formik, handleOnChange }: Props) {
>
<TextField
size="small"
label="Identificación"
label="Cédula o RUC"
variant="outlined"
fullWidth
name="identificacion"

View File

@ -94,7 +94,7 @@ function ListDetalleProductoRender() {
];
return (
<Paper className="flex flex-col flex-auto p-24 shadow rounded-2 overflow-hidden mt-6">
<Paper className="flex flex-col flex-auto p-24 shadow rounded-2 overflow-hidden m-10">
<div className="flex md:flex-row justify-between flex-col">
<div>
<Typography className="mr-16 text-lg font-medium tracking-tight leading-6 truncate">
@ -148,7 +148,7 @@ function ListDetalleProductoRender() {
switch (key) {
case "artEstado": {
return (
<TableCell key={key} component="th" scope="row">
<TableCell key={key} component="th" scope="row" >
<Typography
className={clsx(
"inline-flex items-center font-bold text-10 px-10 py-2 rounded-full tracking-wide uppercase",
@ -169,21 +169,23 @@ function ListDetalleProductoRender() {
key={key}
component="th"
scope="row"
className="flex gap-5"
className="text-center"
>
<div>
<div className="flex items-center justify-left">
<Typography>{value}</Typography>
<IconButton size="small" color="inherit">
<FuseSvgIcon>
heroicons-outline:pencil-alt
</FuseSvgIcon>
</IconButton>
</div>
<div>
<ResponsiveDialog></ResponsiveDialog>
</div>
</TableCell>
);
}
default: {
return (
<TableCell key={key} component="th" scope="row">

View File

@ -6,4 +6,4 @@ const FormularioProducto = () => {
);
};
export default FormularioProducto;
export default FormularioProducto;

View File

@ -12,141 +12,214 @@ import {
Grid,
} from "@mui/material";
import { useState } from "react";
import { Formik, Form, Field, ErrorMessage } from "formik";
import * as Yup from "yup";
const FormularioProductoRender = () => {
const [formData, setFormData] = useState({
codigo: "",
tipo: "",
nombre: "",
descripcion: "",
stockMinimo: "",
margenGanancia: "",
estado: "",
});
const [datosCargados, setDatosCargados] = useState(false);
const cargarDatosDesdeBD = () => {
setDatosCargados(true);
};
const validationSchema = Yup.object().shape({
codigo: Yup.string().required("El código es requerido"),
tipo: Yup.string().required("El tipo es requerido"),
nombre: Yup.string().required("El nombre es requerido"),
estado: Yup.string().required("El estado es requerido"),
stockMinimo: Yup.string().required("El stock mínimo es requerido"),
margenGanancia: Yup.string().required("El margen de ganancia es requerido"),
descripcion: Yup.string().required("La descripción es requerida"),
});
return (
<Card className="m-20 p-24">
<CardHeader title="Registro producto" className="text-16 font-bold " />
<Divider />
<CardContent className="flex">
<Grid className="grid grid-cols-1 sm:grid-cols-6 gap-24 w-full min-w-0 p-24">
<TextField
className="mt-8 mb-16 sm:col-span-3 lg:col-span-3"
required
label="Código"
id="codigo"
name="codigo"
variant="outlined"
fullWidth
/>
<Autocomplete
className="mt-8 mb-16 sm:col-span-3 lg:col-span-3"
multiple
freeSolo
options={[]}
renderInput={(params) => (
<TextField
{...params}
placeholder="Seleccione el tipo de producto"
label="Tipo"
variant="outlined"
InputLabelProps={{
shrink: true,
}}
/>
)}
/>
<Formik
initialValues={{
codigo: "",
tipo: "",
nombre: "",
estado: "",
stockMinimo: "",
margenGanancia: "",
descripcion: "",
}}
<TextField
className="mt-8 mb-16 sm:col-span-3 lg:col-span-3"
required
label="Nombre"
id="nombre"
name="nombre"
variant="outlined"
fullWidth
/>
<Autocomplete
className="mt-8 mb-16 sm:col-span-3"
multiple
freeSolo
options={["Activo", "Inactivo"]}
renderInput={(params) => (
<TextField
{...params}
placeholder="Seleccione el estado del producto"
label="Estado"
variant="outlined"
InputLabelProps={{
shrink: true,
}}
/>
)}
/>
<TextField
className="mt-8 mb-16 sm:col-span-3 lg:col-span-3"
required
label="Stock Mínimo"
id="stockMinimo"
name="stockMinimo"
variant="outlined"
fullWidth
/>
<TextField
className="mt-8 mb-16 sm:col-span-3 md:col-span-3"
required
label="Margen de Ganancia"
id="margenGanancia"
name="margenGanancia"
variant="outlined"
fullWidth
/>
<TextField
className="mt-8 mb-16 sm:col-span-6 lg:col-span-6"
id="descripcion"
label="Descripción"
name="descripcion"
type="text"
multiline
rows={5}
variant="outlined"
fullWidth
/>
</Grid>
</CardContent>
<CardActions
className=""
validationSchema={validationSchema}
onSubmit={(values, { setSubmitting }) => {
console.log(values);
setSubmitting(false);
}}
>
<Button
className="w-320"
variant="contained"
size="small"
color="secondary"
>
Guardar{" "}
</Button>
{datosCargados && (
<Button
className="w-320"
variant="contained"
size="small"
color="primary"
>
Actualizar{" "}
</Button>
{({ isSubmitting, touched, errors, setFieldTouched }) => (
<Form>
<CardContent className="flex">
<Grid className="grid grid-cols-1 sm:grid-cols-6 gap-10 w-full min-w-0">
<div className="mt-20 sm:col-span-3 lg:col-span-3">
<Field
as={TextField}
label="Código"
name="codigo"
variant="outlined"
fullWidth
size="small"
error={touched.codigo && !!errors.codigo}
/>
<ErrorMessage
name="codigo"
component="div"
className="text-red-500 text-md ml-12 pt-4"
/>
</div>
<div className="mt-20 sm:col-span-3 lg:col-span-3">
<Autocomplete
multiple
size="small"
freeSolo
options={["Hola", "Chao"]}
onChange={() => setFieldTouched("tipo", true)}
renderInput={(params) => (
<TextField
{...params}
label="Seleccione el tipo de producto"
name="tipo"
variant="outlined"
error={touched.tipo && !!errors.tipo}
/>
)}
/>
<ErrorMessage
name="tipo"
component="div"
className="text-red-500 text-md ml-12 pt-4"
/>
</div>
<div className="mt-10 sm:col-span-3 lg:col-span-3">
<Field
as={TextField}
label="Nombre"
name="nombre"
variant="outlined"
fullWidth
size="small"
error={touched.nombre && !!errors.nombre}
/>
<ErrorMessage
name="nombre"
component="div"
className="text-red-500 text-md ml-12 pt-4"
/>
</div>
<div className="mt-10 sm:col-span-3 lg:col-span-3">
<Autocomplete
multiple
size="small"
freeSolo
options={["Activo", "Inactivo"]}
onChange={() => setFieldTouched("estado", true)}
renderInput={(params) => (
<TextField
{...params}
label="Seleccione el estado"
name="estado"
variant="outlined"
error={touched.estado && !!errors.estado}
/>
)}
/>
<ErrorMessage
name="estado"
component="div"
className="text-red-500 text-md ml-12 pt-4"
/>
</div>
<div className="mt-10 sm:col-span-3 lg:col-span-3">
<Field
as={TextField}
label="Stock Mínimo"
name="stockMinimo"
variant="outlined"
fullWidth
size="small"
error={touched.stockMinimo && !!errors.stockMinimo}
/>
<ErrorMessage
name="stockMinimo"
component="div"
className="text-red-500 text-md ml-12 pt-4"
/>
</div>
<div className="mt-10 sm:col-span-3 md:col-span-3">
<Field
as={TextField}
label="Margen de Ganancia"
name="margenGanancia"
variant="outlined"
fullWidth
size="small"
error={touched.margenGanancia && !!errors.margenGanancia}
/>
<ErrorMessage
name="margenGanancia"
component="div"
className="text-red-500 text-md ml-12 pt-4"
/>
</div>
<div className="mt-10 sm:col-span-6 lg:col-span-6">
<Field
as={TextField}
id="descripcion"
label="Descripción"
name="descripcion"
type="text"
multiline
rows={5}
variant="outlined"
fullWidth
size="small"
error={touched.descripcion && !!errors.descripcion}
/>
<ErrorMessage
name="descripcion"
component="div"
className="text-red-500 text-md ml-12 pt-4"
/>
</div>
</Grid>
</CardContent>
<CardActions className="">
<Button
className="w-320"
variant="contained"
size="small"
color="secondary"
type="submit"
disabled={isSubmitting}
>
Guardar
</Button>
{datosCargados && (
<Button
className="w-320"
variant="contained"
size="small"
color="primary"
>
Actualizar
</Button>
)}
</CardActions>
</Form>
)}
</CardActions>
</Formik>
</Card>
);
};

View File

@ -0,0 +1,81 @@
import * as React from 'react';
import { styled, alpha } from '@mui/material/styles';
import Box from '@mui/material/Box';
import Toolbar from '@mui/material/Toolbar';
import IconButton from '@mui/material/IconButton';
import Typography from '@mui/material/Typography';
import InputBase from '@mui/material/InputBase';
import FuseSvgIcon from '@fuse/core/FuseSvgIcon';
import FuseSearch from '@fuse/core/FuseSearch';
import { Card } from '@mui/material';
import { color } from '@mui/system';
const Search = styled('div')(({ theme }) => ({
position: 'relative',
borderRadius: theme.shape.borderRadius,
backgroundColor: alpha(theme.palette.common.black, 0.06),
'&:hover': {
/* backgroundColor: alpha(theme.palette.common.white, 0.25), */
},
width: '100%',
[theme.breakpoints.up('sm')]: {
/* marginLeft: theme.spacing(), */
width: 'auto',
},
}));
const SearchIconWrapper = styled('div')(({ theme }) => ({
padding: theme.spacing(0, 2),
height: '100%',
position: 'absolute',
pointerEvents: 'none',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}));
const StyledInputBase = styled(InputBase)(({ theme }) => ({
color: 'inherit',
width: '100%',
'& .MuiInputBase-input': {
padding: theme.spacing(1, 1, 1, 0),
// vertical padding + font size from searchIcon
paddingLeft: `calc(1em + ${theme.spacing(4)})`,
transition: theme.transitions.create('width'),
},
}));
function BuscarProducto() {
return (
<Box sx={{ flexGrow: 1 }}>
<div
className='bg-white'>
<Typography className="text-lg font-medium tracking-tight leading-6 truncate"
paddingTop={1}
paddingLeft={3}
>
{("Buscar producto")}
</Typography>
<Toolbar>
<Search>
<SearchIconWrapper>
<FuseSvgIcon
className="text-48 text-black"
size={24}
color="action"
>
heroicons-outline:search
</FuseSvgIcon>
</SearchIconWrapper>
<StyledInputBase
placeholder="Buscar Producto"
inputProps={{ 'aria-label': 'search' }}
/>
</Search>
</Toolbar>
</div>
</Box>
);
}
export default BuscarProducto;

View File

@ -0,0 +1,59 @@
import FuseSvgIcon from "@fuse/core/FuseSvgIcon";
import {
Button,
useMediaQuery,
useTheme,
Dialog,
DialogTitle,
DialogContent,
DialogContentText,
DialogActions,
IconButton,
} from "@mui/material";
import React from "react";
function ResponsiveDialog() {
const [open, setOpen] = React.useState(false);
const theme = useTheme();
const fullScreen = useMediaQuery(theme.breakpoints.down("sm"));
const handleClickOpen = () => {
setOpen(true);
};
const handleClose = () => {
setOpen(false);
};
return (
<div>
<IconButton size="small" color="default"
onClick={handleClickOpen}>
<FuseSvgIcon>heroicons-outline:trash</FuseSvgIcon>
</IconButton>
<Dialog
fullScreen={fullScreen}
open={open}
onClose={handleClose}
aria-labelledby="responsive-dialog-title"
>
<DialogTitle id="responsive-dialog-title">{"Confirmar"}</DialogTitle>
<DialogContent>
<DialogContentText>
Este elemento se eliminará permanentemente. ¿Deseas continuar?.
</DialogContentText>
</DialogContent>
<DialogActions>
<Button autoFocus onClick={handleClose} color="primary">
Cancelar
</Button>
<Button onClick={handleClose} color="primary" autoFocus>
Aceptar
</Button>
</DialogActions>
</Dialog>
</div>
);
}
export default ResponsiveDialog;

View File

@ -0,0 +1,14 @@
type DetalleProductoRow = {
artCodigo: number;
artNombre: string;
artDescripcion: string;
artStockMinimo: number;
artEstado: any;
};
type DetalleProductoType = {
columns: string[];
rows: DetalleProductoRow[];
};
export default DetalleProductoType;