From fc6122e3a6e624e39c695aafce81e09595d4572b Mon Sep 17 00:00:00 2001 From: swve Date: Sat, 22 Jul 2023 18:06:03 +0200 Subject: [PATCH] feat: init new login page --- front/app/orgs/[orgslug]/login/login.tsx | 136 +++++++++++++++++++++++ front/app/orgs/[orgslug]/login/page.tsx | 115 ++++--------------- front/services/auth/auth.ts | 5 +- 3 files changed, 158 insertions(+), 98 deletions(-) create mode 100644 front/app/orgs/[orgslug]/login/login.tsx diff --git a/front/app/orgs/[orgslug]/login/login.tsx b/front/app/orgs/[orgslug]/login/login.tsx new file mode 100644 index 00000000..06b662d1 --- /dev/null +++ b/front/app/orgs/[orgslug]/login/login.tsx @@ -0,0 +1,136 @@ +"use client"; +import learnhouseIcon from "public/learnhouse_bigicon_1.png"; +import FormLayout, { ButtonBlack, FormField, FormLabel, FormLabelAndMessage, FormMessage, Input } from '@components/StyledElements/Form/Form' +import Image from 'next/image'; +import * as Form from '@radix-ui/react-form'; +import { useFormik } from 'formik'; +import { getOrgLogoMediaDirectory } from "@services/media/media"; +import { BarLoader } from "react-spinners"; +import React from "react"; +import { loginAndGetToken } from "@services/auth/auth"; +import { AlertTriangle } from "lucide-react"; +import { useRouter } from "next/navigation"; + +interface LoginClientProps { + org: any; +} + +const validate = (values: any) => { + const errors: any = {}; + + if (!values.email) { + errors.email = 'Required'; + } + else if ( + !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.email) + ) { + errors.email = 'Invalid email address'; + } + + if (!values.password) { + errors.password = 'Required'; + } + else if (values.password.length < 8) { + errors.password = 'Password must be at least 8 characters'; + } + + return errors; +}; + +const LoginClient = (props: LoginClientProps) => { + const [isSubmitting, setIsSubmitting] = React.useState(false); + const router = useRouter(); + const [error, setError] = React.useState(''); + const formik = useFormik({ + initialValues: { + email: '', + password: '', + }, + validate, + onSubmit: async values => { + setIsSubmitting(true); + let res = await loginAndGetToken(values.email, values.password); + console.log(res.status); + if (res.status == 200) { + router.push(`/`); + setIsSubmitting(false); + } + else if (res.status == 401 || res.status == 400 || res.status == 404 || res.status == 409) { + setError("Invalid email or password"); + setIsSubmitting(false); + } + else { + setError("Something went wrong"); + setIsSubmitting(false); + } + + }, + }); + return ( +
+
+
+ +
+
+
+
Login to
+
+ {props.org?.logo ? ( + Learnhouse + ) : ( + + )} +
+
{props.org?.name}
+
+
+
+
+
+ {error && ( +
+ +
{error}
+
+ )} + + + + + + + + {/* for password */} + + + + + + + + + +
+ + + +
+ +
+
+
+
+ ); +}; + +export default LoginClient + diff --git a/front/app/orgs/[orgslug]/login/page.tsx b/front/app/orgs/[orgslug]/login/page.tsx index 08aa23a7..11dd3f5b 100644 --- a/front/app/orgs/[orgslug]/login/page.tsx +++ b/front/app/orgs/[orgslug]/login/page.tsx @@ -1,110 +1,35 @@ -"use client"; -import { useRouter } from 'next/navigation'; -import React, { useState } from "react"; -import { styled } from '@stitches/react'; -import { loginAndGetToken } from "../../../../services/auth/auth"; -import FormLayout, { ButtonBlack, Flex, FormField, FormLabel, FormMessage, Input } from '@components/StyledElements/Form/Form'; -import * as Form from '@radix-ui/react-form'; -import { BarLoader } from 'react-spinners'; -import Toast from '@components/StyledElements/Toast/Toast'; -import { toast } from 'react-hot-toast'; +import { getOrganizationContextInfo } from "@services/organizations/orgs"; +import LoginClient from "./login"; +import { Metadata } from 'next'; -const Login = () => { - const [email, setEmail] = React.useState(""); - const [password, setPassword] = React.useState(""); - const [isSubmitting, setIsSubmitting] = useState(false); - const router = useRouter(); +type MetadataProps = { + params: { orgslug: string, courseid: string }; + searchParams: { [key: string]: string | string[] | undefined }; +}; - const handleSubmit = (e: any) => { - e.preventDefault(); - setIsSubmitting(true); - toast.promise( - loginAndGetToken(email, password), - { - loading: 'Logging in...', - success: () => { - router.push('/'); - return Logged in successfully; - }, - error: Wrong credentials, - } - ); +export async function generateMetadata( + { params }: MetadataProps, +): Promise { + const orgslug = params.orgslug; + // Get Org context information + const org = await getOrganizationContextInfo(orgslug, { revalidate: 1800, tags: ['organizations'] }); - setIsSubmitting(false); + return { + title: 'Login' + ` — ${org.name}`, }; +} - const handleEmailChange = (e: any) => { - setEmail(e.target.value); - }; - - const handlePasswordChange = (e: any) => { - setPassword(e.target.value); - }; +const Login = async (params: any) => { + const orgslug = params.params.orgslug; + const org = await getOrganizationContextInfo(orgslug, { revalidate: 1800, tags: ['organizations'] }); return (
- - - - - - - Email - Please provide an email - - - - - - - - Password - Please provide a password - - - - - - - - - - {isSubmitting ? : "Login"} - - - - - - - +
); }; -const LoginPage = styled('div', { - display: 'flex', - justifyContent: 'center', - alignItems: 'center', - height: '100vh', - width: '100vw', - backgroundColor: '#f5f5f5', -}); -const LoginBox = styled('div', { - display: 'flex', - flexDirection: 'column', - justifyContent: 'center', - alignItems: 'center', - height: '40vh', - width: '40vw', - backgroundColor: '#ffffff', - borderRadius: 10, - - '@media (max-width: 768px)': { - width: '100vw', - height: '100vh', - borderRadius: 0, - }, -}); export default Login; diff --git a/front/services/auth/auth.ts b/front/services/auth/auth.ts index 5c16970c..45a2ecb1 100644 --- a/front/services/auth/auth.ts +++ b/front/services/auth/auth.ts @@ -8,7 +8,7 @@ interface LoginAndGetTokenResponse { // ⚠️ mvp phase code // TODO : everything in this file need to be refactored including security issues fix -export async function loginAndGetToken(username: string, password: string): Promise { +export async function loginAndGetToken(username: string, password: string): Promise { // Request Config // get origin @@ -25,8 +25,7 @@ export async function loginAndGetToken(username: string, password: string): Prom // fetch using await and async const response = await fetch(`${getAPIUrl()}auth/login`, requestOptions); - const data = await response.json(); - return data; + return response; } export async function getUserInfo(token: string): Promise {