2026-05-26 02:39:46 +08:00

184 lines
5.6 KiB
JavaScript

import { useCallback, useEffect, useMemo, useState } from "react";
import { parseForm } from "@/shared/forms/validation";
import { usePaginatedQuery } from "@/shared/hooks/usePaginatedQuery.js";
import { useToast } from "@/shared/ui/ToastProvider.jsx";
import { listResourceGroups } from "@/features/resources/api";
import {
getSevenDayCheckInConfig,
listSevenDayCheckInClaims,
updateSevenDayCheckInConfig,
} from "@/features/seven-day-checkin/api";
import { useSevenDayCheckInAbilities } from "@/features/seven-day-checkin/permissions.js";
import { sevenDayCheckInConfigFormSchema } from "@/features/seven-day-checkin/schema";
const pageSize = 50;
const emptyClaims = { items: [], page: 1, pageSize, total: 0 };
const emptyForm = {
enabled: false,
rewards: Array.from({ length: 7 }, (_, index) => ({
dayIndex: index + 1,
resourceGroupId: "",
})),
};
export function useSevenDayCheckInPage() {
const abilities = useSevenDayCheckInAbilities();
const { showToast } = useToast();
const [config, setConfig] = useState(null);
const [configDrawerOpen, setConfigDrawerOpen] = useState(false);
const [form, setForm] = useState(emptyForm);
const [configLoading, setConfigLoading] = useState(false);
const [configSaving, setConfigSaving] = useState(false);
const [resourceGroups, setResourceGroups] = useState([]);
const [query, setQuery] = useState("");
const [status, setStatus] = useState("");
const [checkinDay, setCheckinDay] = useState("");
const [dayIndex, setDayIndex] = useState("");
const [page, setPage] = useState(1);
const filters = useMemo(
() => ({ checkin_day: checkinDay, day_index: dayIndex, keyword: query, status }),
[checkinDay, dayIndex, query, status],
);
const {
data: claims = emptyClaims,
error: claimsError,
loading: claimsLoading,
reload: reloadClaims,
} = usePaginatedQuery({
errorMessage: "加载签到记录失败",
fetcher: listSevenDayCheckInClaims,
filters,
page,
pageSize,
queryKey: ["seven-day-checkin-claims", filters, page],
});
const reloadConfig = useCallback(async () => {
setConfigLoading(true);
try {
const [config, groups] = await Promise.all([
getSevenDayCheckInConfig(),
listResourceGroups({ page: 1, page_size: 100, status: "active" }),
]);
setConfig(config);
setForm(formFromConfig(config));
setResourceGroups(groups.items || []);
} catch (err) {
showToast(err.message || "加载七日签到配置失败", "error");
} finally {
setConfigLoading(false);
}
}, [showToast]);
useEffect(() => {
void reloadConfig();
}, [reloadConfig]);
const openConfigDrawer = useCallback(() => {
setForm(config ? formFromConfig(config) : emptyForm);
setConfigDrawerOpen(true);
}, [config]);
const closeConfigDrawer = useCallback(() => {
setConfigDrawerOpen(false);
setForm(config ? formFromConfig(config) : emptyForm);
}, [config]);
const changeQuery = (value) => {
setQuery(value);
setPage(1);
};
const changeStatus = (value) => {
setStatus(value);
setPage(1);
};
const changeCheckinDay = (value) => {
setCheckinDay(value);
setPage(1);
};
const changeDayIndex = (value) => {
setDayIndex(value);
setPage(1);
};
const submitConfig = async (event) => {
event.preventDefault();
if (!abilities.canUpdate) {
return;
}
setConfigSaving(true);
try {
const parsed = parseForm(sevenDayCheckInConfigFormSchema, form);
const saved = await updateSevenDayCheckInConfig(payloadFromForm(parsed));
setConfig(saved);
setForm(formFromConfig(saved));
setConfigDrawerOpen(false);
showToast("七日签到配置已保存", "success");
await reloadClaims();
} catch (err) {
showToast(err.message || "保存七日签到配置失败", "error");
} finally {
setConfigSaving(false);
}
};
return {
abilities,
changeCheckinDay,
changeDayIndex,
changeQuery,
changeStatus,
checkinDay,
claims,
claimsError,
claimsLoading,
closeConfigDrawer,
config,
configDrawerOpen,
configLoading,
configSaving,
dayIndex,
form,
openConfigDrawer,
page,
query,
reloadClaims,
reloadConfig,
resourceGroups,
setForm,
setPage,
status,
submitConfig,
};
}
function formFromConfig(config) {
return {
enabled: Boolean(config?.enabled),
rewards: Array.from({ length: 7 }, (_, index) => {
const dayIndex = index + 1;
const reward = config?.rewards?.find((item) => Number(item.dayIndex) === dayIndex);
return {
dayIndex,
resourceGroupId: reward?.resourceGroupId ? String(reward.resourceGroupId) : "",
};
}),
};
}
function payloadFromForm(form) {
return {
enabled: Boolean(form.enabled),
rewards: form.rewards
.map((reward) => ({
day_index: Number(reward.dayIndex),
resource_group_id: Number(reward.resourceGroupId || 0),
}))
.sort((left, right) => left.day_index - right.day_index),
};
}