- "backend/schemas.py" - "backend/routers/topics.py" - "backend/routers/videos.py" - "frontend/src/api/topics.ts" - "frontend/src/pages/TopicsBrowse.tsx" - "frontend/src/pages/Home.tsx" GSD-Task: S05/T03
42 lines
1.5 KiB
TypeScript
42 lines
1.5 KiB
TypeScript
import { request, BASE } from "./client";
|
|
import type { TechniqueListResponse } from "./techniques";
|
|
|
|
// ── Types ────────────────────────────────────────────────────────────────────
|
|
|
|
export interface TopicSubTopic {
|
|
name: string;
|
|
technique_count: number;
|
|
creator_count: number;
|
|
}
|
|
|
|
export interface TopicCategory {
|
|
name: string;
|
|
description: string;
|
|
sub_topics: TopicSubTopic[];
|
|
}
|
|
|
|
export interface TopicListResponse {
|
|
items: TopicCategory[];
|
|
total: number;
|
|
}
|
|
|
|
// ── Functions ────────────────────────────────────────────────────────────────
|
|
|
|
export async function fetchTopics(): Promise<TopicListResponse> {
|
|
return request<TopicListResponse>(`${BASE}/topics`);
|
|
}
|
|
|
|
export async function fetchSubTopicTechniques(
|
|
categorySlug: string,
|
|
subtopicSlug: string,
|
|
params: { limit?: number; offset?: number; sort?: string } = {},
|
|
): Promise<TechniqueListResponse> {
|
|
const qs = new URLSearchParams();
|
|
if (params.limit !== undefined) qs.set("limit", String(params.limit));
|
|
if (params.offset !== undefined) qs.set("offset", String(params.offset));
|
|
if (params.sort) qs.set("sort", params.sort);
|
|
const query = qs.toString();
|
|
return request<TechniqueListResponse>(
|
|
`${BASE}/topics/${encodeURIComponent(categorySlug)}/${encodeURIComponent(subtopicSlug)}${query ? `?${query}` : ""}`,
|
|
);
|
|
}
|