Ignore:
Timestamp:
08/08/2026 06:35:21 AM (5 weeks ago)
Author:
roboburr <roboburr@…>
Branches:
main
Children:
2bfe26c
Parents:
cf5073b
git-author:
Robin <roboburr@…> (08/08/2026 06:35:19 AM)
git-committer:
roboburr <roboburr@…> (08/08/2026 06:35:21 AM)
Message:

De apps kunnen nu zien wat er voor een ward gated is (shaer-ahy.1)

Bart: iOS en Android op hetzelfde plan als de PWA. Dit is het blokkerende stuk --
zonder dit kan geen app een poort tonen.

wardsCollection gaf {id, handle, since}. Een app kon een ward dus wel TONEN maar
niets over hem zeggen, en dat is precies de helft van het antwoord op "wat mag
dit kind". Er zit nu shaer:gates bij: dezelfde rijen als het PWA-paneel, met
soort, drempel, lopend voorstel en omkeerbaarheid.

UIT DEZELFDE FUNCTIE, en dat is de kern. wardGates stond in routes/guardian.js
en daar kon alleen de PWA erbij. Een tweede berekening ernaast zou vroeg of laat
een ander antwoord geven op dezelfde vraag -- geen schoonheidsfoutje, maar twee
guardians die een verschillend beeld van hetzelfde kind krijgen. Verplaatst naar
queues.js; beide schermen lezen er nu uit, en een toets vergelijkt de twee
uitkomsten letterlijk met deepEqual.

Suite 688/688; zonder de nieuwe regel vallen er twee om.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/services/guardianship/queues.js

    rcf5073b rf3a2556  
    1414import * as outgoing from './outgoing.js';
    1515import * as follows from './follows.js';
     16import * as gated from './gated.js';
    1617import * as handshake from './handshake.js';
    1718
     
    9495export function wardsCollection(id, slug) {
    9596  const items = relations.listWards(slug)
    96     .map((r) => ({ id: r.other_uri, 'shaer:handle': r.other_handle || undefined, since: r.created_at }));
     97    .map((r) => ({
     98      id: r.other_uri,
     99      'shaer:handle': r.other_handle || undefined,
     100      since: r.created_at,
     101      // Alles wat voor dit kind gated is, met soort, drempel en lopend voorstel
     102      // (shaer-ahy.1). Zonder dit kon een app wel een ward TONEN maar niets over
     103      // hem zeggen -- en dat is precies de helft van het antwoord op "wat mag
     104      // dit kind". Dezelfde rijen als het PWA-paneel, uit dezelfde functie.
     105      'shaer:gates': wardGates(slug, r.other_uri),
     106    }));
    97107  return collection(id, items);
    98108}
     
    105115}
    106116
    107 export default { offersCollection, followsCollection, outgoingFollowsCollection, wardsCollection, guardiansCollection };
     117export default { offersCollection, followsCollection, outgoingFollowsCollection, wardsCollection, guardiansCollection, wardGates, wardGuardianStatuses };
     118
     119// ── Wat er voor een ward gated is (shaer-ahy.1) ─────────────────────────
     120//
     121// STOND IN routes/guardian.js, en daar kon alleen de PWA erbij. De Shaer-apps
     122// lezen dezelfde toestand via de wards-queue, en een tweede berekening naast
     123// deze zou vroeg of laat een ander antwoord geven op dezelfde vraag -- dat is
     124// hier geen schoonheidsfoutje maar twee guardians die een verschillend beeld
     125// van hetzelfde kind krijgen. Een plek dus, en beide schermen lezen eruit.
     126/** The guardians of a ward WE host, with availability (3.6.1: owner-only in
     127 *  spirit; the co-guardians are among the owners of the relationship). Null
     128 *  for a remote ward: its server tracks availability, not us. */
     129export function wardGuardianStatuses(wardUri) {
     130  const base = (process.env.PUBLIC_BASE_URL || '').replace(/\/+$/, '');
     131  if (!base || !String(wardUri || '').startsWith(`${base}/`)) return null;
     132  const slug = String(wardUri).trim().replace(/\/+$/, '').split('/').pop();
     133  try {
     134    const uris = relations.listGuardians(slug).map((g) => ({ uri: g.other_uri, handle: g.other_handle }));
     135    const st = Object.fromEntries(
     136      availability.statusesFor(slug, uris.map((u) => u.uri), Date.now()).map((s) => [s.id, s]),
     137    );
     138    return uris.map((u) => ({
     139      uri: u.uri,
     140      handle: u.handle,
     141      availability: (st[u.uri] || {})['shaer:availability'] || 'active',
     142      awayUntil: (st[u.uri] || {})['shaer:awayUntil'] || null,
     143      lapse: (st[u.uri] || {})['shaer:lapse'] || null,
     144    }));
     145  } catch { return null; }
     146}
     147/**
     148 * De gate-rijen van een ward voor het paneel.
     149 *
     150 * De standen komen uit onze eigen kolommen als we het kind hosten; bij een ward
     151 * elders weten we ze niet en blijft het NULL -- onbekend, niet uit. Het aantal
     152 * guardians idem: dat wordt op de server van die ward bijgehouden, en zonder dat
     153 * getal wordt er geen drempel verzonnen.
     154 */
     155export function wardGates(mySlug, wardUri) {
     156  const statuses = wardGuardianStatuses(wardUri);
     157  const wachtend = follows.listReviewsByDirection(mySlug, 'incoming')
     158    .filter((r) => r.ward_uri === wardUri).length;
     159  return gated.gateRows({
     160    // Uit de BESLUITEN, niet uit onze eigen kolom. Er zijn geen lokale accounts:
     161    // elke ward woont elders, dus wardEmbedSetting() gaf voor iedere ward null en
     162    // stond er in het paneel overal "onbekend". Wat een guardian wel heeft is de
     163    // uitslag van wat hij voorstelde.
     164    settings: Object.fromEntries(gated.GATE_CATALOGUE
     165      .filter((g) => g.available !== false && gated.featureColumn(g.feature))
     166      .map((g) => [g.feature, gated.knownSetting(mySlug, wardUri, g.feature)])),
     167    guardianCount: statuses ? statuses.length : null,
     168    proposals: gated.listSent(mySlug, wardUri).map((p) => ({
     169      feature: p.feature, value: !!p.value, status: gated.sentStatus(p, Date.now()),
     170    })),
     171    waiting: { 'shaer:follows': wachtend || undefined },
     172  });
     173}
Note: See TracChangeset for help on using the changeset viewer.