189 lines
5.6 KiB
JavaScript

import { useEffect, useMemo, useState } from "react";
import { parseForm } from "@/shared/forms/validation";
import { useRegionOptions } from "@/shared/hooks/useRegionOptions.js";
import { usePaginatedQuery } from "@/shared/hooks/usePaginatedQuery.js";
import { useConfirm } from "@/shared/ui/ConfirmProvider.jsx";
import { useToast } from "@/shared/ui/ToastProvider.jsx";
import { cancelRoomPin, createRoomPin, listRoomPins, listRooms } from "@/features/rooms/api";
import { useRoomAbilities } from "@/features/rooms/permissions.js";
import { roomPinCreateSchema } from "@/features/rooms/schema";
const pageSize = 10;
const emptyData = { items: [], page: 1, pageSize, total: 0 };
const emptyForm = () => ({ durationDays: "30", roomId: "", weight: "0" });
export function useRoomPinsPage() {
const abilities = useRoomAbilities();
const confirm = useConfirm();
const { showToast } = useToast();
const { loadingRegions, regionOptions } = useRegionOptions();
const [query, setQuery] = useState("");
const [regionId, setRegionId] = useState("");
const [status, setStatus] = useState("active");
const [page, setPage] = useState(1);
const [activeAction, setActiveAction] = useState("");
const [form, setForm] = useState(emptyForm);
const [loadingAction, setLoadingAction] = useState("");
const [roomSearch, setRoomSearch] = useState("");
const [roomOptionsState, setRoomOptionsState] = useState({ error: "", loading: false, options: [] });
const filters = useMemo(
() => ({
keyword: query,
region_id: regionId,
status,
}),
[query, regionId, status],
);
const {
data = emptyData,
error,
loading,
reload,
} = usePaginatedQuery({
errorMessage: "加载房间置顶列表失败",
fetcher: listRoomPins,
filters,
page,
pageSize,
queryKey: ["room-pins", filters, page],
});
useEffect(() => {
if (activeAction !== "create") {
return undefined;
}
let cancelled = false;
const timer = window.setTimeout(async () => {
setRoomOptionsState((current) => ({ ...current, error: "", loading: true }));
try {
const data = await listRooms({
keyword: roomSearch.trim(),
page: 1,
page_size: 20,
status: "active",
});
if (!cancelled) {
setRoomOptionsState({ error: "", loading: false, options: data?.items || [] });
}
} catch (err) {
if (!cancelled) {
setRoomOptionsState({ error: err.message || "搜索房间失败", loading: false, options: [] });
}
}
}, 300);
return () => {
cancelled = true;
window.clearTimeout(timer);
};
}, [activeAction, roomSearch]);
const changeQuery = (value) => {
setQuery(value);
setPage(1);
};
const changeRegionId = (value) => {
setRegionId(value);
setPage(1);
};
const changeStatus = (value) => {
setStatus(value || "active");
setPage(1);
};
const resetFilters = () => {
setQuery("");
setRegionId("");
setStatus("active");
setPage(1);
};
const openCreate = () => {
setForm(emptyForm());
setRoomSearch("");
setRoomOptionsState({ error: "", loading: false, options: [] });
setActiveAction("create");
};
const closeAction = () => {
setActiveAction("");
};
const submitCreate = async (event) => {
event.preventDefault();
await runAction("create", "房间已置顶", async () => {
const payload = parseForm(roomPinCreateSchema, form);
await createRoomPin(payload);
closeAction();
await reload();
});
};
const cancelPin = async (pin) => {
const room = pin.room || {};
const ok = await confirm({
confirmText: "取消置顶",
message: room.title || room.roomShortId || room.roomId,
title: "取消房间置顶",
tone: "danger",
});
if (!ok) {
return;
}
await runAction(`cancel-${pin.id}`, "房间置顶已取消", async () => {
await cancelRoomPin(pin.id);
await reload();
});
};
const runAction = async (action, successMessage, submitter) => {
setLoadingAction(action);
try {
await submitter();
showToast(successMessage, "success");
} catch (err) {
showToast(err.message || "操作失败", "error");
} finally {
setLoadingAction("");
}
};
const selectedRoom = roomOptionsState.options.find((room) => room.roomId === form.roomId) || null;
return {
abilities,
activeAction,
cancelPin,
changeQuery,
changeRegionId,
changeStatus,
closeAction,
data,
error,
form,
loading,
loadingAction,
loadingRegions,
openCreate,
page,
query,
regionId,
regionOptions,
reload,
resetFilters,
roomOptions: roomOptionsState.options,
roomOptionsError: roomOptionsState.error,
roomOptionsLoading: roomOptionsState.loading,
roomSearch,
selectedRoom,
setForm,
setPage,
setRoomSearch,
status,
submitCreate,
};
}