Add mini family genealogy tree with per-person photos
Per explicit request: "mini family genealogy mapping with ability to add
photos on each family member." Scoped via clarifying questions: people are
lightweight records independent of login accounts (most real tree nodes —
grandparents, deceased relatives, young children — never sign up),
relationships support parent/child + spouse (enough to render a real
multi-generation tree), photos go to Supabase Storage (native to the
backend already in use, no new infrastructure).
Schema: nf_people (name, gender, birth/death dates, notes, optional
linked_user_id if the person also happens to have a real account,
photo_path) and nf_relationships (person_a/person_b + type: parent_of
directional, spouse_of symmetric). Both family-member-shared like the
Asset Registry — any owner/agent/member can view and edit, unlike the
per-author Wassiyah/Waqf model. New private Storage bucket
nf-people-photos, path convention {family_id}/{person_id}/{filename} so
RLS can check family membership straight from the path without a join.
New FamilyTree.svelte: add/edit/delete a person, upload/replace/remove
their photo (signed URLs, 1hr TTL, refreshed on every load since the
bucket is private), link/unlink relationships, and a recursive generational
tree render — roots are anyone with no recorded parent, spouses shown
inline next to their partner rather than as separate branches.
e2e-family-tree.cjs: 4-person 3-generation tree built end to end against
the live backend — add people, link parent/child + spouse relationships,
upload a real PNG to Supabase Storage and confirm it renders as the
avatar, remove it and confirm it reverts to the initial-letter fallback,
edit a person's notes, delete a relationship, and confirm a second family
under the same account sees none of this tree (isolation, same pattern
already proven for Wassiyah/Waqf). Found two real test-authoring bugs
along the way (not app bugs): a case-insensitive :has-text substring match
on "Spouse" was also matching the relationship-type select's own "is
spouse of" option text, and a person-summary click meant to inspect an
already-expanded card was instead toggling it closed. Both fixed by
selecting on DOM position/structure instead of loose text matching.
9/9 passing.
Full regression sweep: e2e-uat 32/32, e2e-fastpath 16/16, e2e-trust 12/12,
e2e-business 10/10, e2e-digital-vehicle 10/10 (one transient failure on
first run, passed clean on retry — consistent with earlier-observed
flakiness under heavy parallel test load, not a regression),
e2e-property 9/9, e2e-other 4/4, e2e-info 31/31, e2e-per-member 11/11,
e2e-family-tree 9/9 — 174/174 total.
This commit is contained in:
+7
-5
@@ -17,6 +17,7 @@
|
||||
import FamilySwitcher from './lib/FamilySwitcher.svelte';
|
||||
import FamilyManagement from './lib/FamilyManagement.svelte';
|
||||
import MutawalliDashboard from './lib/MutawalliDashboard.svelte';
|
||||
import FamilyTree from './lib/FamilyTree.svelte';
|
||||
|
||||
let currentLang = $state('en');
|
||||
lang.subscribe(v => currentLang = v);
|
||||
@@ -40,8 +41,8 @@
|
||||
}
|
||||
});
|
||||
|
||||
const tabs = ['Coverage', 'Faraid', 'Assets', 'Wassiyah', 'Hibah', 'Family Waqf', 'Nominate', 'Trigger', 'Mutawalli', 'Claims (H2)', 'Family', 'Settings'];
|
||||
const icons = ['🎯', '📊', '📁', '📜', '🎁', '⛲', '📇', '⚡', '🕋', '🔗', '👥', '⚙️'];
|
||||
const tabs = ['Coverage', 'Faraid', 'Assets', 'Wassiyah', 'Hibah', 'Family Waqf', 'Nominate', 'Trigger', 'Mutawalli', 'Tree', 'Claims (H2)', 'Family', 'Settings'];
|
||||
const icons = ['🎯', '📊', '📁', '📜', '🎁', '⛲', '📇', '⚡', '🕋', '🌳', '🔗', '👥', '⚙️'];
|
||||
let activeTab = $state(0);
|
||||
|
||||
function handleKeydown(e) {
|
||||
@@ -104,9 +105,10 @@
|
||||
{:else if activeTab === 6}<NominationRegistry />
|
||||
{:else if activeTab === 7}<DeathTrigger />
|
||||
{:else if activeTab === 8}<MutawalliDashboard />
|
||||
{:else if activeTab === 9}<DigitalClaims />
|
||||
{:else if activeTab === 10}<FamilyManagement />
|
||||
{:else if activeTab === 11}
|
||||
{:else if activeTab === 9}<FamilyTree />
|
||||
{:else if activeTab === 10}<DigitalClaims />
|
||||
{:else if activeTab === 11}<FamilyManagement />
|
||||
{:else if activeTab === 12}
|
||||
<div class="module">
|
||||
<div class="module-header">
|
||||
<h2>Settings</h2>
|
||||
|
||||
Reference in New Issue
Block a user