129 lines
4.6 KiB
TypeScript
129 lines
4.6 KiB
TypeScript
import { ref } from "vue";
|
|
import { defineStore } from "pinia";
|
|
import * as api from "@/api/rulebooks";
|
|
import type { Rulebook, RulebookTopic, Rule, RuleHeader } from "@/api/rulebooks";
|
|
import { useToastStore } from "@/stores/toast";
|
|
|
|
export const useRulebooksStore = defineStore("rulebooks", () => {
|
|
const rulebooks = ref<Rulebook[]>([]);
|
|
const topicsByRulebook = ref<Record<number, RulebookTopic[]>>({});
|
|
const rulesByTopic = ref<Record<number, RuleHeader[]>>({});
|
|
const currentRule = ref<Rule | null>(null);
|
|
const loading = ref(false);
|
|
|
|
async function fetchRulebooks() {
|
|
loading.value = true;
|
|
try {
|
|
rulebooks.value = await api.listRulebooks();
|
|
} catch (e) {
|
|
useToastStore().show("Failed to load rulebooks", "error");
|
|
throw e;
|
|
} finally {
|
|
loading.value = false;
|
|
}
|
|
}
|
|
|
|
async function fetchTopics(rulebookId: number) {
|
|
try {
|
|
topicsByRulebook.value[rulebookId] = await api.listTopics(rulebookId);
|
|
} catch (e) {
|
|
useToastStore().show("Failed to load topics", "error");
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
async function fetchRules(topicId: number) {
|
|
try {
|
|
const rules = await api.listRules({ topic_id: topicId });
|
|
rulesByTopic.value[topicId] = rules.map((r) => ({
|
|
id: r.id, title: r.title, statement: r.statement, topic_id: r.topic_id,
|
|
}));
|
|
} catch (e) {
|
|
useToastStore().show("Failed to load rules", "error");
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
async function fetchRule(id: number) {
|
|
currentRule.value = await api.getRule(id);
|
|
}
|
|
|
|
async function createRulebook(data: { title: string; description?: string }) {
|
|
const rb = await api.createRulebook(data);
|
|
rulebooks.value.push(rb);
|
|
return rb;
|
|
}
|
|
|
|
async function updateRulebook(id: number, data: Partial<Pick<Rulebook, "title" | "description">>) {
|
|
const rb = await api.updateRulebook(id, data);
|
|
const idx = rulebooks.value.findIndex((r) => r.id === id);
|
|
if (idx >= 0) rulebooks.value[idx] = rb;
|
|
return rb;
|
|
}
|
|
|
|
async function deleteRulebook(id: number) {
|
|
await api.deleteRulebook(id);
|
|
rulebooks.value = rulebooks.value.filter((r) => r.id !== id);
|
|
delete topicsByRulebook.value[id];
|
|
}
|
|
|
|
async function createTopic(rulebookId: number, data: { title: string; description?: string }) {
|
|
const topic = await api.createTopic(rulebookId, data);
|
|
if (!topicsByRulebook.value[rulebookId]) topicsByRulebook.value[rulebookId] = [];
|
|
topicsByRulebook.value[rulebookId].push(topic);
|
|
return topic;
|
|
}
|
|
|
|
async function updateTopic(id: number, data: Partial<Pick<RulebookTopic, "title" | "description" | "order_index">>) {
|
|
const topic = await api.updateTopic(id, data);
|
|
for (const rbId of Object.keys(topicsByRulebook.value)) {
|
|
const list = topicsByRulebook.value[Number(rbId)];
|
|
const idx = list.findIndex((t) => t.id === id);
|
|
if (idx >= 0) list[idx] = topic;
|
|
}
|
|
return topic;
|
|
}
|
|
|
|
async function deleteTopic(id: number) {
|
|
await api.deleteTopic(id);
|
|
for (const rbId of Object.keys(topicsByRulebook.value)) {
|
|
topicsByRulebook.value[Number(rbId)] = topicsByRulebook.value[Number(rbId)].filter((t) => t.id !== id);
|
|
}
|
|
delete rulesByTopic.value[id];
|
|
}
|
|
|
|
async function createRule(topicId: number, data: { title: string; statement: string; why?: string; how_to_apply?: string }) {
|
|
const rule = await api.createRule(topicId, data);
|
|
if (!rulesByTopic.value[topicId]) rulesByTopic.value[topicId] = [];
|
|
rulesByTopic.value[topicId].push({ id: rule.id, title: rule.title, statement: rule.statement, topic_id: rule.topic_id });
|
|
return rule;
|
|
}
|
|
|
|
async function updateRule(id: number, data: Partial<Pick<Rule, "title" | "statement" | "why" | "how_to_apply" | "order_index">>) {
|
|
const rule = await api.updateRule(id, data);
|
|
if (currentRule.value?.id === id) currentRule.value = rule;
|
|
for (const tid of Object.keys(rulesByTopic.value)) {
|
|
const list = rulesByTopic.value[Number(tid)];
|
|
const idx = list.findIndex((r) => r.id === id);
|
|
if (idx >= 0) list[idx] = { id: rule.id, title: rule.title, statement: rule.statement, topic_id: rule.topic_id };
|
|
}
|
|
return rule;
|
|
}
|
|
|
|
async function deleteRule(id: number) {
|
|
await api.deleteRule(id);
|
|
if (currentRule.value?.id === id) currentRule.value = null;
|
|
for (const tid of Object.keys(rulesByTopic.value)) {
|
|
rulesByTopic.value[Number(tid)] = rulesByTopic.value[Number(tid)].filter((r) => r.id !== id);
|
|
}
|
|
}
|
|
|
|
return {
|
|
rulebooks, topicsByRulebook, rulesByTopic, currentRule, loading,
|
|
fetchRulebooks, fetchTopics, fetchRules, fetchRule,
|
|
createRulebook, updateRulebook, deleteRulebook,
|
|
createTopic, updateTopic, deleteTopic,
|
|
createRule, updateRule, deleteRule,
|
|
};
|
|
});
|