189 lines
5.6 KiB
JavaScript
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,
|
|
};
|
|
}
|