diff --git a/.firebase/hosting.YnVpbGQ.cache b/.firebase/hosting.YnVpbGQ.cache new file mode 100644 index 000000000..391ccd9f5 --- /dev/null +++ b/.firebase/hosting.YnVpbGQ.cache @@ -0,0 +1,36 @@ +favicon.ico,499162500000,d96ddbc4933b04e12c738ab39f469573143949ca2c39eda0a49d16f83d40c319 +logo192.png,499162500000,3ee59515172ee198f3be375979df15ac5345183e656720a381b8872b2a39dc8b +logo512.png,499162500000,ee7e2f3fdb8209c4b6fd7bef6ba50d1b9dba30a25bb5c3126df057e1cb6f5331 +logQueen.png,1593650837105,f48a4251a5af6d751d93e48d975ef4da933aadf658e044ae4771eb6e31c91d6c +logQueen192.png,1594660083401,f76e441433b08aeb8028b882ef7516c14e867a205675073d464068b7f76610fc +logQueen512.png,1594660170467,6b94c6ab6ac89e0b6accf59eab7df86fc4faa7490a6b17c9a524d77bf5cbeb21 +manifest.json,1595258052743,6c1b3e4b7ab740c6b42bfe505b5306347259ad1a8307ef928125e13bfdcd7998 +maskable_iconQueen.png,1594931219890,33480cf6421caf5e6417a887e8d74db7c9b26e4d2e2bc38115edb607a3d01692 +robots.txt,499162500000,bfe106a3fb878dc83461c86818bf74fc1bdc7f28538ba613cd3e775516ce8b49 +Thumbs.db,1595257838725,5fb6b9bbb3a3b9ef652b5ca1d5644f71c23da491fef145269fe92af0177b468c +asset-manifest.json,1595287931071,e94b30ad0721488dcb6be6f3310b4dcf6fff2d19b19d36c3226da8aa37810d4c +index.html,1595287931070,37f2f8f1c544eb18066d152bc6c62908364e7d253c8c374b2fa9f4fabad1ac21 +precache-manifest.df2572b32120dddf465fd7958a922b03.js,1595287931070,c36edd3e4ae885d0839ee79a337fbfc8a7feb3d14ee673269d6254dbf4c43d2b +service-worker.js,1595287931070,20016185440f0822aec2455cad15cfb590d591fb88316f99f2ee20df85a4d381 +static/css/main.379eec51.chunk.css,1595287931007,e421473db3422639bae76245ac4960b6bdcca840353715710d07b57d5f4191e0 +static/css/main.379eec51.chunk.css.map,1595287931073,a8afd3ca385911b5f1b626464be71af4824d80f75ecc551bfa8633e14e39433e +static/js/2.94b281fd.chunk.js.LICENSE.txt,1595287931073,99677d0f5522ee72e399c2e67c5e775311b8aadf8ac265324d7b1e5e2a8bfdd9 +static/js/main.81684295.chunk.js,1595287931007,1a84ccb944538a995a0ddfdc3183f30fd049aba9a2d1d03c0a977e17168cdf8d +static/js/runtime-main.961881d2.js,1595287931071,50b322606ee7bdeff2474bf477488e3423fb47ddd6e0384c4a50a288807dc9a9 +static/js/runtime-main.961881d2.js.map,1595287931074,4377ef9382405335930d8ce87c804e2898f35d1c7ee6078c029953e73397088a +static/media/bigSoda.f8fbd973.png,1595287931008,797d15516ea42470a5d92f800665a16be84f52378a4cb0a0cd5558ed26fd60d1 +static/media/bigWater.853b8e1d.png,1595287931008,5cf832beeeed8ae06670338bdd93bad4631130babdbd54a4d0d22d078cefcd61 +static/media/frenchFries.061bd213.png,1595287931008,892760377ea27ae9bcdd3ed02204695cebafd667482505329e45bc55c3b0c371 +static/media/simpleBurguer.0a5690a2.png,1595287931007,17a7f9062a9a2db874204e3c589c183e77c896f29471273bbfa74de5583dc463 +static/media/coffe.ac76ceff.png,1595287931006,2b0ce27c7c1312d24b25d5eab2ea9054fa60c1ea94ee4fe0402a613e266ce60a +static/media/doubleBurguer.fc6a27f4.png,1595287931008,a4ea34a8362ff5044e6cc3113b39c9f3de6c9e3e58b1e823f3644416ec27f62c +static/media/juice.2f216e25.png,1595287931006,3c993b5d886763290d7d0cdb91952923756f72e2780b6e68ec3cf87f6e2b761b +static/media/logQueen.303cd5c4.png,1595287931014,f48a4251a5af6d751d93e48d975ef4da933aadf658e044ae4771eb6e31c91d6c +static/media/sandwich.591bf75b.png,1595287931009,3cb9f1c74aea278ef857a882e92c36d3041de790186db8129bd2ffe979074b20 +static/media/smallSoda.91a1323d.png,1595287931012,6612ce5fa2c5a1d9b5cbe6220327a2c872e58b666ac27c5dd967058f851782ea +static/media/smallWater.b54a99c4.png,1595287931008,1345bbd228a4b5d7ed41df6206a779734ba6c39b9b8fcc4f4067258bf7f5a596 +static/media/coffeMilk.d1608cd7.png,1595287931001,65d556942e2ce3e500585dd309470ece9d03d8280b099592a648c040a5510661 +static/media/onion.f70093bd.png,1595287931008,dc5fbc150504449cec9f797ce690ab38f82ef6865c6891298c6bb34680d73b35 +static/js/main.81684295.chunk.js.map,1595287931074,06820e9c4d70742518a4e0be15bdb238ae8b317fb85fa2cf500bc1906258421f +static/js/2.94b281fd.chunk.js,1595287931073,b935cb08d04053ff79cef0979d5fb1ceb82fa955975f205b3c84f965002540d2 +static/js/2.94b281fd.chunk.js.map,1595287931078,83afe3c07c2a534b8e5b9f114fed5d88bf2da613cfc160011925cdd69b5782b6 diff --git a/.firebaserc b/.firebaserc new file mode 100644 index 000000000..8c2187774 --- /dev/null +++ b/.firebaserc @@ -0,0 +1,5 @@ +{ + "projects": { + "default": "burguerqueen-f6391" + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..7a352ae5d --- /dev/null +++ b/.gitignore @@ -0,0 +1,28 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* + + +package-lock.json +/src/firebase +/.firebase \ No newline at end of file diff --git a/README.md b/README.md index b2b4e9ba7..336596652 100644 --- a/README.md +++ b/README.md @@ -1,352 +1,59 @@ -# Burger Queen +# Burguer Queen -## Preámbulo +Aplicación creada para un pequeño restaurante de hamburguesas, el cual requiere tomar pedidos usando una tablet y enviarlos a cocina para que se preparen de manera ordenada y eficiente. -[React](https://reactjs.org/), [Vue](https://es.vuejs.org/index.html) y [Angular](https://angular.io/) -son algunos de los _frameworks_ y _librerías_ de JavaScript más utilizados por -lxs desarrolladorxs alrededor del mundo, y hay una razón para eso. -En el contexto del navegador, [_mantener la interfaz sincronizada con el estado -es difícil_](https://medium.com/dailyjs/the-deepest-reason-why-modern-javascript-frameworks-exist-933b86ebc445). -Al elegir un _framework_ o _librería_ para nuestra interfaz, nos apoyamos en una -serie de convenciones e implementaciones _probadas_ y _documentadas_ para -resolver un problema común a toda interfaz web. Esto nos permite concentrarnos -mejor (dedicar más tiempo) en las características _específicas_ de -nuestra aplicación. +Proyecto propuesto por Laboratoria, creado con React, Html5, Sass y como backend, Firebase. Desarrollado por [Lizeth Rivera](https://github.com/LizethRivera04) y [Elizabeth Flores](https://github.com/ElizaFlores11), teniendo como principales retos el aprendizaje de un framework (React), generar una PWA y mantener datos sin conexión. -Cuando elegimos una de estas tecnologías no solo importamos un pedacito de -código para reusarlo (lo cuál es un gran valor per se), si no que adoptamos una -**arquitectura**, una serie de **principios de diseño**, un **paradigma**, unas -**abstracciones**, un **vocabulario**, una **comunidad**, etc... -Como desarrolladora Front-end, estos kits de desarrollo pueden resultarte -de gran ayuda para implementar rápidamente características de los proyectos en -los que trabajes. +## Características -## Resumen del proyecto +- La aplicación fue diseñada para tablet con fines prácticos del restaurant, sin embargo, si usted desea probarla, es posible visualizarla en desktop. +- Como backend usamos Cloud Firestore. +- Es una [Progressive Web App](https://codigofacilito.com/articulos/progressive-apps) auditada con [Lighthouse](https://developers.google.com/web/tools/lighthouse/?hl=es) por lo que es posible usarla offline. +- El testing se realizó usando Testing Library y Jest. -Esta vez tenemos un proyecto 100% por encargo. Si bien siempre puedes (y debes) -hacer sugerencias de mejoras y/o cambios, muchas veces trabajarás en proyectos -en los que primero hay que asegurarse de cumplir con lo requerido. +## Funcionalidades -Un pequeño restaurante de hamburguesas, que está creciendo, necesita una -interfaz en la que puedan tomar pedidos usando una _tablet_, y enviarlos -a la cocina para que se preparen ordenada y eficientemente (a través de un -_backend_ del que nos darán detalles más adelante). +- La interfaz esta divida en dos perfiles : Mesero y Cocina. +- En la interfaz mesero, podemos encontrar dos menus: Desayuno y Comida, una vez seleccionado el platillo, se pueden agregar algunos aditamentos y la cantidad deseada. +- Una vez completado el pedido, el mesero la envía a cocina. +- El cocinero puede visualizar en tiempo real las ordenes pendientes y cambiar su estatus a listo una vez finalizada su preparación o en su defecto, cancelar el pedido. +- Cocinero y mesero pueden visualizar una lista de las ordenes con estatus pendiente y lista con el fin de llevar un control de las ordenes faltantes de entregar por parte de cocina, las ordenes que ya han sido preparadas para entregar al cliente, así como la opción de eliminar de la lista las ordenes entregadas. +- En caso de ser el mesero y estar en modo offline, las ordenes se guardan en caché y se envian a cocina, una vez regresando al modo online las ordenes son enviadas a Firestore. +- En caso de ser el cocinero y estar en modo offline, puede cambiar el estatus de las ordenes y visualizar el cambio en la lista de ordenes, una vez regresando al modo online el estatus es modificado en Firestore. -![burger-queen](https://user-images.githubusercontent.com/110297/42118136-996b4a52-7bc6-11e8-8a03-ada078754715.jpg) -Esta es la información que tenemos del cliente: +## Tecnologías usadas +- HTML +- CSS (Grid, Flexbox) +- SASS +- JavaScript +- React JS +- Firebase +- Jest +- Test Library +- Lighthouse -> Somos **Burguer Queen**, una cadena de comida 24hrs. -> -> Nuestra propuesta de servicio 24hrs ha tenido muy buena acogida y, para -> seguir creciendo, necesitamos un sistema que nos ayude a tomar los pedidos de -> nuestros clientes. -> -> Tenemos 2 menús: uno muy sencillo para el desayuno: -> -> | Ítem | Precio \$ | -> | ------------------------- | --------- | -> | Café americano | 5 | -> | Café con leche | 7 | -> | Sandwich de jamón y queso | 10 | -> | Jugo de frutas natural | 7 | -> -> Y otro menú para el resto del día: -> -> | Ítem | Precio | -> | -------------------- | ------ | -> | **Hamburguesas** | **\$** | -> | Hamburguesa simple | 10 | -> | Hamburguesa doble | 15 | -> | **Acompañamientos** | **\$** | -> | Papas fritas | 5 | -> | Aros de cebolla | 5 | -> | **Para tomar** | **\$** | -> | Agua 500ml | 5 | -> | Agua 750ml | 7 | -> | Bebida/gaseosa 500ml | 7 | -> | Bebida/gaseosa 750ml | 10 | -> -> **Importante:** Lxs clientes pueden escoger entre hamburguesas de res, -> de pollo, o vegetariana. Además, por \$ 1 adicional, pueden agregarle queso -> o huevo. -> -> Nuestros clientes son bastante indecisos, por lo que es muy común que cambien -> el pedido varias veces antes de finalizarlo. +## Nota -La interfaz debe mostrar los dos menús (desayuno y resto del día), cada uno -con todos sus _productos_. El usuario debe poder ir eligiendo qué _productos_ -agregar y la interfaz debe ir mostrando el _resumen del pedido_ con el -costo total. +Para visualizar el proyecto puedes ingresar al siguiente enlace https://burguerqueen-f6391.web.app/ y probarlo en una tablet, usando el simulador de Chrome o en modo desktop. -![out](https://user-images.githubusercontent.com/110297/45984241-b8b51c00-c025-11e8-8fa4-a390016bee9d.gif) +En caso de clonar el repositorio, necesitarás tener mínimo Node v.8.10 y npm v.5.6 instalados en tu computadora y ejecutar los siguientes comandos: -## Objetivos de aprendizaje +##### `npm start` +Ejecuta la aplicación en modo de desarrollo, al abrir http://localhost:3000 podrás visualizarlo en el navegador. -1. El objetivo principal de es aprender a construir una _interfaz web_ usando - el _framework_ elegido ([React](https://reactjs.org/), [Vue](https://es.vuejs.org/index.html) o [Angular](https://angular.io/)) o vanilla JS. Todos estos frameworks de - Front-end atacan el mismo problema: **cómo mantener la interfaz y el estado - sincronizados**. Así que esta experiencia espera familiarizarte con el concepto - de _estado de pantalla_, y cómo cada cambio sobre el estado se va a - ir reflejando en la interfaz (por ejemplo, cada vez que agregamos un _producto_ - a un _pedido_, la interfaz debe actualizar la lista del pedido y el total). +##### `npm test` +Se ejecutarán los test relacionados con los últimos archivos modificados. -2. Como objetivo secundario, deberás seguir las recomendaciones para PWAs - (_Progressive Web Apps_), lo cual incluye conceptos como **offline**. Para - guiarte con respecto a este tema te recomendamos usar [Lighthouse](https://developers.google.com/web/tools/lighthouse/?hl=es), - que es una herramienta de Google que nos ayuda a asegurar que nuestras web apps - sigan "buenas prácticas". De hecho, usaremos Lighthouse a la hora de evaluar el - proyecto. +##### `npm run build` +Corre este comando cuando estés listo para desplegar la app a producción, se creará una carpeta build que contendrá una compilación optimizada del proyecto -Recuerda colocar en esta seccion los objetivos de aprendizaje que quedaron -pendientes de tu proyecto anterior. -### HTML y CSS -- [ ] HTML semántico -- [ ] CSS flexbox -- [ ] Sass -- [ ] Maquetación +![Principal](img/BQ1.JPG) +![Waiter1](img/BQ3.JPG) +![Waiter2](img/BQ4.JPG) +![Kitchen1](img/BQ5.JPG) +![Kitchen2](img/BQ6.JPG) -### Frontend Development - -- [ ] Componentes -- [ ] Manejo del estado - -### PWA - -- [ ] Concepto -- [ ] Utilidad -- [ ] Que es [Workbox](https://developers.google.com/web/tools/workbox) -- [ ] Qué es un `serviceWorker` - -### Angular - -- [ ] [Uso de Components | Templates](https://angular.io/guide/architecture-components#introduction-to-components) -- [ ] [Directivas estructurales (ngIf / ngFor)](https://angular.io/guide/template-syntax#built-in-structural-directives) -- [ ] [@Input | @Ouput](https://angular.io/guide/component-interaction#component-interaction) -- [ ] [Creación y uso de servicios](https://angular.io/guide/architecture-services#providing-services) -- [ ] [Manejos de rutas](https://angular.io/guide/router) -- [ ] [Uso de Observables](https://angular.io/guide/observables-in-angular) -- [ ] [Uso de HttpClient](https://angular.io/guide/http) -- [ ] [Estilos de componentes (ngStyle / ngClass)](https://angular.io/guide/template-syntax#built-in-directives) - -### React - -- [ ] [`JSX`](https://es.reactjs.org/docs/introducing-jsx.html) -- [ ] [Componentes `class` y componentes `function`](https://es.reactjs.org/docs/components-and-props.html#function-and-class-components) -- [ ] `props` -- [ ] [Manejo de eventos](https://es.reactjs.org/docs/handling-events.html) -- [ ] [Listas y keys](https://es.reactjs.org/docs/lists-and-keys.html) -- [ ] [Renderizado condicional](https://es.reactjs.org/docs/conditional-rendering.html) -- [ ] [Levantamiento de estados](https://es.reactjs.org/docs/lifting-state-up.html) -- [ ] [`hooks`](https://es.reactjs.org/docs/hooks-intro.html) -- [ ] [`CSS` modules](https://create-react-app.dev/docs/adding-a-css-modules-stylesheet) -- [ ] [React Router](https://reacttraining.com/react-router/web) - -### Vue - -- [ ] [Instancia de Vue.js](https://es.vuejs.org/v2/guide/instance.html) -- [ ] [Datos y métodos](https://es.vuejs.org/v2/guide/instance.html#Datos-y-Metodos) -- [ ] [Uso y creación de Componentes](https://vuejs.org/v2/guide/components.html) -- [ ] [Props](https://es.vuejs.org/v2/guide/components.html#Pasando-datos-a-componentes-secundarios-con-Props) -- [ ] Directivas ([v-bind](https://es.vuejs.org/v2/api/#v-bind) | [v-model](https://es.vuejs.org/v2/guide/forms.html)) -- [ ] Renderizado condicional ([v-if](https://es.vuejs.org/v2/guide/conditional.html#v-if) | [v-else](https://es.vuejs.org/v2/guide/conditional.html#v-else)) -- [ ] Iteraciones ([v-for](https://es.vuejs.org/v2/guide/list.html#Mapeando-una-matriz-a-elementos-con-v-for)) -- [ ] Eventos ([v-on](https://es.vuejs.org/v2/guide/events.html)) -- [ ] [Propiedades Computadas y Observadores](https://es.vuejs.org/v2/guide/computed.html) -- [ ] [Router](https://router.vuejs.org/guide/#html) -- [ ] [Clases y Estilos](https://es.vuejs.org/v2/guide/class-and-style.html) -- [ ] [Gestión de Estado](https://es.vuejs.org/v2/guide/state-management.html#Gestion-de-estado-simple-desde-cero) - -### Firebase - -- [ ] Firestore -- [ ] Firebase security rules -- [ ] Observables - -### Testing - -- [ ] Testeo de tus interfaces -- [ ] Testeo de componentes -- [ ] Testeo asíncrono -- [ ] Mocking - -### Colaboración en Github - -- [ ] Branches -- [ ] Pull Requests -- [ ] Tags - -### Organización en Github - -- [ ] Projects -- [ ] Issues -- [ ] Labels -- [ ] Milestones - -### Buenas prácticas de desarrollo - -- [ ] Modularización -- [ ] Nomenclatura / Semántica -- [ ] Linting - ---- - -## Consideraciones - -- Este proyecto se debe "resolver" de a pares. - -- La duración propuesta del proyecto es 5 sprints, con una duración de una semana cada uno. - -- Trabaja en una historia hasta terminarla antes de pasar a la siguiente. - -- Trabaja hasta la historia que puedas en el tiempo especificado. - -- La lógica del proyecto debe estar implementada completamente en JavaScript - (ES6+), HTML y CSS y empaquetada de manera automatizada. - -- En este proyecto Sí está permitido usar librerías o frameworks - (debes elegir entre [React](https://reactjs.org/), [Vue](https://es.vuejs.org/index.html), - [Angular](https://angular.io/) o Vanilla Js). - -- La aplicación debe ser un _Single Page App_. Los pedidos los tomaremos desde una - _tablet_, pero **no queremos una app nativa**, sino una web app que sea - **responsive** y pueda funcionar **offline**. - -- La interfaz debe estar diseñada específicamente para correr en - **tablets**. - -- Necesitamos pensar bien en el aspecto UX de quienes van a tomar los pedidos, - el tamaño y aspecto de los botones, la visibilidad del estado actual del - pedido, etc. - -- La aplicación desplegada debe tener 80% o más el las puntuaciones de - Performance, Progressive Web App, Accessibility y Best Practices de Lighthouse. - -- Deberas de guardar la información de los pedidos realizados por - lo cual te recomendamos utilizar [Firebase](https://firebase.google.com/). - -- La aplicación debe hacer uso de `npm-scripts` y contar con scripts `start`, - `test`, `build` y `deploy`, que se encarguen de arrancar, correr las pruebas, - empaquetar y desplegar la aplicación respectivamente. - -- Los tests unitarios deben cubrir un mínimo del 90% de _statements_, _functions_, - _lines_ y _branches_. - -- Por otro lado, deberás definir la estructura de carpetas y archivos que consideres - necesaria. Puedes guiarte de las convenciones del _framework_ elegido. Por ende, - los _tests_ y el _setup_ necesario para ejecutarlos, serán hechos por ti. - -## Criterios de aceptación del proyecto - -### Definición del producto - -El [_Product Owner_](https://www.youtube.com/watch?v=r2hU7MVIzxs&t=202s) nos presenta este _backlog_ que es el resultado de su trabajo con el cliente hasta hoy. - ---- - -#### [Historia de usuario 1] Mesero/a debe poder tomar pedido de cliente - -Yo como meserx quiero tomar el pedido de un cliente para no depender de mi mala -memoria, para saber cuánto cobrar, y enviarlo a la cocina para evitar errores y -que se puedan ir preparando en orden. - -##### Criterios de aceptación - -Lo que debe ocurrir para que se satisfagan las necesidades del usuario - -- Anotar nombre de cliente. -- Agregar productos al pedido. -- Eliminar productos. -- Ver resumen y el total de la compra. -- Enviar pedido a cocina (guardar en alguna base de datos). -- Se ve y funciona bien en una _tablet_ - -##### Definición de terminado - -Lo acordado que debe ocurrir para decir que la historia está terminada. - -- Debes haber recibido _code review_ de al menos una compañera. -- Haces _test_ unitarios y, además, has testeado tu producto manualmente. -- Hiciste _tests_ de usabilidad e incorporaste el _feedback_ del usuario. -- Desplegaste tu aplicación y has etiquetado tu versión (git tag). - ---- - -#### [Historia de usuario 2] Jefe de cocina debe ver los pedidos - -Yo como jefx de cocina quiero ver los pedidos de los clientes en orden y -marcar cuáles están listos para saber qué se debe cocinar y avisar a lxs meserxs -que un pedido está listo para servirlo a un cliente. - -##### Criterios de aceptación - -- Ver los pedidos ordenados según se van haciendo. -- Marcar los pedidos que se han preparado y están listos para servirse. -- Ver el tiempo que tomó prepara el pedido desde que llegó hasta que se - marcó como completado. - -##### Definición de terminado - -- Debes haber recibido _code review_ de al menos una compañera. -- Haces _test_ unitarios y, además, has testeado tu producto manualmente. -- Hiciste _tests_ de usabilidad e incorporaste el _feedback_ del usuario. -- Desplegaste tu aplicación y has etiquetado tu versión (git tag). - ---- - -#### [Historia de usuario 3] Meserx debe ver pedidos listos para servir - -Yo como meserx quiero ver los pedidos que están preparados para entregarlos -rápidamente a los clientes que las hicieron. - -##### Criterios de aceptación - -- Ver listado de pedido listos para servir. -- Marcar pedidos que han sido entregados. - -##### Definición de terminado - -- Debes haber recibido _code review_ de al menos una compañera. -- Haces _test_ unitarios y, además, has testeado tu producto manualmente. -- Hiciste _tests_ de usabilidad e incorporaste el _feedback_ del usuario. -- Desplegaste tu aplicación y has etiquetado tu versión (git tag). -- Los datos se deben mantener íntegros, incluso después de que un pedido ha - terminado. Todo esto para poder tener estadísticas en el futuro. - ---- - -## Pistas / Tips - -### Frameworks / libraries - -- [React](https://reactjs.org/) -- [Angular](https://angular.io/) -- [Vue](https://es.vuejs.org/index.html) - -### Herramientas - -- [npm-scripts](https://docs.npmjs.com/misc/scripts) -- [Babel](https://babeljs.io/) -- [webpack](https://webpack.js.org/) - -### PWA - -- [Tu primera Progressive Web App - Google developers](https://developers.google.com/web/fundamentals/codelabs/your-first-pwapp/?hl=es) -- [Progressive Web Apps - codigofacilito.com](https://codigofacilito.com/articulos/progressive-apps) -- [offlinefirst.org](http://offlinefirst.org/) -- [Usando Service Workers - MDN](https://developer.mozilla.org/es/docs/Web/API/Service_Worker_API/Using_Service_Workers) -- [Cómo habilitar datos sin conexión - Firebase Docs](https://firebase.google.com/docs/firestore/manage-data/enable-offline?hl=es-419) - -### Serverless - -- [Qué es eso de serverless? - @PamRucinque en Medium](https://medium.com/@PamRucinque/qu%C3%A9-es-eso-de-serverless-f4f6c8949b87) -- [Qué es Serverless? | FooBar - YouTube](https://www.youtube.com/watch?v=_SYHUpLi-2U) -- [Firebase](https://firebase.google.com/) -- [Serverless Architectures - Martin Fowler](https://www.martinfowler.com/articles/serverless.html) - -### Cloud functions - -- [Cloud functions - Firebase Docs](https://firebase.google.com/docs/functions/?hl=es-419) diff --git a/firebase.json b/firebase.json new file mode 100644 index 000000000..340ed5b73 --- /dev/null +++ b/firebase.json @@ -0,0 +1,16 @@ +{ + "hosting": { + "public": "build", + "ignore": [ + "firebase.json", + "**/.*", + "**/node_modules/**" + ], + "rewrites": [ + { + "source": "**", + "destination": "/index.html" + } + ] + } +} diff --git a/img/BQ1.JPG b/img/BQ1.JPG new file mode 100644 index 000000000..aaf6e5d0b Binary files /dev/null and b/img/BQ1.JPG differ diff --git a/img/BQ3.JPG b/img/BQ3.JPG new file mode 100644 index 000000000..17a116a67 Binary files /dev/null and b/img/BQ3.JPG differ diff --git a/img/BQ4.JPG b/img/BQ4.JPG new file mode 100644 index 000000000..204d6f7e9 Binary files /dev/null and b/img/BQ4.JPG differ diff --git a/img/BQ5.JPG b/img/BQ5.JPG new file mode 100644 index 000000000..65ab5a445 Binary files /dev/null and b/img/BQ5.JPG differ diff --git a/img/BQ6.JPG b/img/BQ6.JPG new file mode 100644 index 000000000..56f9f7a91 Binary files /dev/null and b/img/BQ6.JPG differ diff --git a/img/Thumbs.db b/img/Thumbs.db new file mode 100644 index 000000000..26ab7fa87 Binary files /dev/null and b/img/Thumbs.db differ diff --git a/package.json b/package.json new file mode 100644 index 000000000..b4c2bce06 --- /dev/null +++ b/package.json @@ -0,0 +1,38 @@ +{ + "name": "burguer-queen", + "version": "0.1.0", + "private": true, + "dependencies": { + "@testing-library/jest-dom": "^4.2.4", + "@testing-library/react": "^9.5.0", + "@testing-library/user-event": "^7.2.1", + "firebase": "^7.15.5", + "node-sass": "^4.14.1", + "react": "^16.13.1", + "react-dom": "^16.13.1", + "react-router-dom": "^5.2.0", + "react-scripts": "3.4.1", + "shortid": "^2.2.15" + }, + "scripts": { + "start": "react-scripts start", + "build": "react-scripts build", + "test": "react-scripts test", + "eject": "react-scripts eject" + }, + "eslintConfig": { + "extends": "react-app" + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + } +} diff --git a/public/Thumbs.db b/public/Thumbs.db new file mode 100644 index 000000000..7c3b3823f Binary files /dev/null and b/public/Thumbs.db differ diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 000000000..bcd5dfd67 Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/index.html b/public/index.html new file mode 100644 index 000000000..5982a3991 --- /dev/null +++ b/public/index.html @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + Burguer Queen + + + + +
+
+ + + + + \ No newline at end of file diff --git a/public/logQueen.png b/public/logQueen.png new file mode 100644 index 000000000..763046880 Binary files /dev/null and b/public/logQueen.png differ diff --git a/public/logQueen192.png b/public/logQueen192.png new file mode 100644 index 000000000..15e7d5000 Binary files /dev/null and b/public/logQueen192.png differ diff --git a/public/logQueen512.png b/public/logQueen512.png new file mode 100644 index 000000000..e35b98170 Binary files /dev/null and b/public/logQueen512.png differ diff --git a/public/logo192.png b/public/logo192.png new file mode 100644 index 000000000..fc44b0a37 Binary files /dev/null and b/public/logo192.png differ diff --git a/public/logo512.png b/public/logo512.png new file mode 100644 index 000000000..a4e47a654 Binary files /dev/null and b/public/logo512.png differ diff --git a/public/manifest.json b/public/manifest.json new file mode 100644 index 000000000..95cde818b --- /dev/null +++ b/public/manifest.json @@ -0,0 +1,31 @@ +{ + "short_name": "Burguer Queen", + "name": "Burguer Queen ", + "icons": [ + { + "src": "maskable_iconQueen.png", + "sizes": "196x196", + "type": "image/png", + "purpose": "any maskable" + }, + { + "src": "logQueen.png", + "sizes": "64x64 32x32 24x24 16x16", + "type": "image/png" + }, + { + "src": "logQueen192.png", + "type": "image/png", + "sizes": "192x192" + }, + { + "src": "logQueen512.png", + "type": "image/png", + "sizes": "512x512" + } + ], + "start_url": ".", + "display": "standalone", + "theme_color": "#3824A0", + "background_color": "#190B54" +} \ No newline at end of file diff --git a/public/maskable_iconQueen.png b/public/maskable_iconQueen.png new file mode 100644 index 000000000..087e8fa0e Binary files /dev/null and b/public/maskable_iconQueen.png differ diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 000000000..e9e57dc4d --- /dev/null +++ b/public/robots.txt @@ -0,0 +1,3 @@ +# https://www.robotstxt.org/robotstxt.html +User-agent: * +Disallow: diff --git a/src/App.js b/src/App.js new file mode 100644 index 000000000..971244087 --- /dev/null +++ b/src/App.js @@ -0,0 +1,64 @@ +import React, { Fragment, useState, useEffect } from 'react'; +import { db } from './firebase/firebase-config' +import Routes from './components/Routes.js'; + +import coffeMilk from './imgs/coffeMilk.png'; +import coffe from './imgs/coffe.png'; +import sandwich from './imgs/sandwich.png'; +import juice from './imgs/juice.png'; +import simpleBurguer from './imgs/simpleBurguer.png'; +import doubleBurguer from './imgs/doubleBurguer.png'; +import frenchFries from './imgs/frenchFries.png'; +import onion from './imgs/onion.png'; +import smallWater from './imgs/smallWater.png'; +import bigWater from './imgs/bigWater.png'; +import smallSoda from './imgs/smallSoda.png'; +import bigSoda from './imgs/bigSoda.png'; + + + + +function App() { + const [breakfasts, saveBreakfast] = useState([ + { id: 1, dish: "Café con leche", img: coffeMilk, price: 7, quantity: 1 }, + { id: 2, dish: "Café americano", img: coffe, price: 5, quantity: 1 }, + { id: 3, dish: "Sandwich de jamón y queso", img: sandwich, price: 10, quantity: 1 }, + { id: 4, dish: "Jugo de frutas natural", img: juice, price: 7, quantity: 1 } + ]) + const [lunchs, saveLunch] = useState([ + { id: 5, idItem: 0, dish: "Hamburguesa simple", img: simpleBurguer, price: 10, addittions: [], quantity: 1 }, + { id: 6, idItem: 0, dish: "Hamburguesa doble", img: doubleBurguer, price: 15, addittions: [], quantity: 1 }, + { id: 7, dish: "Papas fritas", img: frenchFries, price: 5, quantity: 1 }, + { id: 8, dish: "Aros de cebolla", img: onion, price: 5, quantity: 1 }, + { id: 9, dish: "Agua 500ml", img: smallWater, price: 5, quantity: 1 }, + { id: 10, dish: "Agua 750ml", img: bigWater, price: 7, quantity: 1 }, + { id: 11, dish: "Soda 500ml", img: smallSoda, price: 7, quantity: 1 }, + { id: 12, dish: "Soda 750ml", img: bigSoda, price: 7, quantity: 1 }, + ]) + + const [order, setOrder] = useState({ + waiter: "", + client: "", + table: "", + items: [], + totalProducts: 0, + total: 0, + state: "pending" //options: ready, delivered, pending + }) + + + + return ( + + + + + ); +} + +export default App; diff --git a/src/App.test.js b/src/App.test.js new file mode 100644 index 000000000..7c3d95918 --- /dev/null +++ b/src/App.test.js @@ -0,0 +1,12 @@ +/* import React from 'react'; +import { render } from '@testing-library/react'; +import App from './App'; + + +test('renders learn react link', () => { + + const { getByText } = render(); + const linkElement = getByText(/learn react/i); + expect(linkElement).toBeInTheDocument(); +}); + */ \ No newline at end of file diff --git a/src/_tests_/Breakfasts/ItemBreakfasts.test.js b/src/_tests_/Breakfasts/ItemBreakfasts.test.js new file mode 100644 index 000000000..7391aaa9a --- /dev/null +++ b/src/_tests_/Breakfasts/ItemBreakfasts.test.js @@ -0,0 +1,27 @@ +import React from 'react'; +import { render, fireEvent } from '@testing-library/react'; +import ItemBreakfast from '../../components/Breakfasts/ItemBreakfast'; + + +it('should be render an image', () => { + const { queryByRole, debug } = render() + debug() + const image = queryByRole("img") + expect(image).toBeInTheDocument() + +}) + +it('should render dish properties', () => { + let props = { + idItem: 3, + dish: 'Café con leche', + price: 7, + } + + const { getByText, debug } = render() + debug() + const nameDish = getByText("Café con leche") + expect(nameDish).toBeInTheDocument() + +}) + diff --git a/src/_tests_/ControlTotal/ControlTotal.test.js b/src/_tests_/ControlTotal/ControlTotal.test.js new file mode 100644 index 000000000..a92cb915f --- /dev/null +++ b/src/_tests_/ControlTotal/ControlTotal.test.js @@ -0,0 +1,29 @@ +import React from 'react' +import { render } from '@testing-library/react' +import ControlTotal from '../../components/ControlTotal/ControlTotal' + + +let props = { + order: { + items: [ + { id: 1, dish: "Café con leche", price: 7, quantity: 1 }, + { id: 2, dish: "Café americano", price: 5, quantity: 1 }] + }, + setOrder: jest.fn() +} + +it('should render total products', () => { + + const { getByText, debug } = render() + debug() + const products = getByText('Productos: 2') + expect(products).toBeInTheDocument() +}) + +it('should render total price', () => { + + const { getByText, debug } = render() + debug() + const price = getByText('Total: $12.00') + expect(price).toBeInTheDocument() +}) \ No newline at end of file diff --git a/src/_tests_/Header/Header.test.js b/src/_tests_/Header/Header.test.js new file mode 100644 index 000000000..a285dd1cd --- /dev/null +++ b/src/_tests_/Header/Header.test.js @@ -0,0 +1,19 @@ +import React from 'react'; +import { render, fireEvent } from '@testing-library/react'; +import Header from '../../components/Header/Header'; + +describe("Testing of header componets", () => { + it('Title', () => { + const { getByRole, debug } = render(
); + const title = getByRole("heading", { name: /Burger/ }); + debug(); + expect(title).toBeInTheDocument(); + }) + + it('hiden modal', () => { + const { queryByRole, debug } = render(
); + const icon = queryByRole("i"); + debug(); + expect(icon).not.toBeInTheDocument(); + }) +}); \ No newline at end of file diff --git a/src/_tests_/HeaderPrincipal/HeaderPrincipal.test.js b/src/_tests_/HeaderPrincipal/HeaderPrincipal.test.js new file mode 100644 index 000000000..bee8271f3 --- /dev/null +++ b/src/_tests_/HeaderPrincipal/HeaderPrincipal.test.js @@ -0,0 +1,10 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import HeaderPrincipal from '../../components/HeaderPrincipal/HeaderPrincipal'; + +it('should render header', () => { + const { getByRole, debug } = render() + // debug() + const header = getByRole("heading", { name: /burguer/i }) + expect(header).toBeInTheDocument() +}) \ No newline at end of file diff --git a/src/_tests_/HomePage/HomePage.test.js b/src/_tests_/HomePage/HomePage.test.js new file mode 100644 index 000000000..4a4c365c8 --- /dev/null +++ b/src/_tests_/HomePage/HomePage.test.js @@ -0,0 +1,24 @@ +import React from 'react' +import { render } from '@testing-library/react' +import HomePage from '../../components/HomePage/HomePage' + +it('should render an image', () => { + const { queryByRole, debug } = render() + debug() + const img = queryByRole("img") + expect(img).toBeInTheDocument() +}) + +it('should render a kitchen button', () => { + const { getByRole, debug } = render() + debug() + const buttonKitchen = getByRole("button", { name: /Cocina/i }) + expect(buttonKitchen).toBeInTheDocument() +}) + +it('should render a waiter button', () => { + const { getByRole, debug } = render() + debug() + const buttonWaiter = getByRole("button", { name: /Mesero/i }) + expect(buttonWaiter).toBeInTheDocument() +}) \ No newline at end of file diff --git a/src/_tests_/Kitchen/Kitchen.test.js b/src/_tests_/Kitchen/Kitchen.test.js new file mode 100644 index 000000000..b584b9191 --- /dev/null +++ b/src/_tests_/Kitchen/Kitchen.test.js @@ -0,0 +1,26 @@ +import React from 'react'; +import { render, fireEvent } from '@testing-library/react'; +import Kitchen from '../../components/Kitchen/Kitchen'; + +describe('Kitchen componets testing', () => { + it('Kitchen view ', () => { + let props = { + orders: { + client: "Raul", + table: "3", + id: "7xJqehKcssw4n4SfeizS", + items: [{ + img: "/static/media/coffeMilk.d1608cd7.png", + price: 7, + quantity: 1, + dish: "Café con leche", + id: 1 + }], + state: "pending" + } + } + const { queryByText } = render(); + const array = queryByText("Café con leche"); + expect(array).toBeInTheDocument(); + }); +}); diff --git a/src/_tests_/Kitchen/Pending.test.js b/src/_tests_/Kitchen/Pending.test.js new file mode 100644 index 000000000..b85f0f15b --- /dev/null +++ b/src/_tests_/Kitchen/Pending.test.js @@ -0,0 +1,16 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import Pending from '../../components/Kitchen/State/Pending'; + +it('Delevery btn', () => { + let props = { + pendings: { + table: '6', + state: 'pending', + id: '9sQX5kVbKE00V9D9A8is', + } + } + const { queryByText } = render(); + const f = queryByText('6'); + expect(f).toBeInTheDocument() +}); \ No newline at end of file diff --git a/src/_tests_/Kitchen/Ready.test.js b/src/_tests_/Kitchen/Ready.test.js new file mode 100644 index 000000000..6bf45f449 --- /dev/null +++ b/src/_tests_/Kitchen/Ready.test.js @@ -0,0 +1,18 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import Ready from '../../components/Kitchen/State/Ready'; + +it('Delevery btn', () => { + let props = { + readys: { + date: '1594214668', + deliveryDate: '648000000', + table: '4', + state: 'ready', + id: '9sQX5kVbKE00V9D9A8is', + } + } + const { queryByText } = render(); + const f = queryByText('4'); + expect(f).toBeInTheDocument() +}); \ No newline at end of file diff --git a/src/_tests_/Lunch/ItemLunch.test.js b/src/_tests_/Lunch/ItemLunch.test.js new file mode 100644 index 000000000..c0ffdd001 --- /dev/null +++ b/src/_tests_/Lunch/ItemLunch.test.js @@ -0,0 +1,25 @@ +import React from 'react' +import { render } from '@testing-library/react' +import ItemLunch from '../../components/Lunch/ItemLunch' + + +it('should render image ', () => { + const { queryByRole, debug } = render() + //debug() + const img = queryByRole("img") + expect(img).toBeInTheDocument() +}) + +it('should render dish properties', () => { + let props = { + idItem: 5, + dish: 'Hamburguesa simple', + price: 10, + } + + const { getByText, debug } = render() + debug() + const nameDish = getByText("Hamburguesa simple") + expect(nameDish).toBeInTheDocument() + +}) \ No newline at end of file diff --git a/src/_tests_/Order/Order.test.js b/src/_tests_/Order/Order.test.js new file mode 100644 index 000000000..36406c8ca --- /dev/null +++ b/src/_tests_/Order/Order.test.js @@ -0,0 +1,92 @@ +import React from 'react' +import { render, fireEvent } from '@testing-library/react' +import Order from '../../components/Order/Order' + +describe('should render Order', () => { + let props = { + breakfasts: [{ id: 1, dish: "Café con leche", price: 7, quantity: 1 }, { id: 2, dish: "Café americano", price: 5, quantity: 1 }], + lunchs: [{ id: 5, dish: "Hamburguesa simple", price: 10, addittions: [], quantity: 1 }, { id: 6, dish: "Hamburguesa doble", price: 15, addittions: [], quantity: 1 }], + order: { + waiter: "", + client: "", + table: "", + items: [], + totalProducts: 0, + total: 0, + state: "pending" + }, + setOrder: jest.fn() + + } + it('should render a Waiters select', () => { + const { queryAllByRole, debug } = render() + //debug() + const selectWaiter = queryAllByRole("combobox") + + expect(selectWaiter) + }) + + + it('Header should send to Home ', () => { + const { getByRole, debug } = render() + //debug() + const linkHome = getByRole("link", { name: /Burguer Queen/ }) + expect(linkHome).toBeInTheDocument() + }) + + it('should render an input to client ', () => { + const { getByRole, debug } = render() + //debug() + const inputName = getByRole("textbox") + expect(inputName).toBeInTheDocument() + }) + + it('should render a btn Breakfast', () => { + const { getByRole, debug } = render() + //debug() + const btnBreakfast = getByRole("button", { name: /Desayuno/ }) + expect(btnBreakfast).toBeInTheDocument() + }) + it('should render a btn Comida', () => { + const { getByRole, debug } = render() + //debug() + const btnLunch = getByRole("button", { name: /Comida/ }) + expect(btnLunch).toBeInTheDocument() + }) + it('should render a btn Send Kitchen', () => { + const { getByRole, debug } = render() + //debug() + const btnKitchen = getByRole("button", { name: /Enviar Cocina/ }) + expect(btnKitchen).toBeInTheDocument() + }) + it('should render a btn Cancel', () => { + const { getByRole, debug } = render() + //debug() + const btnCancel = getByRole("button", { name: /Cancelar orden/ }) + expect(btnCancel).toBeInTheDocument() + }) + it('should render cafe americano', () => { + const { getByText, debug } = render() + //debug() + const cafeAmericano = getByText('Café americano') + expect(cafeAmericano).toBeInTheDocument() + }) + + it('should render Comida Menu', () => { + const { getByRole, getByText, debug } = render() + //debug() + const btnLunch = getByRole("button", { name: /Comida/ }) + fireEvent.click(btnLunch); + debug() + expect(getByText('Hamburguesa simple')).toBeInTheDocument() + }) + + it('should render Desayuno Menu', () => { + const { getByRole, getByText, debug } = render() + //debug() + const btnBreakfast = getByRole("button", { name: /Desayuno/ }) + fireEvent.click(btnBreakfast); + debug() + expect(getByText('Café con leche')).toBeInTheDocument() + }) +}) \ No newline at end of file diff --git a/src/_tests_/Summary/Summary.test.js b/src/_tests_/Summary/Summary.test.js new file mode 100644 index 000000000..a6db8141a --- /dev/null +++ b/src/_tests_/Summary/Summary.test.js @@ -0,0 +1,57 @@ +import React from 'react' +import { render, fireEvent, getByTestId } from '@testing-library/react' +import Summary from '../../components/Sumary/Summary' +import Extras from '../../components/Sumary/Extras' + + +let props = { + order: { + items: [ + { id: 1, dish: "Café con leche", price: 7, quantity: 1 }, + { id: 2, dish: "Café americano", price: 5, quantity: 1 }] + }, + setOrder: jest.fn(), + breakfasts: [ + { id: 1, dish: "Café con leche", price: 7, quantity: 1 }, + { id: 2, dish: "Café americano", price: 5, quantity: 1 }], + lunchs: [{ id: 7, dish: "Papas fritas", price: 5, quantity: 1 }, + { id: 8, dish: "Aros de cebolla", price: 5, quantity: 1 }] +} + +it('should render dish select', () => { + const { getByText, debug } = render() + //debug() + const dish = getByText("Café con leche") + expect(dish).toBeInTheDocument() +}) +it('should render price dish select', () => { + const { getByText, debug } = render() + //debug() + const price = getByText("$7") + expect(price).toBeInTheDocument() +}) + +const portalRoot = document.createElement('div') +portalRoot.setAttribute('id', 'modalAdditions') +document.body.appendChild(portalRoot) +it('should not check de input', () => { + const { getByTestId, debug } = render() + const checkbox = getByTestId("chicken") + // debug() + expect(checkbox.checked).toEqual(false) +}) + + + +/* it('should delete product', () => { + const { getAllByTestId, getByText, debug } = render() + const iconDelete = getAllByTestId('iconDelete') + //console.log(iconDelete[0]); + fireEvent.click(iconDelete[0]); + debug() + //expect(getByText('Café americano')).not.toBeInTheDocument() +}) */ + + + + diff --git a/src/components/Breakfasts/Breakfast.js b/src/components/Breakfasts/Breakfast.js new file mode 100644 index 000000000..77bbb80a9 --- /dev/null +++ b/src/components/Breakfasts/Breakfast.js @@ -0,0 +1,32 @@ +import React, { Fragment } from 'react'; +import ItemBreakfast from './ItemBreakfast.js' +import './Menus.scss'; + + +const Breakfast = ({ breakfasts, order, setOrder }) => { + + return ( + + {breakfasts.map(breakfast => ( + + < ItemBreakfast + key={breakfast.id} + idItem={breakfast.id} + img={breakfast.img} + dish={breakfast.dish} + price={breakfast.price} + breakfasts={breakfasts} + order={order} + setOrder={setOrder} + /> + + + ))} + + + + ) +} + +export default Breakfast + diff --git a/src/components/Breakfasts/ItemBreakfast.js b/src/components/Breakfasts/ItemBreakfast.js new file mode 100644 index 000000000..5c852013d --- /dev/null +++ b/src/components/Breakfasts/ItemBreakfast.js @@ -0,0 +1,40 @@ +import React from 'react' + + +const ItemBreakfast = ({ idItem, img, dish, price, breakfasts, order, setOrder }) => { + + + //Add items selected to state + const updateBreakfast = (idItem, price) => { + //console.log(idItem); + //Items selected + const productSelect = breakfasts.filter(lunch => lunch.id === idItem)[0] + console.log(productSelect); + + //Update state with items selected + setOrder({ ...order, items: [...order.items, productSelect] }) + } + + return ( +
+ {dish} { + updateBreakfast(idItem, price) + }} + > +

{dish}

+

${price}.00

+ +
+ + ) +} + + +export default ItemBreakfast \ No newline at end of file diff --git a/src/components/Breakfasts/Menus.scss b/src/components/Breakfasts/Menus.scss new file mode 100644 index 000000000..61873eb49 --- /dev/null +++ b/src/components/Breakfasts/Menus.scss @@ -0,0 +1,44 @@ +$menu-blue:#190B54; +$pink: #EB60DD; +//Menu +.container-menu{ + display: grid; + column-gap: 20px; + row-gap: 30px; + grid-template-columns: repeat(2, 250px); + grid-template-rows: repeat(3,245px); + height: 100%; + overflow: scroll; + + + .dish{ + height: 100%; + background-color: $menu-blue; + border-style: solid; + border-color: #EB60DD; + border-width: 5px; + border-radius: 20px; + text-align: center; + + } + + .img-menu{ + margin: 8px; + width: 50%; + } + + p{ + margin: 0; + font-size: 25px; + } + + .container-menu::-webkit-scrollbar { + width: 15px; + } + + .container-menu::-webkit-scrollbar-thumb { + background: $pink; + border-radius: 8px; + } + +} \ No newline at end of file diff --git a/src/components/ControlTotal/ControlTotal.js b/src/components/ControlTotal/ControlTotal.js new file mode 100644 index 000000000..0dc452118 --- /dev/null +++ b/src/components/ControlTotal/ControlTotal.js @@ -0,0 +1,43 @@ +import React, { Fragment } from 'react'; +import './ControlTotal.scss'; + +const ControlTotal = ({ order, setOrder }) => { + + //Price and quantity from product, include the increase in item quantity + const priceProducts = order.items.map(product => product.price) + //console.log(priceProducts); + const quantityProducts = order.items.map(product => product.quantity) + //console.log(quantityProducts); + + //Sum of prices in the array + let sumPrice = priceProducts.reduce((a, b) => a + b, 0) + //console.log(sumPrice); + + //Sum of quantity of products in the array + let sumQuantity = quantityProducts.reduce((a, b) => a + b, 0) + //console.log(sumQuantity); + + //Add as properties of state + if (sumPrice !== 0) { + order.total = sumPrice + order.totalProducts = sumQuantity + //setOrder({ ...order, total: sum }) + } + + + + return ( + + +
+

Productos: {sumQuantity}

+
+

Total: ${sumPrice}.00

+
+ +
+ + ) +} + +export default ControlTotal \ No newline at end of file diff --git a/src/components/ControlTotal/ControlTotal.scss b/src/components/ControlTotal/ControlTotal.scss new file mode 100644 index 000000000..d347c5c1e --- /dev/null +++ b/src/components/ControlTotal/ControlTotal.scss @@ -0,0 +1,17 @@ + + //Control Total + .total-order{ + display: flex; + justify-content: flex-end; + margin-right: 25px; + + .total{ + margin-right: 40px; + margin-left: 50px; + p{ + font-size: 30px; + } + } + + +} \ No newline at end of file diff --git a/src/components/Header/Header.js b/src/components/Header/Header.js new file mode 100644 index 000000000..915a7fb41 --- /dev/null +++ b/src/components/Header/Header.js @@ -0,0 +1,41 @@ +import React, { useState } from 'react'; +import Modal from '../Kitchen/Modal/Modal'; +import { Link } from "react-router-dom"; + +const Header = () => { + const [listModal, updateModal] = useState(false); + const showModal = (m) => { + if (m === 'm') { + updateModal(true); + return + } + updateModal(false) + } + return ( +
+
+ +

+ + Burguer Queen +

+ +
+
+ + showModal('m')} + > + + {listModal + ? + ( updateModal(false)} + />) + : null + } +
+
+ ) +} +export default Header; diff --git a/src/components/Header/_Header.scss b/src/components/Header/_Header.scss new file mode 100644 index 000000000..5aefb589d --- /dev/null +++ b/src/components/Header/_Header.scss @@ -0,0 +1,15 @@ + +//HEADER +$font-header: 'Orbitron', sans-serif; +$width-header : 100%; +$height-header: 85px; +$font-size-header : 80px; +$white: #FDFFFC; +$color-header: #170849; +$position-header: absolute; +$top-header: 0px; +$left-header: 0px; +$size-header: 48px; +$line-header: 85px; +$font-bold: bold; + diff --git a/src/components/HeaderPrincipal/HeaderPrincipal.js b/src/components/HeaderPrincipal/HeaderPrincipal.js new file mode 100644 index 000000000..dc2f1c300 --- /dev/null +++ b/src/components/HeaderPrincipal/HeaderPrincipal.js @@ -0,0 +1,17 @@ +import React from 'react' +import './HeaderPrincipal.scss'; + + +const HeaderPrincipal = () => { + + return ( + +
+

Burguer Queen

+
+ ) +} + +export default HeaderPrincipal + + diff --git a/src/components/HeaderPrincipal/HeaderPrincipal.scss b/src/components/HeaderPrincipal/HeaderPrincipal.scss new file mode 100644 index 000000000..09e681ef5 --- /dev/null +++ b/src/components/HeaderPrincipal/HeaderPrincipal.scss @@ -0,0 +1,28 @@ +//Header +$general-font: 'Nunito', sans-serif; +$font-header: 'Orbitron', sans-serif; +$width-header : 100%; +$height-header: 120px; +$font-size-header : 40px; +$white: #FDFFFC; +$color-header: #3824A0; + + +.header-principal { + width: $width-header; + height: $height-header; + padding-top: 20px; + background-color: $color-header; + font-family: $font-header; + font-size: $font-size-header; + color: $white; + text-align: center; + + h1{ + margin-top: 0; + margin-bottom: 0; + + } + + +} \ No newline at end of file diff --git a/src/components/HomePage/HomePage.js b/src/components/HomePage/HomePage.js new file mode 100644 index 000000000..7009c6651 --- /dev/null +++ b/src/components/HomePage/HomePage.js @@ -0,0 +1,45 @@ +import React, { Fragment } from 'react' +import { Link, BrowserRouter } from "react-router-dom"; +import HeaderPrincipal from '../HeaderPrincipal/HeaderPrincipal' +import './HomePage.scss'; +import Logo from '../../imgs/logQueen.png'; + + +const HomePage = () => { + + return ( + // + + +
+
+ Burguer Queen +
+ + +
+ {/* + + */} + + + + + + + +
+ + +
+ +
+ //
+ ) +} + +export default HomePage \ No newline at end of file diff --git a/src/components/HomePage/HomePage.scss b/src/components/HomePage/HomePage.scss new file mode 100644 index 000000000..b22836ac1 --- /dev/null +++ b/src/components/HomePage/HomePage.scss @@ -0,0 +1,68 @@ +$general-font: 'Heebo', sans-serif; +$color-body: #170B48; +$white: #FDFFFC; + +body{ + background-color: $color-body ; +} + +.container-home{ + display: grid; + grid-template-rows: 80%; + row-gap: 30px; +} +.img-home{ + margin-top: 40px; + margin-bottom: 0; + display: flex; + justify-content: center; + + .logo{ + width: 512px; + height: 511px; + } +} + +//Btns Start +$btn-radius: 30px; +$pink: #EB60DD; + +$btn-heigth: 80px; +$font-size-btn: 40px; +$margin-btn: 10px; + +@mixin btn { + border-style: solid; + border-width: 7px; + font-family: $general-font; + color: $white; + margin: $margin-btn; + height: $btn-heigth; + width: 75%; + border-radius: $btn-radius; + font-size: $font-size-btn; + border-color: $pink; + background-color: $color-body; +} + +.btns-home{ + margin-top: 20px; + padding-right: 20px; + display: flex; + justify-content: center; + + + + .btn-view{ + @include btn; + } + + + a{ + width: 30%; + display: flex; + justify-content: center; + text-decoration: inherit; + } +} + diff --git a/src/components/Kitchen/Modal/Modal.js b/src/components/Kitchen/Modal/Modal.js new file mode 100644 index 000000000..c0b56ea57 --- /dev/null +++ b/src/components/Kitchen/Modal/Modal.js @@ -0,0 +1,71 @@ +import React, { useState, useEffect } from 'react'; +import ReactDOM from 'react-dom'; +import Pending from '../State/Pending'; +import Ready from '../State/Ready'; +import { db } from '../../../firebase/firebase-config'; + + +const Modal = ({ onClose }) => { + //Ejemplo de ordern + const [pending, changePending] = useState([]); + useEffect(() => { + const goPending = db.collection('orders').where('state', '==', 'pending').orderBy('date', 'desc'); + return goPending.onSnapshot(snapshotPending => { + const pendingData = [] + snapshotPending.forEach(doc => pendingData.push({ ...doc.data(), id: doc.id })); + changePending(pendingData); + }); + }, []); + const [ready, changeReady] = useState([]); + useEffect(() => { + const goReady = db.collection('orders').where('state', '==', 'ready').orderBy('date', 'desc'); + return goReady.onSnapshot(snapshotReady => { + const readyData = [] + snapshotReady.forEach(doc => readyData.push({ ...doc.data(), id: doc.id })); + changeReady(readyData); + }); + }, []); + + const done = ( +
+
+
+ +

+
+
+
No. Mesa
+
Status
+
+
+
+ {pending.map((pendings) => ( + + ) + ) + } + {ready.map((readys) => ( + + ) + ) + } +
+
+ +
+ + ) + return ReactDOM.createPortal(done, document.querySelector("#modal-root")) +} + +export default Modal; \ No newline at end of file diff --git a/src/components/Kitchen/Modal/_Modal.scss b/src/components/Kitchen/Modal/_Modal.scss new file mode 100644 index 000000000..0bf15caed --- /dev/null +++ b/src/components/Kitchen/Modal/_Modal.scss @@ -0,0 +1,21 @@ +$modal-trasparent : transparent; +$modal-fixed: fixed; +$modal-top: 0px; +$modal-right: 0px; +$modal-bottom:0px; +$modal-left: 0px; + +$modal-width: 600px; +$modal-padding: 10px 20px; +$modal-margin: 10% auto; +$modal-relative: relative; +$modal-height: auto; +$modal-overflow: auto; + +$color-gray : #aaa; +$line-height: 50px; +$font-size-c: 30px; +$width-c: 70px; +$text-decoration: none; +$absolute: absolute; +$color-black: black; \ No newline at end of file diff --git a/src/components/Kitchen/Orders/DeliveredOrder.js b/src/components/Kitchen/Orders/DeliveredOrder.js new file mode 100644 index 000000000..69afa177f --- /dev/null +++ b/src/components/Kitchen/Orders/DeliveredOrder.js @@ -0,0 +1,25 @@ +import React from 'react'; +import Kitchen from './Kitchen'; + +const DeliveredOrder = ({deliveredOrder, saveDeliveryOrder}) => { + + return( +
+ { deliveredOrder.length != 0 + ? + deliveredOrder.map(orders =>( + + ) + ) + : + null + } +
+ ) +} + + +export default DeliveredOrder; \ No newline at end of file diff --git a/src/components/Kitchen/Orders/GeneralKitchen.js b/src/components/Kitchen/Orders/GeneralKitchen.js new file mode 100644 index 000000000..bdee050d6 --- /dev/null +++ b/src/components/Kitchen/Orders/GeneralKitchen.js @@ -0,0 +1,47 @@ +import React, { useState, useEffect } from 'react'; +import Kitchen from './Kitchen'; +import DeliveredOrder from './DeliveredOrder'; +import { db } from '../../../firebase/firebase-config'; + +const GeneralKitchen = () => { + + const [order, listOrder] = useState([]); + const [deliveredOrder, saveDeliveryOrder] = useState([]); + + useEffect(() => { + const d = db.collection('orders').where('state', '==', 'pending'); + return d.onSnapshot(snapshot => { + const spellsData = [] + snapshot.forEach(doc => spellsData.push({ ...doc.data(), id: doc.id })); + listOrder(spellsData); + }); + }, []); + + return ( +
+
+ {order.map((orders) => ( + + ) + ) + } +
+ + + +
+ + ); +} + +export default GeneralKitchen; \ No newline at end of file diff --git a/src/components/Kitchen/Orders/Kitchen.js b/src/components/Kitchen/Orders/Kitchen.js new file mode 100644 index 000000000..1df9ef23a --- /dev/null +++ b/src/components/Kitchen/Orders/Kitchen.js @@ -0,0 +1,79 @@ +import React, { useState } from "react"; +import { onChangeStateReady, onChangeStateCancel } from '../../../firebase/firebase-config';; +//import +const Kitchen = ({ orders, order, deliveredOrder, saveDeliveryOrder, listOrder }) => { + const { client, table, id, items, state } = orders + const deliveredOrders = (id) => { + const ordersf = order.filter(orders => orders.id === id)[0]; + saveDeliveryOrder([ + ...deliveredOrder, + orders + ] + ); + deleteOrderslist(id); + onChangeStateReady(id); + } + + const deleteOrderslist = (id) => { + const newOrder = order.filter(orders => orders.id !== id); + listOrder( + newOrder + ); + } + const deleteOrders = (id) => { + const newOrder = order.filter(orders => orders.id !== id); + listOrder( + newOrder + ); + onChangeStateCancel(id); + } + return ( +
+
+

Cliente: {client}

+

Mesa: {table}

+ {items.map((item, index) => { + + return ( +
+
+
+ {item.dish} +
+ {item.addittions}
+
+
+
{item.quantity}
+
+
+ + ) + })} + {order + ? +
+
+ +
+
+ +
+
+
+ : + null + } +
+

+
+ ); +} + +export default Kitchen; \ No newline at end of file diff --git a/src/components/Kitchen/Orders/_Kitchen.scss b/src/components/Kitchen/Orders/_Kitchen.scss new file mode 100644 index 000000000..e7b241403 --- /dev/null +++ b/src/components/Kitchen/Orders/_Kitchen.scss @@ -0,0 +1,38 @@ +$display-kitchen: flex; +$direction-kitchen: row; +$justify-kitchen: flex-start; +$wrap-kitchen: wrap; + +$absolute: absolute; +$card-width: 70%; +$card-height: auto; +$card-top: 227px; +$background-active: #3824A0 ; +$background-inactive: #AEA1F4; +$card-border: 40px; +$bordercolor: 5px solid #10ABE0; +$list-sourcer: 100%; +$border-radius: 40px; +$font-size-card: 30px; +$color-inactive: #726B6B;; +$margin-container-list: 0px; +$item-padding:10px; +$item-size: 20px; + +$item1-width: 70%; +$item2-width: 20%; +$item3-width: 50%; +$button-radius: 20px; +$card-padding: 40px; + +/** Maquetado de Ordernes Entregagas*/ +$right: 0px; +$top-delivery: 120px; +$pfixed: fixed; + +$button-width: 80%; + +$spa-size: 25px; +$cincuenta-pixeles: 50px; +$cero-pixeles: 0px; +$trenta-cinco:40px; \ No newline at end of file diff --git a/src/components/Kitchen/State/Pending.js b/src/components/Kitchen/State/Pending.js new file mode 100644 index 000000000..94fa44ebd --- /dev/null +++ b/src/components/Kitchen/State/Pending.js @@ -0,0 +1,39 @@ +import React from 'react'; +import { onChangeStateCancel } from '../../../firebase/firebase-config';; + +const Pending = ({ pendings, pending, changePending }) => { + + const { table, state, id } = pendings + const deletList = (id) => { + const newPending = pending.filter(pendings => pendings.id !== id); + changePending(newPending); + //console.log(id); + onChangeStateCancel(id); + + } + return ( +
+
+
+
+
+ {table} +
+
+

+ {state == 'pending' ? 'Pendiente' : null} +

+
+ +
+
+ ) +} +export default Pending; \ No newline at end of file diff --git a/src/components/Kitchen/State/Pendingred.js b/src/components/Kitchen/State/Pendingred.js new file mode 100644 index 000000000..6d68e3f58 --- /dev/null +++ b/src/components/Kitchen/State/Pendingred.js @@ -0,0 +1,46 @@ +import React from 'react'; +import { db } from '../../../firebase/firebase-config'; + +const Pending = ({ pendings, pending, changePending }) => { + + const { table, state, id } = pendings + const deletList = (id) => { + const newPending = pending.filter(pendings => pendings.id !== id); + changePending(newPending); + //console.log(id); + let onchangeState = db.collection("orders").doc(id); + onchangeState.update({ + "state": "cancel" + }).then(function () { + //alert("Registro cancelado exitosamente"); + + }).catch(function (error) { + console.error("Error updating document: ", error); + }); + } + return ( +
+
+
+
+
+ {table} +
+
+

+ {state == 'pending' ? 'Pendiente' : null} +

+
+ +
+
+ ) +} +export default Pending; \ No newline at end of file diff --git a/src/components/Kitchen/State/Ready.js b/src/components/Kitchen/State/Ready.js new file mode 100644 index 000000000..5390254a1 --- /dev/null +++ b/src/components/Kitchen/State/Ready.js @@ -0,0 +1,39 @@ +import React from 'react'; +import { ordersSetDelivered } from '../../../firebase/firebase-config';; + + +const Ready = ({ readys, ready, changeReady }) => { + + const { date, deliveryDate, table, state, id } = readys + + const starTime = date; + const endTime = deliveryDate; + let timeDifference = (endTime) - (starTime); + let min = Math.floor(timeDifference / 60); + const Entregado = (i) => { + const newDelivered = ready.filter(read => read.id !== id); + changeReady(newDelivered); + ordersSetDelivered(id); + } + return ( +
+
+
+ {min} min +
+
+ {table} +
+
+

+ {state == 'ready' ? 'Listo' : null} +

+
+
+ Entregado(id)}> +
+
+
+ ) +} +export default Ready; \ No newline at end of file diff --git a/src/components/Kitchen/State/Readyred.js b/src/components/Kitchen/State/Readyred.js new file mode 100644 index 000000000..75d1a7986 --- /dev/null +++ b/src/components/Kitchen/State/Readyred.js @@ -0,0 +1,47 @@ +import React from 'react'; +import { db } from '../../../firebase/firebase-config'; + + +const Ready = ({ readys, ready, changeOrderReady }) => { + const { date, deliveryDate, table, state, id } = readys + const starTime = date; + const endTime = deliveryDate; + let timeDifference = (endTime) - (starTime); + let min = Math.floor(timeDifference / 60); + //let seg = (min * 60); + //let segfinish = (seg / 60); + const Entregado = (i) => { + console.log(id); + let onchangeState = db.collection("orders").doc(id); + onchangeState.update({ + "state": "delivered" + }).then(function () { + //alert("Registro cancelado exitosamente"); + + }).catch(function (error) { + console.error("Error updating document: ", error); + }); + } + return ( +
+
+
+ {min} min +
+
+ {table} +
+
+

+ {state == 'ready' ? 'Listo' : null} +

+
+
+ {/* */} + Entregado(id)}> +
+
+
+ ) +} +export default Ready; \ No newline at end of file diff --git a/src/components/Kitchen/State/_ListOrder.scss b/src/components/Kitchen/State/_ListOrder.scss new file mode 100644 index 000000000..43ff3b399 --- /dev/null +++ b/src/components/Kitchen/State/_ListOrder.scss @@ -0,0 +1,14 @@ +$list-padding: 10px; +$width-title:150px; +$height-title: 48px; + +$width-status-list: 150; +$size-title: 20px; + +$container-list-width: 70%; +$continer-list-edit-width: 80%; +$azul-ligh: #10ABE0; +$diez-pixeles: 10px; +$veinte-pixeles: 20px; +$transparente: transparent; +$auto: auto; diff --git a/src/components/Lunch/ItemLunch.js b/src/components/Lunch/ItemLunch.js new file mode 100644 index 000000000..6e90f67f1 --- /dev/null +++ b/src/components/Lunch/ItemLunch.js @@ -0,0 +1,43 @@ +import React from 'react' +import shortid from 'shortid' + +const ItemLunch = ({ idItem, img, dish, price, lunchs, order, setOrder }) => { + + const updateLunchs = (idItem, price) => { + //Items selected + const productSelect = lunchs.filter(lunch => lunch.id === idItem)[0] + + //In case of burguer add unique id to add additions + if (productSelect.dish === 'Hamburguesa simple' || productSelect.dish === 'Hamburguesa doble') { + productSelect.idItem = shortid.generate() + + } + + //Update state with items, sum price + setOrder({ ...order, items: [...order.items, productSelect] }) + + } + + return ( + +
+ {dish} { + updateLunchs(idItem, price) + + }} + > +

{dish}

+

${price}.00

+
+ ) +} + + +export default ItemLunch \ No newline at end of file diff --git a/src/components/Lunch/Lunch.js b/src/components/Lunch/Lunch.js new file mode 100644 index 000000000..1931573e4 --- /dev/null +++ b/src/components/Lunch/Lunch.js @@ -0,0 +1,31 @@ +import React, { Fragment } from 'react'; +import ItemLunch from './ItemLunch.js' +import './Menus.scss'; + +const Lunch = ({ lunchs, order, setOrder }) => { + + + return ( + + {lunchs.map(lunch => ( + + + ))} + + + + ) +} + + +export default Lunch + diff --git a/src/components/Lunch/Menus.scss b/src/components/Lunch/Menus.scss new file mode 100644 index 000000000..801fafecb --- /dev/null +++ b/src/components/Lunch/Menus.scss @@ -0,0 +1,43 @@ +$menu-blue:#190B54; +$pink: #EB60DD; +//Menu +.container-menu{ + display: grid; + column-gap: 20px; + row-gap: 30px; + grid-template-columns: repeat(2, 250px); + grid-template-rows: repeat(3,245px); + height: 100%; + overflow: scroll; + + + .dish{ + height: 100%; + background-color: $menu-blue; + border-style: solid; + border-color: #EB60DD; + border-width: 5px; + border-radius: 20px; + text-align: center; + + } + + .img-menu{ + margin: 8px; + width: 50%; + } + + p{ + margin: 0; + font-size: 25px; + } + + .container-menu::-webkit-scrollbar { + width: 15px; + } + + .container-menu::-webkit-scrollbar-thumb { + background: $pink; + border-radius: 8px; + } +} \ No newline at end of file diff --git a/src/components/Order/Order.js b/src/components/Order/Order.js new file mode 100644 index 000000000..8129fb34d --- /dev/null +++ b/src/components/Order/Order.js @@ -0,0 +1,256 @@ +import React, { Fragment, useState } from 'react'; +import { saveOrderBD } from '../../firebase/firebase-config' +import { Link, BrowserRouter } from "react-router-dom"; + +import Summary from '../Sumary/Summary.js' +import Breakfast from '../Breakfasts/Breakfast.js' +import Lunch from '../Lunch/Lunch.js' +import ControlTotal from '../ControlTotal/ControlTotal.js' +import Modal from '../Kitchen/Modal/Modal'; +import Extras from '../Sumary/Extras.js' +import './Order.scss'; + +const Order = ({ saveOrders, orders, breakfasts, lunchs, order, setOrder }) => { + + //Show error in case the fields are not completed (selects,name) + const [error, setError] = useState(false) + //Destructuring state order + const { waiter, client, table, items, totalProducts, total } = order + + //Start tru the first time that the application start, and show breakfast menu + const [showMenu, setMenu] = useState(true) + const [listModal, updateModal] = useState(false); + + + //Func that change state showMenu in click + const changeMenu = (e) => { + let btnLunch = document.querySelector('#btnLunch') + let btnBreakfast = document.querySelector('#btnBreakfast') + if (e.target.name === 'lunch') { + btnBreakfast.classList.add('btn-no-select') + btnBreakfast.classList.remove('btn-select') + btnLunch.classList.add('btn-select') + btnLunch.classList.remove('btn-no-select') + setMenu(false) + return + } + setMenu(true) + btnLunch.classList.add('btn-no-select') + btnLunch.classList.remove('btn-select') + btnBreakfast.classList.add('btn-select') + btnBreakfast.classList.remove('btn-no-select') + } + + //Read elements and put in state + const updateStateOrder = (e) => { + //update state + setOrder({ + //copy of state + ...order, + [e.target.name]: e.target.value + }); + + } + + + const formValidation = () => { + if (waiter === "" || client === "" || table === "") { + setError(true) + return + } + setError(false) + order.date = new Date() + + saveOrderBD(order) + + //Clean inputs + setOrder({ + waiter: "", + client: "", + table: "", + items: [], + totalProducts: 0, + total: 0, + state: "pending" + }) + + } + + const cancelOrder = () => { + setOrder({ + waiter: "", + client: "", + table: "", + items: [], + totalProducts: 0, + total: 0, + state: "pending" + }) + } + + + const showModal = (m) => { + if (m === 'm') { + updateModal(true); + return + } + updateModal(false) + } + + return ( + // + + +
+ + +

Burguer Queen

+ + + showModal('m')} + > +
+ + + +
+ + {/* input client´s name */} +
+ +
+ + {/* Select tables */} +
+
+ +
+
+

Resumen:

+
+
+ + {/* Btns kind of menu */} +
+
+ + +
+ + {/* Titles table summary */} +
+

Platillo

+

Cantidad

+

Precio

+

+
+
+ + {/* Container Menu */} + {/* if, that show the menu depends the click */} +
+
+ {showMenu ? ( + + ) : + ( + + )} +
+ + +
+ + + {/* Show error if the form is empty when click send the kitchen */} + {error ?

Todos los campos son obligatorios

: null} + + + {/* Show total of products, total price, and btns to send to the kitchen */} + + +
+ + +
+ + {listModal + ? + ( updateModal(false)} + />) + : null + } + {/* container-view-->*/}
+
+ + ) +} + +export default Order \ No newline at end of file diff --git a/src/components/Order/Order.scss b/src/components/Order/Order.scss new file mode 100644 index 000000000..d3a40d59a --- /dev/null +++ b/src/components/Order/Order.scss @@ -0,0 +1,274 @@ +//Header +$general-font: 'Heebo', sans-serif; +$font-header: 'Orbitron', sans-serif; +$width-header : 100%; +$height-header: 85px; +$font-size-header : 80px; +$white: #FDFFFC; +$color-header: #170B48; + +//View Title +$font-title: 30px; +$light-blue : #10ABE0; +$menu-blue:#DFF8EB; + +//Btns + +$blue : #3824A0; +$orange : #FFB400; +$green: #7EE166; +$red: #FC6471; +$btn-heigth: 70px; +$font-size-btn: 30px; +$margin-btn: 30px; +$btn-radius: 20px; + +@mixin select { + font-size: 30px; + height: 50px; + background-color: $color-header; + border-color: $blue; + border-radius: 15px; + border-width: 5px; + color: $white; +} +@mixin btn { + border-style: solid; + border-color: $blue; + background-color: $blue; + font-family: $general-font; + margin: $margin-btn; + height: $btn-heigth; + width: 25%; + border-radius: $btn-radius; + font-size: $font-size-btn; + color: $white; +} + +@mixin btn-cancel { + border-style: solid; + border-radius: $btn-radius; + border-width: 7px; + font-family: $general-font; + color: $white; + margin: $margin-btn; + height: $btn-heigth; + width: 20%; + font-size: $font-size-btn; + background-color: $color-header; +} + +body{ + margin: 0px; + font-family: $general-font; + color: $white; +} + + +.header-order { + padding-top: 40px; + display: grid; + grid-template-columns: 20% 60% 20%; + grid-template-rows: 85px; + justify-items: center; + width: $width-header; + height: $height-header; + background-color: $color-header; + font-family:$font-header; + font-style: normal; + font-weight: bold; + font-size: $font-size-header; + color: $white; + a{ + text-decoration: none; + + p{ + margin-top: 0; + color: $white; + } + } + + select{ + @include select; + width: 60%; + align-self: center; + + } + i{ + align-self: end; + color: #EB60DD; + font-size: 50px; + } +} + + + +.error-form{ + border-style: solid; + border-color: $red; + text-align: center; + font-size: 20px; + color: $red; +} + +.container-view{ + margin-top: 40px; + margin-left: 50px; + margin-right: 50px; +//Selection table, client name + .container-client{ + margin-bottom: 25px; + font-size: 25px; + + input{ + border-style: solid; + border-color: $blue; + border-width: 5px; + border-radius: 15px; + background-color: $color-header; + width: 20%; + height: 35px; + font-size: 30px; + color: $white; + + + } + } + + .container-tables-summary{ + height: 90px; + display: flex; + justify-content: space-between; + margin-right: 70px; + .container-tables{ + margin-bottom: 25px; + margin-bottom: 25px; + font-size: 25px; + + select{ + @include select; + width: 100%; + } + } + + .title-summary{ + display: flex; + width: 46%; + justify-content: center; + } + p{ + margin: 0; + font-size: 30px; + } + + } + + + //Btns menu + + .container-btns-title{ + height: 80px; + display: flex; + align-items: flex-end; + + .container-btns-menu{ + width: 600px; + margin-right: 5px; + display: flex; + justify-content: center; + + .btn-breakfast{ + @include btn; + } + + .btn-lunch{ + @include btn; + } + + .btn-select{ + border-style: solid; + border-color: #EB60DD; + border-width: 08px; + } + .btn-no-select{ + background-color: #9987F2; + } + + } + + + .container-titles-summary{ + /* border-color: $light-blue $light-blue transparent $light-blue; + border-style: solid; + border-width: 7px; + border-radius: 20px; */ + padding: 15px 15px 0px 15px; + display: flex; + width: 46%; + height: 50px; + display: grid; + grid-template-columns: 1.8fr 0.8fr 0.8fr 0.3fr; + + + .title-summary{ + display: grid; + justify-items: center; + align-items: center; + grid-template-rows: 50px; + width: 100%; + height: 50px; + background-color: $light-blue; + font-size: 25px; + color: black; + } + .title-dish{ + border-radius: 20px 0px 0px 20px; + } + .title-empty{ + border-radius: 0px 20px 20px 0px; + } + } + + + } + + + .container-btns-total{ + display: flex; + justify-content: flex-end; + margin-right: 25px; + + .btn-send-kitchen{ + @include btn-cancel; + border-color: $green; + + } + + .btn-cancel-order{ + @include btn-cancel; + border-color: $red; + + + } + } + + @media (min-width:1500px) { + .container-titles-summary{ + /* border-color: $light-blue $light-blue transparent $light-blue; + border-style: solid; + border-width: 7px; + border-radius: 20px; */ + padding: 15px 15px 0px 15px; + display: flex; + width: 46%; + height: 50px; + display: grid; + grid-template-columns: 1.8fr 0.8fr 0.8fr 0.3fr; + margin-left: 200px; + } + } + +} + + + diff --git a/src/components/Routes.js b/src/components/Routes.js new file mode 100644 index 000000000..31cd9c641 --- /dev/null +++ b/src/components/Routes.js @@ -0,0 +1,34 @@ +import React from 'react' +import { Switch, Route } from "react-router-dom"; +import Order from './Order/Order'; +import GeneralKitchen from './Kitchen/Orders/GeneralKitchen'; +import Header from './Header/Header'; +import HomePage from './HomePage/HomePage'; +import '../styles/Styles.scss'; + +const Routes = ({ breakfasts, lunchs, order, setOrder }) => { + + return ( + + + + + + +
+ + + + + + + + ) +} + +export default Routes \ No newline at end of file diff --git a/src/components/Sumary/AddQuantity.js b/src/components/Sumary/AddQuantity.js new file mode 100644 index 000000000..52ab9e88b --- /dev/null +++ b/src/components/Sumary/AddQuantity.js @@ -0,0 +1,57 @@ +import React from 'react' + + +const AddQuantity = ({ idItem, dish, order, breakfasts, lunchs, setOrder }) => { + + + const addQuantity = (id) => { + //Search item´s index who add quantity within item´s array con su id + const indexItem = order.items.findIndex(elem => elem.id === id) + + if (id < 5) { + //We filter the price of item´s breakfast with its id + const breakfastsItem = breakfasts.filter(breakfast => breakfast.id === id)[0] + //We access to properties of item and add the new values to quantity y price + let newQuantity = [...order.items] + newQuantity[indexItem] = { ...newQuantity[indexItem], quantity: parseInt(order.items[indexItem].quantity + 1), price: order.items[indexItem].price + breakfastsItem.price } + //console.log(newQuantity); + + //Update the state of item who add quantity + setOrder({ ...order, items: newQuantity }) + return + } + if (id >= 5) { + //We filter the price of item´s breakfast with its id + const lunchsItem = lunchs.filter(lunch => lunch.id === id)[0] + //We access to properties of item and add the new values to quantity y price + let newQuantity = [...order.items] + newQuantity[indexItem] = { ...newQuantity[indexItem], quantity: parseInt(order.items[indexItem].quantity + 1), price: order.items[indexItem].price + lunchsItem.price } + + //Update the state of item who add quantity + setOrder({ ...order, items: newQuantity }) + } + if (id >= 5 && dish === 'Hamburguesa doble' || id >= 5 && dish === 'Hamburguesa simple') { + + const lunchsItem = lunchs.filter(lunch => lunch.id === id)[0] + + let newQuantity = [...order.items] + newQuantity[indexItem] = { ...newQuantity[indexItem], quantity: parseInt(order.items[indexItem].quantity + 1), price: order.items[indexItem].price + (lunchsItem.price) } + + setOrder({ ...order, items: newQuantity }) + } + } + + + return ( + + { + addQuantity(idItem) + + }} + > + ) +} + + +export default AddQuantity \ No newline at end of file diff --git a/src/components/Sumary/Decrease.js b/src/components/Sumary/Decrease.js new file mode 100644 index 000000000..753062f0b --- /dev/null +++ b/src/components/Sumary/Decrease.js @@ -0,0 +1,60 @@ +import React from 'react' + + +const Decrease = ({ idItem, dish, order, breakfasts, lunchs, setOrder }) => { + + + const decreaseQuantity = (id) => { + //console.log(id); + + //Search item´s index who sum whithin item´s array with it´s id + const indexItem = order.items.findIndex(elem => elem.id === id) + + + if (id < 5) { + //We filter the price of item with its id + const breakfastsItem = breakfasts.filter(ind => ind.id === id)[0] + + //We access to properties of item and add the new values to quantity y price + let newQuantity = [...order.items] + newQuantity[indexItem] = { ...newQuantity[indexItem], quantity: parseInt(order.items[indexItem].quantity - 1), price: order.items[indexItem].price - breakfastsItem.price } + + //Update the state of item to added elements + setOrder({ ...order, items: newQuantity }) + return + } + if (id >= 5) { + //We filter the price of item´s breakfast with its id + const lunchsItem = lunchs.filter(lunch => lunch.id === id)[0] + + //We access to properties of item and add the new values to quantity y price + let newQuantity = [...order.items] + newQuantity[indexItem] = { ...newQuantity[indexItem], quantity: parseInt(order.items[indexItem].quantity - 1), price: order.items[indexItem].price - lunchsItem.price } + + //Update the state of item who add quantity + setOrder({ ...order, items: newQuantity }) + } + if (id >= 5 && dish === 'Hamburguesa doble' || id >= 5 && dish === 'Hamburguesa simple') { + + const lunchsItem = lunchs.filter(lunch => lunch.id === id)[0] + + let newQuantity = [...order.items] + newQuantity[indexItem] = { ...newQuantity[indexItem], quantity: parseInt(order.items[indexItem].quantity - 1), price: order.items[indexItem].price - (lunchsItem.price) } + + + setOrder({ ...order, items: newQuantity }) + } + } + + + return ( + + decreaseQuantity(idItem) + + } + > + ) +} + +export default Decrease \ No newline at end of file diff --git a/src/components/Sumary/Delete.js b/src/components/Sumary/Delete.js new file mode 100644 index 000000000..52f560c75 --- /dev/null +++ b/src/components/Sumary/Delete.js @@ -0,0 +1,26 @@ +import React from 'react' + + +const Delete = ({ idItem, order, setOrder }) => { + + const removeProductSummary = (id) => { + + + //Array with items within add the item who click delete + const products = order.items.filter(product => product.id !== id) + + + //Update state with the item selected to delete + setOrder({ ...order, items: [products][0] }) + + } + + return ( + + removeProductSummary(idItem)} > + ) +} + +export default Delete \ No newline at end of file diff --git a/src/components/Sumary/Extras.js b/src/components/Sumary/Extras.js new file mode 100644 index 000000000..ad717949d --- /dev/null +++ b/src/components/Sumary/Extras.js @@ -0,0 +1,156 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; + +const Extras = ({ onClose, order, setOrder, idItem }) => { + + const saveChecks = (e) => { + console.log(idItem); + + //Additions(chicken,meat,egg,etc) + let addittion = e.target.value + //Return true if checkbox is selected + let targetChecked = e.target.checked + //let check = document.querySelector(`#${addittion}`).checked + + //Found itme´s index in state order + const indexItem = order.items.findIndex(elem => elem.idItem === idItem) + console.log(indexItem); + //Access to property addittions of item + let newAddittion = [...order.items] + //We do a copy of addittions of item with its index in the array order.items and add the new addition + newAddittion[indexItem] = { ...newAddittion[indexItem], addittions: [...order.items[indexItem].addittions, addittion] } + + //Condition if check = true and if is different of egg and chesse + if (targetChecked && addittion !== 'egg' && addittion !== 'chesse') { + console.log(addittion); + setOrder({ ...order, items: newAddittion }) + return + + //Condition if check = true and if is equal of egg and chesse + } if (targetChecked && addittion === 'egg' || targetChecked && addittion === 'chesse') { + console.log(addittion); + let newAddittion = [...order.items] + //We do a copy of additions in addittions: and add the new addition + newAddittion[indexItem] = { ...newAddittion[indexItem], addittions: [...order.items[indexItem].addittions, addittion], price: order.items[indexItem].price + 1 } + setOrder({ ...order, items: newAddittion }) + return + + //Condition in case of let´s move check and is different to egg or chesse + } if (targetChecked !== true && addittion !== 'egg' && addittion !== 'chesse') { + console.log(targetChecked); + console.log(addittion); + + //Access to addittions of item with its index + const productaddittion = order.items.map(product => product.addittions)[indexItem] + + //We extract an array within addition + const extras = productaddittion.filter(product => product !== addittion) + + //We are located in addittions of item to update the state with the new array + let newAddittion = [...order.items] + newAddittion[indexItem] = { ...newAddittion[indexItem], addittions: extras } + setOrder({ ...order, items: newAddittion }) + return + + } + //Condition in case of let´s move check and is equal to egg or chesse + if (targetChecked !== true && addittion === 'egg' || targetChecked !== true && addittion === 'chesse') { + console.log(targetChecked); + console.log(addittion); + //Price of product with addition egg or cheese + const priceProductaddittion = order.items.map(product => product.price)[indexItem] + console.log(priceProductaddittion); + //Access to addittions of item with its index + const productaddittion = order.items.map(product => product.addittions)[indexItem] + console.log(productaddittion); + //We extract an array within addition + const extras = productaddittion.filter(product => product !== addittion) + console.log(extras); + + //We are located in addittions of item to update the state with new array + let newAddittion = [...order.items] + //newAddittion[indexItem] = { ...newAddittion[indexItem], addittions: extras, price: priceProductaddittion - 1 } + newAddittion[indexItem] = { ...newAddittion[indexItem], addittions: extras, price: order.items[indexItem].price - 1 } + setOrder({ ...order, items: newAddittion }) + return + + } + } + + + + const node = ( +
+
+ +

Extras:

+
+ + + + + + + + + + + + + + +
+
+ +
+ +
+
+ + ) + //1er param: what we want render, 2do: where we want it render + return ReactDOM.createPortal(node, document.querySelector('#modalAdditions')) +} + +export default Extras diff --git a/src/components/Sumary/Extras.scss b/src/components/Sumary/Extras.scss new file mode 100644 index 000000000..fd655b758 --- /dev/null +++ b/src/components/Sumary/Extras.scss @@ -0,0 +1,93 @@ +$color-header: #190B54; +$green: #6DCE55; +$btn-heigth: 60px; +$font-size-btn: 25px; +$margin-btn: 30px; +$btn-radius: 20px; +$pink:#EB60DD; + +@mixin btn-accept { + border-style: solid; + margin: $margin-btn; + height: $btn-heigth; + width: 30%; + border-radius: $btn-radius; + font-size: $font-size-btn; +} + +.modal-container { + background-color: rgba(0, 0, 0, .8); + width: 100%; + height: 100vh; + position: fixed; + top: 0; + left: 0; + z-index: 1100; + display: flex; + justify-content: center; +} + +.modal-box { + width: 500px; + align-self: center; + padding: 2rem; + display: flex; + flex-direction: column; + background-color: $color-header; + border-radius: 6px; + border-style: solid; + border-radius: 25px; + border-color: $pink; + border-width: 7px; + + a{ + display: flex; + justify-content: flex-end; + + .icon-close{ + font-size: 40px; + color:white; + } + } + + + h1{ + margin-top: 0; + text-align: center; + } + + .cheks{ + margin: 30px; + display: grid; + grid-template-columns: 0.2fr 2.8fr; + justify-content: center; + align-items: center; + + + label{ + margin: 10px; + font-size: 30px; + } + input{ + width: 30px; + height: 40px; + margin-right: 10px; + } + } + + + + .container-btn-accept{ + display: flex; + justify-content: center; + + .btn-accept{ + @include btn-accept; + color: white; + background-color: $color-header; + border-width: 7px; + border-color: $green; + } + } + +} \ No newline at end of file diff --git a/src/components/Sumary/ItemSummary.js b/src/components/Sumary/ItemSummary.js new file mode 100644 index 000000000..701618fb8 --- /dev/null +++ b/src/components/Sumary/ItemSummary.js @@ -0,0 +1,95 @@ +import React, { Fragment, useState } from 'react'; +import Decrease from './Decrease' +import AddQuantity from './AddQuantity' +import Delete from './Delete' +import Extras from './Extras'; +import './Extras.scss'; +function ItemSummary({ item, idUnique, idItem, dish, additions, quantity, price, order, setOrder, breakfasts, lunchs }) { + + + //State Modal extras + const [extrasModal, setExtrasModal] = useState({ + idDish: 0, + state: false + }) + + + const showModal = (dish, idUnique) => { + console.log(dish, idUnique); + + if (dish === 'Hamburguesa simple') { + setExtrasModal({ idDish: idUnique, state: true }) + //setExtrasModal(true) + return + } if (dish === 'Hamburguesa doble') { + setExtrasModal({ idDish: idUnique, state: true }) + //setExtrasModal(true) + return + } + + setExtrasModal(false) + + } + + + + return ( + +
+

{ + showModal(dish, idUnique) + + }} + >{dish}

+ {additions !== undefined ? (

{additions.join()}

) : null} + +
+ +

{quantity}

+ +
+ + + + +
+ +

${price}

+ + + + { + extrasModal.state ? ( setExtrasModal(false)} + order={order} + setOrder={setOrder} + + />) : null + } +
+ + + ) +} +export default ItemSummary \ No newline at end of file diff --git a/src/components/Sumary/Summary.js b/src/components/Sumary/Summary.js new file mode 100644 index 000000000..e5078a24f --- /dev/null +++ b/src/components/Sumary/Summary.js @@ -0,0 +1,40 @@ +import React, { Fragment } from 'react'; +import ItemSummary from './ItemSummary.js'; +import './Summary.scss'; + +const Summary = ({ order, setOrder, breakfasts, lunchs }) => { + + return ( + + + < div className="container-summary" > + { + order.items.map(dish => ( + + + + )) + } + + + + + + + + ) +} + +export default Summary diff --git a/src/components/Sumary/Summary.scss b/src/components/Sumary/Summary.scss new file mode 100644 index 000000000..b600e82ce --- /dev/null +++ b/src/components/Sumary/Summary.scss @@ -0,0 +1,62 @@ +$white: #FDFFFC; +$light-blue : #10ABE0; +$orange : #FFB400; +$red: #FC6471; +$color-header: #190B54; +$pink: #EB60DD; +.container-order{ + display: grid; + grid-gap: 50px; + grid-template-columns: 1.6fr 1.8fr; + height: 600px; + margin: 10px ; + justify-items: center; + + //Order Summary + .container-summary{ + justify-self: start; + width: 90%; + height: 100%; + overflow: scroll; + display: grid; + grid-template-columns: 2fr 0.3fr 0.6fr 0.8fr 0.4fr; + grid-template-rows: repeat(10,90px); + justify-items: center; + align-items: center; + background-color: $color-header; + border-style: solid; + border-color: $light-blue; + border-width: 7px; + border-radius: 20px; + font-size: 25px; + text-align: center; + + p{ + margin: 0; + } + .additions{ + font-size: 25px; + color:#9987F2; + } + + .container-arrow-increment{ + i{ + font-size: 60px; + + } + } + + .icon-delete{ + color: $red; + } + } + + .container-summary::-webkit-scrollbar { + width: 9px; + } + + .container-summary::-webkit-scrollbar-thumb { + background: $pink; + border-radius: 8px; + } + } \ No newline at end of file diff --git a/src/firebase/firebase-config.js b/src/firebase/firebase-config.js new file mode 100644 index 000000000..460dcce14 --- /dev/null +++ b/src/firebase/firebase-config.js @@ -0,0 +1,128 @@ +import firebase from 'firebase/app' +import 'firebase/firestore' +//import { setDownData } from './App.js' + +let firebaseConfig = { + apiKey: "AIzaSyCwD2vRMyzzoVSlgMw1ugRcjke2wBCZCMc", + authDomain: "burguerqueen-f6391.firebaseapp.com", + databaseURL: "https://burguerqueen-f6391.firebaseio.com", + projectId: "burguerqueen-f6391", + storageBucket: "burguerqueen-f6391.appspot.com", + messagingSenderId: "22715911302", + appId: "1:22715911302:web:42b667553f3a91a381d507" +}; +// Initialize Firebase +firebase.initializeApp(firebaseConfig); + +export const db = firebase.firestore() + +export const saveOrderBD = (order) => { + + db.collection('orders') + .add(order).then(res => console.log(res)) + .catch(err => console.log(err)) +} + +/* export const getDataBD = () => { + return db.collection('orders').onSnapshot((snapshot) => { + const arrayData = [] + console.log(snapshot); + snapshot.forEach(doc => arrayData.push(({ ...doc.data(), id: doc.id }))) + setDownData(arrayData) + }) +} */ + + + +const viewOrders = (listOrder) => { + const d = db.collection('orders').where('state', '==', 'pending'); + return d.onSnapshot(snapshot => { + const spellsData = [] + snapshot.forEach(doc => spellsData.push({ ...doc.data(), id: doc.id })); + listOrder(spellsData); + }); +} + +const viewModalPending = (changePending) => { + const goPending = db.collection('orders').where('state', '==', 'pending').orderBy('date', 'desc'); + return goPending.onSnapshot(snapshotPending => { + const pendingData = [] + snapshotPending.forEach(doc => pendingData.push({ ...doc.data(), id: doc.id })); + changePending(pendingData); + }); +} +const viewModalReady = (changeReady) => { + const goReady = db.collection('orders').where('state', '==', 'ready').orderBy('date', 'desc'); + return goReady.onSnapshot(snapshotReady => { + const readyData = [] + snapshotReady.forEach(doc => readyData.push({ ...doc.data(), id: doc.id })); + changeReady(readyData); + }); +} + +const ordersSetDelivered = (id) => { + let onchangeStateD = db.collection("orders").doc(id); + return onchangeStateD.update({ + "state": "delivered" + }) +} + +const onChangeStateReady = (id) => { + let newDate = new Date; + let onchangeStateR = db.collection("orders").doc(id); + onchangeStateR.update({ + "state": "ready", + "deliveryDate": newDate + }); +} + +const onChangeStateCancel = (id) => { + let onChangeStateC = db.collection("orders").doc(id); + onChangeStateC.update({ + "state": "cancel" + }) +} +export { + viewOrders, + viewModalPending, + viewModalReady, + ordersSetDelivered, + onChangeStateReady, + onChangeStateCancel +}; + + +db.enablePersistence() + .catch(function (err) { + if (err.code == 'failed-precondition') { + // Multiple tabs open, persistence can only be enabled + // in one tab at a a time. + // ... + } else if (err.code == 'unimplemented') { + // The current browser does not support all of the + // features required to enable persistence + // ... + } + }); +// The default cache size threshold is 40 MB. Configure "cacheSizeBytes" +// for a different threshold (minimum 1 MB) or set to "CACHE_SIZE_UNLIMITED" +// to disable clean-up. +db.settings({ + cacheSizeBytes: db.CACHE_SIZE_UNLIMITED +}); + + + +db.collection("orders") + .onSnapshot({ includeMetadataChanges: true }, function (snapshot) { + snapshot.docChanges().forEach(function (change) { + if (change.type === "added") { + //console.log("New city: ", change.doc.data()); + } + + var source = snapshot.metadata.fromCache ? "local cache" : "server"; + //console.log("Data came from " + source); + console.log(snapshot.metadata); + + }); + }); \ No newline at end of file diff --git a/src/imgs/Thumbs.db b/src/imgs/Thumbs.db new file mode 100644 index 000000000..fc152f75a Binary files /dev/null and b/src/imgs/Thumbs.db differ diff --git a/src/imgs/bigSoda.png b/src/imgs/bigSoda.png new file mode 100644 index 000000000..d9136d371 Binary files /dev/null and b/src/imgs/bigSoda.png differ diff --git a/src/imgs/bigWater.png b/src/imgs/bigWater.png new file mode 100644 index 000000000..b192083f9 Binary files /dev/null and b/src/imgs/bigWater.png differ diff --git a/src/imgs/chicken.png b/src/imgs/chicken.png new file mode 100644 index 000000000..012378c56 Binary files /dev/null and b/src/imgs/chicken.png differ diff --git a/src/imgs/coffe.png b/src/imgs/coffe.png new file mode 100644 index 000000000..310ee1e3c Binary files /dev/null and b/src/imgs/coffe.png differ diff --git a/src/imgs/coffeMilk.png b/src/imgs/coffeMilk.png new file mode 100644 index 000000000..909321b65 Binary files /dev/null and b/src/imgs/coffeMilk.png differ diff --git a/src/imgs/doubleBurguer.png b/src/imgs/doubleBurguer.png new file mode 100644 index 000000000..572ba58a7 Binary files /dev/null and b/src/imgs/doubleBurguer.png differ diff --git a/src/imgs/frenchFries.png b/src/imgs/frenchFries.png new file mode 100644 index 000000000..89bb99212 Binary files /dev/null and b/src/imgs/frenchFries.png differ diff --git a/src/imgs/juice.png b/src/imgs/juice.png new file mode 100644 index 000000000..cb2234b97 Binary files /dev/null and b/src/imgs/juice.png differ diff --git a/src/imgs/logQueen.png b/src/imgs/logQueen.png new file mode 100644 index 000000000..763046880 Binary files /dev/null and b/src/imgs/logQueen.png differ diff --git a/src/imgs/meat.png b/src/imgs/meat.png new file mode 100644 index 000000000..84294de80 Binary files /dev/null and b/src/imgs/meat.png differ diff --git a/src/imgs/onion.png b/src/imgs/onion.png new file mode 100644 index 000000000..0abd1c9af Binary files /dev/null and b/src/imgs/onion.png differ diff --git a/src/imgs/sandwich.png b/src/imgs/sandwich.png new file mode 100644 index 000000000..856bece82 Binary files /dev/null and b/src/imgs/sandwich.png differ diff --git a/src/imgs/simpleBurguer.png b/src/imgs/simpleBurguer.png new file mode 100644 index 000000000..379cb1579 Binary files /dev/null and b/src/imgs/simpleBurguer.png differ diff --git a/src/imgs/smallSoda.png b/src/imgs/smallSoda.png new file mode 100644 index 000000000..711195641 Binary files /dev/null and b/src/imgs/smallSoda.png differ diff --git a/src/imgs/smallWater.png b/src/imgs/smallWater.png new file mode 100644 index 000000000..3f9cb4c7a Binary files /dev/null and b/src/imgs/smallWater.png differ diff --git a/src/imgs/vegy.png b/src/imgs/vegy.png new file mode 100644 index 000000000..f266048d5 Binary files /dev/null and b/src/imgs/vegy.png differ diff --git a/src/index.js b/src/index.js new file mode 100644 index 000000000..1b3461ef8 --- /dev/null +++ b/src/index.js @@ -0,0 +1,26 @@ +import React, { Suspense } from 'react'; +import ReactDOM from 'react-dom'; +import './styles/index.scss'; +import App from './App'; +import * as serviceWorker from './serviceWorker'; + +//Browser Router +import { BrowserRouter } from "react-router-dom"; + + +ReactDOM.render( + + + + + + + + , + document.getElementById('root') +); + +// If you want your app to work offline and load faster, you can change +// unregister() to register() below. Note this comes with some pitfalls. +// Learn more about service workers: https://bit.ly/CRA-PWA +serviceWorker.register(); diff --git a/src/serviceWorker.js b/src/serviceWorker.js new file mode 100644 index 000000000..b04b771a8 --- /dev/null +++ b/src/serviceWorker.js @@ -0,0 +1,141 @@ +// This optional code is used to register a service worker. +// register() is not called by default. + +// This lets the app load faster on subsequent visits in production, and gives +// it offline capabilities. However, it also means that developers (and users) +// will only see deployed updates on subsequent visits to a page, after all the +// existing tabs open on the page have been closed, since previously cached +// resources are updated in the background. + +// To learn more about the benefits of this model and instructions on how to +// opt-in, read https://bit.ly/CRA-PWA + +const isLocalhost = Boolean( + window.location.hostname === 'localhost' || + // [::1] is the IPv6 localhost address. + window.location.hostname === '[::1]' || + // 127.0.0.0/8 are considered localhost for IPv4. + window.location.hostname.match( + /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ + ) +); + +export function register(config) { + if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { + // The URL constructor is available in all browsers that support SW. + const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); + if (publicUrl.origin !== window.location.origin) { + // Our service worker won't work if PUBLIC_URL is on a different origin + // from what our page is served on. This might happen if a CDN is used to + // serve assets; see https://github.com/facebook/create-react-app/issues/2374 + return; + } + + window.addEventListener('load', () => { + const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; + + if (isLocalhost) { + // This is running on localhost. Let's check if a service worker still exists or not. + checkValidServiceWorker(swUrl, config); + + // Add some additional logging to localhost, pointing developers to the + // service worker/PWA documentation. + navigator.serviceWorker.ready.then(() => { + console.log( + 'This web app is being served cache-first by a service ' + + 'worker. To learn more, visit https://bit.ly/CRA-PWA' + ); + }); + } else { + // Is not localhost. Just register service worker + registerValidSW(swUrl, config); + } + }); + } +} + +function registerValidSW(swUrl, config) { + navigator.serviceWorker + .register(swUrl) + .then(registration => { + registration.onupdatefound = () => { + const installingWorker = registration.installing; + if (installingWorker == null) { + return; + } + installingWorker.onstatechange = () => { + if (installingWorker.state === 'installed') { + if (navigator.serviceWorker.controller) { + // At this point, the updated precached content has been fetched, + // but the previous service worker will still serve the older + // content until all client tabs are closed. + console.log( + 'New content is available and will be used when all ' + + 'tabs for this page are closed. See https://bit.ly/CRA-PWA.' + ); + + // Execute callback + if (config && config.onUpdate) { + config.onUpdate(registration); + } + } else { + // At this point, everything has been precached. + // It's the perfect time to display a + // "Content is cached for offline use." message. + console.log('Content is cached for offline use.'); + + // Execute callback + if (config && config.onSuccess) { + config.onSuccess(registration); + } + } + } + }; + }; + }) + .catch(error => { + console.error('Error during service worker registration:', error); + }); +} + +function checkValidServiceWorker(swUrl, config) { + // Check if the service worker can be found. If it can't reload the page. + fetch(swUrl, { + headers: { 'Service-Worker': 'script' }, + }) + .then(response => { + // Ensure service worker exists, and that we really are getting a JS file. + const contentType = response.headers.get('content-type'); + if ( + response.status === 404 || + (contentType != null && contentType.indexOf('javascript') === -1) + ) { + // No service worker found. Probably a different app. Reload the page. + navigator.serviceWorker.ready.then(registration => { + registration.unregister().then(() => { + window.location.reload(); + }); + }); + } else { + // Service worker found. Proceed as normal. + registerValidSW(swUrl, config); + } + }) + .catch(() => { + console.log( + 'No internet connection found. App is running in offline mode.' + ); + }); +} + +export function unregister() { + if ('serviceWorker' in navigator) { + navigator.serviceWorker.ready + .then(registration => { + registration.unregister(); + }) + .catch(error => { + console.error(error.message); + }); + } +} diff --git a/src/setupTests.js b/src/setupTests.js new file mode 100644 index 000000000..74b1a275a --- /dev/null +++ b/src/setupTests.js @@ -0,0 +1,5 @@ +// jest-dom adds custom jest matchers for asserting on DOM nodes. +// allows you to do things like: +// expect(element).toHaveTextContent(/react/i) +// learn more: https://github.com/testing-library/jest-dom +import '@testing-library/jest-dom/extend-expect'; diff --git a/src/styles/App.scss b/src/styles/App.scss new file mode 100644 index 000000000..55f30113f --- /dev/null +++ b/src/styles/App.scss @@ -0,0 +1,29 @@ +//Header +$general-font: 'Nunito', sans-serif; +$font-header: 'Pacifico', cursive; +$width-header : 100%; +$height-header: 85px; +$font-size-header : 40px; +$white: #FDFFFC; +$color-header: #0A2463; + +body{ + margin: 0px; + font-family: $general-font; +} + + +.header { + width: $width-header; + height: $height-header; + background-color: $color-header; + font-family: $font-header; + font-size: $font-size-header; + color: $white; + text-align: center; + p{ + margin-top: 0; + + } +} + diff --git a/src/styles/Styles.scss b/src/styles/Styles.scss new file mode 100644 index 000000000..1de556afe --- /dev/null +++ b/src/styles/Styles.scss @@ -0,0 +1,394 @@ +@import 'General'; +@import '../components/Header/Header'; +@import '../components/kitchen/Orders/Kitchen'; +@import '../components/kitchen/State/ListOrder'; +@import '../components/kitchen/Modal/Modal'; +body{ + margin: $margin-body; + padding: $padding-body; + background-color: $background-body; + font-family: $general-font; +} +.header-kitchen{ + background-color: $color-header; + width: $width-header; + height: 100%; + // height: $height-header; + /* position: $position-header; */ + top: $top-header; + left: $left-header; + display: grid; + grid-template-columns: 2fr 0.5fr; + justify-items: end; + flex-direction: $direction-kitchen; + justify-content: $justify-kitchen; + + .title-header{ + font-style: normal; + font-weight: bold; + text-align: $text-align-center; + font-size: $font-size-header; + font-family: 'Orbitron', sans-serif; + } + a{ + text-decoration: none; + + h1{ + color: $white; + } + } + + .div-header2{ + width: 20%; + align-self: center; + justify-self: center; + + i{ + color: #EB60DD; + font-size: 50px; + } + } +} +.div-header1{ + width: 80%; +} + +.container{ + margin: $margin-container; + width: $width-container; + height: $height-container; + margin-top: $margin-container-top; + +} +.title-kitchen{ + font-family: $general-font; + font-size: $title-size; + // font-style: $style; + font-weight: $weight; + text-align: $text-align-center; +} +.container{ + display: grid; + grid-template-columns: repeat(2 ,1fr); + justify-items: center; +} + .container-kitchen{ + /* display: $display-kitchen; + flex-direction: $direction-kitchen; + justify-content: $justify-kitchen; + flex-wrap: $wrap-kitchen; */ + display: grid; + grid-template-rows:repeat(10,auto); + grid-gap: 30px; +} +/* .card-padding{ + display: flex; + justify-content: center; + width: 50%; +} */ +.card-active{ + width: 450px; + height: $card-height; + top: $card-top; + background-color: $background-active; + color: $white; + margin-right: 0; + h4{ + margin:40px 40px 60px 40px; + text-align: $text-align-center; + height: 0px; + } + border: $bordercolor; + border-radius: $border-radius; + border-width: 7px; + font-size: $font-size-card; + font-family:'Nunito', sans-serif; + + h5{ + margin: 0; + font-size: 25px; + } +} +.card-inactive{ + width: 450px; + height: $card-height; + top: $card-top; + background-color: $background-inactive; + color: $color-inactive; + padding: 20px; + h4{ + margin:0px 40px 60px 40px; + text-align: $text-align-center; + height: 0px; + + } + border-radius: $border-radius; + font-size: $font-size-card; + font-family:'Nunito', sans-serif; + + h5{ + margin: 0; + font-size: 25px; + } +} +.list-source{ + display: $display-kitchen; + flex-direction: $display-kitchen; + justify-content: $justify-kitchen; + flex-wrap: $wrap-kitchen; + margin: 10px; + + +} +.list-source2{ + display: $display-kitchen; + flex-direction: $display-kitchen; + justify-content: $justify-kitchen; + flex-wrap: $wrap-kitchen; + margin-top: $cincuenta-pixeles; + height: auto; + +} +.item1-card{ + width: $item1-width; + font-size: $item-size; + padding-left: $item-padding; + height: auto; + margin-left: 10px; + h5{ + font-family: $general-font; + font-weight: $weight; + font-size: 30px; + } +} +.item2-card{ + width: $item2-width; + font-size: $item-size; + text-align: $text-align-center; + height: $trenta-cinco; + margin: 10px; + h5{ + margin: 0; + } +} +.spa{ + font-size: $spa-size; + color:#ADA3E1; +} +.item3-card{ + width: $item3-width; + /* font-size: $item-size; */ + text-align: $text-align-center; + margin-bottom: 40px; + +} +.button-red{ + background-color: $red; + border-radius: $button-radius; + border-color: $red; + font-weight: $weight; + font-style: $style; + font-family: $general-font; + color: $white; + width: $button-width; + font-size: 30px; +} +.button-green{ + background-color: $green; + border-radius: $button-radius; + border-color: $green; + font-weight: $weight; + font-style: $style; + font-family: $general-font; + color: $white; + width: $button-width; + font-size: 30px; +} + +.button-gray{ + background-color: $gray; + border-radius: $button-radius; + border-color: $gray; + font-weight: $weight; + font-style: $style; + font-family: $general-font; + color: $white; + width: $button-width; +} + +.item2-widtn-kitchem{ + right: $right; + top: $top-delivery; + display: grid; + grid-template-rows: repeat(10,auto); + +} +.headerList{ + display: $display-kitchen; + flex-direction: $direction-kitchen; + justify-content: $justify-kitchen; + flex-wrap: $wrap-kitchen; + border-radius: $diez-pixeles; + background-color: $azul-ligh; + color: $color-black; +} +.titulo-list{ + width: $width-title; + height: $height-title; + //top: $card-top; + //background-color: $light-blue; + padding-top: $diez-pixeles; + text-align: $text-align-center; + font-family: $general-font; + font-style: $style; + font-weight: $weight; + font-size: 30px; +} +.contentList{ + display: $display-kitchen; + flex-direction: $direction-kitchen; + justify-content: $justify-kitchen; + flex-wrap: $wrap-kitchen; + background-color: $transparente; +} +.list{ + width: $width-title; + height: $height-title; + top: $card-top; + text-align: $text-align-center; + font-family: $general-font; + font-style: $style; + font-weight: $weight; + font-size: 30px; + color: $white; + margin-bottom: 10px; +} +.icono{ + color: $red; +} + +.icon-delivered{ + color: $green; + font-size: 30px; +} + +.list-green{ + width: $width-status-list; + background-color: $green; + border-radius: $button-radius; + border-color: $green; + font-weight: $weight; + font-style: $style; + font-family: $general-font; + font-size: 30px; + margin: 0; +} + +.list-orange{ + width: $width-status-list; + background-color: $orange; + border-radius: $button-radius; + border-color: $green; + font-weight: $weight; + font-style: $style; + font-family: $general-font; + font-size: 30px; + margin: 0; + +} + +.list-edit{ + width: $width-title; + height: $auto; + top: $card-top; + background-color: $white; + text-align: $text-align-center; + font-family: $general-font; + font-style: $style; + font-weight: $weight; +} + +.container-list{ + margin: $margin-container; + width: $container-list-width; + height: $height-container; + margin-top: $margin-container-list; + +} +.container-list-edit{ + margin: $margin-container; + width: $continer-list-edit-width; + height: $height-container; + margin-top: $margin-container-list; + +} + +.modal-background{ + background-color: rgba(0, 0, 0, .8); + width: 100%; + height: 100vh; + position: fixed; + top: 0; + left: 0; + z-index: 1100; + display: flex; + justify-content: center; +} + +.modal-contenido{ + background-color: $background-body; + width: $modal-width; + padding: $modal-padding; + margin: $modal-margin; + position: $modal-relative; + height: $modal-height; + overflow: $modal-overflow; + border-style: solid; + border-radius: 25px; + border-color: #EB60DD; + border-width: 7px; + + + } + .modal{ + background-color: $modal-trasparent; + position: $modal-fixed; + top: $modal-top; + right: $modal-right; + bottom: $modal-bottom; + left: $modal-left; + } + .title-list{ + font-family: $general-font; + font-size: $size-title; + font-style: $style; + font-weight: $weight; + text-align: $text-align-center; +} +.right{ + color: $color-gray; + line-height: $line-height; + font-size: $font-size-c; + right: $modal-right; + text-align: $text-align-center; + top: $modal-top; + width: $width-c; + text-decoration: $text-decoration; + &:hover { + color: $color-black; + } +} +.modal-close { + position: $absolute; + color: $white; + line-height: $line-height; + font-size: $font-size-c; + right: $modal-right; + text-align: $text-align-center; + top: $modal-top; + width: $width-c; + text-decoration: $text-decoration; + &:hover { + color: $color-black; + } + } \ No newline at end of file diff --git a/src/styles/_General.scss b/src/styles/_General.scss new file mode 100644 index 000000000..6fa3bcad2 --- /dev/null +++ b/src/styles/_General.scss @@ -0,0 +1,25 @@ +$general-font: 'Heebo', sans-serif; +$margin-body: 0px; +$padding-body: 0px; +$background-body: #170849; +$text-align-center: center; +$style: normal; +$weight: normal; +$title-size: 36px; +//Color btns +$green : #6DCE55; + +$red : #FC6471; +$gray : transparent; +$orange : orange; + +//Colors modal +$light-blue : #C6DDFA; + +$height-container: 100%; +$width-container: 90%; +$border: 1px solid red; +$margin-container: auto; +$margin-container-top: 100px; + +$padding-left:10px; diff --git a/src/styles/index.scss b/src/styles/index.scss new file mode 100644 index 000000000..ec2585e8c --- /dev/null +++ b/src/styles/index.scss @@ -0,0 +1,13 @@ +body { + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', + 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', + sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +code { + font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', + monospace; +}