diff --git a/.gitignore b/.gitignore index 92f076d..79e9c33 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ albums/ wallpapers/ frontend/node_modules/ frontend/.next/ +frontend/src/data/types.ts diff --git a/frontend/generate_types.sh b/frontend/generate_types.sh new file mode 100755 index 0000000..a805c4b --- /dev/null +++ b/frontend/generate_types.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +if [ -z "$1" ]; then + set -- "BACKEND_HOST" +fi + +HOST=$(grep "$1" .env 2>/dev/null | cut -d '=' -f 2 | tr -d '"') +echo $1 +echo $HOST +cmd="npx openapi-typescript $HOST/api/schema/ -o src/data/types.tmp.ts" +if eval $cmd +then + echo $cmd + mv src/data/types.tmp.ts src/data/types.ts +fi +chmod go+rw src/data/types.ts diff --git a/frontend/package.json b/frontend/package.json index def9f10..87b8cea 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -9,10 +9,11 @@ "react-oidc-context": "^3.3.0" }, "scripts": { - "dev": "next dev", - "build": "next build", + "dev": "npm run generate:types && next dev", + "build": "npm run generate:types && next build", "start": "next start", - "lint": "next lint" + "lint": "next lint", + "generate:types": "bash generate_types.sh DOCKER_BACKEND" }, "devDependencies": { "@tailwindcss/postcss": "^4.1.10", diff --git a/frontend/src/app/users/page.tsx b/frontend/src/app/users/page.tsx index 57a5729..c66aa9d 100644 --- a/frontend/src/app/users/page.tsx +++ b/frontend/src/app/users/page.tsx @@ -1,10 +1,10 @@ "use client"; import { getUser } from "muzak/data/fetch"; import { useEffect, useState } from "react"; -import api from "muzak/data/fetcher"; +import { api, User } from "muzak/data/fetcher"; export default function Page() { - const [userData, setUserData] = useState([]); + const [userData, setUserData] = useState([]); useEffect(() => { async function getUsers() { @@ -17,7 +17,7 @@ export default function Page() { return (
{userData.length > 0 ? ( - userData.map((user) =>
{user.email}
) + userData.map((user: User) =>
{user.email}
) ) : (
Loading users...
)} diff --git a/frontend/src/data/fetcher.ts b/frontend/src/data/fetcher.ts index 9d7f2a3..e6dd53e 100644 --- a/frontend/src/data/fetcher.ts +++ b/frontend/src/data/fetcher.ts @@ -1,13 +1,9 @@ "use client"; import { Fetcher } from "openapi-typescript-fetch"; import { getUser } from "./fetch"; +import { paths, components } from "muzak/data/types"; -interface GenericPaths { - [path: string]: { - [method: string]: any; - }; -} -const fetcher = Fetcher.for(); +const fetcher = Fetcher.for(); const BASE_URL = process.env.BACKEND_HOST || "http://127.0.0.1:8001"; // Configure the fetcher @@ -19,7 +15,7 @@ fetcher.configure({ }, }, use: [ - // Authentication middleware + // Add authentication token to request async (url, init, next) => { const user = getUser(); if (user?.access_token) { @@ -30,18 +26,14 @@ fetcher.configure({ } return next(url, init); }, - // Error handling middleware + // Handle errors async (url, init, next) => { const response = await next(url, init); if (!response.ok) { - // Handle authentication errors if (response.status === 401) { console.warn("Authentication failed - token may be expired"); - // You might want to trigger a redirect to login or token refresh here } - - // Log other errors console.error(`API Error: ${response.status} ${response.statusText}`, { url, method: init.method, @@ -53,7 +45,6 @@ fetcher.configure({ ], }); -// Create your API methods export const api = { tracks: { list: fetcher.path("/api/track/").method("get").create(), @@ -88,4 +79,9 @@ export const api = { }, }; +export type User = components["schemas"]["User"]; +export type Track = components["schemas"]["Track"]; +export type Album = components["schemas"]["Album"]; +export type Vote = components["schemas"]["Vote"]; + export default api;