150 lines
4.1 KiB
JavaScript
150 lines
4.1 KiB
JavaScript
"use client";
|
|
import React, { createContext, useContext, useState, useEffect } from "react";
|
|
|
|
const CurrencyContext = createContext();
|
|
|
|
export const SUPPORTED_CURRENCIES = {
|
|
INR: { symbol: "₹", name: "Indian Rupee", country: "India" },
|
|
MYR: { symbol: "RM", name: "Malaysian Ringgit", country: "Malaysia" },
|
|
NPR: { symbol: "रू", name: "Nepalese Rupee", country: "Nepal" },
|
|
};
|
|
|
|
export const CurrencyProvider = ({ children }) => {
|
|
const [selectedCurrency, setSelectedCurrency] = useState("INR");
|
|
const [exchangeRates, setExchangeRates] = useState(null);
|
|
const [isLoading, setIsLoading] = useState(true);
|
|
const [error, setError] = useState(null);
|
|
|
|
const fetchExchangeRates = async () => {
|
|
try {
|
|
setIsLoading(true);
|
|
setError(null);
|
|
|
|
const cachedData = localStorage.getItem("exchangeRates");
|
|
const cached = cachedData ? JSON.parse(cachedData) : null;
|
|
|
|
if (
|
|
cached &&
|
|
new Date().getTime() - cached.timestamp < 24 * 60 * 60 * 1000
|
|
) {
|
|
setExchangeRates(cached.rates);
|
|
setIsLoading(false);
|
|
return;
|
|
}
|
|
|
|
const currencies = Object.keys(SUPPORTED_CURRENCIES)
|
|
.filter((key) => key !== "INR")
|
|
.join(",");
|
|
|
|
const response = await fetch(
|
|
`https://apilayer.net/api/live?access_key=9bcb30907dee1cda9866f7b49f0f8def¤cies=${currencies}&source=INR&format=1`
|
|
);
|
|
|
|
if (!response.ok) {
|
|
throw new Error("Failed to fetch exchange rates");
|
|
}
|
|
|
|
const data = await response.json();
|
|
if (!data.success) {
|
|
throw new Error(data.error?.info || "API request failed");
|
|
}
|
|
|
|
const rates = Object.keys(SUPPORTED_CURRENCIES).reduce(
|
|
(acc, currency) => {
|
|
if (currency === "INR") {
|
|
acc[currency] = 1;
|
|
} else {
|
|
const rate = data.quotes?.[`INR${currency}`];
|
|
acc[currency] = rate || null;
|
|
}
|
|
return acc;
|
|
},
|
|
{}
|
|
);
|
|
|
|
const ratesData = {
|
|
rates,
|
|
timestamp: data.timestamp * 1000,
|
|
};
|
|
|
|
localStorage.setItem("exchangeRates", JSON.stringify(ratesData));
|
|
setExchangeRates(rates);
|
|
} catch (err) {
|
|
setError("Error fetching exchange rates");
|
|
console.error("Exchange rate fetch error:", err);
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
};
|
|
|
|
const convertPrice = (price) => {
|
|
if (!price || typeof price !== "number") return price;
|
|
if (!exchangeRates || !exchangeRates[selectedCurrency]) return price;
|
|
if (selectedCurrency === "INR") return price;
|
|
|
|
try {
|
|
const rate = exchangeRates[selectedCurrency];
|
|
return rate ? Number((price * rate).toFixed(2)) : price;
|
|
} catch (err) {
|
|
console.error("Price conversion error:", err);
|
|
return price;
|
|
}
|
|
};
|
|
|
|
const formatPrice = (price) => {
|
|
const convertedPrice = convertPrice(price);
|
|
|
|
if (typeof convertedPrice !== "number")
|
|
return `${SUPPORTED_CURRENCIES[selectedCurrency].symbol}0.00`;
|
|
|
|
try {
|
|
return new Intl.NumberFormat(getLocaleFromCurrency(selectedCurrency), {
|
|
style: "currency",
|
|
currency: selectedCurrency,
|
|
}).format(convertedPrice);
|
|
} catch (err) {
|
|
return `${
|
|
SUPPORTED_CURRENCIES[selectedCurrency].symbol
|
|
}${convertedPrice.toFixed(2)}`;
|
|
}
|
|
};
|
|
|
|
const getLocaleFromCurrency = (currency) => {
|
|
const localeMap = {
|
|
INR: "en-IN",
|
|
MYR: "ms-MY",
|
|
NPR: "ne-NP",
|
|
};
|
|
return localeMap[currency] || "en-US";
|
|
};
|
|
|
|
useEffect(() => {
|
|
fetchExchangeRates();
|
|
const interval = setInterval(fetchExchangeRates, 24 * 60 * 60 * 1000);
|
|
return () => clearInterval(interval);
|
|
}, []);
|
|
|
|
const value = {
|
|
selectedCurrency,
|
|
setSelectedCurrency,
|
|
convertPrice,
|
|
formatPrice,
|
|
isLoading,
|
|
error,
|
|
SUPPORTED_CURRENCIES,
|
|
refreshRates: fetchExchangeRates,
|
|
};
|
|
|
|
return (
|
|
<CurrencyContext.Provider value={value}>
|
|
{children}
|
|
</CurrencyContext.Provider>
|
|
);
|
|
};
|
|
export const useCurrency = () => {
|
|
const context = useContext(CurrencyContext);
|
|
if (!context) {
|
|
throw new Error('useCurrency must be used within a CurrencyProvider');
|
|
}
|
|
return context;
|
|
}; |