A modern, feature-rich currency converter application specializing in Moroccan currencies (Dirham, Riyal, Franc) with support for major world currencies. Built with Next.js 15, TypeScript, Redux Toolkit, and TanStack Query.
- Bidirectional Conversion - Type amounts in either the "From" or "To" field
- Real-time Exchange Rates - Live rates via ExchangeRate-API
- Moroccan Currency Support - MAD (Dirham), Riyal, and Franc with automatic conversions
- World Currencies - 10+ major currencies (USD, EUR, GBP, JPY, CAD, AUD, CHF, CNY, INR, MXN)
- Denomination Breakdown - Visual breakdown of MAD banknotes and coins
- Dark/Light Mode - Full theme support with automatic system detection
- Responsive Design - Works perfectly on mobile, tablet, and desktop
- MAD to Riyal: 1 MAD = 20 Riyals
- MAD to Franc: 1 MAD = 100 Francs
- Automatic Denomination Display: When converting to MAD, see the exact coins and banknotes needed
- Authentic Currency Images: Real Moroccan currency images included
- Soft blue/indigo/purple gradient background
- Clean white cards with subtle shadows
- Blue-tinted input fields for better visual hierarchy
- Excellent contrast and readability
- Dark gray gradient background
- Dark cards with proper borders
- All text and UI elements adapt automatically
- Smooth transitions between modes
- Next.js 15 - React framework with App Router
- React 19 - Latest React with concurrent features
- TypeScript - Type safety throughout
- Redux Toolkit - Global state management
- TanStack Query (React Query) - Server state & caching
- Tailwind CSS - Utility-first CSS framework
- shadcn/ui - Beautiful, accessible components
- Lucide Icons - Clean, modern icon library
- ExchangeRate-API - Real-time exchange rates
- Local Currency Data - Pre-configured Moroccan currency rates
currencito/
โโโ app/ # Next.js App Router
โ โโโ layout.tsx # Root layout with providers
โ โโโ page.tsx # Home page
โ
โโโ components/ # React components
โ โโโ ui/ # shadcn/ui components
โ โ โโโ button.tsx
โ โ โโโ card.tsx
โ โ โโโ input.tsx
โ โ โโโ select.tsx
โ โโโ CurrencyConverter.tsx # Main converter component
โ โโโ CurrencySelect.tsx # Currency dropdown
โ โโโ DenominationBreakdown.tsx # MAD denomination display
โ
โโโ lib/ # Core logic & utilities
โ โโโ api/
โ โ โโโ exchangeRates.ts # API client
โ โโโ currency/
โ โ โโโ converter.ts # Conversion logic
โ โ โโโ denominations.ts # Denomination calculations
โ โ โโโ constants.ts # Currency metadata
โ โ โโโ types.ts # TypeScript types
โ โโโ query/
โ โ โโโ hooks/
โ โ โโโ useExchangeRates.ts # React Query hook
โ โโโ store/
โ โโโ index.ts # Redux store
โ โโโ hooks.ts # Typed Redux hooks
โ โโโ slices/
โ โโโ converterSlice.ts # Converter state
โ
โโโ public/
โโโ currency/ # Currency images
โโโ mad-200-note.jpg
โโโ mad-100-note.jpg
โโโ ... (coins & notes)
Manages user input and currency selections:
interface ConverterState {
amount: string; // From amount
toAmount: string; // To amount
fromCurrency: Currency;
toCurrency: Currency;
}Actions:
setAmount(value)- Set from amount (clears to amount)setToAmount(value)- Set to amount (clears from amount)setFromCurrency(currency)- Change from currencysetToCurrency(currency)- Change to currencyswapCurrencies()- Swap currencies and amounts
Handles exchange rate fetching with caching:
- Cache Time: 5 minutes
- Stale Time: 1 minute
- Refetch: On window focus
- API: ExchangeRate-API (free tier)
convertCurrency(amount, fromCurrency, toCurrency, rates)Uses the USD as the base currency:
- Convert from currency to USD
- Convert USD to target currency
// Direct conversions (no API needed)
MAD โ Riyal: multiply/divide by 20
MAD โ Franc: multiply/divide by 100
Riyal โ Franc: multiply/divide by 5Greedy algorithm to calculate minimum coins/notes:
calculateDenominations(amount: number): Denomination[]MAD Denominations:
- Notes: 200, 100, 50, 20
- Coins: 10, 5, 2, 1, 0.5, 0.2, 0.1
- Node.js 18+
- pnpm (recommended) or npm
- Clone the repository
git clone <repository-url>
cd currencito- Install dependencies
pnpm install
# or
npm install- Run development server
pnpm dev
# or
npm run dev- Open your browser
http://localhost:3002
pnpm build
pnpm start- Enter amount in the "From" field
- Select currencies from dropdowns
- View result in the "To" field automatically
- Type in either field - the other updates automatically
- Start typing in one field, the other clears
- Perfect for "how much would I need" calculations
Click the swap button (โ) between fields to:
- Exchange the from/to currencies
- Swap the amounts
- Quick reverse calculation
When converting to MAD:
- Automatic denomination breakdown appears below
- Shows exact banknotes and coins needed
- Displays authentic Moroccan currency images
- Calculates minimum number of denominations
- Automatic: Follows system preference
- Manual: Toggle in browser/system settings
- Smooth: Instant theme switching
Located in lib/api/exchangeRates.ts:
const API_KEY = 'YOUR_API_KEY'; // Free tier available
const BASE_URL = 'https://v6.exchangerate-api.com/v6';Get your free API key at: https://www.exchangerate-api.com/
Hardcoded in lib/currency/constants.ts:
export const MOROCCAN_RATES = {
MAD_TO_RIYAL: 20,
MAD_TO_FRANC: 100,
} as const;Moroccan:
- MAD - Moroccan Dirham (๐ฒ๐ฆ)
- RIYAL - Moroccan Riyal (๐ฒ๐ฆ)
- FRANC - Moroccan Franc (๐ฒ๐ฆ)
World:
- USD - US Dollar (๐บ๐ธ)
- EUR - Euro (๐ช๐บ)
- GBP - British Pound (๐ฌ๐ง)
- JPY - Japanese Yen (๐ฏ๐ต)
- CAD - Canadian Dollar (๐จ๐ฆ)
- AUD - Australian Dollar (๐ฆ๐บ)
- CHF - Swiss Franc (๐จ๐ญ)
- CNY - Chinese Yuan (๐จ๐ณ)
- INR - Indian Rupee (๐ฎ๐ณ)
- MXN - Mexican Peso (๐ฒ๐ฝ)
Main converter component with all logic.
State:
- Manages amounts (from/to)
- Handles currency selection
- Fetches exchange rates
- Calculates conversions
Features:
- Bidirectional input
- Real-time conversion
- Denomination breakdown
- Exchange rate display
Currency dropdown selector.
Props:
interface CurrencySelectProps {
value: Currency;
onChange: (value: Currency) => void;
}Features:
- Grouped currencies (Moroccan/World)
- Flag icons
- Currency codes and names
- Dark mode support
Visual display of MAD denominations.
Props:
interface DenominationBreakdownProps {
denominations: Denomination[];
total: number;
}Features:
- Currency images
- Count display
- Total calculation
- Responsive grid
type Currency =
| 'MAD' | 'RIYAL' | 'FRANC' // Moroccan
| 'USD' | 'EUR' | 'GBP' | 'JPY' | 'CAD'
| 'AUD' | 'CHF' | 'CNY' | 'INR' | 'MXN'; // Worldinterface CurrencyInfo {
code: string;
name: string;
symbol: string;
flag: string;
isMoroccan: boolean;
}interface Denomination {
value: number;
count: number;
type: 'note' | 'coin';
imageUrl: string;
}- Add to types in
lib/currency/types.ts:
type Currency = ... | 'NEW_CURRENCY';- Add metadata in
lib/currency/constants.ts:
NEW_CURRENCY: {
code: 'NEW',
name: 'New Currency',
symbol: 'N$',
flag: '๐ณ๏ธ',
isMoroccan: false,
}- Add to groups in
lib/currency/constants.ts:
export const WORLD_CURRENCIES = [...,
CURRENCIES.NEW_CURRENCY
];Theme Colors:
- Edit
tailwind.config.tsfor global theme - Component styles use Tailwind utilities
- Dark mode variants:
dark:prefix
Gradients:
// Light mode
bg-gradient-to-br from-blue-50 via-indigo-50 to-purple-50
// Dark mode
dark:from-gray-900 dark:via-gray-800 dark:to-gray-900- React Query Caching - Reduces API calls
- Optimized Re-renders - Redux selectors
- Code Splitting - Next.js automatic splitting
- Image Optimization - Next.js Image component (if used)
- No sensitive data stored
- API key can be environment variable
- Client-side only calculations
- No user authentication required
- Exchange rates update every 24 hours on free API tier
- Some currency symbols may not display on all systems
- Denomination images require manual addition
- Historical exchange rate charts
- Multiple currency comparison
- Favorite currency pairs
- Conversion history
- Offline mode with cached rates
- PWA support
- Currency alerts/notifications
- Export conversion results
This project is open source and available under the MIT License.
Contributions are welcome! Please feel free to submit a Pull Request.
For issues or questions, please open an issue on GitHub.
Made with โค๏ธ for the Moroccan community
๐ฒ๐ฆ Supporting MAD, Riyal, and Franc conversions since 2026