Changeset 70677e96 in Klonkt for src/routes/guardian.js


Ignore:
Timestamp:
07/28/2026 07:43:49 PM (6 weeks ago)
Author:
Robin Genis <roboburr@…>
Branches:
main
Children:
742ba7e
Parents:
a7bcf66
Message:

Guardian-PWA: een paneel per kind

/guardian was een platte lijst van zeven secties: de wards' berichten, de
volgverzoeken, de hulpvragen, adopteren, verzonden aanvragen, wards, meldingen.
Wie een kind wilde overzien moest tussen die secties heen en weer, en nergens
stond bij elkaar wat er over dat ene kind speelt. Een guardian denkt niet per
functie maar per kind.

Nu is de wards-lijst de ingang: elk kind is een regel die opent naar een paneel
met zijn instellingen, zijn volgverzoeken, zijn hulpvragen en zijn recente
berichten. De regel zelf draagt de tellers (hulpvragen, volgverzoeken), zodat
een dicht paneel nooit iets verbergt dat een antwoord nodig heeft; dat is
belangrijk voor de volgverzoeken, want daar zit de follow-gating in.

De hulpvragen blijven daarnaast bovenaan staan, over alle kinderen heen, want
dat is waar deze app voor bestaat en het moet opvallen zonder dat je eerst een
kind opent. Ze verschijnen dus bewust twee keer: bovenaan de recente, in het
paneel de volledige geschiedenis van dat kind.

De hulpvraag is geen alarm. Er wordt niemand automatisch gewaarschuwd; een
guardian kan hem stil oplossen. De kaart is daarom rustig gehouden.

Changed files:
src/views/pages/guardian.ejs

  • feed-section en follow-section weg als losse secties

src/assets/js/guardian.js

  • helpCard, feedCard en followCard losgetrokken zodat beide plekken ze delen
  • wardPanel: instellingen, volgverzoeken, hulpvragen, berichten, acties
  • openPanels onthoudt wat open staat, zodat verversen niet dichtklapt
  • feed en volgverzoeken vullen nu een cache en hertekenen de wards-lijst

src/assets/css/guardian.css

  • opmaak voor het paneel en de tellers op de regel

src/routes/guardian.js

  • authorUri en wardUri meegeven: de sleutels waarop gegroepeerd wordt
  • de nieuwe labels toegevoegd aan uiStrings

src/services/i18n.js

  • 39 strings voor het paneel in nl, en, de

New file:
test/guardian-panel.test.js

  • de client schrijft nergens naar een verdwenen sectie
  • elke paneelsectie heeft zijn groepeersleutel
  • elk label dat de client gebruikt wordt ook geserveerd

remarks: geverifieerd in de browser op een wegwerp-database met twee kinderen:
elk paneel toont alleen zijn eigen volgverzoek, hulpvraag en post, een geopend
paneel blijft open over een ververs-ronde heen, en op 375px loopt niets buiten
beeld. De afhandel-lifecycle (oppakken/afgehandeld, shaer-jxi) en luid publiek
als tweede gated feature (shaer-3kp) komen hierna in dit paneel.

-robo
Co-Authored-By: Claude Opus 4.8 <noreply@…>

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/routes/guardian.js

    ra7bcf66 r70677e96  
    4141    'pending', 'active', 'retract', 'release', 'release_confirm', 'open', 'push_unavailable',
    4242    'embeds_on', 'embeds_off', 'embeds_propose', 'embeds_waiting',
    43     'accept', 'reject', 'complete', 'awaiting_others', 'coguard'];
     43    'accept', 'reject', 'complete', 'awaiting_others', 'coguard',
     44    // The per-ward panel: everything about one child in one place.
     45    'settings_title', 'panel_open', 'panel_close', 'panel_help', 'panel_help_empty',
     46    'panel_follow', 'panel_follow_empty', 'panel_posts', 'panel_posts_empty',
     47    'panel_actions', 'badge_help', 'badge_follow', 'badge_follow_one', 'help_empty'];
    4448  const s = Object.fromEntries(keys.map((k) => [k, i18nT(L, `guardian.${k}`)]));
    4549  s.wave = i18nT(L, 'guardian.wave');
     
    139143      id: p.id,
    140144      author: p.author_handle || p.author_name || p.author_uri,
     145      authorUri: p.author_uri,   // the grouping key: which child's panel this belongs in
    141146      authorName: p.author_name,
    142147      authorIcon: p.author_icon,
     
    157162  const base = (process.env.PUBLIC_BASE_URL || '').replace(/\/+$/, '');
    158163  return Guardianship.listWards(site.slug)
    159     .map((w) => (w.other_uri.startsWith(base) ? w.other_uri.split('/').pop() : null))
     164    .map((w) => (w.other_uri.startsWith(base) ? { slug: w.other_uri.split('/').pop(), uri: w.other_uri } : null))
    160165    .filter(Boolean);
    161166}
     
    166171  const items = [];
    167172  const host = (() => { try { return new URL(process.env.PUBLIC_BASE_URL || '').host; } catch { return ''; } })();
     173  // wardUri is the grouping key for the per-ward panel: the handle is for
     174  // reading, the URI is what identifies the child across both cases below.
    168175  // Local wards (guardian co-located): read the pending follows directly.
    169   for (const wardSlug of wardSlugsOf(site)) {
    170     for (const f of Guardianship.follows.listForWard(wardSlug)) {
    171       items.push({ id: f.id, ward: `@${wardSlug}@${host}`, follower: f.follower_handle || f.follower_name || f.follower_uri, followerIcon: f.follower_icon, remote: false, created: f.created_at });
     176  for (const w of wardSlugsOf(site)) {
     177    for (const f of Guardianship.follows.listForWard(w.slug)) {
     178      items.push({ id: f.id, ward: `@${w.slug}@${host}`, wardUri: w.uri, follower: f.follower_handle || f.follower_name || f.follower_uri, followerIcon: f.follower_icon, remote: false, created: f.created_at });
    172179    }
    173180  }
     
    175182  for (const rev of Guardianship.follows.listReviews(site.slug)) {
    176183    const wardName = (() => { try { const u = new URL(rev.ward_uri); return `@${u.pathname.split('/').pop()}@${u.host}`; } catch { return rev.ward_uri; } })();
    177     items.push({ id: rev.id, ward: wardName, follower: rev.follower_handle || rev.follower_uri, followerIcon: rev.follower_icon, remote: true, created: rev.created_at });
     184    items.push({ id: rev.id, ward: wardName, wardUri: rev.ward_uri, follower: rev.follower_handle || rev.follower_uri, followerIcon: rev.follower_icon, remote: true, created: rev.created_at });
    178185  }
    179186  res.json({ items });
Note: See TracChangeset for help on using the changeset viewer.