diff --git a/apps/platform/src/components/common/logo.component.tsx b/apps/platform/src/components/common/logo.component.tsx new file mode 100644 index 0000000..8de7654 --- /dev/null +++ b/apps/platform/src/components/common/logo.component.tsx @@ -0,0 +1,201 @@ +export const LogoComponent = () => ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +) diff --git a/apps/platform/src/layouts/private.layout.tsx b/apps/platform/src/layouts/private.layout.tsx new file mode 100644 index 0000000..ee182bc --- /dev/null +++ b/apps/platform/src/layouts/private.layout.tsx @@ -0,0 +1,63 @@ +import React, { FC } from 'react' +import useSession from '../hooks/useSession' +import { Link, useNavigate } from 'react-router-dom' +import { toast } from 'react-toastify' +import { clearAuthState, pages, useLogoutPerformForm } from '@isomera/impl' +import { LogoComponent } from '../components/common/logo.component' + +interface Props { + children: React.ReactNode | React.ReactNode[] +} + +export const PrivateLayout: FC = ({ children }) => { + const { user, setUser } = useSession() + const navigate = useNavigate() + + const onSuccess = (message: string) => { + toast.success(message) + setUser(undefined) + clearAuthState() + navigate(pages.login.path) + } + + const onError = (message: string) => { + toast.error(message) + } + + const { handleClick } = useLogoutPerformForm(onSuccess, onError) + + return ( + <> + +
{children}
+ + ) +} diff --git a/apps/platform/src/layouts/public.layout.tsx b/apps/platform/src/layouts/public.layout.tsx new file mode 100644 index 0000000..058d4c7 --- /dev/null +++ b/apps/platform/src/layouts/public.layout.tsx @@ -0,0 +1,13 @@ +import React, { FC } from 'react' + +interface Props { + children: React.ReactNode | React.ReactNode[] +} + +export const PublicLayout: FC = ({ children }) => { + return ( +
+
{children}
+
+ ) +} diff --git a/apps/platform/src/router/privateRoute.tsx b/apps/platform/src/router/privateRoute.tsx index 01b8ddd..90d1206 100644 --- a/apps/platform/src/router/privateRoute.tsx +++ b/apps/platform/src/router/privateRoute.tsx @@ -20,7 +20,7 @@ function PrivateRoute(props: Props) { return } - return
{children}
+ return <>{children} } export default PrivateRoute diff --git a/apps/platform/src/router/publicRoute.tsx b/apps/platform/src/router/publicRoute.tsx index ae54119..eb40380 100644 --- a/apps/platform/src/router/publicRoute.tsx +++ b/apps/platform/src/router/publicRoute.tsx @@ -13,10 +13,10 @@ function PublicRoute(props: Props) { const { isAuthenticated } = useSession() if (isAuthenticated) { - return + return } - return
{children}
+ return <>{children} } export default PublicRoute diff --git a/apps/platform/src/router/router.tsx b/apps/platform/src/router/router.tsx index a6a72bd..15df109 100644 --- a/apps/platform/src/router/router.tsx +++ b/apps/platform/src/router/router.tsx @@ -11,6 +11,8 @@ import { VerificationCodeView } from '../views/auth/verificationCode.view' import { Routes, Route } from 'react-router-dom' import PrivateRoute from './privateRoute' +import { PublicLayout } from '../layouts/public.layout' +import { PrivateLayout } from '../layouts/private.layout' function Router() { return ( @@ -19,7 +21,9 @@ function Router() { path="/" element={ -
+ +
...
+
} /> @@ -28,8 +32,10 @@ function Router() { path={pages.verificationCode.path} element={ - - Sign In + + + Sign In + } /> @@ -38,8 +44,10 @@ function Router() { path={pages.passwordResetRequestConfirmation.path} element={ - - Sign In + + + Sign In + } /> @@ -48,18 +56,22 @@ function Router() { path={pages.passwordResetRequest.path} element={ - - Sign In + + + Sign In + } /> - - Sign in + + + Sign in + } /> @@ -68,9 +80,11 @@ function Router() { path={pages.login.path} element={ - - Sign Up - Forgot password + + + Sign Up + Forgot password + } /> @@ -79,7 +93,9 @@ function Router() { path={pages.userInfo.path} element={ - + + + } /> diff --git a/apps/platform/src/styles.scss b/apps/platform/src/styles.scss index 90d4ee0..f55fb5d 100644 --- a/apps/platform/src/styles.scss +++ b/apps/platform/src/styles.scss @@ -1 +1,209 @@ /* You can add global styles to this file, and also import other style files */ + +/* Reset CSS */ +html, +body, +div, +span, +applet, +object, +iframe, +h1, +h2, +h3, +h4, +h5, +h6, +p, +blockquote, +pre, +a, +abbr, +acronym, +address, +big, +cite, +code, +del, +dfn, +em, +img, +ins, +kbd, +q, +s, +samp, +small, +strike, +strong, +sub, +sup, +tt, +var, +b, +u, +i, +center, +dl, +dt, +dd, +ol, +ul, +li, +fieldset, +form, +label, +legend, +table, +caption, +tbody, +tfoot, +thead, +tr, +th, +td, +article, +aside, +canvas, +details, +embed, +figure, +figcaption, +footer, +header, +hgroup, +menu, +nav, +output, +ruby, +section, +summary, +time, +mark, +audio, +video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; +} +/* HTML5 display-role reset for older browsers */ +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +menu, +nav, +section { + display: block; +} +body { + line-height: 1; +} +ol, +ul { + list-style: none; +} +blockquote, +q { + quotes: none; +} +blockquote:before, +blockquote:after, +q:before, +q:after { + content: ''; + content: none; +} +table { + border-collapse: collapse; + border-spacing: 0; +} +body, +html, +#root { + height: 100%; +} + +/* Implement example styles */ +nav.nav_top { + padding: 16px 32px; + border-bottom: thin solid gray; + display: flex; + flex-direction: row; + gap: 8px; + justify-content: space-between; + align-items: center; + + .nav_left { + display: flex; + flex-direction: row; + gap: 8px; + align-items: center; + + .nav_logo_wrapper { + margin-right: 16px; + + svg { + width: 115px; + } + } + } + .nav_right { + display: flex; + flex-direction: row; + gap: 8px; + align-items: center; + } + + .nav_logout_button { + } +} + +main { + padding: 32px; +} + +.public_layout { + font-family: inherit; + line-height: inherit; + margin: 0; + height: 100%; + + background: radial-gradient( + 62.43% 70.59% at 50% 1.48%, + #00303d 0%, + #010d19 100% + ); + background-repeat: no-repeat; + background-position: top center; + background-size: cover; + + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + gap: 32px; + + a { + color: #34aadc; + display: block; + } + + form { + background-color: rgba(255, 255, 255, 0.8); + padding: 32px; + border-radius: 32px; + margin-bottom: 32px; + + label { + display: block; + } + } +} diff --git a/apps/platform/src/views/auth/signIn.view.tsx b/apps/platform/src/views/auth/signIn.view.tsx index 635deda..d6e9d22 100644 --- a/apps/platform/src/views/auth/signIn.view.tsx +++ b/apps/platform/src/views/auth/signIn.view.tsx @@ -1,13 +1,16 @@ -import { useSignInFormHook } from '@isomera/impl' +import { pages, useHandleErrorHook, useSignInFormHook } from '@isomera/impl' import { UserInterface } from '@isomera/interfaces' import useSession from '../../hooks/useSession' +import { useNavigate } from 'react-router-dom' export const SignInView = () => { const { setUser } = useSession() + const navigate = useNavigate() + const { handleError } = useHandleErrorHook() - // const from = (location.state?.from.pathname as string) || '/profile' const onSuccess = (data: UserInterface) => { setUser(data) + navigate(pages.dashboard.path) } const { @@ -18,28 +21,10 @@ export const SignInView = () => { touched, handleSubmit, isSubmitting - } = useSignInFormHook(onSuccess) - - // useEffect(() => { - // if (isSuccess) { - // toast.success('You successfully logged in') - // navigate(from) - // } - // if (isError) { - // if (Array.isArray((error as any).data.error)) { - // ;(error as any).data.error.forEach((el: any) => - // toast.error(el.message, { - // position: 'top-right' - // }) - // ) - // } else { - // toast.error((error as any).data.message, { - // position: 'top-right' - // }) - // } - // } - // // eslint-disable-next-line react-hooks/exhaustive-deps - // }, [isLoading]) + } = useSignInFormHook({ + onSuccess, + onError: error => handleError(error, { view: 'login' }) + }) return (
diff --git a/apps/platform/src/views/auth/signUp.view.tsx b/apps/platform/src/views/auth/signUp.view.tsx index b1890b9..53bad42 100644 --- a/apps/platform/src/views/auth/signUp.view.tsx +++ b/apps/platform/src/views/auth/signUp.view.tsx @@ -1,6 +1,14 @@ -import { useSignUpFormHook } from '@isomera/impl' +import { pages, useHandleErrorHook, useSignUpFormHook } from '@isomera/impl' +import { useNavigate } from 'react-router-dom' export const SignUpView = () => { + const { handleError } = useHandleErrorHook() + const navigate = useNavigate() + + const onSuccess = () => { + navigate(pages.verificationCode.path) + } + const { values, handleChange, @@ -9,8 +17,11 @@ export const SignUpView = () => { touched, handleSubmit, isSubmitting - } = useSignUpFormHook() - console.log('val', values) + } = useSignUpFormHook({ + onSuccess, + onError: error => handleError(error, { view: 'login' }) + }) + return (
diff --git a/apps/platform/src/views/user /info.view.tsx b/apps/platform/src/views/user /info.view.tsx index bd24d05..eec6090 100644 --- a/apps/platform/src/views/user /info.view.tsx +++ b/apps/platform/src/views/user /info.view.tsx @@ -1,35 +1,13 @@ -import { clearAuthState, pages, useLogoutPerformForm } from '@isomera/impl' -import { toast } from 'react-toastify' import useSession from '../../hooks/useSession' -import { useNavigate } from 'react-router-dom' export const UserInfoView = () => { - const { user, setUser } = useSession() - const navigate = useNavigate() - - const onSuccess = (message: string) => { - toast.success(message) - setUser(undefined) - clearAuthState() - navigate(pages.login.path) - } - - const onError = (message: string) => { - toast.error(message) - } - - const { handleClick } = useLogoutPerformForm(onSuccess, onError) + const { user } = useSession() return (
Profile here
First Name: {user?.firstName}
Last Name: {user?.lastName}
-
- -
) } diff --git a/libs/impl/src/constants/pages.ts b/libs/impl/src/constants/pages.ts index 51535a3..6b07f7b 100644 --- a/libs/impl/src/constants/pages.ts +++ b/libs/impl/src/constants/pages.ts @@ -3,7 +3,7 @@ export const pages = { path: '/login' }, register: { - path: '/register' + path: '/sign-up' }, dashboard: { path: '/' diff --git a/libs/impl/src/hooks/auth/useSignInForm.hook.ts b/libs/impl/src/hooks/auth/useSignInForm.hook.ts index 68ebdfc..bfe8ac6 100644 --- a/libs/impl/src/hooks/auth/useSignInForm.hook.ts +++ b/libs/impl/src/hooks/auth/useSignInForm.hook.ts @@ -1,11 +1,6 @@ import { useFormik } from 'formik' - -import { useNavigate } from 'react-router-dom' - -import { pages } from '../../constants/pages' import { useSignInHook } from './useSignIn.hook' import { formikValidate, SignInWithEmailCredentialsDto } from '@isomera/dtos' -import { useHandleErrorHook } from '../error/useHandleError.hook' import { LoginResponseInterface, Pure } from '@isomera/interfaces' const initialValues: Pure = { @@ -13,20 +8,20 @@ const initialValues: Pure = { password: '' } -export const useSignInFormHook = ( - onSuccess: (arg0: LoginResponseInterface) => void -) => { +interface Options { + onSuccess?: (arg0: LoginResponseInterface) => void + onError?: (error?: unknown) => void +} + +export const useSignInFormHook = (options: Options) => { const { login } = useSignInHook() - const { handleError } = useHandleErrorHook() - const navigate = useNavigate() const onSubmit = async (values: typeof initialValues) => { try { const data = await login(values) - onSuccess(data) - navigate(pages.userInfo.path) + options.onSuccess && options.onSuccess(data) } catch (error) { - handleError(error, { view: 'login' }) + options.onError && options.onError(error) } } diff --git a/libs/impl/src/hooks/auth/useSignUpForm.hook.ts b/libs/impl/src/hooks/auth/useSignUpForm.hook.ts index 68e0322..3dfca84 100644 --- a/libs/impl/src/hooks/auth/useSignUpForm.hook.ts +++ b/libs/impl/src/hooks/auth/useSignUpForm.hook.ts @@ -1,10 +1,5 @@ import { useFormik } from 'formik' - -import { useNavigate } from 'react-router-dom' - -import { pages } from '../../constants/pages' import { formikValidate, SignUpWithEmailCredentialsDto } from '@isomera/dtos' -import { useHandleErrorHook } from '../error/useHandleError.hook' import { Pure } from '@isomera/interfaces' import { useSignUpHook } from './useSignUp.hook' @@ -16,17 +11,20 @@ const initialValues: Pure = { isPrivacyPolicyAccepted: undefined } -export const useSignUpFormHook = () => { +interface Options { + onSuccess?: () => void + onError?: (error?: unknown) => void +} + +export const useSignUpFormHook = (options: Options) => { const { register } = useSignUpHook() - const { handleError } = useHandleErrorHook() - const navigate = useNavigate() const onSubmit = async (values: typeof initialValues) => { try { await register(values) - navigate(pages.verificationCode.path) + options.onSuccess && options.onSuccess() } catch (error) { - handleError(error, { view: 'login' }) + options.onError && options.onError(error) } }