Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
76ccd4c
initial commit (vite + react + ts + tailwind)
matiasbaldanza Nov 15, 2024
5316091
add product schema
matiasbaldanza Nov 17, 2024
c0289f3
update ProductSchema to match FakeStoreAPI specs
matiasbaldanza Nov 17, 2024
8d5d6c2
add productApi for data access with zod validation
matiasbaldanza Nov 17, 2024
572259e
feat: add 'product not found' condition to fetchAndValidateProduct a…
matiasbaldanza Nov 19, 2024
974b09d
feat: add basic Cart and addProductForm functionality, implemented wi…
matiasbaldanza Nov 19, 2024
b06d7f5
feat: add increase and decrease item quantity actions
matiasbaldanza Nov 19, 2024
59fc932
refactor: ADD_ITEM uses INCREASE_ITEM_QUANTITY if the item exists in …
matiasbaldanza Nov 19, 2024
aacacdb
feat (style): remove vite template elements
matiasbaldanza Nov 19, 2024
4a942f7
feat: add layout for styling
matiasbaldanza Nov 19, 2024
9641d8f
chore: fix dep (axios)
matiasbaldanza Nov 19, 2024
802fe56
feat: handle page metadata with react-helmet-sync
matiasbaldanza Nov 19, 2024
45cf396
chore: add path alias '@'
matiasbaldanza Nov 19, 2024
aa248b1
feat (styling): add shadcn/ui
matiasbaldanza Nov 19, 2024
dda87f7
feat: re-do form using shadcn/ui components and a form
matiasbaldanza Nov 19, 2024
e16dc04
fix: ADD_ITEM now applies the quantity
matiasbaldanza Nov 19, 2024
f03b807
fix
matiasbaldanza Nov 19, 2024
fc54359
Revert "fix"
matiasbaldanza Nov 19, 2024
598eb85
fix: INCREASE_ITEM_QUANTITY now adds the quantity when a repeated car…
matiasbaldanza Nov 19, 2024
564b479
fix: items with quantity = 0 are not added to the cart
matiasbaldanza Nov 19, 2024
ccb12fc
feat: add strings for Cart and AddProductForm, display clear cart but…
matiasbaldanza Nov 19, 2024
c73ba4b
chore: lint
matiasbaldanza Nov 19, 2024
26f60f2
feat (style): include author and repo links in footer
matiasbaldanza Nov 19, 2024
b3d84a4
fix: not allow productId to be < 1, disable form if no productId is e…
matiasbaldanza Nov 19, 2024
aba575b
feat: add Quantity selector
matiasbaldanza Nov 19, 2024
a32e40c
feat: cart summary
matiasbaldanza Nov 19, 2024
2d92791
chore: rename interface CartItem to CartItemI to implement CartItem c…
matiasbaldanza Nov 19, 2024
23870c0
feat: add UI text for empty cart state and addProductForm
matiasbaldanza Nov 19, 2024
20e2f07
chore: remove console.log and add comments
matiasbaldanza Nov 19, 2024
7d3aaf4
feat: CartItemsList
matiasbaldanza Nov 19, 2024
f48a533
refactor: extract CurrencyFormatted
matiasbaldanza Nov 19, 2024
3a30c49
style: format elements, add className props to components
matiasbaldanza Nov 19, 2024
674aff1
fix: style Quantity selector
matiasbaldanza Nov 19, 2024
c3904fb
feat: allow user to update quantities in CartItemsList
matiasbaldanza Nov 19, 2024
5b25120
docs: update README
matiasbaldanza Nov 19, 2024
4d70c45
chore: update vite
matiasbaldanza Nov 19, 2024
a48ac62
fix: display errors outside the form
matiasbaldanza Nov 19, 2024
15bc058
docs: update README
matiasbaldanza Nov 19, 2024
b8092e2
fix: remove react-markdown. It broke Vite's build (unable to resolve …
matiasbaldanza Nov 19, 2024
2bec003
docs: update README with local deploy
matiasbaldanza Nov 19, 2024
c67859a
update README with deploy url
matiasbaldanza Nov 20, 2024
24b0c05
feat: add quantity limits per product (TODO: does not enforce this li…
matiasbaldanza Nov 20, 2024
36b2dc1
update README
matiasbaldanza Nov 20, 2024
1ebccbf
add TODOs to README
matiasbaldanza Nov 20, 2024
a060aec
feat: show cart createdAt in Cart details (Cart)
matiasbaldanza Nov 20, 2024
3efb6ec
fix: addProductForm submits on Enter keypressed from any child inputs…
matiasbaldanza Nov 20, 2024
b86b9ae
feat: add Total per product and change Remove button to a link
matiasbaldanza Nov 20, 2024
793a3e2
fix: add rollup as optional dependency for build bug on Vite > v5
matiasbaldanza Nov 20, 2024
18e224a
refactor: extract Footer
matiasbaldanza Nov 20, 2024
8b01855
content: change footer repo link to the dev branch 'cart-matias'
matiasbaldanza Nov 20, 2024
f0ed699
feat: Add Build Info (Vercel) in footer
matiasbaldanza Nov 20, 2024
99e9dd1
update README with deploy URL (Vercel)
matiasbaldanza Nov 20, 2024
709bbe2
fix: debug info in footer - remove info on deployment
matiasbaldanza Nov 20, 2024
a681463
fix: remove build info on deploy (doesn't work yet)
matiasbaldanza Nov 20, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# For BuildInfo (Vercel deploy info)
VITE_COMMIT_SHA=\$VERCEL_GIT_COMMIT_SHA
VITE_BUILD_DATE=\$(date -u +'%Y-%m-%dT%H:%M:%SZ')
26 changes: 26 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

.env
2 changes: 2 additions & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
packageManager=pnpm@ ERROR  This project is configured to use yarn
For help, run: pnpm help
109 changes: 74 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,65 +1,104 @@
[![Wallbit](./assets/logo.jpg)](https://wallbit.io/)
# Wallbit Junior Frontend Challenge

Este proyecto es un desafío de frontend para crear un carrito de compras utilizando React. A continuación, se detallan los pasos para instalar y ejecutar el proyecto.

> El banco digital para trabajadores remotos.

# Wallbit Junior Frontend Challenge
## Requisitos Previos

Para este desafío, nuestro cliente nos encargó hacer un carrito de compras para programadores. Tiene un formulario con 2 campos: ID del producto y cantidad. Los programadores habitualmente no necesitan saber ni ver que productos comprar, sino que saben por conexiones astrales cual es el ID del producto que quieren y así los agregan a su carrito.
Asegúrate de tener instalado Node.js y npm en tu máquina.

Cada vez que se agrega un producto, vamos a obtener el producto desde la API y lo vamos a mostrar en una tabla, junto a la cantidad que el usuario eligió.
## Tecnologías utilizadas

> Solo lo mostramos visualmente por si hay alguien que no sea programador mirando la pantalla.
- React
- Typescript
- TailwindCSS
- Shadcn/UI

La aplicación se vería así:
## Deploy de prueba

![Sin productos](./assets/app-0.jpg)
> Inicialmente no hay productos en el carrito
https://wallbit-challenge-mati.vercel.app/

![Con productos](./assets/app-1.jpg)
> Con productos en el carrito
## Instalación

1. Clona el repositorio:

```bash
git clone https://github.com/matiasbaldanza/wallbit-challenge.git
```

2. Instala las dependencias:

```bash
cd wallbit-challenge
npm install
```

3. Inicia el proyecto:

```bash
npm run dev
```

o:

```bash
vite dev
```

## Requisitos

La API que nos dió nuestro cliente es: [Fake Store API](https://fakestoreapi.com/). El cliente nos dijo que su stack de frontend es React, que prefiere el challenge hecho con eso, pero está abierto a cualquier stack que quieras usar.

- [ ] Podemos agregar productos al carrito.
- [ ] Manejar errores que nos devuelva la API.
- [ ] Mostrar una lista con los productos agregados incluyendo `title`, `price` e `image` del producto y la `cantidad` que el usuario agregó.
- [X] Podemos agregar productos al carrito.
- [X] Manejar errores que nos devuelva la API.
- [X] Mostrar una lista con los productos agregados incluyendo `title`, `price` e `image` del producto y la `cantidad` que el usuario agregó.

## Extras

- [ ] El carrito se persiste al recargar la página.
- [ ] Mostrar el total de productos agregados.
- [ ] Mostrar el costo total del carrito.
- [ ] Mostrar la fecha de creación del carrito.
- [X] El carrito se persiste al recargar la página.
- [X] Mostrar el total de productos agregados.
- [X] Mostrar el costo total del carrito.
- [X] Mostrar la fecha de creación del carrito.

## Bonus
## Detalles de implementación

Para destacar, podés agregar cualquier cosa que se te ocurra que llame la atención. No tiene por qué ser necesariamente en el código, o una dependencia. Puede ser algo visual, un easter egg, una funcionalidad, o bueno, algo en el código.
- [X] Implementación de una API wrapper para facilitar las llamadas a la API (con solo una acción - getProductById)
- [X] Implementación de un cart context para facilitar el manejo del estado
- [X] Implementación de un cart reducer para facilitar extensiones futuras

> [!NOTE]
> Siempre recordá que lo que agregues debe sumar a la experiencia del usuario y no complicar su navegación. Tenés que pensar que quien va a usar la aplicación no va a haber hablado con vos previamente y aun así debería poder usar la aplicación y obtener la mejor experiencia posible.
## Bonus

## Entregables
- [X] Input personalizado para gestionar cantidad de productos ya agregados
- [X] Formato personalido de precios
- [X] Botón para vaciar el carrito

- [ ] Crear un Pull Request a este repositorio con tu solución.
- [ ] Reemplazar el `README.md` con instrucciones para correr el proyecto e información relevante para la evaluación.
- [ ] Incluir el link al deploy de tu aplicación.
## Pendientes/TODOs

## Premio
- [ ] Deploy (falla el build en Vercel, posiblemente por versión de Node)
- [ ] Tests (no llegué)
- [ ] Unificar validaciones/mensajes de error con Zod (ahora valida con Zod en el fetch, pero no gestiona los mensajes de error, que están en un try/catch, el carrito no tiene schema ni validación completa)
- [ ] Implementar notificaciones de errores al usuario (ahora hay mensaje genérico con dos posible valores, y se mantiene la validación nativa del browser en los inputs)
- [ ] Ver layout shifts / lazy loading
- [ ] Toasts para notificaciones al usuario
- [ ] Mejorar estilos
- [ ] Animaciones
- [ ] Responsive
- [ ] Mostrar errores usando un ErrorBoundary
- [ ] Bug de persistencia carrito (el carrito se preserva en múltiples refresh de la página, pero si se hacen multiples refresh de la página rápidos, se pierde el carrito)

Se va a entregar un premio en vivo durante [mi stream](https://twitch.tv/goncypozzo) el 19 de Noviembre de 2024 a las 19:00hs Argentina (GMT -3) entre todos los que completen el desafío. El premio va a ser un micrófono Razer Seiren Mini.
## Instrucciones y requisitos originales

El ganador va a ser elegido por el chat, la gente de Wallbit y yo.
Para este desafío, nuestro cliente nos encargó hacer un carrito de compras para programadores. Tiene un formulario con 2 campos: ID del producto y cantidad. Los programadores habitualmente no necesitan saber ni ver que productos comprar, sino que saben por conexiones astrales cual es el ID del producto que quieren y así los agregan a su carrito.

> [!IMPORTANT]
> El ganador debe estar presente en el stream para recibir el premio.
Cada vez que se agrega un producto, vamos a obtener el producto desde la API y lo vamos a mostrar en una tabla, junto a la cantidad que el usuario eligió.

![Razer Seiren Mini](./assets/sorteo.jpg)
> Solo lo mostramos visualmente por si hay alguien que no sea programador mirando la pantalla.

> En caso de no poder enviarse el premio, se pagará el equivalente de 70 USD.
La aplicación se vería así:

El deadline para enviar el PR es el 19 de Noviembre de 2024 a las 15:00hs Argentina (GMT -3).
![Sin productos](./assets/app-0.jpg)
> Inicialmente no hay productos en el carrito

> [!IMPORTANT]
> Los PRs se cerrarán luego de esa hora así que no te olvides de hacerlo antes.
![Con productos](./assets/app-1.jpg)
> Con productos en el carrito
21 changes: 21 additions & 0 deletions components.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york",
"rsc": false,
"tsx": true,
"tailwind": {
"config": "tailwind.config.js",
"css": "src/index.css",
"baseColor": "zinc",
"cssVariables": true,
"prefix": ""
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
},
"iconLibrary": "lucide"
}
28 changes: 28 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import tseslint from 'typescript-eslint'

export default tseslint.config(
{ ignores: ['dist'] },
{
extends: [js.configs.recommended, ...tseslint.configs.recommended],
files: ['**/*.{ts,tsx}'],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
},
plugins: {
'react-hooks': reactHooks,
'react-refresh': reactRefresh,
},
rules: {
...reactHooks.configs.recommended.rules,
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
},
},
)
15 changes: 15 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<!doctype html>
<html lang="en">

<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>

<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>

</html>
Loading