feat: update styles and enhance pet purchase flow in marketplace components

This commit is contained in:
arussac
2026-05-31 15:15:48 +02:00
parent 02bba16285
commit 21e35107c7
11 changed files with 99 additions and 99 deletions

View File

@@ -39,6 +39,37 @@ export interface Message extends Reply {
const API_URL = import.meta.env.VITE_API_URL ?? 'http://localhost:3000';
/** Refresh the viewer's own perks from the server (callable from anywhere). */
export async function refreshMyPerks(): Promise<void> {
try {
const res = await fetch(`${API_URL}/api/shop/me`);
if (!res.ok) return;
const { entitlements } = (await res.json()) as {
entitlements: { kind: string; metaJson?: string | null }[];
};
const p: Perks = {};
const pets: { char: string; position: 'left' | 'right' | 'both' }[] = [];
for (const e of entitlements) {
let meta: any = {};
try { meta = e.metaJson ? JSON.parse(e.metaJson) : {}; } catch { /* */ }
if (e.kind === 'noads') { p.noads = true; if (meta.plan === 'annual') p.badge = true; }
if (e.kind === 'style-dore') p.skin = 'gold';
if (e.kind === 'pet' && meta.char) pets.push({ char: meta.char, position: meta.position ?? 'left' });
if (e.kind === 'element-skin') p.elementSkin = true;
if (e.kind === 'rich-htmlcss') p.richHtmlcss = true;
if (e.kind === 'rich-js') p.richJs = true;
if (e.kind === 'no-file-limit') p.noFileLimit = true;
if (e.kind === 'audio-alert') p.audioAlert = true;
}
if (pets.length) p.pets = pets;
myPerks.value = p;
const { ip } = useWallet();
if (ip.value) setPerks(ip.value, p);
} catch {
/* ignore */
}
}
export function useMessages() {
const messages = ref<Message[]>([]);
const loading = ref(false);
@@ -102,32 +133,7 @@ export function useMessages() {
// myPerks is module-level; this ref is the same reference.
async function fetchMyPerks(): Promise<void> {
try {
const res = await fetch(`${API_URL}/api/shop/me`);
if (!res.ok) return;
const { entitlements } = (await res.json()) as {
entitlements: { kind: string; metaJson?: string | null }[];
};
const p: Perks = {};
const pets: { char: string; position: 'left' | 'right' | 'both' }[] = [];
for (const e of entitlements) {
let meta: any = {};
try { meta = e.metaJson ? JSON.parse(e.metaJson) : {}; } catch { /* */ }
if (e.kind === 'noads') { p.noads = true; if (meta.plan === 'annual') p.badge = true; }
if (e.kind === 'style-dore') p.skin = 'gold';
if (e.kind === 'pet' && meta.char) pets.push({ char: meta.char, position: meta.position ?? 'left' });
if (e.kind === 'element-skin') p.elementSkin = true;
if (e.kind === 'rich-htmlcss') p.richHtmlcss = true;
if (e.kind === 'rich-js') p.richJs = true;
if (e.kind === 'no-file-limit') p.noFileLimit = true;
if (e.kind === 'audio-alert') p.audioAlert = true;
}
if (pets.length) p.pets = pets.slice(0, 3);
myPerks.value = p;
if (myIp.value) setPerks(myIp.value, p);
} catch {
/* ignore */
}
return refreshMyPerks();
}
const { stats, connected, sendTyping } = useRealtime({