82 changed files with 40452 additions and 0 deletions
@ -0,0 +1,45 @@ |
|||
# Instalación y backup de GITEA |
|||
|
|||
En esta documentación se detallará como realizar la instalación de GITEA mediante docker y también como realizar un backup del mismo o restaurarlo mendiando un archivo .sql. El tiempo estimado de descarga e instalación de la base de datos y el servicio GITEA mediante docker es de 3:30 minutos en una Raspberry. |
|||
|
|||
|
|||
|
|||
### Pre-requisitos 📋 |
|||
|
|||
_Para poder realizar la instalación de gitea es necesario tener instalado en nuestro terminal Docker y Docker Compose. Acceda a [Instalación de docker y docker compose](http://fabrica.faniot.ar:90/Soporte/docker-raspberry) para más detalles._ |
|||
|
|||
|
|||
### Instalación 🔧 |
|||
|
|||
_Se deberá ejecutar el archivo docker-compose.yml para que este comience el proceso de descarga e instalación de GITEA y la base de datos Postgres._ |
|||
|
|||
|
|||
|
|||
``` |
|||
docker-compose up -d |
|||
``` |
|||
|
|||
|
|||
_Una vez terminado el servicio quedará establecido en el puerto 3000 por defecto, puede cambiarse este puerto por otro editando el archivo docker-compose.yml._ |
|||
|
|||
|
|||
## Backup 💽 |
|||
_Para poder realizar o cargar un backcup es necesario haber instalado previamente el servidor gitea con su base de datos postgres mediante docker._ |
|||
|
|||
_Una vez descargado el archivo "backup-gitea.sh" deberá ejecutarlo en su terminal de la siguiente manera:_ |
|||
|
|||
``` |
|||
sudo sh backup-gitea.sh |
|||
``` |
|||
|
|||
_Una vez ejecutado siga las instrucciones provistas por el script para poder realizar la carga o descarga de su backup de la base de datos Postgres._ |
|||
|
|||
## Autores ✒️ |
|||
|
|||
|
|||
* **Matias Gonzalez** - desarrollo de script y documentación - [matias.gonzalez](http://fabrica.faniot.ar:90/matias.gonzalez) |
|||
|
|||
|
|||
|
|||
|
|||
--- |
|||
@ -0,0 +1 @@ |
|||
REACT_APP_API='http://192.168.1.18:1997' |
|||
@ -0,0 +1,2 @@ |
|||
node_modules |
|||
build |
|||
File diff suppressed because it is too large
@ -0,0 +1,57 @@ |
|||
{ |
|||
"name": "crud-react", |
|||
"version": "0.1.0", |
|||
"private": true, |
|||
"dependencies": { |
|||
"@emotion/react": "^11.7.1", |
|||
"@emotion/styled": "^11.6.0", |
|||
"@mui/icons-material": "^5.3.1", |
|||
"@mui/material": "^5.4.0", |
|||
"@mui/x-data-grid": "^5.5.0", |
|||
"@testing-library/jest-dom": "^5.12.0", |
|||
"@testing-library/react": "^11.2.7", |
|||
"@testing-library/user-event": "^12.8.3", |
|||
"animate.css": "^4.1.1", |
|||
"axios": "^0.21.1", |
|||
"lottie-react": "^2.2.1", |
|||
"multiselect-react-dropdown": "^2.0.17", |
|||
"react": "^17.0.2", |
|||
"react-dom": "^17.0.2", |
|||
"react-editext": "^4.2.1", |
|||
"react-pro-sidebar": "^0.7.1", |
|||
"react-redux": "^7.2.6", |
|||
"react-router-dom": "^5.2.0", |
|||
"react-scripts": "^5.0.0", |
|||
"reakit": "^1.3.11", |
|||
"redux": "^4.1.2", |
|||
"redux-devtools-extension": "^2.13.9", |
|||
"redux-thunk": "^2.4.1", |
|||
"socket.io-client": "^4.4.1", |
|||
"styled-components": "^5.3.3", |
|||
"web-vitals": "^1.1.2" |
|||
}, |
|||
"scripts": { |
|||
"start": "react-scripts start", |
|||
"build": "react-scripts build", |
|||
"test": "react-scripts test", |
|||
"eject": "react-scripts eject" |
|||
}, |
|||
"eslintConfig": { |
|||
"extends": [ |
|||
"react-app", |
|||
"react-app/jest" |
|||
] |
|||
}, |
|||
"browserslist": { |
|||
"production": [ |
|||
">0.2%", |
|||
"not dead", |
|||
"not op_mini all" |
|||
], |
|||
"development": [ |
|||
"last 1 chrome version", |
|||
"last 1 firefox version", |
|||
"last 1 safari version" |
|||
] |
|||
} |
|||
} |
|||
|
After Width: | Height: | Size: 4.2 KiB |
@ -0,0 +1,9 @@ |
|||
.container-fluid, |
|||
.row, |
|||
.col-6, |
|||
.col-12, |
|||
.col-4, |
|||
.col-2 { |
|||
margin: 0px; |
|||
padding: 0px; |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="en"> |
|||
<head> |
|||
<meta charset="utf-8" /> |
|||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" /> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1" /> |
|||
<meta name="theme-color" content="#000000" /> |
|||
<meta |
|||
name="description" |
|||
content="Web site created using create-react-app" |
|||
/> |
|||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> |
|||
|
|||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> |
|||
|
|||
<link rel="stylesheet" type="text/css" href="/style.css" /> |
|||
|
|||
<link |
|||
rel="stylesheet" |
|||
href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" |
|||
/> |
|||
|
|||
<title>FanStock</title> |
|||
</head> |
|||
<body> |
|||
<noscript>You need to enable JavaScript to run this app.</noscript> |
|||
<div id="root"></div> |
|||
</body> |
|||
</html> |
|||
@ -0,0 +1,15 @@ |
|||
{ |
|||
"short_name": "FanStock", |
|||
"name": "FanStock", |
|||
"icons": [ |
|||
{ |
|||
"src": "favicon.ico", |
|||
"sizes": "64x64 32x32 24x24 16x16", |
|||
"type": "image/x-icon" |
|||
} |
|||
], |
|||
"start_url": ".", |
|||
"display": "standalone", |
|||
"theme_color": "#000000", |
|||
"background_color": "#ffffff" |
|||
} |
|||
@ -0,0 +1,3 @@ |
|||
# https://www.robotstxt.org/robotstxt.html |
|||
User-agent: * |
|||
Disallow: |
|||
@ -0,0 +1,238 @@ |
|||
/* futureColor: #1d1d1d */ |
|||
|
|||
* { |
|||
margin: 0; |
|||
padding: 0; |
|||
list-style: none; |
|||
text-decoration: none; |
|||
border: none; |
|||
outline: none; |
|||
font-family: "Roboto", sans-serif; |
|||
} |
|||
|
|||
body { |
|||
background: #11181b; |
|||
} |
|||
|
|||
.link:link { |
|||
color: #fff; |
|||
font-size: 1.6rem; |
|||
line-height: 1.6rem; |
|||
text-decoration: none; |
|||
} |
|||
a:visited { |
|||
color: rgb(228, 228, 228); |
|||
} |
|||
a:hover { |
|||
color: rgb(228, 228, 228); |
|||
} |
|||
a:active { |
|||
color: whitesmoke; |
|||
} |
|||
|
|||
.active { |
|||
background-color: #3082aa; |
|||
color: black; |
|||
} |
|||
.active a { |
|||
color: #fff; |
|||
} |
|||
|
|||
.hide { |
|||
display: none; |
|||
} |
|||
|
|||
.myDIV:hover + .hide { |
|||
display: block; |
|||
color: grey; |
|||
} |
|||
|
|||
/* width */ |
|||
::-webkit-scrollbar { |
|||
width: 3px; |
|||
} |
|||
|
|||
/* Track */ |
|||
::-webkit-scrollbar-track { |
|||
box-shadow: inset 0 0 5px rgb(42, 42, 42); |
|||
border-radius: 10px; |
|||
} |
|||
|
|||
/* Handle */ |
|||
::-webkit-scrollbar-thumb { |
|||
background: rgb(180, 180, 180); |
|||
border-radius: 10px; |
|||
} |
|||
|
|||
.styleProSidebar > * { |
|||
color: whitesmoke !important; |
|||
background: #0d1214 !important; |
|||
} |
|||
|
|||
.styleProSidebarSM > * { |
|||
color: whitesmoke !important; |
|||
background: #0d1214 !important; |
|||
} |
|||
|
|||
.darkgrey { |
|||
background: #23282c; /* navbar */ |
|||
} |
|||
|
|||
.lightblue { |
|||
background: #3082aa; |
|||
} |
|||
|
|||
.lightblack { |
|||
background: #11181b; /* background bodi */ |
|||
} |
|||
|
|||
.MuiDataGrid-virtualScrollerContent * { |
|||
border: none !important; |
|||
} |
|||
|
|||
.MuiDataGrid-menuIcon * { |
|||
color: whitesmoke !important; |
|||
} |
|||
|
|||
p, |
|||
.MuiTablePagination-actions { |
|||
color: whitesmoke !important; |
|||
} |
|||
|
|||
.textField * { |
|||
color: rgb(172, 172, 172) !important; |
|||
border-color: rgb(59, 59, 59) !important; |
|||
} |
|||
|
|||
.darktext { |
|||
color: rgb(42, 42, 42) !important; |
|||
font-weight: 500 !important; |
|||
} |
|||
|
|||
.textGrey, |
|||
.Mui-disabled { |
|||
color: #7a7979 !important; |
|||
} |
|||
|
|||
|
|||
|
|||
.MuiPaper-root { |
|||
background: #23282c !important; |
|||
color: whitesmoke !important; |
|||
} |
|||
|
|||
#mui-1, |
|||
.MuiInput-root { |
|||
color: whitesmoke !important; |
|||
} |
|||
|
|||
.btn-hover:hover { |
|||
background-color: opacity(#000000, 0.9); |
|||
} |
|||
|
|||
.MuiDialog-paper { |
|||
border-color: #26698b !important; |
|||
background: #11181b !important; |
|||
-webkit-box-shadow: 5px 5px 15px 5px #000000 !important; |
|||
box-shadow: 5px 5px 15px 5px #000000 !important; |
|||
} |
|||
|
|||
.complete { |
|||
text-decoration: line-through !important; |
|||
} |
|||
|
|||
.css-1ps6pg7-MuiPaper-root, |
|||
.MuiDataGrid-panelContent, |
|||
.css-1sjjn1c-MuiDataGrid-panelContent { |
|||
background: #23282c !important; |
|||
} |
|||
|
|||
.MuiIconButton-sizeSmall * { |
|||
color: white !important ; |
|||
} |
|||
|
|||
table { |
|||
background-color: #23282c; |
|||
} |
|||
|
|||
.container-body { |
|||
display: flex; |
|||
flex-direction: column; |
|||
justify-content: center; |
|||
align-items: center; |
|||
min-height: 100vh; |
|||
width: 100vw; |
|||
} |
|||
|
|||
.container-body-paper { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
justify-content: center; |
|||
min-height: 100vh; |
|||
width: 95vw; |
|||
} |
|||
|
|||
.wrapper-header { |
|||
width: 95vw; |
|||
display: flex; |
|||
justify-content: flex-end; |
|||
align-items: center; |
|||
} |
|||
|
|||
.header-title { |
|||
position: absolute; |
|||
left: 3%; |
|||
color: rgb(82, 82, 82); |
|||
font-size: 20px; |
|||
} |
|||
|
|||
.text-hover { |
|||
color: #3082aa !important; |
|||
} |
|||
|
|||
.wrapper-header-providers { |
|||
position: absolute; |
|||
width: 95vw; |
|||
display: flex; |
|||
justify-content: flex-end; |
|||
align-items: center; |
|||
top: 11%; |
|||
} |
|||
|
|||
.header-title-providers { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
width: 93vw; |
|||
color: #3082aa; |
|||
font-size: 20px; |
|||
margin-bottom: 20px; |
|||
margin-top: 15%; |
|||
} |
|||
|
|||
.container-body-providers { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
} |
|||
|
|||
|
|||
.header-title-neworder { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
width: 65vw; |
|||
color: #3082aa; |
|||
font-size: 20px; |
|||
margin-bottom: 20px; |
|||
margin-top: 3%; |
|||
} |
|||
|
|||
.MuiMenuItem-root { |
|||
background: #23282c !important; |
|||
color: whitesmoke !important; |
|||
} |
|||
|
|||
.MuiMenuItem-paper { |
|||
background: #23282c !important; |
|||
color: whitesmoke !important; |
|||
} |
|||
@ -0,0 +1,65 @@ |
|||
import { BrowserRouter as Router, Route, Switch } from "react-router-dom"; |
|||
|
|||
//import views |
|||
import Home from "./views/Home"; |
|||
import Components from "./views/Components"; |
|||
import FormProductModel from "./components/FormProductModel"; |
|||
import NewComponent from "./views/NewComponent"; |
|||
import NewProductModel from "./views/NewProductModel"; |
|||
import ProductModel from "./views/ProductModel"; |
|||
import Layout from "./views/Layout"; |
|||
import NewProductFabric from "./views/NewProductFabric"; |
|||
import FabricDashboard from "./views/FabricDashboard"; |
|||
import EditComponent from "./views/EditComponent"; |
|||
import Supplies from "./views/Supplies"; |
|||
import Calculator_View from "./views/Calculator_View"; |
|||
import NewSupply from "./views/NewSupply"; |
|||
import EditSupply from "./views/EditSupply"; |
|||
import ProvidersDetail from "./views/ProvidersDetail"; |
|||
import SuppliesArchived from "./views/SuppliesArchived"; |
|||
import NewOrder_View from "./views/NewOrder_View"; |
|||
|
|||
//Utilizo el switch para que no se pierda el navbar a medida que uno se vaya moviendo por las diferentes vistas de la app :D |
|||
|
|||
function App() { |
|||
return ( |
|||
<div |
|||
className="App" |
|||
style={{ |
|||
minHeight: "100vh", |
|||
margin: "0", |
|||
padding: "0", |
|||
boxSizing: "border-box", |
|||
}} |
|||
> |
|||
<Router> |
|||
<Layout> |
|||
<Switch> |
|||
<Route exact path="/" component={Home} /> |
|||
<Route exact path="/components" component={Components} /> |
|||
<Route exact path="/test" component={FormProductModel} /> |
|||
<Route exact path="/newcomponent" component={NewComponent} /> |
|||
<Route exact path="/newproductmodel" component={NewProductModel} /> |
|||
<Route exact path="/productmodel" component={ProductModel} /> |
|||
<Route |
|||
exact |
|||
path="/newproductfabric" |
|||
component={NewProductFabric} |
|||
/> |
|||
<Route exact path="/fabricdashboard" component={FabricDashboard} /> |
|||
<Route exact path="/editcomponent" component={EditComponent} /> |
|||
<Route exact path="/editsupply/:id" component={EditSupply} /> |
|||
<Route exact path="/supplies" component={Supplies} /> |
|||
<Route exact path="/archivedsupplies" component={SuppliesArchived} /> |
|||
<Route exact path="/newsupply" component={NewSupply} /> |
|||
<Route exact path="/calculator" component={Calculator_View} /> |
|||
<Route exact path="/providersDetail/:id" component={ProvidersDetail} /> |
|||
<Route exact path="/neworder/:id" component={NewOrder_View} /> |
|||
</Switch> |
|||
</Layout> |
|||
</Router> |
|||
</div> |
|||
); |
|||
} |
|||
|
|||
export default App; |
|||
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 52 KiB |
@ -0,0 +1 @@ |
|||
{"v":"5.5.7","meta":{"g":"LottieFiles AE 0.1.20","a":"","k":"","d":"","tc":""},"fr":24,"ip":0,"op":60,"w":400,"h":400,"nm":"seat-2","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 3","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":9.6,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[1],"y":[0]},"t":28.8,"s":[100]},{"t":48,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":9.6,"s":[200,-23,0],"to":[0,21.667,0],"ti":[0,-41.667,0]},{"i":{"x":0.667,"y":1},"o":{"x":1,"y":0},"t":28.8,"s":[200,107,0],"to":[0,41.667,0],"ti":[0,-20,0]},{"t":48,"s":[200,227,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-85,4.5],[7,76.5],[99.5,4]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.18823529411764706,0.5098039215686274,0.6666666666666666,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":37,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":6,"op":78,"st":6,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 2","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[1],"y":[0]},"t":19.2,"s":[100]},{"t":38.400390625,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[200,70,0],"to":[0,21.667,0],"ti":[0,-38.333,0]},{"i":{"x":0.667,"y":1},"o":{"x":1,"y":0},"t":19.2,"s":[200,200,0],"to":[0,38.333,0],"ti":[0,-16.667,0]},{"t":38.400390625,"s":[200,300,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-85,4.5],[7,76.5],[99.5,4]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.18823529411764706,0.5098039215686274,0.6666666666666666,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":37,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":72,"st":0,"bm":0}],"markers":[]} |
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,20 @@ |
|||
import { useLottie } from "lottie-react"; |
|||
import emptySearch from "../assets/emptySearch.json"; |
|||
|
|||
const EmptySearch = () => { |
|||
const options = { |
|||
animationData: emptySearch, |
|||
loop: true, |
|||
autoplay: true, |
|||
}; |
|||
|
|||
const style = { |
|||
height: 150, |
|||
}; |
|||
|
|||
const { View } = useLottie(options, style); |
|||
|
|||
return <>{View}</>; |
|||
}; |
|||
|
|||
export default EmptySearch; |
|||
@ -0,0 +1,28 @@ |
|||
import Button from "@mui/material/Button"; |
|||
import { useLottie } from "lottie-react"; |
|||
import addButton from "../assets/addButton.json"; |
|||
import { Link } from "react-router-dom"; |
|||
|
|||
const ButtonAdd = ({ router }) => { |
|||
const options = { |
|||
animationData: addButton, |
|||
loop: true, |
|||
autoplay: true, |
|||
}; |
|||
|
|||
const style = { |
|||
height: 70, |
|||
}; |
|||
|
|||
const { View } = useLottie(options, style); |
|||
|
|||
return ( |
|||
<Link to={router}> |
|||
<Button> |
|||
<div>{View}</div> |
|||
</Button> |
|||
</Link> |
|||
); |
|||
}; |
|||
|
|||
export default ButtonAdd; |
|||
@ -0,0 +1,39 @@ |
|||
import Button from "@mui/material/Button"; |
|||
import ArchiveOutlinedIcon from "@mui/icons-material/ArchiveOutlined"; |
|||
import UnarchiveOutlinedIcon from "@mui/icons-material/UnarchiveOutlined"; |
|||
|
|||
import { Link } from "react-router-dom"; |
|||
|
|||
const ButtonArchived = ({ router, title, icon }) => { |
|||
if (icon === "down") { |
|||
return ( |
|||
<Link to={router} > |
|||
<div style={{ marginRight: "15px" }}> |
|||
<Button |
|||
variant="contained" |
|||
style={{ backgroundColor: "#23282c" }} |
|||
endIcon={<ArchiveOutlinedIcon />} |
|||
> |
|||
{title} |
|||
</Button> |
|||
</div> |
|||
</Link> |
|||
); |
|||
} else { |
|||
return ( |
|||
<Link to={router}> |
|||
<div style={{ marginRight: "15px" }}> |
|||
<Button |
|||
variant="contained" |
|||
style={{ backgroundColor: "#23282c" }} |
|||
endIcon={<UnarchiveOutlinedIcon />} |
|||
> |
|||
{title} |
|||
</Button> |
|||
</div> |
|||
</Link> |
|||
); |
|||
} |
|||
}; |
|||
|
|||
export default ButtonArchived; |
|||
@ -0,0 +1,5 @@ |
|||
export default function Calculator() { |
|||
return <div style={{display: 'flex', justifyContent: 'center'}}> |
|||
<img style={{width: '35%', borderRadius: '75%'}} src={require('../assets/dificultades-tecnicas-1.jpg')} alt="F" /> |
|||
</div>; |
|||
} |
|||
@ -0,0 +1,77 @@ |
|||
import React, { useEffect } from "react"; |
|||
import { Link } from "react-router-dom"; |
|||
import Grid from "@mui/material/Grid"; |
|||
import { styled } from "@mui/material/styles"; |
|||
import ProductCard from "./ProductCard"; |
|||
import { useDispatch, useSelector } from "react-redux"; |
|||
import { showImage } from "../utils/imageUtils"; |
|||
import { Button } from "@mui/material"; |
|||
|
|||
import "animate.css"; |
|||
|
|||
const useStyles = styled((theme) => ({ |
|||
root: { |
|||
flexGrow: 1, |
|||
padding: theme.spacing(2), |
|||
}, |
|||
})); |
|||
|
|||
export default function CardGrid() { |
|||
// redux state |
|||
const dispatch = useDispatch(); |
|||
|
|||
// state |
|||
const products = useSelector((state) => state.products); |
|||
|
|||
// process image |
|||
const processImage = (imageData, contentType) => { |
|||
const img = showImage(imageData, contentType); |
|||
return img; |
|||
}; |
|||
|
|||
return ( |
|||
// style={{ height: '70vh', overflowY: 'scroll', paddingTop: '2%', marginTop: '1.5%' }} |
|||
<div |
|||
style={{ |
|||
display: "flex", |
|||
justifyContent: "center", |
|||
height: "75vh", |
|||
overflowY: "auto", |
|||
padding: "3%", |
|||
marginTop: "4%", |
|||
}} |
|||
> |
|||
<Grid |
|||
container |
|||
gap={2} |
|||
direction="row" |
|||
justifyContent="center" |
|||
alignItems="center" |
|||
> |
|||
{products.map((product) => { |
|||
let productImage = processImage(product.imageData, product.imageType); |
|||
return ( |
|||
<Link |
|||
className="animate__animated animate__fadeIn" |
|||
key={product._id} |
|||
to={{ |
|||
pathname: "/productmodel", |
|||
state: { product: product }, |
|||
}} |
|||
style={{ paddingLeft: 13, textDecoration: "none" }} |
|||
onClick={() => { |
|||
dispatch({ type: "PRODUCT_SELECTED", payload: product }); |
|||
}} |
|||
> |
|||
<ProductCard |
|||
name={product.name} |
|||
description={product.description} |
|||
img={productImage} |
|||
/> |
|||
</Link> |
|||
); |
|||
})} |
|||
</Grid> |
|||
</div> |
|||
); |
|||
} |
|||
@ -0,0 +1,82 @@ |
|||
import { Link } from "react-router-dom"; |
|||
import Grid from "@mui/material/Grid"; |
|||
import { useDispatch, useSelector } from "react-redux"; |
|||
import { showImage } from "../utils/imageUtils"; |
|||
import ProductCardFabric from "./ProductCardFabric"; |
|||
import EmptyBox from "./emptyBox"; |
|||
import "animate.css"; |
|||
|
|||
export default function CardGridFabric() { |
|||
// redux state |
|||
const dispatch = useDispatch(); |
|||
// state |
|||
const processProducts = useSelector((state) => state.processProducts); |
|||
|
|||
// process image |
|||
const processImage = (imageData, contentType) => { |
|||
const img = showImage(imageData, contentType); |
|||
return img; |
|||
}; |
|||
|
|||
return ( |
|||
<div |
|||
style={{ |
|||
display: "flex", |
|||
justifyContent: "center", |
|||
height: "80vh", |
|||
overflowY: "auto", |
|||
padding: "2%", |
|||
marginTop: "1.5%", |
|||
}} |
|||
> |
|||
<Grid |
|||
container |
|||
spacing={2} |
|||
direction="row" |
|||
justifyContent="center" |
|||
alignItems="center" |
|||
gap={4} |
|||
> |
|||
{processProducts.length > 0 ? ( |
|||
processProducts.map((processProduct) => { |
|||
let processProductImage = processImage( |
|||
processProduct.model.image.data, |
|||
processProduct.model.image.contentType |
|||
); |
|||
|
|||
return ( |
|||
<Link |
|||
className="animate__animated animate__fadeIn" |
|||
to={{ |
|||
pathname: "/newproductfabric", |
|||
state: { product: processProduct }, |
|||
}} |
|||
style={{ paddingLeft: 13, textDecoration: "none" }} |
|||
onClick={() => { |
|||
dispatch({ |
|||
type: "PRODUCT_SELECTED", |
|||
payload: processProduct, |
|||
}); |
|||
}} |
|||
> |
|||
<ProductCardFabric |
|||
key={processProduct.id} |
|||
name={processProduct.name} |
|||
description={processProduct.model.name} |
|||
img={processProductImage} |
|||
stateProduction={processProduct.stateProduction} |
|||
/> |
|||
</Link> |
|||
); |
|||
}) |
|||
) : ( |
|||
<div |
|||
style={{ display: "flex", alignItems: "center", height: "80vh" }} |
|||
> |
|||
<EmptyBox /> |
|||
</div> |
|||
)} |
|||
</Grid> |
|||
</div> |
|||
); |
|||
} |
|||
@ -0,0 +1,462 @@ |
|||
import Button from "@mui/material/Button"; |
|||
import { showImage } from "../utils/imageUtils"; |
|||
import EdiText from "react-editext"; |
|||
import DeleteIcon from "@mui/icons-material/Delete"; |
|||
import { useSelector } from "react-redux"; |
|||
import styled from "styled-components"; |
|||
import MenuItem from "@mui/material/MenuItem"; |
|||
import TextField from "@mui/material/TextField"; |
|||
import { deleteComponent, editComponentById } from "../services/components"; |
|||
import { useHistory } from "react-router-dom"; |
|||
import { useState } from "react"; |
|||
import { createFormData } from "../utils/formUtils"; |
|||
|
|||
import Dialog from "@mui/material/Dialog"; |
|||
import DialogActions from "@mui/material/DialogActions"; |
|||
import DialogContent from "@mui/material/DialogContent"; |
|||
import useMediaQuery from "@mui/material/useMediaQuery"; |
|||
import { useTheme } from "@mui/material/styles"; |
|||
|
|||
const categories = [ |
|||
{ |
|||
value: "Generales", |
|||
label: "Generales", |
|||
}, |
|||
{ |
|||
value: "Circuitos integrados", |
|||
label: "Circuitos integrados", |
|||
}, |
|||
{ |
|||
value: "Diodos", |
|||
label: "Diodos", |
|||
}, |
|||
{ |
|||
value: "Fichas, cables y pines", |
|||
label: "Fichas, cables y pines", |
|||
}, |
|||
{ |
|||
value: "Modulos", |
|||
label: "Modulos", |
|||
}, |
|||
{ |
|||
value: "Pasivos", |
|||
label: "Pasivos", |
|||
}, |
|||
{ |
|||
value: "Pantallas", |
|||
label: "Pantallas", |
|||
}, |
|||
{ |
|||
value: "Sensores", |
|||
label: "Sensores", |
|||
}, |
|||
{ |
|||
value: "Otros", |
|||
label: "Otros", |
|||
}, |
|||
]; |
|||
|
|||
const H1Style = styled(EdiText)` |
|||
button { |
|||
border: none; |
|||
background: rgba(0, 0, 0, 0); |
|||
border-radius: 50%; |
|||
width: 20px; |
|||
} |
|||
button:hover { |
|||
background: #11181b; |
|||
} |
|||
button[editext="edit-button"] { |
|||
transform: scaleX(-1); |
|||
font-size: x-large; |
|||
color: grey; |
|||
width: 50px; |
|||
} |
|||
button[editext="save-button"] { |
|||
} |
|||
button[editext="cancel-button"] { |
|||
} |
|||
input, |
|||
textarea { |
|||
font-family: "Roboto"; |
|||
font-size: x-large; |
|||
border: none; |
|||
} |
|||
div[editext="view-container"], |
|||
div[editext="edit-container"] { |
|||
font-family: "Roboto"; |
|||
font-size: xx-large; |
|||
color: whitesmoke; |
|||
} |
|||
`; |
|||
|
|||
const H3Style = styled(EdiText)` |
|||
button { |
|||
border: none; |
|||
background: rgba(0, 0, 0, 0); |
|||
border-radius: 50%; |
|||
width: 20px; |
|||
} |
|||
button:hover { |
|||
background: #11181b; |
|||
} |
|||
button[editext="edit-button"] { |
|||
transform: scaleX(-1); |
|||
font-size: x-large; |
|||
color: grey; |
|||
width: 50px; |
|||
} |
|||
button[editext="save-button"] { |
|||
} |
|||
button[editext="cancel-button"] { |
|||
} |
|||
input, |
|||
textarea { |
|||
font-family: "Roboto"; |
|||
font-size: large; |
|||
color: grey; |
|||
border: none; |
|||
} |
|||
div[editext="view-container"], |
|||
div[editext="edit-container"] { |
|||
font-family: "Roboto"; |
|||
font-size: large; |
|||
color: grey; |
|||
color: whitesmoke; |
|||
} |
|||
`; |
|||
const H2Style = styled(EdiText)` |
|||
button { |
|||
border: none; |
|||
background: rgba(0, 0, 0, 0); |
|||
border-radius: 50%; |
|||
width: 20px; |
|||
} |
|||
button:hover { |
|||
background: #11181b; |
|||
} |
|||
button[editext="edit-button"] { |
|||
transform: scaleX(-1); |
|||
font-size: x-large; |
|||
color: grey; |
|||
width: 50px; |
|||
} |
|||
button[editext="save-button"] { |
|||
} |
|||
button[editext="cancel-button"] { |
|||
} |
|||
input, |
|||
textarea { |
|||
font-family: "Roboto"; |
|||
font-size: large; |
|||
color: grey; |
|||
} |
|||
div[editext="view-container"], |
|||
div[editext="edit-container"] { |
|||
font-family: "Roboto"; |
|||
font-size: large; |
|||
color: whitesmoke; |
|||
border-radius: 15px; |
|||
padding-left: 8px; |
|||
border: 0.1px solid rgba(200, 200, 200, 0.1); |
|||
margin-top: 10px; |
|||
} |
|||
`; |
|||
|
|||
export default function ComponentEdit() { |
|||
//popUp |
|||
const [open, setOpen] = useState(false); |
|||
const theme = useTheme(); |
|||
const fullScreen = useMediaQuery(theme.breakpoints.down("md")); |
|||
|
|||
const handleClickOpen = () => { |
|||
setOpen(true); |
|||
}; |
|||
|
|||
const handleClose = () => { |
|||
setOpen(false); |
|||
}; |
|||
//end PopUp |
|||
|
|||
// history |
|||
const history = useHistory(); |
|||
const componentSelected = useSelector((state) => state.componentSelected); |
|||
const [image, setImage] = useState({ preview: "", raw: "" }); |
|||
// form state |
|||
const [form, setForm] = useState({ |
|||
name: componentSelected.name, |
|||
description: componentSelected.description, |
|||
image: image, |
|||
quantity: componentSelected.quantity, |
|||
category: componentSelected.category, |
|||
price: componentSelected.price, |
|||
location: componentSelected.location, |
|||
}); |
|||
|
|||
//handlers |
|||
|
|||
//delete service |
|||
const handleSubmitDelete = (e) => { |
|||
e.preventDefault(); |
|||
const response = deleteComponent(componentSelected._id); |
|||
if (response !== null) { |
|||
history.push("/components"); |
|||
} |
|||
}; |
|||
|
|||
// handlers for form |
|||
const handleForm = (value, inputProp) => { |
|||
setForm({ |
|||
...form, |
|||
[inputProp]: value, |
|||
}); |
|||
}; |
|||
const handleFormCat = (e) => { |
|||
setForm({ |
|||
...form, |
|||
[e.target.name]: e.target.value, |
|||
}); |
|||
}; |
|||
|
|||
// image |
|||
const handleImage = (e) => { |
|||
if (e.target.files.length) { |
|||
setImage({ |
|||
preview: URL.createObjectURL(e.target.files[0]), |
|||
raw: e.target.files[0], |
|||
}); |
|||
} |
|||
|
|||
setForm({ |
|||
...form, |
|||
image: e.target.files[0], |
|||
}); |
|||
}; |
|||
|
|||
//edit service |
|||
const handleEditSubmit = (e) => { |
|||
e.preventDefault(); |
|||
|
|||
const formData = createFormData(form); |
|||
|
|||
const response = editComponentById(componentSelected._id, formData); |
|||
if (response !== null) { |
|||
} |
|||
|
|||
history.push("/components"); |
|||
}; |
|||
|
|||
// process image |
|||
const processImage = (imageData, contentType) => { |
|||
const img = showImage(imageData, contentType); |
|||
return img; |
|||
}; |
|||
let productImage = processImage( |
|||
componentSelected.imageData, |
|||
componentSelected.imageType |
|||
); |
|||
return ( |
|||
<div |
|||
id="container-screen" |
|||
style={{ |
|||
display: "flex", |
|||
justifyContent: "center", |
|||
alignItems: "center", |
|||
height: "100%", |
|||
flexDirection: "column", |
|||
}} |
|||
> |
|||
<div |
|||
id="card" |
|||
style={{ |
|||
width: "80%", |
|||
height: "60%", |
|||
background: "#23282c", |
|||
borderRadius: "10px", |
|||
display: "flex", |
|||
flexDirection: "row", |
|||
}} |
|||
> |
|||
<div |
|||
id="left-column" |
|||
style={{ |
|||
display: "flex", |
|||
justifyContent: "center", |
|||
width: "50%", |
|||
alignItems: "center", |
|||
// background: "yellow", |
|||
}} |
|||
> |
|||
<div id="imageBox" style={{ maxWidth: "50%" }}> |
|||
<Button |
|||
href="#" |
|||
onClick={(e) => { |
|||
e.preventDefault(); |
|||
document.getElementById("image").click(); |
|||
}} |
|||
> |
|||
<img |
|||
src={image.preview ? image.preview : productImage} |
|||
alt="preview" |
|||
style={{ |
|||
maxWidth: "100%", |
|||
borderRadius: "50%", |
|||
overflow: "hidden", |
|||
}} |
|||
/> |
|||
</Button> |
|||
<input |
|||
type="file" |
|||
id="image" |
|||
name="image" |
|||
accept="image/*" |
|||
style={{ display: "none" }} |
|||
onChange={handleImage} |
|||
/> |
|||
</div> |
|||
</div> |
|||
|
|||
<div |
|||
id="right-col" |
|||
style={{ |
|||
width: "50%", |
|||
display: "flex", |
|||
justifyContent: "center", |
|||
flexDirection: "column", |
|||
// background: 'yellow' |
|||
}} |
|||
> |
|||
<div |
|||
style={{ |
|||
width: "90%", |
|||
display: "flex", |
|||
flexDirection: "row", |
|||
justifyContent: "space-between", |
|||
}} |
|||
> |
|||
<H1Style |
|||
inputProps="name" |
|||
type="text" |
|||
value={form.name} |
|||
onSave={handleForm} |
|||
/> |
|||
|
|||
<TextField |
|||
className="textField" |
|||
name="category" |
|||
select |
|||
helperText="Seleccione categoría" |
|||
defaultValue={componentSelected.category} |
|||
style={{ width: "28ch", marginBottom: "30px" }} |
|||
onChange={handleFormCat} |
|||
> |
|||
{categories.map((option) => ( |
|||
<MenuItem key={option.value} value={option.value}> |
|||
{option.label} |
|||
</MenuItem> |
|||
))} |
|||
</TextField> |
|||
</div> |
|||
|
|||
<div style={{ height: "200px", width: "90%" }}> |
|||
<p className="textGrey">Descripción</p> |
|||
|
|||
<H2Style |
|||
inputProps="description" |
|||
type="text" |
|||
value={form.description} |
|||
onSave={handleForm} |
|||
/> |
|||
</div> |
|||
<div |
|||
style={{ |
|||
width: "90%", |
|||
display: "flex", |
|||
flexDirection: "row", |
|||
justifyContent: "space-between", |
|||
}} |
|||
> |
|||
<div style={{ display: "flex", flexDirection: "column" }}> |
|||
<p className="textGrey">Ubicacion</p> |
|||
|
|||
<H2Style |
|||
inputProps="location" |
|||
type="text" |
|||
value={form.location} |
|||
onSave={handleForm} |
|||
/> |
|||
</div> |
|||
|
|||
<div style={{ display: "flex", flexDirection: "column" }}> |
|||
<p className="textGrey">Cantidad</p> |
|||
|
|||
<H2Style |
|||
inputProps="quantity" |
|||
type="text" |
|||
value={form.quantity} |
|||
onSave={handleForm} |
|||
/> |
|||
</div> |
|||
|
|||
<div style={{ display: "flex", flexDirection: "column" }}> |
|||
<p className="textGrey">Precio</p> |
|||
|
|||
<H2Style |
|||
inputProps="price" |
|||
type="text" |
|||
value={form.price} |
|||
onSave={handleForm} |
|||
/> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
{/* footer */} |
|||
<div |
|||
style={{ |
|||
width: "80%", |
|||
display: "flex", |
|||
justifyContent: "space-between", |
|||
marginTop: "1%", |
|||
}} |
|||
> |
|||
<div> |
|||
<Button variant="contained" color="error" onClick={handleClickOpen}> |
|||
<DeleteIcon /> |
|||
</Button> |
|||
</div> |
|||
|
|||
<Button |
|||
className="btn-hover" |
|||
variant="contained" |
|||
sx={{ background: "#3082AA !important" }} |
|||
onClick={handleEditSubmit} |
|||
> |
|||
CONFIRMAR |
|||
</Button> |
|||
|
|||
{/* POP UP DIALOG */} |
|||
<Dialog |
|||
fullScreen={fullScreen} |
|||
open={open} |
|||
onClose={handleClose} |
|||
aria-labelledby="responsive-dialog-title" |
|||
> |
|||
<DialogContent> |
|||
<h3 style={{ fontWeight: "400", color: "lightgrey " }}> |
|||
¿Está seguro/a que desea eliminar el elemento? |
|||
</h3> |
|||
</DialogContent> |
|||
<DialogActions> |
|||
<Button className="textGrey" autoFocus onClick={handleClose}> |
|||
NO |
|||
</Button> |
|||
<Button className="textGrey" onClick={handleSubmitDelete} autoFocus> |
|||
SI |
|||
</Button> |
|||
</DialogActions> |
|||
</Dialog> |
|||
</div> |
|||
</div> |
|||
); |
|||
} |
|||
@ -0,0 +1,198 @@ |
|||
import Table from "@mui/material/Table"; |
|||
import TableBody from "@mui/material/TableBody"; |
|||
import TableCell from "@mui/material/TableCell"; |
|||
import TableContainer from "@mui/material/TableContainer"; |
|||
import TableHead from "@mui/material/TableHead"; |
|||
import TableRow from "@mui/material/TableRow"; |
|||
import Paper from "@mui/material/Paper"; |
|||
|
|||
export default function ComponentsProductModel({ product }) { |
|||
/* useEffect(() => { |
|||
rows = []; |
|||
|
|||
rows = product.components.map((component) => { |
|||
return { |
|||
name: component.name, |
|||
description: component.description, |
|||
quantity: component.quantity, |
|||
category: component.category, |
|||
}; |
|||
}); |
|||
}, []); */ |
|||
|
|||
return ( |
|||
<div> |
|||
<TableContainer |
|||
component={Paper} |
|||
sx={{ |
|||
width: "100%", |
|||
display: "fluid", |
|||
}} |
|||
> |
|||
<Table sx={{ minWidth: 650 }} aria-label="simple table"> |
|||
<TableHead |
|||
sx={{ |
|||
backgroundColor: "#23282C", |
|||
}} |
|||
> |
|||
<TableRow> |
|||
<TableCell |
|||
sx={{ |
|||
color: "whitesmoke", |
|||
}} |
|||
> |
|||
Nombre del componente |
|||
</TableCell> |
|||
<TableCell |
|||
sx={{ |
|||
color: "whitesmoke", |
|||
}} |
|||
align="right" |
|||
> |
|||
Categoría |
|||
</TableCell> |
|||
<TableCell |
|||
sx={{ |
|||
color: "whitesmoke", |
|||
}} |
|||
align="right" |
|||
> |
|||
Descripción |
|||
</TableCell> |
|||
<TableCell |
|||
sx={{ |
|||
color: "whitesmoke", |
|||
}} |
|||
align="right" |
|||
> |
|||
Ubicación |
|||
</TableCell> |
|||
<TableCell |
|||
sx={{ |
|||
color: "whitesmoke", |
|||
}} |
|||
align="right" |
|||
> |
|||
Cantidad |
|||
</TableCell> |
|||
</TableRow> |
|||
</TableHead> |
|||
<TableBody> |
|||
{product.components.map((component) => |
|||
component.statusDB ? ( |
|||
<TableRow |
|||
key={component._id} |
|||
sx={{ |
|||
"&:last-child td, &:last-child th": { border: 0 }, |
|||
}} |
|||
> |
|||
<TableCell |
|||
component="th" |
|||
scope="row" |
|||
style={{ |
|||
background: "#23282C", |
|||
color: "whitesmoke", |
|||
width: "20%", |
|||
}} |
|||
> |
|||
{component.name} |
|||
</TableCell> |
|||
<TableCell |
|||
style={{ |
|||
background: "#23282C", |
|||
color: "whitesmoke", |
|||
}} |
|||
align="right" |
|||
> |
|||
{component.category} |
|||
</TableCell> |
|||
<TableCell |
|||
style={{ |
|||
background: "#23282C", |
|||
color: "whitesmoke", |
|||
}} |
|||
align="right" |
|||
> |
|||
{component.description} |
|||
</TableCell> |
|||
<TableCell |
|||
style={{ |
|||
background: "#23282C", |
|||
color: "whitesmoke", |
|||
}} |
|||
align="right" |
|||
> |
|||
{component.location} |
|||
</TableCell> |
|||
<TableCell |
|||
style={{ |
|||
background: "#23282C", |
|||
color: "whitesmoke", |
|||
}} |
|||
align="right" |
|||
> |
|||
{component.quantity} |
|||
</TableCell> |
|||
</TableRow> |
|||
) : ( |
|||
<TableRow |
|||
key={component._id} |
|||
sx={{ "&:last-child td, &:last-child th": { border: 0 } }} |
|||
> |
|||
<TableCell |
|||
component="th" |
|||
scope="row" |
|||
style={{ |
|||
color: "rgb(100, 100, 100)", |
|||
background: "#23282C", |
|||
}} |
|||
> |
|||
{component.name} |
|||
</TableCell> |
|||
|
|||
<TableCell |
|||
align="right" |
|||
style={{ |
|||
color: "rgb(100, 100, 100)", |
|||
background: "#23282C", |
|||
}} |
|||
> |
|||
{component.quantity} |
|||
</TableCell> |
|||
|
|||
<TableCell |
|||
align="right" |
|||
style={{ |
|||
color: "rgb(100, 100, 100)", |
|||
background: "#23282C", |
|||
}} |
|||
> |
|||
{component.location} |
|||
</TableCell> |
|||
<TableCell |
|||
align="right" |
|||
style={{ |
|||
color: "rgb(100, 100, 100)", |
|||
background: "#23282C", |
|||
}} |
|||
> |
|||
{component.description} |
|||
</TableCell> |
|||
<TableCell |
|||
align="right" |
|||
style={{ |
|||
color: "rgb(100, 100, 100)", |
|||
background: "#23282C", |
|||
}} |
|||
> |
|||
{component.category} |
|||
</TableCell> |
|||
</TableRow> |
|||
) |
|||
)} |
|||
</TableBody> |
|||
</Table> |
|||
</TableContainer> |
|||
</div> |
|||
); |
|||
} |
|||
@ -0,0 +1,284 @@ |
|||
import React, { useEffect, useRef, useState } from "react"; |
|||
import { DataGrid } from "@mui/x-data-grid"; |
|||
import { useDispatch, useSelector } from "react-redux"; |
|||
import { getComponents } from "../services/components"; |
|||
import { Button, CircularProgress, TextField } from "@mui/material"; |
|||
import { showImage } from "../utils/imageUtils"; |
|||
import { useHistory } from "react-router-dom"; |
|||
import EditIcon from "@mui/icons-material/Edit"; |
|||
import NoteIcon from "@mui/icons-material/Notes"; |
|||
import EmptySearch from "./AnimationEmptySearch"; |
|||
// import { addOrUpdateNotesThunk, getNotesThunk } from "../reducers/notes"; |
|||
|
|||
import Dialog from "@mui/material/Dialog"; |
|||
import DialogActions from "@mui/material/DialogActions"; |
|||
import DialogContent from "@mui/material/DialogContent"; |
|||
import useMediaQuery from "@mui/material/useMediaQuery"; |
|||
import { useTheme } from "@mui/material/styles"; |
|||
|
|||
const columns = [ |
|||
{ field: "id", headerName: "ID", width: 70, hide: true }, |
|||
{ |
|||
field: "image", |
|||
headerName: "Imagen", |
|||
width: 80, |
|||
renderCell: (rowData) => { |
|||
return ( |
|||
<div |
|||
style={{ |
|||
borderRadius: "50%", |
|||
overflow: "hidden", |
|||
width: "60px", |
|||
height: "60px", |
|||
}} |
|||
> |
|||
<img |
|||
style={{ |
|||
height: "100%", |
|||
width: "100%", |
|||
}} |
|||
src={rowData.row.image} |
|||
/> |
|||
</div> |
|||
); |
|||
}, |
|||
}, |
|||
{ field: "name", headerName: "Nombre", width: 200 }, |
|||
{ field: "category", headerName: "Categoría", width: 190 }, |
|||
{ field: "description", headerName: "Descripción", width: 200 }, |
|||
|
|||
{ field: "location", headerName: "Ubicación", width: 130 }, |
|||
{ field: "quantity", headerName: "Cantidad", width: 100 }, |
|||
{ field: "unity", headerName: "Unidad de medida", width: 150 }, |
|||
{ field: "price", headerName: "Precio", width: 100 }, |
|||
{ field: "entryDate", headerName: "Fecha de Ingreso", width: 150 }, |
|||
{ |
|||
field: "note", |
|||
headerName: "Notas", |
|||
width: 100, |
|||
renderCell: (rowData) => ( |
|||
<Button |
|||
className="btn-hover" |
|||
variant="contained" |
|||
sx={{ background: "#3082AA !important" }} |
|||
onClick={() => { |
|||
rowData.row.note(rowData.row); |
|||
}} |
|||
> |
|||
<NoteIcon /> |
|||
</Button> |
|||
), |
|||
}, |
|||
{ |
|||
field: "edit", |
|||
headerName: "Editar", |
|||
width: 90, |
|||
renderCell: (rowData) => ( |
|||
<Button |
|||
className="btn-hover" |
|||
variant="contained" |
|||
sx={{ background: "#3082AA !important" }} |
|||
onClick={() => { |
|||
rowData.row.edit(rowData.row); |
|||
}} |
|||
> |
|||
<EditIcon /> |
|||
</Button> |
|||
), |
|||
}, |
|||
]; |
|||
|
|||
const DataTableComponents = () => { |
|||
//popUp |
|||
const [open, setOpen] = useState(false); |
|||
const theme = useTheme(); |
|||
const fullScreen = useMediaQuery(theme.breakpoints.down("md")); |
|||
const [selectedComponentModal, setSelectedComponentModal] = useState(); |
|||
|
|||
const notesThunk = useSelector((state) => state.notesThunk); |
|||
|
|||
// get note by id component |
|||
|
|||
const handleClickOpen = async (id) => { |
|||
// await dispatch(getNotesThunk(id)); |
|||
|
|||
setSelectedComponentModal(id); |
|||
|
|||
setOpen(true); |
|||
}; |
|||
|
|||
const handleClose = () => { |
|||
setOpen(false); |
|||
}; |
|||
|
|||
//reference to textarea |
|||
const textAreaRef = useRef(); |
|||
|
|||
//end PopUp |
|||
|
|||
const history = useHistory(); |
|||
const components = useSelector((state) => state.componentsFull); |
|||
const dispatch = useDispatch(); |
|||
|
|||
const getComponentsFromServer = async () => { |
|||
const data = await getComponents(); |
|||
|
|||
return data; |
|||
}; |
|||
|
|||
useEffect(() => { |
|||
const fetchData = async () => { |
|||
const data = await getComponentsFromServer(); |
|||
dispatch({ type: "GET_COMPONENTS", payload: data }); |
|||
}; |
|||
|
|||
fetchData(); |
|||
}, []); |
|||
|
|||
const processImage = (imageData, imageType) => { |
|||
const img = showImage(imageData, imageType); |
|||
return img; |
|||
}; |
|||
|
|||
// handlers |
|||
|
|||
const handleSubmitModal = (id, data) => { |
|||
let note = { |
|||
idComponent: id, |
|||
data: data, |
|||
}; |
|||
|
|||
// dispatch(addOrUpdateNotesThunk(selectedComponentModal, note)); |
|||
setOpen(false); |
|||
}; |
|||
|
|||
return ( |
|||
<div style={{ height: "70vh", width: "100%" }}> |
|||
{components.length > 0 ? ( |
|||
<> |
|||
<DataGrid |
|||
autoPageSize={true} |
|||
columns={columns} |
|||
rows={components.map((component) => { |
|||
// process image |
|||
let img; |
|||
|
|||
if (component.imageType) { |
|||
img = processImage(component.imageData, component.imageType); |
|||
} |
|||
|
|||
return { |
|||
id: component._id, |
|||
name: component.name, |
|||
description: component.description, |
|||
image: img, |
|||
category: component.category, |
|||
location: component.location, |
|||
quantity: component.quantity, |
|||
price: component.price, |
|||
unity: 'm2', |
|||
entryDate: '21/04/2021', |
|||
edit: () => { |
|||
dispatch({ type: "COMPONENT_SELECTED", payload: component }); |
|||
history.push("/editcomponent"); |
|||
}, |
|||
note: async () => { |
|||
handleClickOpen(component._id); |
|||
}, |
|||
}; |
|||
})} |
|||
getRowId={(row) => { |
|||
return row.id; |
|||
}} |
|||
onRowClick={(row) => {}} |
|||
rowHeight={80} |
|||
rowHeightMode="fixed" |
|||
rowSelectionMode="None" |
|||
selectionMode="None" |
|||
sx={{ |
|||
height: "100%", |
|||
width: "100%", |
|||
background: "#23282C", |
|||
color: "whitesmoke", |
|||
border: "1px solid #23282C", |
|||
"& .super-app-theme--header": { |
|||
backgroundColor: "rgba(255, 7, 0, 0.55)", |
|||
}, |
|||
boxShadow: 8, |
|||
}} |
|||
/> |
|||
|
|||
{/* POP UP DIALOG */} |
|||
<Dialog |
|||
fullWidth={true} |
|||
fullScreen={fullScreen} |
|||
open={open} |
|||
onClose={handleClose} |
|||
aria-labelledby="responsive-dialog-title" |
|||
> |
|||
<DialogContent> |
|||
{!notesThunk.loading ? ( |
|||
<TextField |
|||
ref={textAreaRef} |
|||
hiddenLabel |
|||
className="textField" |
|||
name="note" |
|||
label="Notas" |
|||
defaultValue={ |
|||
!notesThunk.data[0] ? "" : notesThunk.data[0].data |
|||
} |
|||
multiline |
|||
maxRows={4} |
|||
variant="outlined" |
|||
style={{ marginBottom: "2ch" }} |
|||
inputProps={{ |
|||
style: { |
|||
width: 500, |
|||
height: 80, |
|||
}, |
|||
}} |
|||
/> |
|||
) : ( |
|||
<CircularProgress /> |
|||
)} |
|||
</DialogContent> |
|||
|
|||
<DialogActions> |
|||
<Button className="textGrey" autoFocus onClick={handleClose}> |
|||
CANCELAR |
|||
</Button> |
|||
<Button |
|||
className="textGrey" |
|||
onClick={(e) => { |
|||
let id = selectedComponentModal; |
|||
let data = textAreaRef.current.children[1].children[0].value; |
|||
|
|||
handleSubmitModal(id, data); |
|||
}} |
|||
autoFocus |
|||
> |
|||
GUARDAR |
|||
</Button> |
|||
</DialogActions> |
|||
</Dialog> |
|||
</> |
|||
) : ( |
|||
<div |
|||
style={{ |
|||
display: "flex", |
|||
flexDirection: "column", |
|||
justifyContent: "center", |
|||
alignItems: "center", |
|||
height: "90%", |
|||
}} |
|||
> |
|||
<EmptySearch /> |
|||
|
|||
{/* lottie animation */} |
|||
</div> |
|||
)} |
|||
</div> |
|||
); |
|||
}; |
|||
|
|||
export default React.memo(DataTableComponents); |
|||
@ -0,0 +1,274 @@ |
|||
import React, { useState, useEffect } from "react"; |
|||
import { useParams } from "react-router-dom"; |
|||
import Box from "@mui/material/Box"; |
|||
import Collapse from "@mui/material/Collapse"; |
|||
import IconButton from "@mui/material/IconButton"; |
|||
import Table from "@mui/material/Table"; |
|||
import TableBody from "@mui/material/TableBody"; |
|||
import TableCell, { tableCellClasses } from "@mui/material/TableCell"; |
|||
import TableContainer from "@mui/material/TableContainer"; |
|||
import TableHead from "@mui/material/TableHead"; |
|||
import TableRow from "@mui/material/TableRow"; |
|||
import Typography from "@mui/material/Typography"; |
|||
import Paper from "@mui/material/Paper"; |
|||
import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown"; |
|||
import KeyboardArrowUpIcon from "@mui/icons-material/KeyboardArrowUp"; |
|||
import { styled } from "@mui/material/styles"; |
|||
import { getListProvidersByIdSupply } from "../services/orders"; |
|||
import { grey } from "@mui/material/colors"; |
|||
|
|||
const StyledTableCell = styled(TableCell)(() => ({ |
|||
[`&.${tableCellClasses.head}`]: { |
|||
backgroundColor: "#23282c", |
|||
color: "#fff", |
|||
fontSize: 16, |
|||
height: "10px", |
|||
}, |
|||
[`&.${tableCellClasses.body}`]: { |
|||
fontSize: 14, |
|||
color: "#fff", |
|||
border: "unset", |
|||
backgroundColor: "#23282c", |
|||
paddingTop: "5px", |
|||
paddingBottom: "5px", |
|||
}, |
|||
})); |
|||
|
|||
const StyledTableRow = styled(TableRow)(() => ({ |
|||
"&:nth-of-type(odd)": { |
|||
backgroundColor: "#23282c", |
|||
height: "20px", |
|||
}, |
|||
// hide last border |
|||
"&:last-child td, &:last-child th": { |
|||
border: 0, |
|||
}, |
|||
})); |
|||
|
|||
function createData( |
|||
name, |
|||
price, |
|||
lastOrderQuantity, |
|||
lastOrderDate, |
|||
description, |
|||
orders, |
|||
providersFull |
|||
) { |
|||
/* console.log("provFULL: "); |
|||
console.log( |
|||
"name:" + name, |
|||
"price: " + price, |
|||
"lastOrderQuantity: " + lastOrderQuantity, |
|||
"lastOrderDate: " + lastOrderDate, |
|||
"description: " + description, |
|||
"orders: " + orders, |
|||
"providersFull: " + providersFull |
|||
); |
|||
|
|||
console.log("providersFull dsde ACa"); |
|||
console.log(providersFull); */ |
|||
|
|||
if (orders) { |
|||
const providerMaped = orders.map((order) => { |
|||
console.log("provMap: " + order.amount); |
|||
console.log("provMap- name: " + order.date); |
|||
return { |
|||
key: order.amount, |
|||
dateH: order.date.slice(0, 10), |
|||
priceH: order.amount, |
|||
quantityH: order.quantity, |
|||
}; |
|||
}); |
|||
|
|||
return { |
|||
name, |
|||
price, |
|||
lastOrderQuantity, |
|||
lastOrderDate, |
|||
description, |
|||
history: providerMaped, |
|||
}; |
|||
} else { |
|||
return { |
|||
name, |
|||
price, |
|||
lastOrderQuantity, |
|||
lastOrderDate, |
|||
description, |
|||
|
|||
history: [], |
|||
}; |
|||
} |
|||
} |
|||
|
|||
function Row(props) { |
|||
const { row } = props; |
|||
const [open, setOpen] = React.useState(false); |
|||
|
|||
return ( |
|||
<React.Fragment> |
|||
<StyledTableRow |
|||
sx={{ "& > *": { borderBottom: "unset" }, background: "#23282C" }} |
|||
> |
|||
<StyledTableCell> |
|||
<IconButton |
|||
aria-label="expand row" |
|||
size="small" |
|||
onClick={() => setOpen(!open)} |
|||
> |
|||
{open ? <KeyboardArrowUpIcon /> : <KeyboardArrowDownIcon />} |
|||
</IconButton> |
|||
</StyledTableCell> |
|||
{/* <StyledTableCell component="th" scope="row">{row._id}</StyledTableCell> */} |
|||
<StyledTableCell style={{ display: "none" }} align="right"> |
|||
{row._id} |
|||
</StyledTableCell> |
|||
<StyledTableCell align="left">{row.name}</StyledTableCell> |
|||
<StyledTableCell align="right">{row.price}</StyledTableCell> |
|||
<StyledTableCell align="right">{row.lastOrderQuantity}</StyledTableCell> |
|||
<StyledTableCell align="right">{row.lastOrderDate}</StyledTableCell> |
|||
</StyledTableRow> |
|||
<StyledTableRow> |
|||
<StyledTableCell style={{ paddingTop: 0 }} colSpan={6}> |
|||
<Collapse in={open} timeout="auto" unmountOnExit> |
|||
<Box sx={{ marginTop: 1, borderBottom: "0.5px solid grey" }}> |
|||
<h4 |
|||
style={{ paddingLeft: 15, color: "#3082aa", fontWeight: "100" }} |
|||
> |
|||
Historial |
|||
</h4> |
|||
|
|||
<Table |
|||
size="small" |
|||
aria-label="historial" |
|||
style={{ width: "100%" }} |
|||
> |
|||
<TableHead> |
|||
<StyledTableRow> |
|||
<StyledTableCell |
|||
style={{ fontSize: "13px" }} |
|||
align="right" |
|||
></StyledTableCell> |
|||
<StyledTableCell style={{ fontSize: "13px" }} align="right"> |
|||
Precio |
|||
</StyledTableCell> |
|||
<StyledTableCell style={{ fontSize: "13px" }} align="right"> |
|||
Cantidad |
|||
</StyledTableCell> |
|||
<StyledTableCell style={{ fontSize: "13px" }} align="right"> |
|||
Fecha de ingreso |
|||
</StyledTableCell> |
|||
</StyledTableRow> |
|||
</TableHead> |
|||
<TableBody> |
|||
{row.history.map((historyRow) => ( |
|||
<StyledTableRow key={historyRow._id}> |
|||
<StyledTableCell |
|||
style={{ fontSize: "13px" }} |
|||
align="right" |
|||
width="29%" |
|||
></StyledTableCell> |
|||
<StyledTableCell |
|||
style={{ fontSize: "13px" }} |
|||
align="right" |
|||
> |
|||
{historyRow.priceH} |
|||
</StyledTableCell> |
|||
<StyledTableCell |
|||
style={{ fontSize: "13px" }} |
|||
align="right" |
|||
width="17%" |
|||
> |
|||
{historyRow.quantityH} |
|||
</StyledTableCell> |
|||
<StyledTableCell |
|||
style={{ fontSize: "13px" }} |
|||
component="th" |
|||
scope="row" |
|||
align="right" |
|||
> |
|||
{historyRow.dateH} |
|||
</StyledTableCell> |
|||
</StyledTableRow> |
|||
))} |
|||
</TableBody> |
|||
</Table> |
|||
</Box> |
|||
</Collapse> |
|||
</StyledTableCell> |
|||
</StyledTableRow> |
|||
</React.Fragment> |
|||
); |
|||
} |
|||
|
|||
export default function DataTableProvidersDetail(props) { |
|||
console.log("providers desde dataTableP"); |
|||
console.log(props.selectedSupply); |
|||
|
|||
const [orders, setOrders] = useState([]); |
|||
|
|||
let total = 0; |
|||
|
|||
const params = useParams(); |
|||
|
|||
const loadOrders = async () => { |
|||
const orders = await getListProvidersByIdSupply(params.id); |
|||
setOrders(orders); |
|||
}; |
|||
|
|||
useEffect(() => { |
|||
loadOrders(); |
|||
}, []); |
|||
|
|||
/* console.log("ver los orders"); |
|||
console.log(orders); */ |
|||
|
|||
const rows = orders.map((e) => { |
|||
total += e.total; |
|||
props.funcTotal(total); |
|||
|
|||
// last orders amount |
|||
const lastOrder = e.orders[e.orders.length - 1].amount; |
|||
|
|||
//last orders quantity |
|||
const lastOrderQuantity = e.orders[e.orders.length - 1].quantity; |
|||
|
|||
// last orders date |
|||
const lastOrderDate = e.orders[e.orders.length - 1].date.slice(0, 10); |
|||
|
|||
return createData( |
|||
e.name.name, |
|||
lastOrder, |
|||
lastOrderQuantity, |
|||
lastOrderDate, |
|||
e.name.description, |
|||
e.orders, |
|||
orders |
|||
); |
|||
}); |
|||
|
|||
return ( |
|||
<> |
|||
<TableContainer component={Paper} style={{ width: "93%" }}> |
|||
<Table aria-label="collapsible table"> |
|||
<TableHead> |
|||
<StyledTableRow> |
|||
<StyledTableCell /> |
|||
<StyledTableCell>Proveedor</StyledTableCell> |
|||
<StyledTableCell align="right">Precio</StyledTableCell> |
|||
<StyledTableCell align="right">Cantidad</StyledTableCell> |
|||
<StyledTableCell align="right"> |
|||
última Fecha de Ingreso |
|||
</StyledTableCell> |
|||
</StyledTableRow> |
|||
</TableHead> |
|||
<TableBody> |
|||
{rows.map((row) => ( |
|||
<Row key={row._id} row={row} /> |
|||
))} |
|||
</TableBody> |
|||
</Table> |
|||
</TableContainer> |
|||
</> |
|||
); |
|||
} |
|||
@ -0,0 +1,282 @@ |
|||
import React, { useEffect, useRef, useState } from "react"; |
|||
import { DataGrid } from "@mui/x-data-grid"; |
|||
import { useDispatch, useSelector } from "react-redux"; |
|||
import { Button, CircularProgress, TextField } from "@mui/material"; |
|||
import { useHistory } from "react-router-dom"; |
|||
import EditIcon from "@mui/icons-material/Edit"; |
|||
import NoteIcon from "@mui/icons-material/Notes"; |
|||
import EyeIcon from "@mui/icons-material/Visibility"; |
|||
import EmptySearch from "./AnimationEmptySearch"; |
|||
import { addOrUpdateNotesThunk, getNotesThunk } from "../reducers/notes"; |
|||
import Dialog from "@mui/material/Dialog"; |
|||
import DialogActions from "@mui/material/DialogActions"; |
|||
import DialogContent from "@mui/material/DialogContent"; |
|||
import useMediaQuery from "@mui/material/useMediaQuery"; |
|||
import { useTheme } from "@mui/material/styles"; |
|||
import { assignProviderAndPrice } from "../services/supplies"; |
|||
import { configure } from "@testing-library/react"; |
|||
// import { getSuppliesThunk, newProviderThunkRedux } from "../reducers/supplies"; |
|||
// import { ContentPasteGoOutlined } from "@mui/icons-material"; |
|||
|
|||
const columns = [ |
|||
{ field: "id", headerName: "ID", width: 70, hide: true }, |
|||
{ |
|||
field: "imageSupply", |
|||
headerName: "Imagen", |
|||
width: 80, |
|||
renderCell: (rowData) => { |
|||
return ( |
|||
<div |
|||
style={{ |
|||
borderRadius: "50%", |
|||
overflow: "hidden", |
|||
width: "55px", |
|||
height: "55px", |
|||
}} |
|||
> |
|||
<img |
|||
alt="imagen" |
|||
style={{ |
|||
height: "100%", |
|||
width: "100%", |
|||
}} |
|||
src={rowData.row.imageSupply} |
|||
/> |
|||
</div> |
|||
); |
|||
}, |
|||
}, |
|||
{ field: "name", headerName: "Nombre", flex: 1, minWidth: 70 }, |
|||
{ field: "code", headerName: "Código", flex: 1, minWidth: 70 }, |
|||
{ field: "category", headerName: "Categoría", flex: 1, minWidth: 100 }, |
|||
{ field: "description", headerName: "Descripción", flex: 1, minWidth: 100 }, |
|||
|
|||
{ field: "location", headerName: "Ubicación", flex: 1, minWidth: 50 }, |
|||
{ field: "unity", headerName: "Unidad de medida", flex: 1, minWidth: 80 }, |
|||
|
|||
{ |
|||
field: "note", |
|||
headerName: "Notas", |
|||
width: 100, |
|||
renderCell: (rowData) => ( |
|||
<Button |
|||
className="btn-hover" |
|||
variant="contained" |
|||
sx={{ background: "#3082AA !important" }} |
|||
onClick={() => { |
|||
rowData.row.note(rowData.row); |
|||
}} |
|||
> |
|||
<NoteIcon /> |
|||
</Button> |
|||
), |
|||
}, |
|||
{ |
|||
field: "providers", |
|||
headerName: "Proveedores", |
|||
width: 100, |
|||
renderCell: (rowData) => ( |
|||
<Button |
|||
className="btn-hover" |
|||
variant="contained" |
|||
sx={{ background: "#3082AA !important" }} |
|||
onClick={() => { |
|||
rowData.row.providers(rowData.row); |
|||
}} |
|||
> |
|||
<EyeIcon /> |
|||
</Button> |
|||
), |
|||
}, |
|||
{ |
|||
field: "edit", |
|||
headerName: "Editar", |
|||
width: 90, |
|||
renderCell: (rowData) => ( |
|||
<Button |
|||
className="btn-hover" |
|||
variant="contained" |
|||
sx={{ background: "#3082AA !important" }} |
|||
onClick={() => { |
|||
rowData.row.edit(rowData.row); |
|||
}} |
|||
> |
|||
<EditIcon /> |
|||
</Button> |
|||
), |
|||
}, |
|||
]; |
|||
|
|||
const DataTableSupplies = ({ suppliesThunk }) => { |
|||
const supplies = suppliesThunk.data; |
|||
|
|||
//popUp |
|||
const [open, setOpen] = useState(false); |
|||
const theme = useTheme(); |
|||
const fullScreen = useMediaQuery(theme.breakpoints.down("md")); |
|||
const [selectedComponentModal, setSelectedComponentModal] = useState(); |
|||
|
|||
const notesThunk = useSelector((state) => state.notesThunk); |
|||
|
|||
// get note by id component |
|||
console.log("supplies ---->" + supplies); |
|||
const handleClickOpen = async (id) => { |
|||
await dispatch(getNotesThunk(id)); |
|||
setSelectedComponentModal(id); |
|||
setOpen(true); |
|||
}; |
|||
|
|||
const handleClose = () => { |
|||
setOpen(false); |
|||
}; |
|||
|
|||
//reference to textarea |
|||
const textAreaRef = useRef(); |
|||
|
|||
//end PopUp |
|||
|
|||
const history = useHistory(); |
|||
const dispatch = useDispatch(); |
|||
|
|||
// handlers |
|||
|
|||
const handleSubmitModal = (id, note) => { |
|||
dispatch(addOrUpdateNotesThunk(id, note)); |
|||
setOpen(false); |
|||
}; |
|||
|
|||
return ( |
|||
<div style={{ height: "70vh", width: "100%" }}> |
|||
{supplies.length > 0 ? ( |
|||
<> |
|||
<DataGrid |
|||
autoPageSize={true} |
|||
columns={columns} |
|||
rows={supplies.map((supply, index) => { |
|||
return { |
|||
id: supply._id, |
|||
name: supply.name, |
|||
code: supply.code, |
|||
description: supply.description, |
|||
imageSupply: supply.imageSupply, |
|||
category: supply.category.name, |
|||
location: supply.location, |
|||
unity: supply.unity, |
|||
// edit: () => { |
|||
|
|||
// history.push(`/editsupply/${supply._id}`); |
|||
// }, |
|||
edit: () => { |
|||
dispatch({ |
|||
type: "COMPONENT_SELECTED", |
|||
payload: supply, |
|||
}); |
|||
// console.log("versupply", supply); |
|||
history.push(`/editsupply/${supply._id}`); |
|||
}, |
|||
note: async () => { |
|||
handleClickOpen(supply._id); |
|||
}, |
|||
providers: () => { |
|||
dispatch({ |
|||
type: "COMPONENT_SELECTED", |
|||
payload: supply, |
|||
}); |
|||
history.push(`/providersDetail/${supply._id}`); |
|||
}, |
|||
}; |
|||
})} |
|||
getRowId={(row) => { |
|||
return row.id; |
|||
}} |
|||
onRowClick={(row) => {}} |
|||
rowHeight={65} |
|||
rowHeightMode="fixed" |
|||
rowSelectionMode="None" |
|||
selectionMode="None" |
|||
sx={{ |
|||
fontSize: "0.8rem", |
|||
height: "100%", |
|||
width: "100%", |
|||
background: "#23282C", |
|||
color: "whitesmoke", |
|||
border: "1px solid #23282C", |
|||
"& .super-app-theme--header": { |
|||
backgroundColor: "rgba(255, 7, 0, 0.55)", |
|||
}, |
|||
boxShadow: 8, |
|||
}} |
|||
/> |
|||
|
|||
{/* POP UP DIALOG */} |
|||
<Dialog |
|||
fullWidth={true} |
|||
fullScreen={fullScreen} |
|||
open={open} |
|||
onClose={handleClose} |
|||
aria-labelledby="responsive-dialog-title" |
|||
> |
|||
<DialogContent> |
|||
{!notesThunk.loading ? ( |
|||
<TextField |
|||
ref={textAreaRef} |
|||
hiddenLabel |
|||
className="textField" |
|||
name="note" |
|||
label="Notas" |
|||
defaultValue={!notesThunk.data ? "" : notesThunk.data} |
|||
multiline |
|||
maxRows={4} |
|||
variant="outlined" |
|||
style={{ marginBottom: "2ch" }} |
|||
inputProps={{ |
|||
style: { |
|||
width: 500, |
|||
height: 80, |
|||
}, |
|||
}} |
|||
/> |
|||
) : ( |
|||
<CircularProgress /> |
|||
)} |
|||
</DialogContent> |
|||
|
|||
<DialogActions> |
|||
<Button className="textGrey" autoFocus onClick={handleClose}> |
|||
CANCELAR |
|||
</Button> |
|||
<Button |
|||
className="textGrey" |
|||
onClick={(e) => { |
|||
let id = selectedComponentModal; |
|||
let data = textAreaRef.current.children[1].children[0].value; |
|||
|
|||
handleSubmitModal(id, data); |
|||
}} |
|||
autoFocus |
|||
> |
|||
GUARDAR |
|||
</Button> |
|||
</DialogActions> |
|||
</Dialog> |
|||
</> |
|||
) : ( |
|||
<div |
|||
style={{ |
|||
display: "flex", |
|||
flexDirection: "column", |
|||
justifyContent: "center", |
|||
alignItems: "center", |
|||
height: "90%", |
|||
}} |
|||
> |
|||
<EmptySearch /> |
|||
|
|||
{/* lottie animation */} |
|||
</div> |
|||
)} |
|||
</div> |
|||
); |
|||
}; |
|||
|
|||
export default React.memo(DataTableSupplies); |
|||
@ -0,0 +1,201 @@ |
|||
import React, { useState } from "react"; |
|||
import { DataGrid } from "@mui/x-data-grid"; |
|||
import { useDispatch} from "react-redux"; |
|||
import { Button} from "@mui/material"; |
|||
import { useHistory } from "react-router-dom"; |
|||
import DeleteIcon from "@mui/icons-material/Delete"; |
|||
import RestorePageIcon from "@mui/icons-material/RestorePage"; |
|||
import EmptySearch from "./AnimationEmptySearch"; |
|||
import useMediaQuery from "@mui/material/useMediaQuery"; |
|||
import { useTheme } from "@mui/material/styles"; |
|||
import { deleteSupply, deleteSupplyDefinitely } from "../services/supplies"; |
|||
|
|||
const columns = [ |
|||
{ field: "id", headerName: "ID", width: 70, hide: true }, |
|||
{ |
|||
field: "imageSupply", |
|||
headerName: "Imagen", |
|||
width: 80, |
|||
renderCell: (rowData) => { |
|||
return ( |
|||
<div |
|||
style={{ |
|||
borderRadius: "50%", |
|||
overflow: "hidden", |
|||
width: "55px", |
|||
height: "55px", |
|||
}} |
|||
> |
|||
<img |
|||
alt="imagen" |
|||
style={{ |
|||
height: "100%", |
|||
width: "100%", |
|||
opacity: "0.5", |
|||
}} |
|||
src={rowData.row.imageSupply} |
|||
/> |
|||
</div> |
|||
); |
|||
}, |
|||
}, |
|||
{ field: "name", headerName: "Nombre", flex: 1, minWidth: 70 }, |
|||
{ field: "code", headerName: "Código", flex: 1, minWidth: 70 }, |
|||
{ field: "category", headerName: "Categoría", flex: 1, minWidth: 100 }, |
|||
{ field: "description", headerName: "Descripción", flex: 1, minWidth: 100 }, |
|||
|
|||
{ field: "location", headerName: "Ubicación", flex: 1, minWidth: 50 }, |
|||
{ field: "quantity", headerName: "Cantidad", flex: 1, minWidth: 50 }, |
|||
{ field: "unity", headerName: "Unidad de medida", flex: 1, minWidth: 80 }, |
|||
{ field: "price", headerName: "Precio", flex: 1, minWidth: 30 }, |
|||
|
|||
{ |
|||
field: "entryDate", |
|||
headerName: "Fecha de Ingreso", |
|||
flex: 1, |
|||
minWidth: 50, |
|||
}, |
|||
{ |
|||
field: "restore", |
|||
headerName: "Restaurar", |
|||
width: 100, |
|||
renderCell: (rowData) => ( |
|||
<Button |
|||
className="btn-hover" |
|||
variant="contained" |
|||
color="success" |
|||
onClick={() => { |
|||
rowData.row.restore(rowData.row); |
|||
}} |
|||
> |
|||
<RestorePageIcon /> |
|||
</Button> |
|||
), |
|||
}, |
|||
{ |
|||
field: "deleteDB", |
|||
headerName: "Eliminar", |
|||
width: 90, |
|||
renderCell: (rowData) => ( |
|||
<Button |
|||
className="btn-hover" |
|||
variant="contained" |
|||
color="error" |
|||
onClick={() => { |
|||
rowData.row.deleteDB(rowData.row); |
|||
}} |
|||
> |
|||
<DeleteIcon /> |
|||
</Button> |
|||
), |
|||
}, |
|||
]; |
|||
|
|||
const DataTableSupplies = ({ suppliesThunk }) => { |
|||
const supplies = suppliesThunk; |
|||
|
|||
|
|||
//delete service |
|||
const handleSubmitDelete = (supplyId) => { |
|||
|
|||
const response = deleteSupplyDefinitely(supplyId); |
|||
if (response !== null) { |
|||
history.push("/supplies"); |
|||
} |
|||
}; |
|||
|
|||
// restore handler |
|||
const handleRestore = (supplyId) => { |
|||
const response = deleteSupply(supplyId); |
|||
if (response !== null) { |
|||
history.push("/supplies"); |
|||
} |
|||
}; |
|||
|
|||
|
|||
const history = useHistory(); |
|||
const dispatch = useDispatch(); |
|||
|
|||
return ( |
|||
<div style={{ height: "70vh", width: "100%" }}> |
|||
{supplies.length > 0 ? ( |
|||
<> |
|||
<DataGrid |
|||
autoPageSize={true} |
|||
columns={columns} |
|||
rows={supplies.map((supply, index) => { |
|||
return { |
|||
id: supply._id, |
|||
name: supply.name, |
|||
code: supply.code, |
|||
description: supply.description, |
|||
imageSupply: supply.imageSupply, |
|||
category: supply.category.name, |
|||
location: supply.location, |
|||
quantity: supply.quantity, |
|||
price: "$500 hardcode", //TODO? ver |
|||
|
|||
unity: supply.unity, |
|||
entryDate: supply.dateSupply.slice(0, 10), |
|||
deleteDB: () => { |
|||
dispatch({ |
|||
type: "COMPONENT_SELECTED", |
|||
payload: supply, |
|||
}); |
|||
handleSubmitDelete(supply._id); |
|||
|
|||
console.log("versupply ID", supply._id); |
|||
//history.push(`/supplies`); |
|||
}, |
|||
|
|||
restore: () => { |
|||
dispatch({ |
|||
type: "COMPONENT_SELECTED", |
|||
payload: supply, |
|||
}); |
|||
handleRestore(supply._id); |
|||
history.push("/supplies"); |
|||
}, |
|||
}; |
|||
})} |
|||
getRowId={(row) => { |
|||
return row.id; |
|||
}} |
|||
onRowClick={(row) => {}} |
|||
rowHeight={65} |
|||
rowHeightMode="fixed" |
|||
rowSelectionMode="None" |
|||
selectionMode="None" |
|||
sx={{ |
|||
fontSize: "0.8rem", |
|||
height: "100%", |
|||
width: "100%", |
|||
background: "#23282C", |
|||
color: "#bebebe", |
|||
border: "1px solid #23282C", |
|||
"& .super-app-theme--header": { |
|||
backgroundColor: "rgba(255, 7, 0, 0.55)", |
|||
}, |
|||
boxShadow: 8, |
|||
}} |
|||
/> |
|||
</> |
|||
) : ( |
|||
<div |
|||
style={{ |
|||
display: "flex", |
|||
flexDirection: "column", |
|||
justifyContent: "center", |
|||
alignItems: "center", |
|||
height: "90%", |
|||
}} |
|||
> |
|||
{/* lottie animation */} |
|||
<EmptySearch /> |
|||
</div> |
|||
)} |
|||
</div> |
|||
); |
|||
}; |
|||
|
|||
export default React.memo(DataTableSupplies); |
|||
@ -0,0 +1,20 @@ |
|||
import { useLottie } from "lottie-react"; |
|||
import downArrow from "../assets/downArrow.json"; |
|||
|
|||
const DownArrow = () => { |
|||
const options = { |
|||
animationData: downArrow, |
|||
loop: true, |
|||
autoplay: true, |
|||
}; |
|||
|
|||
const style = { |
|||
height: 150, |
|||
}; |
|||
|
|||
const { View } = useLottie(options, style); |
|||
|
|||
return <>{View}</>; |
|||
}; |
|||
|
|||
export default DownArrow; |
|||
@ -0,0 +1,330 @@ |
|||
import Box from "@mui/material/Box"; |
|||
import TextField from "@mui/material/TextField"; |
|||
import MenuItem from "@mui/material/MenuItem"; |
|||
import Button from "@mui/material/Button"; |
|||
import Paper from "@mui/material/Paper"; |
|||
import Grid from "@mui/material/Grid"; |
|||
import { InputAdornment } from "@mui/material"; |
|||
|
|||
import React, { useState } from "react"; |
|||
import { createFormData } from "../utils/formUtils"; |
|||
import { addComponent } from "../services/components"; |
|||
import { useHistory } from "react-router-dom"; |
|||
|
|||
import { sendCsvFile } from "../services/components"; |
|||
import { styled } from "@mui/material/styles"; |
|||
import IconButton from "@mui/material/IconButton"; |
|||
import UploadFileIcon from "@mui/icons-material/UploadFile"; |
|||
|
|||
const categories = [ |
|||
{ |
|||
value: "Generales", |
|||
label: "Generales", |
|||
}, |
|||
{ |
|||
value: "Circuitos integrados", |
|||
label: "Circuitos integrados", |
|||
}, |
|||
{ |
|||
value: "Diodos", |
|||
label: "Diodos", |
|||
}, |
|||
{ |
|||
value: "Fichas, cables y pines", |
|||
label: "Fichas, cables y pines", |
|||
}, |
|||
{ |
|||
value: "Modulos", |
|||
label: "Modulos", |
|||
}, |
|||
{ |
|||
value: "Pasivos", |
|||
label: "Pasivos", |
|||
}, |
|||
{ |
|||
value: "Pantallas", |
|||
label: "Pantallas", |
|||
}, |
|||
{ |
|||
value: "Sensores", |
|||
label: "Sensores", |
|||
}, |
|||
{ |
|||
value: "Otros", |
|||
label: "Otros", |
|||
}, |
|||
]; |
|||
|
|||
const Input = styled("input")({ |
|||
display: "none", |
|||
}); |
|||
|
|||
export default function FormComponent() { |
|||
// history |
|||
const history = useHistory(); |
|||
|
|||
const [csv, setCsv] = useState([]); |
|||
|
|||
// form state |
|||
const [form, setForm] = useState({ |
|||
name: "", |
|||
descript: "", |
|||
image: "", |
|||
quantity: "", |
|||
category: "", |
|||
price: "", |
|||
location: "", |
|||
}); |
|||
|
|||
const [image, setImage] = useState({ preview: "", raw: "" }); |
|||
|
|||
// handlers for form |
|||
const handleChange = (e) => { |
|||
setForm({ |
|||
...form, |
|||
[e.target.name]: e.target.value, |
|||
}); |
|||
}; |
|||
|
|||
const handleImage = (e) => { |
|||
if (e.target.files.length) { |
|||
setImage({ |
|||
preview: URL.createObjectURL(e.target.files[0]), |
|||
raw: e.target.files[0], |
|||
}); |
|||
} |
|||
|
|||
setForm({ |
|||
...form, |
|||
image: e.target.files[0], |
|||
}); |
|||
}; |
|||
|
|||
const handleSubmit = async (e) => { |
|||
e.preventDefault(); |
|||
|
|||
if (!csv.name) { |
|||
const formData = createFormData(form); |
|||
addComponentToServer(formData); |
|||
// reset states |
|||
setForm({ |
|||
name: "", |
|||
descript: "", |
|||
image: "", |
|||
quantity: "", |
|||
category: "", |
|||
price: "", |
|||
location: "", |
|||
}); |
|||
|
|||
setImage({ preview: "", raw: "" }); |
|||
} else { |
|||
const formData = new FormData(); |
|||
formData.append("file", csv); |
|||
const res = await sendCsvFile(formData); |
|||
console.log(res); |
|||
if (res !== null) { |
|||
history.push("/components"); |
|||
} |
|||
} |
|||
}; |
|||
//============================================================================== |
|||
|
|||
// add component |
|||
const addComponentToServer = async (form) => { |
|||
const response = await addComponent(form); |
|||
if (response !== null) { |
|||
history.push("/components"); |
|||
} |
|||
}; |
|||
|
|||
return ( |
|||
<> |
|||
<Paper elevation={3} style={{ padding: "5ch", background: " #23282C" }}> |
|||
<div |
|||
style={{ |
|||
display: "flex", |
|||
justifyContent: "space-around", |
|||
width: "60vw", |
|||
}} |
|||
> |
|||
<div |
|||
style={{ |
|||
display: "flex", |
|||
justifyContent: "space-between", |
|||
flexDirection: "column", |
|||
}} |
|||
> |
|||
<TextField |
|||
name="name" |
|||
className="textField" |
|||
label="Nombre" |
|||
variant="outlined" |
|||
onChange={handleChange} |
|||
|
|||
// sx= {{color: 'whitesmoke'}} |
|||
/> |
|||
|
|||
<div style={{ display: "flex", flexDirection: "row" }}> |
|||
<TextField |
|||
className="textField" |
|||
name="category" |
|||
select |
|||
label="Categoría" |
|||
value={form.category} |
|||
onChange={handleChange} |
|||
style={{ width: "28ch" }} |
|||
> |
|||
{categories.map((option) => ( |
|||
<MenuItem key={option.value} value={option.value}> |
|||
{option.label} |
|||
</MenuItem> |
|||
))} |
|||
</TextField> |
|||
<TextField |
|||
className="textField" |
|||
name="quantity" |
|||
label="Cantidad" |
|||
type="number" |
|||
style={{ width: "10ch", marginLeft: "2ch" }} |
|||
InputLabelProps={{ |
|||
shrink: true, |
|||
}} |
|||
onChange={handleChange} |
|||
/> |
|||
</div> |
|||
<TextField |
|||
className="textField" |
|||
name="price" |
|||
label="Precio" |
|||
InputProps={{ |
|||
startAdornment: ( |
|||
<InputAdornment position="start">$</InputAdornment> |
|||
), |
|||
}} |
|||
variant="outlined" |
|||
onChange={handleChange} |
|||
type="number" |
|||
/> |
|||
<TextField |
|||
className="textField" |
|||
name="location" |
|||
label="Ubicación" |
|||
variant="outlined" |
|||
onChange={handleChange} |
|||
type="text" |
|||
/> |
|||
</div> |
|||
<div |
|||
style={{ |
|||
display: "flex", |
|||
width: "50%", |
|||
justifyContent: "space-evenly", |
|||
flexDirection: "column", |
|||
}} |
|||
> |
|||
<TextField |
|||
className="textField" |
|||
name="descript" |
|||
label="Descripcion" |
|||
variant="outlined" |
|||
onChange={handleChange} |
|||
style={{ marginBottom: "2ch" }} |
|||
multiline="true" |
|||
inputProps={{ |
|||
style: { |
|||
height: 80, |
|||
}, |
|||
}} |
|||
/> |
|||
<Grid |
|||
container |
|||
direction="row" |
|||
alignItems="center" |
|||
justifyContent="center" |
|||
> |
|||
<Grid item xs={5}> |
|||
<div |
|||
style={{ |
|||
background: "whitesmoke", |
|||
display: "flex", |
|||
justifyContent: "center", |
|||
overflow: "hidden", |
|||
borderRadius: "50%", |
|||
width: "200px", |
|||
height: "200px", |
|||
}} |
|||
> |
|||
<Button |
|||
style={{ |
|||
padding: "0", |
|||
}} |
|||
href="#" |
|||
onClick={(e) => { |
|||
e.preventDefault(); |
|||
document.getElementById("image").click(); |
|||
}} |
|||
> |
|||
<img |
|||
src={ |
|||
image.preview |
|||
? image.preview |
|||
: "https://thealmanian.com/wp-content/uploads/2019/01/product_image_thumbnail_placeholder.png" |
|||
} |
|||
alt="preview" |
|||
style={{ |
|||
width: "100%", |
|||
objectFit: "fill", |
|||
}} |
|||
/> |
|||
</Button> |
|||
<input |
|||
type="file" |
|||
id="image" |
|||
name="image" |
|||
accept="image/*" |
|||
style={{ display: "none" }} |
|||
onChange={handleImage} |
|||
/> |
|||
</div> |
|||
</Grid> |
|||
</Grid> |
|||
</div> |
|||
</div> |
|||
</Paper> |
|||
<div |
|||
style={{ |
|||
display: "flex", |
|||
justifyContent: "flex-end", |
|||
marginTop: "3ch", |
|||
width: "66vw", |
|||
}} |
|||
> |
|||
<label htmlFor="icon-button-file"> |
|||
<Input |
|||
id="icon-button-file" |
|||
type="file" |
|||
name="file" |
|||
onChange={(e) => { |
|||
const file = e.target.files[0]; |
|||
setCsv(file); |
|||
}} |
|||
/> |
|||
<IconButton color="primary" aria-label="upload file" component="span"> |
|||
<UploadFileIcon /> |
|||
</IconButton> |
|||
</label> |
|||
|
|||
<Button |
|||
type="submit" |
|||
variant="contained" |
|||
color="primary" |
|||
onClick={handleSubmit} |
|||
sx={{ ml: "20px" }} |
|||
> |
|||
Agregar |
|||
</Button> |
|||
</div> |
|||
</> |
|||
); |
|||
} |
|||
@ -0,0 +1,251 @@ |
|||
import TextField from "@mui/material/TextField"; |
|||
import MenuItem from "@mui/material/MenuItem"; |
|||
import Button from "@mui/material/Button"; |
|||
import { DialogTitle } from "@mui/material"; |
|||
import { useState, useEffect, useRef } from "react"; |
|||
import { createFormData } from "../utils/formUtils"; |
|||
import { useHistory } from "react-router-dom"; |
|||
import { styled } from "@mui/material/styles"; |
|||
import AddIcon from "@mui/icons-material/Add"; |
|||
import { getProviders, addProvider } from "../services/providers"; |
|||
import { useParams } from "react-router-dom"; |
|||
import { addOrder } from "../services/orders"; |
|||
|
|||
import { getSupplyById } from "../services/supplies"; |
|||
|
|||
//sockets |
|||
import io from "socket.io-client"; |
|||
|
|||
//pop up |
|||
import Dialog from "@mui/material/Dialog"; |
|||
import DialogActions from "@mui/material/DialogActions"; |
|||
import DialogContent from "@mui/material/DialogContent"; |
|||
|
|||
const API = process.env.REACT_APP_API; |
|||
|
|||
export default function FormNewOrder({ supplyData }) { |
|||
console.log("supplyData", supplyData); |
|||
|
|||
//popUp |
|||
const [openP, setOpenP] = useState(false); |
|||
|
|||
const handleClickOpenP = () => { |
|||
setOpenP(true); |
|||
}; |
|||
|
|||
const handleCloseP = () => { |
|||
setOpenP(false); |
|||
}; |
|||
|
|||
// history |
|||
const history = useHistory(); |
|||
|
|||
// form state |
|||
const [form, setForm] = useState({ |
|||
idProduct: supplyData._id, |
|||
idProvider: "", |
|||
description: "", |
|||
quantity: "", |
|||
amount: "", |
|||
}); |
|||
|
|||
console.log("form antes: " + form.idProduct); |
|||
|
|||
// handlers |
|||
|
|||
const handleChange = (e) => { |
|||
setForm({ |
|||
...form, |
|||
idProduct: supplyData._id, |
|||
[e.target.name]: e.target.value, |
|||
}); |
|||
}; |
|||
|
|||
const handleSubmit = async (e) => { |
|||
e.preventDefault(); |
|||
|
|||
addNewOrderToServer(form); |
|||
|
|||
// reset states |
|||
setForm({ |
|||
idProduct: supplyData._id, |
|||
description: "", |
|||
idProvider: "", |
|||
quantity: "", |
|||
amount: "", |
|||
}); |
|||
}; |
|||
|
|||
//============================================================================== |
|||
|
|||
//services |
|||
|
|||
// add supply |
|||
const addNewOrderToServer = async (form) => { |
|||
console.log("form VERVER", form); |
|||
const response = await addOrder(form); |
|||
console.log("response", response); |
|||
if (response !== null) { |
|||
history.push(`/providersDetail/${supplyData._id}`); |
|||
} |
|||
}; |
|||
|
|||
//PROVIDERS |
|||
const socketRef = useRef(); |
|||
const [providers, setProviders] = useState([]); |
|||
const [newProvider, setNewProvider] = useState({ |
|||
name: "", |
|||
}); |
|||
|
|||
const handleChangeProviders = (event) => { |
|||
setNewProvider({ |
|||
...newProvider, |
|||
[event.target.name]: event.target.value, |
|||
}); |
|||
}; |
|||
|
|||
const handleSubmitProvider = (event) => { |
|||
event.preventDefault(); |
|||
console.log(newProvider.name); |
|||
addProvider({ |
|||
name: newProvider.name, |
|||
description: "", |
|||
}); |
|||
|
|||
handleCloseP(); |
|||
}; |
|||
|
|||
//Crea el array de proveedores y queda a la escucha de nuevos posts |
|||
|
|||
useEffect(() => { |
|||
socketRef.current = io.connect(`${API}`); |
|||
|
|||
socketRef.current.on("listenProviders", async () => { |
|||
loadProviders(); |
|||
}); |
|||
|
|||
const loadProviders = async () => { |
|||
const providers = await getProviders(); |
|||
setProviders(providers); |
|||
console.log(providers); |
|||
}; |
|||
loadProviders(); |
|||
}, []); |
|||
|
|||
return ( |
|||
<> |
|||
<div |
|||
style={{ |
|||
display: "flex", |
|||
flexDirection: "column", |
|||
justifyContent: "space-around", |
|||
width: "60vw", |
|||
background: " #23282C", |
|||
padding: "5ch", |
|||
}} |
|||
> |
|||
<div style={{ display: "flex", width: "90%" }}> |
|||
<TextField |
|||
className="textField" |
|||
name="idProvider" |
|||
style={{ width: "50%", marginBottom: "15px" }} |
|||
select |
|||
value={form.idProvider} |
|||
onChange={handleChange} |
|||
label="Proveedor" |
|||
> |
|||
{providers.map((item) => ( |
|||
<MenuItem key={item._id} value={item._id}> |
|||
{item.name} |
|||
</MenuItem> |
|||
))} |
|||
</TextField> |
|||
<Button |
|||
className="btn-hover" |
|||
variant="contained" |
|||
sx={{ background: "#3082AA !important", marginBottom: "15px" }} |
|||
onClick={handleClickOpenP} |
|||
> |
|||
<AddIcon /> |
|||
</Button> |
|||
</div> |
|||
|
|||
<TextField |
|||
className="textField" |
|||
name="quantity" |
|||
label="Cantidad" |
|||
variant="outlined" |
|||
onChange={handleChange} |
|||
type="number" |
|||
style={{ width: "45%", marginBottom: "15px" }} |
|||
/> |
|||
|
|||
<TextField |
|||
className="textField" |
|||
name="amount" |
|||
label="Precio" |
|||
variant="outlined" |
|||
onChange={handleChange} |
|||
type="number" |
|||
style={{ width: "45%", marginBottom: "15px" }} |
|||
/> |
|||
|
|||
<TextField |
|||
className="textField" |
|||
name="description" |
|||
label="Descripcion" |
|||
variant="outlined" |
|||
onChange={handleChange} |
|||
style={{ marginBottom: "15px" }} |
|||
multiline |
|||
inputProps={{ |
|||
style: { |
|||
height: 80, |
|||
}, |
|||
}} |
|||
/> |
|||
</div> |
|||
<div |
|||
style={{ |
|||
display: "flex", |
|||
justifyContent: "flex-end", |
|||
marginTop: "3ch", |
|||
width: "66vw", |
|||
}} |
|||
> |
|||
<Button |
|||
type="submit" |
|||
variant="contained" |
|||
color="primary" |
|||
onClick={handleSubmit} |
|||
sx={{ ml: "20px" }} |
|||
> |
|||
Agregar |
|||
</Button> |
|||
|
|||
{/* POP UP DIALOG PROVIDERS */} |
|||
<Dialog open={openP} onClose={handleCloseP}> |
|||
<DialogTitle>Nuevo Proveedor</DialogTitle> |
|||
<DialogContent> |
|||
<TextField |
|||
autoFocus |
|||
name="name" |
|||
margin="dense" |
|||
id="provider" |
|||
label="Proveedor" |
|||
onChange={handleChangeProviders} |
|||
type="string" |
|||
fullWidth |
|||
variant="standard" |
|||
/> |
|||
</DialogContent> |
|||
|
|||
<DialogActions> |
|||
<Button onClick={handleCloseP}>Cancelar</Button> |
|||
<Button onClick={handleSubmitProvider}>Confirmar</Button> |
|||
</DialogActions> |
|||
</Dialog> |
|||
</div> |
|||
</> |
|||
); |
|||
} |
|||
@ -0,0 +1,372 @@ |
|||
import Box from "@mui/material/Box"; |
|||
import TextField from "@mui/material/TextField"; |
|||
import Button from "@mui/material/Button"; |
|||
import Paper from "@mui/material/Paper"; |
|||
import Grid from "@mui/material/Grid"; |
|||
import List from "@mui/material/List"; |
|||
import { CssBaseline, Divider, Modal } from "@mui/material"; |
|||
import React, { useEffect, useState } from "react"; |
|||
import { createFormData } from "../utils/formUtils"; |
|||
import { useHistory } from "react-router-dom"; |
|||
import ModalComponents from "./ModalComponents"; |
|||
import { useDispatch, useSelector } from "react-redux"; |
|||
import ItemComponent from "./ItemComponent"; |
|||
import { getComponents } from "../services/components"; |
|||
import { getComponentsById } from "../utils/getComponentsUtils"; |
|||
import { addProduct } from "../services/products"; |
|||
|
|||
export default function FormProductModel() { |
|||
// TODO move getComponents to home screen |
|||
|
|||
// redux states |
|||
const dispatch = useDispatch(); |
|||
const components = useSelector((state) => state.components); |
|||
const componentsProduct = useSelector((state) => state.componentsProduct); |
|||
const componentsForModel = useSelector((state) => state.componentsModel); |
|||
|
|||
// local states |
|||
const [changeComponentsProduct, setChangeComponentsProduct] = useState(0); |
|||
|
|||
// service for get components |
|||
const getComponentsFromServer = async () => { |
|||
const data = await getComponents(); |
|||
|
|||
if (data !== null) { |
|||
dispatch({ |
|||
type: "GET_COMPONENTS", |
|||
payload: data, |
|||
}); |
|||
} else { |
|||
console.log("error"); |
|||
} |
|||
}; |
|||
|
|||
useEffect(() => { |
|||
getComponentsFromServer(); |
|||
|
|||
return () => { |
|||
dispatch({ |
|||
type: "CLEAN_COMPONENTS_PRODUCT", |
|||
}); |
|||
}; |
|||
}, []); |
|||
|
|||
useEffect(() => { |
|||
setForm({ |
|||
...form, |
|||
components: componentsProduct, |
|||
}); |
|||
}, [changeComponentsProduct]); |
|||
|
|||
// history |
|||
const history = useHistory(); |
|||
|
|||
// states |
|||
const [modalComponents, setModalComponents] = useState(false); |
|||
|
|||
const [form, setForm] = useState({ |
|||
name: "", |
|||
descript: "", |
|||
image: "", |
|||
quantity: "", |
|||
components: [], |
|||
}); |
|||
|
|||
const [image, setImage] = useState({ preview: "", raw: "" }); |
|||
|
|||
// handlers |
|||
const handleChange = (e) => { |
|||
setForm({ |
|||
...form, |
|||
[e.target.name]: e.target.value, |
|||
}); |
|||
}; |
|||
|
|||
const handleImage = (e) => { |
|||
if (e.target.files.length) { |
|||
setImage({ |
|||
preview: URL.createObjectURL(e.target.files[0]), |
|||
raw: e.target.files[0], |
|||
}); |
|||
} |
|||
|
|||
setForm({ |
|||
...form, |
|||
image: e.target.files[0], |
|||
}); |
|||
}; |
|||
|
|||
const handleSubmit = async (e) => { |
|||
e.preventDefault(); |
|||
|
|||
const formData = await createFormData(form); |
|||
|
|||
const res = await addProductToServer(formData); |
|||
|
|||
if (res) { |
|||
// reset states and redirect |
|||
setForm({ |
|||
name: "", |
|||
descript: "", |
|||
image: "", |
|||
quantity: "", |
|||
components: [], |
|||
}); |
|||
|
|||
dispatch({ |
|||
type: "RESET_COMPONENTS_PRODUCT", |
|||
}); |
|||
|
|||
history.push("/"); |
|||
} else { |
|||
console.log("error"); |
|||
} |
|||
}; |
|||
|
|||
const handleModal = () => { |
|||
setModalComponents(!modalComponents); |
|||
}; |
|||
|
|||
// dispatch events |
|||
|
|||
const componentsForProduct = (ids) => { |
|||
const componentsList = getComponentsById(ids, componentsForModel); |
|||
setChangeComponentsProduct(changeComponentsProduct + 1); |
|||
dispatch({ |
|||
type: "ADD_COMPONENTS_PRODUCT", |
|||
payload: componentsList, |
|||
}); |
|||
}; |
|||
|
|||
const removeComponentForProduct = (id) => { |
|||
setChangeComponentsProduct(changeComponentsProduct + 1); |
|||
dispatch({ |
|||
type: "REMOVE_COMPONENTS_PRODUCT", |
|||
payload: id, |
|||
}); |
|||
|
|||
// update form |
|||
}; |
|||
|
|||
const setQuantity = (value, id) => { |
|||
let componentQuantity = { |
|||
id: id, |
|||
quantity: value, |
|||
}; |
|||
|
|||
dispatch({ |
|||
type: "SET_QUANTITY_COMPONENT_PRODUCT", |
|||
payload: componentQuantity, |
|||
}); |
|||
}; |
|||
|
|||
const addProductToServer = async (formData) => { |
|||
const res = await addProduct(formData); |
|||
|
|||
if (res !== null) { |
|||
return true; |
|||
} else { |
|||
return false; |
|||
} |
|||
}; |
|||
|
|||
return ( |
|||
<> |
|||
<ModalComponents |
|||
handlerModal={handleModal} |
|||
stateModal={modalComponents} |
|||
components={components} |
|||
addIdComponentsForProduct={componentsForProduct} |
|||
/> |
|||
|
|||
<CssBaseline /> |
|||
{/* LEFT COLUMN */} |
|||
|
|||
<div |
|||
style={{ |
|||
padding: "5%", |
|||
marginTop: "5%", |
|||
width: "50vw", |
|||
height: "90vh", |
|||
display: "flex", |
|||
justifyContent: "space-between", |
|||
flexDirection: "column", |
|||
}} |
|||
> |
|||
<TextField |
|||
className="textField" |
|||
name="name" |
|||
label="Nombre" |
|||
variant="outlined" |
|||
onChange={handleChange} |
|||
style={{ marginBottom: "2ch" }} |
|||
/> |
|||
<TextField |
|||
className="textField" |
|||
name="descript" |
|||
label="Descripcion" |
|||
variant="outlined" |
|||
multiline |
|||
onChange={handleChange} |
|||
style={{ marginBottom: "2ch" }} |
|||
inputProps={{ |
|||
style: { |
|||
height: 80, |
|||
}, |
|||
}} |
|||
/> |
|||
|
|||
<div |
|||
style={{ |
|||
display: "flex", |
|||
flexDirection: "column", |
|||
alignItems: "center", |
|||
}} |
|||
> |
|||
<div |
|||
style={{ |
|||
borderRadius: "100px", |
|||
display: "flex", |
|||
width: "200px", |
|||
height: "200px", |
|||
overflow: "hidden", |
|||
alignItems: "center", |
|||
justifyContent: "center", |
|||
}} |
|||
> |
|||
<Button |
|||
href="#" |
|||
onClick={(e) => { |
|||
e.preventDefault(); |
|||
document.getElementById("image").click(); |
|||
}} |
|||
> |
|||
<img |
|||
src={ |
|||
image.preview |
|||
? image.preview |
|||
: "https://thealmanian.com/wp-content/uploads/2019/01/product_image_thumbnail_placeholder.png" |
|||
} |
|||
alt="preview" |
|||
style={{ width: "200px", height: "200px" }} |
|||
/> |
|||
</Button> |
|||
<input |
|||
type="file" |
|||
id="image" |
|||
name="image" |
|||
accept="image/*" |
|||
style={{ display: "none" }} |
|||
onChange={handleImage} |
|||
/> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
{/* RIGHT COLUMN */} |
|||
<Grid |
|||
item |
|||
xs={12} |
|||
sm={8} |
|||
md={6} |
|||
component={Paper} |
|||
elevation={0} |
|||
sx={{ |
|||
display: "flex", |
|||
justifyContent: "center", |
|||
verticalAlign: "center", |
|||
backgroundColor: "#11181B", |
|||
}} |
|||
> |
|||
<Box |
|||
sx={{ |
|||
width: "90%", |
|||
display: "flex", |
|||
flexDirection: "column", |
|||
alignItems: "center", |
|||
}} |
|||
> |
|||
<h3 |
|||
style={{ |
|||
width: "80%", |
|||
fontWeight: "400", |
|||
color: "#7a7979", |
|||
display: "block", |
|||
position: "relative", |
|||
top: "6%", |
|||
}} |
|||
> |
|||
Lista de componentes |
|||
</h3> |
|||
<div |
|||
style={{ |
|||
display: "block", |
|||
position: "relative", |
|||
left: "40%", |
|||
top: "5%", |
|||
//justifyContent: "end", |
|||
}} |
|||
> |
|||
<Button |
|||
style={{ |
|||
width: "40px", |
|||
height: "60px", |
|||
borderRadius: "100px", |
|||
fontSize: "2rem", |
|||
}} |
|||
variant="contained" |
|||
color="primary" |
|||
onClick={() => { |
|||
//open modal |
|||
handleModal(); |
|||
}} |
|||
> |
|||
+ |
|||
</Button> |
|||
</div> |
|||
<div |
|||
style={{ |
|||
overflow: "scroll", |
|||
minHeight: "60vh", |
|||
maxHeight: "60vh", |
|||
borderRadius: "1ch", |
|||
padding: "5ch", |
|||
width: "80%", |
|||
background: "#23282C", |
|||
}} |
|||
> |
|||
{componentsProduct && componentsProduct.length > 0 |
|||
? componentsProduct.map((item) => ( |
|||
<> |
|||
<ItemComponent |
|||
key={item.id} |
|||
id={item._id} |
|||
name={item.name} |
|||
setQuantity={setQuantity} |
|||
remove={removeComponentForProduct} |
|||
/> |
|||
<Divider |
|||
color="whitesmoke" |
|||
style={{ |
|||
marginBottom: "1em", |
|||
}} |
|||
/> |
|||
</> |
|||
)) |
|||
: null} |
|||
</div> |
|||
|
|||
<Button |
|||
type="submit" |
|||
style={{ width: "50%", margin: "5ch" }} |
|||
variant="contained" |
|||
color="primary" |
|||
onClick={handleSubmit} |
|||
> |
|||
CONFIRMAR |
|||
</Button> |
|||
</Box> |
|||
</Grid> |
|||
</> |
|||
); |
|||
} |
|||
@ -0,0 +1,531 @@ |
|||
import TextField from "@mui/material/TextField"; |
|||
import MenuItem from "@mui/material/MenuItem"; |
|||
import Button from "@mui/material/Button"; |
|||
import { DialogTitle, InputAdornment } from "@mui/material"; |
|||
import { useState, useEffect, useRef } from "react"; |
|||
import { createFormData } from "../utils/formUtils"; |
|||
import { addSupply, sendCsvFile } from "../services/supplies"; |
|||
import { useHistory } from "react-router-dom"; |
|||
import { styled } from "@mui/material/styles"; |
|||
import IconButton from "@mui/material/IconButton"; |
|||
import UploadFileIcon from "@mui/icons-material/UploadFile"; |
|||
import AddIcon from "@mui/icons-material/Add"; |
|||
import { |
|||
getProviders, |
|||
addPriceToProviderById, |
|||
addProvider, |
|||
} from "../services/providers"; |
|||
import { getCategories, addCategory } from "../services/categories"; |
|||
import { useParams } from "react-router-dom"; |
|||
|
|||
//sockets |
|||
import io from "socket.io-client"; |
|||
|
|||
//pop up |
|||
import Dialog from "@mui/material/Dialog"; |
|||
import DialogActions from "@mui/material/DialogActions"; |
|||
import DialogContent from "@mui/material/DialogContent"; |
|||
|
|||
const API = process.env.REACT_APP_API; |
|||
|
|||
const Input = styled("input")({ |
|||
display: "none", |
|||
}); |
|||
|
|||
export default function FormSupply() { |
|||
//popUp |
|||
const [openC, setOpenC] = useState(false); |
|||
const [openP, setOpenP] = useState(false); |
|||
|
|||
const handleClickOpen = () => { |
|||
setOpenC(true); |
|||
}; |
|||
|
|||
const handleClose = () => { |
|||
setOpenC(false); |
|||
}; |
|||
|
|||
const handleClickOpenP = () => { |
|||
setOpenP(true); |
|||
}; |
|||
|
|||
const handleCloseP = () => { |
|||
setOpenP(false); |
|||
}; |
|||
|
|||
//end PopUp |
|||
|
|||
// history |
|||
const history = useHistory(); |
|||
|
|||
const [csv, setCsv] = useState([]); |
|||
|
|||
// form state |
|||
const [form, setForm] = useState({ |
|||
name: "", |
|||
description: "", |
|||
category: "", |
|||
providers: "", |
|||
unity: "", |
|||
imageSupply: "", |
|||
code: "", |
|||
location: "", |
|||
}); |
|||
|
|||
const [image, setImage] = useState({ preview: "", raw: "" }); |
|||
|
|||
// handlers |
|||
|
|||
const handleChange = (e) => { |
|||
setForm({ |
|||
...form, |
|||
[e.target.name]: e.target.value, |
|||
}); |
|||
}; |
|||
|
|||
const handleImage = (e) => { |
|||
if (e.target.files.length) { |
|||
// console.log(e.target.files[0]); |
|||
setImage({ |
|||
preview: URL.createObjectURL(e.target.files[0]), |
|||
raw: e.target.files[0], |
|||
}); |
|||
} |
|||
|
|||
setForm({ |
|||
...form, |
|||
imageSupply: e.target.files[0], |
|||
}); |
|||
}; |
|||
|
|||
const handleSubmit = async (e) => { |
|||
e.preventDefault(); |
|||
|
|||
// console.log('form', form); |
|||
// console.log('csv', cvs); |
|||
// console.log('formProvider', formProvider); |
|||
|
|||
if (!csv.name) { |
|||
const formData = createFormData(form); |
|||
console.log("formData desde formSupply", formData); |
|||
addSupplyToServer(formData); |
|||
|
|||
// reset states |
|||
setForm({ |
|||
name: "", |
|||
description: "", |
|||
category: "", |
|||
providers: "", |
|||
imageSupply: "", |
|||
code: "", |
|||
location: "", |
|||
quantity: "", |
|||
amount: "", |
|||
}); |
|||
|
|||
setImage({ preview: "", raw: "" }); |
|||
} else { |
|||
const formData = new FormData(); |
|||
formData.append("file", csv); |
|||
const res = await sendCsvFile(formData); |
|||
console.log(res); |
|||
if (res !== null) { |
|||
history.push("/supplies"); |
|||
} |
|||
} |
|||
}; |
|||
|
|||
//============================================================================== |
|||
|
|||
//services |
|||
|
|||
// add supply |
|||
const addSupplyToServer = async (form) => { |
|||
console.log("form VERVER", form); |
|||
const response = await addSupply(form); |
|||
console.log("response", response); |
|||
if (response !== null) { |
|||
history.push("/supplies"); |
|||
} |
|||
}; |
|||
|
|||
//PROVIDERS |
|||
|
|||
const socketRef = useRef(); |
|||
const [providers, setProviders] = useState([]); |
|||
const [newProvider, setNewProvider] = useState({ |
|||
name: "", |
|||
}); |
|||
|
|||
const handleChangeProviders = (event) => { |
|||
setNewProvider({ |
|||
...newProvider, |
|||
[event.target.name]: event.target.value, |
|||
}); |
|||
}; |
|||
|
|||
const handleSubmitProvider = (event) => { |
|||
event.preventDefault(); |
|||
console.log(newProvider.name); |
|||
addProvider({ |
|||
name: newProvider.name, |
|||
description: "", |
|||
}); |
|||
|
|||
handleCloseP(); |
|||
}; |
|||
|
|||
//Crea el array de proveedores y queda a la escucha de nuevos posts |
|||
|
|||
useEffect(() => { |
|||
socketRef.current = io.connect(`${API}`); |
|||
|
|||
socketRef.current.on("listenProviders", async () => { |
|||
loadProviders(); |
|||
}); |
|||
|
|||
const loadProviders = async () => { |
|||
const providers = await getProviders(); |
|||
setProviders(providers); |
|||
console.log(providers); |
|||
}; |
|||
loadProviders(); |
|||
}, []); |
|||
|
|||
//CATEGORIES |
|||
|
|||
const [categories, setCategories] = useState([]); |
|||
const [newCategory, setNewCategory] = useState({ |
|||
nombre: "", |
|||
}); |
|||
|
|||
const handleChangeCategories = (event) => { |
|||
setNewCategory({ |
|||
...newCategory, |
|||
[event.target.name]: event.target.value, |
|||
}); |
|||
}; |
|||
|
|||
const handleSubmitCategory = (event) => { |
|||
event.preventDefault(); |
|||
console.log(newCategory.nombre); |
|||
addCategory({ |
|||
name: newCategory.nombre, |
|||
description: "Es una descripción", |
|||
}); |
|||
handleClose(); |
|||
}; |
|||
|
|||
//Crea el array de categorías y queda a la escucha de nuevos posts |
|||
|
|||
useEffect(() => { |
|||
socketRef.current = io.connect(`${API}`); |
|||
|
|||
socketRef.current.on("listenCategories", async () => { |
|||
loadCategories(); |
|||
}); |
|||
|
|||
const loadCategories = async () => { |
|||
const categories = await getCategories(); |
|||
setCategories(categories); |
|||
console.log(categories); |
|||
}; |
|||
loadCategories(); |
|||
}, []); |
|||
|
|||
const handleSubmitTest = async (e) => { |
|||
e.preventDefault(); |
|||
console.log("test"); |
|||
console.log(form); |
|||
}; |
|||
|
|||
return ( |
|||
<> |
|||
<div |
|||
style={{ |
|||
display: "flex", |
|||
flexDirection: "column", |
|||
justifyContent: "space-around", |
|||
width: "60vw", |
|||
background: " #23282C", |
|||
padding: "5ch", |
|||
height: "850px", |
|||
}} |
|||
> |
|||
<div |
|||
style={{ |
|||
display: "flex", |
|||
flexDirection: "row", |
|||
justifyContent: "space-between", |
|||
alignItems: "center", |
|||
height: "400px", |
|||
}} |
|||
> |
|||
<div |
|||
style={{ |
|||
width: "50%", |
|||
flexDirection: "column", |
|||
height: "100%", |
|||
display: "flex", |
|||
justifyContent: "space-between", |
|||
}} |
|||
> |
|||
<TextField |
|||
name="name" |
|||
className="textField" |
|||
label="Nombre" |
|||
variant="outlined" |
|||
onChange={handleChange} |
|||
style={{ width: "90%" }} |
|||
/> |
|||
<TextField |
|||
className="textField" |
|||
name="location" |
|||
label="Ubicación" |
|||
variant="outlined" |
|||
onChange={handleChange} |
|||
type="text" |
|||
style={{ width: "90%" }} |
|||
/> |
|||
<TextField |
|||
name="code" |
|||
className="textField" |
|||
label="Código" |
|||
variant="outlined" |
|||
onChange={handleChange} |
|||
style={{ width: "90%" }} |
|||
/> |
|||
<div |
|||
style={{ display: "flex", flexDirection: "row", width: "100%" }} |
|||
> |
|||
<TextField |
|||
className="textField" |
|||
name="category" |
|||
select |
|||
label="Categoría" |
|||
value={form.category} |
|||
onChange={handleChange} |
|||
style={{ width: "100%" }} |
|||
> |
|||
{categories.map((option) => ( |
|||
<MenuItem key={option._id} value={option._id}> |
|||
<p> {option.name} </p> |
|||
</MenuItem> |
|||
))} |
|||
</TextField> |
|||
|
|||
<Button |
|||
className="btn-hover" |
|||
variant="contained" |
|||
sx={{ background: "#3082AA !important" }} |
|||
onClick={handleClickOpen} |
|||
> |
|||
<AddIcon /> |
|||
</Button> |
|||
</div> |
|||
|
|||
<TextField |
|||
className="textField" |
|||
name="unity" |
|||
label="Unidad de medida" |
|||
type="string" |
|||
variant="outlined" |
|||
style={{ width: "90%" }} |
|||
onChange={handleChange} |
|||
/> |
|||
</div> |
|||
<div |
|||
style={{ |
|||
width: "50%", |
|||
display: "flex", |
|||
justifyContent: "center", |
|||
}} |
|||
> |
|||
<div |
|||
style={{ |
|||
display: "flex", |
|||
justifyContent: "center", |
|||
overflow: "hidden", |
|||
borderRadius: "50%", |
|||
width: "200px", |
|||
height: "200px", |
|||
}} |
|||
> |
|||
<Button |
|||
style={{ |
|||
padding: "0", |
|||
}} |
|||
href="#" |
|||
onClick={(e) => { |
|||
e.preventDefault(); |
|||
document.getElementById("imageSupply").click(); |
|||
}} |
|||
> |
|||
<img |
|||
src={ |
|||
image.preview |
|||
? image.preview |
|||
: "https://thealmanian.com/wp-content/uploads/2019/01/product_image_thumbnail_placeholder.png" |
|||
} |
|||
alt="preview" |
|||
style={{ |
|||
width: "100%", |
|||
objectFit: "fill", |
|||
}} |
|||
/> |
|||
</Button> |
|||
<input |
|||
type="file" |
|||
id="imageSupply" |
|||
name="imageSupply" |
|||
accept="image/*" |
|||
style={{ display: "none" }} |
|||
onChange={handleImage} |
|||
/> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div style={{ display: "flex", width: "90%" }}> |
|||
<TextField |
|||
className="textField" |
|||
name="providers" |
|||
style={{ width: "50%" }} |
|||
select |
|||
value={form.providers} |
|||
onChange={handleChange} |
|||
label="Proveedor" |
|||
> |
|||
{providers.map((item) => ( |
|||
<MenuItem key={item._id} value={item._id}> |
|||
{item.name} |
|||
</MenuItem> |
|||
))} |
|||
</TextField> |
|||
<Button |
|||
className="btn-hover" |
|||
variant="contained" |
|||
sx={{ background: "#3082AA !important" }} |
|||
onClick={handleClickOpenP} |
|||
> |
|||
<AddIcon /> |
|||
</Button> |
|||
</div> |
|||
|
|||
<TextField |
|||
className="textField" |
|||
name="quantity" |
|||
label="Cantidad" |
|||
variant="outlined" |
|||
onChange={handleChange} |
|||
type="number" |
|||
style={{ width: "45%" }} |
|||
/> |
|||
|
|||
<TextField |
|||
className="textField" |
|||
name="amount" |
|||
label="Precio" |
|||
variant="outlined" |
|||
onChange={handleChange} |
|||
type="number" |
|||
style={{ width: "45%" }} |
|||
/> |
|||
|
|||
<TextField |
|||
className="textField" |
|||
name="description" |
|||
label="Descripcion" |
|||
variant="outlined" |
|||
onChange={handleChange} |
|||
style={{ marginBottom: "2ch" }} |
|||
multiline |
|||
inputProps={{ |
|||
style: { |
|||
height: 80, |
|||
}, |
|||
}} |
|||
/> |
|||
</div> |
|||
<div |
|||
style={{ |
|||
display: "flex", |
|||
justifyContent: "flex-end", |
|||
marginTop: "3ch", |
|||
width: "66vw", |
|||
}} |
|||
> |
|||
<label htmlFor="icon-button-file"> |
|||
<Input |
|||
id="icon-button-file" |
|||
type="file" |
|||
name="file" |
|||
onChange={(e) => { |
|||
const file = e.target.files[0]; |
|||
setCsv(file); |
|||
}} |
|||
/> |
|||
<IconButton color="primary" aria-label="upload file" component="span"> |
|||
<UploadFileIcon /> |
|||
</IconButton> |
|||
</label> |
|||
|
|||
<Button onClick={handleSubmitTest}>test</Button> |
|||
|
|||
<Button |
|||
type="submit" |
|||
variant="contained" |
|||
color="primary" |
|||
onClick={handleSubmit} |
|||
sx={{ ml: "20px" }} |
|||
> |
|||
Agregar |
|||
</Button> |
|||
|
|||
{/* POP UP DIALOG CATEGORY */} |
|||
<Dialog open={openC} onClose={handleClose}> |
|||
<DialogTitle>Nueva Categoría</DialogTitle> |
|||
<DialogContent> |
|||
<TextField |
|||
autoFocus |
|||
name="nombre" |
|||
margin="dense" |
|||
id="category" |
|||
label="Categoría" |
|||
onChange={handleChangeCategories} |
|||
type="text" |
|||
fullWidth |
|||
variant="standard" |
|||
/> |
|||
</DialogContent> |
|||
<DialogActions> |
|||
<Button onClick={handleClose}>Cancelar</Button> |
|||
<Button onClick={handleSubmitCategory}>Confirmar</Button> |
|||
</DialogActions> |
|||
</Dialog> |
|||
|
|||
{/* POP UP DIALOG PROVIDERS */} |
|||
<Dialog open={openP} onClose={handleCloseP}> |
|||
<DialogTitle>Nuevo Proveedor</DialogTitle> |
|||
<DialogContent> |
|||
<TextField |
|||
autoFocus |
|||
name="name" |
|||
margin="dense" |
|||
id="provider" |
|||
label="Proveedor" |
|||
onChange={handleChangeProviders} |
|||
type="string" |
|||
fullWidth |
|||
variant="standard" |
|||
/> |
|||
</DialogContent> |
|||
|
|||
<DialogActions> |
|||
<Button onClick={handleCloseP}>Cancelar</Button> |
|||
<Button onClick={handleSubmitProvider}>Confirmar</Button> |
|||
</DialogActions> |
|||
</Dialog> |
|||
</div> |
|||
</> |
|||
); |
|||
} |
|||
@ -0,0 +1,15 @@ |
|||
import { Button, Grid } from "@mui/material"; |
|||
import React from "react"; |
|||
import { Link } from "react-router-dom"; |
|||
|
|||
const GridHome = ({ children }) => { |
|||
return ( |
|||
<> |
|||
<Grid container justifyContent="center"> |
|||
{children} |
|||
</Grid> |
|||
</> |
|||
); |
|||
}; |
|||
|
|||
export default GridHome; |
|||
@ -0,0 +1,53 @@ |
|||
import { |
|||
Avatar, |
|||
IconButton, |
|||
ListItem, |
|||
ListItemAvatar, |
|||
ListItemText, |
|||
TextField, |
|||
} from "@mui/material"; |
|||
import SelectAllIcon from "@mui/icons-material/SelectAll"; |
|||
import DeleteIcon from "@mui/icons-material/Delete"; |
|||
import React from "react"; |
|||
|
|||
const ItemComponent = ({ name, id, setQuantity, remove }) => { |
|||
return ( |
|||
<ListItem |
|||
secondaryAction={ |
|||
<IconButton edge="end" aria-label="delete" onClick={() => remove(id)}> |
|||
<DeleteIcon style={{color: 'grey'}}/> |
|||
</IconButton> |
|||
} |
|||
> |
|||
<ListItemAvatar> |
|||
<Avatar> |
|||
<SelectAllIcon /> |
|||
</Avatar> |
|||
</ListItemAvatar> |
|||
<ListItemText className="textField">{name}</ListItemText> |
|||
|
|||
<TextField |
|||
className="textField" |
|||
key={id} |
|||
id="quantity" |
|||
label="cantidad" |
|||
type="number" |
|||
onChange={(e) => { |
|||
setQuantity(e.target.value, id); |
|||
}} |
|||
InputLabelProps={{ |
|||
shrink: true, |
|||
}} |
|||
InputProps={{ |
|||
inputProps: { |
|||
defaultValue: 1, |
|||
min: 0, |
|||
max: 100, |
|||
}, |
|||
}} |
|||
/> |
|||
</ListItem> |
|||
); |
|||
}; |
|||
|
|||
export default ItemComponent; |
|||
@ -0,0 +1,105 @@ |
|||
//import React from "react"; |
|||
import Box from "@mui/material/Box"; |
|||
import TextField from "@mui/material/TextField"; |
|||
import MenuItem from "@mui/material/MenuItem"; |
|||
import Button from "@mui/material/Button"; |
|||
import { Modal } from "@mui/material"; |
|||
|
|||
// table |
|||
import { DataGrid, renderEditInputCell } from "@mui/x-data-grid"; |
|||
import { componentsJsonToDataGrid } from "../utils/tableUtils"; |
|||
import { useEffect, useState } from "react"; |
|||
|
|||
let rows = []; |
|||
let columns = []; |
|||
|
|||
const ModalComponents = ({ |
|||
handlerModal, |
|||
stateModal, |
|||
components, |
|||
addIdComponentsForProduct, |
|||
}) => { |
|||
const [componentsForProduct, setComponentsForProduct] = useState([]); |
|||
|
|||
useEffect(() => { |
|||
const dataGrid = componentsJsonToDataGrid(components); |
|||
rows = []; |
|||
columns = []; |
|||
rows.push(...dataGrid.rows); |
|||
columns.push(...dataGrid.columns); |
|||
}, [components]); |
|||
|
|||
return ( |
|||
<Modal |
|||
open={stateModal} |
|||
aria-labelledby="simple-modal-title" |
|||
aria-describedby="simple-modal-description" |
|||
style={{ |
|||
display: "flex", |
|||
justifyContent: "center", |
|||
alignItems: "center", |
|||
}} |
|||
> |
|||
<Box |
|||
sx={{ |
|||
display: "flex", |
|||
flexDirection: "column", |
|||
justifyContent: "center", |
|||
alignItems: "center", |
|||
width: "80%", |
|||
height: "80%", |
|||
backgroundColor: "#23282C", |
|||
}} |
|||
> |
|||
<div |
|||
style={{ |
|||
display: "flex", |
|||
flexDirection: "row", |
|||
justifyContent: "space-around", |
|||
alignItems: "center", |
|||
width: "100%", |
|||
overflow: "auto", |
|||
}} |
|||
> |
|||
<div style={{ height: "50vh", width: "60vw" }}> |
|||
<DataGrid |
|||
columnVisibilityModel={{ |
|||
id: false, |
|||
name: true, |
|||
description: true, |
|||
category: true, |
|||
}} |
|||
sx={{ |
|||
color: "whitesmoke", |
|||
}} |
|||
disableSelectionOnClick |
|||
rows={rows} |
|||
columns={columns} |
|||
pageSize={7} |
|||
rowsPerPageOptions={[7]} |
|||
checkboxSelection={true} |
|||
onSelectionModelChange={(selectionModel) => { |
|||
setComponentsForProduct(selectionModel); |
|||
}} |
|||
/> |
|||
</div> |
|||
</div> |
|||
<Button |
|||
sx={{ |
|||
marginTop: "2rem", |
|||
}} |
|||
variant="contained" |
|||
color="primary" |
|||
onClick={() => { |
|||
addIdComponentsForProduct(componentsForProduct); |
|||
handlerModal(false); |
|||
}} |
|||
> |
|||
Agregar componentes |
|||
</Button> |
|||
</Box> |
|||
</Modal> |
|||
); |
|||
}; |
|||
|
|||
export default ModalComponents; |
|||
@ -0,0 +1,118 @@ |
|||
import { useState } from "react"; |
|||
import { Link, NavLink } from "react-router-dom"; |
|||
|
|||
import AppBar from "@mui/material/AppBar"; |
|||
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 Menu from "@mui/material/Menu"; |
|||
import MenuIcon from "@mui/icons-material/Menu"; |
|||
import MenuItem from "@mui/material/MenuItem"; |
|||
|
|||
const NavBar = () => { |
|||
const [anchorElNav, setAnchorElNav] = useState(null); |
|||
|
|||
const handleOpenNavMenu = (event) => { |
|||
setAnchorElNav(event.currentTarget); |
|||
}; |
|||
|
|||
const handleCloseNavMenu = () => { |
|||
setAnchorElNav(null); |
|||
}; |
|||
|
|||
return ( |
|||
<AppBar position="static" style={{ background: "#23282C" }}> |
|||
<Toolbar style={{ minHeight: "0px" }}> |
|||
<h2 style={{ color: "#3082aa", paddingRight: "1%" }}> |
|||
<span>FAN</span> |
|||
<span style={{ color: "#27698a" }}>STOCK</span> |
|||
</h2> |
|||
<Box sx={{ flexGrow: 1, display: { xs: "flex", md: "none" } }}> |
|||
<IconButton |
|||
size="large" |
|||
aria-label="account of current user" |
|||
aria-controls="menu-appbar" |
|||
aria-haspopup="true" |
|||
onClick={handleOpenNavMenu} |
|||
style={{ color: "white" }} |
|||
> |
|||
<MenuIcon /> |
|||
</IconButton> |
|||
<Menu |
|||
id="menu-appbar" |
|||
anchorEl={anchorElNav} |
|||
anchorOrigin={{ |
|||
vertical: "bottom", |
|||
horizontal: "left", |
|||
}} |
|||
keepMounted |
|||
transformOrigin={{ |
|||
vertical: "top", |
|||
horizontal: "left", |
|||
}} |
|||
open={Boolean(anchorElNav)} |
|||
onClose={handleCloseNavMenu} |
|||
sx={{ |
|||
display: { xs: "block", md: "none" }, |
|||
}} |
|||
> |
|||
<MenuItem |
|||
onClick={handleCloseNavMenu} |
|||
style={{ background: "#23282C" }} |
|||
> |
|||
<Link to="/components"> |
|||
<Typography>Componentes</Typography> |
|||
</Link> |
|||
</MenuItem> |
|||
<MenuItem |
|||
onClick={handleCloseNavMenu} |
|||
style={{ background: "#23282C" }} |
|||
> |
|||
<Link to="/"> |
|||
<Typography>Productos</Typography> |
|||
</Link> |
|||
</MenuItem> |
|||
<MenuItem |
|||
onClick={handleCloseNavMenu} |
|||
style={{ background: "#23282C" }} |
|||
> |
|||
<Link to="/fabricdashboard"> |
|||
<Typography>Fábrica</Typography> |
|||
</Link> |
|||
</MenuItem> |
|||
</Menu> |
|||
</Box> |
|||
|
|||
<Box sx={{ flexGrow: 1, display: { xs: "none", md: "flex" } }}> |
|||
<NavLink to="/supplies" activeClassName="active"> |
|||
<Typography textAlign="center" padding={2}> |
|||
Insumos |
|||
</Typography> |
|||
</NavLink> |
|||
<NavLink to="/components" activeClassName="active"> |
|||
<Typography textAlign="center" padding={2}> |
|||
Componentes |
|||
</Typography> |
|||
</NavLink> |
|||
<NavLink exact to="/" activeClassName="active"> |
|||
<Typography textAlign="center" padding={2}> |
|||
Productos |
|||
</Typography> |
|||
</NavLink> |
|||
<NavLink to="/fabricdashboard" activeClassName="active"> |
|||
<Typography textAlign="center" padding={2}> |
|||
Fábrica |
|||
</Typography> |
|||
</NavLink> |
|||
<NavLink to="/calculator" activeClassName="active"> |
|||
<Typography textAlign="center" padding={2}> |
|||
Calculadora |
|||
</Typography> |
|||
</NavLink> |
|||
</Box> |
|||
</Toolbar> |
|||
</AppBar> |
|||
); |
|||
}; |
|||
export default NavBar; |
|||
@ -0,0 +1,473 @@ |
|||
import { useDispatch, useSelector } from "react-redux"; |
|||
import { useEffect, useState } from "react"; |
|||
import Checkbox from "@mui/material/Checkbox"; |
|||
import { useLocation } from "react-router"; |
|||
|
|||
import { ProSidebar, Menu, MenuItem, SubMenu } from "react-pro-sidebar"; |
|||
import "react-pro-sidebar/dist/css/styles.css"; |
|||
|
|||
import { Button, Stack } from "@mui/material"; |
|||
|
|||
import { |
|||
getProcessProductById, |
|||
updateQuantity, |
|||
} from "../services/processProduct"; |
|||
import { getComponentsByIds } from "../services/components"; |
|||
import { createFormData } from "../utils/formUtils"; |
|||
import { getProcessProductsThunk } from "../reducers/actionsProcessProducts"; |
|||
import SaveIcon from "@mui/icons-material/Save"; |
|||
import UndoIcon from "@mui/icons-material/Backspace"; |
|||
|
|||
export default function NewProductFabricComponents({ productId, percentage }) { |
|||
const dispatch = useDispatch(); |
|||
const processProduct = useSelector((state) => state.productSelected); |
|||
const componentstoProduct = useSelector((state) => state.componentstoProduct); |
|||
const [refresh, setRefresh] = useState(true); |
|||
const [categoryCreated, setCategoryCreated] = useState(false); |
|||
const [matrixHandlersCategories, setMatrixHandlersCategories] = useState([]); |
|||
const [categoryList, setCategoryList] = useState([]); |
|||
|
|||
const [saved, setSaved] = useState(false); |
|||
const [finishedComponents, setFinishedComponents] = useState({ |
|||
finishedQuantityValue: [], |
|||
}); |
|||
|
|||
const processRequest = useSelector((state) => state.processRequest); |
|||
const checkedStates = useSelector((state) => state.processProductsChecked); |
|||
let checkedStatesArray = []; |
|||
const processRequestThunk = useSelector( |
|||
(state) => state.processProductsThunk |
|||
); |
|||
|
|||
const saveChanges = async (e) => { |
|||
const response = await updateQuantity( |
|||
finishedComponents, |
|||
processProduct._id |
|||
); |
|||
|
|||
setSaved((saved) => true); |
|||
|
|||
await getInfo(); |
|||
createCategories(processProduct.components); |
|||
|
|||
// reset state |
|||
setFinishedComponents({ |
|||
finishedQuantityValue: [], |
|||
}); |
|||
|
|||
percentage(); |
|||
}; |
|||
|
|||
const getInfo = async () => { |
|||
await dispatch(getProcessProductsThunk(processProduct._id)); |
|||
}; |
|||
|
|||
useEffect(() => { |
|||
createCategories(processProduct.components); |
|||
}, [categoryList]); |
|||
|
|||
useEffect(() => { |
|||
const apiResponse = async () => { |
|||
await getInfo(); |
|||
createCategories(processProduct.components); |
|||
}; |
|||
apiResponse(); |
|||
}, []); |
|||
|
|||
const createCategories = (components) => { |
|||
components.forEach((component) => { |
|||
if ( |
|||
categoryList.findIndex( |
|||
(category) => category.label === component.category |
|||
) === -1 |
|||
) { |
|||
const category = { |
|||
value: component.category, |
|||
label: component.category, |
|||
}; |
|||
setCategoryList([...categoryList, category]); |
|||
} |
|||
}); |
|||
setCategoryCreated(true); |
|||
}; |
|||
|
|||
const mappedCategory = (categoriesJson) => { |
|||
return categoriesJson.map((category) => { |
|||
// verify if category already exist in the matrix state |
|||
const categoryExist = matrixHandlersCategories.find( |
|||
(matrixHandler) => matrixHandler.label === category.label |
|||
); |
|||
|
|||
if (!categoryExist) { |
|||
// create a new category |
|||
const newCategory = { |
|||
label: category.label, |
|||
state: false, |
|||
}; |
|||
setMatrixHandlersCategories([...matrixHandlersCategories, newCategory]); |
|||
} |
|||
|
|||
const handlerState = matrixHandlersCategories.find( |
|||
(matrixHandler) => matrixHandler.label === category.label |
|||
); |
|||
|
|||
return ( |
|||
<SubMenu |
|||
title={category.label} |
|||
// open={handlerState ? handlerState.state : false} |
|||
suffix={ |
|||
<div |
|||
style={{ |
|||
display: "flex", |
|||
flexDirection: "row", |
|||
}} |
|||
> |
|||
<Button |
|||
onClick={() => { |
|||
handlerState.state = !handlerState.state; |
|||
setMatrixHandlersCategories([...matrixHandlersCategories]); |
|||
}} |
|||
> |
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"> |
|||
<path |
|||
d="M7.41 7.84L12 12.42l4.59-4.58L18 9.25l-6 6-6-6z" |
|||
fill="#fff" |
|||
/> |
|||
<path d="M0-.75h24v24H0z" fill="none" /> |
|||
</svg> |
|||
</Button> |
|||
</div> |
|||
} |
|||
/* prefix={ |
|||
<Checkbox |
|||
onChange={(e) => { |
|||
e.currentTarget.checked |
|||
? console.log("checked" + category.label) |
|||
: console.log("unchecked" + category.label); |
|||
}} |
|||
/> |
|||
} */ |
|||
> |
|||
{processProduct.components |
|||
? mappedComponents(processProduct.components, category.value) |
|||
: null} |
|||
</SubMenu> |
|||
); |
|||
}); |
|||
}; |
|||
|
|||
const finishedComponentsVerifyExist = (component) => { |
|||
const componentExist = finishedComponents.finishedQuantityValue.find( |
|||
(finishedComponent) => finishedComponent._id === component._id |
|||
); |
|||
if (componentExist) { |
|||
return true; |
|||
} else { |
|||
// create a new component |
|||
const newComponent = { |
|||
_id: component._id, |
|||
quantity: 0, |
|||
}; |
|||
|
|||
// setFinishedComponents([...finishedComponents, newComponent]); |
|||
setFinishedComponents({ |
|||
...finishedComponents, |
|||
finishedQuantityValue: [ |
|||
...finishedComponents.finishedQuantityValue, |
|||
newComponent, |
|||
], |
|||
}); |
|||
} |
|||
}; |
|||
|
|||
const finishedComponentsHandler = (component, state) => { |
|||
// verify if component already exist in the finishedComponents state |
|||
|
|||
switch (state) { |
|||
case "ADD": |
|||
const componentExist = finishedComponents.finishedQuantityValue.find( |
|||
(finishedComponent) => finishedComponent._id === component._id |
|||
); |
|||
componentExist.quantity += 1; |
|||
setFinishedComponents({ |
|||
...finishedComponents, |
|||
finishedQuantityValue: [...finishedComponents.finishedQuantityValue], |
|||
}); |
|||
|
|||
break; |
|||
case "LESS": |
|||
const componentExistLess = |
|||
finishedComponents.finishedQuantityValue.find( |
|||
(finishedComponent) => finishedComponent._id === component._id |
|||
); |
|||
componentExistLess.quantity -= 1; |
|||
setFinishedComponents({ |
|||
...finishedComponents, |
|||
finishedQuantityValue: [...finishedComponents.finishedQuantityValue], |
|||
}); |
|||
|
|||
break; |
|||
default: |
|||
break; |
|||
} |
|||
}; |
|||
|
|||
const undoComponent = (component) => { |
|||
const componentExist = finishedComponents.finishedQuantityValue.find( |
|||
(finishedComponent) => finishedComponent._id === component._id |
|||
); |
|||
|
|||
let quantity = (componentExist.quantity = -1); |
|||
|
|||
let newFinishedComponents = finishedComponents.finishedQuantityValue.map( |
|||
(finishedComponent) => { |
|||
if (finishedComponent._id === component._id) { |
|||
return { |
|||
...finishedComponent, |
|||
quantity: quantity, |
|||
}; |
|||
} else { |
|||
return finishedComponent; |
|||
} |
|||
} |
|||
); |
|||
|
|||
setFinishedComponents({ |
|||
...finishedComponents, |
|||
finishedQuantityValue: newFinishedComponents, |
|||
}); |
|||
|
|||
saveChanges(); |
|||
}; |
|||
|
|||
const mappedComponents = (components, category) => { |
|||
return components.map((component, index) => { |
|||
finishedComponentsVerifyExist(component); |
|||
return component.category === category ? ( |
|||
<Stack flexDirection="row"> |
|||
<SubMenu |
|||
style={{ |
|||
width: "100%", |
|||
}} |
|||
suffix={ |
|||
<div |
|||
style={{ |
|||
display: "flex", |
|||
justifyContent: "space-between", |
|||
flexDirection: "row", |
|||
}} |
|||
> |
|||
<Button> |
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"> |
|||
<path |
|||
d="M7.41 7.84L12 12.42l4.59-4.58L18 9.25l-6 6-6-6z" |
|||
fill="#fff" |
|||
/> |
|||
<path d="M0-.75h24v24H0z" fill="none" /> |
|||
</svg> |
|||
</Button> |
|||
</div> |
|||
} |
|||
title={ |
|||
component.name + " " + "(" + component.outstandingQuantity + ")" |
|||
} |
|||
prefix={ |
|||
<Checkbox |
|||
checked={component.outstandingQuantity <= 0 ? true : false} |
|||
color="success" |
|||
sx={ |
|||
component.outstandingQuantity <= 0 |
|||
? { |
|||
color: "green", |
|||
} |
|||
: { |
|||
color: "whitesmoke", |
|||
} |
|||
} |
|||
/> |
|||
} |
|||
> |
|||
{ |
|||
// create menuItem for quantity in the processProduct.components.quantity |
|||
Array.from( |
|||
{ |
|||
length: |
|||
component.outstandingQuantity + component.finishedQuantity, |
|||
}, |
|||
(v, i) => i + 1 |
|||
).map((i) => { |
|||
let name = `${component.name}-${i}`; |
|||
let value; |
|||
|
|||
if (i <= component.outstandingQuantity) { |
|||
value = false; |
|||
} else { |
|||
value = true; |
|||
} |
|||
|
|||
checkedStatesArray.push({ |
|||
name: name, |
|||
value: value, |
|||
}); |
|||
|
|||
return ( |
|||
<div |
|||
style={{ |
|||
display: "flex", |
|||
flexDirection: "row", |
|||
}} |
|||
> |
|||
<MenuItem |
|||
className={ |
|||
i <= component.finishedQuantity ? "myDIV complete" |
|||
: "myDIV" |
|||
} |
|||
key={component.id} |
|||
suffix={ |
|||
<div |
|||
style={{ |
|||
marginLeft: "50px", |
|||
}} |
|||
> |
|||
{component.finishedQuantity >= i ? ( |
|||
<Button |
|||
onClick={(e) => { |
|||
let stateCheck = |
|||
e.currentTarget.parentNode.parentNode |
|||
.parentNode.children[0].children[0] |
|||
.children[0].checked; |
|||
|
|||
if (stateCheck) { |
|||
undoComponent(component); |
|||
} |
|||
|
|||
let componentState = checkedStatesArray.find( |
|||
(state) => state.name === name |
|||
); |
|||
}} |
|||
> |
|||
<UndoIcon |
|||
sx={{ |
|||
fontSize: "15px", |
|||
color: "whitesmoke", |
|||
}} |
|||
/> |
|||
</Button> |
|||
) : null} |
|||
</div> |
|||
} |
|||
prefix={ |
|||
<Checkbox |
|||
sx={{ |
|||
color: |
|||
i <= component.finishedQuantity |
|||
? "#7a7979 !important" |
|||
: "#3082aa !important", |
|||
}} |
|||
key={`${component.name}-${i}`} |
|||
checked={ |
|||
component.finishedQuantity >= i ? true : undefined |
|||
} |
|||
onClick={(e) => { |
|||
setSaved((saved) => false); |
|||
/* e.currentTarget.childNodes[0].checked |
|||
? quantityHanlder++ |
|||
: quantityHanlder--; |
|||
|
|||
console.log(quantityHanlder); */ |
|||
}} |
|||
onChange={(e) => { |
|||
e.currentTarget.checked |
|||
? finishedComponentsHandler(component, "ADD") |
|||
: finishedComponentsHandler(component, "LESS"); |
|||
}} |
|||
/> |
|||
} |
|||
> |
|||
{name} |
|||
</MenuItem> |
|||
<MenuItem className="hide"> |
|||
<div |
|||
style={{ |
|||
marginTop: "10px", |
|||
}} |
|||
> |
|||
<p> |
|||
{processProduct.model |
|||
? `Stock: ${ |
|||
componentstoProduct |
|||
? componentstoProduct[index].quantity |
|||
: 0 |
|||
} | Necesarios: ${ |
|||
processProduct.components[index] |
|||
.outstandingQuantity |
|||
} | Ubicacion: ${ |
|||
processProduct.components[index].location |
|||
}` |
|||
: null} |
|||
</p> |
|||
</div> |
|||
</MenuItem> |
|||
</div> |
|||
); |
|||
}) |
|||
} |
|||
</SubMenu> |
|||
</Stack> |
|||
) : null; |
|||
}); |
|||
}; |
|||
|
|||
return ( |
|||
<> |
|||
{/* create sidebar mapped info */} |
|||
<div |
|||
style={{ |
|||
display: "flex", |
|||
flexDirection: "row", |
|||
}} |
|||
> |
|||
<div |
|||
style={{ |
|||
height: "70vh", |
|||
overflow: "auto", |
|||
// style scrollbar |
|||
|
|||
backgroundColor: "#fff", |
|||
}} |
|||
> |
|||
<ProSidebar width="50vw" className="styleProSidebar"> |
|||
<Menu innerSubMenuArrows={false} iconShape="square"> |
|||
<SubMenu |
|||
className="styleProSidebarSM" |
|||
title="Components" |
|||
open={true} |
|||
> |
|||
{!processRequestThunk.loading ? ( |
|||
mappedCategory(categoryList) |
|||
) : ( |
|||
<div> |
|||
<p>Cargando...</p> |
|||
</div> |
|||
)} |
|||
</SubMenu> |
|||
</Menu> |
|||
</ProSidebar> |
|||
</div> |
|||
<Button |
|||
style={{ |
|||
height: "3em", |
|||
marginLeft: "1em", |
|||
background: "#3082aa", |
|||
}} |
|||
variant="contained" |
|||
onClick={() => { |
|||
saveChanges(); |
|||
}} |
|||
> |
|||
<SaveIcon /> |
|||
</Button> |
|||
</div> |
|||
</> |
|||
); |
|||
} |
|||
@ -0,0 +1,69 @@ |
|||
import * as React from "react"; |
|||
import Card from "@mui/material/Card"; |
|||
import CardContent from "@mui/material/CardContent"; |
|||
import CardMedia from "@mui/material/CardMedia"; |
|||
import Typography from "@mui/material/Typography"; |
|||
import { Box } from "@mui/system"; |
|||
import { CardActions } from "@mui/material"; |
|||
|
|||
export default function ProductCard({ name, img, description }) { |
|||
return ( |
|||
<Card |
|||
sx={{ |
|||
display: "flex", |
|||
flexDirection: "column", |
|||
justifyContent: "space-between", |
|||
maxWidth: 200, |
|||
minWidth: 200, |
|||
maxHeight: 300, |
|||
minHeight: 300, |
|||
mb: 2, |
|||
background: "#23282C", |
|||
display: "flex", |
|||
flexDirection: "column", |
|||
borderRadius: "15px", |
|||
paddingTop: "10px", |
|||
boxShadow: 6, |
|||
}} |
|||
> |
|||
{/* <CardMedia |
|||
component="img" |
|||
alt="faniot-img" |
|||
image={img} |
|||
sx={{ |
|||
borderRadius: "50%", |
|||
width: "140px", |
|||
alignSelf: "center", |
|||
mt: "10px", |
|||
mb: "20px", |
|||
}} |
|||
/> */} |
|||
|
|||
<img |
|||
src={img} |
|||
alt="faniot-img" |
|||
style={{ |
|||
alignSelf: "center", |
|||
width: "150px", |
|||
height: "150px", |
|||
borderRadius: "50%", |
|||
}} |
|||
/> |
|||
|
|||
<CardContent |
|||
sx={{ |
|||
background: "#3082AA", |
|||
overFlow: "hidden", |
|||
}} |
|||
> |
|||
<Typography variant="h5" component="div" sx={{ color: "whitesmoke" }}> |
|||
{name} |
|||
</Typography> |
|||
|
|||
<Typography color="text.secondary" sx={{ lineHeight: "30px" }}> |
|||
{description} |
|||
</Typography> |
|||
</CardContent> |
|||
</Card> |
|||
); |
|||
} |
|||
@ -0,0 +1,74 @@ |
|||
import * as React from "react"; |
|||
import Card from "@mui/material/Card"; |
|||
import CardContent from "@mui/material/CardContent"; |
|||
import CardMedia from "@mui/material/CardMedia"; |
|||
import Typography from "@mui/material/Typography"; |
|||
import { CardActions } from "@mui/material"; |
|||
import { Link } from "react-router-dom"; |
|||
|
|||
export default function ProductCardFabric({ |
|||
name, |
|||
img, |
|||
description, |
|||
stateProduction, |
|||
}) { |
|||
return ( |
|||
<Card |
|||
sx={{ |
|||
maxWidth: 200, |
|||
minWidth: 200, |
|||
maxHeight: 300, |
|||
minHeight: 300, |
|||
background: "#23282C", |
|||
boxShadow: 6, |
|||
display: "flex", |
|||
flexDirection: "column", |
|||
paddingTop: "10px", |
|||
borderRadius: "15px", |
|||
}} |
|||
> |
|||
<CardMedia |
|||
component="img" |
|||
alt="faniot-img" |
|||
height="140" |
|||
image={img} |
|||
sx={{ |
|||
borderRadius: "50%", |
|||
width: "140px", |
|||
alignSelf: "center", |
|||
mt: "10px", |
|||
mb: "20px", |
|||
}} |
|||
/> |
|||
<CardContent sx={{ background: "#3082AA" }}> |
|||
<Typography |
|||
gutterBottom |
|||
variant="h5" |
|||
component="div" |
|||
sx={{ color: "whitesmoke" }} |
|||
> |
|||
{name} |
|||
</Typography> |
|||
<Typography variant="body2" color="text.secondary"> |
|||
{description} |
|||
</Typography> |
|||
</CardContent> |
|||
<CardActions |
|||
sx={{ |
|||
display: "flex", |
|||
justifyContent: "center", |
|||
}} |
|||
> |
|||
<Typography variant="body2" sx={{paddingTop: '3px'}} > |
|||
{stateProduction === "PENDING" |
|||
? "EN PROCESO" |
|||
: stateProduction === "FINISHED" |
|||
? "TERMINADO" |
|||
: stateProduction === "ARCHIVED" |
|||
? "ARCHIVADO" |
|||
: stateProduction} |
|||
</Typography> |
|||
</CardActions> |
|||
</Card> |
|||
); |
|||
} |
|||
@ -0,0 +1,209 @@ |
|||
import { useState } from "react"; |
|||
import Box from "@mui/material/Box"; |
|||
import TextField from "@mui/material/TextField"; |
|||
import Grid from "@mui/material/Grid"; |
|||
import Button from "@mui/material/Button"; |
|||
import DeleteIcon from "@mui/icons-material/Delete"; |
|||
import Typography from "@mui/material/Typography"; |
|||
import { showImage } from "../utils/imageUtils"; |
|||
import { addProcessProduct } from "../services/processProduct"; |
|||
import { useHistory } from "react-router-dom"; |
|||
import { createFormData } from "../utils/formUtils"; |
|||
import { deleteProductModel } from "../services/products"; |
|||
import { CssBaseline } from "@mui/material"; |
|||
import ChevronRightIcon from "@mui/icons-material/ChevronRight"; |
|||
|
|||
import Dialog from "@mui/material/Dialog"; |
|||
import DialogActions from "@mui/material/DialogActions"; |
|||
import DialogContent from "@mui/material/DialogContent"; |
|||
import useMediaQuery from "@mui/material/useMediaQuery"; |
|||
import { useTheme } from "@mui/material/styles"; |
|||
import 'animate.css'; |
|||
|
|||
export default function ProductModelInfo({ product }) { |
|||
//popUp |
|||
const [open, setOpen] = useState(false); |
|||
const theme = useTheme(); |
|||
const fullScreen = useMediaQuery(theme.breakpoints.down("md")); |
|||
|
|||
const handleClickOpen = () => { |
|||
setOpen(true); |
|||
}; |
|||
|
|||
const handleClose = () => { |
|||
setOpen(false); |
|||
}; |
|||
//end PopUp |
|||
|
|||
const [form, setForm] = useState({ |
|||
modelId: product._id, |
|||
name: "", |
|||
users: "", |
|||
}); |
|||
|
|||
// handlers |
|||
const handleChange = (e) => { |
|||
setForm({ |
|||
...form, |
|||
[e.target.name]: e.target.value, |
|||
}); |
|||
}; |
|||
|
|||
const { name, description, imageType, imageData } = product; |
|||
|
|||
const processImage = (imageData, contentType) => { |
|||
const img = showImage(imageData, contentType); |
|||
|
|||
return img; |
|||
}; |
|||
|
|||
// history |
|||
const history = useHistory(); |
|||
|
|||
// handle addProcessProduct |
|||
const handleSubmit = async (e) => { |
|||
e.preventDefault(); |
|||
const formData = await createFormData(form); |
|||
const res = await addProcessProduct(formData); |
|||
|
|||
history.push("/fabricdashboard"); |
|||
}; |
|||
|
|||
// handle deleteProduct |
|||
const handleSubmitDelete = (e) => { |
|||
e.preventDefault(); |
|||
|
|||
const response = deleteProductModel(product._id); |
|||
if (response !== null) { |
|||
console.log("wep"); |
|||
history.push("/"); |
|||
} |
|||
}; |
|||
|
|||
return ( |
|||
<> |
|||
<Grid container component="main" sx={{ height: "100vh" }}> |
|||
<Grid |
|||
|
|||
id="left-col" |
|||
item |
|||
xs={false} |
|||
sm={4} |
|||
md={6} |
|||
sx={{ |
|||
backgroundColor: "#11181B", |
|||
display: "flex", |
|||
justifyContent: "center", |
|||
alignItems: "center", |
|||
}} |
|||
> |
|||
<div id="imageBox" style={{ maxWidth: "50%" }} className='animate__animated animate__fadeIn' > |
|||
<img |
|||
|
|||
src={`${processImage(imageData, imageType)}`} |
|||
alt="preview" |
|||
style={{ |
|||
maxWidth: "100%", |
|||
borderRadius: "50%", |
|||
overflow: "hidden", |
|||
}} |
|||
/> |
|||
</div> |
|||
</Grid> |
|||
<Grid |
|||
id="right-col" |
|||
item |
|||
xs={12} |
|||
sm={8} |
|||
md={6} |
|||
sx={{ |
|||
backgroundColor: "#11181B", |
|||
display: "flex", |
|||
alignItems: "center", |
|||
}} |
|||
> |
|||
<Box |
|||
|
|||
sx={{ |
|||
width: "100%", |
|||
my: 10, |
|||
mx: 4, |
|||
display: "flex", |
|||
flexDirection: "column", |
|||
alignItems: "center", |
|||
}} |
|||
> |
|||
<Typography component="h1" variant="h3" color={"whitesmoke"}> |
|||
{name} |
|||
</Typography> |
|||
<Box sx={{ mt: 10, mb: 10, color: "whitesmoke" }}> |
|||
{description} |
|||
</Box> |
|||
<TextField |
|||
className="textField" |
|||
name="name" |
|||
label="Id" |
|||
helperText="Ingrese un identificador del producto a fabricar" |
|||
variant="outlined" |
|||
onChange={handleChange} |
|||
style={{ marginBottom: "2ch" }} |
|||
/> |
|||
<div |
|||
style={{ |
|||
display: "flex", |
|||
flexDirection: "row", |
|||
width: "35%", |
|||
marginTop: "5%", |
|||
}} |
|||
> |
|||
<Button |
|||
color="error" |
|||
variant="contained" |
|||
sx={{ mt: 3, mb: 2, mr: 5 }} |
|||
onClick={handleClickOpen} |
|||
> |
|||
<DeleteIcon /> |
|||
</Button> |
|||
<Button |
|||
className="btn-hover" |
|||
variant="contained" |
|||
sx={{ |
|||
mt: 3, |
|||
mb: 2, |
|||
backgroundColor: "#3082aa", |
|||
width: "200px", |
|||
}} |
|||
onClick={handleSubmit} |
|||
endIcon={<ChevronRightIcon />} |
|||
> |
|||
FABRICAR |
|||
</Button> |
|||
|
|||
{/* POP UP DIALOG */} |
|||
<Dialog |
|||
fullScreen={fullScreen} |
|||
open={open} |
|||
onClose={handleClose} |
|||
aria-labelledby="responsive-dialog-title" |
|||
> |
|||
<DialogContent> |
|||
<h3 style={{ fontWeight: "400", color: "lightgrey " }}> |
|||
¿Está seguro/a que desea eliminar el elemento? |
|||
</h3> |
|||
</DialogContent> |
|||
<DialogActions> |
|||
<Button className="textGrey" autoFocus onClick={handleClose}> |
|||
NO |
|||
</Button> |
|||
<Button className="textGrey" onClick={handleSubmitDelete} autoFocus> |
|||
SI |
|||
</Button> |
|||
</DialogActions> |
|||
</Dialog> |
|||
</div> |
|||
</Box> |
|||
</Grid> |
|||
</Grid> |
|||
</> |
|||
); |
|||
} |
|||
@ -0,0 +1,653 @@ |
|||
import { useState, useEffect, useRef } from "react"; |
|||
import Button from "@mui/material/Button"; |
|||
import { showImage } from "../utils/imageUtils"; |
|||
import EdiText from "react-editext"; |
|||
import DeleteIcon from "@mui/icons-material/Delete"; |
|||
import { useSelector } from "react-redux"; |
|||
import styled from "styled-components"; |
|||
import MenuItem from "@mui/material/MenuItem"; |
|||
import TextField from "@mui/material/TextField"; |
|||
import { deleteSupply } from "../services/supplies"; |
|||
import { useHistory } from "react-router-dom"; |
|||
import { createFormData } from "../utils/formUtils"; |
|||
import { DialogTitle } from "@mui/material"; |
|||
|
|||
import Dialog from "@mui/material/Dialog"; |
|||
import DialogActions from "@mui/material/DialogActions"; |
|||
import DialogContent from "@mui/material/DialogContent"; |
|||
import useMediaQuery from "@mui/material/useMediaQuery"; |
|||
import { useTheme } from "@mui/material/styles"; |
|||
import { editSupplyById } from "../services/supplies"; |
|||
import { getProviders, addProvider } from "../services/providers"; |
|||
import { getCategories, addCategory } from "../services/categories"; |
|||
import AddIcon from "@mui/icons-material/Add"; |
|||
//sockets |
|||
import io from "socket.io-client"; |
|||
|
|||
const H1Style = styled(EdiText)` |
|||
button { |
|||
border: none; |
|||
background: rgba(0, 0, 0, 0); |
|||
border-radius: 50%; |
|||
width: 20px; |
|||
} |
|||
button:hover { |
|||
background: #11181b; |
|||
} |
|||
button[editext="edit-button"] { |
|||
transform: scaleX(-1); |
|||
font-size: x-large; |
|||
color: grey; |
|||
width: 50px; |
|||
} |
|||
button[editext="save-button"] { |
|||
} |
|||
button[editext="cancel-button"] { |
|||
} |
|||
input, |
|||
textarea { |
|||
font-family: "Roboto"; |
|||
font-size: x-large; |
|||
border: none; |
|||
} |
|||
div[editext="view-container"], |
|||
div[editext="edit-container"] { |
|||
font-family: "Roboto"; |
|||
font-size: xx-large; |
|||
color: whitesmoke; |
|||
} |
|||
`; |
|||
|
|||
const H2Style = styled(EdiText)` |
|||
button { |
|||
border: none; |
|||
background: rgba(0, 0, 0, 0); |
|||
border-radius: 50%; |
|||
width: 20px; |
|||
} |
|||
button:hover { |
|||
background: #11181b; |
|||
} |
|||
button[editext="edit-button"] { |
|||
transform: scaleX(-1); |
|||
font-size: x-large; |
|||
color: grey; |
|||
width: 50px; |
|||
} |
|||
button[editext="save-button"] { |
|||
} |
|||
button[editext="cancel-button"] { |
|||
} |
|||
input, |
|||
textarea { |
|||
font-family: "Roboto"; |
|||
font-size: large; |
|||
color: grey; |
|||
} |
|||
div[editext="view-container"], |
|||
div[editext="edit-container"] { |
|||
font-family: "Roboto"; |
|||
font-size: large; |
|||
color: whitesmoke; |
|||
border-radius: 15px; |
|||
padding-left: 8px; |
|||
border: 0.1px solid rgba(200, 200, 200, 0.1); |
|||
margin-top: 10px; |
|||
align-self: center; |
|||
width: 100%; |
|||
} |
|||
`; |
|||
|
|||
const API = process.env.REACT_APP_API; |
|||
|
|||
export default function SupplyEdit() { |
|||
const socketRef = useRef(); |
|||
const [categories, setCategories] = useState([{ name: "Loading..." }]); |
|||
const [providers, setProviders] = useState([]); |
|||
const [newCategory, setNewCategory] = useState({ nombre: "" }); |
|||
const [newProvider, setNewProvider] = useState({ name: "" }); |
|||
|
|||
// PROVIDERS |
|||
|
|||
const handleChangeProviders = (event) => { |
|||
setNewProvider({ |
|||
...newProvider, |
|||
[event.target.name]: event.target.value, |
|||
}); |
|||
}; |
|||
|
|||
const handleSubmitProvider = (event) => { |
|||
event.preventDefault(); |
|||
console.log(newProvider.name); |
|||
addProvider({ |
|||
name: newProvider.name, |
|||
description: "", |
|||
}); |
|||
|
|||
handleClose(); |
|||
}; |
|||
|
|||
//Crea el array de proveedores y queda a la escucha de nuevos posts |
|||
|
|||
useEffect(() => { |
|||
socketRef.current = io.connect(`${API}`); |
|||
|
|||
socketRef.current.on("listenProviders", async () => { |
|||
loadProviders(); |
|||
}); |
|||
|
|||
const loadProviders = async () => { |
|||
const providers = await getProviders(); |
|||
setProviders(providers); |
|||
console.log(providers); |
|||
}; |
|||
loadProviders(); |
|||
}, []); |
|||
|
|||
//Crea el array de categorías y queda a la escucha de nuevos posts |
|||
useEffect(() => { |
|||
socketRef.current = io.connect(`${API}`); |
|||
socketRef.current.on("listenCategories", async () => { |
|||
loadCategories(); |
|||
}); |
|||
|
|||
const loadCategories = async () => { |
|||
const categories = await getCategories(); |
|||
setCategories(categories); |
|||
console.log(categories); |
|||
}; |
|||
loadCategories(); |
|||
}, []); |
|||
|
|||
console.log(" categories ", categories); |
|||
console.log(" providers ", providers); |
|||
|
|||
//popUp |
|||
const [open, setOpen] = useState(false); |
|||
const [openC, setOpenC] = useState(false); |
|||
const [openP, setOpenP] = useState(false); |
|||
|
|||
const theme = useTheme(); |
|||
const fullScreen = useMediaQuery(theme.breakpoints.down("md")); |
|||
|
|||
const handleClickOpen = () => { |
|||
setOpen(true); |
|||
}; |
|||
|
|||
const handleClose = () => { |
|||
setOpen(false); |
|||
setOpenC(false); |
|||
setOpenP(false); |
|||
}; |
|||
|
|||
const handleAddCategory = () => { |
|||
setOpenC(true); |
|||
}; |
|||
|
|||
const handleAddProvider = () => { |
|||
setOpenP(true); |
|||
}; |
|||
//end PopUp |
|||
|
|||
const handleChangeCategories = (event) => { |
|||
setNewCategory({ |
|||
...newCategory, |
|||
[event.target.name]: event.target.value, |
|||
}); |
|||
}; |
|||
|
|||
const handleSubmitCategory = (event) => { |
|||
event.preventDefault(); |
|||
console.log(newCategory.nombre); |
|||
addCategory({ |
|||
name: newCategory.nombre, |
|||
description: "Es una descripción", |
|||
}); |
|||
handleClose(); |
|||
}; |
|||
|
|||
// history |
|||
const history = useHistory(); |
|||
const componentSelected = useSelector((state) => state.componentSelected); |
|||
console.log("componentSelected"); |
|||
console.log(componentSelected); |
|||
|
|||
const [image, setImage] = useState({ |
|||
preview: componentSelected.imageSupply, |
|||
raw: "", |
|||
}); |
|||
console.log("image"); |
|||
console.log(image); |
|||
// form state |
|||
const [form, setForm] = useState({ |
|||
name: componentSelected.name, |
|||
description: componentSelected.description, |
|||
code: componentSelected.code, |
|||
note: componentSelected.note, |
|||
unity: componentSelected.unity, |
|||
quantity: componentSelected.quantity, |
|||
location: componentSelected.location, |
|||
imageSupply: componentSelected.imageSupply, |
|||
// category: componentSelected.category, |
|||
// price: componentSelected.price, |
|||
}); |
|||
|
|||
//handlers |
|||
|
|||
//delete service |
|||
const handleSubmitDelete = (e) => { |
|||
e.preventDefault(); |
|||
console.log("componentSelected._id"); |
|||
console.log(componentSelected._id); |
|||
const response = deleteSupply(componentSelected._id); |
|||
if (response) { |
|||
history.push("/supplies"); |
|||
} |
|||
}; |
|||
|
|||
// handlers for form |
|||
const handleForm = (value, inputProp) => { |
|||
setForm({ |
|||
...form, |
|||
[inputProp]: value, |
|||
}); |
|||
}; |
|||
const handleFormCat = (e) => { |
|||
setForm({ |
|||
...form, |
|||
[e.target.name]: e.target.value, |
|||
}); |
|||
}; |
|||
|
|||
// image |
|||
const handleImage = (e) => { |
|||
console.log("e.target.files[0]"); |
|||
console.log(e.target.files[0]); |
|||
if (e.target.files.length) { |
|||
setImage({ |
|||
preview: URL.createObjectURL(e.target.files[0]), |
|||
raw: e.target.files[0], |
|||
}); |
|||
} |
|||
console.log("image 2"); |
|||
console.log(e.target.files[0]); |
|||
setForm({ |
|||
...form, |
|||
imageSupply: e.target.files[0], |
|||
}); |
|||
}; |
|||
|
|||
// const handleTest = () => { |
|||
// console.log("test"); |
|||
// console.log(form); |
|||
// }; |
|||
|
|||
//edit submit hanlder |
|||
const handleEditSubmit = (e) => { |
|||
e.preventDefault(); |
|||
|
|||
const formData = createFormData(form); |
|||
console.log("formData desde front" + formData); |
|||
|
|||
editSupplyToServer(componentSelected._id, formData); |
|||
}; |
|||
|
|||
//services |
|||
const editSupplyToServer = async (id, formData) => { |
|||
const response = await editSupplyById(componentSelected._id, formData); |
|||
if (response !== null) { |
|||
history.push("/supplies"); |
|||
} |
|||
}; |
|||
// process image |
|||
const processImage = (imageData, contentType) => { |
|||
const img = showImage(imageData, contentType); |
|||
return img; |
|||
}; |
|||
let productImage = processImage( |
|||
componentSelected.imageData, |
|||
componentSelected.imageType |
|||
); |
|||
|
|||
useEffect(() => { |
|||
const loadProviders = async () => { |
|||
const providers = await getProviders(); |
|||
setProviders(providers); |
|||
}; |
|||
|
|||
const loadCategories = async () => { |
|||
const categories = await getCategories(); |
|||
setCategories(categories); |
|||
}; |
|||
|
|||
loadProviders(); |
|||
loadCategories(); |
|||
}, []); |
|||
|
|||
return ( |
|||
<div |
|||
id="container-screen" |
|||
style={{ |
|||
display: "flex", |
|||
justifyContent: "center", |
|||
alignItems: "center", |
|||
height: "100%", |
|||
flexDirection: "column", |
|||
}} |
|||
> |
|||
<div |
|||
id="card" |
|||
style={{ |
|||
width: "80%", |
|||
height: "80%", |
|||
marginTop: "5%", |
|||
background: "#23282c", |
|||
borderRadius: "10px", |
|||
display: "flex", |
|||
flexDirection: "row", |
|||
}} |
|||
> |
|||
<div |
|||
id="left-column" |
|||
style={{ |
|||
display: "flex", |
|||
justifyContent: "center", |
|||
width: "30%", |
|||
alignItems: "center", |
|||
// background: "yellow", |
|||
}} |
|||
> |
|||
<div id="imageBox" style={{ maxWidth: "50%" }}> |
|||
<Button |
|||
href="#" |
|||
onClick={(e) => { |
|||
e.preventDefault(); |
|||
document.getElementById("image").click(); |
|||
}} |
|||
> |
|||
<img |
|||
// src={image.preview ? image.preview : productImage} // TODO |
|||
src={image.preview ? image.preview : productImage} |
|||
alt="preview" |
|||
style={{ |
|||
maxWidth: "100%", |
|||
borderRadius: "50%", |
|||
overflow: "hidden", |
|||
}} |
|||
/> |
|||
</Button> |
|||
<input |
|||
type="file" |
|||
id="image" |
|||
name="image" |
|||
accept="image/*" |
|||
style={{ display: "none" }} |
|||
onChange={handleImage} |
|||
/> |
|||
</div> |
|||
</div> |
|||
|
|||
<div |
|||
id="right-col" |
|||
style={{ |
|||
width: "70%", |
|||
display: "flex", |
|||
justifyContent: "center", |
|||
flexDirection: "column", |
|||
// background: 'yellow' |
|||
}} |
|||
> |
|||
<div |
|||
style={{ |
|||
width: "90%", |
|||
display: "flex", |
|||
flexDirection: "row", |
|||
justifyContent: "space-between", |
|||
}} |
|||
> |
|||
<H1Style |
|||
inputProps="name" |
|||
type="text" |
|||
value={form.name} |
|||
onSave={handleForm} |
|||
/> |
|||
|
|||
<div |
|||
style={{ display: "flex", flexDirection: "row", width: "40%" }} |
|||
> |
|||
<TextField |
|||
className="textField" |
|||
name="provider" |
|||
select |
|||
helperText="Seleccione proveedor" |
|||
//defaultValue="provider1" |
|||
style={{ width: "80%", marginBottom: "30px" }} |
|||
onChange={handleFormCat} |
|||
> |
|||
{providers.map((option) => ( |
|||
<MenuItem key={option._id} value={option._id}> |
|||
{option.name} |
|||
</MenuItem> |
|||
))} |
|||
</TextField> |
|||
<Button |
|||
className="btn-hover" |
|||
variant="contained" |
|||
sx={{ |
|||
background: "#3082AA !important", |
|||
width: "55px", |
|||
height: "55px", |
|||
marginLeft: "10px", |
|||
marginRight: "10px", |
|||
}} |
|||
onClick={handleAddProvider} |
|||
> |
|||
<AddIcon /> |
|||
</Button> |
|||
</div> |
|||
|
|||
<div |
|||
style={{ display: "flex", flexDirection: "row", width: "40%" }} |
|||
> |
|||
{/* TextField to show Categories */} |
|||
<TextField |
|||
className="textField" |
|||
name="category" |
|||
select |
|||
helperText="Seleccione categoria" |
|||
style={{ width: "80%", marginBottom: "30px" }} |
|||
onChange={handleFormCat} |
|||
> |
|||
{categories.map((option) => ( |
|||
<MenuItem key={option._id} value={option._id}> |
|||
{option.name} |
|||
</MenuItem> |
|||
))} |
|||
</TextField> |
|||
|
|||
<Button |
|||
className="btn-hover" |
|||
variant="contained" |
|||
sx={{ |
|||
background: "#3082AA !important", |
|||
height: "55px", |
|||
marginLeft: "10px", |
|||
}} |
|||
onClick={handleAddCategory} |
|||
> |
|||
<AddIcon /> |
|||
</Button> |
|||
</div> |
|||
</div> |
|||
|
|||
<div style={{ height: "120px", width: "90%" }}> |
|||
<p className="textGrey">Código</p> |
|||
|
|||
<H2Style |
|||
inputProps="code" |
|||
type="text" |
|||
value={form.code} |
|||
onSave={handleForm} |
|||
/> |
|||
</div> |
|||
|
|||
<div style={{ height: "120px", width: "90%" }}> |
|||
<p className="textGrey">Descripción</p> |
|||
|
|||
<H2Style |
|||
inputProps="description" |
|||
type="text" |
|||
value={form.description} |
|||
onSave={handleForm} |
|||
/> |
|||
</div> |
|||
|
|||
<div |
|||
style={{ |
|||
width: "90%", |
|||
display: "flex", |
|||
flexDirection: "row", |
|||
justifyContent: "space-between", |
|||
}} |
|||
> |
|||
<div style={{ display: "flex", flexDirection: "column" }}> |
|||
<p className="textGrey">Ubicacion</p> |
|||
|
|||
<H2Style |
|||
inputProps="location" |
|||
type="text" |
|||
value={form.location} |
|||
onSave={handleForm} |
|||
/> |
|||
</div> |
|||
|
|||
<div style={{ display: "flex", flexDirection: "column" }}> |
|||
<p className="textGrey">Cantidad</p> |
|||
|
|||
<H2Style |
|||
inputProps="quantity" |
|||
type="text" |
|||
value={form.quantity} |
|||
onSave={handleForm} |
|||
/> |
|||
</div> |
|||
|
|||
<div style={{ display: "flex", flexDirection: "column" }}> |
|||
<p className="textGrey">Unidad de medida</p> |
|||
|
|||
<H2Style |
|||
inputProps="unity" |
|||
type="text" |
|||
value={form.unity} |
|||
onSave={handleForm} |
|||
/> |
|||
</div> |
|||
|
|||
<div style={{ display: "flex", flexDirection: "column" }}> |
|||
<p className="textGrey">Precio</p> |
|||
|
|||
<H2Style |
|||
inputProps="price" |
|||
type="text" |
|||
value={form.price} |
|||
onSave={handleForm} |
|||
/> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
{/* footer */} |
|||
<div |
|||
style={{ |
|||
width: "80%", |
|||
display: "flex", |
|||
justifyContent: "space-between", |
|||
marginTop: "1%", |
|||
}} |
|||
> |
|||
{/* <button onClick={handleTest}>TEST</button> */} |
|||
<div> |
|||
<Button variant="contained" color="error" onClick={handleClickOpen}> |
|||
<DeleteIcon /> |
|||
</Button> |
|||
</div> |
|||
|
|||
<Button |
|||
className="btn-hover" |
|||
variant="contained" |
|||
sx={{ background: "#3082AA !important" }} |
|||
onClick={handleEditSubmit} |
|||
> |
|||
CONFIRMAR |
|||
</Button> |
|||
|
|||
{/* POP UP DIALOG CATEGORY */} |
|||
<Dialog open={openC} onClose={handleClose}> |
|||
<DialogTitle>Nueva Categoría</DialogTitle> |
|||
<DialogContent> |
|||
<TextField |
|||
autoFocus |
|||
name="nombre" |
|||
margin="dense" |
|||
id="category" |
|||
label="Categoría" |
|||
onChange={handleChangeCategories} |
|||
type="text" |
|||
fullWidth |
|||
variant="standard" |
|||
/> |
|||
</DialogContent> |
|||
<DialogActions> |
|||
<Button onClick={handleClose}>Cancelar</Button> |
|||
<Button onClick={handleSubmitCategory}>Confirmar</Button> |
|||
</DialogActions> |
|||
</Dialog> |
|||
|
|||
{/* POP UP DIALOG PROVIDERS */} |
|||
<Dialog open={openP} onClose={handleClose}> |
|||
<DialogTitle>Nuevo Proveedor</DialogTitle> |
|||
<DialogContent> |
|||
<TextField |
|||
autoFocus |
|||
name="name" |
|||
margin="dense" |
|||
id="provider" |
|||
label="Proveedor" |
|||
onChange={handleChangeProviders} |
|||
type="string" |
|||
fullWidth |
|||
variant="standard" |
|||
/> |
|||
</DialogContent> |
|||
|
|||
<DialogActions> |
|||
<Button onClick={handleClose}>Cancelar</Button> |
|||
<Button onClick={handleSubmitProvider}>Confirmar</Button> |
|||
</DialogActions> |
|||
</Dialog> |
|||
|
|||
{/* POP UP DIALOG */} |
|||
<Dialog |
|||
fullScreen={fullScreen} |
|||
open={open} |
|||
onClose={handleClose} |
|||
aria-labelledby="responsive-dialog-title" |
|||
> |
|||
<DialogContent> |
|||
<h3 style={{ fontWeight: "400", color: "lightgrey " }}> |
|||
¿Está seguro/a que desea eliminar el elemento? |
|||
</h3> |
|||
</DialogContent> |
|||
<DialogActions> |
|||
<Button className="textGrey" autoFocus onClick={handleClose}> |
|||
NO |
|||
</Button> |
|||
<Button className="textGrey" onClick={handleSubmitDelete} autoFocus> |
|||
SI |
|||
</Button> |
|||
</DialogActions> |
|||
</Dialog> |
|||
</div> |
|||
</div> |
|||
); |
|||
} |
|||
@ -0,0 +1,20 @@ |
|||
import { useLottie } from "lottie-react"; |
|||
import emptyBox from "../assets/emptyBox.json"; |
|||
|
|||
const EmptyBox = () => { |
|||
const options = { |
|||
animationData: emptyBox, |
|||
loop: true, |
|||
autoplay: true, |
|||
}; |
|||
|
|||
const style = { |
|||
height: 150, |
|||
}; |
|||
|
|||
const { View } = useLottie(options, style); |
|||
|
|||
return <>{View}</>; |
|||
}; |
|||
|
|||
export default EmptyBox; |
|||
@ -0,0 +1,30 @@ |
|||
import { useEffect, useState } from "react"; |
|||
|
|||
const useFetch = (request) => { |
|||
const [data, setData] = useState(null); |
|||
const [isFetching, setIsFetching] = useState(false); |
|||
const [error, setError] = useState(null); |
|||
|
|||
useEffect(() => { |
|||
const doFetch = async () => { |
|||
const fetchData = async () => { |
|||
try { |
|||
setIsFetching(true); |
|||
const data = await request; |
|||
setData(data); |
|||
} catch (e) { |
|||
setError(e); |
|||
} finally { |
|||
setIsFetching(false); |
|||
} |
|||
}; |
|||
fetchData(); |
|||
}; |
|||
|
|||
doFetch(); |
|||
}, [request]); |
|||
|
|||
return { data, isFetching, error }; |
|||
}; |
|||
|
|||
export default useFetch; |
|||
@ -0,0 +1,16 @@ |
|||
import React from "react"; |
|||
import ReactDOM from "react-dom"; |
|||
import App from "./App"; |
|||
|
|||
//redux
|
|||
import { Provider } from "react-redux"; |
|||
import store from "./reducers/store"; |
|||
|
|||
ReactDOM.render( |
|||
<React.StrictMode> |
|||
<Provider store={store}> |
|||
<App /> |
|||
</Provider> |
|||
</React.StrictMode>, |
|||
document.getElementById("root") |
|||
); |
|||
|
After Width: | Height: | Size: 2.6 KiB |
@ -0,0 +1,373 @@ |
|||
//actions
|
|||
|
|||
const initState = { |
|||
// list components full data
|
|||
componentsFull: [], |
|||
// list of components
|
|||
components: [], |
|||
// list of products
|
|||
products: [], |
|||
// List of components without quantity
|
|||
componentsModel: [], |
|||
// info user
|
|||
user: {}, |
|||
// components for product
|
|||
componentsProduct: [], |
|||
// product selected
|
|||
productSelected: {}, |
|||
// component selected
|
|||
componentSelected: {}, |
|||
// List of process products
|
|||
processProducts: [], |
|||
// state of checked process products components
|
|||
processProductsChecked: [], |
|||
// process request
|
|||
processRequest: { |
|||
loading: false, |
|||
}, |
|||
processProductsThunk: { |
|||
loading: false, |
|||
data: {}, |
|||
error: null, |
|||
}, |
|||
// c of products
|
|||
componentstoProduct: [], |
|||
// notes
|
|||
notesThunk: { |
|||
loading: false, |
|||
data: {}, |
|||
error: null, |
|||
}, |
|||
// supplies //TODO
|
|||
suppliesThunk: { |
|||
loading: false, |
|||
data: {}, |
|||
error: null, |
|||
}, |
|||
// supplies
|
|||
supplies: [], |
|||
//providers
|
|||
providers: [], |
|||
// select provider
|
|||
providerSelected: [], |
|||
|
|||
newPrice: 0, |
|||
newProviderThunk: { |
|||
loading: false, |
|||
data: {}, |
|||
error: null, |
|||
}, |
|||
}; |
|||
|
|||
//action types
|
|||
|
|||
const ADD_COMPONENT = "ADD_COMPONENT"; |
|||
const ADD_PRODUCT = "ADD_PRODUCT"; |
|||
const GET_PROCESS_PRODUCTS = "GET_PROCESS_PRODUCTS"; |
|||
const GET_PRODUCTS = "GET_PRODUCTS"; |
|||
const GET_COMPONENTS = "GET_COMPONENTS"; |
|||
const ADD_COMPONENTS_PRODUCT = "ADD_COMPONENTS_PRODUCT"; |
|||
const REMOVE_COMPONENTS_PRODUCT = "REMOVE_COMPONENTS_PRODUCT"; |
|||
const CLEAN_COMPONENTS_PRODUCT = "CLEAN_COMPONENTS_PRODUCT"; |
|||
const SET_QUANTITY_COMPONENT_PRODUCT = "SET_QUANTITY_COMPONENT_PRODUCT"; |
|||
const PRODUCT_SELECTED = "PRODUCT_SELECTED"; |
|||
const COMPONENT_SELECTED = "COMPONENT_SELECTED"; |
|||
const RESET_COMPONENTS_PRODUCT = "RESET_COMPONENTS_PRODUCT"; |
|||
const CHECKED_PROCESS_PRODUCTS = "CHECKED_PROCESS_PRODUCTS"; |
|||
const SET_PROCESS_REQUEST = "SET_PROCESS_REQUEST"; |
|||
const START_PROCESS_PRODUCTS = "START_PROCESS_PRODUCTS"; |
|||
const ERROR_PROCESS_PRODUCTS = "ERROR_PROCESS_PRODUCTS"; |
|||
const SUCCESS_PROCESS_PRODUCTS = "SUCCESS_PROCESS_PRODUCTS"; |
|||
const START_NOTES = "START_NOTES"; |
|||
const ERROR_NOTES = "ERROR_NOTES"; |
|||
const SUCCESS_NOTES = "SUCCESS_NOTES"; |
|||
const REQUEST_GET_SUPPLIES = "REQUEST_GET_SUPPLIES"; |
|||
const ERROR_GET_SUPPLIES = "ERROR_GET_SUPPLIES"; |
|||
const SUCCESS_GET_SUPPLIES = "SUCCESS_GET_SUPPLIES"; |
|||
//add providers
|
|||
const ADD_PROVIDER = "ADD_PROVIDER"; |
|||
const GET_PROVIDERS = "GET_PROVIDERS"; |
|||
|
|||
//provider selected
|
|||
const PROVIDER_SELECTED = "PROVIDER_SELECTED"; |
|||
|
|||
//new price
|
|||
const NEW_PRICE = "NEW_PRICE"; |
|||
|
|||
//thunk new price
|
|||
const REQUEST_NEW_PROVIDER = "REQUEST_NEW_PROVIDER"; |
|||
const ERROR_NEW_PROVIDER = "ERROR_NEW_PROVIDER"; |
|||
const SUCCESS_NEW_PROVIDER = "SUCCESS_NEW_PROVIDER"; |
|||
|
|||
//reducer
|
|||
|
|||
export default function reducer(state = initState, action) { |
|||
switch (action.type) { |
|||
case ADD_COMPONENT: |
|||
return { |
|||
...state, |
|||
components: [action.payload], |
|||
}; |
|||
case GET_COMPONENTS: |
|||
// remove field quantity from components
|
|||
const compForModel = action.payload.map((component) => { |
|||
const { quantity, ...rest } = component; |
|||
return rest; |
|||
}); |
|||
return { |
|||
...state, |
|||
components: action.payload, |
|||
componentsModel: compForModel, |
|||
componentsFull: action.payload, |
|||
}; |
|||
case ADD_PRODUCT: |
|||
return { |
|||
...state, |
|||
products: [action.payload], |
|||
}; |
|||
case ADD_COMPONENTS_PRODUCT: |
|||
//verify if the component is already in the list
|
|||
|
|||
let components = action.payload; |
|||
let componentsProduct = state.componentsModel; |
|||
let prevState = state.componentsProduct; |
|||
|
|||
// add _id from prevState to components
|
|||
prevState.forEach((component) => { |
|||
components.forEach((comp) => { |
|||
if (component._id !== comp._id) { |
|||
components.push(component); |
|||
} |
|||
}); |
|||
}); |
|||
|
|||
componentsProduct = componentsProduct.filter((component) => { |
|||
return components.find((comp) => { |
|||
return comp._id === component._id; |
|||
}); |
|||
}); |
|||
|
|||
// add field quantity to the componentsProduct
|
|||
|
|||
componentsProduct.forEach((component) => { |
|||
// verify if field quantity is already in the component
|
|||
if (!component.hasOwnProperty("quantity")) { |
|||
component.quantity = 1; |
|||
} |
|||
}); |
|||
|
|||
return { |
|||
...state, |
|||
componentsProduct: componentsProduct, |
|||
}; |
|||
|
|||
case REMOVE_COMPONENTS_PRODUCT: |
|||
let idComponentRemove = action.payload; |
|||
let componentsProductRemove = state.componentsProduct; |
|||
|
|||
componentsProductRemove = componentsProductRemove.filter((component) => { |
|||
return component._id !== idComponentRemove; |
|||
}); |
|||
|
|||
return { |
|||
...state, |
|||
componentsProduct: componentsProductRemove, |
|||
}; |
|||
|
|||
case CLEAN_COMPONENTS_PRODUCT: |
|||
return { |
|||
...state, |
|||
componentsProduct: [], |
|||
}; |
|||
|
|||
case SET_QUANTITY_COMPONENT_PRODUCT: |
|||
//verify if the component is already in the list
|
|||
let componentsProduct2 = state.componentsProduct; |
|||
let componentQuantity = action.payload; |
|||
|
|||
componentsProduct2.forEach((component) => { |
|||
if (component._id === componentQuantity.id) { |
|||
component.quantity = parseInt(componentQuantity.quantity); |
|||
} |
|||
}); |
|||
return { |
|||
...state, |
|||
componentsProduct: componentsProduct2, |
|||
}; |
|||
case GET_PRODUCTS: |
|||
return { |
|||
...state, |
|||
products: action.payload, |
|||
}; |
|||
case PRODUCT_SELECTED: |
|||
return { |
|||
...state, |
|||
productSelected: action.payload, |
|||
}; |
|||
case COMPONENT_SELECTED: |
|||
return { |
|||
...state, |
|||
componentSelected: action.payload, |
|||
}; |
|||
case RESET_COMPONENTS_PRODUCT: |
|||
return { |
|||
...state, |
|||
componentsProduct: [], |
|||
}; |
|||
case GET_PROCESS_PRODUCTS: |
|||
return { |
|||
...state, |
|||
processRequest: { |
|||
loading: false, |
|||
}, |
|||
processProducts: action.payload, |
|||
}; |
|||
case CHECKED_PROCESS_PRODUCTS: |
|||
return { |
|||
...state, |
|||
processProductsChecked: action.payload, |
|||
}; |
|||
case SET_PROCESS_REQUEST: |
|||
return { |
|||
...state, |
|||
processRequest: action.payload, |
|||
}; |
|||
case START_PROCESS_PRODUCTS: |
|||
return { |
|||
...state, |
|||
processProductsThunk: { |
|||
loading: true, |
|||
data: {}, |
|||
error: null, |
|||
}, |
|||
}; |
|||
case ERROR_PROCESS_PRODUCTS: |
|||
return { |
|||
...state, |
|||
processProductsThunk: { |
|||
loading: false, |
|||
data: {}, |
|||
error: action.payload, |
|||
}, |
|||
}; |
|||
case SUCCESS_PROCESS_PRODUCTS: |
|||
return { |
|||
...state, |
|||
componentstoProduct: action.payload.resComponents, |
|||
productSelected: { |
|||
...state.productSelected, |
|||
components: action.payload.resProduct.components, |
|||
}, |
|||
processProductsThunk: { |
|||
loading: false, |
|||
data: action.payload.resProduct, |
|||
error: null, |
|||
}, |
|||
}; |
|||
case START_NOTES: |
|||
return { |
|||
...state, |
|||
notesThunk: { |
|||
loading: true, |
|||
data: {}, |
|||
error: null, |
|||
}, |
|||
}; |
|||
case ERROR_NOTES: |
|||
return { |
|||
...state, |
|||
notesThunk: { |
|||
loading: false, |
|||
data: {}, |
|||
error: action.payload, |
|||
}, |
|||
}; |
|||
case SUCCESS_NOTES: |
|||
return { |
|||
...state, |
|||
notesThunk: { |
|||
loading: false, |
|||
data: action.payload, |
|||
error: null, |
|||
}, |
|||
}; |
|||
|
|||
case REQUEST_GET_SUPPLIES: |
|||
return { |
|||
...state, |
|||
suppliesThunk: { |
|||
loading: true, |
|||
data: {}, |
|||
error: null, |
|||
}, |
|||
}; |
|||
case ERROR_GET_SUPPLIES: |
|||
return { |
|||
...state, |
|||
suppliesThunk: { |
|||
loading: false, |
|||
data: {}, |
|||
error: action.payload, |
|||
}, |
|||
}; |
|||
case SUCCESS_GET_SUPPLIES: |
|||
return { |
|||
...state, |
|||
suppliesThunk: { |
|||
loading: false, |
|||
data: action.payload, |
|||
error: null, |
|||
}, |
|||
}; |
|||
case ADD_PROVIDER: |
|||
return { |
|||
...state, |
|||
providers: [action.payload], |
|||
}; |
|||
case GET_PROVIDERS: |
|||
return { |
|||
...state, |
|||
providers: action.payload, |
|||
}; |
|||
case PROVIDER_SELECTED: |
|||
return { |
|||
...state, |
|||
providerSelected: action.payload, |
|||
}; |
|||
case NEW_PRICE: |
|||
return { |
|||
...state, |
|||
newPrice: action.payload, |
|||
}; |
|||
case REQUEST_NEW_PROVIDER: |
|||
return { |
|||
...state, |
|||
newProviderThunk: { |
|||
loading: true, |
|||
data: {}, |
|||
error: null, |
|||
}, |
|||
}; |
|||
case ERROR_NEW_PROVIDER: |
|||
return { |
|||
...state, |
|||
newProviderThunk: { |
|||
loading: false, |
|||
data: {}, |
|||
error: action.payload, |
|||
}, |
|||
}; |
|||
case SUCCESS_NEW_PROVIDER: |
|||
return { |
|||
...state, |
|||
newProviderThunk: { |
|||
loading: false, |
|||
data: action.payload, |
|||
error: null, |
|||
}, |
|||
}; |
|||
|
|||
default: |
|||
return state; |
|||
} |
|||
} |
|||
@ -0,0 +1,34 @@ |
|||
import { getComponentsByIds } from "../services/components"; |
|||
import { getProcessProductById } from "../services/processProduct"; |
|||
|
|||
const START_PROCESS_PRODUCTS = "START_PROCESS_PRODUCTS"; |
|||
const ERROR_PROCESS_PRODUCTS = "ERROR_PROCESS_PRODUCTS"; |
|||
const SUCCESS_PROCESS_PRODUCTS = "SUCCESS_PROCESS_PRODUCTS"; |
|||
|
|||
export const getProcessProductsThunk = (processProductId) => { |
|||
return async (dispatch) => { |
|||
dispatch({ type: START_PROCESS_PRODUCTS }); |
|||
|
|||
try { |
|||
const response = await getProcessProductById(processProductId); |
|||
|
|||
// get components ids
|
|||
let ids = []; |
|||
response.components.forEach((component) => { |
|||
ids.push(component._id); |
|||
}); |
|||
|
|||
// get components
|
|||
const components = await getComponentsByIds(ids); |
|||
|
|||
let finalResponse = { |
|||
resProduct: response, |
|||
resComponents: components, |
|||
}; |
|||
|
|||
dispatch({ type: SUCCESS_PROCESS_PRODUCTS, payload: finalResponse }); |
|||
} catch (error) { |
|||
dispatch({ type: ERROR_PROCESS_PRODUCTS, payload: error }); |
|||
} |
|||
}; |
|||
}; |
|||
@ -0,0 +1,33 @@ |
|||
import { getNotesByIdSupply } from "../services/supplies"; |
|||
import { addOrUpdateNotes } from "../services/supplies"; |
|||
|
|||
|
|||
const START_NOTES = "START_NOTES"; |
|||
const ERROR_NOTES = "ERROR_NOTES"; |
|||
const SUCCESS_NOTES = "SUCCESS_NOTES"; |
|||
|
|||
export const getNotesThunk = (supplyId) => { |
|||
return async (dispatch) => { |
|||
dispatch({ type: START_NOTES }); |
|||
try { |
|||
const res = await getNotesByIdSupply(supplyId); |
|||
|
|||
dispatch({ type: SUCCESS_NOTES, payload: res }); |
|||
} catch (error) { |
|||
dispatch({ type: ERROR_NOTES, payload: error }); |
|||
} |
|||
}; |
|||
}; |
|||
|
|||
export const addOrUpdateNotesThunk = (supplyId, note) => { |
|||
return async (dispatch) => { |
|||
dispatch({ type: START_NOTES }); |
|||
try { |
|||
const res = await addOrUpdateNotes(supplyId, note); |
|||
|
|||
dispatch({ type: SUCCESS_NOTES, payload: res }); |
|||
} catch (error) { |
|||
dispatch({ type: ERROR_NOTES, payload: error }); |
|||
} |
|||
}; |
|||
}; |
|||
@ -0,0 +1,40 @@ |
|||
import { addProvider } from "../services/providers"; |
|||
|
|||
const ADD_PROVIDER = "ADD_PROVIDER"; |
|||
const PROVIDER_SELECTED = "PROVIDER_SELECTED"; |
|||
const NEW_PRICE = "NEW_PRICE"; |
|||
|
|||
export const addProviderRedux = (formData) => { |
|||
return async (dispatch) => { |
|||
try { |
|||
const res = await addProvider(formData); |
|||
dispatch({ type: ADD_PROVIDER, payload: res }); |
|||
} catch (error) { |
|||
dispatch({ type: ADD_PROVIDER, payload: error }); |
|||
} |
|||
}; |
|||
}; |
|||
|
|||
// save selected provider
|
|||
export const providerSelectedRedux = (provider) => { |
|||
console.log("provider desde redux"); |
|||
console.log(provider); |
|||
return async (dispach) => { |
|||
try { |
|||
dispach({ type: PROVIDER_SELECTED, payload: provider }); |
|||
} catch (error) { |
|||
console.log(error); |
|||
} |
|||
}; |
|||
}; |
|||
|
|||
//save new price value
|
|||
export const newPriceRedux = (price) => { |
|||
return async (dispach) => { |
|||
try { |
|||
dispach({ type: NEW_PRICE, payload: price }); |
|||
} catch (error) { |
|||
console.log(error); |
|||
} |
|||
}; |
|||
}; |
|||
@ -0,0 +1,10 @@ |
|||
//create store
|
|||
|
|||
import thunk from "redux-thunk"; |
|||
import { createStore, applyMiddleware } from "redux"; |
|||
import reducer from "./actions"; |
|||
import { composeWithDevTools} from "redux-devtools-extension"; |
|||
|
|||
// export create Store with thunk and devtools
|
|||
export default createStore(reducer, composeWithDevTools(applyMiddleware(thunk))); |
|||
|
|||
@ -0,0 +1,55 @@ |
|||
import { getSupplies, assignProviderAndPrice } from "../services/supplies"; |
|||
|
|||
const REQUEST_GET_SUPPLIES = "REQUEST_GET_SUPPLIES"; |
|||
const ERROR_GET_SUPPLIES = "ERROR_GET_SUPPLIES"; |
|||
const SUCCESS_GET_SUPPLIES = "SUCCESS_GET_SUPPLIES"; |
|||
|
|||
const REQUEST_NEW_PROVIDER = "REQUEST_NEW_PROVIDER"; |
|||
const ERROR_NEW_PROVIDER = "ERROR_NEW_PROVIDER"; |
|||
const SUCCESS_NEW_PROVIDER = "SUCCESS_NEW_PROVIDER"; |
|||
|
|||
export const getSuppliesThunk = () => { |
|||
return async (dispatch) => { |
|||
dispatch({ type: REQUEST_GET_SUPPLIES }); |
|||
try { |
|||
const res = await getSupplies(); |
|||
|
|||
dispatch({ type: SUCCESS_GET_SUPPLIES, payload: res }); |
|||
} catch (error) { |
|||
dispatch({ type: ERROR_GET_SUPPLIES, payload: error }); |
|||
} |
|||
}; |
|||
}; |
|||
|
|||
// save new data in newProviderThunk
|
|||
export const newProviderThunkRedux = (idSupply, idProvider, price) => { |
|||
// console.log("desde supplies reducer");
|
|||
// console.log(idSupply, idProvider, price);
|
|||
return async (dispatch) => { |
|||
dispatch({ type: REQUEST_NEW_PROVIDER }); |
|||
try { |
|||
const res = await assignProviderAndPrice(idSupply, idProvider, price); |
|||
// console.log("res from supplies reducer", res);
|
|||
dispatch({ type: SUCCESS_NEW_PROVIDER, payload: res}); |
|||
} catch (error) { |
|||
dispatch({ type: ERROR_NEW_PROVIDER, payload: error }); |
|||
} |
|||
}; |
|||
}; |
|||
|
|||
|
|||
// // save new price value in new_priceThunk
|
|||
// export const newProviderThunkRedux = (idSupply, idProvider, price) => {
|
|||
// console.log('desde supplies reducer')
|
|||
// console.log(idSupply, idProvider, price)
|
|||
// return async (dispatch) => {
|
|||
// try {
|
|||
// dispatch({ type: REQUEST_NEW_PROVIDER });
|
|||
// const res = await assignProviderAndPrice(idSupply, idProvider, price);
|
|||
// console.log('res from supplies reducer',)
|
|||
// dispatch({ type: SUCCESS_NEW_PROVIDER, payload: res });
|
|||
// } catch (error) {
|
|||
// dispatch({ type: ERROR_NEW_PROVIDER, payload: error });
|
|||
// }
|
|||
// };
|
|||
// };
|
|||
@ -0,0 +1,28 @@ |
|||
import axios from "axios"; |
|||
const API = process.env.REACT_APP_API; |
|||
|
|||
//get all supplies
|
|||
export const getCategories = async () => { |
|||
const res = await axios.get(`${API}/api/categories`); |
|||
if (res.status === 201) { |
|||
console.log('desde el service', res.data.body); |
|||
return res.data.body; |
|||
} else { |
|||
return; |
|||
} |
|||
}; |
|||
|
|||
//add new provider
|
|||
export const addCategory = async (formData) => { |
|||
const res = await axios({ |
|||
method: "post", |
|||
url: `${API}/api/categories`, |
|||
data: formData, |
|||
}); |
|||
|
|||
if (res.status === 201) { |
|||
return res.data; |
|||
} else { |
|||
return; |
|||
} |
|||
}; |
|||
@ -0,0 +1,96 @@ |
|||
import axios from "axios"; |
|||
const API = process.env.REACT_APP_API; |
|||
|
|||
//get all components
|
|||
export const getComponents = async () => { |
|||
console.log(API); |
|||
const res = await axios.get( |
|||
`${API}/api/inventory/components/get` |
|||
); |
|||
|
|||
if (res.status === 200) { |
|||
return res.data; |
|||
} else { |
|||
return; |
|||
} |
|||
}; |
|||
|
|||
// add component
|
|||
export const addComponent = async (formData) => { |
|||
const res = await axios({ |
|||
method: "post", |
|||
url: `${API}/api/inventory/components/add`, |
|||
data: formData, |
|||
headers: { |
|||
"Content-Type": "multipart/form-data", |
|||
}, |
|||
}); |
|||
|
|||
if (res.status === 200) { |
|||
return res.data; |
|||
} else { |
|||
return; |
|||
} |
|||
}; |
|||
|
|||
// get component by Id
|
|||
export const getComponentsByIds = async (ids) => { |
|||
const res = await axios.post( |
|||
`${API}/api/inventory/components/getids`, |
|||
{ ids } |
|||
); |
|||
|
|||
if (res.status === 200) { |
|||
return res.data; |
|||
} else { |
|||
return; |
|||
} |
|||
}; |
|||
|
|||
export const deleteComponent = async (id) => { |
|||
const res = await axios.delete( |
|||
`${API}/api/inventory/components/delete/${id}` |
|||
); |
|||
|
|||
if (res.status === 200) { |
|||
return res.data; |
|||
} else { |
|||
return; |
|||
} |
|||
}; |
|||
|
|||
// edit component by Id
|
|||
export const editComponentById = async (id, formData) => { |
|||
const res = await axios({ |
|||
method: "put", |
|||
url: `${API}/api/inventory/components/editdata/${id}`, |
|||
data: formData, |
|||
headers: { |
|||
"Content-Type": "multipart/form-data", |
|||
}, |
|||
}); |
|||
|
|||
if (res.status === 200) { |
|||
return res.data; |
|||
} else { |
|||
return; |
|||
} |
|||
}; |
|||
|
|||
// send csv file to server
|
|||
export const sendCsvFile = async (formData) => { |
|||
const res = await axios({ |
|||
method: "post", |
|||
url: `${API}/api/inventory/components/csv`, |
|||
data: formData, |
|||
headers: { |
|||
"Content-Type": "multipart/form-data", |
|||
}, |
|||
}); |
|||
|
|||
if (res.status === 200) { |
|||
return res.data; |
|||
} else { |
|||
return; |
|||
} |
|||
}; |
|||
@ -0,0 +1,33 @@ |
|||
import axios from "axios"; |
|||
const API = process.env.REACT_APP_API; |
|||
//get notes by id component
|
|||
export const getNotesByIdComponent = async (ids) => { |
|||
const res = await axios.get( |
|||
`${API}/api/inventory/notes/${ids}` |
|||
); |
|||
|
|||
if (res.status === 200) { |
|||
return res.data; |
|||
} else { |
|||
return; |
|||
} |
|||
}; |
|||
|
|||
// add or update notes
|
|||
export const addOrUpdateNotes = async (componentId, data) => { |
|||
console.log(componentId, data); |
|||
const res = await axios({ |
|||
method: "post", |
|||
url: `${API}/api/inventory/notes/`, |
|||
data: { |
|||
componentId: componentId, |
|||
data: data, |
|||
}, |
|||
}); |
|||
|
|||
if (res.status === 200) { |
|||
return res.data; |
|||
} else { |
|||
return; |
|||
} |
|||
}; |
|||
@ -0,0 +1,48 @@ |
|||
import axios from "axios"; |
|||
const API = process.env.REACT_APP_API; |
|||
|
|||
// add new order
|
|||
// add supply
|
|||
export const addOrder = async (formData) => { |
|||
console.log("NewOrder desde el service"); |
|||
console.log("formData", formData); |
|||
const res = await axios({ |
|||
method: "post", |
|||
url: `${API}/api/orders`, |
|||
data: formData, |
|||
headers: { |
|||
"Content-Type": "application/json", |
|||
}, |
|||
}); |
|||
|
|||
if (res.status === 201) { |
|||
return res.data; |
|||
} else { |
|||
return; |
|||
} |
|||
}; |
|||
|
|||
// get list providers by supply Id
|
|||
export const getListProvidersByIdSupply = async (id) => { |
|||
console.log("desde service listProviderByIdSupply", id); |
|||
const res = await axios.get(`${API}/api/supplies/listproviders?id=${id}`); |
|||
|
|||
if (res.status === 201) { |
|||
console.log("RESPUESTA" + res.data.body); |
|||
return res.data.body; |
|||
} else { |
|||
return; |
|||
} |
|||
}; |
|||
|
|||
// get orders by supply id // TODO! OLD
|
|||
export const getOrdersBySupplyId = async (supplyId) => { |
|||
console.log("supplyId desde el service", supplyId); |
|||
const res = await axios.get(`${API}/api/orders?id=${supplyId}`); |
|||
if (res.status === 201) { |
|||
console.log("exito status 201 .res.data.body: ", res.data.body); |
|||
return res.data.body; |
|||
} else { |
|||
return; |
|||
} |
|||
}; |
|||
@ -0,0 +1,73 @@ |
|||
import axios from "axios"; |
|||
const API = process.env.REACT_APP_API; |
|||
|
|||
export const getProcessProducts = async () => { |
|||
const res = await axios.get(`${API}/api/inventory/process`); |
|||
|
|||
if (res.status === 200) { |
|||
return res.data; |
|||
} else { |
|||
return; |
|||
} |
|||
}; |
|||
|
|||
export const getProcessProductById = async (id) => { |
|||
const res = await axios.get( |
|||
`${API}/api/inventory/process/${id}` |
|||
); |
|||
|
|||
console.log(res); |
|||
|
|||
if (res.status === 200) { |
|||
return res.data; |
|||
} else { |
|||
return; |
|||
} |
|||
}; |
|||
|
|||
export const addProcessProduct = async (formData) => { |
|||
const res = await axios({ |
|||
method: "post", |
|||
url: `${API}/api/inventory/process/add`, |
|||
data: formData, |
|||
headers: { |
|||
"Content-Type": "multipart/form-data", |
|||
}, |
|||
}); |
|||
|
|||
if (res.status === 200) { |
|||
return res.data; |
|||
} else { |
|||
return; |
|||
} |
|||
}; |
|||
|
|||
export const updateQuantity = async (formData, id) => { |
|||
const res = await axios({ |
|||
method: "put", |
|||
url: `${API}/api/inventory/process/quantity/${id}`, |
|||
data: formData, |
|||
}); |
|||
if (res.status === 200) { |
|||
return res.data; |
|||
} else { |
|||
return; |
|||
} |
|||
}; |
|||
|
|||
export const updateStatus = async (id, status) => { |
|||
const res = await axios({ |
|||
method: "put", |
|||
url: `${API}/api/inventory/process/state/${id}`, |
|||
data: status, |
|||
headers: { |
|||
"content-type": "application/json", |
|||
}, |
|||
}); |
|||
|
|||
if (res.status === 200) { |
|||
return res.data; |
|||
} else { |
|||
return; |
|||
} |
|||
}; |
|||
@ -0,0 +1,48 @@ |
|||
import axios from "axios"; |
|||
const API = process.env.REACT_APP_API; |
|||
|
|||
export const addProduct = async (formData) => { |
|||
const res = await axios({ |
|||
method: "post", |
|||
url: `${API}/api/inventory/products/addmodel`, |
|||
data: formData, |
|||
headers: { |
|||
"Content-Type": "multipart/form-data", |
|||
}, |
|||
}); |
|||
|
|||
if (res.status === 200) { |
|||
return res.data; |
|||
} else { |
|||
return; |
|||
} |
|||
}; |
|||
|
|||
export const getProducts = async () => { |
|||
const res = await axios({ |
|||
method: "get", |
|||
url: `${API}/api/inventory/products/all`, |
|||
}); |
|||
|
|||
console.log(res); |
|||
|
|||
if (res.status === 200) { |
|||
return res.data; |
|||
} else { |
|||
return; |
|||
} |
|||
}; |
|||
|
|||
export const deleteProductModel = async (id) => { |
|||
console.log("Eliminar"); |
|||
console.log(id); |
|||
const res = await axios.delete( |
|||
`http://localhost:5000/api/inventory/products/deleteModel/${id}` |
|||
); |
|||
|
|||
if (res.status === 200) { |
|||
return res.data; |
|||
} else { |
|||
return; |
|||
} |
|||
}; |
|||
@ -0,0 +1,46 @@ |
|||
import axios from "axios"; |
|||
const API = process.env.REACT_APP_API; |
|||
|
|||
//add new provider
|
|||
export const addProvider = async (formData) => { |
|||
const res = await axios({ |
|||
method: "post", |
|||
url: `${API}/api/providers`, |
|||
data: formData, |
|||
}); |
|||
|
|||
if (res.status === 201) { |
|||
return res.data; |
|||
} else { |
|||
return; |
|||
} |
|||
}; |
|||
|
|||
// get all providers
|
|||
export const getProviders = async () => { |
|||
const res = await axios.get(`${API}/api/providers`); |
|||
if (res.status === 201) { |
|||
return res.data.body; |
|||
} else { |
|||
return; |
|||
} |
|||
}; |
|||
|
|||
// add price to provider by Id
|
|||
export const addPriceToProviderById = async (idProvider, price) => { |
|||
const res = await axios.put( |
|||
`${API}/api/providers/price/${idProvider}`, |
|||
{ price: price }, |
|||
{ |
|||
headers: { |
|||
"Content-Type": "application/json", |
|||
}, |
|||
} |
|||
); |
|||
|
|||
if (res.status === 201) { |
|||
return res.data; |
|||
} else { |
|||
return; |
|||
} |
|||
}; |
|||
@ -0,0 +1,201 @@ |
|||
import axios from "axios"; |
|||
const API = process.env.REACT_APP_API; |
|||
|
|||
//get all supplies
|
|||
export const getSupplies = async () => { |
|||
const res = await axios.get(`${API}/api/supplies`); |
|||
if (res.status === 201) { |
|||
console.log("LOS SUPLAIS VIENEN ASI", res.data.body); |
|||
return res.data.body; |
|||
} else { |
|||
return; |
|||
} |
|||
}; |
|||
|
|||
// add supply
|
|||
export const addSupply = async (formData) => { |
|||
console.log("Add Supply desde el service"); |
|||
console.log("formData", formData); |
|||
const res = await axios({ |
|||
method: "post", |
|||
url: `${API}/api/supplies`, |
|||
data: formData, |
|||
headers: { |
|||
"Content-Type": "multipart/form-data", |
|||
}, |
|||
}); |
|||
|
|||
if (res.status === 200) { |
|||
return res.data; |
|||
} else { |
|||
return; |
|||
} |
|||
}; |
|||
|
|||
// get supply by Id
|
|||
export const getSupplyById = async (id) => { |
|||
console.log("id en funcion " + id); |
|||
const res = await axios.get(`${API}/api/supplies?id=${id}`); |
|||
|
|||
if (res.status === 201) { |
|||
return res.data.body[0]; |
|||
} else { |
|||
console.log("no hace el get"); |
|||
return; |
|||
} |
|||
}; |
|||
|
|||
//delete supply - status DB false
|
|||
export const deleteSupply = async (id) => { |
|||
console.log("desde el service" + id); |
|||
const res = await axios.patch(`${API}/api/supplies/totrash/${id}`); |
|||
|
|||
if (res.status === 201) { |
|||
return res; |
|||
} else { |
|||
return; |
|||
} |
|||
}; |
|||
|
|||
//delete supply definitely
|
|||
export const deleteSupplyDefinitely = async (id) => { |
|||
console.log("deleteSupplyDefinitely desde el service " + id); |
|||
const res = await axios.delete(`${API}/api/supplies/${id}`); |
|||
|
|||
if (res.status === 201) { |
|||
console.log("RES > " + res); |
|||
return res; |
|||
} else { |
|||
return; |
|||
} |
|||
}; |
|||
|
|||
//get trash supplies NUEVO
|
|||
export const getTrashSupplies = async () => { |
|||
console.log("entro al getTrashSupplies"); |
|||
const res = await axios.get(`${API}/api/supplies/trash`); |
|||
if (res.status === 201) { |
|||
console.log("LOS ARCHIVED SUPLAIS VIENEN ASI", res.data.body); |
|||
return res.data.body; |
|||
} else { |
|||
return; |
|||
} |
|||
}; |
|||
|
|||
// edit supply by Id
|
|||
export const editSupplyById = async (id, formData) => { |
|||
console.log("Edit Supply desde el service"); |
|||
console.log("id", id); |
|||
console.log("formData", formData); |
|||
const res = await axios.patch(`${API}/api/supplies/${id}`, formData, { |
|||
headers: { |
|||
"Content-Type": "multipart/form-data", |
|||
Accept: "application/json", |
|||
}, |
|||
}); |
|||
|
|||
if (res.status === 201) { |
|||
return res.data; |
|||
} else { |
|||
return res.error; |
|||
} |
|||
}; |
|||
|
|||
// send csv file to server
|
|||
export const sendCsvFile = async (formData) => { |
|||
const res = await axios({ |
|||
method: "post", |
|||
url: `${API}/api/inventory/supply/csv`, |
|||
data: formData, |
|||
headers: { |
|||
"Content-Type": "multipart/form-data", |
|||
}, |
|||
}); |
|||
|
|||
if (res.status === 200) { |
|||
return res.data; |
|||
} else { |
|||
return; |
|||
} |
|||
}; |
|||
|
|||
// assign provider to supply with patch method // TODO? ESTO EL METODO VIEJO.
|
|||
export const assignProvider = async (idSupply, idProvider) => { |
|||
const res = await axios.patch( |
|||
`${API}/api/supplies/assign/${idSupply}`, |
|||
{ idProvider: idProvider }, |
|||
{ |
|||
headers: { |
|||
"Content-Type": "application/json", |
|||
}, |
|||
} |
|||
); |
|||
|
|||
if (res.status === 200) { |
|||
return; |
|||
} else { |
|||
return; |
|||
} |
|||
}; |
|||
|
|||
//asign provider and price to supply with patch method // TODO ESTO EL METODO NUEVO!!!.
|
|||
export const assignProviderAndPrice = async (idSupply, idProvider, price) => { |
|||
console.log("dsde el service", idSupply, idProvider, price); |
|||
const res = await axios.patch( |
|||
`${API}/api/supplies/assignPrice/${idSupply}`, |
|||
{ provider: idProvider, price: price }, |
|||
{ |
|||
headers: { |
|||
"Content-Type": "application/json", |
|||
}, |
|||
} |
|||
); |
|||
|
|||
if (res.status === 200) { |
|||
console.log("res.data.body.providers[0] desde service...... !"); |
|||
console.log(res.data.body); |
|||
return res.data.body; |
|||
} else { |
|||
return; |
|||
} |
|||
}; |
|||
|
|||
//get notes by supply Id
|
|||
export const getNotesByIdSupply = async (id) => { |
|||
const res = await axios.get(`${API}/api/supplies?id=${id}`); |
|||
|
|||
if (res.status === 201) { |
|||
console.log("desde service : ", res.data.body[0].note); |
|||
return res.data.body[0].note; |
|||
} else { |
|||
console.log("no hace el get"); |
|||
return; |
|||
} |
|||
}; |
|||
|
|||
// add or update note by supply id
|
|||
export const addOrUpdateNotes = async (id, note) => { |
|||
console.log("addOrUpdateNoteByIdSupply desde el service"); |
|||
console.log("id", id); |
|||
console.log("note", note); |
|||
const res = await axios.patch(`${API}/api/supplies/updatenote/${id}`, { |
|||
note: note, |
|||
}); |
|||
|
|||
if (res.status === 201) { |
|||
return res.data; |
|||
} else { |
|||
return; |
|||
} |
|||
}; |
|||
|
|||
// // get list providers by supply Id
|
|||
// export const getListProvidersByIdSupply = async (id) => {
|
|||
// const res = await axios.get(`${API}/api/supplies/listproviders?id=${id}`);
|
|||
|
|||
// if (res.status === 201) {
|
|||
// return res.data.body;
|
|||
// } else {
|
|||
// return;
|
|||
// }
|
|||
// };
|
|||
@ -0,0 +1,26 @@ |
|||
export const createFormData = (jsonData) => { |
|||
const formData = new FormData(); |
|||
Object.keys(jsonData).forEach((key) => { |
|||
|
|||
switch (typeof jsonData[key]) { |
|||
case "object": |
|||
if (jsonData[key] instanceof File) { |
|||
formData.append(key, jsonData[key]); |
|||
} else { |
|||
formData.append(key, JSON.stringify(jsonData[key])); |
|||
} |
|||
break; |
|||
case "string": |
|||
case "number": |
|||
formData.append(key, jsonData[key]); |
|||
break; |
|||
|
|||
default: |
|||
formData.append(key, JSON.stringify(jsonData[key])); |
|||
} |
|||
}); |
|||
return formData; |
|||
}; |
|||
|
|||
|
|||
|
|||
@ -0,0 +1,13 @@ |
|||
import { useDispatch, useSelector } from "react-redux"; |
|||
|
|||
export const getComponentsById = (ids, componentsList) => { |
|||
let components = []; |
|||
|
|||
componentsList.forEach((component) => { |
|||
if (ids.includes(component._id)) { |
|||
components.push(component); |
|||
} |
|||
}); |
|||
|
|||
return components; |
|||
}; |
|||
@ -0,0 +1,4 @@ |
|||
export const showImage = (imageData, imageType) => { |
|||
const image = `data:${imageType};base64,${imageData}`; |
|||
return image; |
|||
}; |
|||
@ -0,0 +1,40 @@ |
|||
import { Button, TextField } from "@mui/material"; |
|||
import React from "react"; |
|||
|
|||
export const componentsJsonToDataGrid = (jsonComponents) => { |
|||
let columns = [ |
|||
{ |
|||
field: "id", |
|||
label: "ID", |
|||
}, |
|||
{ |
|||
field: "Name", |
|||
headerName: "Name", |
|||
}, |
|||
{ |
|||
field: "Description", |
|||
headerName: "Description", |
|||
}, |
|||
{ |
|||
field: "Category", |
|||
headerName: "Category", |
|||
}, |
|||
]; |
|||
let rows = []; |
|||
|
|||
for (let i = 0; i < jsonComponents.length; i++) { |
|||
let row = { |
|||
id: jsonComponents[i]._id, |
|||
Name: jsonComponents[i].name, |
|||
Description: jsonComponents[i].description, |
|||
Category: jsonComponents[i].category, |
|||
}; |
|||
|
|||
rows.push(row); |
|||
} |
|||
|
|||
return { |
|||
columns, |
|||
rows, |
|||
}; |
|||
}; |
|||
@ -0,0 +1,20 @@ |
|||
import Calculator from "../components/Calculator"; |
|||
|
|||
export default function Calculator_View() { |
|||
return ( |
|||
<> |
|||
<div |
|||
style={{ |
|||
display: "flex", |
|||
flexDirection: "column", |
|||
alignItems: "center", |
|||
justifyContent: 'center', |
|||
minHeight: "100vh", |
|||
background: "#0d1214", |
|||
}} |
|||
> |
|||
<Calculator /> |
|||
</div> |
|||
</> |
|||
); |
|||
} |
|||
@ -0,0 +1,47 @@ |
|||
import React, { useEffect, useState } from "react"; |
|||
import DataTableComponents from "../components/DataTableComponents"; |
|||
import { useDispatch, useSelector } from "react-redux"; |
|||
import { Button, Container, Grid } from "@mui/material"; |
|||
import { Link } from "react-router-dom"; |
|||
import ButtonAdd from "../components/ButtonAdd"; |
|||
|
|||
export default function Components() { |
|||
const components = useSelector((state) => state.components); |
|||
|
|||
return ( |
|||
<div |
|||
style={{ |
|||
display: "flex", |
|||
flexDirection: "column", |
|||
alignItems: "center", |
|||
justifyContent: "center", |
|||
minHeight: "100vh", |
|||
width: "100vw", |
|||
}} |
|||
> |
|||
<div |
|||
style={{ |
|||
display: "flex", |
|||
flexDirection: "column", |
|||
alignItems: "center", |
|||
justifyContent: "center", |
|||
minHeight: "100vh", |
|||
width: "95vw", |
|||
}} |
|||
> |
|||
<div |
|||
style={{ |
|||
width: '100vw', |
|||
display: "flex", |
|||
justifyContent: "flex-end", |
|||
marginRight: "3%", |
|||
marginTop: '1%' |
|||
}} |
|||
> |
|||
<ButtonAdd router={"/newcomponent"} /> |
|||
</div> |
|||
<DataTableComponents components={components} /> |
|||
</div> |
|||
</div> |
|||
); |
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
import ComponentEdit from "../components/ComponentEdit"; |
|||
|
|||
export default function EditComponent() { |
|||
return ( |
|||
<> |
|||
<div style={{ height: "100vh" }}> |
|||
<ComponentEdit /> |
|||
</div> |
|||
</> |
|||
); |
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
import SupplyEdit from "../components/SupplyEdit"; |
|||
|
|||
export default function EditSuppy() { |
|||
return ( |
|||
<> |
|||
<div style={{ height: "100vh" }}> |
|||
<SupplyEdit /> |
|||
</div> |
|||
</> |
|||
); |
|||
} |
|||
@ -0,0 +1,40 @@ |
|||
import React, { useEffect, useState } from "react"; |
|||
import Grid from "@mui/material/Grid"; |
|||
import { getProcessProducts } from "../services/processProduct"; |
|||
import { useDispatch, useSelector } from "react-redux"; |
|||
import CardGridFabric from "../components/CardGridFabric"; |
|||
|
|||
export default function FabricDashboard() { |
|||
const dispatch = useDispatch(); |
|||
|
|||
// redux state |
|||
const processProducts = useSelector((state) => state.processProducts); |
|||
const [refresh, setRefresh] = useState(false); |
|||
|
|||
const getProcessProductsFromServer = async () => { |
|||
const data = await getProcessProducts(); |
|||
if (data !== null) { |
|||
dispatch({ type: "GET_PROCESS_PRODUCTS", payload: data }); |
|||
} |
|||
setRefresh(true); |
|||
}; |
|||
|
|||
useEffect(() => { |
|||
getProcessProductsFromServer(); |
|||
}, [refresh]); |
|||
|
|||
return ( |
|||
<> |
|||
<Grid |
|||
container |
|||
spacing={0} |
|||
direction="column" |
|||
alignItems="center" |
|||
justifyContent="center" |
|||
style={{ minHeight: "100vh" }} |
|||
> |
|||
<CardGridFabric /> |
|||
</Grid> |
|||
</> |
|||
); |
|||
} |
|||
@ -0,0 +1,69 @@ |
|||
import React, { useEffect, useState } from "react"; |
|||
import CardGrid from "../components/CardGrid"; |
|||
import ButtonAdd from "../components/ButtonAdd"; |
|||
import { getProducts } from "../services/products"; |
|||
import { useDispatch, useSelector } from "react-redux"; |
|||
import GridHome from "../components/GridHome"; |
|||
import EmptyBox from "../components/emptyBox"; |
|||
|
|||
export default function Home() { |
|||
const dispatch = useDispatch(); |
|||
|
|||
// delete info location state |
|||
|
|||
// redux state |
|||
const products = useSelector((state) => state.products); |
|||
|
|||
const getProductsFromServer = async () => { |
|||
const data = await getProducts(); |
|||
|
|||
if (data !== null) { |
|||
dispatch({ type: "GET_PRODUCTS", payload: data }); |
|||
} |
|||
}; |
|||
|
|||
useEffect(() => { |
|||
getProductsFromServer(); |
|||
}, []); |
|||
|
|||
return ( |
|||
<> |
|||
<div |
|||
style={{ |
|||
display: "flex", |
|||
flexDirection: "column", |
|||
alignItems: "center", |
|||
minHeight: "100vh", |
|||
background: "#0d1214", |
|||
}} |
|||
> |
|||
<div |
|||
style={{ |
|||
position: "fixed", |
|||
right: "2em", |
|||
top: "4em", |
|||
zIndex: "1000", |
|||
}} |
|||
> |
|||
<ButtonAdd router={"/newproductmodel"} /> |
|||
</div> |
|||
{products.length < 1 ? ( |
|||
<div style={{ width: "90vw" }}> |
|||
<div |
|||
style={{ |
|||
display: "flex", |
|||
alignItems: "center", |
|||
justifyContent: "center", |
|||
height: "100vh", |
|||
}} |
|||
> |
|||
<EmptyBox /> |
|||
</div> |
|||
</div> |
|||
) : ( |
|||
<CardGrid /> |
|||
)} |
|||
</div> |
|||
</> |
|||
); |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
import React, { Children } from "react"; |
|||
import { BrowserRouter as Router, Route, Switch } from "react-router-dom"; |
|||
import NavBar from "../components/NavBar"; |
|||
|
|||
const Layout = ({ children }) => { |
|||
return ( |
|||
<div className="lightblack"> |
|||
<div |
|||
style={{ |
|||
position: "absolute", |
|||
top: "0", |
|||
left: "0", |
|||
width: "100%", |
|||
zIndex: '1' |
|||
}} |
|||
> |
|||
<NavBar /> |
|||
</div> |
|||
{children} |
|||
</div> |
|||
); |
|||
}; |
|||
|
|||
export default Layout; |
|||
@ -0,0 +1,36 @@ |
|||
import React from "react"; |
|||
import FormComponent from "../components/FormComponent"; |
|||
import Grid from "@mui/material/Grid"; |
|||
|
|||
const NewComponent = () => { |
|||
return ( |
|||
<> |
|||
{/* form */} |
|||
|
|||
<Grid |
|||
container |
|||
spacing={0} |
|||
direction="column" |
|||
alignItems="center" |
|||
justifyContent="center" |
|||
style={{ |
|||
minHeight: "100vh", |
|||
}} |
|||
> |
|||
<h2 |
|||
style={{ |
|||
color: "lightgrey", |
|||
marginBottom: "1%", |
|||
fontWeight: "400", |
|||
}} |
|||
> |
|||
AGREGAR COMPONENTE |
|||
</h2> |
|||
|
|||
<FormComponent /> |
|||
</Grid> |
|||
</> |
|||
); |
|||
}; |
|||
|
|||
export default NewComponent; |
|||
@ -0,0 +1,64 @@ |
|||
import { Box } from "@mui/system"; |
|||
import { useEffect, useState } from "react"; |
|||
import FormNewOrder from "../components/FormNewOrder"; |
|||
import { getSupplyById } from "../services/supplies"; |
|||
import { useParams } from "react-router-dom"; |
|||
import { Link } from "react-router-dom"; |
|||
import ArrowBackIosIcon from "@mui/icons-material/ArrowBackIos"; |
|||
|
|||
const NewOrder_View = () => { |
|||
const { id } = useParams(); |
|||
const [supply, setSupply] = useState({}); |
|||
|
|||
const loadSupply = async () => { |
|||
const supply = await getSupplyById(id); |
|||
setSupply(supply); |
|||
}; |
|||
|
|||
// use Effect get Supply by id |
|||
useEffect(() => { |
|||
loadSupply(); |
|||
}, []); |
|||
|
|||
console.log("supply", supply); |
|||
|
|||
return ( |
|||
<> |
|||
{/* form */} |
|||
<div |
|||
style={{ |
|||
display: "flex", |
|||
flexDirection: "column", |
|||
justifyContent: "center", |
|||
alignItems: "center", |
|||
minHeight: "100vh", |
|||
}} |
|||
> |
|||
<Box style={{ height: "100px" }}></Box> |
|||
|
|||
<div className="wrapper-header-providers"> |
|||
<Link to={"/supplies"}> |
|||
<div className="header-title text-hover"> |
|||
<ArrowBackIosIcon style={{ fontSize: "15px" }} /> |
|||
INSUMOS | PROVEEDORES | NUEVA ORDEN |
|||
</div> |
|||
</Link> |
|||
</div> |
|||
<div className="header-title-neworder"> |
|||
<h2>{supply.name}</h2> |
|||
<h2 |
|||
style={{ |
|||
fontWeight: "400", |
|||
}} |
|||
> |
|||
NUEVA ORDEN |
|||
</h2> |
|||
</div> |
|||
|
|||
<FormNewOrder supplyData={supply} /> |
|||
</div> |
|||
</> |
|||
); |
|||
}; |
|||
|
|||
export default NewOrder_View; |
|||
@ -0,0 +1,303 @@ |
|||
import React, { useCallback, useEffect, useState } from "react"; |
|||
import { |
|||
Box, |
|||
Button, |
|||
MenuItem, |
|||
Stack, |
|||
TextField, |
|||
Typography, |
|||
} from "@mui/material"; |
|||
import NewProductFabricComponents from "../components/NewProductFabricComponents"; |
|||
import { useHistory } from "react-router-dom"; |
|||
import LinearProgress, { |
|||
linearProgressClasses, |
|||
} from "@mui/material/LinearProgress"; |
|||
import { showImage } from "../utils/imageUtils"; |
|||
import { styled } from "@mui/material/styles"; |
|||
import { useSelector } from "react-redux"; |
|||
import { updateStatus } from "../services/processProduct"; |
|||
import Dialog from "@mui/material/Dialog"; |
|||
import DialogActions from "@mui/material/DialogActions"; |
|||
import DialogContent from "@mui/material/DialogContent"; |
|||
import useMediaQuery from "@mui/material/useMediaQuery"; |
|||
import { useTheme } from "@mui/material/styles"; |
|||
|
|||
// progress bar style |
|||
const BorderLinearProgress = styled(LinearProgress)(({ theme }) => ({ |
|||
height: 10, |
|||
borderRadius: 5, |
|||
[`&.${linearProgressClasses.colorPrimary}`]: { |
|||
backgroundColor: |
|||
theme.palette.grey[200], |
|||
}, |
|||
[`& .${linearProgressClasses.bar}`]: { |
|||
borderRadius: 5, |
|||
backgroundColor: "#3082aa", |
|||
}, |
|||
})); |
|||
|
|||
//status options |
|||
const statusOptions = [ |
|||
{ |
|||
value: "PENDING", |
|||
label: "EN PROCESO", |
|||
}, |
|||
{ |
|||
value: "FINISHED", |
|||
label: "TERMINADO", |
|||
}, |
|||
{ |
|||
value: "ARCHIVED", |
|||
label: "ARCHIVADO", |
|||
}, |
|||
]; |
|||
|
|||
export default function NewProductFabric() { |
|||
//popUp |
|||
const [open, setOpen] = useState(false); |
|||
const theme = useTheme(); |
|||
const fullScreen = useMediaQuery(theme.breakpoints.down("md")); |
|||
|
|||
const history = useHistory(); |
|||
|
|||
const handleClickOpen = () => { |
|||
setOpen(true); |
|||
}; |
|||
|
|||
const handleClose = () => { |
|||
setOpen(false); |
|||
}; |
|||
//end PopUp |
|||
|
|||
// local state |
|||
const [percentage, setPercentage] = useState(0); |
|||
|
|||
//redux |
|||
const productSelected = useSelector((state) => state.productSelected); |
|||
|
|||
// process image |
|||
const processImage = (imageData, contentType) => { |
|||
const img = showImage(imageData, contentType); |
|||
return img; |
|||
}; |
|||
|
|||
let processProductImage = processImage( |
|||
productSelected.model.image.data, |
|||
productSelected.model.image.contentType |
|||
); |
|||
|
|||
let statusNow = productSelected.stateProduction; |
|||
|
|||
// form state |
|||
const [form, setForm] = useState(statusNow); |
|||
// handler for state |
|||
const handleChange = (e) => { |
|||
setForm(e.target.value); |
|||
}; |
|||
|
|||
//service |
|||
|
|||
const editStatus = async () => { |
|||
// json object for send |
|||
const data = { |
|||
stateProduction: form, |
|||
}; |
|||
|
|||
const res = await updateStatus(productSelected._id, data); |
|||
history.push("/fabricdashboard"); |
|||
return res; |
|||
}; |
|||
|
|||
useEffect(() => { |
|||
const value = progressbarPercent(); |
|||
setPercentage(value); |
|||
}, [percentage]); |
|||
|
|||
const progressbarPercent = () => { |
|||
let components = productSelected.components; |
|||
let total = components.map( |
|||
(component) => component.outstandingQuantity + component.finishedQuantity |
|||
); |
|||
let totalSum = total.reduce((a, b) => a + b, 0); |
|||
|
|||
let totalFinished = 0; |
|||
|
|||
components.forEach((component) => { |
|||
totalFinished += component.finishedQuantity; |
|||
}); |
|||
|
|||
let percent = (totalFinished * 100) / totalSum; |
|||
|
|||
percent = Math.round(percent); |
|||
|
|||
setPercentage(percent); |
|||
|
|||
return percent; |
|||
}; |
|||
|
|||
return ( |
|||
<div id="main-container" style={{ height: "100vh" }}> |
|||
<div |
|||
id="header" |
|||
style={{ |
|||
backgroundColor: "#0d1214", |
|||
paddingTop: "4%", |
|||
paddingLeft: 10, |
|||
paddingBottom: 10, |
|||
paddingRight: 10, |
|||
height: "10vh", |
|||
display: "flex", |
|||
justifyContent: "space-between", |
|||
alignItems: "end", |
|||
}} |
|||
> |
|||
<Stack> |
|||
<div |
|||
style={{ |
|||
// background: "yellow", |
|||
display: "flex", |
|||
flexDirection: "row", |
|||
alignItems: "end", |
|||
height: "100%", |
|||
width: 400, |
|||
}} |
|||
> |
|||
<Box id="img-box" width={75}> |
|||
<img |
|||
src={processProductImage} |
|||
alt="preview" |
|||
style={{ width: "100%", borderRadius: 50 }} |
|||
/> |
|||
</Box> |
|||
<div style={{ marginLeft: "1em" }}> |
|||
<Typography variant="h6" style={{ color: "whitesmoke" }}> |
|||
{productSelected.model.name} |
|||
</Typography> |
|||
<Typography variant="h4" style={{ color: "whitesmoke" }}> |
|||
{productSelected.name} |
|||
</Typography> |
|||
</div> |
|||
</div> |
|||
</Stack> |
|||
<div |
|||
id="progressBar" |
|||
style={{ |
|||
display: "flex", |
|||
flexDirection: "column", |
|||
verticalAlign: "center", |
|||
marginBottom: 30, |
|||
|
|||
width: "30%", |
|||
marginRight: "2%", |
|||
}} |
|||
> |
|||
<p |
|||
style={{ |
|||
marginLeft: "50%", |
|||
marginBottom: "1%", |
|||
}} |
|||
> |
|||
{percentage}% |
|||
</p> |
|||
<BorderLinearProgress variant="determinate" value={percentage} /> |
|||
</div> |
|||
|
|||
<Box |
|||
style={{ |
|||
alignSelf: "end", |
|||
paddingRight: 30, |
|||
}} |
|||
> |
|||
<TextField |
|||
name="stateProduction" |
|||
select |
|||
value={form} |
|||
onChange={handleChange} |
|||
style={{ |
|||
width: "40ch", |
|||
border: "2px solid #3082aa", |
|||
textAlign: "center", |
|||
borderRadius: 50, |
|||
paddingRight: 5, |
|||
paddingLeft: 5, |
|||
marginBottom: 20, |
|||
}} |
|||
InputProps={{ disableUnderline: true }} |
|||
variant="standard" |
|||
> |
|||
{statusOptions.map((option) => ( |
|||
<MenuItem key={option.value} value={option.value}> |
|||
{option.label} |
|||
</MenuItem> |
|||
))} |
|||
</TextField> |
|||
</Box> |
|||
</div> |
|||
|
|||
<div |
|||
id="body" |
|||
style={{ |
|||
height: "75vh", |
|||
|
|||
padding: 20, |
|||
display: "flex", |
|||
justifyContent: "center", |
|||
}} |
|||
> |
|||
<div style={{ height: "100%" }}> |
|||
<NewProductFabricComponents |
|||
Scomponents={productSelected.model.components} |
|||
percentage={progressbarPercent} |
|||
/> |
|||
</div> |
|||
|
|||
<Button |
|||
type="submit" |
|||
style={{ |
|||
width: "200", |
|||
position: "absolute", |
|||
bottom: 50, |
|||
right: 100, |
|||
backgroundColor: "#3082aa", |
|||
}} |
|||
variant="contained" |
|||
onClick={handleClickOpen} |
|||
> |
|||
{/* <svg |
|||
xmlns="http://www.w3.org/2000/svg" |
|||
width="24" |
|||
height="24" |
|||
viewBox="0 0 24 24" |
|||
fill="none" |
|||
stroke="currentColor" |
|||
strokeWidth="2" |
|||
> |
|||
<path d="M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 16.2z" /> |
|||
</svg> */} |
|||
CONFIRMAR |
|||
</Button> |
|||
|
|||
<Dialog |
|||
fullScreen={fullScreen} |
|||
open={open} |
|||
onClose={handleClose} |
|||
aria-labelledby="responsive-dialog-title" |
|||
> |
|||
<DialogContent> |
|||
<h3 style={{ fontWeight: '400' , color: "lightgrey " }}> |
|||
¿Desea confirmar sin guardar los cambios? |
|||
</h3> |
|||
</DialogContent> |
|||
<DialogActions> |
|||
<Button className="textGrey" autoFocus onClick={handleClose}> |
|||
NO |
|||
</Button> |
|||
<Button className="textGrey" onClick={editStatus} autoFocus> |
|||
SI |
|||
</Button> |
|||
</DialogActions> |
|||
</Dialog> |
|||
</div> |
|||
</div> |
|||
); |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
import React from "react"; |
|||
import FormProductModel from "../components/FormProductModel"; |
|||
|
|||
const NewProductModel = () => { |
|||
return ( |
|||
<> |
|||
<div |
|||
style={{ |
|||
height: "100vh", |
|||
display: "flex", |
|||
justifyContent: "center", |
|||
alignItems: "center", |
|||
}} |
|||
> |
|||
<FormProductModel /> |
|||
</div> |
|||
</> |
|||
); |
|||
}; |
|||
|
|||
export default NewProductModel; |
|||
@ -0,0 +1,35 @@ |
|||
import Grid from "@mui/material/Grid"; |
|||
import { Box } from "@mui/system"; |
|||
import FormSupply from "../components/FormSupply"; |
|||
|
|||
const NewSupply = () => { |
|||
return ( |
|||
<> |
|||
{/* form */} |
|||
<div |
|||
style={{ |
|||
display: "flex", |
|||
flexDirection: "column", |
|||
justifyContent: "center", |
|||
alignItems: "center", |
|||
minHeight: "100vh", |
|||
}} |
|||
> |
|||
<Box style={{height: '100px'}}></Box> |
|||
<h2 |
|||
style={{ |
|||
color: "lightgrey", |
|||
marginBottom: "1%", |
|||
fontWeight: "400", |
|||
}} |
|||
> |
|||
AGREGAR INSUMO |
|||
</h2> |
|||
|
|||
<FormSupply /> |
|||
</div> |
|||
</> |
|||
); |
|||
}; |
|||
|
|||
export default NewSupply; |
|||
@ -0,0 +1,31 @@ |
|||
import React from "react"; |
|||
import ProductModelInfo from "../components/ProductModelInfo"; |
|||
import ComponentsProductModel from "../components/ComponentsProductModel"; |
|||
import { useSelector } from "react-redux"; |
|||
import DownArrow from "../components/DownArrow"; |
|||
|
|||
export default function ProductModel() { |
|||
// redux state |
|||
|
|||
const productSelected = useSelector((state) => state.productSelected); |
|||
return ( |
|||
<> |
|||
<div style={{ height: "100vh", background: "#f2f4f6" }}> |
|||
<ProductModelInfo product={productSelected} /> |
|||
</div> |
|||
<div |
|||
style={{ |
|||
width: "100%", |
|||
background: "", |
|||
display: "fluid", |
|||
alignItems: "left", |
|||
}} |
|||
> |
|||
<ComponentsProductModel product={productSelected} /> |
|||
<div style={{ position: "absolute", bottom: "2%", left: "45%" }}> |
|||
<DownArrow /> |
|||
</div> |
|||
</div> |
|||
</> |
|||
); |
|||
} |
|||
@ -0,0 +1,54 @@ |
|||
import { useState } from "react"; |
|||
import { useSelector } from "react-redux"; |
|||
import { Link } from "react-router-dom"; |
|||
import ButtonAdd from "../components/ButtonAdd"; |
|||
import DataTableProvidersDetail from "../components/DataTableProvidersDetail"; |
|||
import ArrowBackIosIcon from "@mui/icons-material/ArrowBackIos"; |
|||
|
|||
export default function ProvidersDetail() { |
|||
const selectedSupply = useSelector((state) => state.componentSelected); |
|||
console.log("selectedSupply desde providersDetail"); |
|||
console.log(selectedSupply); |
|||
|
|||
const [total, setTotal] = useState(0); |
|||
|
|||
const pull_total = (total) => { |
|||
setTotal(total); |
|||
console.log("total: " + total); // LOGS DATA FROM CHILD (My name is Dean Winchester... &) |
|||
}; |
|||
|
|||
return ( |
|||
<> |
|||
<div className="container-body-providers"> |
|||
<div className="wrapper-header-providers"> |
|||
<Link to={"/supplies"}> |
|||
<div className="header-title text-hover"> |
|||
<ArrowBackIosIcon style={{ fontSize: "15px" }} /> |
|||
INSUMOS | PROVEEDORES |
|||
</div> |
|||
</Link> |
|||
<ButtonAdd router={`/neworder/${selectedSupply._id}`} /> |
|||
</div> |
|||
|
|||
<div className="header-title-providers"> |
|||
<h2>{selectedSupply.name}</h2> |
|||
<div |
|||
style={{ |
|||
display: "flex", |
|||
flexDirection: "column", |
|||
alignItems: "end", |
|||
}} |
|||
> |
|||
<h5>CANTIDAD TOTAL</h5> |
|||
<h4>{total}</h4> |
|||
</div> |
|||
</div> |
|||
|
|||
<DataTableProvidersDetail |
|||
selectedSupply={selectedSupply} |
|||
funcTotal={pull_total} |
|||
/> |
|||
</div> |
|||
</> |
|||
); |
|||
} |
|||
@ -0,0 +1,46 @@ |
|||
import DataTableSupplies from "../components/DataTableSupplies"; |
|||
import { useDispatch, useSelector } from "react-redux"; |
|||
import ButtonAdd from "../components/ButtonAdd"; |
|||
import ButtonArchived from "../components/ButtonArchived"; |
|||
import ArrowBackIosIcon from "@mui/icons-material/ArrowBackIos"; |
|||
|
|||
import { useEffect } from "react"; |
|||
import { getSuppliesThunk } from "../reducers/supplies"; |
|||
import { Link } from "react-router-dom"; |
|||
|
|||
export default function Supplies() { |
|||
const components = useSelector((state) => state.components); |
|||
const supplies = useSelector((state) => state.suppliesThunk); |
|||
|
|||
const dispatch = useDispatch(); |
|||
|
|||
const fetchSupplies = async () => { |
|||
await dispatch(getSuppliesThunk()); |
|||
}; |
|||
|
|||
useEffect(() => { |
|||
fetchSupplies(); |
|||
}, []); |
|||
|
|||
//console.log("supplies desde SuppliesView"); |
|||
//console.log(supplies); |
|||
|
|||
return ( |
|||
<div className="container-body"> |
|||
<div className="container-body-paper"> |
|||
<div className="wrapper-header"> |
|||
<Link style={{cursor: 'default'}}> |
|||
<div className="header-title text-hover">INSUMOS</div> |
|||
</Link> |
|||
<ButtonArchived |
|||
router={"/archivedsupplies"} |
|||
title={"ARCHIVADOS"} |
|||
icon={"down"} |
|||
/> |
|||
<ButtonAdd router={"/newsupply"} /> |
|||
</div> |
|||
<DataTableSupplies suppliesThunk={supplies} /> |
|||
</div> |
|||
</div> |
|||
); |
|||
} |
|||
@ -0,0 +1,61 @@ |
|||
import ButtonAdd from "../components/ButtonAdd"; |
|||
import ButtonArchived from "../components/ButtonArchived"; |
|||
import ArrowBackIosIcon from "@mui/icons-material/ArrowBackIos"; |
|||
import { getTrashSupplies } from "../services/supplies"; |
|||
import DataTableSuppliesArchived from "../components/DataTableSuppliesArchived"; |
|||
import { Link } from "react-router-dom"; |
|||
import { CircularProgress } from "@mui/material"; |
|||
import useFetch from "../hooks/useFetch"; |
|||
import { useEffect, useState } from "react"; |
|||
|
|||
const request = getTrashSupplies(); |
|||
|
|||
export default function SuppliesArchived() { |
|||
/* const { data, isFetching, error } = useFetch(request); |
|||
|
|||
if (isFetching) { |
|||
return ( |
|||
<div className="container-body"> |
|||
<CircularProgress /> |
|||
</div> |
|||
); |
|||
} |
|||
|
|||
if (error) { |
|||
return <p>{error.message}</p>; |
|||
} |
|||
|
|||
if (!data) { |
|||
return null; |
|||
} */ |
|||
|
|||
// get trash supplies |
|||
const [trashSupplies, setTrashSupplies] = useState([]); |
|||
|
|||
const getTrashSuppliesToServer = async () => { |
|||
const trashSupplies = await getTrashSupplies(); |
|||
setTrashSupplies(trashSupplies); |
|||
}; |
|||
|
|||
useEffect(() => { |
|||
getTrashSuppliesToServer(); |
|||
}, []); |
|||
|
|||
return ( |
|||
<div className="container-body"> |
|||
<div className="container-body-paper"> |
|||
<div className="wrapper-header"> |
|||
<Link to={"/supplies"}> |
|||
<div className="header-title text-hover"> |
|||
<ArrowBackIosIcon style={{ fontSize: "15px" }} /> |
|||
INSUMOS | ARCHIVADOS |
|||
</div> |
|||
</Link> |
|||
<ButtonArchived router={"/supplies"} title={"INSUMOS"} icon={"up"} /> |
|||
<ButtonAdd router={"/newsupply"} /> |
|||
</div> |
|||
<DataTableSuppliesArchived suppliesThunk={trashSupplies} /> |
|||
</div> |
|||
</div> |
|||
); |
|||
} |
|||
Loading…
Reference in new issue