diff --git a/src/TODO.md b/src/TODO.md new file mode 100644 index 00000000000..7382675c319 --- /dev/null +++ b/src/TODO.md @@ -0,0 +1,44 @@ +# TODO + +## Links + +- [PC-TicketNumber](https://passculture.atlassian.net/browse/PC-TicketNumber) +- [MobTime](https://mobtime.hadrienmp.fr/mob/pass-culture) + +--- + +## Tasks + +- [ ] CAS 0 : Utilisation de `formatToFrenchDecimal()` + - [ ] Modifier `formatToFrenchDecimal()` pour qu'il fasse la conversion en XPF + + +- [ ] CAS 1 : Prix en dur dans le code : + - [ ] 1.1 : Crédits par âges + - [ ] Utiliser `useDepositAmountsByAge()` lorsque le crédit est marqué en dur car il utilise directement `formatToFrenchDecimal()`: + - [ ] `300\u00a0€` + - [ ] `30\u00a0€` + - [ ] `20\u00a0€` + - [ ] 1.2 : Crédit par seuil comme la part pour les offres numériques (plus tard le spectacle vivant) + - [ ] Utiliser `formatToFrenchDecimal(NUMERIC_AMOUNT)` + - [ ] Créer une constante la part du crédit pour les offres numériques. ex: const NUMERIC_AMOUNT = 10.000. + + +- [ ] CAS 2 : Utilisation de `useMaxPrice()` (ex `${maxPrice}\u00a0€ ...`) + - [ ] Utiliser des centimes plutôt que des euros dans `useMaxPrice()` ? + + +- [ ] CAS 3 : Utilisation de `getDisplayPrice()` (ex: `dès 15,60\u00a0€` (tableau de prix)) + + +- [ ] CAS 4 : Utilisation de `formatPriceInEuroToDisplayPrice()` + + +- [ ] CAS 5 : Mention de "€" (ex: `en €`) + - [ ] Créer une fonction qui ne gère pas les crédits mais juste les devises + +--- + +## Tasks for another US + +- [ ] \ No newline at end of file diff --git a/src/features/birthdayNotifications/pages/EighteenBirthday.tsx b/src/features/birthdayNotifications/pages/EighteenBirthday.tsx index 6a86e8c1a5d..4e12ba9ef8f 100644 --- a/src/features/birthdayNotifications/pages/EighteenBirthday.tsx +++ b/src/features/birthdayNotifications/pages/EighteenBirthday.tsx @@ -12,16 +12,18 @@ import { ClockFilled } from 'ui/svg/icons/ClockFilled' import { Spacer } from 'ui/theme' import { CaptionNeutralInfo, Typo } from 'ui/theme/typography' import { getHeadingAttrs } from 'ui/theme/typographyAttrs/getHeadingAttrs' +import { formatToFrenchDecimal } from 'libs/parsers/getDisplayPrice' +import { useDepositAmountsByAge } from 'shared/user/useDepositAmountsByAge' const getPageWording = (userRequiresIdCheck?: boolean) => { if (userRequiresIdCheck) { return { - text: 'Vérifie ton identité pour débloquer tes 300\u00a0€.', + text: `Vérifie ton identité pour débloquer tes ${useDepositAmountsByAge().eighteenYearsOldDeposit}.`, buttonText: 'Vérifier mon identité', } } return { - text: 'Confirme tes informations personnelles pour débloquer tes 300\u00a0€.', + text: `Confirme tes informations personnelles pour débloquer tes ${useDepositAmountsByAge().eighteenYearsOldDeposit}.`, buttonText: 'Confirmer mes informations', } } @@ -39,7 +41,7 @@ export function EighteenBirthday() { {pageWording.text} - Ton crédit précédent a été remis à 0 €. + Ton crédit précédent a été remis à {formatToFrenchDecimal(0)}. { + const { selectedPlace } = useLocation() + const isNewCaledonianLocation = selectedPlace?.info === 'Nouvelle-Calédonie' + + return isNewCaledonianLocation ? MAX_PRICE * EURO_TO_XPF_RATE : MAX_PRICE +} diff --git a/src/features/search/helpers/useMaxPrice/useMaxPrice.ts b/src/features/search/helpers/useMaxPrice/useMaxPrice.ts index 90c05d80ba5..9e3ce13994a 100644 --- a/src/features/search/helpers/useMaxPrice/useMaxPrice.ts +++ b/src/features/search/helpers/useMaxPrice/useMaxPrice.ts @@ -1,16 +1,17 @@ import { useAuthContext } from 'features/auth/context/AuthContext' import { isUserExBeneficiary } from 'features/profile/helpers/isUserExBeneficiary' -import { MAX_PRICE } from 'features/search/helpers/reducer.helpers' +import { useGetMaxPrice } from 'features/search/helpers/useMaxPrice/useGetMaxPrice' import { convertCentsToEuros } from 'libs/parsers/pricesConversion' export const useMaxPrice = (): number => { + const maxPrice = useGetMaxPrice() const { user } = useAuthContext() const initialCredit = user?.domainsCredit?.all.initial - if (!user || !initialCredit) return MAX_PRICE + if (!user || !initialCredit) return maxPrice - if (isUserExBeneficiary(user) || initialCredit === 0) return MAX_PRICE + if (isUserExBeneficiary(user) || initialCredit === 0) return maxPrice return convertCentsToEuros(initialCredit) } diff --git a/src/features/search/pages/modals/PriceModal/PriceModal.tsx b/src/features/search/pages/modals/PriceModal/PriceModal.tsx index 8a3b5528068..789432c624c 100644 --- a/src/features/search/pages/modals/PriceModal/PriceModal.tsx +++ b/src/features/search/pages/modals/PriceModal/PriceModal.tsx @@ -11,7 +11,6 @@ import { SearchCustomModalHeader } from 'features/search/components/SearchCustom import { SearchFixedModalBottom } from 'features/search/components/SearchFixedModalBottom' import { useSearch } from 'features/search/context/SearchWrapper' import { FilterBehaviour } from 'features/search/enums' -import { MAX_PRICE } from 'features/search/helpers/reducer.helpers' import { makeSearchPriceSchema } from 'features/search/helpers/schema/makeSearchPriceSchema/makeSearchPriceSchema' import { SearchState } from 'features/search/types' import { formatToFrenchDecimal } from 'libs/parsers/getDisplayPrice' @@ -26,6 +25,8 @@ import { Separator } from 'ui/components/Separator' import { Close } from 'ui/svg/icons/Close' import { Error } from 'ui/svg/icons/Error' import { getSpacing, Spacer } from 'ui/theme' +import { useGetMaxPrice } from 'features/search/helpers/useMaxPrice/useGetMaxPrice' +import { useCurrencyToDisplay } from 'features/search/pages/modals/PriceModal/useCurrencyToDisplay' type PriceModalFormData = { minPrice: string @@ -55,6 +56,8 @@ export const PriceModal: FunctionComponent = ({ filterBehaviour, onClose, }) => { + const currency = useCurrencyToDisplay() + const MAX_PRICE = useGetMaxPrice() const { searchState, dispatch } = useSearch() const { isLoggedIn, user } = useAuthContext() const availableCredit = useAvailableCredit() @@ -301,7 +304,7 @@ export const PriceModal: FunctionComponent = ({ autoCapitalize="none" isError={error && value.length > 0} keyboardType="numeric" - label="Prix minimum (en €)" + label={`Prix minimum (en\u00a0${currency})`} value={value} onChangeText={onChange} onBlur={onBlur} @@ -331,7 +334,7 @@ export const PriceModal: FunctionComponent = ({ autoCapitalize="none" isError={error && value.length > 0} keyboardType="numeric" - label="Prix maximum (en €)" + label={`Prix maximum (en\u00a0${currency})`} value={value} onChangeText={(value) => { onChange(value) @@ -341,7 +344,7 @@ export const PriceModal: FunctionComponent = ({ textContentType="none" // disable autofill on iOS accessibilityDescribedBy={maxPriceInputId} testID="Entrée pour le prix maximum" - rightLabel={`max\u00a0: ${formatInitialCredit}\u00a0€`} + rightLabel={`max\u00a0: ${formatInitialCredit}\u00a0${currency}`} placeholder={`${formatInitialCredit}`} disabled={getValues('isLimitCreditSearch') || getValues('isOnlyFreeOffersSearch')} /> diff --git a/src/features/search/pages/modals/PriceModal/useCurrencyToDisplay.ts b/src/features/search/pages/modals/PriceModal/useCurrencyToDisplay.ts new file mode 100644 index 00000000000..9f69a43beab --- /dev/null +++ b/src/features/search/pages/modals/PriceModal/useCurrencyToDisplay.ts @@ -0,0 +1,8 @@ +import { useLocation } from 'libs/location' + +export const useCurrencyToDisplay = () => { + const { selectedPlace } = useLocation() + const isNewCaledonianLocation = selectedPlace?.info === 'Nouvelle-Calédonie' + + return isNewCaledonianLocation ? 'CSP' : '€' +} diff --git a/src/features/tutorial/components/profileTutorial/EighteenBlockDescription.tsx b/src/features/tutorial/components/profileTutorial/EighteenBlockDescription.tsx index 44e888fd9ca..309c600fdf2 100644 --- a/src/features/tutorial/components/profileTutorial/EighteenBlockDescription.tsx +++ b/src/features/tutorial/components/profileTutorial/EighteenBlockDescription.tsx @@ -10,11 +10,14 @@ import { BicolorNumeric } from 'ui/svg/icons/bicolor/Numeric' import { BicolorClock } from 'ui/svg/icons/BicolorClock' import { BicolorLock } from 'ui/svg/icons/BicolorLock' import { Spacer, Typo } from 'ui/theme' +import { formatToFrenchDecimal } from 'libs/parsers/getDisplayPrice' type Props = { ongoingCredit?: boolean } +const NUMERIC_AMOUNT = 10000 + export const EighteenBlockDescription: FunctionComponent = ({ ongoingCredit = false }) => { const { isLoggedIn, user } = useAuthContext() @@ -32,7 +35,7 @@ export const EighteenBlockDescription: FunctionComponent = ({ ongoingCred } - text="La limite de 100 € est là pour t’encourager à tester des offres culturelles variées." + text={`La limite de ${formatToFrenchDecimal(NUMERIC_AMOUNT)} est là pour t’encourager à tester des offres culturelles variées.`} />, ] const items = @@ -43,7 +46,7 @@ export const EighteenBlockDescription: FunctionComponent = ({ ongoingCred - dont 100 € en offres numériques (streaming, presse en ligne, …) + {`dont ${formatToFrenchDecimal(NUMERIC_AMOUNT)} en offres numériques (streaming, presse en ligne, …)`} } items={items} /> diff --git a/src/libs/parsers/getDisplayPrice.ts b/src/libs/parsers/getDisplayPrice.ts index a64ac8b2f12..88f27a8ae37 100644 --- a/src/libs/parsers/getDisplayPrice.ts +++ b/src/libs/parsers/getDisplayPrice.ts @@ -1,25 +1,42 @@ -import { CENTS_IN_EURO, convertEuroToCents } from 'libs/parsers/pricesConversion' +import { CENTS_IN_EURO, EURO_TO_XPF_RATE, convertEuroToCents } from 'libs/parsers/pricesConversion' type FormatPriceOptions = { fractionDigits?: number } /** - * Takes a price in cents (ex: 5.5€ = 550 cents) and returns a string with the - * price in euros in the French format, ex: "5,50 €" - * @param {number} priceInCents + * Takes a price in cents (for EUR) and returns a string with the + * price in the appropriate format, ex: "5,50 €" or "11933 XPF" + * based on the value of isNewCaledonianLocation + * @param {number} priceInCents - price in euros (in cents) */ + export const formatToFrenchDecimal = (priceInCents: number, options?: FormatPriceOptions) => { - const euros = priceInCents / CENTS_IN_EURO - const fractionDigits = options?.fractionDigits ?? (euros === Math.floor(euros) ? 0 : 2) + const isNewCaledonianLocation = true + // const { selectedPlace } = useLocation() + // const isNewCaledonianLocation = selectedPlace?.info === 'Nouvelle-Calédonie' + + const priceInEuros = priceInCents / CENTS_IN_EURO + let price: number + let unit: string + let fractionDigits: number + + if (isNewCaledonianLocation) { + price = priceInEuros * EURO_TO_XPF_RATE + unit = 'CFP' + fractionDigits = 0 + } else { + price = priceInEuros + unit = '€' + fractionDigits = options?.fractionDigits ?? (price === Math.floor(price) ? 0 : 2) + } const formatter = new Intl.NumberFormat('fr-FR', { - style: 'currency', - currency: 'EUR', minimumFractionDigits: fractionDigits, + maximumFractionDigits: fractionDigits, }) - return formatter.format(euros) + return `${formatter.format(price)}\u00A0${unit}` } export const formatPriceInEuroToDisplayPrice = (priceInEuro: number) => diff --git a/src/libs/parsers/pricesConversion.ts b/src/libs/parsers/pricesConversion.ts index f018444fcfe..ea3b72afe8d 100644 --- a/src/libs/parsers/pricesConversion.ts +++ b/src/libs/parsers/pricesConversion.ts @@ -1,4 +1,5 @@ export const CENTS_IN_EURO = 100 +export const EURO_TO_XPF_RATE = 119.48 export const convertEuroToCents = (p: number): number => { return Math.floor(Number((p * CENTS_IN_EURO).toFixed(2)))