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.