diff --git a/src/components/Dropdown.jsx b/src/components/Dropdown.jsx new file mode 100644 index 0000000000000000000000000000000000000000..60df2ceded2b353012e5ff342ce1ac82e99d6dc3 --- /dev/null +++ b/src/components/Dropdown.jsx @@ -0,0 +1,52 @@ +/** + * Infima's clickable dropdown (used by Docusaurus) doesn't work out of the box. + * There's an open issue: https://github.com/facebookincubator/infima/issues/110 + * + * The suggested solution is to inject some vanilla JavaScript. + * But it would mess with React so this component implements a better abstraction, + * until it's fixed on Docusaurus' or Infima's side. + */ +import React from "react"; + +const DropdownContext = React.createContext({ + open: false, + setOpen: () => {}, +}); + +export function Dropdown({ children }) { + const containerRef = React.useRef(null); + const [open, setOpen] = React.useState(false); + + const contextValue = React.useMemo( + () => ({ open, setOpen }), + [open, setOpen] + ); + + React.useEffect(() => { + const listener = event => { + if (!containerRef.current) { + return; + } + + if (containerRef.current.contains(event.target)) { + setOpen(currentOpen => !currentOpen); + } else { + setOpen(false); + } + }; + + window.document.addEventListener("mouseup", listener); + return () => window.document.removeEventListener("mouseup", listener); + }, []); + + const child = React.Children.only(children); + + return ( + <DropdownContext.Provider value={contextValue}> + {React.cloneElement(child, { + ref: containerRef, + className: `${child.props.className} ${open ? "dropdown--show" : ""}`, + })} + </DropdownContext.Provider> + ); +} diff --git a/src/components/PricingComparator/PricingComparator.js b/src/components/PricingComparator/PricingComparator.js new file mode 100644 index 0000000000000000000000000000000000000000..a7fc83583b030525510755281150054cf21648ec --- /dev/null +++ b/src/components/PricingComparator/PricingComparator.js @@ -0,0 +1,263 @@ +/* eslint-disable react/no-unescaped-entities */ +import React from "react"; +import { FaMinus, FaPlus, FaSortDown } from "react-icons/fa"; +import styles from "./PricingComparator.module.css"; +import { Dropdown } from "../Dropdown"; +import formatNumber from "@site/src/utils/formatNumber"; +import plans from "@site/src/constants/plans"; +import competitors from "@site/src/constants/competitors"; + +function getPrices(users, paidAnnually, labCompetitor, chatCompetitor) { + const plan = [ + { + users: 1, + paidMonthly: plans.grenouille.paidMonthly, + paidAnnually: plans.grenouille.paidAnnually, + }, + { + users: 2, + paidMonthly: plans.grenouille.paidMonthly, + paidAnnually: plans.etang2.paidAnnually, + }, + { + users: 5, + paidMonthly: plans.grenouille.paidMonthly, + paidAnnually: plans.etang5.paidAnnually, + }, + { + users: 10, + paidMonthly: plans.grenouille.paidMonthly, + paidAnnually: plans.etang10.paidAnnually, + }, + { + users: 50, + paidMonthly: plans.grenouille.paidMonthly, + paidAnnually: plans.etang50.paidAnnually, + }, + { + users: 100, + paidMonthly: plans.grenouille.paidMonthly, + paidAnnually: plans.etang100.paidAnnually, + }, + ] + .slice() + .reverse() + .find(plan => plan.users <= users); + + if (paidAnnually) { + return { + froggit: (plan.paidAnnually * Math.max(plan.users, users)) / users, + lab: labCompetitor.paidAnnually, + chat: chatCompetitor.paidAnnually, + }; + } + + return { + froggit: (plan.paidMonthly * Math.max(plan.users, users)) / users, + lab: labCompetitor.paidMonthly, + chat: chatCompetitor.paidMonthly, + }; +} + +export default function PricingComparator() { + const [users, setUsers] = React.useState(1); + const [paidAnnually, setPaidAnnually] = React.useState(true); + const [labCompetitor, setLabCompetitor] = React.useState(competitors.lab[0]); + const [chatCompetitor, setChatCompetitor] = React.useState( + competitors.chat[0] + ); + + const prices = getPrices(users, paidAnnually, labCompetitor, chatCompetitor); + + const decreaseUsers = shiftKey => { + const step = shiftKey ? 10 : 1; + setUsers(currentUsers => Math.max(1, currentUsers - step)); + }; + const increaseUsers = shiftKey => { + const step = shiftKey ? 10 : 1; + setUsers(currentUsers => currentUsers + step); + }; + + return ( + <div className={styles.container}> + <div className={styles.controls}> + <div className={styles.controlsUsers}> + <div className={styles.controlsUsersLabel}>Utilisateurs</div> + <div className={styles.controlsUsersActions}> + <button + type="button" + className="button button--secondary button--sm" + onClick={event => decreaseUsers(event.shiftKey)} + disabled={users <= 1} + > + <FaMinus size={10} /> + </button> + <input + type="text" + onKeyDown={event => { + switch (event.key) { + case "ArrowDown": + return decreaseUsers(event.shiftKey); + case "ArrowUp": + return increaseUsers(event.shiftKey); + } + }} + onChange={event => { + const value = Math.round(Number(event.target.value)); + + if (isNaN(value)) { + return; + } + + setUsers(Math.max(1, value)); + }} + pattern="[0-9]*" + value={users} + className={styles.controlsUsersInput} + /> + <button + type="button" + className="button button--secondary button--sm" + onClick={event => increaseUsers(event.shiftKey)} + > + <FaPlus size={10} /> + </button> + </div> + </div> + + <ul className={`${styles.controlsPeriodicity} pills`}> + <li + role="button" + tabIndex={0} + className={`pills__item ${ + !paidAnnually ? "pills__item--active" : "" + }`} + onClick={() => setPaidAnnually(false)} + > + Mensuel + </li> + <li + role="button" + tabIndex={0} + className={`pills__item ${ + paidAnnually ? "pills__item--active" : "" + }`} + onClick={() => setPaidAnnually(true)} + > + Annuel <span className="badge badge--success">-20%</span> + </li> + </ul> + </div> + + <div className={styles.table}> + <div className={styles.tableHead}> + <div className={styles.tableHeadCell} /> + <div className={styles.tableHeadCell}> + <div> + <strong>Froggit</strong> + </div> + <small>GitLab + Mattermost</small> + </div> + <div className={styles.tableHeadCell}> + <div> + <Dropdown> + <div className="dropdown"> + <div + tabIndex={0} + role="button" + className={styles.dropdownTrigger} + > + <strong>{labCompetitor.name}</strong> <FaSortDown /> + </div> + <ul className="dropdown__menu"> + {competitors.lab.map(competitor => ( + <li key={competitor.name}> + <div + className="dropdown__link" + onClick={() => setLabCompetitor(competitor)} + > + {competitor.name} + </div> + </li> + ))} + </ul> + </div> + </Dropdown> + </div> + <small> </small> + </div> + <div className={styles.tableHeadCell}> + <FaPlus + style={{ + position: "absolute", + top: "24px", + left: "0", + transform: "translateX(-50%)", + }} + /> + <div> + <Dropdown> + <div className="dropdown"> + <div + tabIndex={0} + role="button" + className={styles.dropdownTrigger} + > + <strong>{chatCompetitor.name}</strong> <FaSortDown /> + </div> + <ul className="dropdown__menu"> + {competitors.chat.map(competitor => ( + <li key={competitor.name}> + <div + className="dropdown__link" + onClick={() => setChatCompetitor(competitor)} + > + {competitor.name} + </div> + </li> + ))} + </ul> + </div> + </Dropdown> + </div> + <small> </small> + </div> + </div> + <div className={styles.tableRow}> + <div className={styles.tableRowCell}> + <small>Tarif mensuel HT par utilisateur</small> + </div> + <div className={styles.tableRowCell}> + <small>{formatNumber(prices.froggit)}€</small> + </div> + <div className={styles.tableRowCell}> + <small>{formatNumber(prices.lab)}€</small> + </div> + <div className={styles.tableRowCell}> + <small>{formatNumber(prices.chat)}€</small> + </div> + </div> + <div className={styles.tableRow}> + <div className={styles.tableRowCell} /> + <div className={styles.tableRowCell}> + <strong>{formatNumber(prices.froggit)}€</strong> + </div> + <div className={styles.tableRowCell}> + <strong>{formatNumber(prices.lab + prices.chat)}€</strong> + </div> + </div> + </div> + <p className={styles.summary}> + Économise{users > 1 ? "z" : ""}{" "} + <span className={styles.summaryBadge}> + {formatNumber( + Math.abs(prices.froggit - (prices.lab + prices.chat)) * users * 12 + )} + € + </span>{" "} + par an pour {users} utilisateur + {users > 1 ? "s" : ""} avec Froggit ! + </p> + </div> + ); +} diff --git a/src/components/PricingComparator/PricingComparator.module.css b/src/components/PricingComparator/PricingComparator.module.css new file mode 100644 index 0000000000000000000000000000000000000000..3906ff44e67838b33f8cdf68c105ea71d84187df --- /dev/null +++ b/src/components/PricingComparator/PricingComparator.module.css @@ -0,0 +1,109 @@ +.container { + margin-bottom: 1em; +} + +.controls { + display: flex; + justify-content: space-between; + justify-items: center; + margin-bottom: 0.5rem; +} +.controls input { + margin: 0; +} + +.controlsUsers { + display: flex; + align-items: center; + gap: 1rem; +} +.controlsUsersLabel { +} +.controlsUsersActions { + display: flex; + align-items: center; + gap: 0.5rem; +} +.controlsUsersActions button { + width: 1.5rem; + height: 1.5rem; + padding: 0; + margin: 0; +} +.controlsUsersInput { + padding: 0.2rem 0.6rem; + width: 8ch; +} + +.controlsPeriodicity { + margin: 0; +} + +.dropdownTrigger { + cursor: pointer; +} + +.table { + background-color: var(--ifm-color-secondary-lightest); + box-shadow: var(--ifm-global-shadow-tl); + border-radius: var(--ifm-card-border-radius); +} +.tableHead, +.tableRow { + display: grid; + grid-template-columns: repeat(4, 1fr); +} +.tableRow:nth-child(even) .tableRowCell { + background-color: var(--ifm-color-gray-100); +} +.tableRow:nth-child(even) .tableRowCell:nth-child(2) { + background-color: var(--ifm-color-primary-dark); +} +.tableHeadCell, +.tableRowCell { + position: relative; + padding: 0.4rem 1rem; + text-align: center; +} +.tableHead .tableHeadCell, +.tableRow:last-child .tableRowCell { + padding: 1rem; +} +.tableHeadCell:first-child, +.tableRowCell:first-child { + text-align: right; +} +.tableRowCell { + display: flex; + align-items: center; + justify-content: center; +} +.tableHeadCell:nth-child(2), +.tableRowCell:nth-child(2) { + color: var(--ifm-color-secondary-lightest); + background-color: var(--ifm-color-light-green); +} +.tableHeadCell li { + cursor: pointer; + text-align: left; +} +.tableHeadCell strong { + font-size: var(--ifm-h3-font-size); +} +.tableRow:last-child .tableRowCell:nth-child(3) { + grid-column: span 2; +} + +.summary { + font-size: var(--ifm-h3-font-size); + text-align: center; + margin-top: 2rem; + margin-bottom: 4rem; +} +.summaryBadge { + color: var(--ifm-color-success); + background-color: var(--ifm-color-frame); + padding: 0.4rem 0.8rem; + border-radius: var(--ifm-badge-border-radius); + font-weight: bold; +} diff --git a/src/constants/competitors.ts b/src/constants/competitors.ts new file mode 100644 index 0000000000000000000000000000000000000000..ac46303acc1d53a045640209c6a3d2ba7702a715 --- /dev/null +++ b/src/constants/competitors.ts @@ -0,0 +1,16 @@ +export default { + lab: [ + { + name: "GitHub", + paidMonthly: 3.62, + paidAnnually: 3.62, + }, + ], + chat: [ + { + name: "Slack", + paidMonthly: 18.25, + paidAnnually: 16.75, + }, + ], +}; diff --git a/src/constants/plans.ts b/src/constants/plans.ts new file mode 100644 index 0000000000000000000000000000000000000000..515c5c9fd1693a02485977daccd0db7da0ac2583 --- /dev/null +++ b/src/constants/plans.ts @@ -0,0 +1,24 @@ +export default { + tetard: { + paidAnnually: 2, + }, + grenouille: { + paidMonthly: 9.9, + paidAnnually: 8.25, + }, + etang2: { + paidAnnually: 8.25, + }, + etang5: { + paidAnnually: 8.25, + }, + etang10: { + paidAnnually: 7.43, + }, + etang50: { + paidAnnually: 6.6, + }, + etang100: { + paidAnnually: 5.8, + }, +}; diff --git a/src/pages/dummy-page.mdx b/src/pages/dummy-page.mdx index 75cd8cf66e966fe71a5ce66acfa79d3e00d84c17..4155eea7be60ca75c0c0c618fd85b4db2f8c0904 100644 --- a/src/pages/dummy-page.mdx +++ b/src/pages/dummy-page.mdx @@ -2,7 +2,9 @@ title: dummy description: "page factice" --- + import CarouselLibre from "@site/src/components/Carousel/CarouselLibre"; +import PricingComparator from "@site/src/components/PricingComparator/PricingComparator"; # Page factice @@ -12,7 +14,8 @@ Page factice penser à créer une vraie page ! #!/bin/bash echo "Hello World" ``` -<CarouselLibre/> + +<CarouselLibre /> <button className="button button--note">button--note</button> <button className="button button--success">button--success</button> @@ -20,7 +23,6 @@ echo "Hello World" <button className="button button--warning">button--warning</button> <button className="button button--danger">button--danger</button> - :::note Encart note 🔜 **Les tarifs arrivent !** <a class="button button--note" href="#">Bouton note !</a> ::: @@ -70,3 +72,5 @@ Some **content** with _markdown_ `syntax`. Check [this `api`](#). Some **content** with _markdown_ `syntax`. Check [this `api`](#). ::: + +<PricingComparator /> diff --git a/src/pages/tarifs.mdx b/src/pages/tarifs.mdx index 9756d2f737a2a5df127b048b54589395441ad410..2f641be4ee2c648f216d0dd1dec93106fa69d63c 100644 --- a/src/pages/tarifs.mdx +++ b/src/pages/tarifs.mdx @@ -3,11 +3,14 @@ title: "Tarifs" description: "Les tarifs de Froggit" keywords: Lydra, SaaS, pricing, tarifs, plans, git, GitLab, Mattermost --- + import useBaseUrl from "@docusaurus/useBaseUrl"; import Highlight from "@site/src/components/Highlight"; import Tabs from "@theme/Tabs"; import TabItem from "@theme/TabItem"; import { GiTadpole, GiFrogFoot, GiFrogPrince } from "react-icons/gi"; +import plans from "@site/src/constants/plans"; +import formatNumber from "@site/src/utils/formatNumber"; # Les tarifs de Froggit @@ -40,8 +43,8 @@ Si vous achetez plusieurs plans (**Grenouille** ou **Étang**), avec le **même <h2>Têtard</h2> <p>Idéal pour <strong>débuter</strong> !</p> <p> - <strong>24 €HT/an</strong><br/> - <small class="small_price">soit 2 €HT/mois</small><br/> + <strong>{plans.tetard.paidAnnually * 12} €HT/an</strong><br/> + <small class="small_price">soit {plans.tetard.paidAnnually} €HT/mois</small><br/> <a class="button disabled button-noclick"><GiTadpole size="20px"/> Démarrer</a> </p> </div> @@ -57,42 +60,79 @@ Si vous achetez plusieurs plans (**Grenouille** ou **Étang**), avec le **même </div> </div> - <div class="col"> +<div class="col"> <div class="headband"> <p>Le plus populaire</p> </div> - <div class="card-test"> - <div class="card shadow--tl card_price card_price_main"> - <div class="card__image margin-top--md"> - <img - src={useBaseUrl("img/pages/tarifs/computer.png")} - alt="Image alt text" - title="Plan Grenouille" /> - </div> - <div class="card__body"> - <h2>Grenouille</h2> - <p>Parfait pour les <strong>solo</strong></p> + <div class="card-test"> + <div class="card shadow--tl card_price card_price_main"> + <div class="card__image margin-top--md"> + <img + src={useBaseUrl("img/pages/tarifs/computer.png")} + alt="Image alt text" + title="Plan Grenouille" + /> + </div> + <div class="card__body"> + <h2>Grenouille</h2> + <p> + Parfait pour les <strong>solo</strong> + </p> + <p> + <strong>{formatNumber(plans.grenouille.paidMonthly)} €HT/mois</strong> + <br /> + <small class="small_price"> + <br /> + </small> + <a + class="button button--price margin-bottom--lg" + href="https://www.lydra.eu/cmd_ly_frg_grenouille_1_m" + > + <GiFrogFoot size="20px" /> Coder sans limites + </a> + </p> + </div> + <div class="card__footer"> + <small> <p> - <strong>9,90 €HT/mois</strong><br/> - <small class="small_price"><br/></small> - <a class="button button--price margin-bottom--lg" href="https://www.lydra.eu/cmd_ly_frg_grenouille_1_m"><GiFrogFoot size="20px"/> Coder sans limites</a> + <Highlight color="var(--ifm-color-light-green)">1</Highlight>{" "} + utilisateur </p> - </div> - <div class="card__footer"> - <small> - <p><Highlight color="var(--ifm-color-light-green)">1</Highlight> utilisateur</p> - <p>Groupes <Highlight color="var(--ifm-color-light-green)">illimités</Highlight></p> - <p>Projets <Highlight color="var(--ifm-color-light-green)">illimités</Highlight></p> - <p>Pipeline CI/CD <Highlight color="var(--ifm-color-light-green)">illimité</Highlight></p> - </small> - <small> - <p>Bénéficiez de <Highlight color="var(--ifm-color-light-green)">2 mois offerts</Highlight> en choisissant l'abonnement annuel - <small> soit 8,25 €HT/mois (plan annuel)</small><br/></p> - </small> - </div> + <p> + Groupes{" "} + <Highlight color="var(--ifm-color-light-green)"> + illimités + </Highlight> + </p> + <p> + Projets{" "} + <Highlight color="var(--ifm-color-light-green)"> + illimités + </Highlight> + </p> + <p> + Pipeline CI/CD{" "} + <Highlight color="var(--ifm-color-light-green)">illimité</Highlight> + </p> + </small> + <small> + <p> + Bénéficiez de{" "} + <Highlight color="var(--ifm-color-light-green)"> + 2 mois offerts + </Highlight>{" "} + en choisissant l'abonnement annuel + <small> + {" "} + soit {formatNumber(plans.grenouille.paidAnnually)} €HT/mois (plan annuel) + </small> + <br /> + </p> + </small> </div> </div> </div> +</div> <div class="col"> <div class="disable_col"> @@ -111,8 +151,8 @@ Si vous achetez plusieurs plans (**Grenouille** ou **Étang**), avec le **même className="tabs-etang-hide"> <TabItem value="2"> <p> - à partir de <strong>198 €HT/an</strong><br/> - <small class="small_price">soit 8,25 €HT/mois/utilisateur</small><br/> + à partir de <strong>{formatNumber(plans.etang2.paidAnnually * 2 * 12)} €HT/an</strong><br/> + <small class="small_price">soit {formatNumber(plans.etang2.paidAnnually)} €HT/mois/utilisateur</small><br/> <a class="button disabled button-noclick" href="#url-2"><GiFrogPrince size="20px"/> Acheter <br/> <small>plusieurs sièges</small></a> </p> </TabItem> @@ -147,8 +187,8 @@ Si vous achetez plusieurs plans (**Grenouille** ou **Étang**), avec le **même <h2>Têtard</h2> <p>Idéal pour <strong>débuter</strong> !</p> <p> - <strong>24 €HT/an</strong><br/> - <small class="small_price">soit 2 €HT/mois</small><br/> + <strong>{formatNumber(plans.tetard.paidAnnually * 12)} €HT/an</strong><br/> + <small class="small_price">soit {formatNumber(plans.tetard.paidAnnually)} €HT/mois</small><br/> <a class="button button--price" href="https://www.lydra.eu/cmd_ly_frg_tetard_1_a"><GiTadpole size="20px"/> Démarrer</a> </p> </div> @@ -164,38 +204,68 @@ Si vous achetez plusieurs plans (**Grenouille** ou **Étang**), avec le **même </div> </div> - <div class="col"> +<div class="col"> <div class="headband"> <p>Le plus populaire</p> </div> - <div class="card-test"> - <div class="card shadow--tl card_price card_price_main"> - <div class="card__image margin-top--md"> - <img - src={useBaseUrl("img/pages/tarifs/computer.png")} - alt="Image alt text" - title="Plan Grenouille" /> - </div> - <div class="card__body"> - <h2>Grenouille</h2> - <p>Parfait pour les <strong>solo</strong></p> + <div class="card-test"> + <div class="card shadow--tl card_price card_price_main"> + <div class="card__image margin-top--md"> + <img + src={useBaseUrl("img/pages/tarifs/computer.png")} + alt="Image alt text" + title="Plan Grenouille" + /> + </div> + <div class="card__body"> + <h2>Grenouille</h2> + <p> + Parfait pour les <strong>solo</strong> + </p> + <p> + <strong> + {formatNumber(plans.grenouille.paidAnnually * 12)} €HT/an + </strong> + <br /> + <small class="small_price"> + soit {formatNumber(plans.grenouille.paidAnnually)} €HT/mois + </small> + <a + class="button button--price" + href="https://www.lydra.eu/cmd_ly_frg_grenouille_1_a" + > + <GiFrogFoot size="20px" /> Coder sans limites + <br /> + </a> + </p> + </div> + <div class="card__footer"> + <small> <p> - <strong>99 €HT/an</strong><br/> - <small class="small_price">soit 8,25 €HT/mois</small> - <a class="button button--price" href="https://www.lydra.eu/cmd_ly_frg_grenouille_1_a"><GiFrogFoot size="20px"/> Coder sans limites<br/></a> + <Highlight color="var(--ifm-color-light-green)">1</Highlight>{" "} + utilisateur </p> - </div> - <div class="card__footer"> - <small> - <p><Highlight color="var(--ifm-color-light-green)">1</Highlight> utilisateur</p> - <p>Groupes <Highlight color="var(--ifm-color-light-green)">illimités</Highlight></p> - <p>Projets <Highlight color="var(--ifm-color-light-green)">illimités</Highlight></p> - <p>Pipeline CI/CD <Highlight color="var(--ifm-color-light-green)">illimité</Highlight></p> - </small> - </div> + <p> + Groupes{" "} + <Highlight color="var(--ifm-color-light-green)"> + illimités + </Highlight> + </p> + <p> + Projets{" "} + <Highlight color="var(--ifm-color-light-green)"> + illimités + </Highlight> + </p> + <p> + Pipeline CI/CD{" "} + <Highlight color="var(--ifm-color-light-green)">illimité</Highlight> + </p> + </small> </div> </div> </div> +</div> <div class="col"> <div class="card-demo"> @@ -214,36 +284,36 @@ Si vous achetez plusieurs plans (**Grenouille** ou **Étang**), avec le **même className="tabs-etang-hide"> <TabItem value="2"> <p> - <strong>198 €HT/an</strong><br/> - <small class="small_price">soit 8,25 €HT/mois/utilisateur</small><br/> + <strong>{formatNumber(plans.etang2.paidAnnually * 2 * 12)} €HT/an</strong><br/> + <small class="small_price">soit {formatNumber(plans.etang2.paidAnnually)} €HT/mois/utilisateur</small><br/> <a class="button button button--price" href="https://www.lydra.eu/cmd_ly_frg_etang_2_a"><GiFrogPrince size="20px"/> Acheter <br/> <small>2 sièges</small></a> </p> </TabItem> <TabItem value="5"> <p> - <strong>495 €HT/an</strong><br/> - <small class="small_price">soit 8,25 €HT/mois/utilisateur</small><br/> + <strong>{formatNumber(plans.etang5.paidAnnually * 5 * 12)} €HT/an</strong><br/> + <small class="small_price">soit {formatNumber(plans.etang5.paidAnnually)} €HT/mois/utilisateur</small><br/> <a class="button button button--price" href="https://www.lydra.eu/cmd_ly_frg_etang_5_a"><GiFrogPrince size="20px"/> Acheter <br/> <small>5 sièges</small></a> </p> </TabItem> <TabItem value="10"> <p> - <strong>891 €HT/an</strong><br/> - <small class="small_price">soit 7,43 €HT/mois/utilisateur</small><br/> + <strong>{formatNumber(plans.etang10.paidAnnually * 10 * 12)} €HT/an</strong><br/> + <small class="small_price">soit {formatNumber(plans.etang10.paidAnnually)} €HT/mois/utilisateur</small><br/> <a class="button button button--price" href="https://www.lydra.eu/cmd_ly_frg_etang_10_a"><GiFrogPrince size="20px"/> Acheter <br/> <small>10 sièges</small></a> </p> </TabItem> <TabItem value="50"> <p> - <strong>3 960 €HT/an</strong><br/> - <small class="small_price">soit 6,60 €HT/mois/utilisateur</small><br/> + <strong>{formatNumber(plans.etang50.paidAnnually * 50 * 12)} €HT/an</strong><br/> + <small class="small_price">soit {formatNumber(plans.etang50.paidAnnually)} €HT/mois/utilisateur</small><br/> <a class="button button button--price" href="https://www.lydra.eu/cmd_ly_frg_etang_50_a"><GiFrogPrince size="20px"/> Acheter <br/> <small>50 sièges</small></a> </p> </TabItem> <TabItem value="100"> <p> - <strong>6 960 €HT/an</strong><br/> - <small class="small_price">soit 5,80 €HT/mois/utilisateur</small><br/> + <strong>{formatNumber(plans.etang100.paidAnnually * 100 * 12)} €HT/an</strong><br/> + <small class="small_price">soit {formatNumber(plans.etang100.paidAnnually)} €HT/mois/utilisateur</small><br/> <a class="button button button--price" href="https://www.lydra.eu/cmd_ly_frg_etang_100_a"><GiFrogPrince size="20px"/> Acheter <br/> <small>100 sièges</small></a> </p> </TabItem> diff --git a/src/utils/formatNumber.ts b/src/utils/formatNumber.ts new file mode 100644 index 0000000000000000000000000000000000000000..8d3d0e02e901cc02c5ba923195f15f96d0f5d8b4 --- /dev/null +++ b/src/utils/formatNumber.ts @@ -0,0 +1,11 @@ +export default function formatNumber(n) { + if (n % 1 === 0) { + // integer + return n.toLocaleString("fr-FR", { maximumFractionDigits: 0 }); + } + // float + return n.toLocaleString("fr-FR", { + minimumFractionDigits: 2, + maximumFractionDigits: 2, + }); +}