130 lines
3.2 KiB
TypeScript
130 lines
3.2 KiB
TypeScript
/**
|
||
* 新用户引导页面数据获取 Hook
|
||
*
|
||
* 封装引导状态检查的 SWR 请求 + 品牌创建的 mutation,替代手动 useState + useEffect 模式。
|
||
* - 引导状态检查:mount 时自动获取
|
||
* - 品牌创建:mutation(由用户交互触发)
|
||
*/
|
||
|
||
import { useCallback } from "react";
|
||
import { useApi, useApiMutation } from "./use-api";
|
||
import type { SWRConfiguration } from "swr";
|
||
import { getSession } from "next-auth/react";
|
||
import type { Session } from "next-auth";
|
||
import { monitoringApi } from "@/lib/api/monitoring";
|
||
|
||
interface OnboardingStatusResponse {
|
||
completed: boolean;
|
||
}
|
||
|
||
interface CreateBrandResponse {
|
||
brand_id: string;
|
||
}
|
||
|
||
export interface CreateBrandPayload {
|
||
name: string;
|
||
competitors: string[];
|
||
platforms: string[];
|
||
frequency: "daily" | "weekly" | "monthly";
|
||
}
|
||
|
||
export interface UseOnboardingDataReturn {
|
||
/** 引导状态数据 */
|
||
onboardingStatus: OnboardingStatusResponse | undefined;
|
||
/** 是否已完成引导 */
|
||
isCompleted: boolean;
|
||
/** 是否正在加载 */
|
||
isLoading: boolean;
|
||
/** 错误信息 */
|
||
error: Error | undefined;
|
||
/** 刷新引导状态 */
|
||
refresh: () => void;
|
||
/** 创建品牌 */
|
||
createBrand: (data: CreateBrandPayload) => Promise<string | null>;
|
||
/** 是否正在创建品牌 */
|
||
isCreatingBrand: boolean;
|
||
/** 创建品牌错误 */
|
||
mutationError: Error | undefined;
|
||
/** 创建监控任务 */
|
||
createMonitoringTask: (
|
||
brandId: string,
|
||
platforms: string[],
|
||
frequency: string
|
||
) => Promise<void>;
|
||
}
|
||
|
||
export interface UseOnboardingDataOptions {
|
||
/** SWR 配置(用于测试时禁用重试等) */
|
||
swrOptions?: SWRConfiguration;
|
||
}
|
||
|
||
export function useOnboardingData(
|
||
options?: UseOnboardingDataOptions
|
||
): UseOnboardingDataReturn {
|
||
const swrOptions = options?.swrOptions;
|
||
|
||
// 引导状态检查
|
||
const {
|
||
data: onboardingStatus,
|
||
isLoading,
|
||
error,
|
||
refresh,
|
||
} = useApi<OnboardingStatusResponse>("/api/v1/onboarding/status", swrOptions);
|
||
|
||
const isCompleted = onboardingStatus?.completed ?? false;
|
||
|
||
// 创建品牌(mutation)
|
||
const {
|
||
trigger: createBrandTrigger,
|
||
isMutating: isCreatingBrand,
|
||
error: mutationError,
|
||
} = useApiMutation<CreateBrandResponse, CreateBrandPayload>(
|
||
"/api/v1/onboarding/brand",
|
||
"POST"
|
||
);
|
||
|
||
const createBrand = useCallback(
|
||
async (data: CreateBrandPayload): Promise<string | null> => {
|
||
const result = await createBrandTrigger(data);
|
||
return result?.brand_id ?? null;
|
||
},
|
||
[createBrandTrigger]
|
||
);
|
||
|
||
const createMonitoringTask = useCallback(
|
||
async (
|
||
brandId: string,
|
||
platforms: string[],
|
||
frequency: string
|
||
): Promise<void> => {
|
||
try {
|
||
const session = await getSession();
|
||
const token = (session as Session)?.accessToken;
|
||
if (!token) return;
|
||
for (const platform of platforms) {
|
||
await monitoringApi.createTask(token, {
|
||
brand_id: brandId,
|
||
platform,
|
||
query_keywords: frequency,
|
||
});
|
||
}
|
||
} catch {
|
||
// silent
|
||
}
|
||
},
|
||
[]
|
||
);
|
||
|
||
return {
|
||
onboardingStatus,
|
||
isCompleted,
|
||
isLoading,
|
||
error,
|
||
refresh,
|
||
createBrand,
|
||
isCreatingBrand,
|
||
mutationError,
|
||
createMonitoringTask,
|
||
};
|
||
}
|