verification
parent
e21745125d
commit
c2147f45f9
|
@ -378,5 +378,22 @@
|
|||
"improveMinLengthRequired": "Bitte geben Sie mindestens {{minLength}} Zeichen ein"
|
||||
}
|
||||
}
|
||||
},
|
||||
"verification": {
|
||||
"error": {
|
||||
"title": "Verifizierung fehlgeschlagen",
|
||||
"description": "Keine ausstehende Überprüfung gefunden"
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"requesting": {
|
||||
"title": "E-Mail-Verifizierung ausstehend"
|
||||
},
|
||||
"Erfolg": {
|
||||
"title": "E-Mail-Überprüfung erfolgreich",
|
||||
"button": "Jetzt anmelden"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -381,5 +381,22 @@
|
|||
"improveMinLengthRequired": "Please enter at least {{minLength}} characters"
|
||||
}
|
||||
}
|
||||
},
|
||||
"verification": {
|
||||
"error": {
|
||||
"title": "Verification failed",
|
||||
"description": "No pending verification found."
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"requesting": {
|
||||
"title": "Email verification pending"
|
||||
},
|
||||
"success": {
|
||||
"title": "Email verification successful",
|
||||
"button": "Login now"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
16
src/App.js
16
src/App.js
|
@ -19,7 +19,10 @@ import StoresProvider from "./Contexts/StoresContext";
|
|||
import { clarity } from "react-microsoft-clarity";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import MyAppLogo from "./Components/MyAppLogo";
|
||||
import { AuthenticationRoutes } from "./Components/AppRoutes";
|
||||
import {
|
||||
AuthenticationRoutes,
|
||||
VerificationRoutes,
|
||||
} from "./Components/AppRoutes";
|
||||
|
||||
export function Loading() {
|
||||
const { t } = useTranslation();
|
||||
|
@ -65,7 +68,16 @@ export function Loading() {
|
|||
);
|
||||
}
|
||||
|
||||
export default function App() {
|
||||
export default function PreApp() {
|
||||
// if the users comes from a verification email (e.g. when sign up or delete account)
|
||||
if (window.location.pathname.startsWith("/verify/")) {
|
||||
return <VerificationRoutes />;
|
||||
}
|
||||
|
||||
return <App />;
|
||||
}
|
||||
|
||||
export function App() {
|
||||
const { _, i18n } = useTranslation();
|
||||
|
||||
const { userSession, setUserSession } = UseUserSession();
|
||||
|
|
|
@ -3,6 +3,7 @@ import { Constants, isDevelopmentEnv } from "../../utils";
|
|||
import { lazy } from "react";
|
||||
import { MySupsenseFallback } from "../MySupsenseFallback";
|
||||
import { AuthenticationMethod } from "../../Pages/Authentication";
|
||||
import Verification from "../../Pages/Verification";
|
||||
|
||||
// Lazy-loaded components
|
||||
const Authentication = lazy(() => import("../../Pages/Authentication"));
|
||||
|
@ -48,6 +49,30 @@ export function AuthenticationRoutes() {
|
|||
);
|
||||
}
|
||||
|
||||
export function VerificationRoutes() {
|
||||
return (
|
||||
<Routes>
|
||||
<Route
|
||||
path={`${Constants.ROUTE_PATHS.VERIFY}/:state/:emailVerificationId`}
|
||||
element={
|
||||
<MySupsenseFallback>
|
||||
<Verification />
|
||||
</MySupsenseFallback>
|
||||
}
|
||||
/>
|
||||
|
||||
<Route
|
||||
path="*"
|
||||
element={
|
||||
<MySupsenseFallback>
|
||||
<Verification />
|
||||
</MySupsenseFallback>
|
||||
}
|
||||
/>
|
||||
</Routes>
|
||||
);
|
||||
}
|
||||
|
||||
export function AppRoutes({ setUserSession }) {
|
||||
return (
|
||||
<Routes>
|
||||
|
|
|
@ -9,6 +9,7 @@ export default function MyModal({
|
|||
onCancel,
|
||||
footer = <MyModalOnlyCloseButtonFooter onCancel={onCancel} />,
|
||||
title,
|
||||
closable = true,
|
||||
}) {
|
||||
const screenBreakpoint = useBreakpoint();
|
||||
|
||||
|
@ -21,6 +22,7 @@ export default function MyModal({
|
|||
footer={footer}
|
||||
centered={screenBreakpoint.xs}
|
||||
title={title}
|
||||
closable={closable}
|
||||
>
|
||||
{children}
|
||||
</Modal>
|
||||
|
|
|
@ -126,6 +126,7 @@ function Login({ notificationApi }) {
|
|||
|
||||
const [step, setStep] = useState(LoginStep.ACCOUNT_NAME);
|
||||
const [isRequesting, setIsRequesting] = useState(false);
|
||||
const recaptchaRef = useRef(null);
|
||||
const recaptchaValueRef = useRef(null);
|
||||
|
||||
const [form] = Form.useForm();
|
||||
|
@ -253,7 +254,7 @@ function Login({ notificationApi }) {
|
|||
]}
|
||||
>
|
||||
<ReCAPTCHA
|
||||
ref={recaptchaValueRef}
|
||||
ref={recaptchaRef}
|
||||
sitekey={process.env.REACT_APP_RECAPTCHA_SITE_KEY}
|
||||
onChange={(value) => (recaptchaValueRef.current = value)}
|
||||
/>
|
||||
|
@ -346,7 +347,7 @@ function Login({ notificationApi }) {
|
|||
.catch((errStatus) => {
|
||||
showErrorNotification(errStatus);
|
||||
setIsRequesting(false);
|
||||
recaptchaValueRef.current.reset();
|
||||
recaptchaRef.current.reset();
|
||||
});
|
||||
})
|
||||
.catch(() => showInputsInvalidNotification(notificationApi, t));
|
||||
|
|
|
@ -3,7 +3,24 @@ import { useTranslation } from "react-i18next";
|
|||
import { Link } from "react-router-dom";
|
||||
import { Constants } from "../../utils";
|
||||
|
||||
export default function PageNotFound() {
|
||||
export function ButtonBackHome({ useHref }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={() => {
|
||||
if (useHref) {
|
||||
window.location.href = Constants.DASHBOARD_ADDRESS;
|
||||
}
|
||||
}}
|
||||
>
|
||||
{t("pageNotFound.buttonBackHome")}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
export default function PageNotFound({ useHref = false }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
|
@ -12,9 +29,13 @@ export default function PageNotFound() {
|
|||
title={t("pageNotFound.title")}
|
||||
subTitle={t("pageNotFound.subTitle")}
|
||||
extra={
|
||||
<Link to={Constants.ROUTE_PATHS.OVERVIEW}>
|
||||
<Button type="primary">{t("pageNotFound.buttonBackHome")}</Button>
|
||||
</Link>
|
||||
useHref ? (
|
||||
<ButtonBackHome useHref={useHref} />
|
||||
) : (
|
||||
<Link to={Constants.DASHBOARD_ADDRESS}>
|
||||
{<ButtonBackHome useHref={useHref} />}
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
import { useParams } from "react-router-dom";
|
||||
import MyModal from "../../Components/MyModal";
|
||||
import { Button, Flex, Result, Spin, notification } from "antd";
|
||||
import { useEffect, useState } from "react";
|
||||
import MyAppLogo from "../../Components/MyAppLogo";
|
||||
import PageNotFound, { ButtonBackHome } from "../PageNotFound";
|
||||
import { Constants, myFetch } from "../../utils";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { RequestState } from "../../Components/MyRequestStateItem";
|
||||
|
||||
export default function Verification() {
|
||||
const { state, emailVerificationId } = useParams();
|
||||
const { t } = useTranslation();
|
||||
const [notificationApi, notificationContextHolder] =
|
||||
notification.useNotification();
|
||||
|
||||
const [isRequesting, setIsRequesting] = useState(RequestState.REQUESTING);
|
||||
|
||||
const content = [
|
||||
{
|
||||
requesting: {
|
||||
title: t("verification.content.0.requesting.title"),
|
||||
},
|
||||
sucess: {
|
||||
title: t("verification.content.0.success.title"),
|
||||
extra: (
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={() => {
|
||||
window.location.href = `${Constants.DASHBOARD_ADDRESS}${Constants.ROUTE_PATHS.AUTHENTICATION.LOGIN}`;
|
||||
}}
|
||||
>
|
||||
{t("verification.content.0.success.button")}
|
||||
</Button>
|
||||
),
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const parsedState = isNaN(state) ? 0 : parseInt(state);
|
||||
|
||||
let elementContent;
|
||||
|
||||
if (
|
||||
state === undefined ||
|
||||
emailVerificationId === undefined ||
|
||||
state > content.length - 1
|
||||
) {
|
||||
elementContent = <PageNotFound useHref />;
|
||||
} else if (isRequesting === RequestState.REQUESTING) {
|
||||
elementContent = (
|
||||
<Result
|
||||
title={content[parsedState].requesting.title}
|
||||
extra={<Spin size="large" />}
|
||||
/>
|
||||
);
|
||||
} else if (isRequesting === RequestState.SUCCESS) {
|
||||
elementContent = (
|
||||
<Result
|
||||
status="success"
|
||||
title={content[parsedState].sucess.title}
|
||||
extra={content[parsedState].sucess.extra}
|
||||
/>
|
||||
);
|
||||
} else if (isRequesting === RequestState.FAILED) {
|
||||
elementContent = (
|
||||
<Result
|
||||
status="error"
|
||||
title={t("verification.error.title")}
|
||||
subTitle={t("verification.error.description")}
|
||||
extra={<ButtonBackHome useHref />}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
elementContent = <PageNotFound useHref />;
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (emailVerificationId === undefined || state === undefined) {
|
||||
setIsRequesting(false);
|
||||
return;
|
||||
}
|
||||
|
||||
myFetch({
|
||||
url: `/user/verify/${state}/${emailVerificationId}`,
|
||||
notificationApi: notificationApi,
|
||||
t: t,
|
||||
})
|
||||
.then(() => setIsRequesting(RequestState.SUCCESS))
|
||||
.catch(() => setIsRequesting(RequestState.FAILED));
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<MyModal isOpen={true} footer={null} closable={false}>
|
||||
{notificationContextHolder}
|
||||
|
||||
<Flex justify="center">
|
||||
<MyAppLogo height={100} />
|
||||
</Flex>
|
||||
|
||||
{elementContent}
|
||||
</MyModal>
|
||||
);
|
||||
}
|
|
@ -7,22 +7,26 @@ import { v4 as uuidv4 } from "uuid";
|
|||
*/
|
||||
//const wssProtocol = window.location.protocol === "https:" ? "wss://" : "ws://";
|
||||
|
||||
let dashboardAddress = "";
|
||||
let apiAddress = "";
|
||||
// let staticContentAddress = "";
|
||||
// let wsAddress = "";
|
||||
|
||||
if (window.location.hostname === "localhost" && window.location.port === "") {
|
||||
// for docker container testing on localhost
|
||||
dashboardAddress = "http://localhost/";
|
||||
apiAddress = "http://localhost/api/v1";
|
||||
// staticContentAddress = "http://localhost/api/";
|
||||
// wsAddress = "ws://localhost/ws";
|
||||
} else if (window.location.hostname === "localhost") {
|
||||
// programming on localhost
|
||||
dashboardAddress = `http://localhost:${window.location.port}/`;
|
||||
apiAddress = "http://localhost:50128/api/v1";
|
||||
// staticContentAddress = "http://localhost:50050/";
|
||||
// wsAddress = "ws://localhost:50050/ws";
|
||||
} else {
|
||||
// production
|
||||
dashboardAddress = `${window.location.protocol}//${window.location.hostname}/`;
|
||||
apiAddress = `${window.location.protocol}//${window.location.hostname}/api/v1`;
|
||||
//staticContentAddress = `${window.location.protocol}//${window.location.hostname}/api/`;
|
||||
// wsAddress = `${wssProtocol}${window.location.hostname}/ws`;
|
||||
|
@ -30,6 +34,7 @@ if (window.location.hostname === "localhost" && window.location.port === "") {
|
|||
|
||||
export const Constants = {
|
||||
TEXT_EMPTY_PLACEHOLDER: "-/-",
|
||||
DASHBOARD_ADDRESS: dashboardAddress,
|
||||
API_ADDRESS: apiAddress,
|
||||
//STATIC_CONTENT_ADDRESS: staticContentAddress,
|
||||
// WS_ADDRESS: wsAddress,
|
||||
|
@ -42,6 +47,7 @@ export const Constants = {
|
|||
LOGIN: "/login",
|
||||
SIGN_UP: "/signup",
|
||||
},
|
||||
VERIFY: "/verify",
|
||||
OVERVIEW: "/",
|
||||
STORE: {
|
||||
// schema: /store/:storeId/:subPage
|
||||
|
|
Loading…
Reference in New Issue