diff --git a/frontend/hooks/usePuzzles.ts b/frontend/hooks/usePuzzles.ts new file mode 100644 index 0000000..b87dd07 --- /dev/null +++ b/frontend/hooks/usePuzzles.ts @@ -0,0 +1,30 @@ +// frontend/hooks/usePuzzles.ts +import { useQuery } from '@tanstack/react-query'; +import { + getPuzzles, + getPuzzleById, + getDailyQuestPuzzles, +} from '../lib/api/puzzleApi'; +import { PuzzleQueryParams, Puzzle } from '../lib/types/puzzles'; + +export function usePuzzles(query: PuzzleQueryParams) { + return useQuery({ + queryKey: ['puzzles', query], + queryFn: () => getPuzzles(query), + }); +} + +export function usePuzzle(id: string) { + return useQuery({ + queryKey: ['puzzle', id], + queryFn: () => getPuzzleById(id), + enabled: !!id, + }); +} + +export function useDailyQuestPuzzles() { + return useQuery({ + queryKey: ['dailyQuestPuzzles'], + queryFn: getDailyQuestPuzzles, + }); +} diff --git a/frontend/lib/api/puzzleApi.ts b/frontend/lib/api/puzzleApi.ts new file mode 100644 index 0000000..b7891ed --- /dev/null +++ b/frontend/lib/api/puzzleApi.ts @@ -0,0 +1,22 @@ +// frontend/lib/api/puzzleApi.ts +import axios from 'axios'; +import { Puzzle, PuzzleQueryParams } from '../types/puzzles'; + +const api = axios.create({ + baseURL: process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3000', +}); + +export async function getPuzzles(query: PuzzleQueryParams): Promise { + const response = await api.get('/puzzles', { params: query }); + return response.data; +} + +export async function getPuzzleById(id: string): Promise { + const response = await api.get(`/puzzles/${id}`); + return response.data; +} + +export async function getDailyQuestPuzzles(): Promise { + const response = await api.get('/puzzles/daily-quest'); + return response.data; +} diff --git a/frontend/lib/types/puzzles.ts b/frontend/lib/types/puzzles.ts new file mode 100644 index 0000000..fdca453 --- /dev/null +++ b/frontend/lib/types/puzzles.ts @@ -0,0 +1,16 @@ +export interface Puzzle { + id: string; + title: string; + description: string; + type: 'logic' | 'coding' | 'blockchain'; + difficulty: 'easy' | 'medium' | 'hard'; + categoryId: string; + timeLimit?: number; +} + +export interface PuzzleQueryParams { + categoryId?: string; + difficulty?: string; + page?: number; + limit?: number; +} diff --git a/package-lock.json b/package-lock.json index 14664cc..2f5e5da 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "dependencies": { "@nestjs/common": "^11.1.14", "@nestjs/core": "^11.1.14", + "@tanstack/react-query": "^5.90.21", "minimatch": "^10.1.1", "reflect-metadata": "^0.2.2", "rxjs": "^7.8.2", @@ -5082,6 +5083,32 @@ "tailwindcss": "4.1.18" } }, + "node_modules/@tanstack/query-core": { + "version": "5.90.20", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.90.20.tgz", + "integrity": "sha512-OMD2HLpNouXEfZJWcKeVKUgQ5n+n3A2JFmBaScpNDUqSrQSjiveC7dKMe53uJUg1nDG16ttFPz2xfilz6i2uVg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-query": { + "version": "5.90.21", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.90.21.tgz", + "integrity": "sha512-0Lu6y5t+tvlTJMTO7oh5NSpJfpg/5D41LlThfepTixPYkJ0sE2Jj0m0f6yYqujBwIXlId87e234+MxG3D3g7kg==", + "license": "MIT", + "dependencies": { + "@tanstack/query-core": "5.90.20" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^18 || ^19" + } + }, "node_modules/@tokenizer/inflate": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/@tokenizer/inflate/-/inflate-0.4.1.tgz", diff --git a/package.json b/package.json index 46cd867..d0f8b60 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "dependencies": { "@nestjs/common": "^11.1.14", "@nestjs/core": "^11.1.14", + "@tanstack/react-query": "^5.90.21", "minimatch": "^10.1.1", "reflect-metadata": "^0.2.2", "rxjs": "^7.8.2",