372 lines
9.8 KiB
JavaScript
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>
|
|
);
|
|
}
|