implement new invitation system

* fix comments on the frontend
* move jwt token service to its own module
* other fixes and updates
This commit is contained in:
Philipinho
2024-05-14 22:55:11 +01:00
parent 525990d6e5
commit eefe63d1cd
75 changed files with 10965 additions and 7846 deletions

View File

@ -1,6 +1,12 @@
.authBackground {
position: relative;
min-height: 100vh;
background-size: cover;
background-image: url(https://images.unsplash.com/photo-1701010063921-5f3255259e6d?q=80&w=3024&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D);
position: relative;
min-height: 100vh;
background-size: cover;
background-image: url(https://images.unsplash.com/photo-1701010063921-5f3255259e6d?q=80&w=3024&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D);
}
.container {
box-shadow: rgba(0, 0, 0, 0.07) 0px 2px 45px 4px;
border-radius: 4px;
background: light-dark(var(--mantine-color-body), rgba(0, 0, 0, 0.1));
}

View File

@ -0,0 +1,102 @@
import * as React from "react";
import * as z from "zod";
import { useForm, zodResolver } from "@mantine/form";
import {
Container,
Title,
TextInput,
Button,
PasswordInput,
Box,
Stack,
} from "@mantine/core";
import { useParams, useSearchParams } from "react-router-dom";
import { IRegister } from "@/features/auth/types/auth.types";
import useAuth from "@/features/auth/hooks/use-auth";
import classes from "@/features/auth/components/auth.module.css";
import { useGetInvitationQuery } from "@/features/workspace/queries/workspace-query.ts";
import { useRedirectIfAuthenticated } from "@/features/auth/hooks/use-redirect-if-authenticated.ts";
const formSchema = z.object({
name: z.string().min(2),
password: z.string().min(8),
});
type FormValues = z.infer<typeof formSchema>;
export function InviteSignUpForm() {
const params = useParams();
const [searchParams] = useSearchParams();
const { data: invitation } = useGetInvitationQuery(params?.invitationId);
const { invitationSignup, isLoading } = useAuth();
useRedirectIfAuthenticated();
const form = useForm<FormValues>({
validate: zodResolver(formSchema),
initialValues: {
name: "",
password: "",
},
});
async function onSubmit(data: IRegister) {
const invitationToken = searchParams.get("token");
await invitationSignup({
invitationId: invitation.id,
name: data.name,
password: data.password,
token: invitationToken,
});
}
if (!invitation) {
return <div></div>;
}
return (
<Container size={420} my={40} className={classes.container}>
<Box p="xl" mt={200}>
<Title order={2} ta="center" fw={500} mb="md">
Complete your signup
</Title>
<Stack align="stretch" justify="center" gap="xl">
<form onSubmit={form.onSubmit(onSubmit)}>
<TextInput
id="name"
type="text"
label="Name"
placeholder="enter your full name"
variant="filled"
{...form.getInputProps("name")}
/>
<TextInput
id="email"
type="email"
label="Email"
value={invitation.email}
disabled
variant="filled"
mt="md"
/>
<PasswordInput
label="Password"
placeholder="Your password"
variant="filled"
mt="md"
{...form.getInputProps("password")}
/>
<Button type="submit" fullWidth mt="xl" loading={isLoading}>
Sign Up
</Button>
</form>
</Stack>
</Box>
</Container>
);
}

View File

@ -1,37 +1,41 @@
import * as React from 'react';
import * as z from 'zod';
import * as React from "react";
import * as z from "zod";
import { useForm, zodResolver } from '@mantine/form';
import useAuth from '@/features/auth/hooks/use-auth';
import { ILogin } from '@/features/auth/types/auth.types';
import { useForm, zodResolver } from "@mantine/form";
import useAuth from "@/features/auth/hooks/use-auth";
import { ILogin } from "@/features/auth/types/auth.types";
import {
Container,
Title,
Anchor,
Paper,
TextInput,
Button,
Text,
PasswordInput,
} from '@mantine/core';
import { Link } from 'react-router-dom';
import classes from './auth.module.css';
Box,
} from "@mantine/core";
import { Link, useNavigate } from "react-router-dom";
import classes from "./auth.module.css";
import { useEffect, useState } from "react";
import { useRedirectIfAuthenticated } from "@/features/auth/hooks/use-redirect-if-authenticated.ts";
const formSchema = z.object({
email: z
.string({ required_error: 'email is required' })
.email({ message: 'Invalid email address' }),
password: z.string({ required_error: 'password is required' }),
.string()
.min(1, { message: "email is required" })
.email({ message: "Invalid email address" }),
password: z.string().min(1, { message: "Password is required" }),
});
export function LoginForm() {
const { signIn, isLoading } = useAuth();
useRedirectIfAuthenticated();
const form = useForm<ILogin>({
validate: zodResolver(formSchema),
initialValues: {
email: '',
password: '',
email: "",
password: "",
},
});
@ -40,9 +44,9 @@ export function LoginForm() {
}
return (
<Container size={420} my={40}>
<Paper shadow="md" p="lg" radius="md" mt={200}>
<Title ta="center" fw={800}>
<Container size={420} my={40} className={classes.container}>
<Box p="xl" mt={200}>
<Title order={2} ta="center" fw={500} mb="md">
Login
</Title>
@ -52,16 +56,16 @@ export function LoginForm() {
type="email"
label="Email"
placeholder="email@example.com"
required
{...form.getInputProps('email')}
variant="filled"
{...form.getInputProps("email")}
/>
<PasswordInput
label="Password"
placeholder="Your password"
required
variant="filled"
mt="md"
{...form.getInputProps('password')}
{...form.getInputProps("password")}
/>
<Button type="submit" fullWidth mt="xl" loading={isLoading}>
Sign In
@ -69,13 +73,12 @@ export function LoginForm() {
</form>
<Text c="dimmed" size="sm" ta="center" mt="sm">
Don't have an account yet?{' '}
Don't have an account yet?{" "}
<Anchor size="sm" component={Link} to="/signup">
Create account
</Anchor>
</Text>
</Paper>
</Box>
</Container>
);
}

View File

@ -1,36 +1,40 @@
import * as React from 'react';
import * as z from 'zod';
import * as React from "react";
import * as z from "zod";
import { useForm, zodResolver } from '@mantine/form';
import { useForm, zodResolver } from "@mantine/form";
import {
Container,
Title,
Anchor,
Paper,
TextInput,
Button,
Text,
PasswordInput,
} from '@mantine/core';
import { Link } from 'react-router-dom';
import { IRegister } from '@/features/auth/types/auth.types';
import useAuth from '@/features/auth/hooks/use-auth';
Box,
} from "@mantine/core";
import { Link } from "react-router-dom";
import { IRegister } from "@/features/auth/types/auth.types";
import useAuth from "@/features/auth/hooks/use-auth";
import classes from "@/features/auth/components/auth.module.css";
import { useRedirectIfAuthenticated } from "@/features/auth/hooks/use-redirect-if-authenticated.ts";
const formSchema = z.object({
email: z
.string({ required_error: 'email is required' })
.email({ message: 'Invalid email address' }),
password: z.string({ required_error: 'password is required' }),
.string()
.min(1, { message: "email is required" })
.email({ message: "Invalid email address" }),
password: z.string().min(1, { message: "Password is required" }),
});
export function SignUpForm() {
const { signUp, isLoading } = useAuth();
useRedirectIfAuthenticated();
const form = useForm<IRegister>({
validate: zodResolver(formSchema),
initialValues: {
email: '',
password: '',
email: "",
password: "",
},
});
@ -39,40 +43,41 @@ export function SignUpForm() {
}
return (
<Container size={420} my={40}>
<Title ta="center" fw={800}>
Create an account
</Title>
<Text c="dimmed" size="sm" ta="center" mt={5}>
Already have an account?{' '}
<Anchor size="sm" component={Link} to="/login">
Login
</Anchor>
</Text>
<Container size={420} my={40} className={classes.container}>
<Box p="xl" mt={200}>
<Title order={2} ta="center" fw={500} mb="md">
Create an account
</Title>
<Paper shadow="md" p={30} mt={30} radius="md">
<form onSubmit={form.onSubmit(onSubmit)}>
<TextInput
id="email"
type="email"
label="Email"
placeholder="email@example.com"
required
{...form.getInputProps('email')}
variant="filled"
{...form.getInputProps("email")}
/>
<PasswordInput
label="Password"
placeholder="Your password"
required
variant="filled"
mt="md"
{...form.getInputProps('password')}
{...form.getInputProps("password")}
/>
<Button type="submit" fullWidth mt="xl" loading={isLoading}>
Sign Up
</Button>
</form>
</Paper>
<Text c="dimmed" size="sm" ta="center" mt="sm">
Already have an account?{" "}
<Anchor size="sm" component={Link} to="/login">
Login
</Anchor>
</Text>
</Box>
</Container>
);
}