React y Angular 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. 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 caractrísticas específicas de nuestra aplicació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.
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).
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.
Esta es la información que tenemos del cliente:
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: Los 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 su pedido varias veces antes de finalizarlo.
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.
El objetivo principal de este proyecto es aprender a construir una interfaz web usando el framework elegido (React o Angular). 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).
Reflexiona y luego marca los objetivos que has llegado a entender y aplicar en tu proyecto. Piensa en eso al decidir tu estrategia de trabajo.
[ ] Uso de HTML semántico
* [HTML semántico](https://curriculum.laboratoria.la/es/topics/html/02-html5/02-semantic-html) * [Semantics - MDN Web Docs Glossary](https://developer.mozilla.org/en-US/docs/Glossary/Semantics#Semantics_in_HTML)
[ ] Uso de selectores de CSS
* [Intro a CSS](https://curriculum.laboratoria.la/es/topics/css/01-css/01-intro-css) * [CSS Selectors - MDN](https://developer.mozilla.org/es/docs/Web/CSS/CSS_Selectors)
[ ] Modelo de caja (box model): borde, margen, padding
* [Box Model & Display](https://curriculum.laboratoria.la/es/topics/css/01-css/02-boxmodel-and-display) * [The box model - MDN](https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/The_box_model) * [Introduction to the CSS box model - MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Box_Model/Introduction_to_the_CSS_box_model) * [CSS display - MDN](https://developer.mozilla.org/pt-BR/docs/Web/CSS/display) * [display - CSS Tricks](https://css-tricks.com/almanac/properties/d/display/)
[ ] Uso de flexbox en CSS
* [A Complete Guide to Flexbox - CSS Tricks](https://css-tricks.com/snippets/css/a-guide-to-flexbox/) * [Flexbox Froggy](https://flexboxfroggy.com/#es) * [Flexbox - MDN](https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Flexbox)
[ ] Uso de CSS Grid Layout
* [A Complete Guide to Grid - CSS Tricks](https://css-tricks.com/snippets/css/complete-guide-grid/) * [Grids - MDN](https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Grids)
[ ] Uso de media queries
* [CSS media queries - MDN](https://developer.mozilla.org/es/docs/CSS/Media_queries)
[ ] Arrays (arreglos)
* [Arreglos](https://curriculum.laboratoria.la/es/topics/javascript/04-arrays) * [Array - MDN](https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Global_Objects/Array/) * [Array.prototype.sort() - MDN](https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) * [Array.prototype.forEach() - MDN](https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach) * [Array.prototype.map() - MDN](https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Global_Objects/Array/map) * [Array.prototype.filter() - MDN](https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) * [Array.prototype.reduce() - MDN](https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce)
[ ] Objetos (key, value)
* [Objetos en JavaScript](https://curriculum.laboratoria.la/es/topics/javascript/05-objects/01-objects)
[ ] Diferenciar entre tipos de datos primitivos y no primitivos
[ ] Uso de condicionales (if-else, switch, operador ternario, lógica booleana)
* [Estructuras condicionales y repetitivas](https://curriculum.laboratoria.la/es/topics/javascript/02-flow-control/01-conditionals-and-loops) * [Tomando decisiones en tu código — condicionales - MDN](https://developer.mozilla.org/es/docs/Learn/JavaScript/Building_blocks/conditionals)
[ ] Funciones (params, args, return)
* [Funciones (control de flujo)](https://curriculum.laboratoria.la/es/topics/javascript/02-flow-control/03-functions) * [Funciones clásicas](https://curriculum.laboratoria.la/es/topics/javascript/03-functions/01-classic) * [Arrow Functions](https://curriculum.laboratoria.la/es/topics/javascript/03-functions/02-arrow) * [Funciones — bloques de código reutilizables - MDN](https://developer.mozilla.org/es/docs/Learn/JavaScript/Building_blocks/Functions)
[ ] Pruebas unitarias (unit tests)
* [Empezando con Jest - Documentación oficial](https://jestjs.io/docs/es-ES/getting-started)
[ ] Pruebas asíncronas
* [Tests de código asincrónico con Jest - Documentación oficial](https://jestjs.io/docs/es-ES/asynchronous)
[ ] Uso de mocks y espías
* [Manual Mocks con Jest - Documentación oficial](https://jestjs.io/docs/es-ES/manual-mocks)
[ ] Módulos de ECMAScript (ES Modules)
* [import - MDN](https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Statements/import) * [export - MDN](https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Statements/export)
[ ] Uso de linter (ESLINT)
[ ] Uso de identificadores descriptivos (Nomenclatura y Semántica)
[ ] Diferenciar entre expresiones (expressions) y sentencias (statements)
[ ] Callbacks
* [Función Callback - MDN](https://developer.mozilla.org/es/docs/Glossary/Callback_function)
[ ] Promesas
* [Promise - MDN](https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Global_Objects/Promise) * [How to Write a JavaScript Promise - freecodecamp (en inglés)](https://www.freecodecamp.org/news/how-to-write-a-javascript-promise-4ed8d44292b8/)
[ ] Git: Instalación y configuración
[ ] Git: Control de versiones con git (init, clone, add, commit, status, push, pull, remote)
[ ] Git: Integración de cambios entre ramas (branch, checkout, fetch, merge, reset, rebase, tag)
[ ] GitHub: Creación de cuenta y repos, configuración de llaves SSH
[ ] GitHub: Despliegue con GitHub Pages
* [Sitio oficial de GitHub Pages](https://pages.github.com/)
[ ] GitHub: Colaboración en Github (branches | forks | pull requests | code review | tags)
[ ] GitHub: Organización en Github (projects | issues | labels | milestones | releases)
[ ] Crear prototipos de alta fidelidad que incluyan interacciones
[ ] Seguir los principios básicos de diseño visual
[ ] Planear y ejecutar testeos de usabilidad de prototipos en distintos niveles de fidelidad
* [Intro a testeos usabilidad](https://coda.io/@bootcamp-laboratoria/contenido-ux/test-de-usabilidad-15) * [Pruebas con Usuarios 1 — ¿Qué, cuándo y para qué testeamos?](https://eugeniacasabona.medium.com/pruebas-con-usuarios-1-qu%C3%A9-cu%C3%A1ndo-y-para-qu%C3%A9-testeamos-7c3a89b4b5e7)
[ ] Firebase Auth
* [Primeros pasos con Firebase Authentication en sitios web - Documentación oficial](https://firebase.google.com/docs/auth/web/start?hl=es) * [Administra usuarios en Firebase (onAuthStateChanged)](https://firebase.google.com/docs/auth/web/manage-users?hl=es#get_the_currently_signed-in_user)
[ ] Firestore
* [Firestore - Documentación oficial](https://firebase.google.com/docs/firestore?hl=es) * [Reglas de seguridad de Firestore - Documentación oficial](https://firebase.google.com/docs/rules?hl=es) * [Obtén actualizaciones en tiempo real con Cloud Firestore - Documentación oficial](https://firebase.google.com/docs/firestore/query-data/listen?hl=es)
[ ] Components & templates
* [Angular Components Overview - Documentación oficial (en inglés)](https://angular.io/guide/component-overview) * [Introduction to components and templates - Documentación oficial (en inglés)](https://angular.io/guide/architecture-components#introduction-to-components)
[ ] Directivas estructurales (ngIf / ngFor)
* [Writing structural directives - Documentación oficial (en inglés)](https://angular.io/guide/structural-directives)
[ ] @Input | @Output
* [Component interaction - Documentación oficial (en inglés)](https://angular.io/guide/component-interaction#component-interaction)
[ ] Creación y uso de servicios
* [Providing services - Documentación oficial (en inglés)](https://angular.io/guide/architecture-services#providing-services)
[ ] Manejo de rutas
* [In-app navigation: routing to views - Documentación oficial (en inglés)](https://angular.io/guide/router)
[ ] Creación y uso de Observables.
* [Observables in Angular - Documentación oficial (en inglés)](https://angular.io/guide/observables-in-angular)
[ ] Uso de HttpClient
* [Communicating with backend services using HTTP - Documentación oficial (en inglés)](https://angular.io/guide/http)
[ ] Estilos de componentes (ngStyle / ngClass)
* [Template syntax - Documentación oficial (en inglés)](https://angular.io/guide/template-syntax#built-in-directives)
[ ] JSX
* [Presentando JSX - Documentación oficial](https://es.reactjs.org/docs/introducing-jsx.html)
[ ] Componentes y propiedades (props)
* [Componentes y propiedades - Documentación oficial](https://es.reactjs.org/docs/components-and-props.html)
[ ] Manejo de eventos
* [Manejando eventos - Documentación oficial](https://es.reactjs.org/docs/handling-events.html)
[ ] Listas y keys
* [Listas y keys - Documentación oficial](https://es.reactjs.org/docs/lists-and-keys.html)
[ ] Renderizado condicional
* [Renderizado condicional - Documentación oficial](https://es.reactjs.org/docs/conditional-rendering.html)
[ ] Elevación de estado
* [Levantando el estado - Documentación oficial](https://es.reactjs.org/docs/lifting-state-up.html)
[ ] Hooks
* [Presentando Hooks - Documentación oficial](https://es.reactjs.org/docs/hooks-intro.html)
[ ] CSS modules
* [Adding a CSS Modules Stylesheet - Documentación de Create React App (en inglés)](https://create-react-app.dev/docs/adding-a-css-modules-stylesheet/)
[ ] React Router
* [Quick Start - Documentación oficial (en inglés)](https://reactrouter.com/web/guides/quick-start)
Este proyecto se debe "resolver" en duplas.
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 o Angular).
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.
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.
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 70% de statements, functions, lines y branches.
Este proyecto incluye un boilerplate con el código necesario para arrancar con la parte de backend ya resuelta. El boilerplate incluye los siguientes archivos/carpetas con la configuración de Fierbase (hosting y firestore):
.
├── .editorconfig
├── firebase.json
├── firestore.indexes.json
├── firestore.rules
├── README.md
└── README.pt-BR.md
Por otro lado, la parte de la interfaz no está incluida, por lo que, 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.
Para comenzar este proyecto tendrás que hacer un fork y clonar este repositorio.
El Product Owner nos presenta este backlog que es el resultado de su trabajo con el cliente hasta hoy.
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.
Lo que debe ocurrir para que se satisfagan las necesidades del usuario)
Lo acordado que debe ocurrir para decir que la historia está terminada.
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.
Yo como meserx quiero ver los pedidos que están preparados para entregarlos rápidamente a los clientes que las hicieron.
NOTA: Si estás haciendo el proyecto en equipo, estos pasos solo los necesita hacer una persona por equipo. El resto de las integrantes del equipo después podrán hacer sus propios forks a partir del fork principal de su equipo.
Haz un fork de este repo (en GitHub).
Clona tu fork en tu computadora:
git clone git@github.com:<tu-usuario-de-github>/<cohortid>-burger-queen.git
cd <cohortid>-burger-queen
Crea una rama a partir de main
para empezar a trabajar. Por ejemplo:
git checkout -b develop
Crea un proyecto en Firebase
Habilita Firestore (comenzar en modo bloqueado) en sección de "Bases de Datos" de Firebase console.
Instala la utilidad de línea de comando de Firebase.
Esta utilidad nos permitirá usar el comando firebase
desde nuestra
terminal. Ten en cuenta que el comando de instalación incluye la opción -g
,
lo cual significa que estamos instalando firebase-tools
de forma global,
con lo cual quedará disponible desde cualquier lugar (es independiente de
un proyecto en particular, no queda instalado en la carpeta node_modules
de
tu proyecto, si no globalmente, por lo tanto no importa desde qué carpeta
ejecutes el siguiente comando de instalación).
npm i -g firebase-tools
Iniciamos sesión con Firebase y agregamos entorno que usaremos para desplegar:
firebase login
firebase use --add
# Una vez agregado el entorno (proyecto de firebase) puedes agregar otros y
# listar los entornos configurados para esta carpeta con este comando
firebase use
Llegado a este punto, ya puedes comenzar con la problemática del proyecto en sí. Te recomendamos como siguiente paso convertir el menú descrito por el cliente en una estructura que podamos poner en un archivo JSON para después pintar en la pantalla.
En esta sección revisamos algunas opciones para desplegar el backend y frontend de tu app. Si usas firebase con reglas de firestore, índices, cloud functions, necesitas desplegar el backend con firebase-cli.
Puedes desplegar el frontend con Firebase hosting. Hay otras opciones como Github Pages (que ya estan familiarizadas), Netlify, y Vercel.
Netlify y Vercel son servicios para desplegar tu web app - backend y frontend - y no son limitados a usar solamente con Firebase. Por ejemplo, puedes desplegar un app MySQL/Express/React.
Cada framework incluye su propio pipeline de construcción o build. Con
esto nos referimos a que para construir nuestro proyecto y producir un
artefacto que podamos desplegar vamos a usar un script que normalmente
configuramos como una tarea de npm-scripts
con el nombre build
e invocamos
así:
npm run build
Una vez hayamos construido la aplicación, tendremos un directorio que contiene
la app lista para desplegar. Dependiendo del framework que uses y tu
configuración en particular, esa carpeta puede tener un nombre distinto;
normalmente build
o dist
.
La herramienta de línea de comando de Firebase (firebase-tools
) incluye un
comando que nos permite desplegar nuestro proyecto a Firebase:
firebase deploy
. A la hora de ejecutar este comando, se usará la configuración
que tenemos en el archivo firebase.json
. En ese archivo asegúrate de que la
propiedad public
del objeto hosting
tenga la ruta correcta a la carpeta
donde hemos construido la aplicación. En este ejemplo es implemente build
,
asumiendo que la carpeta build
es una subcarpeta del directorio donde se
encuentra nuestro firebase.json
.
...
"hosting": {
"public": "build",
...
},
...
Finalmente, estás lista para desplegar tu proyecto a Firebase :rocket::fire:!
firebase deploy
Netlify es un servicio de hosting para sitios web estáticos. Para usarlo primero necesitas crear una cuenta en Netlify y después puedes conectar tu repo.
Para desplegar tu aplicación en netlify seleccionas acceder con GitHub y luego concedes los permisos para que Netlify acceda a tus repositorios y generar la clave para poder realizar el despliegue continuo.
Una vez terminado el registro bastará con compilar tu aplicación para producción y arrastrar tu carpeta (dist, build) a la parte de sites dentro de netlify.
Al terminar de cargar los archivos podras ver el nombre de la aplicación dentro de Netlify junto al link del app ya hosteada.
Hay un netlify-cli
si prefieres hacer el despliegue por linea de comando.
Para usarlo, hay que instalar el cli en tu proyecto y authorizarlo.
Puedes checar la documentación o seguir con los siguentes comandos:
npm install netlify-cli --save-dev
netlify login
Esto va a crear un config.json
en tu proyecto.
Puedes usar netlify
con continuous deployment (despliegue continuo) y así
cada vez que agregues un commit se va a compilar y desplegar tu app con
los nuevos cambios. Alternativamente, también puedes hacer depliegue manual.
Para continuous deployment corre netlify init
y sigue las instrucciones
para conectar un repo de tu github.
Puedes configurar deploy settings (comando para el build, directorio de la
carpeta y la rama para producción) en "deploy settings" de tu site en netlify.
Para desplegar manualmente puedes usar netlify deploy
. También por defecto
busca un directorio build
en tu proyecto para desplegarlo. Si tu proyecto
tiene un directorio de otro nombre puedes usar la opción --dir
.
netlify deploy --dir=dist`
create-react-app
Si tratas de usar create-react-app
en el directorio del proyecto recibirás un error diciendo que hay archivos que
podrían presentar un conflicto. Para evitar este problema puedes crear una nueva
app usando create-react-app
y de ahí mezclarla con la carpeta del proyecto:
# Si estabas en la carpeta del proyecto, salimos a la carpeta de más arriba
cd ..
# Creamos una nueva aplicación con `create-react-app` en la carpeta
# `burger-queen-tmp`
npx create-react-app burger-queen-tmp
# Copiamos el _boilerplate_ del proyecto _encima_ de la aplicación creada con
# `create-react-app`
cp -r <cohort-id>-burger-queen/* burger-queen-tmp/
# Copiamos el contenido de la aplicación creada con `create-react-app` de vuelta
# al repo del proyecto (teniendo en cuenta el archivo _oculto_ `.gitignore`).
cp -r burger-queen-tmp/.gitignore burger-queen-tmp/* <cohort-id>-burger-queen/
# Ya podemos borrar la instalación _temporal_ y quedarnos solo con el repo del
# proyecto, con el que partimos.
rm -rf burger-queen-tmp
# Volvemos a entrar en el directorio del proyecto y ya deberíamos estar listas
# para comenzar.
cd <cohort-id>-burger-queen
# Para confirmar que todo fue bien arranca la aplicación con el siguinte comando
# y verifica que la interfaz se abre en el navegador.
yarn start
Te sugerimos implementar las siguientes funcionalidades para que puedas reforzar aún más los Objetivos de Aprendizaje asociados a promesas.
Agrega la opción de actualizar 2 o más pedidos que esten en la cocina. Muestra al usuario un único mensaje de confirmación cuando todos los pedidos hayan sido actualizados con éxito. Recuerda, firestore al actualizar un documento retorna una promesa. ¿Cómo podrías mostrar el mensaje de confirmación unicamente cuando todas las promesas se hayan resuelto? Te sugerimos revisar la función Promise.all.
Cuando un pedido finalice, puedes incorporar a tu código la
siguiente función getDiscount
:
export const getDiscount = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
const discount = parseInt(Math.random() * 100);
if (discount > 80) {
reject(new Error(`¡${discount}% es demasiado descuento!`));
} else {
resolve(discount);
}
}, 0);
});
}
Que retornará una promesa que generará un número entero aleatorio
discount
que puedes utilizar como porcentaje de descuento para
calcular el total del pedido en caso de que sea menor o igual a 80;
En caso de que el número entero discount
sea mayor a 80,
la promesa retornará un error con el mensaje de que el descuento es
demasiado grande, y por ende, no aplicable.