101 lines
2.7 KiB
TypeScript
101 lines
2.7 KiB
TypeScript
"use client";
|
|
|
|
import type {
|
|
ChatAction,
|
|
ChatActionEventType,
|
|
} from "@/data/schemas/chat";
|
|
import { chatApi } from "@/data/services/api";
|
|
|
|
const EVENT_PREFIX = "cozsweet:chat-action-event:v1";
|
|
const ARRIVAL_KEY = "cozsweet:chat-action-arrival:v1";
|
|
|
|
interface PendingChatActionArrival {
|
|
actionId: string;
|
|
characterId: string;
|
|
expectedPath: string;
|
|
}
|
|
|
|
export async function recordChatActionEvent(
|
|
action: ChatAction,
|
|
characterId: string,
|
|
eventType: ChatActionEventType,
|
|
): Promise<void> {
|
|
await recordChatActionEventById(action.actionId, characterId, eventType);
|
|
}
|
|
|
|
export async function recordChatActionEventById(
|
|
actionId: string,
|
|
characterId: string,
|
|
eventType: ChatActionEventType,
|
|
): Promise<void> {
|
|
await chatApi.recordActionEvent({
|
|
eventId: getOrCreateEventId(actionId, eventType),
|
|
actionId,
|
|
characterId,
|
|
eventType,
|
|
});
|
|
}
|
|
|
|
export function rememberChatActionArrival(
|
|
action: ChatAction,
|
|
characterId: string,
|
|
targetUrl: string,
|
|
): void {
|
|
if (typeof window === "undefined") return;
|
|
const target = new URL(targetUrl, window.location.origin);
|
|
if (target.origin !== window.location.origin) return;
|
|
const pending: PendingChatActionArrival = {
|
|
actionId: action.actionId,
|
|
characterId,
|
|
expectedPath: target.pathname,
|
|
};
|
|
window.sessionStorage.setItem(ARRIVAL_KEY, JSON.stringify(pending));
|
|
}
|
|
|
|
export function readPendingChatActionArrival(): PendingChatActionArrival | null {
|
|
if (typeof window === "undefined") return null;
|
|
try {
|
|
const raw = window.sessionStorage.getItem(ARRIVAL_KEY);
|
|
if (!raw) return null;
|
|
const parsed = JSON.parse(raw) as Partial<PendingChatActionArrival>;
|
|
if (!parsed.actionId || !parsed.characterId || !parsed.expectedPath) {
|
|
return null;
|
|
}
|
|
return parsed as PendingChatActionArrival;
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export function clearPendingChatActionArrival(): void {
|
|
if (typeof window === "undefined") return;
|
|
window.sessionStorage.removeItem(ARRIVAL_KEY);
|
|
}
|
|
|
|
function getOrCreateEventId(
|
|
actionId: string,
|
|
eventType: ChatActionEventType,
|
|
): string {
|
|
const key = `${EVENT_PREFIX}:${actionId}:${eventType}`;
|
|
if (typeof window !== "undefined") {
|
|
const existing = window.sessionStorage.getItem(key);
|
|
if (existing) return existing;
|
|
}
|
|
const eventId = createUuid();
|
|
if (typeof window !== "undefined") {
|
|
window.sessionStorage.setItem(key, eventId);
|
|
}
|
|
return eventId;
|
|
}
|
|
|
|
function createUuid(): string {
|
|
if (typeof globalThis.crypto?.randomUUID === "function") {
|
|
return globalThis.crypto.randomUUID();
|
|
}
|
|
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (value) => {
|
|
const random = Math.floor(Math.random() * 16);
|
|
const next = value === "x" ? random : (random & 0x3) | 0x8;
|
|
return next.toString(16);
|
|
});
|
|
}
|