2026-05-15 17:10:03 +00:00
|
|
|
import { defineStore } from "pinia";
|
2026-05-15 20:10:14 +00:00
|
|
|
import { ref, shallowRef } from "vue";
|
2026-05-15 17:10:03 +00:00
|
|
|
|
|
|
|
|
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,
|
2026-05-15 17:10:03 +00:00
|
|
|
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);
|
2026-05-15 17:10:03 +00:00
|
|
|
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;
|
2026-05-15 17:10:03 +00:00
|
|
|
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);
|
2026-05-15 17:10:03 +00:00
|
|
|
}
|
|
|
|
|
async function byURI(uri: string): Promise<full> {
|
2026-05-15 20:10:14 +00:00
|
|
|
let cur = _resourceFetchByURI.value.get(uri);
|
2026-05-15 17:10:03 +00:00
|
|
|
if (cur) {
|
|
|
|
|
return cur;
|
|
|
|
|
}
|
2026-05-15 20:10:14 +00:00
|
|
|
cur = fetchByURI(uri);
|
|
|
|
|
_resourceFetchByURI.value.set(uri, cur);
|
|
|
|
|
return cur;
|
2026-05-15 17:10:03 +00:00
|
|
|
}
|
|
|
|
|
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 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 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,
|
2026-05-15 17:10:03 +00:00
|
|
|
byID,
|
|
|
|
|
byURI,
|
|
|
|
|
fetchAll,
|
2026-05-15 20:10:14 +00:00
|
|
|
fetchByID,
|
|
|
|
|
fetchByURI,
|
2026-05-15 17:10:03 +00:00
|
|
|
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,
|
|
|
|
|
),
|
2026-05-15 17:10:03 +00:00
|
|
|
publicreport: createResourceStore<PublicReportDTO, PublicReport>(
|
|
|
|
|
"sync:publicreport",
|
|
|
|
|
"/publicreport",
|
|
|
|
|
PublicReport.fromJSON,
|
|
|
|
|
),
|
|
|
|
|
};
|
|
|
|
|
});
|