diff --git a/src/front/Components/DesignSystem/Form/TextField/index.tsx b/src/front/Components/DesignSystem/Form/TextField/index.tsx index a10c0a40..bb83fbf2 100644 --- a/src/front/Components/DesignSystem/Form/TextField/index.tsx +++ b/src/front/Components/DesignSystem/Form/TextField/index.tsx @@ -9,6 +9,7 @@ import Image from "next/image"; export type IProps = IBaseFieldProps & { canCopy?: boolean; + password?: boolean; }; export default class TextField extends BaseField { @@ -32,6 +33,7 @@ export default class TextField extends BaseField { onBlur={this.onBlur} name={this.props.name} disabled={this.props.disabled} + type={this.props.password ? "password" : "text"} />
{this.props.placeholder} {!this.props.required && " (Facultatif)"} diff --git a/src/front/Components/Layouts/Protect/classes.module.scss b/src/front/Components/Layouts/Protect/classes.module.scss new file mode 100644 index 00000000..4291a2ac --- /dev/null +++ b/src/front/Components/Layouts/Protect/classes.module.scss @@ -0,0 +1,29 @@ +@import "@Themes/constants.scss"; + +.root { + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + height: 100%; + max-width: 530px; + margin: auto; + + .title { + margin: 32px 0; + text-align: center; + + @media (max-width: $screen-s) { + font-family: 48px; + } + } + + .forget-password { + margin-top: 32px; + margin-bottom: 8px; + } + + .form { + display: flex; + } +} diff --git a/src/front/Components/Layouts/Protect/index.tsx b/src/front/Components/Layouts/Protect/index.tsx new file mode 100644 index 00000000..695910ad --- /dev/null +++ b/src/front/Components/Layouts/Protect/index.tsx @@ -0,0 +1,57 @@ +import Module from "@Front/Config/Module"; +import { useRouter } from "next/router"; +import { useState } from "react"; +import Image from "next/image"; +import classes from "./classes.module.scss"; +import LandingImage from "./landing-connect.jpeg"; +import DefaultDoubleSidePage from "@Front/Components/LayoutTemplates/DefaultDoubleSidePage"; +import Typography, { ITypo } from "@Front/Components/DesignSystem/Typography"; +import CoffreIcon from "@Assets/Icons/coffre.svg"; +import TextField from "@Front/Components/DesignSystem/Form/TextField"; +import Button from "@Front/Components/DesignSystem/Button"; + +export default function Protect() { + const [password, setPassword] = useState(""); + const router = useRouter(); + const setPasswordFromInput = (event: React.ChangeEvent) => { + setPassword(event.target.value); + }; + + const submitAuth = (e: React.FormEvent) => { + e.preventDefault(); + + if (password === "team-fullstack") { + console.log("ok"); + setCookie("protect_staging", Date.now().toString()); + router.push(Module.getInstance().get().modules.pages.Login.props.path); + } else { + console.log("pas ok"); + } + }; + + const setCookie = (name: string, value: string) => { + if (!name || !value) throw new Error("Cookie name or value is empty"); + const date = new Date(); + + // Set it expire in 7 days + date.setTime(date.getTime() + 7 * 24 * 60 * 60 * 1000); + + // Set it + document.cookie = name + "=" + value + "; expires=" + date.toUTCString() + "; path=/"; + }; + + return ( + +
+ coffre + +
Le site est verrouillé
+
+
+ + + +
+
+ ); +} diff --git a/src/front/Components/Layouts/Protect/landing-connect.jpeg b/src/front/Components/Layouts/Protect/landing-connect.jpeg new file mode 100644 index 00000000..789e0ef3 Binary files /dev/null and b/src/front/Components/Layouts/Protect/landing-connect.jpeg differ diff --git a/src/middleware.ts b/src/middleware.ts index e5c65548..b73a3231 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -4,11 +4,28 @@ import { NextResponse } from "next/server"; import type { NextRequest } from "next/server"; export async function middleware(request: NextRequest) { + const cookieStaging = request.cookies.get("protect_staging"); + console.log(cookieStaging); + if (!cookieStaging) return NextResponse.redirect(new URL("/protect", request.url)); + + // Get the JWT from the cookies const cookies = request.cookies.get("leCoffreAccessToken"); if (!cookies) return NextResponse.redirect(new URL("/login", request.url)); + + // Decode it const userDecodedToken = jwt_decode(cookies.value) as IUserJwtPayload; const customerDecodedToken = jwt_decode(cookies.value) as ICustomerJwtPayload; + + // If no JWT provided, redirect to login page if (!userDecodedToken && !customerDecodedToken) return NextResponse.redirect(new URL("/login", request.url)); + + // If JWT expired, redirect to login page + const token = userDecodedToken ?? customerDecodedToken; + const now = Math.floor(Date.now() / 1000); + if (token.exp < now) { + return NextResponse.redirect(new URL("/login", request.url)); + } + const requestUrlPath = request.nextUrl.pathname; if ( requestUrlPath.startsWith("/collaborators") || @@ -21,7 +38,8 @@ export async function middleware(request: NextRequest) { if (userDecodedToken.role !== "admin" && userDecodedToken.role !== "super-admin") return NextResponse.redirect(new URL("/404", request.url)); } - if ((requestUrlPath.startsWith("/my-account") || requestUrlPath.startsWith("/document-types")) && !userDecodedToken) return NextResponse.redirect(new URL("/404", request.url)); + if ((requestUrlPath.startsWith("/my-account") || requestUrlPath.startsWith("/document-types")) && !userDecodedToken) + return NextResponse.redirect(new URL("/404", request.url)); if (requestUrlPath.startsWith("/client-dashboard") && !customerDecodedToken) return NextResponse.redirect(new URL("/404", request.url)); return NextResponse.next(); @@ -33,7 +51,7 @@ export const config = { "/collaborators/:path*", "/customer/:path*", "/document-types/:path*", - "/deed-types/:path*", + "/deed-types/:path*", "/folders/:path*", "/my-account/:path*", "/offices/:path*", diff --git a/src/pages/protect.tsx b/src/pages/protect.tsx new file mode 100644 index 00000000..d554b993 --- /dev/null +++ b/src/pages/protect.tsx @@ -0,0 +1,5 @@ +import Protect from "@Front/Components/Layouts/Protect"; + +export default function Route() { + return ; +}