From a919c385f8fb8ef5869c3e839b41a90e93f0263b Mon Sep 17 00:00:00 2001 From: aelassas Date: Wed, 11 Dec 2024 22:57:50 +0100 Subject: [PATCH] Add currency conversion to homepage --- frontend/.env.docker.example | 1 - frontend/.env.example | 1 - frontend/src/common/helper.ts | 20 ++++++++++--- frontend/src/config/env.config.ts | 15 ++++++---- frontend/src/lang/common.ts | 7 +++-- frontend/src/pages/Home.tsx | 41 +++++++++++++++++++++----- frontend/src/services/StripeService.ts | 8 +++++ packages/bookcars-helper/index.ts | 14 ++++++--- 8 files changed, 81 insertions(+), 26 deletions(-) diff --git a/frontend/.env.docker.example b/frontend/.env.docker.example index 97b6fae46..9dfb1ac7a 100644 --- a/frontend/.env.docker.example +++ b/frontend/.env.docker.example @@ -21,7 +21,6 @@ VITE_BC_MINIMUM_AGE=21 VITE_BC_PAGINATION_MODE=classic VITE_BC_STRIPE_PUBLISHABLE_KEY=STRIPE_PUBLISHABLE_KEY VITE_BC_STRIPE_CURRENCY_CODE=USD -VITE_BC_CURRENCY=$ VITE_BC_SET_LANGUAGE_FROM_IP=false VITE_BC_GOOGLE_ANALYTICS_ENABLED=false VITE_BC_GOOGLE_ANALYTICS_ID=G-XXXXXXXXXX diff --git a/frontend/.env.example b/frontend/.env.example index 67c8e02ca..38a49d754 100644 --- a/frontend/.env.example +++ b/frontend/.env.example @@ -22,7 +22,6 @@ VITE_BC_MINIMUM_AGE=21 VITE_BC_PAGINATION_MODE=classic VITE_BC_STRIPE_PUBLISHABLE_KEY=STRIPE_PUBLISHABLE_KEY VITE_BC_STRIPE_CURRENCY_CODE=USD -VITE_BC_CURRENCY=$ VITE_BC_SET_LANGUAGE_FROM_IP=false VITE_BC_GOOGLE_ANALYTICS_ENABLED=false VITE_BC_GOOGLE_ANALYTICS_ID=G-XXXXXXXXXX diff --git a/frontend/src/common/helper.ts b/frontend/src/common/helper.ts index 86ce49f28..e7ad86b07 100644 --- a/frontend/src/common/helper.ts +++ b/frontend/src/common/helper.ts @@ -4,6 +4,7 @@ import * as bookcarsHelper from ':bookcars-helper' import { strings } from '@/lang/cars' import { strings as commonStrings } from '@/lang/common' import env from '@/config/env.config' +import * as StripeService from '@/services/StripeService' /** * Get language. @@ -627,9 +628,20 @@ export const downloadURI = (uri: string, name: string = '') => { } /** - * Return currency symbol. + * Convert a price to a given currency. * - * @param {string} code - * @returns {string|undefined} + * @async + * @param {number} amount + * @param {string} to + * @returns {Promise} */ -export const getCurrencySymbol = (code: string) => env._CURRENCIES.find((c) => c.code === code)?.symbol +export const convertPrice = async (amount: number) => { + const to = StripeService.getCurrency() + + if (to !== env.BASE_CURRENCY) { + const res = await bookcarsHelper.convertPrice(amount, env.BASE_CURRENCY, to) + return res + } + + return amount +} diff --git a/frontend/src/config/env.config.ts b/frontend/src/config/env.config.ts index 0abcaf106..6cb4a16f7 100644 --- a/frontend/src/config/env.config.ts +++ b/frontend/src/config/env.config.ts @@ -43,6 +43,10 @@ const CURRENCIES: Currency[] = [ { code: 'EUR', symbol: '€', + }, + { + code: 'IQD', + symbol: 'IQD', } ] @@ -58,6 +62,11 @@ const env = { DEFAULT_LANGUAGE: String(import.meta.env.VITE_BC_DEFAULT_LANGUAGE || 'en'), CURRENCIES: CURRENCIES.map((c) => c.code), _CURRENCIES: CURRENCIES, + /** + * The three-letter ISO 4217 alphabetic currency code, e.g. "USD" or "EUR". Required for Stripe payments. Default is "USD". + * Must be a supported currency: https://docs.stripe.com/currencies + * */ + STRIPE_CURRENCY_CODE: String(import.meta.env.VITE_BC_STRIPE_CURRENCY_CODE || 'USD'), BASE_CURRENCY: String(import.meta.env.VITE_BC_BASE_CURRENCY || 'USD'), PAGE_SIZE: Number.parseInt(String(import.meta.env.VITE_BC_PAGE_SIZE), 10) || 30, CARS_PAGE_SIZE: Number.parseInt(String(import.meta.env.VITE_BC_CARS_PAGE_SIZE), 10) || 15, @@ -90,12 +99,6 @@ const env = { ? Const.PAGINATION_MODE.INFINITE_SCROLL : Const.PAGINATION_MODE.CLASSIC, STRIPE_PUBLISHABLE_KEY: String(import.meta.env.VITE_BC_STRIPE_PUBLISHABLE_KEY), - /** - * The three-letter ISO 4217 alphabetic currency code, e.g. "USD" or "EUR". Required for Stripe payments. Default is "USD". - * Must be a supported currency: https://docs.stripe.com/currencies - * */ - STRIPE_CURRENCY_CODE: String(import.meta.env.VITE_BC_STRIPE_CURRENCY_CODE || 'USD'), - CURRENCY: import.meta.env.VITE_BC_CURRENCY || '$', SET_LANGUAGE_FROM_IP: (import.meta.env.VITE_BC_SET_LANGUAGE_FROM_IP && import.meta.env.VITE_BC_SET_LANGUAGE_FROM_IP.toLowerCase()) === 'true', GOOGLE_ANALYTICS_ENABLED: (import.meta.env.VITE_BC_GOOGLE_ANALYTICS_ENABLED && import.meta.env.VITE_BC_GOOGLE_ANALYTICS_ENABLED.toLowerCase()) === 'true', GOOGLE_ANALYTICS_ID: String(import.meta.env.VITE_BC_GOOGLE_ANALYTICS_ID), diff --git a/frontend/src/lang/common.ts b/frontend/src/lang/common.ts index 322d2424e..b8976d7ca 100644 --- a/frontend/src/lang/common.ts +++ b/frontend/src/lang/common.ts @@ -1,6 +1,7 @@ import LocalizedStrings from 'react-localization' import env from '@/config/env.config' import * as langHelper from '@/common/langHelper' +import * as StripeService from '@/services/StripeService' const strings = new LocalizedStrings({ fr: { @@ -31,7 +32,7 @@ const strings = new LocalizedStrings({ SAVE: 'Sauvegarder', CANCEL: 'Annuler', RESET_PASSWORD: 'Changer le mot de passe', - CURRENCY: env.CURRENCY, + CURRENCY: StripeService.getCurrencySymbol(), DAILY: '/jour', DELETE_AVATAR_CONFIRM: 'Êtes-vous sûr de vouloir supprimer la photo ?', DELETE_IMAGE: "Supprimer l'image", @@ -117,7 +118,7 @@ const strings = new LocalizedStrings({ SAVE: 'Save', CANCEL: 'Cancel', RESET_PASSWORD: 'Change Password', - CURRENCY: env.CURRENCY, + CURRENCY: StripeService.getCurrencySymbol(), DAILY: '/day', DELETE_AVATAR_CONFIRM: 'Are you sure you want to delete the picture?', UPLOAD_IMAGE: 'Upload image', @@ -203,7 +204,7 @@ const strings = new LocalizedStrings({ SAVE: 'Guardar', CANCEL: 'Cancelar', RESET_PASSWORD: 'Cambiar contraseña', - CURRENCY: env.CURRENCY, + CURRENCY: StripeService.getCurrencySymbol(), DAILY: '/día', DELETE_AVATAR_CONFIRM: '¿Está seguro de que desea eliminar la foto?', DELETE_IMAGE: 'Eliminar imagen', diff --git a/frontend/src/pages/Home.tsx b/frontend/src/pages/Home.tsx index e84e6f5fd..a02fc9398 100644 --- a/frontend/src/pages/Home.tsx +++ b/frontend/src/pages/Home.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react' +import React, { useEffect, useState } from 'react' import { Button, Checkbox, @@ -37,6 +37,7 @@ import SearchForm from '@/components/SearchForm' import Map from '@/components/Map' import Footer from '@/components/Footer' import FaqList from '@/components/FaqList' +import * as helper from '@/common/helper' import Mini from '@/assets/img/mini.png' import Midi from '@/assets/img/midi.png' @@ -56,6 +57,32 @@ const Home = () => { const [ranges, setRanges] = useState([bookcarsTypes.CarRange.Mini, bookcarsTypes.CarRange.Midi]) const [openRangeSearchFormDialog, setOpenRangeSearchFormDialog] = useState(false) const [videoLoaded, setVideoLoaded] = useState(false) + const [miniPricePhr, setMiniPricePhr] = useState(2.5) + const [miniPricePday, setMiniPricePday] = useState(40) + const [midiPricePhr, setMidiPricePhr] = useState(3.5) + const [midiPricePday, setMidiPricePday] = useState(50) + const [maxiPricePhr, setMaxiPricePhr] = useState(3.5) + const [maxiPricePday, setMaxiPricePday] = useState(50) + + useEffect(() => { + const init = async () => { + const _miniPricePhr = await helper.convertPrice(miniPricePhr) + setMiniPricePhr(_miniPricePhr) + const _miniPricePday = await helper.convertPrice(miniPricePday) + setMiniPricePday(_miniPricePday) + const _midiPricePhr = await helper.convertPrice(midiPricePhr) + setMidiPricePhr(_midiPricePhr) + const _midiPricePday = await helper.convertPrice(midiPricePday) + setMidiPricePday(_midiPricePday) + const _maxiPricePhr = await helper.convertPrice(maxiPricePhr) + setMaxiPricePhr(_maxiPricePhr) + const _maxiPricePday = await helper.convertPrice(maxiPricePday) + setMaxiPricePday(_maxiPricePday) + } + + init() + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []) const handleTabChange = (_event: React.SyntheticEvent, newValue: number) => { setTabValue(newValue) @@ -315,11 +342,11 @@ const Home = () => { /> @@ -347,11 +374,11 @@ const Home = () => { /> @@ -378,11 +405,11 @@ const Home = () => { /> diff --git a/frontend/src/services/StripeService.ts b/frontend/src/services/StripeService.ts index e9b6dc34b..94a88ec1f 100644 --- a/frontend/src/services/StripeService.ts +++ b/frontend/src/services/StripeService.ts @@ -68,3 +68,11 @@ export const getCurrency = () => { } return env.BASE_CURRENCY } + +/** + * Return currency symbol. + * + * @param {string} code + * @returns {string|undefined} + */ +export const getCurrencySymbol = () => env._CURRENCIES.find((c) => c.code === getCurrency())?.symbol || '$' diff --git a/packages/bookcars-helper/index.ts b/packages/bookcars-helper/index.ts index 0fcd99dec..9f2c50811 100644 --- a/packages/bookcars-helper/index.ts +++ b/packages/bookcars-helper/index.ts @@ -1,5 +1,5 @@ import * as bookcarsTypes from ':bookcars-types' -import CurrencyConverter, { CurrencyCode, currencies } from ':currency-converter' +import CurrencyConverter, { currencies } from ':currency-converter' /** * Format a number. @@ -342,11 +342,17 @@ export const calculateTotalPrice = (car: bookcarsTypes.Car, from: Date, to: Date * * @async * @param {number} amount - * @param {CurrencyCode} from - * @param {CurrencyCode} to + * @param {string} from + * @param {string} to * @returns {Promise} */ -export const convertPrice = async (amount: number, from: CurrencyCode, to: CurrencyCode): Promise => { +export const convertPrice = async (amount: number, from: string, to: string): Promise => { + if (!checkCurrency(from)) { + throw new Error(`Currency ${from} not supported`) + } + if (!checkCurrency(to)) { + throw new Error(`Currency ${to} not supported`) + } const cc = new CurrencyConverter({ from, to, amount }) const res = await cc.convert() return res