diff --git a/front/app/orgs/[orgslug]/login/login.tsx b/front/app/orgs/[orgslug]/login/login.tsx
new file mode 100644
index 00000000..d8f32cb8
--- /dev/null
+++ b/front/app/orgs/[orgslug]/login/login.tsx
@@ -0,0 +1,139 @@
+"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";
+import Link from "next/link";
+import { getUriWithOrg } from "@services/config/config";
+
+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);
+ let message = await res.json();
+ if (res.status == 200) {
+ router.push(`/`);
+ setIsSubmitting(false);
+ }
+ else if (res.status == 401 || res.status == 400 || res.status == 404 || res.status == 409) {
+ setError(message.detail);
+ setIsSubmitting(false);
+ }
+ else {
+ setError("Something went wrong");
+ setIsSubmitting(false);
+ }
+
+ },
+ });
+ return (
+
+
+
+
+
+
+
+
+
Login to
+
+ {props.org?.logo ? (
+

+ ) : (
+
+ )}
+
+
{props.org?.name}
+
+
+
+
+
+ );
+};
+
+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/app/orgs/[orgslug]/signup/page.tsx b/front/app/orgs/[orgslug]/signup/page.tsx
index 29e13ff8..dd70b7f4 100644
--- a/front/app/orgs/[orgslug]/signup/page.tsx
+++ b/front/app/orgs/[orgslug]/signup/page.tsx
@@ -1,115 +1,33 @@
-"use client";
+
import React from "react";
-import { signup } from "../../../../services/auth/auth";
-import { useRouter } from "next/navigation";
+import SignUpClient from "./signup";
+import { Metadata } from "next";
+import { getOrganizationContextInfo } from "@services/organizations/orgs";
-const SignUp = (params: any) => {
- const org_slug = params.params.orgslug;
- const router = useRouter();
- const [email, setEmail] = React.useState("");
- const [password, setPassword] = React.useState("");
- const [username, setUsername] = React.useState("");
+type MetadataProps = {
+ params: { orgslug: string, courseid: string };
+ searchParams: { [key: string]: string | string[] | undefined };
+};
- const handleSubmit = (e: any) => {
- e.preventDefault();
- console.log({ email, password, username, org_slug });
- alert(JSON.stringify({ email, password, username, org_slug }));
- try {
- signup({ email, password, username, org_slug });
- router.push("/");
- }
- catch (err) {
- console.log(err);
- }
+export async function generateMetadata(
+ { params }: MetadataProps,
+): Promise {
+ const orgslug = params.orgslug;
+ // Get Org context information
+ const org = await getOrganizationContextInfo(orgslug, { revalidate: 1800, tags: ['organizations'] });
+
+ return {
+ title: 'Sign up' + ` — ${org.name}`,
};
+}
- const handleEmailChange = (e: any) => {
- setEmail(e.target.value);
- };
-
- const handlePasswordChange = (e: any) => {
- setPassword(e.target.value);
- };
-
- const handleUsernameChange = (e: any) => {
- setUsername(e.target.value);
- };
+const SignUp = async (params: any) => {
+ const orgslug = params.params.orgslug;
+ const org = await getOrganizationContextInfo(orgslug, { revalidate: 1800, tags: ['organizations'] });
return (
);
};
diff --git a/front/app/orgs/[orgslug]/signup/signup.tsx b/front/app/orgs/[orgslug]/signup/signup.tsx
new file mode 100644
index 00000000..102af86c
--- /dev/null
+++ b/front/app/orgs/[orgslug]/signup/signup.tsx
@@ -0,0 +1,188 @@
+"use client";
+import { useFormik } from 'formik';
+import { useRouter } from 'next/navigation';
+import learnhouseIcon from "public/learnhouse_bigicon_1.png";
+import React from 'react'
+import FormLayout, { ButtonBlack, FormField, FormLabel, FormLabelAndMessage, FormMessage, Input, Textarea } from '@components/StyledElements/Form/Form'
+import Image from 'next/image';
+import * as Form from '@radix-ui/react-form';
+import { getOrgLogoMediaDirectory } from '@services/media/media';
+import { AlertTriangle } from 'lucide-react';
+import Link from 'next/link';
+import { signup } from '@services/auth/auth';
+import { getUriWithOrg } from '@services/config/config';
+
+
+interface SignUpClientProps {
+ 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';
+ }
+
+ if (!values.username) {
+ errors.username = 'Required';
+ }
+
+ if (!values.username || values.username.length < 4) {
+ errors.username = 'Username must be at least 4 characters';
+ }
+
+ if (!values.full_name) {
+ errors.full_name = 'Required';
+ }
+
+ if (!values.bio) {
+ errors.bio = 'Required';
+ }
+
+
+ return errors;
+};
+
+
+function SignUpClient(props: SignUpClientProps) {
+ const [isSubmitting, setIsSubmitting] = React.useState(false);
+ const router = useRouter();
+ const [error, setError] = React.useState('');
+ const formik = useFormik({
+ initialValues: {
+ org_slug: props.org?.slug,
+ email: '',
+ password: '',
+ username: '',
+ bio: '',
+ full_name: '',
+ },
+ validate,
+ onSubmit: async values => {
+ setIsSubmitting(true);
+ let res = await signup(values);
+ let message = await res.json();
+ if (res.status == 200) {
+ router.push(`/`);
+ setIsSubmitting(false);
+ }
+ else if (res.status == 401 || res.status == 400 || res.status == 404 || res.status == 409) {
+ setError(message.detail);
+ setIsSubmitting(false);
+ }
+ else {
+ setError("Something went wrong");
+ setIsSubmitting(false);
+ }
+
+ },
+ });
+
+ return (
+
+
+
+
+
+
+
+
+
+
Join
+
+ {props.org?.logo ? (
+

+ ) : (
+
+ )}
+
+
{props.org?.name}
+
+
+
+
+
+ )
+}
+
+export default SignUpClient
\ No newline at end of file
diff --git a/front/services/auth/auth.ts b/front/services/auth/auth.ts
index 5c16970c..d09a6746 100644
--- a/front/services/auth/auth.ts
+++ b/front/services/auth/auth.ts
@@ -5,14 +5,14 @@ interface LoginAndGetTokenResponse {
token_type: "string";
}
-// ⚠️ mvp phase code
-// TODO : everything in this file need to be refactored including security issues fix
+// ⚠️ 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
- const HeadersConfig = new Headers({ "Content-Type": "application/x-www-form-urlencoded" });
+ // get origin
+ const HeadersConfig = new Headers({ "Content-Type": "application/x-www-form-urlencoded" });
const urlencoded = new URLSearchParams({ username: username, password: password });
const requestOptions: any = {
@@ -21,17 +21,16 @@ export async function loginAndGetToken(username: string, password: string): Prom
body: urlencoded,
redirect: "follow",
credentials: "include",
- };
+ };
// 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 {
const origin = window.location.origin;
- const HeadersConfig = new Headers({ Authorization: `Bearer ${token}`, Origin:origin });
+ const HeadersConfig = new Headers({ Authorization: `Bearer ${token}`, Origin: origin });
const requestOptions: any = {
method: "GET",
@@ -68,7 +67,7 @@ interface NewAccountBody {
export async function signup(body: NewAccountBody): Promise {
const HeadersConfig = new Headers({ "Content-Type": "application/json" });
-
+
const requestOptions: any = {
method: "POST",
headers: HeadersConfig,
@@ -76,9 +75,6 @@ export async function signup(body: NewAccountBody): Promise {
redirect: "follow",
};
- return fetch(`${getAPIUrl()}users/?org_slug=${body.org_slug}`, requestOptions)
- .then((result) => result.json())
- .catch((error) => console.log("error", error));
+ const res = await fetch(`${getAPIUrl()}users/?org_slug=${body.org_slug}`, requestOptions);
+ return res;
}
-
-