Merge branch 'dev' into staging
This commit is contained in:
commit
eda95803ec
940
package-lock.json
generated
940
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -12,6 +12,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emotion/react": "^11.10.6",
|
"@emotion/react": "^11.10.6",
|
||||||
"@emotion/styled": "^11.10.6",
|
"@emotion/styled": "^11.10.6",
|
||||||
|
"@heroicons/react": "^2.1.3",
|
||||||
"@mui/material": "^5.11.13",
|
"@mui/material": "^5.11.13",
|
||||||
"@types/node": "18.15.1",
|
"@types/node": "18.15.1",
|
||||||
"@types/react": "18.0.28",
|
"@types/react": "18.0.28",
|
||||||
@ -24,7 +25,7 @@
|
|||||||
"eslint-config-next": "13.2.4",
|
"eslint-config-next": "13.2.4",
|
||||||
"form-data": "^4.0.0",
|
"form-data": "^4.0.0",
|
||||||
"jwt-decode": "^3.1.2",
|
"jwt-decode": "^3.1.2",
|
||||||
"le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.119",
|
"le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.126",
|
||||||
"next": "13.2.4",
|
"next": "13.2.4",
|
||||||
"prettier": "^2.8.7",
|
"prettier": "^2.8.7",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
|
40
src/front/Api/LeCoffreApi/Admin/Stripe/Stripe.ts
Normal file
40
src/front/Api/LeCoffreApi/Admin/Stripe/Stripe.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import { EType } from "le-coffre-resources/dist/Admin/Subscription";
|
||||||
|
import BaseAdmin from "../BaseAdmin";
|
||||||
|
|
||||||
|
export interface IPostStripeParams {
|
||||||
|
type: EType;
|
||||||
|
nb_seats: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type IPostStripeResponse = {
|
||||||
|
url: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class Stripe extends BaseAdmin {
|
||||||
|
private static instance: Stripe;
|
||||||
|
private readonly baseURl = this.namespaceUrl.concat("/stripe");
|
||||||
|
|
||||||
|
private constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static getInstance() {
|
||||||
|
if (!this.instance) {
|
||||||
|
return new Stripe();
|
||||||
|
} else {
|
||||||
|
return this.instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async post(body: IPostStripeParams) {
|
||||||
|
const url = new URL(this.baseURl);
|
||||||
|
try {
|
||||||
|
console.log(body);
|
||||||
|
|
||||||
|
return await this.postRequest<IPostStripeResponse>(url, body as any);
|
||||||
|
} catch (err) {
|
||||||
|
this.onError(err);
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -96,6 +96,10 @@
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&[fullwidthattr="false"] {
|
||||||
|
width: fit-content;
|
||||||
|
}
|
||||||
|
|
||||||
&[touppercase="false"] {
|
&[touppercase="false"] {
|
||||||
text-transform: inherit;
|
text-transform: inherit;
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,13 @@
|
|||||||
&.H1-60 {
|
&.H1-60 {
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
font-size: 50px;
|
font-size: 56px;
|
||||||
line-height: 61px;
|
line-height: 67.2px;
|
||||||
|
|
||||||
|
@media (max-width: $screen-m) {
|
||||||
|
font-size: 48px;
|
||||||
|
line-height: 56.7px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.H1-bis-40 {
|
&.H1-bis-40 {
|
||||||
@ -115,6 +120,14 @@
|
|||||||
letter-spacing: 0.5px;
|
letter-spacing: 0.5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.Caption_14-semibold {
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 22px;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
}
|
||||||
|
|
||||||
&.re-hover {
|
&.re-hover {
|
||||||
color: $re-hover;
|
color: $re-hover;
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ export enum ITypo {
|
|||||||
P_ERR_16 = "Paragraphe-16-error",
|
P_ERR_16 = "Paragraphe-16-error",
|
||||||
|
|
||||||
CAPTION_14 = "Caption_14",
|
CAPTION_14 = "Caption_14",
|
||||||
|
CAPTION_14_SB = "Caption_14-semibold",
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ITypoColor {
|
export enum ITypoColor {
|
||||||
@ -45,7 +46,7 @@ export enum ITypoColor {
|
|||||||
export default class Typography extends React.Component<IProps, IState> {
|
export default class Typography extends React.Component<IProps, IState> {
|
||||||
public override render(): JSX.Element {
|
public override render(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<div
|
<span
|
||||||
className={classNames(
|
className={classNames(
|
||||||
classes["root"],
|
classes["root"],
|
||||||
classes[this.props.typo],
|
classes[this.props.typo],
|
||||||
@ -54,7 +55,7 @@ export default class Typography extends React.Component<IProps, IState> {
|
|||||||
)}
|
)}
|
||||||
title={this.props.title}>
|
title={this.props.title}>
|
||||||
{this.props.children}
|
{this.props.children}
|
||||||
</div>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
31
src/front/Components/Elements/MessageBox/classes.module.scss
Normal file
31
src/front/Components/Elements/MessageBox/classes.module.scss
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
.root {
|
||||||
|
display: flex;
|
||||||
|
gap: 24px;
|
||||||
|
padding: 16px;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
min-width: 20px;
|
||||||
|
min-height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.info {
|
||||||
|
border: 1px solid #005176;
|
||||||
|
background: #c3eae64d;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.warning {
|
||||||
|
background-color: var(--Warning-100);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.success {
|
||||||
|
border: 1px solid var(--green-flash);
|
||||||
|
background: #12bf4d0d;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.error {
|
||||||
|
border: 1px solid var(--red-soft);
|
||||||
|
background: #f087711a;
|
||||||
|
}
|
||||||
|
}
|
37
src/front/Components/Elements/MessageBox/index.tsx
Normal file
37
src/front/Components/Elements/MessageBox/index.tsx
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import classes from "./classes.module.scss";
|
||||||
|
import classNames from "classnames";
|
||||||
|
import { InformationCircleIcon, ExclamationTriangleIcon } from "@heroicons/react/24/outline";
|
||||||
|
import Typography, { ITypo } from "@Front/Components/DesignSystem/Typography";
|
||||||
|
|
||||||
|
export type IProps = {
|
||||||
|
type: "info" | "warning" | "success" | "error";
|
||||||
|
children?: React.ReactNode;
|
||||||
|
className?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function MessageBox(props: IProps) {
|
||||||
|
const { className, type, children } = props;
|
||||||
|
return (
|
||||||
|
<div className={classNames(className, classes["root"], classes[type])}>
|
||||||
|
{getIcon(type)}
|
||||||
|
<div className={classes["content"]}>
|
||||||
|
<Typography className={classes["text"]} typo={ITypo.CAPTION_14}>
|
||||||
|
{children}
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
function getIcon(type: IProps["type"]) {
|
||||||
|
switch (type) {
|
||||||
|
case "info":
|
||||||
|
return <InformationCircleIcon />;
|
||||||
|
case "warning":
|
||||||
|
return <ExclamationTriangleIcon />;
|
||||||
|
case "success":
|
||||||
|
return <InformationCircleIcon />;
|
||||||
|
case "error":
|
||||||
|
return <InformationCircleIcon />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
src/front/Components/Elements/NavTab/classes.module.scss
Normal file
25
src/front/Components/Elements/NavTab/classes.module.scss
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
.root {
|
||||||
|
nav {
|
||||||
|
display: flex;
|
||||||
|
gap: 32px;
|
||||||
|
.link {
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 16px;
|
||||||
|
text-decoration: none;
|
||||||
|
border-bottom: 1px solid transparent;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-bottom: 1px solid black;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
color: black;
|
||||||
|
border-bottom: 1px solid black;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
margin-top: 24px;
|
||||||
|
}
|
||||||
|
}
|
43
src/front/Components/Elements/NavTab/index.tsx
Normal file
43
src/front/Components/Elements/NavTab/index.tsx
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import classNames from "classnames";
|
||||||
|
import classes from "./classes.module.scss";
|
||||||
|
import Link from "next/link";
|
||||||
|
import Typography, { ITypo } from "@Front/Components/DesignSystem/Typography";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
|
|
||||||
|
type ITabItem = {
|
||||||
|
label: string;
|
||||||
|
path: string;
|
||||||
|
activePaths?: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
type IProps = {
|
||||||
|
items: ITabItem[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function NavTab(props: IProps) {
|
||||||
|
const router = useRouter();
|
||||||
|
return (
|
||||||
|
<div className={classes["root"]}>
|
||||||
|
<nav>
|
||||||
|
{props.items.map((item, index) => {
|
||||||
|
let isMatch = false;
|
||||||
|
if (item.activePaths) {
|
||||||
|
isMatch = item.activePaths.some((path) => router.pathname.includes(path));
|
||||||
|
} else {
|
||||||
|
isMatch = router.pathname.includes(item.path) ? true : false;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Link
|
||||||
|
key={item.path.toString()}
|
||||||
|
href={item.path}
|
||||||
|
className={classNames(classes["link"], isMatch && classes["active"])}>
|
||||||
|
<Typography key={index} typo={isMatch ? ITypo.P_SB_18 : ITypo.P_18}>
|
||||||
|
{item.label}
|
||||||
|
</Typography>
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,2 @@
|
|||||||
|
.root {
|
||||||
|
}
|
47
src/front/Components/Elements/NumberPicker/index.tsx
Normal file
47
src/front/Components/Elements/NumberPicker/index.tsx
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import { useState } from "react";
|
||||||
|
import classes from "./classes.module.scss";
|
||||||
|
|
||||||
|
type IProps = {
|
||||||
|
defaultValue: number;
|
||||||
|
onChange: (value: number) => void;
|
||||||
|
min?: number;
|
||||||
|
max?: number;
|
||||||
|
disabled?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function NumberPicker(props: IProps) {
|
||||||
|
const { defaultValue, onChange, min, max, disabled } = props;
|
||||||
|
const [value, setValue] = useState(defaultValue);
|
||||||
|
|
||||||
|
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
let value = parseInt(e.target.value);
|
||||||
|
if (min && value < min) {
|
||||||
|
value = min;
|
||||||
|
}
|
||||||
|
if (max && value > max) {
|
||||||
|
value = max;
|
||||||
|
}
|
||||||
|
setValue(value);
|
||||||
|
onChange(value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMinus = () => {
|
||||||
|
handleChange({ target: { value: value - 1 } } as any);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handlePlus = () => {
|
||||||
|
handleChange({ target: { value: value + 1 } } as any);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classes["root"]}>
|
||||||
|
<button onClick={handleMinus} disabled={min && value <= min ? true : false}>
|
||||||
|
-
|
||||||
|
</button>
|
||||||
|
<input type="number" value={value} onChange={handleChange} disabled={disabled} />
|
||||||
|
<button onClick={handlePlus} disabled={max && value >= max ? true : false}>
|
||||||
|
+
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -4,7 +4,6 @@
|
|||||||
margin: var(--root-margin);
|
margin: var(--root-margin);
|
||||||
max-width: var(--root-max-width);
|
max-width: var(--root-max-width);
|
||||||
min-width: 100%;
|
min-width: 100%;
|
||||||
min-height: calc(100vh - 83px);
|
|
||||||
|
|
||||||
&.padding {
|
&.padding {
|
||||||
padding: var(--root-padding);
|
padding: var(--root-padding);
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,196 @@
|
|||||||
|
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";
|
||||||
|
import { EType } from "le-coffre-resources/dist/Admin/Subscription";
|
||||||
|
import Stripe from "@Front/Api/LeCoffreApi/Admin/Stripe/Stripe";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
|
|
||||||
|
export const forfeitsPrices: Record<EForfeitType, number> = {
|
||||||
|
[EForfeitType.standard]: 99,
|
||||||
|
[EForfeitType.unlimited]: 249,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const collaboratorPrice = 6.99;
|
||||||
|
|
||||||
|
type IProps = {
|
||||||
|
forfeitType: EForfeitType;
|
||||||
|
numberOfCollaborators: number;
|
||||||
|
defaultFrequency?: EPaymentFrequency;
|
||||||
|
};
|
||||||
|
|
||||||
|
export enum EPaymentFrequency {
|
||||||
|
monthly,
|
||||||
|
yearly,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function SubscribeCheckoutTicket(props: IProps) {
|
||||||
|
const router = useRouter();
|
||||||
|
const { forfeitType, numberOfCollaborators } = props;
|
||||||
|
const [paymentFrequency, setPaymentFrequency] = useState<EPaymentFrequency>(props.defaultFrequency ?? EPaymentFrequency.monthly);
|
||||||
|
const [multiplier, setMultiplier] = useState<number>(1);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setMultiplier(paymentFrequency === EPaymentFrequency.monthly ? 1 : 12);
|
||||||
|
}, [paymentFrequency]);
|
||||||
|
|
||||||
|
const handleFrequencyChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setPaymentFrequency(parseInt(e.target.value) as EPaymentFrequency);
|
||||||
|
};
|
||||||
|
|
||||||
|
const formatFloat = (value: number) => {
|
||||||
|
return value.toFixed(2).replace(".", ",");
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSubmitPayment = async () => {
|
||||||
|
console.log("handleSubmitPayment");
|
||||||
|
|
||||||
|
const stripeCheckout = {
|
||||||
|
type: EType.Standard,
|
||||||
|
nb_seats: numberOfCollaborators,
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const newStripeCheckout = await Stripe.getInstance().post(stripeCheckout);
|
||||||
|
router.push(newStripeCheckout.url);
|
||||||
|
} catch (error) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classes["root"]}>
|
||||||
|
<div className={classes["container"]}>
|
||||||
|
<div className={classes["forfeit-type"]}>
|
||||||
|
<Typography typo={ITypo.P_18} color={ITypoColor.BLACK}>
|
||||||
|
{forfeitType === EForfeitType.standard ? "Forfait standard" : "Forfait illimité"}
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={classes["separator"]} />
|
||||||
|
<div className={classes["container-frequency"]}>
|
||||||
|
<RadioBox
|
||||||
|
name="paymentFrequency"
|
||||||
|
value={EPaymentFrequency.yearly.toString()}
|
||||||
|
onChange={handleFrequencyChange}
|
||||||
|
defaultChecked={paymentFrequency === EPaymentFrequency.yearly}>
|
||||||
|
<Typography typo={ITypo.P_ERR_18}>Annuel</Typography>
|
||||||
|
</RadioBox>
|
||||||
|
<RadioBox
|
||||||
|
name="paymentFrequency"
|
||||||
|
value={EPaymentFrequency.monthly.toString()}
|
||||||
|
onChange={handleFrequencyChange}
|
||||||
|
defaultChecked={paymentFrequency === EPaymentFrequency.monthly}>
|
||||||
|
<Typography typo={ITypo.P_ERR_18}>Mensuel</Typography>
|
||||||
|
</RadioBox>
|
||||||
|
</div>
|
||||||
|
<div className={classes["separator"]} />
|
||||||
|
<div className={classes["container-line"]}>
|
||||||
|
<div className={classes["line"]}>
|
||||||
|
<div className={classes["line-sub-container"]}>
|
||||||
|
<Typography typo={ITypo.P_18} color={ITypoColor.BLACK}>
|
||||||
|
{forfeitType === EForfeitType.standard ? "Plan individuel" : "Plan illimité"}
|
||||||
|
</Typography>
|
||||||
|
{paymentFrequency === EPaymentFrequency.yearly && (
|
||||||
|
<Typography typo={ITypo.CAPTION_14_SB} color={ITypoColor.BLACK}>
|
||||||
|
{forfeitType === EForfeitType.standard
|
||||||
|
? forfeitsPrices[EForfeitType.standard]
|
||||||
|
: forfeitsPrices[EForfeitType.unlimited]}
|
||||||
|
€ x 12
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Typography typo={ITypo.P_SB_18} color={ITypoColor.BLACK}>
|
||||||
|
{forfeitType === EForfeitType.standard
|
||||||
|
? forfeitsPrices[EForfeitType.standard] * multiplier
|
||||||
|
: forfeitsPrices[EForfeitType.unlimited] * multiplier}
|
||||||
|
€
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
{forfeitType === EForfeitType.standard && (
|
||||||
|
<div className={classes["line"]}>
|
||||||
|
<div className={classes["line-sub-container"]}>
|
||||||
|
<Typography typo={ITypo.P_18} color={ITypoColor.BLACK}>
|
||||||
|
{numberOfCollaborators} collaborateurs
|
||||||
|
</Typography>
|
||||||
|
<Typography typo={ITypo.CAPTION_14_SB} color={ITypoColor.BLACK}>
|
||||||
|
{formatFloat(collaboratorPrice)} € x {numberOfCollaborators}
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<Typography typo={ITypo.P_SB_18} color={ITypoColor.BLACK}>
|
||||||
|
{formatFloat(collaboratorPrice * numberOfCollaborators * multiplier)} €
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{forfeitType === EForfeitType.standard && (
|
||||||
|
<>
|
||||||
|
<div className={classes["separator"]} />
|
||||||
|
<div className={classnames(classes["container-line"], classes["container-tight"])}>
|
||||||
|
<div className={classes["line"]}>
|
||||||
|
<Typography typo={ITypo.P_18} color={ITypoColor.BLACK}>
|
||||||
|
Total HT
|
||||||
|
</Typography>
|
||||||
|
<Typography typo={ITypo.P_SB_18} color={ITypoColor.BLACK}>
|
||||||
|
{formatFloat(
|
||||||
|
(forfeitsPrices[EForfeitType.standard] + collaboratorPrice * numberOfCollaborators) * multiplier,
|
||||||
|
)}
|
||||||
|
€
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={classes["line"]}>
|
||||||
|
<Typography typo={ITypo.P_18} color={ITypoColor.BLACK}>
|
||||||
|
TVA 20%
|
||||||
|
</Typography>
|
||||||
|
<Typography typo={ITypo.P_SB_18} color={ITypoColor.BLACK}>
|
||||||
|
{formatFloat(
|
||||||
|
(forfeitsPrices[EForfeitType.standard] + collaboratorPrice * numberOfCollaborators) *
|
||||||
|
0.2 *
|
||||||
|
multiplier,
|
||||||
|
)}
|
||||||
|
€
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
<div className={classes["separator"]} />
|
||||||
|
<div className={classnames(classes["container-line"], classes["container-tight"])}>
|
||||||
|
{forfeitType === EForfeitType.unlimited && (
|
||||||
|
<div className={classes["line"]}>
|
||||||
|
<Typography typo={ITypo.P_18} color={ITypoColor.BLACK}>
|
||||||
|
TVA 20%
|
||||||
|
</Typography>
|
||||||
|
<Typography typo={ITypo.P_SB_18} color={ITypoColor.BLACK}>
|
||||||
|
{formatFloat(forfeitsPrices[EForfeitType.unlimited] * 0.2 * multiplier)} €
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className={classes["line"]}>
|
||||||
|
<Typography typo={ITypo.P_18} color={ITypoColor.BLACK}>
|
||||||
|
Total TTC
|
||||||
|
</Typography>
|
||||||
|
{forfeitType === EForfeitType.standard && (
|
||||||
|
<Typography typo={ITypo.P_SB_18} color={ITypoColor.BLACK}>
|
||||||
|
{formatFloat(
|
||||||
|
(forfeitsPrices[EForfeitType.standard] + collaboratorPrice * numberOfCollaborators) * 1.2 * multiplier,
|
||||||
|
)}
|
||||||
|
€
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
{forfeitType === EForfeitType.unlimited && (
|
||||||
|
<Typography typo={ITypo.P_SB_18} color={ITypoColor.BLACK}>
|
||||||
|
{formatFloat(forfeitsPrices[EForfeitType.unlimited] * 1.2 * multiplier)}
|
||||||
|
€
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Button onClick={handleSubmitPayment} fullwidth className={classes["payment-button"]}>
|
||||||
|
Passer au paiement
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,98 @@
|
|||||||
|
@import "@Themes/constants.scss";
|
||||||
|
|
||||||
|
.root {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 104px;
|
||||||
|
max-width: 1400px;
|
||||||
|
margin: auto;
|
||||||
|
@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;
|
||||||
|
flex-direction: column;
|
||||||
|
.infos-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
.line {
|
||||||
|
svg {
|
||||||
|
min-width: 24px;
|
||||||
|
min-height: 24px;
|
||||||
|
}
|
||||||
|
display: flex;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,125 @@
|
|||||||
|
import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography";
|
||||||
|
import classes from "./classes.module.scss";
|
||||||
|
import DefaultTemplate from "@Front/Components/LayoutTemplates/DefaultTemplate";
|
||||||
|
import NavTab from "@Front/Components/Elements/NavTab";
|
||||||
|
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>(EPaymentFrequency.monthly);
|
||||||
|
const [multiplier, setMultiplier] = useState<number>(1);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setMultiplier(paymentFrequency === EPaymentFrequency.monthly ? 1 : 12);
|
||||||
|
}, [paymentFrequency]);
|
||||||
|
|
||||||
|
const handleFrequencyChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setPaymentFrequency(parseInt(e.target.value) as EPaymentFrequency);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DefaultTemplate title="Nouvelle souscription" hasHeaderLinks={false}>
|
||||||
|
<div className={classes["root"]}>
|
||||||
|
<div className={classes["left"]}>
|
||||||
|
<NavTab
|
||||||
|
items={[
|
||||||
|
{ label: "Forfait standard", path: "/subscription/subscribe/standard" },
|
||||||
|
{ label: "Forfait illimité", path: "/subscription/subscribe/illimity" },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
<Typography typo={ITypo.H2} color={ITypoColor.BLACK}>
|
||||||
|
Nombre de collaborateurs illimité
|
||||||
|
</Typography>
|
||||||
|
<div className={classes["infos-container"]}>
|
||||||
|
<div className={classes["line"]}>
|
||||||
|
<Check color={ITypoColor.GREY} />
|
||||||
|
<Typography typo={ITypo.P_16} color={ITypoColor.GREY}>
|
||||||
|
Accompagnement facilité : profitez d'un onboarding individualisé, où nous vous guidons pour une prise en
|
||||||
|
main optimale de l'application
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={classes["line"]}>
|
||||||
|
<Check color={ITypoColor.GREY} />
|
||||||
|
<Typography typo={ITypo.P_16} color={ITypoColor.GREY}>
|
||||||
|
Support technique : notre équipe support est disponible pour vous assister en cas d’incident
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={classes["line"]}>
|
||||||
|
<Check color={ITypoColor.GREY} />
|
||||||
|
<Typography typo={ITypo.P_16} color={ITypoColor.GREY}>
|
||||||
|
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
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={classes["line"]}>
|
||||||
|
<Check color={ITypoColor.BLACK} />
|
||||||
|
<Typography typo={ITypo.P_16} color={ITypoColor.BLACK}>
|
||||||
|
Sans limite d'utilisateurs
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={classes["right"]}>
|
||||||
|
<SubscribeCheckoutTicket forfeitType={EForfeitType.unlimited} numberOfCollaborators={1} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</DefaultTemplate>
|
||||||
|
<Confirm isOpen={isOpen} onClose={close} showCancelButton={false} confirmText={"Passer au paiement"} closeBtn onAccept={close}>
|
||||||
|
<SubscribeCheckoutTicket
|
||||||
|
forfeitType={EForfeitType.unlimited}
|
||||||
|
numberOfCollaborators={1}
|
||||||
|
defaultFrequency={paymentFrequency}
|
||||||
|
/>
|
||||||
|
</Confirm>
|
||||||
|
<div className={classes["bottom"]}>
|
||||||
|
<div className={classes["container-frequency"]}>
|
||||||
|
<RadioBox
|
||||||
|
name="paymentFrequencyInSubscription"
|
||||||
|
value={EPaymentFrequency.yearly.toString()}
|
||||||
|
onChange={handleFrequencyChange}
|
||||||
|
defaultChecked={paymentFrequency === EPaymentFrequency.yearly}>
|
||||||
|
<Typography typo={ITypo.P_ERR_18}>Annuel</Typography>
|
||||||
|
</RadioBox>
|
||||||
|
<RadioBox
|
||||||
|
name="paymentFrequencyInSubscription"
|
||||||
|
value={EPaymentFrequency.monthly.toString()}
|
||||||
|
onChange={handleFrequencyChange}
|
||||||
|
defaultChecked={paymentFrequency === EPaymentFrequency.monthly}>
|
||||||
|
<Typography typo={ITypo.P_ERR_18}>Mensuel</Typography>
|
||||||
|
</RadioBox>
|
||||||
|
</div>
|
||||||
|
<div className={classes["separator"]} />
|
||||||
|
<div className={classes["container-line"]}>
|
||||||
|
<Typography typo={ITypo.P_18} color={ITypoColor.BLACK}>
|
||||||
|
Total TTC
|
||||||
|
</Typography>
|
||||||
|
<Typography typo={ITypo.P_SB_18} color={ITypoColor.BLACK}>
|
||||||
|
{formatFloat(forfeitsPrices[EForfeitType.unlimited] * 1.2 * multiplier)}
|
||||||
|
€
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={classes["voir-recap"]}>
|
||||||
|
<Button fullwidth variant={EButtonVariant.LINE} onClick={open}>
|
||||||
|
Voir le récapitulatif plus en détail
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<div className={classes["payment-button"]}>
|
||||||
|
<Button fullwidth>Passer au paiement</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,98 @@
|
|||||||
|
@import "@Themes/constants.scss";
|
||||||
|
|
||||||
|
.root {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 104px;
|
||||||
|
max-width: 1400px;
|
||||||
|
margin: auto;
|
||||||
|
@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;
|
||||||
|
flex-direction: column;
|
||||||
|
.infos-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
.line {
|
||||||
|
svg {
|
||||||
|
min-width: 24px;
|
||||||
|
min-height: 24px;
|
||||||
|
}
|
||||||
|
display: flex;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,129 @@
|
|||||||
|
import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography";
|
||||||
|
import classes from "./classes.module.scss";
|
||||||
|
import DefaultTemplate from "@Front/Components/LayoutTemplates/DefaultTemplate";
|
||||||
|
import NavTab from "@Front/Components/Elements/NavTab";
|
||||||
|
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";
|
||||||
|
// import Stripe from "@Front/Api/LeCoffreApi/Admin/Stripe/Stripe";
|
||||||
|
// import { EType } from "le-coffre-resources/dist/Admin/Subscription";
|
||||||
|
|
||||||
|
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>(EPaymentFrequency.monthly);
|
||||||
|
const [multiplier, setMultiplier] = useState<number>(1);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setMultiplier(paymentFrequency === EPaymentFrequency.monthly ? 1 : 12);
|
||||||
|
}, [paymentFrequency]);
|
||||||
|
|
||||||
|
const handleFrequencyChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setPaymentFrequency(parseInt(e.target.value) as EPaymentFrequency);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DefaultTemplate title="Nouvelle souscription" hasHeaderLinks={false}>
|
||||||
|
<div className={classes["root"]}>
|
||||||
|
<div className={classes["left"]}>
|
||||||
|
<NavTab
|
||||||
|
items={[
|
||||||
|
{ label: "Forfait standard", path: "/subscription/subscribe/standard" },
|
||||||
|
{ label: "Forfait illimité", path: "/subscription/subscribe/illimity" },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
<Typography typo={ITypo.H2} color={ITypoColor.BLACK}>
|
||||||
|
Choisissez le nombre de collaborateurs pour votre abonnement
|
||||||
|
</Typography>
|
||||||
|
<NumberPicker defaultValue={1} onChange={handleCollaboratorsChange} min={1} />
|
||||||
|
<div className={classes["infos-container"]}>
|
||||||
|
<div className={classes["line"]}>
|
||||||
|
<Check color={ITypoColor.GREY} />
|
||||||
|
<Typography typo={ITypo.P_16} color={ITypoColor.GREY}>
|
||||||
|
Accompagnement facilité : profitez d'un onboarding individualisé, où nous vous guidons pour une prise en
|
||||||
|
main optimale de l'application
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={classes["line"]}>
|
||||||
|
<Check color={ITypoColor.GREY} />
|
||||||
|
<Typography typo={ITypo.P_16} color={ITypoColor.GREY}>
|
||||||
|
Support technique : notre équipe support est disponible pour vous assister en cas d’incident
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={classes["line"]}>
|
||||||
|
<Check color={ITypoColor.GREY} />
|
||||||
|
<Typography typo={ITypo.P_16} color={ITypoColor.GREY}>
|
||||||
|
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
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={classes["right"]}>
|
||||||
|
<SubscribeCheckoutTicket forfeitType={EForfeitType.standard} numberOfCollaborators={numberOfCollaborators} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</DefaultTemplate>
|
||||||
|
<Confirm isOpen={isOpen} onClose={close} showCancelButton={false} confirmText={"Passer au paiement"} closeBtn onAccept={close}>
|
||||||
|
<SubscribeCheckoutTicket
|
||||||
|
forfeitType={EForfeitType.standard}
|
||||||
|
numberOfCollaborators={numberOfCollaborators}
|
||||||
|
defaultFrequency={paymentFrequency}
|
||||||
|
/>
|
||||||
|
</Confirm>
|
||||||
|
<div className={classes["bottom"]}>
|
||||||
|
<div className={classes["container-frequency"]}>
|
||||||
|
<RadioBox
|
||||||
|
name="paymentFrequencyInSubscription"
|
||||||
|
value={EPaymentFrequency.yearly.toString()}
|
||||||
|
onChange={handleFrequencyChange}
|
||||||
|
defaultChecked={paymentFrequency === EPaymentFrequency.yearly}>
|
||||||
|
<Typography typo={ITypo.P_ERR_18}>Annuel</Typography>
|
||||||
|
</RadioBox>
|
||||||
|
<RadioBox
|
||||||
|
name="paymentFrequencyInSubscription"
|
||||||
|
value={EPaymentFrequency.monthly.toString()}
|
||||||
|
onChange={handleFrequencyChange}
|
||||||
|
defaultChecked={paymentFrequency === EPaymentFrequency.monthly}>
|
||||||
|
<Typography typo={ITypo.P_ERR_18}>Mensuel</Typography>
|
||||||
|
</RadioBox>
|
||||||
|
</div>
|
||||||
|
<div className={classes["separator"]} />
|
||||||
|
<div className={classes["container-line"]}>
|
||||||
|
<Typography typo={ITypo.P_18} color={ITypoColor.BLACK}>
|
||||||
|
Total TTC
|
||||||
|
</Typography>
|
||||||
|
<Typography typo={ITypo.P_SB_18} color={ITypoColor.BLACK}>
|
||||||
|
{formatFloat(
|
||||||
|
(forfeitsPrices[EForfeitType.standard] + collaboratorPrice * numberOfCollaborators) * 1.2 * multiplier,
|
||||||
|
)}
|
||||||
|
€
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={classes["voir-recap"]}>
|
||||||
|
<Button fullwidth variant={EButtonVariant.LINE} onClick={open}>
|
||||||
|
Voir le récapitulatif plus en détail
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<div className={classes["payment-button"]}>
|
||||||
|
<Button fullwidth>Passer au paiement</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
.root {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 32px;
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography";
|
||||||
|
import classes from "./classes.module.scss";
|
||||||
|
|
||||||
|
export default function SubscriptionClientInfos() {
|
||||||
|
return (
|
||||||
|
<div className={classes["root"]}>
|
||||||
|
<Typography typo={ITypo.P_SB_18} color={ITypoColor.BLACK}>
|
||||||
|
Informations client
|
||||||
|
</Typography>
|
||||||
|
<Typography typo={ITypo.P_18} color={ITypoColor.BLACK}>
|
||||||
|
john.doe@contact.fr
|
||||||
|
</Typography>
|
||||||
|
<Typography typo={ITypo.P_SB_18} color={ITypoColor.BLACK}>
|
||||||
|
Adresse de facturation
|
||||||
|
</Typography>
|
||||||
|
<Typography typo={ITypo.P_18} color={ITypoColor.BLACK}>
|
||||||
|
John Doe <br />
|
||||||
|
23 rue taitbout,
|
||||||
|
<br />
|
||||||
|
75009 Paris
|
||||||
|
<br />
|
||||||
|
France
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
.root {
|
||||||
|
display: flex;
|
||||||
|
gap: 104px;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.left {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 32px;
|
||||||
|
width: 548px;
|
||||||
|
}
|
||||||
|
.separator {
|
||||||
|
width: 100%;
|
||||||
|
height: 2px;
|
||||||
|
background: var(--grey-medium);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
import DefaultTemplate from "@Front/Components/LayoutTemplates/DefaultTemplate";
|
||||||
|
import classes from "./classes.module.scss";
|
||||||
|
import SubscriptionTicket from "../SubscriptionTicket";
|
||||||
|
import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography";
|
||||||
|
import MessageBox from "@Front/Components/Elements/MessageBox";
|
||||||
|
import SubscriptionClientInfos from "../SubscriptionClientInfos";
|
||||||
|
import Button from "@Front/Components/DesignSystem/Button";
|
||||||
|
|
||||||
|
export default function SubscriptionError() {
|
||||||
|
return (
|
||||||
|
<DefaultTemplate title="Erreur à la souscription" hasHeaderLinks={false}>
|
||||||
|
<div className={classes["root"]}>
|
||||||
|
<div className={classes["left"]}>
|
||||||
|
<div className={classes["title"]}>
|
||||||
|
<Typography typo={ITypo.H1} color={ITypoColor.BLACK}>
|
||||||
|
Paiement échoué
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={classes["alert"]}>
|
||||||
|
<MessageBox type={"error"}>
|
||||||
|
Votre transaction n'a pas pu être complétée.
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
Malheureusement, nous n'avons pas pu traiter votre paiement et votre abonnement n'a pas été activé. Veuillez
|
||||||
|
vérifier vos informations de paiement et essayer à nouveau.
|
||||||
|
</MessageBox>
|
||||||
|
</div>
|
||||||
|
<div className={classes["separator"]} />
|
||||||
|
<div className={classes["client-infos"]}>
|
||||||
|
<SubscriptionClientInfos />
|
||||||
|
</div>
|
||||||
|
<div className={classes["separator"]} />
|
||||||
|
<Button>Réessayer le paiement</Button>
|
||||||
|
</div>
|
||||||
|
<div className={classes["right"]}>
|
||||||
|
<SubscriptionTicket />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</DefaultTemplate>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,83 @@
|
|||||||
|
@import "@Themes/constants.scss";
|
||||||
|
|
||||||
|
.root {
|
||||||
|
display: flex;
|
||||||
|
justify-content: baseline;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 64px;
|
||||||
|
max-width: 1000px;
|
||||||
|
margin: auto;
|
||||||
|
.top-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.forfeits-container {
|
||||||
|
display: flex;
|
||||||
|
gap: 32px;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
@media (max-width: $screen-s) {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.forfeit-block {
|
||||||
|
flex: 1;
|
||||||
|
padding: 32px;
|
||||||
|
border: 1px solid black;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 32px;
|
||||||
|
|
||||||
|
&[data-inactive="true"] {
|
||||||
|
border: 1px solid #e7e7e7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.forfeit-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
.left {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.active-plan {
|
||||||
|
@media (max-width: $screen-s) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.separator {
|
||||||
|
border-bottom: 1px solid black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.price-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 48px;
|
||||||
|
justify-content: flex-end;
|
||||||
|
justify-self: flex-end;
|
||||||
|
align-self: flex-end;
|
||||||
|
margin-bottom: 64px;
|
||||||
|
|
||||||
|
@media (max-width: $screen-s) {
|
||||||
|
flex-direction: column-reverse;
|
||||||
|
align-self: center;
|
||||||
|
justify-self: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,185 @@
|
|||||||
|
import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography";
|
||||||
|
import classes from "./classes.module.scss";
|
||||||
|
import DefaultTemplate from "@Front/Components/LayoutTemplates/DefaultTemplate";
|
||||||
|
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
|
||||||
|
import { useCallback, useState } from "react";
|
||||||
|
import Confirm from "@Front/Components/DesignSystem/Modal/Confirm";
|
||||||
|
import useOpenable from "@Front/Hooks/useOpenable";
|
||||||
|
import MessageBox from "@Front/Components/Elements/MessageBox";
|
||||||
|
|
||||||
|
export enum EForfeitType {
|
||||||
|
"standard",
|
||||||
|
"unlimited",
|
||||||
|
}
|
||||||
|
export default function SubscriptionFacturation() {
|
||||||
|
const [forfeitType, _setForfeitType] = useState(EForfeitType.standard);
|
||||||
|
const { close: closeCancelSubscription, isOpen: isCancelSubscriptionOpen, open: openCancelSubscription } = useOpenable();
|
||||||
|
const { close: closeConfirmation, isOpen: isConfirmationOpen, open: openConfirmation } = useOpenable();
|
||||||
|
|
||||||
|
const cancelSubscription = useCallback(() => {
|
||||||
|
closeCancelSubscription();
|
||||||
|
openConfirmation();
|
||||||
|
return;
|
||||||
|
}, [closeCancelSubscription, openConfirmation]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DefaultTemplate title="Nouvelle souscription" hasHeaderLinks={false}>
|
||||||
|
<div className={classes["root"]}>
|
||||||
|
<div className={classes["top-container"]}>
|
||||||
|
<div className={classes["top-container-title"]}>
|
||||||
|
<Typography typo={ITypo.H1} color={ITypoColor.BLACK}>
|
||||||
|
Facturation
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={classes["sub-title"]}>
|
||||||
|
<Typography typo={ITypo.P_16} color={ITypoColor.BLACK}>
|
||||||
|
Nos forfaits sont adaptés à la taille de votre office
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={classes["forfeits-container"]}>
|
||||||
|
<div className={classes["forfeit-block"]} data-inactive={forfeitType !== EForfeitType.standard}>
|
||||||
|
<div className={classes["forfeit-header"]}>
|
||||||
|
<div className={classes["left"]}>
|
||||||
|
<Typography typo={ITypo.P_SB_18} color={ITypoColor.BLACK}>
|
||||||
|
Forfait standard
|
||||||
|
</Typography>
|
||||||
|
<Typography typo={ITypo.P_16} color={ITypoColor.PINK_FLASH}>
|
||||||
|
Plan par utilisateur
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
{forfeitType === EForfeitType.standard && (
|
||||||
|
<div className={classes["active-plan"]}>
|
||||||
|
<Typography typo={ITypo.P_18} color={ITypoColor.GREEN_FLASH}>
|
||||||
|
Plan actif
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className={classes["separator"]} />
|
||||||
|
<div className={classes["price-container"]}>
|
||||||
|
<Typography typo={ITypo.H1} color={ITypoColor.BLACK}>
|
||||||
|
99€
|
||||||
|
<Typography typo={ITypo.H2} color={ITypoColor.BLACK}>
|
||||||
|
HT
|
||||||
|
</Typography>
|
||||||
|
/ mois
|
||||||
|
</Typography>
|
||||||
|
<Typography typo={ITypo.P_18} color={ITypoColor.BLACK}>
|
||||||
|
+ 6,99€ / collaborateur / mois
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={classes["button-container"]}>
|
||||||
|
{forfeitType !== EForfeitType.standard && (
|
||||||
|
<Button fullwidth variant={EButtonVariant.GHOST}>
|
||||||
|
Rétrograder mon abonnement
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
{forfeitType === EForfeitType.standard && (
|
||||||
|
<Button fullwidth variant={EButtonVariant.PRIMARY}>
|
||||||
|
Gérer mes collaborateurs
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={classes["forfeit-block"]} data-inactive={forfeitType === EForfeitType.standard}>
|
||||||
|
<div className={classes["forfeit-header"]}>
|
||||||
|
<div className={classes["left"]}>
|
||||||
|
<Typography typo={ITypo.P_SB_18} color={ITypoColor.BLACK}>
|
||||||
|
Forfait illimité
|
||||||
|
</Typography>
|
||||||
|
<Typography typo={ITypo.P_16} color={ITypoColor.PINK_FLASH}>
|
||||||
|
Plan par office
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
{forfeitType !== EForfeitType.standard && (
|
||||||
|
<div className={classes["active-plan"]}>
|
||||||
|
<Typography typo={ITypo.P_18} color={ITypoColor.GREEN_FLASH}>
|
||||||
|
Plan actif
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className={classes["separator"]} />
|
||||||
|
<div className={classes["price-container"]}>
|
||||||
|
<Typography typo={ITypo.H1} color={ITypoColor.BLACK}>
|
||||||
|
249€
|
||||||
|
<Typography typo={ITypo.H2} color={ITypoColor.BLACK}>
|
||||||
|
HT
|
||||||
|
</Typography>
|
||||||
|
/ mois
|
||||||
|
</Typography>
|
||||||
|
<Typography typo={ITypo.P_18} color={ITypoColor.BLACK}>
|
||||||
|
Sans limite de collaborateurs
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={classes["button-container"]}>
|
||||||
|
{forfeitType !== EForfeitType.standard && (
|
||||||
|
<Button fullwidth variant={EButtonVariant.PRIMARY} disabled>
|
||||||
|
Abonnement Max Activé
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
{forfeitType === EForfeitType.standard && (
|
||||||
|
<Button fullwidth variant={EButtonVariant.GHOST}>
|
||||||
|
Améliorer mon abonnement
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={classes["actions-container"]}>
|
||||||
|
<Button variant={EButtonVariant.LINE} onClick={openCancelSubscription}>
|
||||||
|
<Typography typo={ITypo.P_18} color={ITypoColor.RED_FLASH}>
|
||||||
|
Arrêter l'abonnement
|
||||||
|
</Typography>
|
||||||
|
</Button>
|
||||||
|
<Button>Gérer la facturation</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Confirm
|
||||||
|
isOpen={isCancelSubscriptionOpen}
|
||||||
|
onClose={closeCancelSubscription}
|
||||||
|
onAccept={cancelSubscription}
|
||||||
|
closeBtn
|
||||||
|
header={"Êtes-vous sûr de vouloir arrêter votre abonnement ?"}
|
||||||
|
confirmText={"Confirmer"}
|
||||||
|
cancelText={"Annuler"}>
|
||||||
|
<div className={classes["modal-content"]}>
|
||||||
|
<Typography typo={ITypo.P_16} className={classes["text"]}>
|
||||||
|
Avant de confirmer, veuillez prendre note des conséquences <br />
|
||||||
|
suivantes :
|
||||||
|
<br />
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
Arrêt des fonctionnalités : Vous n'aurez plus accès aux outils de traitement et de mise à jour en temps
|
||||||
|
réel.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Accès limité : Vous pourrez uniquement télécharger vos documents existants, sans possibilité de les éditer
|
||||||
|
ou de créer de nouveaux fichiers.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
Votre abonnement se terminera le XX/XX/XXXX. Assurez-vous de sauvegarder tout ce dont vous avez besoin avant cette
|
||||||
|
date.
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
</Confirm>
|
||||||
|
|
||||||
|
<Confirm
|
||||||
|
isOpen={isConfirmationOpen}
|
||||||
|
onClose={closeConfirmation}
|
||||||
|
onAccept={closeConfirmation}
|
||||||
|
closeBtn
|
||||||
|
header={"Abonnement résilié avec succès"}
|
||||||
|
confirmText={"Retour à la plateforme"}
|
||||||
|
showCancelButton={false}>
|
||||||
|
<div className={classes["modal-content"]}>
|
||||||
|
<MessageBox type="info">
|
||||||
|
Votre abonnement se terminera le XX/XX/XXXX. Assurez-vous de sauvegarder tout ce dont vous avez besoin avant cette
|
||||||
|
date.
|
||||||
|
</MessageBox>
|
||||||
|
</div>
|
||||||
|
</Confirm>
|
||||||
|
</DefaultTemplate>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,63 @@
|
|||||||
|
@import "@Themes/constants.scss";
|
||||||
|
|
||||||
|
.root {
|
||||||
|
display: flex;
|
||||||
|
justify-content: baseline;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 64px;
|
||||||
|
max-width: 1000px;
|
||||||
|
margin: auto;
|
||||||
|
.top-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.forfeits-container {
|
||||||
|
display: flex;
|
||||||
|
gap: 32px;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
@media (max-width: $screen-s) {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.forfeit-block {
|
||||||
|
flex: 1;
|
||||||
|
padding: 32px;
|
||||||
|
border: 1px solid black;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 32px;
|
||||||
|
|
||||||
|
.forfeit-header {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.separator {
|
||||||
|
border-bottom: 1px solid black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.price-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.infos-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
.line {
|
||||||
|
display: flex;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,108 @@
|
|||||||
|
import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography";
|
||||||
|
import classes from "./classes.module.scss";
|
||||||
|
import CheckIcon from "@Assets/Icons/check.svg";
|
||||||
|
import Image from "next/image";
|
||||||
|
import DefaultTemplate from "@Front/Components/LayoutTemplates/DefaultTemplate";
|
||||||
|
import Button from "@Front/Components/DesignSystem/Button";
|
||||||
|
import Link from "next/link";
|
||||||
|
|
||||||
|
export default function SubscriptionNew() {
|
||||||
|
return (
|
||||||
|
<DefaultTemplate title="Nouvelle souscription" hasHeaderLinks={false}>
|
||||||
|
<div className={classes["root"]}>
|
||||||
|
<div className={classes["top-container"]}>
|
||||||
|
<div className={classes["top-container-title"]}>
|
||||||
|
<Typography typo={ITypo.H1} color={ITypoColor.BLACK}>
|
||||||
|
Tarifs
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={classes["sub-title"]}>
|
||||||
|
<Typography typo={ITypo.P_16} color={ITypoColor.BLACK}>
|
||||||
|
Nos forfaits sont adaptés à la taille de votre office
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={classes["forfeits-container"]}>
|
||||||
|
<div className={classes["forfeit-block"]}>
|
||||||
|
<div className={classes["forfeit-header"]}>
|
||||||
|
<Typography typo={ITypo.P_SB_18} color={ITypoColor.BLACK}>
|
||||||
|
Forfait standard
|
||||||
|
</Typography>
|
||||||
|
<Typography typo={ITypo.P_16} color={ITypoColor.PINK_FLASH}>
|
||||||
|
Plan par utilisateur
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={classes["separator"]} />
|
||||||
|
<div className={classes["price-container"]}>
|
||||||
|
<Typography typo={ITypo.H1} color={ITypoColor.BLACK}>
|
||||||
|
99€
|
||||||
|
<Typography typo={ITypo.H2} color={ITypoColor.BLACK}>
|
||||||
|
HT
|
||||||
|
</Typography>
|
||||||
|
/ mois
|
||||||
|
</Typography>
|
||||||
|
<Typography typo={ITypo.P_18} color={ITypoColor.BLACK}>
|
||||||
|
+ 6,99€ / collaborateur / mois
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={classes["button-container"]}>
|
||||||
|
<Link href={"/subscription/subscribe/standard"}>
|
||||||
|
<Button fullwidth>S'abonner</Button>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={classes["forfeit-block"]}>
|
||||||
|
<div className={classes["forfeit-header"]}>
|
||||||
|
<Typography typo={ITypo.P_SB_18} color={ITypoColor.BLACK}>
|
||||||
|
Forfait illimité
|
||||||
|
</Typography>
|
||||||
|
<Typography typo={ITypo.P_16} color={ITypoColor.PINK_FLASH}>
|
||||||
|
Plan par office
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={classes["separator"]} />
|
||||||
|
<div className={classes["price-container"]}>
|
||||||
|
<Typography typo={ITypo.H1} color={ITypoColor.BLACK}>
|
||||||
|
249€
|
||||||
|
<Typography typo={ITypo.H2} color={ITypoColor.BLACK}>
|
||||||
|
HT
|
||||||
|
</Typography>
|
||||||
|
/ mois
|
||||||
|
</Typography>
|
||||||
|
<Typography typo={ITypo.P_18} color={ITypoColor.BLACK}>
|
||||||
|
Sans limite de collaborateurs
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={classes["button-container"]}>
|
||||||
|
<Link href={"/subscription/subscribe/illimity"}>
|
||||||
|
<Button fullwidth>S'abonner</Button>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={classes["infos-container"]}>
|
||||||
|
<div className={classes["line"]}>
|
||||||
|
<Image src={CheckIcon} alt="Check icon" />
|
||||||
|
<Typography typo={ITypo.P_16} color={ITypoColor.BLACK}>
|
||||||
|
Accompagnement facilité : profitez d'un onboarding individualisé, où nous vous guidons pour une prise en main
|
||||||
|
optimale de l'application
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={classes["line"]}>
|
||||||
|
<Image src={CheckIcon} alt="Check icon" />
|
||||||
|
<Typography typo={ITypo.P_16} color={ITypoColor.BLACK}>
|
||||||
|
Support technique : notre équipe support est disponible pour vous assister en cas d’incident
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={classes["line"]}>
|
||||||
|
<Image src={CheckIcon} alt="Check icon" />
|
||||||
|
<Typography typo={ITypo.P_16} color={ITypoColor.BLACK}>
|
||||||
|
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
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</DefaultTemplate>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
.root {
|
||||||
|
display: flex;
|
||||||
|
gap: 104px;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.left {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 32px;
|
||||||
|
width: 548px;
|
||||||
|
}
|
||||||
|
.separator {
|
||||||
|
width: 100%;
|
||||||
|
height: 2px;
|
||||||
|
background: var(--grey-medium);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
import DefaultTemplate from "@Front/Components/LayoutTemplates/DefaultTemplate";
|
||||||
|
import classes from "./classes.module.scss";
|
||||||
|
import SubscriptionTicket from "../SubscriptionTicket";
|
||||||
|
import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography";
|
||||||
|
import MessageBox from "@Front/Components/Elements/MessageBox";
|
||||||
|
import SubscriptionClientInfos from "../SubscriptionClientInfos";
|
||||||
|
import Button from "@Front/Components/DesignSystem/Button";
|
||||||
|
|
||||||
|
export default function SubscriptionSuccess() {
|
||||||
|
return (
|
||||||
|
<DefaultTemplate title="Abonnement réussi" hasHeaderLinks={false}>
|
||||||
|
<div className={classes["root"]}>
|
||||||
|
<div className={classes["left"]}>
|
||||||
|
<div className={classes["title"]}>
|
||||||
|
<Typography typo={ITypo.H1} color={ITypoColor.BLACK}>
|
||||||
|
Abonnement réussi !
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={classes["alert"]}>
|
||||||
|
<MessageBox type={"success"}>
|
||||||
|
Votre transaction a été effectuée avec succès !
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
Votre abonnement a été pris en compte et est désormais actif.
|
||||||
|
</MessageBox>
|
||||||
|
</div>
|
||||||
|
<div className={classes["separator"]} />
|
||||||
|
<div className={classes["client-infos"]}>
|
||||||
|
<SubscriptionClientInfos />
|
||||||
|
</div>
|
||||||
|
<div className={classes["separator"]} />
|
||||||
|
<Button>Inviter vos collaborateurs</Button>
|
||||||
|
</div>
|
||||||
|
<div className={classes["right"]}>
|
||||||
|
<SubscriptionTicket />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</DefaultTemplate>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
.root {
|
||||||
|
width: 372px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 40px;
|
||||||
|
|
||||||
|
box-shadow: 0px 8px 10px 0px #00000012;
|
||||||
|
padding: 24px;
|
||||||
|
border-radius: 16px;
|
||||||
|
.top-category {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
.line {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.separator {
|
||||||
|
width: 100%;
|
||||||
|
height: 2px;
|
||||||
|
background: var(--grey-medium);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,84 @@
|
|||||||
|
import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography";
|
||||||
|
import classes from "./classes.module.scss";
|
||||||
|
|
||||||
|
type IProps = {};
|
||||||
|
export default function SubscriptionTicket(props: IProps) {
|
||||||
|
return (
|
||||||
|
<div className={classes["root"]}>
|
||||||
|
<div className={classes["top-category"]}>
|
||||||
|
<Typography typo={ITypo.P_SB_18} color={ITypoColor.BLACK}>
|
||||||
|
Récapitulatif
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={classes["separator"]} />
|
||||||
|
|
||||||
|
<div className={classes["top-category"]}>
|
||||||
|
<Typography typo={ITypo.P_18} color={ITypoColor.BLACK}>
|
||||||
|
Forfait standard
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={classes["separator"]} />
|
||||||
|
<div className={classes["category"]}>
|
||||||
|
<div className={classes["line"]}>
|
||||||
|
<Typography typo={ITypo.P_18} color={ITypoColor.BLACK}>
|
||||||
|
Plan individuel
|
||||||
|
</Typography>
|
||||||
|
<Typography typo={ITypo.P_SB_18} color={ITypoColor.BLACK}>
|
||||||
|
99 €
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={classes["line"]}>
|
||||||
|
<Typography typo={ITypo.P_18} color={ITypoColor.BLACK}>
|
||||||
|
2 collaborateurs
|
||||||
|
</Typography>
|
||||||
|
<Typography typo={ITypo.P_SB_18} color={ITypoColor.BLACK}>
|
||||||
|
13,98 €
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={classes["sub-line"]}>
|
||||||
|
<Typography typo={ITypo.CAPTION_14_SB} color={ITypoColor.BLACK}>
|
||||||
|
6,99 € x 2
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={classes["separator"]} />
|
||||||
|
<div className={classes["category"]}>
|
||||||
|
<div className={classes["line"]}>
|
||||||
|
<Typography typo={ITypo.P_18} color={ITypoColor.BLACK}>
|
||||||
|
Sous-total
|
||||||
|
</Typography>
|
||||||
|
<Typography typo={ITypo.P_SB_18} color={ITypoColor.BLACK}>
|
||||||
|
112,98 €
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={classes["line"]}>
|
||||||
|
<Typography typo={ITypo.P_18} color={ITypoColor.BLACK}>
|
||||||
|
FR TVA
|
||||||
|
</Typography>
|
||||||
|
<Typography typo={ITypo.P_SB_18} color={ITypoColor.BLACK}>
|
||||||
|
14 €
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={classes["line"]}>
|
||||||
|
<Typography typo={ITypo.P_18} color={ITypoColor.BLACK}>
|
||||||
|
Taxes
|
||||||
|
</Typography>
|
||||||
|
<Typography typo={ITypo.P_SB_18} color={ITypoColor.BLACK}>
|
||||||
|
14 €
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={classes["separator"]} />
|
||||||
|
<div className={classes["category"]}>
|
||||||
|
<div className={classes["line"]}>
|
||||||
|
<Typography typo={ITypo.P_18} color={ITypoColor.BLACK}>
|
||||||
|
Total
|
||||||
|
</Typography>
|
||||||
|
<Typography typo={ITypo.P_SB_18} color={ITypoColor.BLACK}>
|
||||||
|
112,98 €
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
26
src/front/Hooks/useOpenable.ts
Normal file
26
src/front/Hooks/useOpenable.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import { useCallback, useState } from "react";
|
||||||
|
|
||||||
|
function useOpenable() {
|
||||||
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
|
||||||
|
const open = useCallback(() => {
|
||||||
|
setIsOpen(true);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const close = useCallback(() => {
|
||||||
|
setIsOpen(false);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const toggle = useCallback(() => {
|
||||||
|
setIsOpen((prev) => !prev);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return {
|
||||||
|
isOpen,
|
||||||
|
open,
|
||||||
|
close,
|
||||||
|
toggle,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useOpenable;
|
@ -4,6 +4,8 @@ body.body {
|
|||||||
// --black: #000000;
|
// --black: #000000;
|
||||||
|
|
||||||
--green-flash: #{green-flash};
|
--green-flash: #{green-flash};
|
||||||
|
--black: #{$black};
|
||||||
|
|
||||||
// --blue-flash: #005176;
|
// --blue-flash: #005176;
|
||||||
// --turquoise-flash: #3fa79e;
|
// --turquoise-flash: #3fa79e;
|
||||||
// --purple-flash: #320756;
|
// --purple-flash: #320756;
|
||||||
|
@ -31,5 +31,6 @@
|
|||||||
--grey-medium: #{$grey-medium};
|
--grey-medium: #{$grey-medium};
|
||||||
--grey-soft: #{$grey-soft};
|
--grey-soft: #{$grey-soft};
|
||||||
|
|
||||||
|
--black: #{$black};
|
||||||
--white: #{$white};
|
--white: #{$white};
|
||||||
}
|
}
|
||||||
|
5
src/pages/subscription/error/index.tsx
Normal file
5
src/pages/subscription/error/index.tsx
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import SubscriptionError from "@Front/Components/Layouts/Subscription/SubscriptionError";
|
||||||
|
|
||||||
|
export default function Route() {
|
||||||
|
return <SubscriptionError />;
|
||||||
|
}
|
5
src/pages/subscription/facturation/index.tsx
Normal file
5
src/pages/subscription/facturation/index.tsx
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import SubscriptionFacturation from "@Front/Components/Layouts/Subscription/SubscriptionFacturation";
|
||||||
|
|
||||||
|
export default function Route() {
|
||||||
|
return <SubscriptionFacturation />;
|
||||||
|
}
|
5
src/pages/subscription/new/index.tsx
Normal file
5
src/pages/subscription/new/index.tsx
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import SubscriptionNew from "@Front/Components/Layouts/Subscription/SubscriptionNew";
|
||||||
|
|
||||||
|
export default function Route() {
|
||||||
|
return <SubscriptionNew />;
|
||||||
|
}
|
5
src/pages/subscription/subscribe/illimity/index.tsx
Normal file
5
src/pages/subscription/subscribe/illimity/index.tsx
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import SubscribeIllimity from "@Front/Components/Layouts/Subscription/Subscribe/SubscribeIllimity";
|
||||||
|
|
||||||
|
export default function Route() {
|
||||||
|
return <SubscribeIllimity />;
|
||||||
|
}
|
5
src/pages/subscription/subscribe/standard/index.tsx
Normal file
5
src/pages/subscription/subscribe/standard/index.tsx
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import SubscribeStandard from "@Front/Components/Layouts/Subscription/Subscribe/SubscribeStandard";
|
||||||
|
|
||||||
|
export default function Route() {
|
||||||
|
return <SubscribeStandard />;
|
||||||
|
}
|
5
src/pages/subscription/success/index.tsx
Normal file
5
src/pages/subscription/success/index.tsx
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import SubscriptionSuccess from "@Front/Components/Layouts/Subscription/SubscriptionSuccess";
|
||||||
|
|
||||||
|
export default function Route() {
|
||||||
|
return <SubscriptionSuccess />;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user