hecha tarea
This commit is contained in:
22
bun.lock
22
bun.lock
@@ -4,9 +4,11 @@
|
||||
"": {
|
||||
"name": "test",
|
||||
"dependencies": {
|
||||
"@reduxjs/toolkit": "^2.9.2",
|
||||
"@tailwindcss/vite": "^4.1.15",
|
||||
"react": "^19.1.1",
|
||||
"react-dom": "^19.1.1",
|
||||
"react-redux": "^9.2.0",
|
||||
"react-router": "^7.9.4",
|
||||
"react-router-dom": "^7.9.4",
|
||||
"tailwindcss": "^4.1.15",
|
||||
@@ -124,6 +126,8 @@
|
||||
|
||||
"@oxc-project/types": ["@oxc-project/types@0.93.0", "", {}, "sha512-yNtwmWZIBtJsMr5TEfoZFDxIWV6OdScOpza/f5YxbqUMJk+j6QX3Cf3jgZShGEFYWQJ5j9mJ6jM0tZHu2J9Yrg=="],
|
||||
|
||||
"@reduxjs/toolkit": ["@reduxjs/toolkit@2.9.2", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "@standard-schema/utils": "^0.3.0", "immer": "^10.0.3", "redux": "^5.0.1", "redux-thunk": "^3.1.0", "reselect": "^5.1.0" }, "peerDependencies": { "react": "^16.9.0 || ^17.0.0 || ^18 || ^19", "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" }, "optionalPeers": ["react", "react-redux"] }, "sha512-ZAYu/NXkl/OhqTz7rfPaAhY0+e8Fr15jqNxte/2exKUxvHyQ/hcqmdekiN1f+Lcw3pE+34FCgX+26zcUE3duCg=="],
|
||||
|
||||
"@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.0.0-beta.41", "", { "os": "android", "cpu": "arm64" }, "sha512-Edflndd9lU7JVhVIvJlZhdCj5DkhYDJPIRn4Dx0RUdfc8asP9xHOI5gMd8MesDDx+BJpdIT/uAmVTearteU/mQ=="],
|
||||
|
||||
"@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.0.0-beta.41", "", { "os": "darwin", "cpu": "arm64" }, "sha512-XGCzqfjdk7550PlyZRTBKbypXrB7ATtXhw/+bjtxnklLQs0mKP/XkQVOKyn9qGKSlvH8I56JLYryVxl0PCvSNw=="],
|
||||
@@ -154,6 +158,10 @@
|
||||
|
||||
"@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.38", "", {}, "sha512-N/ICGKleNhA5nc9XXQG/kkKHJ7S55u0x0XUJbbkmdCnFuoRkM1Il12q9q0eX19+M7KKUEPw/daUPIRnxhcxAIw=="],
|
||||
|
||||
"@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="],
|
||||
|
||||
"@standard-schema/utils": ["@standard-schema/utils@0.3.0", "", {}, "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g=="],
|
||||
|
||||
"@tailwindcss/node": ["@tailwindcss/node@4.1.15", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "enhanced-resolve": "^5.18.3", "jiti": "^2.6.0", "lightningcss": "1.30.2", "magic-string": "^0.30.19", "source-map-js": "^1.2.1", "tailwindcss": "4.1.15" } }, "sha512-HF4+7QxATZWY3Jr8OlZrBSXmwT3Watj0OogeDvdUY/ByXJHQ+LBtqA2brDb3sBxYslIFx6UP94BJ4X6a4L9Bmw=="],
|
||||
|
||||
"@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.15", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.15", "@tailwindcss/oxide-darwin-arm64": "4.1.15", "@tailwindcss/oxide-darwin-x64": "4.1.15", "@tailwindcss/oxide-freebsd-x64": "4.1.15", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.15", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.15", "@tailwindcss/oxide-linux-arm64-musl": "4.1.15", "@tailwindcss/oxide-linux-x64-gnu": "4.1.15", "@tailwindcss/oxide-linux-x64-musl": "4.1.15", "@tailwindcss/oxide-wasm32-wasi": "4.1.15", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.15", "@tailwindcss/oxide-win32-x64-msvc": "4.1.15" } }, "sha512-krhX+UOOgnsUuks2SR7hFafXmLQrKxB4YyRTERuCE59JlYL+FawgaAlSkOYmDRJdf1Q+IFNDMl9iRnBW7QBDfQ=="],
|
||||
@@ -204,6 +212,8 @@
|
||||
|
||||
"@types/react-dom": ["@types/react-dom@19.2.2", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw=="],
|
||||
|
||||
"@types/use-sync-external-store": ["@types/use-sync-external-store@0.0.6", "", {}, "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg=="],
|
||||
|
||||
"@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.46.1", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.46.1", "@typescript-eslint/type-utils": "8.46.1", "@typescript-eslint/utils": "8.46.1", "@typescript-eslint/visitor-keys": "8.46.1", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.46.1", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-rUsLh8PXmBjdiPY+Emjz9NX2yHvhS11v0SR6xNJkm5GM1MO9ea/1GoDKlHHZGrOJclL/cZ2i/vRUYVtjRhrHVQ=="],
|
||||
|
||||
"@typescript-eslint/parser": ["@typescript-eslint/parser@8.46.1", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.46.1", "@typescript-eslint/types": "8.46.1", "@typescript-eslint/typescript-estree": "8.46.1", "@typescript-eslint/visitor-keys": "8.46.1", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-6JSSaBZmsKvEkbRUkf7Zj7dru/8ZCrJxAqArcLaVMee5907JdtEbKGsZ7zNiIm/UAkpGUkaSMZEXShnN2D1HZA=="],
|
||||
@@ -342,6 +352,8 @@
|
||||
|
||||
"ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="],
|
||||
|
||||
"immer": ["immer@10.2.0", "", {}, "sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw=="],
|
||||
|
||||
"import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="],
|
||||
|
||||
"imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="],
|
||||
@@ -448,12 +460,20 @@
|
||||
|
||||
"react-dom": ["react-dom@19.2.0", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.0" } }, "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ=="],
|
||||
|
||||
"react-redux": ["react-redux@9.2.0", "", { "dependencies": { "@types/use-sync-external-store": "^0.0.6", "use-sync-external-store": "^1.4.0" }, "peerDependencies": { "@types/react": "^18.2.25 || ^19", "react": "^18.0 || ^19", "redux": "^5.0.0" }, "optionalPeers": ["@types/react", "redux"] }, "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g=="],
|
||||
|
||||
"react-refresh": ["react-refresh@0.17.0", "", {}, "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ=="],
|
||||
|
||||
"react-router": ["react-router@7.9.4", "", { "dependencies": { "cookie": "^1.0.1", "set-cookie-parser": "^2.6.0" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" }, "optionalPeers": ["react-dom"] }, "sha512-SD3G8HKviFHg9xj7dNODUKDFgpG4xqD5nhyd0mYoB5iISepuZAvzSr8ywxgxKJ52yRzf/HWtVHc9AWwoTbljvA=="],
|
||||
|
||||
"react-router-dom": ["react-router-dom@7.9.4", "", { "dependencies": { "react-router": "7.9.4" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" } }, "sha512-f30P6bIkmYvnHHa5Gcu65deIXoA2+r3Eb6PJIAddvsT9aGlchMatJ51GgpU470aSqRRbFX22T70yQNUGuW3DfA=="],
|
||||
|
||||
"redux": ["redux@5.0.1", "", {}, "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w=="],
|
||||
|
||||
"redux-thunk": ["redux-thunk@3.1.0", "", { "peerDependencies": { "redux": "^5.0.0" } }, "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw=="],
|
||||
|
||||
"reselect": ["reselect@5.1.1", "", {}, "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w=="],
|
||||
|
||||
"resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="],
|
||||
|
||||
"reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="],
|
||||
@@ -502,6 +522,8 @@
|
||||
|
||||
"uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="],
|
||||
|
||||
"use-sync-external-store": ["use-sync-external-store@1.6.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w=="],
|
||||
|
||||
"vite": ["rolldown-vite@7.1.14", "", { "dependencies": { "@oxc-project/runtime": "0.92.0", "fdir": "^6.5.0", "lightningcss": "^1.30.1", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rolldown": "1.0.0-beta.41", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "esbuild": "^0.25.0", "jiti": ">=1.21.0", "less": "^4.0.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "esbuild", "jiti", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-eSiiRJmovt8qDJkGyZuLnbxAOAdie6NCmmd0NkTC0RJI9duiSBTfr8X2mBYJOUFzxQa2USaHmL99J9uMxkjCyw=="],
|
||||
|
||||
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
|
||||
|
||||
@@ -10,9 +10,11 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@reduxjs/toolkit": "^2.9.2",
|
||||
"@tailwindcss/vite": "^4.1.15",
|
||||
"react": "^19.1.1",
|
||||
"react-dom": "^19.1.1",
|
||||
"react-redux": "^9.2.0",
|
||||
"react-router": "^7.9.4",
|
||||
"react-router-dom": "^7.9.4",
|
||||
"tailwindcss": "^4.1.15"
|
||||
|
||||
@@ -7,7 +7,7 @@ import { Seccion } from "./Components/Seccion";
|
||||
import type { PermissionLevel } from "./types/usuario";
|
||||
|
||||
function App() {
|
||||
const { usuario, setPermissionLevel, setUsuario } = useUsuario();
|
||||
const { usuario, setPermissionLevel } = useUsuario();
|
||||
return (
|
||||
<>
|
||||
<Navbar>
|
||||
@@ -17,7 +17,9 @@ function App() {
|
||||
<Link to="/admin">Admin</Link>
|
||||
)}
|
||||
<Link to="/productos">productos</Link>
|
||||
<Link to="/counter">contador</Link>
|
||||
<Link to="/about">About</Link>
|
||||
{usuario !== null && <Link to="/logout">Cerrar Sesion</Link>}
|
||||
</Seccion>
|
||||
<Seccion>
|
||||
El permiso el usuario es:
|
||||
@@ -33,7 +35,7 @@ function App() {
|
||||
</select>
|
||||
</Seccion>
|
||||
</Navbar>
|
||||
<AppRouter usuario={usuario} setUsuario={setUsuario} />
|
||||
<AppRouter />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
24
src/Components/AboutPage.tsx
Normal file
24
src/Components/AboutPage.tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
import { useUsuario } from "../services/useUsuario";
|
||||
|
||||
export function AboutPage() {
|
||||
const { usuario } = useUsuario();
|
||||
return (
|
||||
<>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Email</th>
|
||||
<th>Username</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{usuario?.email}</td>
|
||||
<td>{usuario?.username}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<ul></ul>
|
||||
</>
|
||||
);
|
||||
}
|
||||
35
src/Components/CounterPage.tsx
Normal file
35
src/Components/CounterPage.tsx
Normal file
@@ -0,0 +1,35 @@
|
||||
import { useState } from "react";
|
||||
import { useCounter } from "../services/useCounter";
|
||||
|
||||
export function CounterPage() {
|
||||
const [salto, setSalto] = useState(0);
|
||||
const { decrement, value, increment, decrementByAmount, incrementByAmount } =
|
||||
useCounter();
|
||||
|
||||
return (
|
||||
<>
|
||||
<h1>{value}</h1>
|
||||
<div className="flex gap-1 justify-center">
|
||||
<button onClick={() => incrementByAmount(salto)}> + {salto}</button>
|
||||
<button onClick={() => increment()}> +1 </button>
|
||||
<button onClick={() => decrement()}> -1 </button>
|
||||
<button onClick={() => decrementByAmount(salto)}> - {salto}</button>
|
||||
</div>
|
||||
<hr />
|
||||
<div className="flex gap-2">
|
||||
<p className="font-bold"> Aumentar por: </p>
|
||||
<input
|
||||
type="number"
|
||||
onInput={(e) => {
|
||||
e.currentTarget.value = e.currentTarget.value.replace(
|
||||
/[^0-9]/g,
|
||||
"",
|
||||
);
|
||||
}}
|
||||
onChange={(e) => setSalto(Number(e.target.value))}
|
||||
min={0}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
7
src/Components/LogOut.tsx
Normal file
7
src/Components/LogOut.tsx
Normal file
@@ -0,0 +1,7 @@
|
||||
import { useUsuario } from "../services/useUsuario";
|
||||
|
||||
export function LogOut() {
|
||||
const { logOut } = useUsuario();
|
||||
logOut();
|
||||
return <></>;
|
||||
}
|
||||
@@ -1,32 +1,30 @@
|
||||
import { useState, type FormEvent } from 'react';
|
||||
import { useNavigate } from 'react-router';
|
||||
import { useState, type FormEvent } from "react";
|
||||
import { useNavigate } from "react-router";
|
||||
import { useUsuario } from "../services/useUsuario";
|
||||
|
||||
const Login = ({setUsuario}:any) => {
|
||||
const Login = () => {
|
||||
const { setUsuario } = useUsuario();
|
||||
const [email, setEmail] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
const [loading, setLoading] = useState(false);
|
||||
const navigate = useNavigate();
|
||||
|
||||
const [email, setEmail] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
const [loading, setLoading] = useState(false);
|
||||
const navigate = useNavigate();
|
||||
const handleSubmit = async (e: FormEvent) => {
|
||||
e.preventDefault();
|
||||
setLoading(true);
|
||||
|
||||
const handleSubmit = async (e:FormEvent) => {
|
||||
e.preventDefault();
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
setUsuario(
|
||||
{
|
||||
id: 1,
|
||||
name: "Juan Pepe",
|
||||
username: "jpepe",
|
||||
email: "",
|
||||
permissionLevel: ["ADMIN"],
|
||||
}
|
||||
);
|
||||
navigate("/home");
|
||||
} catch (error) {
|
||||
} finally {
|
||||
//simulamos latencia
|
||||
setLoading(false);
|
||||
try {
|
||||
setUsuario({
|
||||
id: 1,
|
||||
name: "Juan Pepe",
|
||||
username: "jpepe",
|
||||
email: email || "",
|
||||
permissionLevel: ["ADMIN"],
|
||||
});
|
||||
navigate("/home");
|
||||
} finally {
|
||||
//simulamos latencia
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -79,14 +77,10 @@ const Login = ({setUsuario}:any) => {
|
||||
type="submit"
|
||||
disabled={loading}
|
||||
className={`group relative w-full flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white ${
|
||||
loading ? 'bg-indigo-400' : 'bg-indigo-600 hover:bg-indigo-700'
|
||||
loading ? "bg-indigo-400" : "bg-indigo-600 hover:bg-indigo-700"
|
||||
} focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500`}
|
||||
>
|
||||
{loading ? (
|
||||
<span>Enviando...</span>
|
||||
) : (
|
||||
<span>Iniciar sesión</span>
|
||||
)}
|
||||
{loading ? <span>Enviando...</span> : <span>Iniciar sesión</span>}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import type { Usuario } from "../types/usuario";
|
||||
import { Routes } from "react-router";
|
||||
import { Route } from "react-router";
|
||||
import { Navigate } from "react-router";
|
||||
@@ -6,20 +5,26 @@ import { RutaProtegida } from "./RutaProtegida";
|
||||
import { ComponenteAdmin } from "../Components/ComponenteAdmin";
|
||||
import { Dashboard } from "../Components/Dashboard";
|
||||
import Login from "../Components/Login";
|
||||
import { AboutPage } from "../Components/AboutPage";
|
||||
import { useUsuario } from "../services/useUsuario";
|
||||
import { LogOut } from "../Components/LogOut";
|
||||
import { CounterPage } from "../Components/CounterPage";
|
||||
|
||||
interface prop {
|
||||
usuario: Usuario | null
|
||||
setUsuario: any
|
||||
}
|
||||
|
||||
export function AppRouter({usuario, setUsuario}: prop) {
|
||||
export function AppRouter() {
|
||||
const { usuario } = useUsuario();
|
||||
return (
|
||||
<Routes>
|
||||
<Route path="/login" element={<Login setUsuario={setUsuario} />} />
|
||||
<Route element={<RutaProtegida estaPermitido={!!usuario} redirectTo="/login"/>}>
|
||||
<Route path="/login" element={<Login />} />
|
||||
<Route path="/counter" element={<CounterPage />}></Route>
|
||||
<Route
|
||||
element={
|
||||
<RutaProtegida estaPermitido={!!usuario} redirectTo="/login" />
|
||||
}
|
||||
>
|
||||
<Route path="/home" element={<Dashboard />} />
|
||||
<Route path="/about" element={<h1>About</h1>}></Route>
|
||||
<Route path="/about" element={<AboutPage />}></Route>
|
||||
<Route path="/productos" element={<h1>Productos</h1>}></Route>
|
||||
<Route path="/logout" element={<LogOut />}></Route>
|
||||
</Route>
|
||||
<Route
|
||||
path="/admin"
|
||||
|
||||
6
src/hooks.ts
Normal file
6
src/hooks.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import type { TypedUseSelectorHook } from "react-redux";
|
||||
import type { RootState, AppDispatch } from "./store";
|
||||
|
||||
export const useAppDispatch = () => useDispatch<AppDispatch>();
|
||||
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
|
||||
10
src/main.tsx
10
src/main.tsx
@@ -3,11 +3,15 @@ import { createRoot } from "react-dom/client";
|
||||
import "./index.css";
|
||||
import App from "./App.tsx";
|
||||
import { BrowserRouter } from "react-router";
|
||||
import { Provider } from "react-redux";
|
||||
import { store } from "./store.ts";
|
||||
|
||||
createRoot(document.getElementById("root")!).render(
|
||||
<StrictMode>
|
||||
<BrowserRouter>
|
||||
<App />
|
||||
</BrowserRouter>
|
||||
<Provider store={store}>
|
||||
<BrowserRouter>
|
||||
<App />
|
||||
</BrowserRouter>
|
||||
</Provider>
|
||||
</StrictMode>,
|
||||
);
|
||||
|
||||
36
src/services/useCounter.ts
Normal file
36
src/services/useCounter.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { useAppSelector, useAppDispatch } from "../hooks";
|
||||
import {
|
||||
increment,
|
||||
decrement,
|
||||
incrementByAmount,
|
||||
decrementByAmount,
|
||||
} from "../types/slices/counter.slice";
|
||||
|
||||
export const useCounter = () => {
|
||||
const value = useAppSelector((state) => state.counter.value);
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const incrementAction = () => {
|
||||
dispatch(increment());
|
||||
};
|
||||
|
||||
const decrementAction = () => {
|
||||
dispatch(decrement());
|
||||
};
|
||||
|
||||
const incrementByAction = (amount: number) => {
|
||||
dispatch(incrementByAmount(amount));
|
||||
};
|
||||
|
||||
const decrementByAction = (amount: number) => {
|
||||
dispatch(decrementByAmount(amount));
|
||||
};
|
||||
|
||||
return {
|
||||
value,
|
||||
increment: incrementAction,
|
||||
decrement: decrementAction,
|
||||
incrementByAmount: incrementByAction,
|
||||
decrementByAmount: decrementByAction,
|
||||
};
|
||||
};
|
||||
@@ -1,26 +1,30 @@
|
||||
import { useState } from "react";
|
||||
import { useAppSelector, useAppDispatch } from "../hooks";
|
||||
import {
|
||||
setUsuario,
|
||||
setPermissionLevel,
|
||||
removeUsuario,
|
||||
} from "../types/slices/usuario.slice";
|
||||
import type { PermissionLevel, Usuario } from "../types/usuario";
|
||||
|
||||
export const useUsuario = () => {
|
||||
const [usuario, setUsuario] = useState<Usuario | null>( null
|
||||
/*
|
||||
{
|
||||
id: 1,
|
||||
name: "Juan Pepe",
|
||||
username: "jpepe",
|
||||
email: "",
|
||||
permissionLevel: ["GUEST"],
|
||||
}
|
||||
*/
|
||||
);
|
||||
const usuario = useAppSelector((state) => state.usuario.usuario);
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
function setPermissionLevel(arg: PermissionLevel) {
|
||||
setUsuario({ ...usuario!, permissionLevel: [arg] });
|
||||
}
|
||||
const setUsuarioAction = (user: Usuario | null) => {
|
||||
dispatch(setUsuario(user));
|
||||
};
|
||||
|
||||
const setPermissionLevelAction = (level: PermissionLevel) => {
|
||||
dispatch(setPermissionLevel(level));
|
||||
};
|
||||
|
||||
const logOut = () => {
|
||||
dispatch(removeUsuario());
|
||||
};
|
||||
return {
|
||||
usuario,
|
||||
setUsuario,
|
||||
setPermissionLevel,
|
||||
setUsuario: setUsuarioAction,
|
||||
setPermissionLevel: setPermissionLevelAction,
|
||||
logOut: logOut,
|
||||
};
|
||||
};
|
||||
|
||||
13
src/store.ts
Normal file
13
src/store.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { configureStore } from "@reduxjs/toolkit";
|
||||
import usuarioReducer from "./types/slices/usuario.slice";
|
||||
import counterReducer from "./types/slices/counter.slice";
|
||||
|
||||
export const store = configureStore({
|
||||
reducer: {
|
||||
usuario: usuarioReducer,
|
||||
counter: counterReducer,
|
||||
},
|
||||
});
|
||||
|
||||
export type RootState = ReturnType<typeof store.getState>;
|
||||
export type AppDispatch = typeof store.dispatch;
|
||||
32
src/types/slices/counter.slice.ts
Normal file
32
src/types/slices/counter.slice.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { createSlice, type PayloadAction } from "@reduxjs/toolkit";
|
||||
|
||||
interface CounterState {
|
||||
value: number;
|
||||
}
|
||||
|
||||
const initialState: CounterState = {
|
||||
value: 0,
|
||||
};
|
||||
|
||||
const counterSlice = createSlice({
|
||||
name: "counter",
|
||||
initialState,
|
||||
reducers: {
|
||||
increment: (state) => {
|
||||
state.value += 1;
|
||||
},
|
||||
incrementByAmount: (state, action: PayloadAction<number>) => {
|
||||
state.value += action.payload;
|
||||
},
|
||||
decrement: (state) => {
|
||||
state.value -= 1;
|
||||
},
|
||||
decrementByAmount: (state, action: PayloadAction<number>) => {
|
||||
state.value -= action.payload;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const { increment, decrement, incrementByAmount, decrementByAmount } =
|
||||
counterSlice.actions;
|
||||
export default counterSlice.reducer;
|
||||
32
src/types/slices/usuario.slice.ts
Normal file
32
src/types/slices/usuario.slice.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { createSlice, type PayloadAction } from "@reduxjs/toolkit";
|
||||
import type { PermissionLevel, Usuario } from "../usuario";
|
||||
|
||||
interface UsuarioState {
|
||||
usuario: Usuario | null;
|
||||
}
|
||||
|
||||
const initialState: UsuarioState = {
|
||||
usuario: null,
|
||||
};
|
||||
|
||||
const usuarioSlice = createSlice({
|
||||
name: "usuario",
|
||||
initialState,
|
||||
reducers: {
|
||||
setUsuario: (state, action: PayloadAction<Usuario | null>) => {
|
||||
state.usuario = action.payload;
|
||||
},
|
||||
setPermissionLevel: (state, action: PayloadAction<PermissionLevel>) => {
|
||||
if (state.usuario) {
|
||||
state.usuario.permissionLevel = [action.payload];
|
||||
}
|
||||
},
|
||||
removeUsuario: (state) => {
|
||||
state.usuario = null;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const { setUsuario, setPermissionLevel, removeUsuario } =
|
||||
usuarioSlice.actions;
|
||||
export default usuarioSlice.reducer;
|
||||
Reference in New Issue
Block a user