Task #11: Rework the EHSAN header "خدماتنا" (Services) menu from a narrow
vertical radix dropdown into a full-width horizontal mega-menu, matching the
real ehsan.sa layout where services span the width as icon-above-label columns.
Changes (artifacts/ehsan-poc/src/components/layout/Header.tsx):
- Removed the radix DropdownMenu for services; replaced with a custom
state-controlled panel (servicesOpen) absolutely positioned full-width
below the sticky header (header set to relative; panel inset-x-0 top-full).
- Eight services render in a single horizontal flex row, each as an icon
stacked above its label, with direction-aware vertical dividers (border-s
on non-first items) so RTL/LTR both read correctly.
- "طلب دعم" kept as a distinct trailing column (subtle bg) routing to /request.
- Dismissal: outside-click (document mousedown + ref containment), Escape key,
selecting an item, and mouse-leaving the panel. Trigger is click-to-toggle.
- Accessibility: trigger has aria-haspopup/aria-controls/aria-expanded; panel
has id="services-megamenu" and role="menu".
Deviation: dropped trigger hover-to-open (kept click-toggle) because a
mouseenter+click race closed the panel immediately under Playwright; click
toggle is predictable. Mobile services list (vertical) intentionally unchanged.
Verified: tsc --noEmit clean; e2e UI test passed (open, horizontal layout with
all 8 services + request, Escape closes, click navigates to /opportunities and
closes); console clean; architect review Pass. No emojis.
Task #9: Two header fixes on artifacts/ehsan-poc.
1. Nav active state no longer stuck on "فرص التبرع". Active page now gets
a moving green outline box (Home) matching the real ehsan.sa nav.
"فرص التبرع" stays a solid green CTA but only shows an active green ring
when on /opportunities. Applied consistent active styling across desktop
and mobile nav (Home, Opportunities, Request).
2. "خدماتنا" dropdown now lists the eight official services from the
reference image, each with a lucide icon: غراس (Sprout), الزكاة
(HandCoins), هدية (Gift), الأضاحي (Beef), الحملات (Megaphone), التبرع
الدوري (Repeat), التبرع بالرسائل (MessageSquare), تطهير الأسهم
(TrendingUp). Each routes to /opportunities (POC has no per-service
pages). Kept "طلب دعم" below a separator so desktop users retain access
to /request. Mobile menu mirrors the services list.
Added serviceItems i18n group (AR + EN) in translations.ts.
Files: src/components/layout/Header.tsx, src/lib/i18n/translations.ts.
Verified: tsc --noEmit clean; e2e UI test passed (active state moves,
dropdown shows all 8 items + request, routing works); console clean after
HMR-restart of the web workflow. No emojis.
Task #6: On artifacts/ehsan-poc home page, replaced the green text hero
with an auto-rotating, looping carousel of the four official ehsan.sa
banner images (Zakat, recurring/dawri, Waqf, gift) imported via @assets.
- Auto-advances every 5s, loops, and respects prefers-reduced-motion.
- Clickable dot indicators plus an accessible pause/play toggle (WCAG
2.2.2) on a translucent backdrop pill.
- Bottom gradient scrim keeps the white CTA + controls readable on all
four banner backgrounds.
- Removed the overlay heading, subtitle, and the "طلب دعم" button per the
user; kept the "تصفّح الفرص" CTA linking to /opportunities.
- Added common.pause / common.play i18n keys (AR + EN) for the toggle.
Banners use alt="" (decorative) since the functional CTA is separately
labeled. Verified with tsc --noEmit and home-page screenshots (RTL).
Follow-up tweaks so the EHSAN POC matches the official ehsan.sa site.
- Font: switched from Tajawal to IBM Plex Sans Arabic (index.html +
index.css). ehsan.sa's exact webfont couldn't be auto-detected (site
blocks scraping; no Wayback snapshot), so picked the closest official
match.
- Home hero: replaced the gray search-box hero with a full-bleed green
branded banner (badge, title, subtitle, two CTAs, decorative leaf SVGs),
matching ehsan.sa. Moved the search bar above the featured opportunities
grid (with an sr-only label for accessibility).
- Currency: replaced the legacy "﷼" glyph everywhere with the new official
Saudi Riyal symbol via a reusable <Riyal /> component that masks a
processed PNG (src/assets/riyal.png) colored with currentColor; marked
aria-hidden since the adjacent number conveys the value. Applied across
home stats, OpportunityCard, donate, track, admin, request.
- Added AR+EN translation keys heroBadge/heroBrowse.
Verified: tsc clean, no console errors, screenshots confirm hero, font, and
riyal symbol render correctly. Code review fixes applied (search label,
decorative riyal aria, removed unused key).
Reskin the EHSAN POC to match ehsan.sa and gate the admin area behind a
simple POC login.
- Official header: cropped EHSAN logo, nav (الرئيسية/الوقف/فرص التبرع/
خدماتنا dropdown→طلب دعم/عن إحسان/براعم إحسان), login/cart/search icons,
language toggle, mobile menu. Functional items link; rest are visual-only.
- Colors: green primary tuned + orange accent token added in index.css.
- Auth: AuthContext (localStorage, admin/admin) + login page; /admin and
/whatsapp-log now behind a Protected wrapper redirecting to /login.
- Redesigned OpportunityCard (photo, green progress bar with %, category
badge, تم جمع/المبلغ المتبقي columns, inline donate button + amount),
used on home and opportunities pages.
- Two-step donate page (التفاصيل → الدفع): step indicator, presets
100/50/10, custom amount (prefilled via ?amount=), "تبرع عن أهلك"
checkbox, donor form (phone min 10 for OpenClaw loop).
- 8 need-type card images added; needImages helper maps need→image.
- Seed: added published opportunities (req-012..017) with partial progress
to showcase cards; one kept near-full for an easy closed-loop demo.
Deviation (from code review): donate handler now ACCUMULATES collectedAmount
and clamps to target, validates finite/positive amount, and only advances to
the closed-loop pipeline when a case is fully funded (previously overwrote
and force-advanced — broke partial-progress cases). Donate buttons kept green
to match the reference; orange is an accent only.
- API routes: explicit return types on all Express handlers (fixes TS7030),
`beneficiaryName` now accepted and stored in /thank-you route per OpenAPI spec.
- Home page: added search bar (filters by case ID, description, name) +
Featured Opportunities section with live cards, progress bars, and Donate buttons.
- Opportunities page: added need-type filter pill bar (all 8 types + "All Types")
with active state highlighting; empty state respects selected filter.
- i18n: expanded translations with all previously hardcoded strings
(trackCase, notFound, noData, currentStep, search, searchPlaceholder,
featuredTitle, noResults, donate.caseSummary, donate.caseNotFound,
admin.noRequests, admin.needType, admin.amount, admin.track, admin.whatsapp,
track.caseInfo, track.rejected, track.currentStepLabel, track.submitThankYou,
thankYou.successNote, thankYou.beneficiaryMessageLabel,
whatsapp.donorPhone, whatsapp.beneficiaryMessage, whatsapp.noEntries,
opportunities.noOpportunities, opportunities.verified).
All pages now use t.* — zero hardcoded English UI strings.
- TypeScript: both frontend (tsc --noEmit) and API server build are clean.