diff --git a/client/package.json b/client/package.json index 3925710..0d17716 100644 --- a/client/package.json +++ b/client/package.json @@ -16,11 +16,15 @@ }, "dependencies": { "@utpost/shared": "file:../shared", + "pinia": "^4.0.3", "vue": "^3.5.40", "vue-router": "^5.2.0" }, "devDependencies": { "@eslint/js": "^10.0.1", + "@testing-library/jest-dom": "^7.0.1", + "@testing-library/user-event": "^14.6.7", + "@testing-library/vue": "^8.1.0", "@typescript-eslint/parser": "^8.71.0", "@vitejs/plugin-vue": "^6.0.0", "@vitest/eslint-plugin": "^1.6.27", @@ -33,10 +37,7 @@ "prettier": "^3.9.5", "vite": "^7.1.0", "vitest": "^3.2.4", - "vue-eslint-parser": "^10.4.1", - "@testing-library/jest-dom": "^7.0.1", - "@testing-library/user-event": "^14.6.7", - "@testing-library/vue": "^8.1.0" + "vue-eslint-parser": "^10.4.1" }, "engines": { "node": "^22.18.0 || >=24.12.0" diff --git a/client/src/App.vue b/client/src/App.vue index fa159e5..7548001 100644 --- a/client/src/App.vue +++ b/client/src/App.vue @@ -1,89 +1,11 @@ - - + diff --git a/client/src/api.ts b/client/src/api.ts index 396e47d..5934a85 100644 --- a/client/src/api.ts +++ b/client/src/api.ts @@ -5,3 +5,16 @@ export async function get(path: string): Promise { if (!response.ok) throw new Error(`API-fel: ${response.status}`); return (await response.json()) as T; } + +export async function post( + path: string, + body: TBody, +): Promise { + const response = await fetch(`${API_URL}${path}`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(body), + }); + if (!response.ok) throw new Error(`API-fel: ${response.status}`); + return (await response.json()) as TResponse; +} diff --git a/client/src/api/auth.ts b/client/src/api/auth.ts new file mode 100644 index 0000000..4257d43 --- /dev/null +++ b/client/src/api/auth.ts @@ -0,0 +1,10 @@ +import { post } from "../api"; +import type { LoginRequest, LoginResponse } from "../../../shared/src/types"; + +export function login(credentials: LoginRequest): Promise { + return post("/auth/login", credentials); +} + +export function logout(): Promise { + return post("/auth/login", {}); +} diff --git a/client/src/components/AppHeader.vue b/client/src/components/AppHeader.vue new file mode 100644 index 0000000..c0357f7 --- /dev/null +++ b/client/src/components/AppHeader.vue @@ -0,0 +1,102 @@ + + + + + diff --git a/client/src/main.js b/client/src/main.js index 7a9c7a8..dabaf88 100644 --- a/client/src/main.js +++ b/client/src/main.js @@ -1,11 +1,14 @@ import "./assets/main.css"; import { createApp } from "vue"; +import { createPinia } from "pinia"; import App from "./App.vue"; import router from "./router"; const app = createApp(App); +app.use(createPinia()); + app.use(router); app.mount("#app"); diff --git a/client/src/router/index.js b/client/src/router/index.js index 7865b9c..6157bb0 100644 --- a/client/src/router/index.js +++ b/client/src/router/index.js @@ -4,6 +4,7 @@ import GuidesView from "../views/GuidesView.vue"; import GuideDetails from "../views/GuideDetails.vue"; import ToursView from "@/views/ToursView.vue"; import TourDetail from "@/views/TourDetail.vue"; +import ProfileView from "@/views/ProfileView.vue"; const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), @@ -41,6 +42,11 @@ const router = createRouter({ name: "tour-detail", component: TourDetail, }, + { + path: "/profil", + name: "profil", + component: ProfileView, + }, ], }); diff --git a/client/src/stores/session.ts b/client/src/stores/session.ts new file mode 100644 index 0000000..5af1030 --- /dev/null +++ b/client/src/stores/session.ts @@ -0,0 +1,44 @@ +import { ref, computed } from "vue"; +import { defineStore } from "pinia"; +import { login as apiLogin, logout as apiLogout } from "@/api/auth"; +import type { LoginRequest, User } from "../../../shared/src/types"; + +export const useSessionStore = defineStore("session", () => { + const user = ref(null); + const token = ref(); + const errorParagraph = ref(null); + const loading = ref(false); + + const isLoggedIn = computed(() => user.value !== null); + + async function login(req: LoginRequest) { + loading.value = true; + errorParagraph.value = null; + try { + const data = await apiLogin(req); + user.value = data.user; + token.value = data.token; + localStorage.setItem("token", data.token); + localStorage.setItem("user", JSON.stringify(data.user)); + } catch (error) { + console.log( + "Inloggningen misslyckades", + error instanceof Error ? error.message : error, + ); + user.value = null; + errorParagraph.value = "Kunde inte logga in."; + } finally { + loading.value = false; + } + } + + async function logout() { + try { + await apiLogout(); + } finally { + user.value = null; + } + } + + return { user, errorParagraph, loading, isLoggedIn, login, logout }; +}); diff --git a/client/src/views/LoginView.vue b/client/src/views/LoginView.vue new file mode 100644 index 0000000..5246885 --- /dev/null +++ b/client/src/views/LoginView.vue @@ -0,0 +1,34 @@ + + + + + diff --git a/client/src/views/ProfileView.vue b/client/src/views/ProfileView.vue new file mode 100644 index 0000000..204d6bd --- /dev/null +++ b/client/src/views/ProfileView.vue @@ -0,0 +1,15 @@ + + + diff --git a/package-lock.json b/package-lock.json index aa4ab7e..02dcf5a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -40,6 +40,7 @@ "version": "0.1.0", "dependencies": { "@utpost/shared": "file:../shared", + "pinia": "^4.0.3", "vue": "^3.5.40", "vue-router": "^5.2.0" }, @@ -76,6 +77,7 @@ "cpu": [ "ppc64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -92,6 +94,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -108,6 +111,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -124,6 +128,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -140,6 +145,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -156,6 +162,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -172,6 +179,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -188,6 +196,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -204,6 +213,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -220,6 +230,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -236,6 +247,7 @@ "cpu": [ "ia32" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -252,6 +264,7 @@ "cpu": [ "loong64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -268,6 +281,7 @@ "cpu": [ "mips64el" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -284,6 +298,7 @@ "cpu": [ "ppc64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -300,6 +315,7 @@ "cpu": [ "riscv64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -316,6 +332,7 @@ "cpu": [ "s390x" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -332,6 +349,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -348,6 +366,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -364,6 +383,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -380,6 +400,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -396,6 +417,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -412,6 +434,7 @@ "cpu": [ "ia32" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -428,6 +451,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -485,6 +509,7 @@ "integrity": "sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg==", "devOptional": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.27.0 || ^0.28.0", "fdir": "^6.5.0", @@ -691,6 +716,7 @@ "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/generator": "^7.29.7", @@ -1143,6 +1169,7 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": ">=20.19.0" }, @@ -1191,6 +1218,7 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": ">=20.19.0" } @@ -1202,6 +1230,7 @@ "cpu": [ "ppc64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1218,6 +1247,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1234,6 +1264,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1250,6 +1281,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1266,6 +1298,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1282,6 +1315,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1298,6 +1332,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1314,6 +1349,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1330,6 +1366,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1346,6 +1383,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1362,6 +1400,7 @@ "cpu": [ "ia32" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1378,6 +1417,7 @@ "cpu": [ "loong64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1394,6 +1434,7 @@ "cpu": [ "mips64el" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1410,6 +1451,7 @@ "cpu": [ "ppc64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1426,6 +1468,7 @@ "cpu": [ "riscv64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1442,6 +1485,7 @@ "cpu": [ "s390x" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1458,6 +1502,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1474,6 +1519,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1490,6 +1536,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1506,6 +1553,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1522,6 +1570,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1538,6 +1587,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1554,6 +1604,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1570,6 +1621,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1586,6 +1638,7 @@ "cpu": [ "ia32" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1602,6 +1655,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1911,6 +1965,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1950,6 +2005,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1963,6 +2019,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1976,6 +2033,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1989,6 +2047,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2002,6 +2061,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2015,6 +2075,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2028,6 +2089,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2041,6 +2103,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2054,6 +2117,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2067,6 +2131,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2080,6 +2145,7 @@ "cpu": [ "loong64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2093,6 +2159,7 @@ "cpu": [ "loong64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2106,6 +2173,7 @@ "cpu": [ "ppc64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2119,6 +2187,7 @@ "cpu": [ "ppc64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2132,6 +2201,7 @@ "cpu": [ "riscv64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2145,6 +2215,7 @@ "cpu": [ "riscv64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2158,6 +2229,7 @@ "cpu": [ "s390x" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2171,6 +2243,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2184,6 +2257,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2197,6 +2271,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2210,6 +2285,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2223,6 +2299,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2236,6 +2313,7 @@ "cpu": [ "ia32" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2249,6 +2327,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2262,6 +2341,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2561,6 +2641,7 @@ "integrity": "sha512-fKVHpikPdg4GKks3JuLEhvwSyvwzF23hnabPy6DD8ljVbC7+6J5dQzdv4arV6jqq57djnMgs1HKBxX4P8aBI3A==", "devOptional": true, "license": "MIT", + "peer": true, "dependencies": { "@types/node": "*", "pg-protocol": "*", @@ -3260,6 +3341,7 @@ "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.43.tgz", "integrity": "sha512-PEZoAk3NQmsn/ejMzSOCyTYqwGqczrWm70PuhBKjjv1+TCoQAaO/zOqNwjV+honlNstT5ILxtc+8r8UUfj+iEQ==", "license": "MIT", + "peer": true, "dependencies": { "@vue/compiler-core": "3.5.43", "@vue/shared": "3.5.43" @@ -3297,6 +3379,7 @@ "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-8.2.1.tgz", "integrity": "sha512-6u4vXBlIBAC1wMplIZgpyPn7uh/s4Bf6F5bMzvLv+EdJ0aHs/+4B7Ygv864EStQSjRbsRzTko/kUG1A1IejQ3A==", "license": "MIT", + "peer": true, "dependencies": { "@vue/devtools-kit": "^8.2.1" } @@ -3416,6 +3499,7 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz", "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==", "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -3674,6 +3758,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.11.20", "caniuse-lite": "^1.0.30001810", @@ -4495,6 +4580,7 @@ "devOptional": true, "hasInstallScript": true, "license": "MIT", + "peer": true, "bin": { "esbuild": "bin/esbuild" }, @@ -4562,6 +4648,7 @@ "integrity": "sha512-P7a6UEEqb9G95MYAtqkmsTbVXIYyzIfl6NGOIJk162PaahFxFyeGcrlXYFSiagECg4sEm8IseJdZBKR3rx6MsQ==", "dev": true, "license": "MIT", + "peer": true, "workspaces": [ "packages/*" ], @@ -5027,6 +5114,7 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -5869,6 +5957,7 @@ "integrity": "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@keyv/serialize": "^1.1.1" } @@ -6503,6 +6592,7 @@ "resolved": "https://registry.npmjs.org/pg/-/pg-8.23.0.tgz", "integrity": "sha512-Ip2EQCngowJLGOfCwkFhPXU7/ljlhn6Rxlmy4XYfL2Y+vyRM59+8uR2xqRWKdYmbXmxCFOAmKxBuSUCdF34qLg==", "license": "MIT", + "peer": true, "dependencies": { "pg-connection-string": "^2.14.0", "pg-pool": "^3.14.0", @@ -6605,6 +6695,32 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pinia": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/pinia/-/pinia-4.0.3.tgz", + "integrity": "sha512-XMQqpvjgG7LMqVhhFUzKLT4KEbsYbfZZ0CZU9PgdFm1O2VKBmIkykL8+SfNhOaT7sR0wT6BEgKT0YNDYWgmVRA==", + "license": "MIT", + "peer": true, + "dependencies": { + "nostics": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "@vue/devtools-api": "^8.1.5", + "typescript": ">=5.6.0", + "vue": "^3.5.11" + }, + "peerDependenciesMeta": { + "@vue/devtools-api": { + "optional": false + }, + "typescript": { + "optional": true + } + } + }, "node_modules/pkg-types": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.3.tgz", @@ -6878,6 +6994,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -6890,6 +7007,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" @@ -7021,6 +7139,7 @@ "integrity": "sha512-3Df9jsstwhccuEfmAMi9l8XUh/GOkVObmFTU7CCVBysEbcOZLl84jCtaAZMcPiMz2EGKsATzQcU+Xr3n/wU6cg==", "devOptional": true, "license": "MIT", + "peer": true, "dependencies": { "@types/estree": "1.0.9" }, @@ -7671,6 +7790,7 @@ "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", "devOptional": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -7857,6 +7977,7 @@ "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", "devOptional": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", @@ -7965,6 +8086,7 @@ "integrity": "sha512-KrxIJ62Fd89gfysR4WotlgZABiz2dqFPgqGzX7s+CwsqLFomRH7777ZcrOD6+WVAh7khPQP41A+BKbpcJFrdEg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/chai": "^5.2.2", "@vitest/expect": "3.2.7", @@ -8062,6 +8184,7 @@ "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.43.tgz", "integrity": "sha512-o5qZoksdnjIKvW1srZ3ab7pcDNYAerBjRe54D0LBLfRdCYFrSgBHVXokMas35czQc0//lmx4/tuY4ZNQ+Rf2Ng==", "license": "MIT", + "peer": true, "dependencies": { "@vue/compiler-dom": "3.5.43", "@vue/compiler-sfc": "3.5.43", @@ -8091,6 +8214,7 @@ "integrity": "sha512-Gk6gRDj0n/fkRa3C3l0bBheoBckUq/Rs0F/TvMWIS6nzzx67amAViMe9CkNgsP2tXyQONvGiHQESHwFtZ3aYDA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "debug": "^4.4.0", "eslint-scope": "^8.2.0 || ^9.0.0", diff --git a/shared/src/types.ts b/shared/src/types.ts index 9b4b446..30aab61 100644 --- a/shared/src/types.ts +++ b/shared/src/types.ts @@ -14,6 +14,25 @@ export interface Guide { updated_at: string; } +export interface User { + id: number, + email: string, + password_hash: string, + display_name: string, + role: string, + createdAt: string, +} + +export interface LoginRequest { + email: string + password_hash: string +} + +export interface LoginResponse { + token: string + user: User +} + export interface TourLog { id: number tour_id: number @@ -23,4 +42,4 @@ export interface TourLog { elevation_m: number | null heart_rate: number | null note: string | null -} \ No newline at end of file +}