customer-dashboard/src/Pages/Authentication/SignUp.js

372 lines
9.8 KiB
JavaScript

import {
Affix,
Button,
Card,
Col,
Divider,
Flex,
Form,
Row,
Segmented,
Skeleton,
Typography,
notification,
} from "antd";
import { useEffect, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import { useNavigate } from "react-router-dom";
import {
AppStyle,
Constants,
EncodeStringToBase64,
myFetch,
showInputsInvalidNotification,
showUnkownErrorNotification,
} from "../../utils";
import {
MyCompanyAddressFormInput,
MyCompanyNameFormInput,
MyEmailFormInput,
MyPasswordFormInput,
MyUsernameFormInput,
} from "../../Components/MyFormInputs";
import { MyRecaptcha, PrivacyPolicyCheckbox } from ".";
import MyAppLogo from "../../Components/MyAppLogo";
import { CheckOutlined } from "@ant-design/icons";
import { RequestState } from "../../Components/MyRequestStateItem";
/*
const SignUpStep = {
SIGN_UP: 1,
PENDING_EMAIL_VERIFICATION: 2,
};
*/
export default function SignUp({ paymentPlan }) {
const [notificationApi, notificationContextHolder] =
notification.useNotification();
const { t, i18n } = useTranslation();
const navigate = useNavigate();
const [form] = Form.useForm();
//const [step, setStep] = useState(SignUpStep.SIGN_UP);
/*
if (step === SignUpStep.PENDING_EMAIL_VERIFICATION) {
return <PendingEmailVerification />;
} */
return (
<>
{notificationContextHolder}
<Flex justify="center" style={{ marginTop: 12 }}>
<MyAppLogo height={100} />
</Flex>
<Row>
<Col
xs={24}
xl={{
span: 10,
offset: 2,
}}
style={{ paddingLeft: 8, paddingRight: 8 }}
>
<ChoosenProduct t={t} paymentPlan={paymentPlan} />
<AccountDetails
notificationApi={notificationApi}
t={t}
i18n={i18n}
navigate={navigate}
form={form}
/>
</Col>
<Col
xs={24}
xl={{
span: 10,
}}
style={{ paddingLeft: 8, paddingRight: 8 }}
>
<CostSummary
notificationApi={notificationApi}
paymentPlan={paymentPlan}
form={form}
/>
</Col>
</Row>
</>
);
}
function AccountDetails({ t, form }) {
return (
<Card
title={t("authentication.signUp.accountDetails.title")}
style={{ marginBottom: 16 }}
>
<Form
form={form}
layout="vertical"
requiredMark={false}
initialValues={{
rememberMe: false,
}}
>
<MyCompanyNameFormInput />
<MyCompanyAddressFormInput />
<MyUsernameFormInput
propsFormItem={{ tooltip: t("common.usernameInfo") }}
/>
<MyEmailFormInput hasFeedback={true} />
<MyPasswordFormInput />
</Form>
</Card>
);
}
export function ChoosenProduct({ t, paymentPlan, extra }) {
return (
<Card
title={t("authentication.signUp.choosenProduct.title")}
style={{ marginBottom: 16 }}
extra={extra}
>
<Typography.Title level={2}>
{Constants.APP_NAME} - {Constants.PAYMENT_PLAN[paymentPlan].name}
</Typography.Title>
<Divider />
<Row>
{[
...Array(
t(
`authentication.signUp.choosenProduct.products.${paymentPlan}.featuresCount`
)
),
].map((_, index) => {
return (
<Col span={24} key={index}>
<Flex gap={12} align="center">
<CheckOutlined
key={index}
style={{ color: AppStyle.colors.primary, fontSize: 24 }}
/>
<Typography.Text style={{ fontSize: 20 }}>
{t(
`authentication.signUp.choosenProduct.products.${paymentPlan}.features.${index}`
)}
</Typography.Text>
</Flex>
</Col>
);
})}
</Row>
</Card>
);
}
function CostSummary({ notificationApi, paymentPlan, form }) {
const { t, i18n } = useTranslation();
const [isRequesting, setIsRequesting] = useState(RequestState.INIT);
const recaptchaRef = useRef(null);
const recaptchaValueRef = useRef(null);
const [prices, setPrices] = useState(null);
const [segmentedValue, setSegmentedValue] = useState(1);
const showErrorNotification = (errStatus) => {
if (errStatus === 400) {
notificationApi["error"]({
message: t("authentication.signUp.request.400.title"),
description: t("authentication.signUp.request.400.description"),
});
}
};
const handleSubmit = () => {
form
.validateFields()
.then((values) => {
setIsRequesting(RequestState.REQUESTING);
myFetch({
url: `/user/auth/signup`,
method: "POST",
body: {
companyName: values.companyName,
email: values.email.toLocaleLowerCase(),
password: EncodeStringToBase64(values.password),
username: values.username,
language: i18n.language,
rememberMe: true,
recaptcha: recaptchaValueRef.current,
paymentPlan: paymentPlan,
paymentInterval: segmentedValue,
companyAddress: values.companyAddress,
},
notificationApi: notificationApi,
t: t,
})
.then((data) => {
setIsRequesting(RequestState.NOTHING);
localStorage.setItem("tmp_session", data.XAuthorization);
window.location.href = data.redirectUrl;
})
.catch((errStatus) => {
recaptchaRef.current.reset();
showErrorNotification(errStatus);
setIsRequesting(false);
});
})
.catch(() => {
recaptchaRef.current.reset();
showInputsInvalidNotification(notificationApi, t);
setIsRequesting(false);
});
};
useEffect(() => {
myFetch({
url: `/payment/prices/${paymentPlan}`,
method: "GET",
})
.then((data) => {
setIsRequesting(RequestState.NOTHING);
setPrices(data.prices);
})
.catch(() => showUnkownErrorNotification(notificationApi, t));
}, []);
const formatPrice = (price) => {
return (price / 100).toLocaleString("de-DE", {
style: "currency",
currency: "EUR",
});
};
const price = prices ? prices[segmentedValue].unit_amount : 0;
const totalNet = formatPrice(price);
const vat = formatPrice((price / 100) * 19);
const totalAmount = formatPrice(price + (price / 100) * 19);
return (
<Affix offsetTop={16}>
<Card title={t("authentication.signUp.costSummary.title")}>
<Form form={form}>
<Segmented
block
options={[
{
label: t("authentication.signUp.costSummary.options.yearly"),
value: 1,
},
{
label: t("authentication.signUp.costSummary.options.monthly"),
value: 0,
},
]}
value={segmentedValue}
onChange={(v) => setSegmentedValue(v)}
/>
<div
style={{
backgroundColor: "#393a56",
borderRadius: 8,
fontSize: 16,
color: "#fff",
textAlign: "center",
fontWeight: "bold",
padding: 8,
marginTop: 12,
marginBottom: 12,
}}
>
{Constants.APP_NAME} - {Constants.PAYMENT_PLAN[paymentPlan].name}
</div>
<Flex justify="space-between">
<Typography.Text style={{ fontSize: 16 }}>
{t("authentication.signUp.costSummary.totalNet")}
</Typography.Text>
{isRequesting === RequestState.INIT ? (
<Skeleton.Button active size="small" />
) : (
<Typography.Text style={{ fontSize: 16 }}>
{totalNet}
</Typography.Text>
)}
</Flex>
<Divider style={{ margin: 8 }} />
<Flex justify="space-between">
<Typography.Text style={{ fontSize: 16 }}>
{t("authentication.signUp.costSummary.vat")}
</Typography.Text>
{isRequesting === RequestState.INIT ? (
<Skeleton.Button active size="small" />
) : (
<Typography.Text style={{ fontSize: 16 }}>{vat}</Typography.Text>
)}
</Flex>
<Divider style={{ margin: 8 }} />
<Flex
justify="space-between"
align="center"
style={{ marginBottom: 20 }}
>
<Typography.Text style={{ fontSize: 16, fontWeight: "600" }}>
{t("authentication.signUp.costSummary.totalAmount")}
</Typography.Text>
{isRequesting === RequestState.INIT ? (
<Skeleton.Button active size="large" />
) : (
<Typography.Text
style={{
fontSize: 16,
backgroundColor: "#4d61d6",
padding: 4,
paddingLeft: 20,
paddingRight: 20,
borderRadius: 20,
color: "#fff",
fontWeight: "bold",
}}
>
{totalAmount}
</Typography.Text>
)}
</Flex>
<PrivacyPolicyCheckbox />
<MyRecaptcha
recaptchaRef={recaptchaRef}
recaptchaValueRef={recaptchaValueRef}
/>
<Button
type="primary"
size="large"
block
onClick={handleSubmit}
loading={isRequesting === RequestState.REQUESTING}
>
{t("authentication.signUp.button")}
</Button>
</Form>
</Card>
</Affix>
);
}