<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Mohammad</title>
    <description>The latest articles on Forem by Mohammad (@karayel_b8db3c5b2df2c5f40).</description>
    <link>https://forem.com/karayel_b8db3c5b2df2c5f40</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3776594%2F89400dda-3c47-4558-bf0d-a41f4cfb5b87.png</url>
      <title>Forem: Mohammad</title>
      <link>https://forem.com/karayel_b8db3c5b2df2c5f40</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/karayel_b8db3c5b2df2c5f40"/>
    <language>en</language>
    <item>
      <title>I Built a Privacy-First Zakat Calculator with React—Here's What I Learned</title>
      <dc:creator>Mohammad</dc:creator>
      <pubDate>Mon, 16 Feb 2026 23:39:10 +0000</pubDate>
      <link>https://forem.com/karayel_b8db3c5b2df2c5f40/i-built-a-privacy-first-zakat-calculator-with-react-heres-what-i-learned-2f8d</link>
      <guid>https://forem.com/karayel_b8db3c5b2df2c5f40/i-built-a-privacy-first-zakat-calculator-with-react-heres-what-i-learned-2f8d</guid>
      <description>&lt;p&gt;A few months ago, I built a Zakat calculator for my family. It was supposed to be a weekend project. It turned into a lesson in privacy, performance, and what "free" actually costs.&lt;/p&gt;

&lt;p&gt;The stack: React, Vite, Tailwind CSS, hosted on Netlify.&lt;/p&gt;

&lt;p&gt;The twist: I decided early that this would be completely privacy-focused. No backend. No database. No analytics. No email capture.&lt;/p&gt;

&lt;p&gt;Here's what that decision taught me.&lt;/p&gt;

&lt;p&gt;Why Privacy-First Architecture Matters&lt;br&gt;
Most Islamic finance apps I tested required:&lt;/p&gt;

&lt;p&gt;Email signup&lt;br&gt;
Phone number verification&lt;br&gt;
Account creation just to calculate a number&lt;br&gt;
Your Zakat calculation reveals your complete financial picture—bank balances, investments, gold holdings, debts. That's sensitive data.&lt;/p&gt;

&lt;p&gt;I didn't want to store that. Ever.&lt;/p&gt;

&lt;p&gt;Technical approach:&lt;/p&gt;

&lt;p&gt;100% client-side JavaScript&lt;br&gt;
localStorage for temporary calculation state (clears on page close)&lt;br&gt;
No API calls after initial page load&lt;br&gt;
No cookies, no tracking pixels, no Google Analytics&lt;br&gt;
Trade-off? I can't "improve the product" with user data. No heatmaps, no A/B testing, no usage analytics.&lt;/p&gt;

&lt;p&gt;Win? Users trust it. They actually use it.&lt;/p&gt;

&lt;p&gt;The Gold Price Problem&lt;br&gt;
Zakat depends on the Nisab threshold—87.48 grams of gold. Gold prices change daily. If I don't update this, calculations are wrong.&lt;/p&gt;

&lt;p&gt;Solution: Simple fetch from a free gold price API on page load, cached for the session.&lt;/p&gt;

&lt;p&gt;// Fetch current gold price for Nisab calculation&lt;br&gt;
const fetchGoldPrice = async () =&amp;gt; {&lt;br&gt;
  const response = await fetch('&lt;a href="https://api.goldprice.com/v1/spot'" rel="noopener noreferrer"&gt;https://api.goldprice.com/v1/spot'&lt;/a&gt;);&lt;br&gt;
  const data = await response.json();&lt;br&gt;
  return calculateNisab(data.price);&lt;br&gt;
};&lt;br&gt;
If the API fails, I fall back to the last known price with a clear warning. Better than a broken calculator.&lt;/p&gt;

&lt;p&gt;Client-Side State Management (Without the Bloat)&lt;br&gt;
I needed to track:&lt;/p&gt;

&lt;p&gt;Multiple asset categories (cash, gold, silver, stocks, crypto, business assets)&lt;br&gt;
Deductible liabilities&lt;br&gt;
Real-time calculation updates&lt;br&gt;
Currency conversion&lt;br&gt;
No Redux. No Context API hell.&lt;/p&gt;

&lt;p&gt;Just React hooks:&lt;/p&gt;

&lt;p&gt;const [assets, setAssets] = useState({&lt;br&gt;
  cash: 0,&lt;br&gt;
  gold: 0,&lt;br&gt;
  silver: 0,&lt;br&gt;
  stocks: 0,&lt;br&gt;
  crypto: 0,&lt;br&gt;
  business: 0,&lt;br&gt;
  other: 0&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;const [liabilities, setLiabilities] = useState({&lt;br&gt;
  debts: 0,&lt;br&gt;
  bills: 0&lt;br&gt;
});&lt;br&gt;
Calculate Zakat in real-time with a simple useEffect:&lt;/p&gt;

&lt;p&gt;const totalAssets = Object.values(assets).reduce((a, b) =&amp;gt; a + b, 0);&lt;br&gt;
const totalLiabilities = Object.values(liabilities).reduce((a, b) =&amp;gt; a + b, 0);&lt;br&gt;
const zakatableWealth = totalAssets - totalLiabilities;&lt;br&gt;
const zakatDue = zakatableWealth &amp;gt; nisabThreshold ? zakatableWealth * 0.025 : 0;&lt;br&gt;
Result: 0.53MB total page size. 0.1s server response. 95+ Lighthouse performance score.&lt;/p&gt;

&lt;p&gt;The Form UX Challenge&lt;br&gt;
Zakat calculation requires ~10 input fields. That's intimidating.&lt;/p&gt;

&lt;p&gt;Solutions I implemented:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Progressive disclosure&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Collapse sections by default&lt;br&gt;
Expand on click&lt;br&gt;
Show running total prominently at top&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Help text everywhere&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;br&gt;
  Gold (market value)&lt;br&gt;
  &lt;span&gt;&lt;br&gt;
    Include jewelry, coins, bars (exclude daily-wear per some scholars)&lt;br&gt;
  &lt;/span&gt;&lt;br&gt;
&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Visual feedback&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Color-coded totals (green = safe, red = error)&lt;br&gt;
Real-time Zakat calculation updates as you type&lt;br&gt;
Clear "You owe $X" result with explanation&lt;br&gt;
Accessibility &amp;amp; Internationalization&lt;br&gt;
Accessibility wins:&lt;/p&gt;

&lt;p&gt;Proper label associations&lt;br&gt;
Keyboard navigation for all inputs&lt;br&gt;
ARIA labels where needed&lt;br&gt;
Color contrast ratios checked&lt;br&gt;
Internationalization challenges:&lt;/p&gt;

&lt;p&gt;Auto-detect user currency via IP geolocation&lt;br&gt;
Format numbers correctly (1,000 vs 1.000 depending on locale)&lt;br&gt;
Support for 50+ currencies&lt;br&gt;
The auto-detection isn't perfect (VPNs break it), so I added manual override. Users appreciate control.&lt;/p&gt;

&lt;p&gt;What "Free" Actually Costs&lt;br&gt;
Building this taught me about hidden costs:&lt;/p&gt;

&lt;p&gt;Cost    Amount  Notes&lt;br&gt;
Domain  $0  Using Netlify subdomain&lt;br&gt;
Hosting $0  Netlify free tier&lt;br&gt;
SSL $0  Let's Encrypt auto&lt;br&gt;
Gold API    $0  Free tier (100 calls/day)&lt;br&gt;
My time 40+ hours   Development, testing, content&lt;br&gt;
"Free" tools aren't free. They monetize your data. I chose to monetize nothing—just solve a problem.&lt;/p&gt;

&lt;p&gt;The Result&lt;br&gt;
ZakatEasy—a calculator that:&lt;/p&gt;

&lt;p&gt;✅ Updates Nisab daily with live gold prices&lt;br&gt;
✅ Handles all modern assets (stocks, crypto, business inventory)&lt;br&gt;
✅ Works in 50+ currencies&lt;br&gt;
✅ Calculates in real-time as you type&lt;br&gt;
✅ Never stores or transmits your financial data&lt;br&gt;
✅ Loads in under 1 second&lt;/p&gt;

&lt;p&gt;Page stats:&lt;/p&gt;

&lt;p&gt;Size: 0.53MB&lt;br&gt;
Load time: 0.8s (desktop), 3.1s (mobile)&lt;br&gt;
Performance score: 95/100&lt;br&gt;
Accessibility score: 100/100&lt;br&gt;
Lessons for Fellow Developers&lt;br&gt;
Privacy is a feature, not a bug—market it as such&lt;br&gt;
Client-side only is viable for many use cases&lt;br&gt;
Simple state &amp;gt; complex architecture&lt;br&gt;
Help text reduces support burden&lt;br&gt;
Free tiers are generous if you're resource-conscious&lt;br&gt;
Try It / Contribute&lt;br&gt;
Live site: zakateasy.netlify.app&lt;/p&gt;

&lt;p&gt;Got ideas? Want to improve the calculation logic? Add a feature?&lt;/p&gt;

&lt;p&gt;The codebase is clean, documented, and open for contributions. Drop suggestions in the comments or fork it if you want to build something similar.&lt;/p&gt;

&lt;p&gt;What's your experience building privacy-first web apps? Trade-offs I missed? Better approaches? Tell me in the comments.&lt;/p&gt;

&lt;h1&gt;
  
  
  javascript #react #webdev #privacy #opensource #showdev #netlify #productivity
&lt;/h1&gt;

</description>
      <category>architecture</category>
      <category>privacy</category>
      <category>react</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
