Skip to content
Client Work & Case Studies
Web App

Hasanat

A donation and Zakat platform for an Australian Islamic charity: appeals priced by outcome, one-off and recurring giving, Zakat and Qurban gated to the Hijri calendar, Stripe and PayPal settling into one ledger, and an admin dashboard — over a Laravel API in English, Arabic, and French.

Visit live site 32 weeks · 2026
Hasanat — project cover
Role
Full-stack development · Laravel + MySQL API and Next.js front end · Borders And Gates team delivery
Services
Laravel 11 + MySQL API · Next.js front end & admin dashboard · Donation cart & guest checkout · Nisab-based Zakat calculator · Seasonal Qurban campaign · Stripe & PayPal integration · Recurring donations & PDF receipts · EN/AR/FR content and RTL · Social login (Google, Facebook, Apple)
Stack
Laravel 11 · PHP 8.2 · MySQL · Next.js 15 · React 19 · TypeScript · Tailwind v4 · Sanctum · Socialite · Stripe · PayPal · dompdf · ApexCharts · Swagger
Client
Hasanat.org
Industry
Nonprofit & Charity
Timeline
32 weeks · 2026

01 / Business context

The Problem to Solve

Hasanat raises from Australia for emergency appeals across Bangladesh, Syria, Lebanon, Yemen, and Palestine, and its giving year is shaped by the Hijri calendar as much as by the crisis cycle. The platform had to make an appeal concrete enough to act on in seconds, treat Zakat and Qurban as real products rather than seasonal landing pages, take money through two gateways without splitting the record in two, and stay editable by the charity's own team in three languages.

Hasanat.org is an Australian Islamic charity running emergency and development appeals overseas, with offices in Sydney and Brisbane. We built the platform it fundraises from: a Laravel API over MySQL holding projects, donations, Zakat calculations, Qurban bookings, transactions, and receipts, and a Next.js front end carrying the public site, the donor's account, and the admin dashboard the charity's team runs everything from — in English, Arabic, and French.

02 / From Scope to Launch

How the Work Moved

The work became clearer through decisions, working increments, and feedback—not a long wait for a final reveal.

07 Steps

  1. Step 01

    We started from the donation itself rather than the page, tracing one gift from an appeal card through the cart, the gateway, the receipt, and the charity's reconciliation, and used that trace to decide what had to be a record in the database rather than a number on a screen.

  2. Step 02

    We modelled the domain as it is actually described by the charity — projects with causes, regions, urgency and a funding goal; donations and their transactions and receipts; Zakat with assets, liabilities, and nisab prices; sacrifices with per-country types — instead of flattening everything into a generic 'payment'.

  3. Step 03

    We built the donation flow around a concrete unit of impact, so an appeal reads as 'one furnished wooden house = A$1,250' with its funding progress and remaining gap visible, and preset amounts derived from that unit.

  4. Step 04

    We integrated Stripe and PayPal as two rails into one ledger, with settlement handled from server-side callbacks and transaction fees resolved per currency, then layered recurring plans, saved payment methods, and PDF receipts on top of the same records.

  5. Step 05

    We treated the Hijri calendar as a first-class part of the product: Qurban and Zakat al-Fitr are availability states the admin controls, with countdowns, previous-season impact, and reminder capture instead of a page that quietly lies.

  6. Step 06

    We made the site the charity's to run — homepage sections, projects, blogs, regions, causes, nisab prices, Qurban types, and manual offline donations are all administered from the dashboard, with per-admin permissions and an activity log.

  7. Step 07

    We shipped three languages by holding each translation on the record itself and selecting it from the request locale, with the front end applying the language preference — including RTL for Arabic — across the whole app.

03 / Decisions that shaped the product

Key Product Decisions

Decision 01

Price the appeal by outcome, not by amount

Business context
A donation form that only asks for a number makes the donor guess what their money does, and leaves the charity describing impact in copy that nothing in the system backs up.
Decision
We gave every project a unit of impact stored on the record — one food pack, one furnished wooden house — with the preset amounts derived from that unit, and showed percent funded and the amount still needed alongside it.
Why
It turns an abstract ask into something closer to a purchase, and because the unit and the goal are data rather than marketing text, the progress bar, the suggested amounts, and the impact line can never drift apart.
Decision 02

A cart for causes, and a checkout that does not demand an account

Business context
Donors often give to more than one appeal in a single sitting, and asking them to register before paying is the most reliable way to lose the gift.
Decision
We built a donation cart keyed to either a signed-in user or a guest session, and a checkout that collects donor details at the point of payment rather than behind a signup wall.
Why
The donation completes on the donor's terms, and the account becomes something they want later — for recurring plans, receipts, and Zakat history — instead of a toll gate in front of the thing they came to do.
Decision 03

Two payment rails, one donation record

Business context
Stripe suits card donors and PayPal is what a large share of charity donors already trust, but wiring both usually produces two parallel histories that only reconcile in a spreadsheet.
Decision
We made both gateways settle from server-side callbacks into the same donation, transaction, and receipt tables, with fees resolved against the currency the donor actually paid in.
Why
The charity reconciles one ledger, and a receipt, a report, or a donor's history never has to ask which rail the money arrived on — which also means adding a third gateway later is an adapter, not a migration.
Decision 04

Zakat as a stored calculation, not a copied calculator

Business context
Zakat is assets minus liabilities measured against a nisab threshold that moves with the gold or silver price and differs by currency. A hard-coded threshold is wrong within weeks, and a calculator that forgets its inputs cannot be checked.
Decision
We stored nisab prices per metal, per currency, and per date, and saved a donor's assets and liabilities as records against a calculation they can return to.
Why
The figure stays defensible and current without a deploy, the charity updates prices from the dashboard as the market moves, and a donor can see how their own number was reached rather than being handed a total to trust.
Decision 05

Seasonal campaigns that gate themselves and keep the donor

Business context
Qurban is bookable for roughly two weeks around Eid al-Adha, and Zakat al-Fitr for the final days of Ramadan. For most of the year those pages either quietly accept bookings they should not, or disappear.
Decision
We made availability an explicit state the admin controls: out of season the page explains itself, counts down to the opening, shows the previous season's impact, and captures a reminder request.
Why
In this product the calendar is not an edge case, it is the rhythm — and the traffic that arrives early becomes a list the charity can open the campaign to, rather than a bounce.
Decision 06

Translations on the record, not in the bundle

Business context
The charity publishes appeals, blogs, and impact copy in English, Arabic, and French, and its team — not a developer — is the one writing them.
Decision
We held each language on the content record itself and selected it from the request locale, so a project's title, description, impact line, and unit label are all authored per language in the dashboard.
Why
A new appeal is trilingual the moment the team saves it, and the Arabic experience — including RTL — is the same product rather than a translated shell that goes stale the first time someone edits the English.

04 / The product in use

Real interfaces across the customer and operational experience.

The Hasanat projects page with cause and region filters and outcome-based donation amounts
Hasanatproduct view 1
The Hasanat Qurban campaign showing its out-of-season state with a countdown and reminder signup
Hasanatproduct view 2
A Hasanat appeal page showing unit pricing, funding progress, and the donation panel
Hasanatproduct view 3

05 / How it was built

Engineering Decisions

  • Laravel 11 API on PHP 8.2 over MySQL, with Sanctum tokens, Socialite for Google, Facebook, and Apple sign-in, dompdf for receipts, Excel export for reporting, and OpenAPI/Swagger documentation for the front-end contract.

  • Domain modelled explicitly rather than generically: projects with causes, regions, urgency and funding goals; donations, cart items, transactions and receipts; subscriptions for recurring giving; sacrifices with per-country types and receipts; Zakat assets, liabilities, calculations, and nisab prices.

  • Donation cart resolved against either a signed-in user or a guest session id, with a checkout that collects donor details, takes payment, and completes the session in ordered steps.

  • Stripe and PayPal integrated as parallel rails with server-side success and cancel handling for standard donations, Zakat, and sacrifices, per-currency transaction fees, and saved payment methods with a default card.

  • Recurring donations as first-class subscriptions the donor can pause and resume, and manual donations an admin can record and complete so an offline bank transfer lands in the same ledger as a card payment.

  • Zakat calculator driven by nisab prices stored per metal type, currency, and date, with the donor's assets and liabilities saved against a retrievable calculation.

  • Qurban and Zakat al-Fitr modelled as season-gated campaigns with admin-controlled availability, countdowns, previous-season impact statistics, and reminder capture for donors who arrive early.

  • Next.js front end carrying the public site, donor account, and admin dashboard from one codebase, with the homepage itself composed of orderable, toggleable sections the charity controls.

  • Three languages held as per-language fields on each content record and selected by an Accept-Language middleware, with the front end applying the preference — including RTL for Arabic — across the app.

06 / What changed

Delivered Outcome

  • Hasanat runs its own fundraising: appeals, unit pricing, homepage composition, blogs, regions, causes, nisab prices, and Qurban availability are all managed from the dashboard.

  • Donors give in seconds from the home page, or filter by cause, region, and urgency and check out several appeals together — as a guest or with an account.

  • Card and PayPal donations, recurring plans, Zakat, Qurban, and offline bank transfers all reconcile inside one donation ledger with PDF receipts.

  • Zakat is calculated against nisab prices the charity keeps current itself, and each donor can revisit how their figure was reached.

  • Seasonal campaigns open and close on the charity's schedule, collecting reminder signups in the months they are shut instead of losing that traffic.

  • Appeals, blogs, and impact content publish in English, Arabic, and French from the same records, with Arabic served RTL.

Facing a similar product challenge?

Bring the problem, the current state, and the outcome you need. We can turn that context into a clear product direction and a workable path to launch.