feat: conformite enonce - explorer, favoris, stats perso, tests, slots
Some checks failed
Deploy XIP / deploy (push) Failing after 37s
Some checks failed
Deploy XIP / deploy (push) Failing after 37s
Fonctionnel
- Backend messages : GET /api/messages/:id (detail) + recherche (q),
pagination par curseur (before/limit) avec enveloppe { items, nextCursor,
hasMore } ; le flux temps reel garde l'ancien format quand aucun parametre.
- Explorer (/explorer) : catalogue distant, recherche debouncee + annulable
(AbortController), filtre, defilement infini, etat garde (keep-alive).
- Details par id : /message/:id et /shop/p/:id (consomment route.params).
- Favoris (/favoris) : liste perso persistee en localStorage, notation
(note/rating/statut) via modale, refletee partout (bouton favori).
- Mes stats (/mes-stats) : agregats derives des favoris (note moyenne, top
pays/auteurs, statuts), auto-mis a jour, route gardee si liste vide.
- Routeur : pages secondaires en lazy-load + repli, garde beforeEnter.
Technique
- Slots : PrefSection (slot defaut + slot nomme) enveloppe les 5 sections
"Mes Persos" ; Modal (Teleport + slots).
- v-model custom : SearchBox (defineModel + debounce).
- Directive custom : v-click-outside.
- Tests Vitest : 25 tests (etat, fonctions, composants), ~86% du code metier.
- Retrait d'Ionic (inutilise). Script typecheck backend ; tsconfig @types/bun.
- Correctif type : garde stockLimit nullable dans l'achat (catalog.ts).
- README complet (URL, stack, run, tests, secrets, deploiement, mention IA).
This commit is contained in:
@@ -1,40 +1,40 @@
|
||||
import { Hono } from "hono";
|
||||
import { listActiveAds, recordImpressions } from "../lib/ads";
|
||||
|
||||
const ads = new Hono();
|
||||
|
||||
// GET /api/ads?kind=band → active ad set for that slot (client rotates).
|
||||
ads.get("/", async (c) => {
|
||||
const kind = c.req.query("kind") === "casino" ? "casino" : "band";
|
||||
const list = await listActiveAds(kind);
|
||||
// Expose only what the UI needs.
|
||||
return c.json(
|
||||
list.map((a) => ({
|
||||
id: a.id,
|
||||
brand: a.brand,
|
||||
subtitle: a.subtitle,
|
||||
url: a.url,
|
||||
cta: a.cta,
|
||||
icon: a.icon,
|
||||
tone: a.tone,
|
||||
kind: a.kind,
|
||||
ownerIp: a.ownerIp,
|
||||
imageUrl: a.imageUrl,
|
||||
}))
|
||||
);
|
||||
});
|
||||
|
||||
// POST /api/ads/impressions { ids: [...] }
|
||||
ads.post("/impressions", async (c) => {
|
||||
let body: { ids?: string[] } = {};
|
||||
try {
|
||||
body = await c.req.json();
|
||||
} catch {
|
||||
return c.json({ error: "JSON invalide" }, 400);
|
||||
}
|
||||
const ids = Array.isArray(body.ids) ? body.ids.filter((x) => typeof x === "string") : [];
|
||||
await recordImpressions(ids);
|
||||
return c.json({ ok: true, counted: ids.length });
|
||||
});
|
||||
|
||||
export default ads;
|
||||
import { Hono } from "hono";
|
||||
import { listActiveAds, recordImpressions } from "../lib/ads";
|
||||
|
||||
const ads = new Hono();
|
||||
|
||||
// GET /api/ads?kind=band → active ad set for that slot (client rotates).
|
||||
ads.get("/", async (c) => {
|
||||
const kind = c.req.query("kind") === "casino" ? "casino" : "band";
|
||||
const list = await listActiveAds(kind);
|
||||
// Expose only what the UI needs.
|
||||
return c.json(
|
||||
list.map((a) => ({
|
||||
id: a.id,
|
||||
brand: a.brand,
|
||||
subtitle: a.subtitle,
|
||||
url: a.url,
|
||||
cta: a.cta,
|
||||
icon: a.icon,
|
||||
tone: a.tone,
|
||||
kind: a.kind,
|
||||
ownerIp: a.ownerIp,
|
||||
imageUrl: a.imageUrl,
|
||||
}))
|
||||
);
|
||||
});
|
||||
|
||||
// POST /api/ads/impressions { ids: [...] }
|
||||
ads.post("/impressions", async (c) => {
|
||||
let body: { ids?: string[] } = {};
|
||||
try {
|
||||
body = await c.req.json();
|
||||
} catch {
|
||||
return c.json({ error: "JSON invalide" }, 400);
|
||||
}
|
||||
const ids = Array.isArray(body.ids) ? body.ids.filter((x) => typeof x === "string") : [];
|
||||
await recordImpressions(ids);
|
||||
return c.json({ ok: true, counted: ids.length });
|
||||
});
|
||||
|
||||
export default ads;
|
||||
|
||||
Reference in New Issue
Block a user