first commit

This commit is contained in:
2026-04-26 21:27:00 +07:00
commit 3ce6f0510b
48 changed files with 9700 additions and 0 deletions
+89
View File
@@ -0,0 +1,89 @@
import { create } from "zustand";
import { apiJson } from "@/utils/api";
import type { AppConfig, Camera, Schedule } from "@/types/api";
type ConfigState = {
config: AppConfig | null;
isLoading: boolean;
error: string | null;
load: () => Promise<void>;
addCamera: (camera: Camera) => Promise<void>;
deleteCamera: (name: string) => Promise<void>;
setSchedulerEnabled: (enabled: boolean) => Promise<void>;
updateSchedule: (schedule: Omit<Schedule, "enabled">) => Promise<void>;
};
function errToMessage(err: unknown) {
if (!err) return "unknown_error";
if (typeof err === "string") return err;
if (typeof err === "object" && err && "status" in err) {
const e = err as { status: number; bodyText?: string };
return `http_${e.status}${e.bodyText ? `: ${e.bodyText}` : ""}`;
}
return "unknown_error";
}
export const useConfigStore = create<ConfigState>((set, get) => ({
config: null,
isLoading: false,
error: null,
load: async () => {
set({ isLoading: true, error: null });
try {
const cfg = await apiJson<AppConfig>("/config", { method: "GET" });
set({ config: cfg, isLoading: false });
} catch (e) {
set({ isLoading: false, error: errToMessage(e) });
}
},
addCamera: async (camera) => {
set({ isLoading: true, error: null });
try {
const cfg = await apiJson<AppConfig>("/cameras", {
method: "POST",
body: JSON.stringify(camera),
});
set({ config: cfg, isLoading: false });
} catch (e) {
set({ isLoading: false, error: errToMessage(e) });
}
},
deleteCamera: async (name) => {
set({ isLoading: true, error: null });
try {
const cfg = await apiJson<AppConfig>(`/cameras/${encodeURIComponent(name)}`, {
method: "DELETE",
});
set({ config: cfg, isLoading: false });
} catch (e) {
set({ isLoading: false, error: errToMessage(e) });
}
},
setSchedulerEnabled: async (enabled) => {
set({ isLoading: true, error: null });
try {
const cfg = await apiJson<AppConfig>("/scheduler/enabled", {
method: "POST",
body: JSON.stringify({ enabled }),
});
set({ config: cfg, isLoading: false });
} catch (e) {
set({ isLoading: false, error: errToMessage(e) });
}
},
updateSchedule: async (schedule) => {
const cfg = get().config;
const enabled = cfg?.schedule.enabled ?? true;
set({ isLoading: true, error: null });
try {
const next = await apiJson<AppConfig>("/scheduler/schedule", {
method: "POST",
body: JSON.stringify(schedule),
});
set({ config: { ...next, schedule: { ...next.schedule, enabled } }, isLoading: false });
} catch (e) {
set({ isLoading: false, error: errToMessage(e) });
}
},
}));