From e94648e2b806146668d7b992371e96cbabc77246 Mon Sep 17 00:00:00 2001 From: Maxime Lalo Date: Tue, 2 Apr 2024 16:07:25 +0200 Subject: [PATCH] :sparkles: Subscribe page --- .../DefaultTemplate/classes.module.scss | 3 +- .../classes.module.scss | 63 +++++++ .../SubscribeCheckoutTicket/index.tsx | 173 +++++++++++++++++- .../SubscribeIllimity/classes.module.scss | 74 +++++++- .../Subscribe/SubscribeIllimity/index.tsx | 155 +++++++++++----- .../SubscribeStandard/classes.module.scss | 74 +++++++- .../Subscribe/SubscribeStandard/index.tsx | 153 ++++++++++++---- src/front/Themes/modes.scss | 2 + src/front/Themes/variables.scss | 1 + 9 files changed, 611 insertions(+), 87 deletions(-) diff --git a/src/front/Components/LayoutTemplates/DefaultTemplate/classes.module.scss b/src/front/Components/LayoutTemplates/DefaultTemplate/classes.module.scss index 5ed93eb5..41b044a9 100644 --- a/src/front/Components/LayoutTemplates/DefaultTemplate/classes.module.scss +++ b/src/front/Components/LayoutTemplates/DefaultTemplate/classes.module.scss @@ -4,7 +4,6 @@ margin: var(--root-margin); max-width: var(--root-max-width); min-width: 100%; - min-height: calc(100vh - 83px); &.padding { padding: var(--root-padding); @@ -17,4 +16,4 @@ padding: 0 16px; } } -} \ No newline at end of file +} diff --git a/src/front/Components/Layouts/Subscription/Subscribe/SubscribeCheckoutTicket/classes.module.scss b/src/front/Components/Layouts/Subscription/Subscribe/SubscribeCheckoutTicket/classes.module.scss index e69de29b..f9ced6e5 100644 --- a/src/front/Components/Layouts/Subscription/Subscribe/SubscribeCheckoutTicket/classes.module.scss +++ b/src/front/Components/Layouts/Subscription/Subscribe/SubscribeCheckoutTicket/classes.module.scss @@ -0,0 +1,63 @@ +@import "@Themes/constants.scss"; + +.root { + width: 372px; + + @media (max-width: $screen-s) { + width: 100%; + } + .container { + display: flex; + flex-direction: column; + justify-content: center; + gap: 32px; + box-shadow: 0px 8px 10px 0px #00000012; + padding: 22px 40px; + border-radius: 16px; + + @media (max-width: $screen-s) { + box-shadow: none; + padding: 0px; + } + + .forfeit-type { + text-align: center; + } + + .container-frequency { + display: flex; + justify-content: space-between; + } + + .separator { + width: 100%; + height: 1px; + background-color: gray; + } + + .container-line { + display: flex; + flex-direction: column; + gap: 24px; + .line { + display: flex; + justify-content: space-between; + + .line-sub-container { + display: flex; + flex-direction: column; + } + } + } + + .container-tight { + gap: 8px; + } + + .payment-button { + @media (max-width: $screen-s) { + display: none; + } + } + } +} diff --git a/src/front/Components/Layouts/Subscription/Subscribe/SubscribeCheckoutTicket/index.tsx b/src/front/Components/Layouts/Subscription/Subscribe/SubscribeCheckoutTicket/index.tsx index 3b567fcc..7c3e7df9 100644 --- a/src/front/Components/Layouts/Subscription/Subscribe/SubscribeCheckoutTicket/index.tsx +++ b/src/front/Components/Layouts/Subscription/Subscribe/SubscribeCheckoutTicket/index.tsx @@ -1,11 +1,178 @@ +import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography"; import { EForfeitType } from "../../SubscriptionFacturation"; import classes from "./classes.module.scss"; +import { useEffect, useState } from "react"; +import RadioBox from "@Front/Components/DesignSystem/RadioBox"; +import Button from "@Front/Components/DesignSystem/Button"; +import classnames from "classnames"; + +export const forfeitsPrices: Record = { + [EForfeitType.standard]: 99, + [EForfeitType.unlimited]: 249, +}; + +export const collaboratorPrice = 6.99; type IProps = { forfeitType: EForfeitType; + numberOfCollaborators: number; + defaultFrequency?: EPaymentFrequency; }; -export default function SubscribeCheckoutTicket(props: IProps) { - const { forfeitType } = props; - return
; +export enum EPaymentFrequency { + monthly, + yearly, +} + +export default function SubscribeCheckoutTicket(props: IProps) { + const { forfeitType, numberOfCollaborators } = props; + const [paymentFrequency, setPaymentFrequency] = useState(props.defaultFrequency ?? EPaymentFrequency.monthly); + const [multiplier, setMultiplier] = useState(1); + + useEffect(() => { + setMultiplier(paymentFrequency === EPaymentFrequency.monthly ? 1 : 12); + }, [paymentFrequency]); + + const handleFrequencyChange = (e: React.ChangeEvent) => { + setPaymentFrequency(parseInt(e.target.value) as EPaymentFrequency); + }; + + const formatFloat = (value: number) => { + return value.toFixed(2).replace(".", ","); + }; + + return ( +
+
+
+ + {forfeitType === EForfeitType.standard ? "Forfait standard" : "Forfait illimité"} + +
+
+
+ + Annuel + + + Mensuel + +
+
+
+
+
+ + {forfeitType === EForfeitType.standard ? "Plan individuel" : "Plan illimité"} + + {paymentFrequency === EPaymentFrequency.yearly && ( + + {forfeitType === EForfeitType.standard + ? forfeitsPrices[EForfeitType.standard] + : forfeitsPrices[EForfeitType.unlimited]} +  € x 12 + + )} +
+ + + {forfeitType === EForfeitType.standard + ? forfeitsPrices[EForfeitType.standard] * multiplier + : forfeitsPrices[EForfeitType.unlimited] * multiplier} + € + +
+ {forfeitType === EForfeitType.standard && ( +
+
+ + {numberOfCollaborators} collaborateurs + + + {formatFloat(collaboratorPrice)} € x {numberOfCollaborators} + +
+ + {formatFloat(collaboratorPrice * numberOfCollaborators * multiplier)} € + +
+ )} +
+ {forfeitType === EForfeitType.standard && ( + <> +
+
+
+ + Total HT + + + {formatFloat( + (forfeitsPrices[EForfeitType.standard] + collaboratorPrice * numberOfCollaborators) * multiplier, + )} +  € + +
+
+ + TVA 20% + + + {formatFloat( + (forfeitsPrices[EForfeitType.standard] + collaboratorPrice * numberOfCollaborators) * + 0.2 * + multiplier, + )} +  € + +
+
+ + )} +
+
+ {forfeitType === EForfeitType.unlimited && ( +
+ + TVA 20% + + + {formatFloat(forfeitsPrices[EForfeitType.unlimited] * 0.2 * multiplier)} € + +
+ )} +
+ + Total TTC + + {forfeitType === EForfeitType.standard && ( + + {formatFloat( + (forfeitsPrices[EForfeitType.standard] + collaboratorPrice * numberOfCollaborators) * 1.2 * multiplier, + )} +  € + + )} + {forfeitType === EForfeitType.unlimited && ( + + {formatFloat(forfeitsPrices[EForfeitType.unlimited] * 1.2 * multiplier)} +  € + + )} +
+
+ +
+
+ ); } diff --git a/src/front/Components/Layouts/Subscription/Subscribe/SubscribeIllimity/classes.module.scss b/src/front/Components/Layouts/Subscription/Subscribe/SubscribeIllimity/classes.module.scss index 80936b83..9796b980 100644 --- a/src/front/Components/Layouts/Subscription/Subscribe/SubscribeIllimity/classes.module.scss +++ b/src/front/Components/Layouts/Subscription/Subscribe/SubscribeIllimity/classes.module.scss @@ -1,9 +1,20 @@ @import "@Themes/constants.scss"; .root { - max-width: 1024px; display: flex; + justify-content: space-between; gap: 104px; + + @media (max-width: $screen-m) { + margin-top: 40px; + margin-bottom: 40px; + gap: 72px; + } + + @media (max-width: $screen-s) { + margin-bottom: 50px; + } + .left { display: flex; gap: 40px; @@ -13,6 +24,10 @@ flex-direction: column; gap: 16px; .line { + svg { + min-width: 24px; + min-height: 24px; + } display: flex; gap: 16px; } @@ -21,5 +36,62 @@ .right { width: 372px; + @media (max-width: $screen-m) { + margin-top: 50px; + } + + @media (max-width: $screen-s) { + display: none; + } + } + + button { + @media (max-width: $screen-s) { + display: none; + } + } +} + +.bottom { + display: none; + position: sticky; + bottom: 0px; + flex-direction: column; + justify-content: center; + gap: 32px; + box-shadow: 0px 8px 10px 0px #00000012; + padding: 22px 16px; + border-radius: 16px 16px 0 0; + background: white; + + @media (max-width: $screen-s) { + display: flex; + } + + box-shadow: 0px 4px 24px 0px #00000026; + + .forfeit-type { + text-align: center; + } + + .container-frequency { + display: flex; + justify-content: space-between; + } + + .separator { + width: 100%; + height: 1px; + background-color: gray; + } + + .container-line { + display: flex; + justify-content: space-between; + gap: 24px; + } + + .container-tight { + gap: 8px; } } diff --git a/src/front/Components/Layouts/Subscription/Subscribe/SubscribeIllimity/index.tsx b/src/front/Components/Layouts/Subscription/Subscribe/SubscribeIllimity/index.tsx index bf7548fa..e275c50d 100644 --- a/src/front/Components/Layouts/Subscription/Subscribe/SubscribeIllimity/index.tsx +++ b/src/front/Components/Layouts/Subscription/Subscribe/SubscribeIllimity/index.tsx @@ -2,54 +2,125 @@ import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Ty import classes from "./classes.module.scss"; import DefaultTemplate from "@Front/Components/LayoutTemplates/DefaultTemplate"; import NavTab from "@Front/Components/Elements/NavTab"; -import CheckIcon from "@Assets/Icons/check.svg"; -import Image from "next/image"; +import SubscribeCheckoutTicket, { EPaymentFrequency, forfeitsPrices } from "../SubscribeCheckoutTicket"; +import { EForfeitType } from "../../SubscriptionFacturation"; +import { useEffect, useState } from "react"; +import Check from "@Front/Components/Elements/Icons/Check"; +import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button"; +import RadioBox from "@Front/Components/DesignSystem/RadioBox"; +import Confirm from "@Front/Components/DesignSystem/Modal/Confirm"; +import useOpenable from "@Front/Hooks/useOpenable"; export default function SubscribeIllimity() { + const { close, isOpen, open } = useOpenable(); + + const formatFloat = (value: number) => { + return value.toFixed(2).replace(".", ","); + }; + + const [paymentFrequency, setPaymentFrequency] = useState(EPaymentFrequency.monthly); + const [multiplier, setMultiplier] = useState(1); + + useEffect(() => { + setMultiplier(paymentFrequency === EPaymentFrequency.monthly ? 1 : 12); + }, [paymentFrequency]); + + const handleFrequencyChange = (e: React.ChangeEvent) => { + setPaymentFrequency(parseInt(e.target.value) as EPaymentFrequency); + }; + return ( - -
-
- - - Nombre de collaborateurs illimités - -
-
- Check icon - - Accompagnement facilité : profitez d'un onboarding individualisé, où nous vous guidons pour une prise en - main optimale de l'application - -
-
- Check icon - - Support technique : notre équipe support est disponible pour vous assister en cas d’incident - -
-
- Check icon - - Mises à jour régulières : bénéficiez de mises à jour fréquentes pour profiter des dernières fonctionnalités, - améliorations de sécurité et performances optimisées - -
-
- Check icon - - Sans limite d'utilisateurs - + <> + +
+
+ + + Nombre de collaborateurs illimité + +
+
+ + + Accompagnement facilité : profitez d'un onboarding individualisé, où nous vous guidons pour une prise en + main optimale de l'application + +
+
+ + + Support technique : notre équipe support est disponible pour vous assister en cas d’incident + +
+
+ + + Mises à jour régulières : bénéficiez de mises à jour fréquentes pour profiter des dernières + fonctionnalités, améliorations de sécurité et performances optimisées + +
+
+ + + Sans limite d'utilisateurs + +
+
+ +
+ +
+
+ + + +
+
+ + Annuel + + + Mensuel + +
+
+
+ + Total TTC + + + {formatFloat(forfeitsPrices[EForfeitType.unlimited] * 1.2 * multiplier)} +  € + +
+
+ +
+
+
-
- + ); } diff --git a/src/front/Components/Layouts/Subscription/Subscribe/SubscribeStandard/classes.module.scss b/src/front/Components/Layouts/Subscription/Subscribe/SubscribeStandard/classes.module.scss index 80936b83..9796b980 100644 --- a/src/front/Components/Layouts/Subscription/Subscribe/SubscribeStandard/classes.module.scss +++ b/src/front/Components/Layouts/Subscription/Subscribe/SubscribeStandard/classes.module.scss @@ -1,9 +1,20 @@ @import "@Themes/constants.scss"; .root { - max-width: 1024px; display: flex; + justify-content: space-between; gap: 104px; + + @media (max-width: $screen-m) { + margin-top: 40px; + margin-bottom: 40px; + gap: 72px; + } + + @media (max-width: $screen-s) { + margin-bottom: 50px; + } + .left { display: flex; gap: 40px; @@ -13,6 +24,10 @@ flex-direction: column; gap: 16px; .line { + svg { + min-width: 24px; + min-height: 24px; + } display: flex; gap: 16px; } @@ -21,5 +36,62 @@ .right { width: 372px; + @media (max-width: $screen-m) { + margin-top: 50px; + } + + @media (max-width: $screen-s) { + display: none; + } + } + + button { + @media (max-width: $screen-s) { + display: none; + } + } +} + +.bottom { + display: none; + position: sticky; + bottom: 0px; + flex-direction: column; + justify-content: center; + gap: 32px; + box-shadow: 0px 8px 10px 0px #00000012; + padding: 22px 16px; + border-radius: 16px 16px 0 0; + background: white; + + @media (max-width: $screen-s) { + display: flex; + } + + box-shadow: 0px 4px 24px 0px #00000026; + + .forfeit-type { + text-align: center; + } + + .container-frequency { + display: flex; + justify-content: space-between; + } + + .separator { + width: 100%; + height: 1px; + background-color: gray; + } + + .container-line { + display: flex; + justify-content: space-between; + gap: 24px; + } + + .container-tight { + gap: 8px; } } diff --git a/src/front/Components/Layouts/Subscription/Subscribe/SubscribeStandard/index.tsx b/src/front/Components/Layouts/Subscription/Subscribe/SubscribeStandard/index.tsx index dc9336d9..e30d151e 100644 --- a/src/front/Components/Layouts/Subscription/Subscribe/SubscribeStandard/index.tsx +++ b/src/front/Components/Layouts/Subscription/Subscribe/SubscribeStandard/index.tsx @@ -2,50 +2,127 @@ import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Ty import classes from "./classes.module.scss"; import DefaultTemplate from "@Front/Components/LayoutTemplates/DefaultTemplate"; import NavTab from "@Front/Components/Elements/NavTab"; -import CheckIcon from "@Assets/Icons/check.svg"; -import Image from "next/image"; import NumberPicker from "@Front/Components/Elements/NumberPicker"; +import SubscribeCheckoutTicket, { EPaymentFrequency, collaboratorPrice, forfeitsPrices } from "../SubscribeCheckoutTicket"; +import { EForfeitType } from "../../SubscriptionFacturation"; +import { useEffect, useState } from "react"; +import Check from "@Front/Components/Elements/Icons/Check"; +import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button"; +import RadioBox from "@Front/Components/DesignSystem/RadioBox"; +import Confirm from "@Front/Components/DesignSystem/Modal/Confirm"; +import useOpenable from "@Front/Hooks/useOpenable"; + +export default function SubscribeStandard() { + const [numberOfCollaborators, setNumberOfCollaborators] = useState(1); + const { close, isOpen, open } = useOpenable(); + const handleCollaboratorsChange = (value: number) => { + setNumberOfCollaborators(value); + }; + + const formatFloat = (value: number) => { + return value.toFixed(2).replace(".", ","); + }; + + const [paymentFrequency, setPaymentFrequency] = useState(EPaymentFrequency.monthly); + const [multiplier, setMultiplier] = useState(1); + + useEffect(() => { + setMultiplier(paymentFrequency === EPaymentFrequency.monthly ? 1 : 12); + }, [paymentFrequency]); + + const handleFrequencyChange = (e: React.ChangeEvent) => { + setPaymentFrequency(parseInt(e.target.value) as EPaymentFrequency); + }; -export default function SubscribeIllimity() { return ( - -
-
- - - Choisissez le nombre de collaborateurs pour votre abonnement - - {}} min={1} /> -
-
- Check icon - - Accompagnement facilité : profitez d'un onboarding individualisé, où nous vous guidons pour une prise en - main optimale de l'application - -
-
- Check icon - - Support technique : notre équipe support est disponible pour vous assister en cas d’incident - -
-
- Check icon - - Mises à jour régulières : bénéficiez de mises à jour fréquentes pour profiter des dernières fonctionnalités, - améliorations de sécurité et performances optimisées - + <> + +
+
+ + + Choisissez le nombre de collaborateurs pour votre abonnement + + +
+
+ + + Accompagnement facilité : profitez d'un onboarding individualisé, où nous vous guidons pour une prise en + main optimale de l'application + +
+
+ + + Support technique : notre équipe support est disponible pour vous assister en cas d’incident + +
+
+ + + Mises à jour régulières : bénéficiez de mises à jour fréquentes pour profiter des dernières + fonctionnalités, améliorations de sécurité et performances optimisées + +
+
+ +
+ +
+
+ + + +
+
+ + Annuel + + + Mensuel + +
+
+
+ + Total TTC + + + {formatFloat( + (forfeitsPrices[EForfeitType.standard] + collaboratorPrice * numberOfCollaborators) * 1.2 * multiplier, + )} +  € + +
+
+ +
+
+
-
- + ); } diff --git a/src/front/Themes/modes.scss b/src/front/Themes/modes.scss index c5a412e1..be21231a 100644 --- a/src/front/Themes/modes.scss +++ b/src/front/Themes/modes.scss @@ -4,6 +4,8 @@ body.body { // --black: #000000; --green-flash: #{green-flash}; + --black: #{$black}; + // --blue-flash: #005176; // --turquoise-flash: #3fa79e; // --purple-flash: #320756; diff --git a/src/front/Themes/variables.scss b/src/front/Themes/variables.scss index a5740818..f067f836 100644 --- a/src/front/Themes/variables.scss +++ b/src/front/Themes/variables.scss @@ -31,5 +31,6 @@ --grey-medium: #{$grey-medium}; --grey-soft: #{$grey-soft}; + --black: #{$black}; --white: #{$white}; }