nidus-sync/ts/store/resource.ts

134 lines
3.3 KiB
TypeScript
Raw Normal View History

import { defineStore } from "pinia";
2026-05-15 20:10:14 +00:00
import { ref, shallowRef } from "vue";
import { SSEManager, SSEMessageResource } from "@/SSEManager";
import { useSessionStore } from "@/store/session";
import { apiClient } from "@/client";
import {
Communication,
type CommunicationDTO,
2026-05-15 20:10:14 +00:00
Contact,
type ContactDTO,
PublicReport,
type PublicReportDTO,
} from "@/type/api";
interface uriHaver {
uri: string;
}
type jsonConverter<dto, full> = (arg: dto) => full;
function createResourceStore<dto, full extends uriHaver>(
resource_name: string,
api_base: string,
from_json: jsonConverter<dto, full>,
) {
const _resourceByURI = shallowRef<Map<string, full>>(new Map());
2026-05-15 20:10:14 +00:00
const _resourceFetchAll = ref<Promise<full[]> | null>(null);
const _resourceFetchByURI = shallowRef<Map<string, Promise<full> | null>>(
new Map(),
);
// Subscription
SSEManager.subscribe((msg: SSEMessageResource) => {
if (msg.resource.startsWith(resource_name) && msg.type == "updated") {
fetchByURI(msg.uri);
}
});
2026-05-15 20:10:14 +00:00
async function byAll(): Promise<full[]> {
const cur = _resourceFetchAll.value;
if (cur) {
return cur;
}
2026-05-15 20:10:14 +00:00
return fetchAll();
}
async function byID(id: string): Promise<full> {
const uri = uriFromID(id);
return byURI(uri);
}
async function byURI(uri: string): Promise<full> {
2026-05-15 20:10:14 +00:00
let cur = _resourceFetchByURI.value.get(uri);
if (cur) {
return cur;
}
2026-05-15 20:10:14 +00:00
cur = fetchByURI(uri);
_resourceFetchByURI.value.set(uri, cur);
return cur;
}
async function fetchAll(): Promise<full[]> {
/*
const sessionStore = useSessionStore();
const session = await sessionStore.get();
const params = new URLSearchParams();
params.append("sort", "-created");
const url = `${session.urls.api.mailer}?${params}`;
*/
const url = `/api${api_base}`;
const dtos = (await apiClient.JSONGet(url)) as dto[];
const resources = dtos.map((m: dto) => from_json(m));
resources.forEach((r: full) => {
_resourceByURI.value.set(r.uri, r);
});
return resources;
}
async function fetchByID(id: string): Promise<full> {
const uri = uriFromID(id);
return fetchByURI(uri);
}
async function fetchByURI(uri: string): Promise<full> {
try {
const response = await fetch(uri);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const body: dto = await response.json();
const report = from_json(body);
_resourceByURI.value.set(report.uri, report);
return report;
} catch (err) {
console.error("Error loading users:", err);
throw err;
}
}
function loadingAll(): boolean {
return !!_resourceFetchAll.value;
}
function loadingURI(uri: string): boolean {
return !!_resourceFetchByURI.value.get(uri);
}
function uriFromID(id: string): string {
return `${api_base}/${id}`;
}
return {
2026-05-15 20:10:14 +00:00
byAll,
byID,
byURI,
fetchAll,
2026-05-15 20:10:14 +00:00
fetchByID,
fetchByURI,
loadingAll,
loadingURI,
};
}
export const useStoreResource = defineStore("resource", () => {
return {
communication: createResourceStore<CommunicationDTO, Communication>(
"sync:communication",
"/communication",
Communication.fromJSON,
),
2026-05-15 20:10:14 +00:00
contact: createResourceStore<ContactDTO, Contact>(
"sync:contact",
"/contact",
Contact.fromJSON,
),
publicreport: createResourceStore<PublicReportDTO, PublicReport>(
"sync:publicreport",
"/publicreport",
PublicReport.fromJSON,
),
};
});