CLASSROOMIO-T-1: 1st logic for signup

This commit is contained in:
Rotimi Best
2022-11-30 09:18:41 +01:00
parent e14af6b1ad
commit 8e169241e1
6 changed files with 192 additions and 71 deletions
+43 -34
View File
@@ -6,6 +6,7 @@
export let supabase;
export let handleSubmit;
export let isLogin = true;
export let showOnlyContent = false;
async function signInWithGoogle() {
const { data, error } = await supabase.auth.signInWithOAuth({
@@ -15,49 +16,57 @@
</script>
<div class="w-full min-h-screen flex items-center justify-center mt-4">
<div class="container border border-gray bg-white">
<div
class="container border border-gray bg-white {showOnlyContent && 'h-2/4'}"
>
<div class="flex items-center flex-col p-2 lg:px-8 lg:py-4">
<div class="flex items-center w-full justify-center">
<img
src="/logo-192.png"
alt="ClassroomIO logo"
height="50"
width="50"
data-atf="1"
/>
<h4 class="text-xl">ClassroomIO</h4>
</div>
{#if !showOnlyContent}
<div class="flex items-center w-full justify-center">
<img
src="/logo-192.png"
alt="ClassroomIO logo"
height="50"
width="50"
data-atf="1"
/>
<h4 class="text-xl">ClassroomIO</h4>
</div>
{/if}
<form
on:submit|preventDefault={handleSubmit}
class="flex items-center flex-col w-10/12"
>
<slot />
</form>
<div class="w-10/12 mb-3">
<p class="text-sm mb-5">or sign up with:</p>
<PrimaryButton
variant={VARIANTS.OUTLINED}
onClick={signInWithGoogle}
className="py-3 sm:w-full w-full"
>
<GoogleIconColored />
<span class="ml-2">Sign up with Google</span>
</PrimaryButton>
</div>
</div>
<div class="w-full p-6 border-t border-grey text-center">
{#if isLogin}
Not registered yet? <a
class="hover:underline text-blue-700"
href="/signup">Sign up</a
>
{:else}
Already have an account? <a
class="hover:underline text-blue-700"
href="/login">Log In</a
>
{#if !showOnlyContent}
<div class="w-10/12 mb-3">
<p class="text-sm mb-5">or sign up with:</p>
<PrimaryButton
variant={VARIANTS.OUTLINED}
onClick={signInWithGoogle}
className="py-3 sm:w-full w-full"
>
<GoogleIconColored />
<span class="ml-2">Sign up with Google</span>
</PrimaryButton>
</div>
{/if}
</div>
{#if !showOnlyContent}
<div class="w-full p-6 border-t border-grey text-center">
{#if isLogin}
Not registered yet? <a
class="hover:underline text-blue-700"
href="/signup">Sign up</a
>
{:else}
Already have an account? <a
class="hover:underline text-blue-700"
href="/login">Log In</a
>
{/if}
</div>
{/if}
</div>
</div>
+44
View File
@@ -0,0 +1,44 @@
<svg
width="120"
height="120"
viewBox="0 0 120 120"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M85.3281 31H34.6719C33.4724 31 32.5 31.9724 32.5 33.1719V70.8281C32.5 72.0276 33.4724 73 34.6719 73H85.3281C86.5276 73 87.5 72.0276 87.5 70.8281V33.1719C87.5 31.9724 86.5276 31 85.3281 31ZM34.6719 27C31.2632 27 28.5 29.7632 28.5 33.1719V70.8281C28.5 74.2368 31.2632 77 34.6719 77H85.3281C88.7368 77 91.5 74.2368 91.5 70.8281V33.1719C91.5 29.7632 88.7368 27 85.3281 27H34.6719Z"
fill="#0233BD"
/>
<rect
x="40.9844"
y="37.875"
width="36.4141"
height="3.08594"
rx="1.54297"
fill="#658DFE"
/>
<rect
x="40.9844"
y="44.0469"
width="36.4141"
height="3.08594"
rx="1.54297"
fill="#658DFE"
/>
<rect
x="40.9844"
y="50.2188"
width="36.4141"
height="3.08594"
rx="1.54297"
fill="#658DFE"
/>
<path
d="M23 94.0391V62.5938H97V94.0391C97 96.067 95.356 97.7109 93.3281 97.7109H26.6719C24.644 97.7109 23 96.067 23 94.0391Z"
fill="#658DFE"
stroke="#0233BD"
stroke-width="5"
/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

+2 -1
View File
@@ -37,9 +37,9 @@
});
async function getProfile() {
console.log('Get user profile');
// Get user profile
const authUser = supabase.auth.user();
console.log('Get user profile', authUser);
// Check if user has profile
let {
@@ -82,6 +82,7 @@
goto('/dashboard');
}
}
$user.fetchingUser = false;
} else if (profileData) {
// Profile exists, go to profile page
$user.fetchingUser = false;
+54 -36
View File
@@ -5,81 +5,92 @@
</script>
<script>
import { goto } from '@sapper/app';
import { Chasing } from 'svelte-loading-spinners';
import TextField from '../components/Form/TextField.svelte';
import PrimaryButton from '../components/PrimaryButton/index.svelte';
import { getSupabase } from '../utils/functions/supabase';
import { user } from '../utils/store/user';
import {
signUpValidation,
getConfirmPasswordError,
getDisableSubmit,
} from '../utils/functions/validator';
import { SIGNUP_FIELDS } from '../utils/constants/authentication';
import AuthUI from '../components/AuthUI/index.svelte';
import EmailSentIcon from '../components/Icons/EmailSentIcon.svelte';
export let config;
let supabase = getSupabase(config);
let email;
let name;
let password;
let passwordAgain;
let fields = Object.assign({}, SIGNUP_FIELDS);
let loading = false;
let success = false;
let errors = {};
let submitError;
let disableSubmit = false;
async function handleSubmit() {
if (!email) {
errors = {
email: 'Email is required',
password: 'Password is required',
};
const validationRes = signUpValidation(fields);
console.log('validationRes', validationRes);
if (Object.keys(validationRes).length) {
errors = Object.assign(errors, validationRes);
return;
}
try {
loading = true;
const { data, error } = await supabase.auth.signIn(
{ email },
{
redirectTo: window.location.origin + '/login',
}
);
const { data, error } = await supabase.auth.signUp({
email: fields.email,
password: fields.password,
options: {
data: {
fullname: fields.name,
},
},
});
if (error) throw error;
success = true;
email = {};
return goto('/login');
// success = true;
// fields = Object.assign({}, SIGNUP_FIELDS);
} catch (error) {
errors = {
email: error.error_description || error.message,
};
submitError = error.error_description || error.message;
} finally {
loading = false;
}
}
$: errors.confirmPassword = getConfirmPasswordError(fields);
$: disableSubmit = getDisableSubmit(fields);
</script>
<svelte:head>
<title>Sign Up - ClassroomIO</title>
</svelte:head>
<AuthUI {supabase} isLogin={false} {handleSubmit}>
<AuthUI {supabase} isLogin={false} {handleSubmit} showOnlyContent={success}>
<div class="mt-4 w-full">
{#if $user.fetchingUser}
<div class="h-40 text-md flex items-center justify-center">
<Chasing size="60" color="#ff3e00" unit="px" duration="1s" />
</div>
{:else if success}
<div class="h-40 text-md flex items-center justify-center flex-col">
<p class="">
A link has been sent to your email. Please check both your
<div class="text-md flex items-center justify-center flex-col">
<EmailSentIcon />
<h2 class="text-xl">Email sent!</h2>
<p class="mt-4 text-center">
We have sent a confirmation email to {fields.email}. Please check both
your
<strong>spam </strong>and your<strong>&nbsp; inbox</strong>.
</p>
<p class="mt-2 underline">
If our email is in your spam, do make sure you mark our email address
as safe, then move it from your spam to your inbox.
</p>
</div>
{:else}
<p class="text-lg font-semibold mb-6">Create a free account</p>
<TextField
label="Full Name"
bind:value={name}
bind:value={fields.name}
type="text"
autoFocus={true}
placeholder="e.g Joke Silva"
@@ -87,37 +98,45 @@
inputClassName="w-full"
isDisabled={loading}
errorMessage={errors.name}
isRequired
/>
<TextField
label="Your Email"
bind:value={email}
bind:value={fields.email}
type="email"
placeholder="you@domain.com"
className="mb-6"
inputClassName="w-full"
isDisabled={loading}
errorMessage={errors.email}
isRequired
/>
<TextField
label="Your Password"
bind:value={password}
bind:value={fields.password}
type="password"
placeholder="************"
className="mb-6"
inputClassName="w-full"
isDisabled={loading}
errorMessage={errors.password}
helperMessage="Password must be more than 6 characters"
isRequired
/>
<TextField
label="Confirm Password"
bind:value={passwordAgain}
bind:value={fields.confirmPassword}
type="password"
placeholder="************"
className="mb-6"
inputClassName="w-full"
isDisabled={loading}
errorMessage={errors.passwordAgain}
errorMessage={errors.confirmPassword}
isRequired
/>
{#if submitError}
<p class="text-sm text-red-500">{submitError}</p>
{/if}
<div class="w-full text-right">
<a class="text-md text-blue-700" href="/forgot"> Forgot password? </a>
</div>
@@ -126,12 +145,11 @@
{#if !success}
<div class="my-4 w-full flex justify-end items-center">
<!-- <a href="/login" class="text-blue-700 text-sm">Create an account</a> -->
<PrimaryButton
label={loading ? 'Creating...' : 'Log In'}
label={loading ? 'Creating...' : 'Create Account'}
type="submit"
className="py-3 sm:w-full w-full"
isDisabled={loading}
isDisabled={disableSubmit || loading}
/>
</div>
{/if}
+6
View File
@@ -0,0 +1,6 @@
export const SIGNUP_FIELDS = {
name: '',
email: '',
password: '',
confirmPassword: '',
};
+43
View File
@@ -0,0 +1,43 @@
import z from 'zod';
const validationSchema = z.object({
name: z.string().min(3, {
message: 'Must be 3 or more characters long',
invalid_type_error: 'Must not be empty',
}),
email: z.string().email({
message: 'Invalid email address',
invalid_type_error: 'Must not be empty',
}),
password: z.string().min(6, {
message: 'Must be 6 or more characters long',
invalid_type_error: 'Must not be empty',
}),
});
export const getConfirmPasswordError = ({ password, confirmPassword }) => {
return password > 6 && confirmPassword > 6 && password !== confirmPassword
? 'Does not match password'
: null;
};
export const signUpValidation = (fields = {}) => {
const { error } = validationSchema.safeParse(fields);
const errors = {};
if (Array.isArray(error?.issues)) {
for (const issue of error.issues) {
const { message, path } = issue;
console.log(issue);
if (path.length) {
errors[path[0]] = message;
}
}
}
return errors;
};
export const getDisableSubmit = ({ password, confirmPassword }) => {
return !!(password && confirmPassword && password !== confirmPassword);
};