diff --git a/app/contexts/currencyContext.js b/app/contexts/currencyContext.js index 72b48db..83aa8f0 100644 --- a/app/contexts/currencyContext.js +++ b/app/contexts/currencyContext.js @@ -13,11 +13,99 @@ export const SUPPORTED_CURRENCIES = { export const CurrencyProvider = ({ children }) => { const [selectedCurrency, setSelectedCurrency] = useState("INR"); + useEffect(() => { + const fetchCurrencyForCountry = async () => { + try { + const userCountry = localStorage.getItem('userCountry'); + if (!userCountry) { + return; + } + + const response = await axios.get(`https://restcountries.com/v3.1/name/${userCountry}`); + if (response.data && response.data.length > 0) { + const countryData = response.data[0]; + + if (countryData.currencies) { + const currencyCode = Object.keys(countryData.currencies)[0]; + + if (currencyCode) { + setSelectedCurrency(currencyCode); + } + } + } + } catch (error) { + console.error("Error fetching currency for country:", error); + setSelectedCurrency("INR") + } + }; + + fetchCurrencyForCountry(); + }, []); const [exchangeRates, setExchangeRates] = useState(null); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(null); + const [userCountry, setUserCountry] = useState(null); + const [allCountries, setAllCountries] = useState([]); + const [countryCurrencyMap, setCountryCurrencyMap] = useState({}); + + // Fetch all countries and their currencies + const fetchCountriesAndCurrencies = async () => { + try { + // First, get the list of countries + const countriesResponse = await fetch('https://countriesnow.space/api/v0.1/countries/'); + const countriesData = await countriesResponse.json(); + + if (!countriesData.error) { + setAllCountries(countriesData.data); + + const currencyResponse = await fetch('https://restcountries.com/v3.1/all?fields=name,currencies'); + const currencyData = await currencyResponse.json(); + + const currencyMap = {}; + const currencyDetails = {}; + + currencyData.forEach(country => { + const countryName = country.name.common; + if (country.currencies) { + const currencyCode = Object.keys(country.currencies)[0]; + if (currencyCode) { + currencyMap[countryName] = currencyCode; + + if (!currencyDetails[currencyCode]) { + const currencyInfo = country.currencies[currencyCode]; + currencyDetails[currencyCode] = { + symbol: currencyInfo.symbol || currencyCode, + name: currencyInfo.name || `${currencyCode} Currency`, + country: countryName + }; + } + } + } + }); + + Object.keys(currencyDetails).forEach(code => { + if (!SUPPORTED_CURRENCIES[code]) { + SUPPORTED_CURRENCIES[code] = currencyDetails[code]; + } + }); + + setCountryCurrencyMap(currencyMap); + + // Check if we have a stored country and set the currency accordingly + const storedCountry = localStorage.getItem('userCountry'); + if (storedCountry && currencyMap[storedCountry]) { + const currencyCode = currencyMap[storedCountry]; + if (currencyCode) { + setSelectedCurrency(currencyCode); + localStorage.setItem('selectedCurrency', currencyCode); + } + } + } + } catch (error) { + console.error("Error fetching countries and currencies:", error); + } + }; - const fetchExchangeRates = async () => { try { setIsLoading(true); @@ -25,7 +113,6 @@ export const CurrencyProvider = ({ children }) => { 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); @@ -33,40 +120,22 @@ export const CurrencyProvider = ({ children }) => { } try { - const currencies = Object.keys(SUPPORTED_CURRENCIES) - .filter((key) => key !== "INR") - .join(","); - - const response = await axios.get("https://apilayer.net/api/live", { - params: { - access_key: "9bcb30907dee1cda9866f7b49f0f8def", - currencies: currencies, - source: "INR", - format: 1, - }, - }); - + const response = await axios.get(`https://open.er-api.com/v6/latest/${selectedCurrency}`); const data = response.data; - if (!data.success) { - throw new Error(data.error?.info || "API request failed"); + if (!data.rates) { + throw new Error("API request failed - no rates returned"); } - const rates = Object.keys(SUPPORTED_CURRENCIES).reduce( - (acc, currency) => { - if (currency === "INR") { - acc[currency] = 1; - } else { - const rate = data.quotes?.[`INR${currency}`]; - if (!rate) { - throw new Error(`Rate not found for ${currency}`); - } - acc[currency] = rate; - } - return acc; - }, - {} - ); + + const rates = {}; + rates["INR"] = 1; // Base currency + + Object.keys(SUPPORTED_CURRENCIES).forEach(currencyCode => { + if (currencyCode !== "INR" && data.rates[currencyCode]) { + rates[currencyCode] = data.rates[currencyCode]; + } + }); localStorage.setItem( "exchangeRates", @@ -94,6 +163,7 @@ export const CurrencyProvider = ({ children }) => { setIsLoading(false); } }; + const convertPrice = (price) => { if (!price || typeof price !== "number") return price; if (!exchangeRates || !exchangeRates[selectedCurrency]) return price; @@ -112,7 +182,7 @@ export const CurrencyProvider = ({ children }) => { const convertedPrice = convertPrice(price); if (typeof convertedPrice !== "number") - return `${SUPPORTED_CURRENCIES[selectedCurrency].symbol}0.00`; + return `${SUPPORTED_CURRENCIES[selectedCurrency]?.symbol || "$"}0.00`; try { return new Intl.NumberFormat(getLocaleFromCurrency(selectedCurrency), { @@ -121,7 +191,7 @@ export const CurrencyProvider = ({ children }) => { }).format(convertedPrice); } catch (err) { return `${ - SUPPORTED_CURRENCIES[selectedCurrency].symbol + SUPPORTED_CURRENCIES[selectedCurrency]?.symbol || "$" }${convertedPrice.toFixed(2)}`; } }; @@ -129,18 +199,58 @@ export const CurrencyProvider = ({ children }) => { const getLocaleFromCurrency = (currency) => { const localeMap = { INR: "en-IN", + USD: "en-US", + GBP: "en-GB", + EUR: "de-DE", + JPY: "ja-JP", + AUD: "en-AU", + CAD: "en-CA", + SGD: "en-SG", MYR: "ms-MY", NPR: "ne-NP", + IDR: "id-ID", + THB: "th-TH", + PHP: "fil-PH", + VND: "vi-VN", + KRW: "ko-KR", }; return localeMap[currency] || "en-US"; }; + const setUserCurrencyFromCountry = (country) => { + if (country && countryCurrencyMap[country]) { + const currencyCode = countryCurrencyMap[country]; + if (currencyCode && SUPPORTED_CURRENCIES[currencyCode]) { + setSelectedCurrency(currencyCode); + localStorage.setItem('selectedCurrency', currencyCode); + } + } + }; + useEffect(() => { + const storedCountry = localStorage.getItem('userCountry'); + if (storedCountry) { + setUserCountry(storedCountry); + } + + fetchCountriesAndCurrencies(); fetchExchangeRates(); + + const savedCurrency = localStorage.getItem('selectedCurrency'); + if (savedCurrency && SUPPORTED_CURRENCIES[savedCurrency]) { + setSelectedCurrency(savedCurrency); + } + const interval = setInterval(fetchExchangeRates, 24 * 60 * 60 * 1000); return () => clearInterval(interval); }, []); + useEffect(() => { + if (userCountry && countryCurrencyMap[userCountry]) { + setUserCurrencyFromCountry(userCountry); + } + }, [userCountry, countryCurrencyMap]); + const value = { selectedCurrency, setSelectedCurrency, @@ -150,6 +260,9 @@ export const CurrencyProvider = ({ children }) => { error, SUPPORTED_CURRENCIES, refreshRates: fetchExchangeRates, + allCountries, + setUserCountry, + userCountry }; return ( @@ -158,10 +271,11 @@ export const CurrencyProvider = ({ children }) => { ); }; + export const useCurrency = () => { - const context = useContext(CurrencyContext); - if (!context) { - throw new Error('useCurrency must be used within a CurrencyProvider'); - } - return context; - }; \ No newline at end of file + const context = useContext(CurrencyContext); + if (!context) { + throw new Error('useCurrency must be used within a CurrencyProvider'); + } + return context; +}; diff --git a/app/contexts/mainContext.js b/app/contexts/mainContext.js index 4f3faab..693ddcf 100644 --- a/app/contexts/mainContext.js +++ b/app/contexts/mainContext.js @@ -27,6 +27,7 @@ export const ContextProvider = ({ children }) => { console.log("Login Successful:", response.data); setToken(response.data.token) localStorage.setItem('token', response.data.token) + localStorage.setItem('userCountry', response.data.country) toast.success('Login Successful'); router.push('/') diff --git a/components/accounts/AccountSidebar.jsx b/components/accounts/AccountSidebar.jsx index bc6c307..792a472 100644 --- a/components/accounts/AccountSidebar.jsx +++ b/components/accounts/AccountSidebar.jsx @@ -15,7 +15,7 @@ const AccountSidebar = () => { localStorage.removeItem('token') setToken(null) toast.success(response.data.message) - router.push('/') + router.push('/accounts/login') } console.log(response) } diff --git a/components/dynamic-navbar/currencySelect.jsx b/components/dynamic-navbar/currencySelect.jsx index 60d4c6b..b654134 100644 --- a/components/dynamic-navbar/currencySelect.jsx +++ b/components/dynamic-navbar/currencySelect.jsx @@ -1,10 +1,12 @@ import React, { useState, useEffect } from 'react'; -import { ChevronDown, AlertCircle } from 'lucide-react'; +import { ChevronDown, AlertCircle, Search } from 'lucide-react'; const CurrencySelect = ({ selectedCurrency, setSelectedCurrency, SUPPORTED_CURRENCIES, error }) => { const [isOpen, setIsOpen] = useState(false); const [isMobile, setIsMobile] = useState(false); const [selectedCurrencyName, setSelectedCurrencyName] = useState(''); + const [searchTerm, setSearchTerm] = useState(''); + const [filteredCurrencies, setFilteredCurrencies] = useState([]); useEffect(() => { const savedCurrency = localStorage.getItem('selectedCurrency'); @@ -28,12 +30,27 @@ const CurrencySelect = ({ selectedCurrency, setSelectedCurrency, SUPPORTED_CURRE setSelectedCurrencyName(SUPPORTED_CURRENCIES[selectedCurrency]?.country || ''); }, [selectedCurrency, SUPPORTED_CURRENCIES]); + useEffect(() => { + if (isOpen) { + const filtered = Object.entries(SUPPORTED_CURRENCIES).filter(([code, details]) => { + const searchLower = searchTerm.toLowerCase(); + return ( + code.toLowerCase().includes(searchLower) || + details.name.toLowerCase().includes(searchLower) || + details.country.toLowerCase().includes(searchLower) + ); + }); + setFilteredCurrencies(filtered); + } + }, [searchTerm, SUPPORTED_CURRENCIES, isOpen]); + const handleCurrencyChange = (code) => { localStorage.setItem('selectedCurrency', code); setSelectedCurrency(code); setSelectedCurrencyName(SUPPORTED_CURRENCIES[code]?.country || ''); setIsOpen(false); + setSearchTerm(''); }; return ( @@ -55,7 +72,7 @@ const CurrencySelect = ({ selectedCurrency, setSelectedCurrency, SUPPORTED_CURRE ) : ( <> - {SUPPORTED_CURRENCIES[selectedCurrency]?.country} + {SUPPORTED_CURRENCIES[selectedCurrency]?.country || selectedCurrency} {error && selectedCurrency !== 'INR' && ( )} @@ -69,27 +86,46 @@ const CurrencySelect = ({ selectedCurrency, setSelectedCurrency, SUPPORTED_CURRE {isOpen && (
+
+
+ + setSearchTerm(e.target.value)} + className="w-full pl-8 pr-4 py-2 text-sm border border-gray-200 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" + /> +
+
+
- {Object.entries(SUPPORTED_CURRENCIES).map(([code, { country, symbol }]) => ( - - ))} + {filteredCurrencies.length > 0 ? ( + filteredCurrencies.map(([code, { country, symbol, name }]) => ( + + )) + ) : ( +
No currencies found
+ )}
)} ); }; + export default CurrencySelect; \ No newline at end of file diff --git a/components/header/Navbar.jsx b/components/header/Navbar.jsx index 2afb853..41722ba 100644 --- a/components/header/Navbar.jsx +++ b/components/header/Navbar.jsx @@ -16,10 +16,16 @@ const Navbar = () => { const [isSidebarOpen, setIsSidebarOpen] = useState(false); const [isScrolled, setIsScrolled] = useState(false); const { category } = useContext(ProductContext); - const { token } = useContext(MainContext); + const { token, user } = useContext(MainContext); const [cartItemCount, setCartItemCount] = useState(0); - const { selectedCurrency, setSelectedCurrency, SUPPORTED_CURRENCIES, error } = - useCurrency(); + const { + selectedCurrency, + setSelectedCurrency, + SUPPORTED_CURRENCIES, + error, + setUserCountry, + userCountry + } = useCurrency(); const toggleSidebar = () => setIsSidebarOpen(!isSidebarOpen); @@ -41,12 +47,17 @@ const Navbar = () => { }; }, []); + // Set user's country from profile if available + useEffect(() => { + if (user && user.country && !userCountry) { + setUserCountry(user.country); + } + }, [user, setUserCountry, userCountry]); + const getCart = async () => { try { const response = await authAxios.get("/orders/cart/"); const cartData = response.data; - console.log(cartData); - console.log(cartData.length); // Calculate total items in cart if (cartData && cartData.length > 0 && cartData[0].items) { @@ -249,7 +260,7 @@ const Navbar = () => { )} -
+
); }; diff --git a/components/payment/paymentComponent.jsx b/components/payment/paymentComponent.jsx index 643d5ee..1fff627 100644 --- a/components/payment/paymentComponent.jsx +++ b/components/payment/paymentComponent.jsx @@ -146,7 +146,6 @@ const PaymentComponent = ({ amount, onSuccess }) => { )} - {/* Show shipping info status */} {shippingInfoCollected && (
Shipping information collected ✓ @@ -159,7 +158,6 @@ const PaymentComponent = ({ amount, onSuccess }) => {
)} - {/* Collect shipping info button */} {!shippingInfoCollected && (