diff --git a/interface/app/$libraryId/TopBar/index.tsx b/interface/app/$libraryId/TopBar/index.tsx index d84646775..3e6afd7a3 100644 --- a/interface/app/$libraryId/TopBar/index.tsx +++ b/interface/app/$libraryId/TopBar/index.tsx @@ -138,7 +138,7 @@ function Tabs() { else if (e.button === 1) removeTab(index); }} className={clsx( - 'group relative flex h-full min-w-40 shrink-0 flex-row items-center justify-center px-8 text-center duration-[50ms]', + 'duration-[50ms] group relative flex h-full min-w-40 shrink-0 flex-row items-center justify-center px-8 text-center', ctx.tabIndex === index ? 'text-ink' : 'top-bar-blur border-t border-sidebar-divider bg-sidebar/30 text-ink-faint/60 transition-colors hover:bg-app/50' @@ -166,7 +166,7 @@ function Tabs() { diff --git a/interface/app/$libraryId/settings/client/account/LoginRegister.tsx b/interface/app/$libraryId/settings/client/account/LoginRegister.tsx new file mode 100644 index 000000000..5efc4f16b --- /dev/null +++ b/interface/app/$libraryId/settings/client/account/LoginRegister.tsx @@ -0,0 +1,257 @@ +import { zodResolver } from '@hookform/resolvers/zod'; +import { useZodForm } from '@sd/client'; +import { Button, Card, Divider, Form, Input, Tooltip, z } from '@sd/ui'; +import { motion } from 'framer-motion'; +import { useState } from 'react'; + +import { GoogleLogo, Icon } from '@phosphor-icons/react'; +import { Apple, Github } from '@sd/assets/svgs/brands'; +import clsx from 'clsx'; +import { Controller, useForm } from 'react-hook-form'; + +const Tabs = ['Login', 'Register'] as const; +const LoginSchema = z.object({ + email: z.string().email(), + password: z.string().min(6), +}) +const RegisterSchema = z.object({ + email: z.string().email(), + password: z.string().min(6), + confirmPassword: z.string().min(6), +}).refine(data => data.password === data.confirmPassword, { + message: 'Passwords do not match', + path: ['confirmPassword'] +}) +type RegisterData = z.infer + +type SocialLogin = { + name: "Github" | "Google" | "Apple"; + icon: Icon; +} + +const SocialLogins: SocialLogin[] = [ + {name: 'Github', icon: Github}, + {name: 'Google', icon: GoogleLogo}, + {name: 'Apple', icon: Apple}, +] + +const LoginRegister = () => { + + const [activeTab, setActiveTab] = useState<'Login' | 'Register'>('Login'); + + const socialLoginHandlers = (name: SocialLogin['name']) => { + return { + 'Github': () => { + console.log('Github login'); + }, + 'Google': () => { + console.log('Google login'); + }, + 'Apple': () => { + console.log('Apple login'); + } + }[name](); + } + + return ( + +
+ {Tabs.map((text) => ( +
{ + setActiveTab(text) + }} className={clsx("relative flex-1 border-b border-app-line p-2.5 text-center", + text === 'Login' ? 'rounded-tl-md' : 'rounded-tr-md', + )}> +

{text}

+ {text === activeTab && ( + + )} +
+ ))} +
+
+ {activeTab === 'Login' ? : } +
+ +

OR

+ +
+
+ {SocialLogins.map((social) => ( + +
socialLoginHandlers(social.name)} key={social.name} className='rounded-full border border-app-line bg-app-input p-3'> + +
+
+ ))} +
+
+
+ ) +} + +const Register = () => { + + // useZodForm seems to be out-dated or needs + //fixing as it does not support the schema using zod.refine + const form = useForm( + { + resolver: zodResolver(RegisterSchema), + defaultValues: { + email: '', + password: '', + confirmPassword: '', + } + }) + return ( +
{ + // handle login submission + return console.log(data); + })} + form={form} + > +
+ ( + + )} + /> + {form.formState.errors.email && ( +

{form.formState.errors.email.message}

+ )} + ( + + )} + /> + {form.formState.errors.password && ( +

{form.formState.errors.password.message}

+ )} + ( + + )} + /> + {form.formState.errors.confirmPassword && ( +

{form.formState.errors.confirmPassword.message}

+ )} + +
+
+ ) +} + +const Login = () => { + const form = useZodForm( + { + schema: LoginSchema, + defaultValues: { + email: '', + password: '', + } + }) + return ( +
{ + // handle login submission + console.log(data); + })} + form={form} + > +
+ ( + + )} + /> + {form.formState.errors.email && ( +

{form.formState.errors.email.message}

+ )} + ( + + )} + /> + {form.formState.errors.password && ( +

{form.formState.errors.password.message}

+ )} + +
+
+ ) +} + +export default LoginRegister; diff --git a/interface/app/$libraryId/settings/client/account/Profile.tsx b/interface/app/$libraryId/settings/client/account/Profile.tsx new file mode 100644 index 000000000..e44289dfa --- /dev/null +++ b/interface/app/$libraryId/settings/client/account/Profile.tsx @@ -0,0 +1,31 @@ +import { Envelope } from "@phosphor-icons/react"; +import { Card } from '@sd/ui'; +import { TruncatedText } from "~/components"; +import { AuthRequiredOverlay } from "~/components/AuthRequiredOverlay"; + + +const Profile = ({ email, authStore }: { email?: string; authStore: { status: string } }) => { + const emailName = authStore.status === 'loggedIn' ? email?.split('@')[0] : 'guest user'; + return ( + + +
+

+ Welcome {emailName}, +

+
+ +
+ +
+ + {authStore.status === 'loggedIn' ? email : 'guestuser@outlook.com'} + +
+
+
+
+ ); +}; + +export default Profile; diff --git a/interface/app/$libraryId/settings/client/account.tsx b/interface/app/$libraryId/settings/client/account/index.tsx similarity index 73% rename from interface/app/$libraryId/settings/client/account.tsx rename to interface/app/$libraryId/settings/client/account/index.tsx index 78be76179..d02002e83 100644 --- a/interface/app/$libraryId/settings/client/account.tsx +++ b/interface/app/$libraryId/settings/client/account/index.tsx @@ -1,12 +1,11 @@ -import { Envelope, User } from '@phosphor-icons/react'; -import { useEffect, useState } from 'react'; import { auth, useBridgeMutation, useBridgeQuery, useFeatureFlag } from '@sd/client'; -import { Button, Card, Input, toast } from '@sd/ui'; -import { TruncatedText } from '~/components'; -import { AuthRequiredOverlay } from '~/components/AuthRequiredOverlay'; +import { Button, Input, toast } from '@sd/ui'; +import { useEffect, useState } from 'react'; import { useLocale } from '~/hooks'; -import { Heading } from '../Layout'; +import { Heading } from '../../Layout'; +import LoginRegister from './LoginRegister'; +import Profile from './Profile'; export const Component = () => { const { t } = useLocale(); @@ -30,41 +29,17 @@ export const Component = () => { description={t('spacedrive_cloud_description')} />
- + {authStore.status === 'notLoggedIn' ? ( + + ) : ( + + )}
{useFeatureFlag('hostedLocations') && } ); }; -const Profile = ({ email, authStore }: { email?: string; authStore: { status: string } }) => { - const emailName = authStore.status === 'loggedIn' ? email?.split('@')[0] : 'guest user'; - return ( - - -
- -
-

- Welcome {emailName}, -

-
- -
- -
- - {authStore.status === 'loggedIn' ? email : 'guestuser@outlook.com'} - -
-
-
- ); -}; - function HostedLocationsPlayground() { const locations = useBridgeQuery(['cloud.locations.list'], { retry: false });