feat: add Khairat, emergency-contact auto-notify, and 5 lifestyle-companion tabs
Big round covering two different asks: Khairat/emergency infrastructure (tightly coupled to what's already built) and a Muslim-lifestyle companion surface (a genuinely different product, added at the user's explicit request after being offered a smaller scope). Khairat & emergency contacts: - nf_khairat_memberships (per-member scheme membership) + nf_emergency_fund (per-family shared reserve tracker) — records intent/contacts only, never holds or moves real money. - nf_trusted_contacts gains category (mosque/police/ambulance/hospital/ khairat/family/other) and email columns. - New notify-emergency-contacts Edge Function, auto-invoked the moment a mutawalli fires a member's death trigger (the one place in this app where auto-send-on-trigger is actually correct), alongside — not instead of — the existing heir notification. Verified with a live fire end-to-end (e2e-emergency-notify.cjs, 5/5). Lifestyle-companion tabs — all computed/searched live, nothing fabricated: - Qibla: pure great-circle bearing math to the Kaaba from geolocation, no API/key. Verified against Kuala Lumpur (293°, matches expected ~292°). - Prayer Times: client-side astronomical calculation (single-pass solar position, MWL angles), sanity-checked against known KL/London times before shipping. - Locate: mosque/halal/cemetery search via the free, keyless OpenStreetMap Overpass API — real community-sourced results only, honest empty state when nothing's mapped nearby. - Quran: Surah list + Arabic/translation via the free alquran.cloud API, fetched fresh each time, nothing stored in this app's own database. - Neighbourhood: a join-by-code community announcement board — a genuinely separate multi-tenant concept from the estate-planning family structure, scoped to the user account. Found and fixed a real UX gap during testing: the create/join form was only reachable with zero existing neighbourhoods, with no way to join a second one. Also found and fixed a real bug: the heir-notify and emergency-notify status messages shared the same CSS class, breaking any script (including the pre-existing e2e-per-member.cjs) that targeted '.notify-status' without further filtering — gave each its own distinguishing class. Covered by e2e-khairat-lifestyle.cjs (13/13) and e2e-emergency-notify.cjs (5/5). Full regression: 316/316 across all suites (several transient flakes under heavy mail-relay load during the sweep, all confirmed clean on rerun — one led to the real class-collision fix above).
This commit is contained in:
+2
-2
@@ -127,8 +127,8 @@ async function main() {
|
||||
const notifyBtn = agentPage.locator('button.btn-secondary', { hasText: 'Notify heirs' });
|
||||
if (await notifyBtn.isVisible().catch(() => false)) {
|
||||
await notifyBtn.click();
|
||||
await agentPage.locator('.notify-status', { hasText: /Sent|Failed/ }).waitFor({ state: 'visible', timeout: 15000 }).catch(() => {});
|
||||
const statusText = await agentPage.locator('.notify-status').textContent().catch(() => '');
|
||||
await agentPage.locator('.heir-notify-status', { hasText: /Sent|Failed/ }).waitFor({ state: 'visible', timeout: 15000 }).catch(() => {});
|
||||
const statusText = await agentPage.locator('.heir-notify-status').textContent().catch(() => '');
|
||||
record('Mutawalli: heir notification actually sends via the real SMTP relay', statusText.includes('Sent'), statusText);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user