forked from phenom/healer-man
Update Healer Man server
This commit is contained in:
1 parent
9c5fb4c614
commit
bd073fb00f
113 files changed
+4902
-273
No files matched your search
@@ -0,0 +1,113 @@
|
||||
import { create } from "zustand";
|
||||
import { requestOnlineJson } from "./onlineAccountClient";
|
||||
import type { PlayerSession } from "./types";
|
||||
import {
|
||||
DEFAULT_DUNGEON_QUEUE_POLICY,
|
||||
normalizeDungeonQueuePolicy,
|
||||
type DungeonQueueMode,
|
||||
type DungeonQueuePolicy,
|
||||
} from "../game/dungeonQueuePolicy";
|
||||
|
||||
interface PublishedPolicy {
|
||||
readonly revision: number;
|
||||
readonly updatedAt: number | null;
|
||||
readonly updatedBy?: string | null;
|
||||
readonly config: DungeonQueuePolicy;
|
||||
}
|
||||
|
||||
interface PolicyState extends PublishedPolicy {
|
||||
readonly draft: DungeonQueuePolicy;
|
||||
readonly loading: boolean;
|
||||
readonly saving: boolean;
|
||||
readonly dirty: boolean;
|
||||
readonly error: string | null;
|
||||
refresh: (session: PlayerSession | null) => Promise<void>;
|
||||
setEnabled: (mode: DungeonQueueMode, dungeonId: string, enabled: boolean) => void;
|
||||
resetDraft: () => void;
|
||||
publish: (session: PlayerSession | null) => Promise<boolean>;
|
||||
}
|
||||
|
||||
const CACHE_KEY = "healer-man.dungeon-queue-policy.v1";
|
||||
|
||||
function cached(): PublishedPolicy {
|
||||
try {
|
||||
const value = JSON.parse(globalThis.localStorage?.getItem(CACHE_KEY) ?? "null") as PublishedPolicy;
|
||||
if (!Number.isInteger(value.revision)) throw new Error("missing");
|
||||
return { ...value, config: normalizeDungeonQueuePolicy(value.config) };
|
||||
} catch {
|
||||
return { revision: 0, updatedAt: null, config: DEFAULT_DUNGEON_QUEUE_POLICY };
|
||||
}
|
||||
}
|
||||
|
||||
function cache(value: PublishedPolicy): void {
|
||||
try { globalThis.localStorage?.setItem(CACHE_KEY, JSON.stringify(value)); } catch { /* offline cache is optional */ }
|
||||
}
|
||||
|
||||
function normalized(value: PublishedPolicy): PublishedPolicy {
|
||||
return { ...value, config: normalizeDungeonQueuePolicy(value.config) };
|
||||
}
|
||||
|
||||
/** Fetch for each random roll so a newly published GM setting is used without a reload. */
|
||||
export async function loadDungeonQueuePolicy(): Promise<DungeonQueuePolicy> {
|
||||
try {
|
||||
const value = normalized(await requestOnlineJson<PublishedPolicy>("/api/dungeon-queue-policy"));
|
||||
cache(value);
|
||||
useDungeonQueuePolicyStore.setState((state) => state.dirty ? state : { ...value, draft: value.config });
|
||||
return value.config;
|
||||
} catch {
|
||||
return cached().config;
|
||||
}
|
||||
}
|
||||
|
||||
const initial = cached();
|
||||
export const useDungeonQueuePolicyStore = create<PolicyState>((set, get) => ({
|
||||
...initial,
|
||||
draft: initial.config,
|
||||
loading: false,
|
||||
saving: false,
|
||||
dirty: false,
|
||||
error: null,
|
||||
refresh: async (session) => {
|
||||
set({ loading: true, error: null });
|
||||
try {
|
||||
const gm = Boolean(session?.accessToken && session.roles?.includes("gm"));
|
||||
const value = normalized(await requestOnlineJson<PublishedPolicy>(
|
||||
gm ? "/api/gm/dungeon-queue-policy" : "/api/dungeon-queue-policy",
|
||||
{}, gm ? session?.accessToken : undefined,
|
||||
));
|
||||
cache(value);
|
||||
set({ ...value, draft: value.config, loading: false, dirty: false });
|
||||
} catch (error) {
|
||||
set({ loading: false, error: error instanceof Error ? error.message : "Could not load dungeon queue settings." });
|
||||
}
|
||||
},
|
||||
setEnabled: (mode, dungeonId, enabled) => set((state) => {
|
||||
const ids = new Set(state.draft.disabled[mode]);
|
||||
if (enabled) ids.delete(dungeonId);
|
||||
else ids.add(dungeonId);
|
||||
return {
|
||||
draft: { schemaVersion: 1, disabled: { ...state.draft.disabled, [mode]: [...ids].sort() } },
|
||||
dirty: true,
|
||||
error: null,
|
||||
};
|
||||
}),
|
||||
resetDraft: () => set((state) => ({ draft: state.config, dirty: false, error: null })),
|
||||
publish: async (session) => {
|
||||
if (!session?.accessToken || !session.roles?.includes("gm")) {
|
||||
set({ error: "Game Master access is required." });
|
||||
return false;
|
||||
}
|
||||
set({ saving: true, error: null });
|
||||
try {
|
||||
const value = normalized(await requestOnlineJson<PublishedPolicy>("/api/gm/dungeon-queue-policy", {
|
||||
method: "PUT", body: JSON.stringify({ expectedRevision: get().revision, config: get().draft }),
|
||||
}, session.accessToken));
|
||||
cache(value);
|
||||
set({ ...value, draft: value.config, saving: false, dirty: false });
|
||||
return true;
|
||||
} catch (error) {
|
||||
set({ saving: false, error: error instanceof Error ? error.message : "Could not publish dungeon queue settings." });
|
||||
return false;
|
||||
}
|
||||
},
|
||||
}));
|
||||
Reference in new issue
Block a user