Compare commits

...

2 commits

15 changed files with 372 additions and 668 deletions

10
.gram/debug.jsonc Normal file
View file

@ -0,0 +1,10 @@
[
{
"adapter": "JavaScript",
"type": "chrome",
"request": "attach",
"port": 9222,
"label": "Conectar a navegador",
"webRoot": "${GRAM_WORKTREE_ROOT}/src",
},
]

3
.gram/settings.jsonc Normal file
View file

@ -0,0 +1,3 @@
{
"language_servers": ["...", "!biome"],
}

4
.rumdl.toml Normal file
View file

@ -0,0 +1,4 @@
[global]
flavor = "gfm"
[MD013]
reflow = true

12
api-tests/profile.hurl Normal file
View file

@ -0,0 +1,12 @@
POST http://localhost:5000/api/auth/login
{
"email": "test@test.com",
"password": "123123"
}
HTTP 200
[Captures]
token: jsonpath "$.token"
GET http://localhost:5000/api/auth/me
Authorization: Bearer {{token}}
HTTP 200

View file

@ -1,94 +1,98 @@
# Simple API JWT # Simple API JWT
API para consumir un servicio de Auth con JWT. API para consumir un servicio de Auth con JWT.
## Instalación ## Instalación
```sh ```sh
npm install npm install
``` ```
## Uso ## Uso
```sh ```sh
npm run dev npm run dev
``` ```
## Endpoints ## Endpoints
### Pizzas ### Pizzas
```sh ```sh
GET /api/pizzas GET /api/pizzas
``` ```
### Pizza (única) ### Pizza (única)
```sh ```sh
GET /api/pizzas/:id GET /api/pizzas/:id
``` ```
### Auth ### Auth
```sh ```sh
POST /api/auth/login POST /api/auth/login
POST /api/auth/register POST /api/auth/register
``` ```
body: body:
```json ```json
{ {
"email": "test@example.com", "email": "test@example.com",
"password": "123123" "password": "123123"
} }
``` ```
### Checkout & Profile ### Checkout & Profile
Esta ruta requiere un token JWT en el header, el token se obtiene en el endpoint de Auth explicado en el item siguiente (JWT). Esta ruta requiere un token JWT en el header, el token se obtiene en el endpoint
de Auth explicado en el item siguiente (JWT).
Además puedes enviar un carrito con los productos a comprar, esto es solo una simulación, no se guarda en la base de datos.
Además puedes enviar un carrito con los productos a comprar, esto es solo una
```sh simulación, no se guarda en la base de datos.
POST /api/checkouts
``` ```sh
POST /api/checkouts
body: ```
```json body:
{
"cart": [...] ```json
} {
``` "cart": [...]
}
Endpoint para obtener el perfil del usuario autenticado. Necesitas enviar el token JWT en el header. ```
```sh Endpoint para obtener el perfil del usuario autenticado. Necesitas enviar el
GET /api/auth/me token JWT en el header.
```
```sh
## JWT GET /api/auth/me
```
Para obtener el token JWT, se debe hacer una petición a `/api/auth/login` o a `/api/auth/register` con el body correspondiente.
## JWT
El token JWT se debe enviar en el header `Authorization` de la siguiente manera:
Para obtener el token JWT, se debe hacer una petición a `/api/auth/login` o a
```sh `/api/auth/register` con el body correspondiente.
Authorization Bearer token_jwt
``` El token JWT se debe enviar en el header `Authorization` de la siguiente manera:
Ejemplo con fetch: ```sh
Authorization Bearer token_jwt
```js ```
await fetch("http://localhost:5000/api/checkout", {
method: "POST", Ejemplo con fetch:
headers: {
"Content-Type": "application/json", ```js
Authorization: `Bearer token_jwt`, await fetch("http://localhost:5000/api/checkout", {
}, method: "POST",
body: JSON.stringify({ headers: {
cart: carrito, "Content-Type": "application/json",
}), Authorization: `Bearer token_jwt`,
}); },
``` body: JSON.stringify({
cart: carrito,
}),
});
```

View file

@ -1,231 +0,0 @@
{
"$schema": "https://biomejs.dev/schemas/2.4.8/schema.json",
"vcs": { "enabled": true, "clientKind": "git", "useIgnoreFile": true },
"files": { "ignoreUnknown": false },
"formatter": { "enabled": true, "indentStyle": "tab" },
"linter": {
"enabled": true,
"rules": { "recommended": false },
"includes": ["**", "!dist"]
},
"javascript": { "formatter": { "quoteStyle": "double" } },
"overrides": [
{
"includes": ["**/*.{js,jsx}"],
"linter": {
"rules": {
"complexity": {
"noAdjacentSpacesInRegex": "error",
"noExtraBooleanCast": "error",
"noUselessCatch": "error",
"noUselessEscapeInRegex": "error"
},
"correctness": {
"noConstAssign": "error",
"noConstantCondition": "error",
"noEmptyCharacterClassInRegex": "error",
"noEmptyPattern": "error",
"noGlobalObjectCalls": "error",
"noInvalidBuiltinInstantiation": "error",
"noInvalidConstructorSuper": "error",
"noNonoctalDecimalEscape": "error",
"noPrecisionLoss": "error",
"noSelfAssign": "error",
"noSetterReturn": "error",
"noSwitchDeclarations": "error",
"noUndeclaredVariables": "error",
"noUnreachable": "error",
"noUnreachableSuper": "error",
"noUnsafeFinally": "error",
"noUnsafeOptionalChaining": "error",
"noUnusedLabels": "error",
"noUnusedPrivateClassMembers": "error",
"noUnusedVariables": "error",
"useIsNan": "error",
"useValidForDirection": "error",
"useValidTypeof": "error",
"useYield": "error"
},
"suspicious": {
"noAsyncPromiseExecutor": "error",
"noCatchAssign": "error",
"noClassAssign": "error",
"noCompareNegZero": "error",
"noConstantBinaryExpressions": "error",
"noControlCharactersInRegex": "error",
"noDebugger": "error",
"noDuplicateCase": "error",
"noDuplicateClassMembers": "error",
"noDuplicateElseIf": "error",
"noDuplicateObjectKeys": "error",
"noDuplicateParameters": "error",
"noEmptyBlockStatements": "error",
"noFallthroughSwitchClause": "error",
"noFunctionAssign": "error",
"noGlobalAssign": "error",
"noImportAssign": "error",
"noIrregularWhitespace": "error",
"noMisleadingCharacterClass": "error",
"noPrototypeBuiltins": "error",
"noRedeclare": "error",
"noShadowRestrictedNames": "error",
"noSparseArray": "error",
"noUnsafeNegation": "error",
"noUselessRegexBackrefs": "error",
"noWith": "error",
"useGetterReturn": "error"
}
}
}
},
{
"includes": ["**/*.{js,jsx}"],
"linter": {
"rules": {
"correctness": {
"useExhaustiveDependencies": "warn",
"useHookAtTopLevel": "error"
}
}
}
},
{ "includes": ["**/*.{js,jsx}"], "linter": { "rules": {} } },
{
"includes": ["**/*.{js,jsx}"],
"javascript": {
"globals": [
"onanimationend",
"ongamepadconnected",
"onlostpointercapture",
"onanimationiteration",
"onkeyup",
"onmousedown",
"onanimationstart",
"onslotchange",
"onprogress",
"ontransitionstart",
"onpause",
"onended",
"onpointerover",
"onscrollend",
"onformdata",
"ontransitionrun",
"onanimationcancel",
"ondrag",
"onchange",
"onbeforeinstallprompt",
"onbeforexrselect",
"onmessage",
"ontransitioncancel",
"onpointerdown",
"onabort",
"onpointerout",
"oncuechange",
"ongotpointercapture",
"onscrollsnapchanging",
"onsearch",
"onsubmit",
"onstalled",
"onsuspend",
"onreset",
"onerror",
"onmouseenter",
"ongamepaddisconnected",
"onresize",
"ondragover",
"onbeforetoggle",
"onmouseover",
"onpagehide",
"onmousemove",
"onratechange",
"oncommand",
"onmessageerror",
"onwheel",
"ondevicemotion",
"onauxclick",
"ontransitionend",
"onpaste",
"onpageswap",
"ononline",
"ondeviceorientationabsolute",
"onkeydown",
"onclose",
"onselect",
"onpageshow",
"onpointercancel",
"onbeforematch",
"onpointerrawupdate",
"ondragleave",
"onscrollsnapchange",
"onseeked",
"onwaiting",
"onbeforeunload",
"onplaying",
"onvolumechange",
"ondragend",
"onstorage",
"onloadeddata",
"onfocus",
"onoffline",
"onplay",
"onafterprint",
"onclick",
"oncut",
"onmouseout",
"ondblclick",
"oncanplay",
"onloadstart",
"onappinstalled",
"onpointermove",
"ontoggle",
"oncontextmenu",
"onblur",
"oncancel",
"onbeforeprint",
"oncontextrestored",
"onloadedmetadata",
"onpointerup",
"onlanguagechange",
"oncopy",
"onselectstart",
"onscroll",
"onload",
"ondragstart",
"onbeforeinput",
"oncanplaythrough",
"oninput",
"oninvalid",
"ontimeupdate",
"ondurationchange",
"onselectionchange",
"onmouseup",
"location",
"onkeypress",
"onpointerleave",
"oncontextlost",
"ondrop",
"onsecuritypolicyviolation",
"oncontentvisibilityautostatechange",
"ondeviceorientation",
"onseeking",
"onrejectionhandled",
"onunload",
"onmouseleave",
"onhashchange",
"onpointerenter",
"onmousewheel",
"onunhandledrejection",
"ondragenter",
"onpopstate",
"onpagereveal",
"onemptied"
]
},
"linter": { "rules": { "correctness": { "noUnusedVariables": "error" } } }
}
],
"assist": {
"enabled": true,
"actions": { "source": { "organizeImports": "on" } }
}
}

View file

@ -1,12 +1,15 @@
mise-task task: mise-task task:
mise r {{task}} mise r {{ task }}
setup: setup:
mise x -- aube i mise x -- aube i
cd backend && npm i cd backend && npm i
start-backend: start-backend:
cd backend && npm start cd backend && npm start
start-frontend: start-frontend:
mise r dev mise r dev
start:
@mprocs

View file

@ -2,10 +2,10 @@
aube = "latest" aube = "latest"
mprocs = "latest" mprocs = "latest"
oxlint = "latest" oxlint = "latest"
pitchfork = "latest"
pnpm = "latest" pnpm = "latest"
prek = "latest" prek = "latest"
oxfmt = "latest" oxfmt = "latest"
node = "24"
[tasks.dev] [tasks.dev]
description = "Arranca el servidor dev" description = "Arranca el servidor dev"

View file

@ -1,33 +1,35 @@
{ {
"name": "desafio", "name": "desafio",
"private": true, "version": "0.0.0",
"version": "0.0.0", "private": true,
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
"build": "vite build", "build": "vite build",
"lint": "biome check", "lint": "biome check",
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
"radashi": "^12.7.2", "@tanstack/react-form": "^1.32.0",
"react": "^19.2.4", "radashi": "^12.7.2",
"react-dom": "^19.2.4", "react": "^19.2.4",
"react-router-dom": "^7.14.2" "react-dom": "^19.2.4",
}, "react-router-dom": "^7.14.2",
"devDependencies": { "zod": "^4.4.3"
"@commitlint/cli": "^20.5.0", },
"@commitlint/config-conventional": "^20.5.0", "devDependencies": {
"@eslint/js": "^9.39.4", "@commitlint/cli": "^20.5.0",
"@types/react": "^19.2.14", "@commitlint/config-conventional": "^20.5.0",
"@types/react-dom": "^19.2.3", "@eslint/js": "^9.39.4",
"@unocss/reset": "^66.6.7", "@types/react": "^19.2.14",
"@vitejs/plugin-react": "^6.0.1", "@types/react-dom": "^19.2.3",
"eslint": "^9.39.4", "@unocss/reset": "^66.6.7",
"eslint-plugin-react-hooks": "^7.0.1", "@vitejs/plugin-react": "^6.0.1",
"eslint-plugin-react-refresh": "^0.5.2", "eslint": "^9.39.4",
"globals": "^17.4.0", "eslint-plugin-react-hooks": "^7.0.1",
"unocss": "^66.6.7", "eslint-plugin-react-refresh": "^0.5.2",
"vite": "^8.0.1" "globals": "^17.4.0",
} "unocss": "^66.6.7",
"vite": "^8.0.1"
}
} }

View file

@ -5,12 +5,23 @@ settings:
excludeLinksFromLockfile: false excludeLinksFromLockfile: false
time: time:
'@tanstack/devtools-event-client@0.4.3': 2026-03-11T13:42:37.747Z
'@tanstack/form-core@1.32.0': 2026-05-10T22:35:01.878Z
'@tanstack/pacer-lite@0.1.1': 2025-12-06T05:29:43.362Z
'@tanstack/react-form@1.32.0': 2026-05-10T22:35:03.027Z
'@tanstack/react-store@0.9.3': 2026-03-25T17:43:08.336Z
'@tanstack/store@0.9.3': 2026-03-25T17:43:08.346Z
radashi@12.7.2: 2026-02-24T20:32:30.146Z radashi@12.7.2: 2026-02-24T20:32:30.146Z
use-sync-external-store@1.6.0: 2025-10-01T21:39:12.499Z
zod@4.4.3: 2026-05-04T07:06:40.819Z
importers: importers:
.: .:
dependencies: dependencies:
'@tanstack/react-form':
specifier: ^1.32.0
version: 1.32.0(react@19.2.4)
'@types/node': '@types/node':
specifier: ^20.19.0 || >=22.12.0 specifier: ^20.19.0 || >=22.12.0
version: 25.6.0 version: 25.6.0
@ -29,6 +40,9 @@ importers:
react-router-dom: react-router-dom:
specifier: ^7.14.2 specifier: ^7.14.2
version: 7.14.2(react@19.2.4)(react-dom@19.2.4(react@19.2.4)) version: 7.14.2(react@19.2.4)(react-dom@19.2.4(react@19.2.4))
zod:
specifier: ^4.4.3
version: 4.4.3
devDependencies: devDependencies:
'@commitlint/cli': '@commitlint/cli':
specifier: ^20.5.0 specifier: ^20.5.0
@ -299,34 +313,6 @@ packages:
'@jridgewell/trace-mapping@0.3.31': '@jridgewell/trace-mapping@0.3.31':
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
'@oxc-parser/binding-darwin-arm64@0.115.0':
resolution: {integrity: sha512-ii/oOZjfGY1aszXTy29Z5DRyCEnBOrAXDVCvfdfXFQsOZlbbOa7NMHD7D+06YFe5qdxfmbWAYv4yn6QJi/0d2g==}
engines: {node: ^20.19.0 || >=22.12.0}
os:
- darwin
cpu:
- arm64
'@oxc-parser/binding-linux-arm64-gnu@0.115.0':
resolution: {integrity: sha512-1ej/MjuTY9tJEunU/hUPIFmgH5PqgMQoRjNOvOkibtJ3Zqlw/+Lc+HGHDNET8sjbgIkWzdhX+p4J96A5CPdbag==}
engines: {node: ^20.19.0 || >=22.12.0}
os:
- linux
cpu:
- arm64
libc:
- glibc
'@oxc-parser/binding-linux-arm64-musl@0.115.0':
resolution: {integrity: sha512-HjsZbJPH9mMd4swJRywVMsDZsJX0hyKb1iNHo5ijRl5yhtbO3lj7ImSrrL1oZ1VEg0te4iKmDGGz/6YPLd1G8w==}
engines: {node: ^20.19.0 || >=22.12.0}
os:
- linux
cpu:
- arm64
libc:
- musl
'@oxc-parser/binding-linux-x64-gnu@0.115.0': '@oxc-parser/binding-linux-x64-gnu@0.115.0':
resolution: {integrity: sha512-9iVX789DoC3SaOOG+X6NcF/tVChgLp2vcHffzOC2/Z1JTPlz6bMG2ogvcW6/9s0BG2qvhNQImd+gbWYeQbOwVw==} resolution: {integrity: sha512-9iVX789DoC3SaOOG+X6NcF/tVChgLp2vcHffzOC2/Z1JTPlz6bMG2ogvcW6/9s0BG2qvhNQImd+gbWYeQbOwVw==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
@ -337,32 +323,6 @@ packages:
libc: libc:
- glibc - glibc
'@oxc-parser/binding-linux-x64-musl@0.115.0':
resolution: {integrity: sha512-RmQmk+mjCB0nMNfEYhaCxwofLo1Z95ebHw1AGvRiWGCd4zhCNOyskgCbMogIcQzSB3SuEKWgkssyaiQYVAA4hQ==}
engines: {node: ^20.19.0 || >=22.12.0}
os:
- linux
cpu:
- x64
libc:
- musl
'@oxc-parser/binding-win32-arm64-msvc@0.115.0':
resolution: {integrity: sha512-/ym+Absk/TLFvbhh3se9XYuI1D7BrUVHw4RaG/2dmWKgBenrZHaJsgnRb7NJtaOyjEOLIPtULx1wDdVL0SX2eg==}
engines: {node: ^20.19.0 || >=22.12.0}
os:
- win32
cpu:
- arm64
'@oxc-parser/binding-win32-x64-msvc@0.115.0':
resolution: {integrity: sha512-oxUl82N+fIO9jIaXPph8SPPHQXrA08BHokBBJW8ct9F/x6o6bZE6eUAhUtWajbtvFhL8UYcCWRMba+kww6MBlA==}
engines: {node: ^20.19.0 || >=22.12.0}
os:
- win32
cpu:
- x64
'@oxc-project/types@0.115.0': '@oxc-project/types@0.115.0':
resolution: {integrity: sha512-4n91DKnebUS4yjUHl2g3/b2T+IUdCfmoZGhmwsovZCDaJSs+QkVAM+0AqqTxHSsHfeiMuueT75cZaZcT/m0pSw==} resolution: {integrity: sha512-4n91DKnebUS4yjUHl2g3/b2T+IUdCfmoZGhmwsovZCDaJSs+QkVAM+0AqqTxHSsHfeiMuueT75cZaZcT/m0pSw==}
@ -375,34 +335,6 @@ packages:
'@quansync/fs@1.0.0': '@quansync/fs@1.0.0':
resolution: {integrity: sha512-4TJ3DFtlf1L5LDMaM6CanJ/0lckGNtJcMjQ1NAV6zDmA0tEHKZtxNKin8EgPaVX1YzljbxckyT2tJrpQKAtngQ==} resolution: {integrity: sha512-4TJ3DFtlf1L5LDMaM6CanJ/0lckGNtJcMjQ1NAV6zDmA0tEHKZtxNKin8EgPaVX1YzljbxckyT2tJrpQKAtngQ==}
'@rolldown/binding-darwin-arm64@1.0.0-rc.11':
resolution: {integrity: sha512-7WQgR8SfOPwmDZGFkThUvsmd/nwAWv91oCO4I5LS7RKrssPZmOt7jONN0cW17ydGC1n/+puol1IpoieKqQidmg==}
engines: {node: ^20.19.0 || >=22.12.0}
os:
- darwin
cpu:
- arm64
'@rolldown/binding-linux-arm64-gnu@1.0.0-rc.11':
resolution: {integrity: sha512-WMW1yE6IOnehTcFE9eipFkm3XN63zypWlrJQ2iF7NrQ9b2LDRjumFoOGJE8RJJTJCTBAdmLMnJ8uVitACUUo1Q==}
engines: {node: ^20.19.0 || >=22.12.0}
os:
- linux
cpu:
- arm64
libc:
- glibc
'@rolldown/binding-linux-arm64-musl@1.0.0-rc.11':
resolution: {integrity: sha512-jfndI9tsfm4APzjNt6QdBkYwre5lRPUgHeDHoI7ydKUuJvz3lZeCfMsI56BZj+7BYqiKsJm7cfd/6KYV7ubrBg==}
engines: {node: ^20.19.0 || >=22.12.0}
os:
- linux
cpu:
- arm64
libc:
- musl
'@rolldown/binding-linux-x64-gnu@1.0.0-rc.11': '@rolldown/binding-linux-x64-gnu@1.0.0-rc.11':
resolution: {integrity: sha512-qXBQQO9OvkjjQPLdUVr7Nr2t3QTZI7s4KZtfw7HzBgjbmAPSFwSv4rmET9lLSgq3rH/ndA3ngv3Qb8l2njoPNA==} resolution: {integrity: sha512-qXBQQO9OvkjjQPLdUVr7Nr2t3QTZI7s4KZtfw7HzBgjbmAPSFwSv4rmET9lLSgq3rH/ndA3ngv3Qb8l2njoPNA==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
@ -413,32 +345,6 @@ packages:
libc: libc:
- glibc - glibc
'@rolldown/binding-linux-x64-musl@1.0.0-rc.11':
resolution: {integrity: sha512-/tpFfoSTzUkH9LPY+cYbqZBDyyX62w5fICq9qzsHLL8uTI6BHip3Q9Uzft0wylk/i8OOwKik8OxW+QAhDmzwmg==}
engines: {node: ^20.19.0 || >=22.12.0}
os:
- linux
cpu:
- x64
libc:
- musl
'@rolldown/binding-win32-arm64-msvc@1.0.0-rc.11':
resolution: {integrity: sha512-dDwf5otnx0XgRY1yqxOC4ITizcdzS/8cQ3goOWv3jFAo4F+xQYni+hnMuO6+LssHHdJW7+OCVL3CoU4ycnh35Q==}
engines: {node: ^20.19.0 || >=22.12.0}
os:
- win32
cpu:
- arm64
'@rolldown/binding-win32-x64-msvc@1.0.0-rc.11':
resolution: {integrity: sha512-LN4/skhSggybX71ews7dAj6r2geaMJfm3kMbK2KhFMg9B10AZXnKoLCVVgzhMHL0S+aKtr4p8QbAW8k+w95bAA==}
engines: {node: ^20.19.0 || >=22.12.0}
os:
- win32
cpu:
- x64
'@rolldown/pluginutils@1.0.0-rc.11': '@rolldown/pluginutils@1.0.0-rc.11':
resolution: {integrity: sha512-xQO9vbwBecJRv9EUcQ/y0dzSTJgA7Q6UVN7xp6B81+tBGSLVAK03yJ9NkJaUA7JFD91kbjxRSC/mDnmvXzbHoQ==} resolution: {integrity: sha512-xQO9vbwBecJRv9EUcQ/y0dzSTJgA7Q6UVN7xp6B81+tBGSLVAK03yJ9NkJaUA7JFD91kbjxRSC/mDnmvXzbHoQ==}
@ -453,6 +359,35 @@ packages:
resolution: {integrity: sha512-KxXvfapcixpz6rVEB6HPjOUZT22yN6v0vI0urQSk1L8MlEWPDFCZkhw2xmkyoTGYeFw7tWTZd7e3lVzRZRN/EA==} resolution: {integrity: sha512-KxXvfapcixpz6rVEB6HPjOUZT22yN6v0vI0urQSk1L8MlEWPDFCZkhw2xmkyoTGYeFw7tWTZd7e3lVzRZRN/EA==}
engines: {node: '>=18'} engines: {node: '>=18'}
'@tanstack/devtools-event-client@0.4.3':
resolution: {integrity: sha512-OZI6QyULw0FI0wjgmeYzCIfbgPsOEzwJtCpa69XrfLMtNXLGnz3d/dIabk7frg0TmHo+Ah49w5I4KC7Tufwsvw==}
engines: {node: '>=18'}
hasBin: true
'@tanstack/form-core@1.32.0':
resolution: {integrity: sha512-Tn5VRDSjyqjmaet2tJMuEWDRFyrCaon03vxXPlSSaiSs6C/N7lCIwGCXJbZXEUq1kTj8jYN9qyXHbsz4LQHcow==}
'@tanstack/pacer-lite@0.1.1':
resolution: {integrity: sha512-y/xtNPNt/YeyoVxE/JCx+T7yjEzpezmbb+toK8DDD1P4m7Kzs5YR956+7OKexG3f8aXgC3rLZl7b1V+yNUSy5w==}
engines: {node: '>=18'}
'@tanstack/react-form@1.32.0':
resolution: {integrity: sha512-6WP5SQTA6/H9crCpvpq3ZppYWqtrdE5NjOy6ebABi6uAQPqhfTzrdjS9t40mCZCFtGI5585OhJV6zBP/KN2zcw==}
peerDependencies:
react: ^17.0.0 || ^18.0.0 || ^19.0.0
peerDependenciesMeta:
'@tanstack/react-start':
optional: true
'@tanstack/react-store@0.9.3':
resolution: {integrity: sha512-y2iHd/N9OkoQbFJLUX1T9vbc2O9tjH0pQRgTcx1/Nz4IlwLvkgpuglXUx+mXt0g5ZDFrEeDnONPqkbfxXJKwRg==}
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
'@tanstack/store@0.9.3':
resolution: {integrity: sha512-8reSzl/qGWGGVKhBoxXPMWzATSbZLZFWhwBAFO9NAyp0TxzfBP0mIrGb8CP8KrQTmvzXlR/vFPPUrHTLBGyFyw==}
'@types/estree@1.0.8': '@types/estree@1.0.8':
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
@ -837,12 +772,6 @@ packages:
flatted@3.4.2: flatted@3.4.2:
resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==}
fsevents@2.3.3:
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os:
- darwin
gensync@1.0.0-beta.2: gensync@1.0.0-beta.2:
resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
@ -974,34 +903,6 @@ packages:
resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
engines: {node: '>= 0.8.0'} engines: {node: '>= 0.8.0'}
lightningcss-darwin-arm64@1.32.0:
resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==}
engines: {node: '>= 12.0.0'}
os:
- darwin
cpu:
- arm64
lightningcss-linux-arm64-gnu@1.32.0:
resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==}
engines: {node: '>= 12.0.0'}
os:
- linux
cpu:
- arm64
libc:
- glibc
lightningcss-linux-arm64-musl@1.32.0:
resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==}
engines: {node: '>= 12.0.0'}
os:
- linux
cpu:
- arm64
libc:
- musl
lightningcss-linux-x64-gnu@1.32.0: lightningcss-linux-x64-gnu@1.32.0:
resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==}
engines: {node: '>= 12.0.0'} engines: {node: '>= 12.0.0'}
@ -1012,32 +913,6 @@ packages:
libc: libc:
- glibc - glibc
lightningcss-linux-x64-musl@1.32.0:
resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==}
engines: {node: '>= 12.0.0'}
os:
- linux
cpu:
- x64
libc:
- musl
lightningcss-win32-arm64-msvc@1.32.0:
resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==}
engines: {node: '>= 12.0.0'}
os:
- win32
cpu:
- arm64
lightningcss-win32-x64-msvc@1.32.0:
resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==}
engines: {node: '>= 12.0.0'}
os:
- win32
cpu:
- x64
lightningcss@1.32.0: lightningcss@1.32.0:
resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==}
engines: {node: '>= 12.0.0'} engines: {node: '>= 12.0.0'}
@ -1364,6 +1239,11 @@ packages:
uri-js@4.4.1: uri-js@4.4.1:
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
use-sync-external-store@1.6.0:
resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==}
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
vite@8.0.2: vite@8.0.2:
resolution: {integrity: sha512-1gFhNi+bHhRE/qKZOJXACm6tX4bA3Isy9KuKF15AgSRuRazNBOJfdDemPBU16/mpMxApDPrWvZ08DcLPEoRnuA==} resolution: {integrity: sha512-1gFhNi+bHhRE/qKZOJXACm6tX4bA3Isy9KuKF15AgSRuRazNBOJfdDemPBU16/mpMxApDPrWvZ08DcLPEoRnuA==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
@ -1451,6 +1331,9 @@ packages:
zod@4.3.6: zod@4.3.6:
resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==}
zod@4.4.3:
resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==}
snapshots: snapshots:
'@antfu/install-pkg@1.1.0': '@antfu/install-pkg@1.1.0':
@ -1764,27 +1647,9 @@ snapshots:
'@jridgewell/resolve-uri': 3.1.2 '@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.5.5 '@jridgewell/sourcemap-codec': 1.5.5
'@oxc-parser/binding-darwin-arm64@0.115.0':
optional: true
'@oxc-parser/binding-linux-arm64-gnu@0.115.0':
optional: true
'@oxc-parser/binding-linux-arm64-musl@0.115.0':
optional: true
'@oxc-parser/binding-linux-x64-gnu@0.115.0': '@oxc-parser/binding-linux-x64-gnu@0.115.0':
optional: true optional: true
'@oxc-parser/binding-linux-x64-musl@0.115.0':
optional: true
'@oxc-parser/binding-win32-arm64-msvc@0.115.0':
optional: true
'@oxc-parser/binding-win32-x64-msvc@0.115.0':
optional: true
'@oxc-project/types@0.115.0': {} '@oxc-project/types@0.115.0': {}
'@oxc-project/types@0.122.0': {} '@oxc-project/types@0.122.0': {}
@ -1795,27 +1660,9 @@ snapshots:
dependencies: dependencies:
quansync: 1.0.0 quansync: 1.0.0
'@rolldown/binding-darwin-arm64@1.0.0-rc.11':
optional: true
'@rolldown/binding-linux-arm64-gnu@1.0.0-rc.11':
optional: true
'@rolldown/binding-linux-arm64-musl@1.0.0-rc.11':
optional: true
'@rolldown/binding-linux-x64-gnu@1.0.0-rc.11': '@rolldown/binding-linux-x64-gnu@1.0.0-rc.11':
optional: true optional: true
'@rolldown/binding-linux-x64-musl@1.0.0-rc.11':
optional: true
'@rolldown/binding-win32-arm64-msvc@1.0.0-rc.11':
optional: true
'@rolldown/binding-win32-x64-msvc@1.0.0-rc.11':
optional: true
'@rolldown/pluginutils@1.0.0-rc.11': {} '@rolldown/pluginutils@1.0.0-rc.11': {}
'@rolldown/pluginutils@1.0.0-rc.7': {} '@rolldown/pluginutils@1.0.0-rc.7': {}
@ -1826,6 +1673,31 @@ snapshots:
'@simple-libs/stream-utils@1.2.0': {} '@simple-libs/stream-utils@1.2.0': {}
'@tanstack/devtools-event-client@0.4.3': {}
'@tanstack/form-core@1.32.0':
dependencies:
'@tanstack/devtools-event-client': 0.4.3
'@tanstack/pacer-lite': 0.1.1
'@tanstack/store': 0.9.3
'@tanstack/pacer-lite@0.1.1': {}
'@tanstack/react-form@1.32.0(react@19.2.4)':
dependencies:
'@tanstack/form-core': 1.32.0
'@tanstack/react-store': 0.9.3(react@19.2.4)(react-dom@19.2.4(react@19.2.4))
react: 19.2.4
'@tanstack/react-store@0.9.3(react@19.2.4)(react-dom@19.2.4(react@19.2.4))':
dependencies:
'@tanstack/store': 0.9.3
react: 19.2.4
react-dom: 19.2.4(react@19.2.4)
use-sync-external-store: 1.6.0(react@19.2.4)
'@tanstack/store@0.9.3': {}
'@types/estree@1.0.8': {} '@types/estree@1.0.8': {}
'@types/json-schema@7.0.15': {} '@types/json-schema@7.0.15': {}
@ -2259,9 +2131,6 @@ snapshots:
flatted@3.4.2: {} flatted@3.4.2: {}
fsevents@2.3.3:
optional: true
gensync@1.0.0-beta.2: {} gensync@1.0.0-beta.2: {}
get-caller-file@2.0.5: {} get-caller-file@2.0.5: {}
@ -2358,38 +2227,14 @@ snapshots:
prelude-ls: 1.2.1 prelude-ls: 1.2.1
type-check: 0.4.0 type-check: 0.4.0
lightningcss-darwin-arm64@1.32.0:
optional: true
lightningcss-linux-arm64-gnu@1.32.0:
optional: true
lightningcss-linux-arm64-musl@1.32.0:
optional: true
lightningcss-linux-x64-gnu@1.32.0: lightningcss-linux-x64-gnu@1.32.0:
optional: true optional: true
lightningcss-linux-x64-musl@1.32.0:
optional: true
lightningcss-win32-arm64-msvc@1.32.0:
optional: true
lightningcss-win32-x64-msvc@1.32.0:
optional: true
lightningcss@1.32.0: lightningcss@1.32.0:
dependencies: dependencies:
detect-libc: 2.1.2 detect-libc: 2.1.2
optionalDependencies: optionalDependencies:
lightningcss-darwin-arm64: 1.32.0
lightningcss-linux-arm64-gnu: 1.32.0
lightningcss-linux-arm64-musl: 1.32.0
lightningcss-linux-x64-gnu: 1.32.0 lightningcss-linux-x64-gnu: 1.32.0
lightningcss-linux-x64-musl: 1.32.0
lightningcss-win32-arm64-msvc: 1.32.0
lightningcss-win32-x64-msvc: 1.32.0
lines-and-columns@1.2.4: {} lines-and-columns@1.2.4: {}
@ -2477,13 +2322,7 @@ snapshots:
dependencies: dependencies:
'@oxc-project/types': 0.115.0 '@oxc-project/types': 0.115.0
optionalDependencies: optionalDependencies:
'@oxc-parser/binding-darwin-arm64': 0.115.0
'@oxc-parser/binding-linux-arm64-gnu': 0.115.0
'@oxc-parser/binding-linux-arm64-musl': 0.115.0
'@oxc-parser/binding-linux-x64-gnu': 0.115.0 '@oxc-parser/binding-linux-x64-gnu': 0.115.0
'@oxc-parser/binding-linux-x64-musl': 0.115.0
'@oxc-parser/binding-win32-arm64-msvc': 0.115.0
'@oxc-parser/binding-win32-x64-msvc': 0.115.0
oxc-walker@0.7.0(oxc-parser@0.115.0): oxc-walker@0.7.0(oxc-parser@0.115.0):
dependencies: dependencies:
@ -2581,13 +2420,7 @@ snapshots:
'@oxc-project/types': 0.122.0 '@oxc-project/types': 0.122.0
'@rolldown/pluginutils': 1.0.0-rc.11 '@rolldown/pluginutils': 1.0.0-rc.11
optionalDependencies: optionalDependencies:
'@rolldown/binding-darwin-arm64': 1.0.0-rc.11
'@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.11
'@rolldown/binding-linux-arm64-musl': 1.0.0-rc.11
'@rolldown/binding-linux-x64-gnu': 1.0.0-rc.11 '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.11
'@rolldown/binding-linux-x64-musl': 1.0.0-rc.11
'@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.11
'@rolldown/binding-win32-x64-msvc': 1.0.0-rc.11
scheduler@0.27.0: {} scheduler@0.27.0: {}
@ -2705,6 +2538,10 @@ snapshots:
dependencies: dependencies:
punycode: 2.3.1 punycode: 2.3.1
use-sync-external-store@1.6.0(react@19.2.4):
dependencies:
react: 19.2.4
vite@8.0.2(@types/node@25.6.0)(jiti@2.6.1): vite@8.0.2(@types/node@25.6.0)(jiti@2.6.1):
dependencies: dependencies:
lightningcss: 1.32.0 lightningcss: 1.32.0
@ -2714,7 +2551,6 @@ snapshots:
tinyglobby: 0.2.15 tinyglobby: 0.2.15
optionalDependencies: optionalDependencies:
'@types/node': 25.6.0 '@types/node': 25.6.0
fsevents: 2.3.3
jiti: 2.6.1 jiti: 2.6.1
webpack-virtual-modules@0.6.2: {} webpack-virtual-modules@0.6.2: {}
@ -2754,3 +2590,5 @@ snapshots:
zod: 4.3.6 zod: 4.3.6
zod@4.3.6: {} zod@4.3.6: {}
zod@4.4.3: {}

View file

@ -1,7 +1,7 @@
[[repos]] [[repos]]
hooks = [ hooks = [
{ id = "commitlint", name = "commitlint", language = "system", entry = "mise x -- aubx commitlint -e", stages = [ { id = "commitlint", name = "commitlint", language = "system", entry = "mise x -- aubx commitlint -e", stages = [
"commit-msg", "commit-msg",
] }, ] },
] ]
repo = "local" repo = "local"

View file

@ -9,7 +9,7 @@ const UserProvider = ({ children }) => {
const storeData = (email, token) => { const storeData = (email, token) => {
setEmail(email); setEmail(email);
setToken(token); setToken(token);
localStorage.setItem("loginToken", data.token); localStorage.setItem("loginToken", token);
}; };
const login = async (user, password) => { const login = async (user, password) => {
const res = await fetch("http://localhost:5000/api/auth/login", { const res = await fetch("http://localhost:5000/api/auth/login", {
@ -40,8 +40,29 @@ const UserProvider = ({ children }) => {
setToken(null); setToken(null);
setEmail(null); setEmail(null);
}; };
const getProfile = async () => {
const res = await fetch("http://localhost:5000/api/auth/me", {
headers: { Authorization: `Bearer ${token}` },
});
if (!res.ok) {
throw new Error("Error al obtener perfil", res.status);
}
const data = await res.json();
return data;
};
return ( return (
<UserContext.Provider value={{ token, setToken, email, setEmail, login, register, logout }}> <UserContext.Provider
value={{
token,
setToken,
email,
setEmail,
login,
register,
getProfile,
logout,
}}
>
{children} {children}
</UserContext.Provider> </UserContext.Provider>
); );

View file

@ -1,65 +1,89 @@
import { useContext, useState } from "react"; import { useContext, useState } from "react";
import { CartContext } from "../context/CartContext"; import { CartContext } from "../context/CartContext";
import { pizzaCart } from "../pizzas";
import { UserContext } from "../context/UserContext"; import { UserContext } from "../context/UserContext";
const Cart = () => { const Cart = () => {
const { token } = useContext(UserContext); const { token } = useContext(UserContext);
const { cart, setCart } = useContext(CartContext); const { cart, setCart, getTotal } = useContext(CartContext);
const [success, setSuccess] = useState(false);
return ( return (
<> <>
<h1 className="text-4xl font-bold">Carrito</h1> <h1 className="text-4xl font-bold">Carrito</h1>
<div id="cartContainer" className="flex gap-4 flex-col"> {!success ? (
{cart.map((pizza) => ( <>
<div <div id="cartContainer" className="flex gap-4 flex-col">
className="border-3 border-lime-300 rounded-md flex gap-4 overflow-hidden" {cart.map((pizza) => (
key={pizza.id} <div
> className="border-3 border-lime-300 rounded-md flex gap-4 overflow-hidden"
<img src={pizza.img} className="w-32 rounded-r-sm" /> key={pizza.id}
<div> >
<h2>Pizza {pizza.name}</h2> <img src={pizza.img} className="w-32 rounded-r-sm" />
<div className="flex gap-4"> <div>
<button <h2>Pizza {pizza.name}</h2>
onClick={() => { <div className="flex gap-4">
setCart((cart) => <button
cart.map((p) => (p.id === pizza.id ? { ...p, count: p.count + 1 } : p)), onClick={() => {
); setCart((cart) =>
}} cart.map((p) =>
className="bg-blue-500 px-4 text-white rounded-md" p.id === pizza.id
> ? { ...p, count: p.count + 1 }
+ : p,
</button> ),
<p className="text-grey-500">{pizza.count}</p> );
<button }}
onClick={() => { className="bg-blue-500 px-4 text-white rounded-md"
setCart((cart) => >
cart +
.map((p) => (p.id === pizza.id ? { ...p, count: p.count - 1 } : p)) </button>
.filter((p) => p.count > 0), <p className="text-grey-500">{pizza.count}</p>
); <button
}} onClick={() => {
className="bg-red-500 px-4 text-white rounded-md" setCart((cart) =>
> cart
- .map((p) =>
</button> p.id === pizza.id
? { ...p, count: p.count - 1 }
: p,
)
.filter((p) => p.count > 0),
);
}}
className="bg-red-500 px-4 text-white rounded-md"
>
-
</button>
</div>
</div>
</div> </div>
</div> ))}
<p className="text-3xl">
Total:
<strong>{` $${getTotal().toLocaleString("es-CL")}`}</strong>
</p>
</div> </div>
))} <button
<p className="text-3xl"> type="button"
Total: disabled={!token}
<strong> className="bg-black text-white rounded-md p-2 text-lg hover:bg-gray-500 disabled:bg-gray-200"
{` $${cart.reduce((acc, it) => acc + it.price * it.count, 0).toLocaleString("es-CL")}`} onClick={async () => {
</strong> const res = await fetch("http://localhost:5000/api/checkouts", {
</p> method: "POST",
</div> headers: { Authorization: `Bearer ${token}` },
<button body: JSON.stringify({ cart }),
type="submit" });
disabled={!token} if (!res.ok) {
className="bg-black text-white rounded-md p-2 text-lg hover:bg-gray-500 disabled:bg-gray-200" console.error(res);
> return;
Pagar }
</button> setSuccess(true);
}}
>
Pagar
</button>
</>
) : (
<p class="text-4xl text-teal-500">¡Compra hecha con éxito!</p>
)}
</> </>
); );
}; };

View file

@ -4,12 +4,15 @@ import { useContext } from "react";
// Librería recomendada en tutoría // Librería recomendada en tutoría
import { z } from "zod"; import { z } from "zod";
import { UserContext } from "../context/UserContext"; import { UserContext } from "../context/UserContext";
import { useNavigate } from "react-router-dom";
// Esquema de validación de login // Esquema de validación de login
const loginSchema = z.object({ const loginSchema = z.object({
user: z.email({ error: "Email inválido" }).nonempty({ error: "Se requiere un email" }), user: z
password: z.string().min(6, { error: "La contraseña debe tener al menos 6 caracteres" }), .email({ error: "Email inválido" })
.nonempty({ error: "Se requiere un email" }),
password: z
.string()
.min(6, { error: "La contraseña debe tener al menos 6 caracteres" }),
}); });
const Login = () => { const Login = () => {
@ -21,6 +24,7 @@ const Login = () => {
try { try {
await login(user, password); await login(user, password);
} catch (error) { } catch (error) {
console.error(error);
alert("Error de login"); alert("Error de login");
} }
}, },

View file

@ -1,9 +1,19 @@
import { useContext } from "react"; import { useContext, useState } from "react";
import { UserContext } from "../context/UserContext"; import { UserContext } from "../context/UserContext";
import { useEffect } from "react";
const Profile = () => { const Profile = () => {
const email = "test@example.com"; const [email, setEmail] = useState("");
const { logout } = useContext(UserContext); const { getProfile, logout } = useContext(UserContext);
useEffect(() => {
getProfile()
.then((data) => {
setEmail(data.email);
})
.catch((error) => {
console.error(error);
});
});
return ( return (
<div> <div>
<p> <p>