Browse Source

refactor(dashboard): change layout and page of auth to be url based instead of state based

Nicolas Meienberger 2 years ago
parent
commit
372a76f485

+ 1 - 0
.eslintrc.js

@@ -31,6 +31,7 @@ module.exports = {
     'react/button-has-type': 0,
     'import/no-extraneous-dependencies': ['error', { devDependencies: ['esbuild.js', '**/*.test.{ts,tsx}', '**/*.spec.{ts,tsx}', '**/*.factory.{ts,tsx}', '**/mocks/**', 'tests/**'] }],
     'no-underscore-dangle': 0,
+    'arrow-body-style': 0,
   },
   globals: {
     JSX: true,

+ 8 - 4
src/client/components/Layout/Layout.tsx

@@ -4,6 +4,7 @@ import React, { useEffect } from 'react';
 import clsx from 'clsx';
 import ReactTooltip from 'react-tooltip';
 import semver from 'semver';
+import { useRouter } from 'next/router';
 import { Header } from '../ui/Header';
 import styles from './Layout.module.scss';
 import { useSystemStore } from '../../state/systemStore';
@@ -18,10 +19,15 @@ interface IProps {
 }
 
 export const Layout: React.FC<IProps> = ({ children, breadcrumbs, title, actions }) => {
+  const router = useRouter();
   const refreshToken = trpc.auth.refreshToken.useMutation({
     onSuccess: (data) => {
       if (data?.token) localStorage.setItem('token', data.token);
     },
+    onError: () => {
+      localStorage.removeItem('token');
+      router.push('/login');
+    },
   });
 
   useEffect(() => {
@@ -52,10 +58,8 @@ export const Layout: React.FC<IProps> = ({ children, breadcrumbs, title, actions
 
   return (
     <div data-testid={`${title?.toLowerCase().split(' ').join('-')}-layout`} className="page">
-      <Head>
-        <title>{title} - Tipi</title>
-      </Head>
-      <ReactTooltip offset={{ right: 1 }} effect="solid" place="bottom" />
+      <Head>{/* <title>{title} - Tipi</title> */}</Head>
+      {/* <ReactTooltip offset={{ right: 1 }} effect="solid" place="bottom" /> */}
       <Header isUpdateAvailable={!isLatest} />
       <div className="page-wrapper">
         <div className="page-header d-print-none">

+ 3 - 0
src/client/components/ui/Header/Header.tsx

@@ -3,6 +3,7 @@ import { IconBrandGithub, IconHeart, IconLogout, IconMoon, IconSun } from '@tabl
 import Image from 'next/image';
 import clsx from 'clsx';
 import Link from 'next/link';
+import { useRouter } from 'next/router';
 import { getUrl } from '../../../core/helpers/url-helpers';
 import { useUIStore } from '../../../state/uiStore';
 import { NavBar } from '../NavBar';
@@ -13,12 +14,14 @@ interface IProps {
 }
 
 export const Header: React.FC<IProps> = ({ isUpdateAvailable }) => {
+  const router = useRouter();
   const { setDarkMode } = useUIStore();
   const utils = trpc.useContext();
   const logout = trpc.auth.logout.useMutation({
     onSuccess: () => {
       localStorage.removeItem('token');
       utils.auth.me.invalidate();
+      router.push('/login');
     },
   });
 

+ 0 - 28
src/client/hooks/useCachedRessources.ts

@@ -1,28 +0,0 @@
-import { useEffect, useState, useCallback } from 'react';
-
-interface IReturnProps {
-  isLoadingComplete?: boolean;
-}
-
-export default function useCachedResources(): IReturnProps {
-  const [isLoadingComplete, setLoadingComplete] = useState(false);
-
-  const loadResourcesAndDataAsync = useCallback(() => {
-    try {
-      // Load any resources or data that we need prior to rendering the app
-    } catch (error) {
-      // We might want to provide this error information to an error reporting service
-      console.error(error);
-    }
-  }, []);
-
-  useEffect(() => {
-    loadResourcesAndDataAsync();
-  }, [loadResourcesAndDataAsync]);
-
-  useEffect(() => {
-    setLoadingComplete(true);
-  }, []);
-
-  return { isLoadingComplete };
-}

+ 4 - 0
src/client/modules/Auth/components/LoginForm/LoginForm.tsx

@@ -2,6 +2,7 @@ import React from 'react';
 import { useForm } from 'react-hook-form';
 import z from 'zod';
 import { zodResolver } from '@hookform/resolvers/zod';
+import Link from 'next/link';
 import { Button } from '../../../../components/ui/Button';
 import { Input } from '../../../../components/ui/Input';
 
@@ -36,6 +37,9 @@ export const LoginForm: React.FC<IProps> = ({ loading, onSubmit }) => {
     <form className="flex flex-col" onSubmit={handleSubmit(onSubmit)}>
       <h2 className="h2 text-center mb-3">Login to your account</h2>
       <Input {...register('email')} label="Email address" error={errors.email?.message} disabled={loading} type="email" className="mb-3" placeholder="you@example.com" />
+      <span className="form-label-description">
+        <Link href="/reset-password">Forgot password?</Link>
+      </span>
       <Input {...register('password')} label="Password" error={errors.password?.message} disabled={loading} type="password" className="mb-3" placeholder="Your password" />
       <Button disabled={isDisabled} loading={loading} type="submit" className="btn btn-primary w-100">
         Login

+ 3 - 0
src/client/modules/Auth/containers/LoginContainer/LoginContainer.tsx

@@ -1,3 +1,4 @@
+import { useRouter } from 'next/router';
 import React from 'react';
 import { useToastStore } from '../../../../state/toastStore';
 import { trpc } from '../../../../utils/trpc';
@@ -7,6 +8,7 @@ import { LoginForm } from '../../components/LoginForm';
 type FormValues = { email: string; password: string };
 
 export const LoginContainer: React.FC = () => {
+  const router = useRouter();
   const { addToast } = useToastStore();
   const utils = trpc.useContext();
   const login = trpc.auth.login.useMutation({
@@ -17,6 +19,7 @@ export const LoginContainer: React.FC = () => {
     onSuccess: (data) => {
       localStorage.setItem('token', data.token);
       utils.auth.me.invalidate();
+      router.push('/');
     },
   });
 

+ 3 - 0
src/client/modules/Auth/containers/RegisterContainer/RegisterContainer.tsx

@@ -1,3 +1,4 @@
+import { useRouter } from 'next/router';
 import React from 'react';
 import { useToastStore } from '../../../../state/toastStore';
 import { trpc } from '../../../../utils/trpc';
@@ -8,6 +9,7 @@ type FormValues = { email: string; password: string };
 
 export const RegisterContainer: React.FC = () => {
   const { addToast } = useToastStore();
+  const router = useRouter();
   const utils = trpc.useContext();
   const register = trpc.auth.register.useMutation({
     onError: (e) => {
@@ -17,6 +19,7 @@ export const RegisterContainer: React.FC = () => {
     onSuccess: (data) => {
       localStorage.setItem('token', data.token);
       utils.auth.me.invalidate();
+      router.push('/');
     },
   });
 

+ 0 - 16
src/client/modules/Auth/pages/ResetPasswordPage.tsx

@@ -1,16 +0,0 @@
-import React from 'react';
-import { ResetPasswordContainer } from '../containers/ResetPasswordContainer/ResetPasswordContainer';
-import { trpc } from '../../../utils/trpc';
-import { ErrorPage } from '../../../components/ui/ErrorPage';
-
-export const ResetPasswordPage = () => {
-  const { data, error } = trpc.auth.checkPasswordChangeRequest.useQuery();
-
-  // TODO: Add loading state
-  return (
-    <>
-      {error && <ErrorPage error={error.message} />}
-      <ResetPasswordContainer isRequested={Boolean(data)} />
-    </>
-  );
-};

+ 1 - 11
src/pages/_app.tsx

@@ -1,14 +1,11 @@
 import React, { useEffect } from 'react';
 import type { AppProps } from 'next/app';
 import Head from 'next/head';
-import useCachedResources from '../client/hooks/useCachedRessources';
 import '../client/styles/global.css';
 import '../client/styles/global.scss';
 import { useUIStore } from '../client/state/uiStore';
 import { ToastProvider } from '../client/components/hoc/ToastProvider';
 import { StatusProvider } from '../client/components/hoc/StatusProvider';
-import { AuthProvider } from '../client/components/hoc/AuthProvider';
-import { StatusScreen } from '../client/components/StatusScreen';
 import { trpc } from '../client/utils/trpc';
 import { SystemStatus, useSystemStore } from '../client/state/systemStore';
 
@@ -39,11 +36,6 @@ function MyApp({ Component, pageProps }: AppProps) {
     themeCheck();
   }, [setDarkMode]);
 
-  const { isLoadingComplete } = useCachedResources();
-  if (!isLoadingComplete) {
-    return <StatusScreen title="" subtitle="" />;
-  }
-
   return (
     <main className="h-100">
       <Head>
@@ -51,9 +43,7 @@ function MyApp({ Component, pageProps }: AppProps) {
       </Head>
       <ToastProvider>
         <StatusProvider>
-          <AuthProvider>
-            <Component {...pageProps} />
-          </AuthProvider>
+          <Component {...pageProps} />
         </StatusProvider>
       </ToastProvider>
     </main>

+ 1 - 0
src/pages/login.tsx

@@ -0,0 +1 @@
+export { LoginPage as default } from '../client/modules/Auth/pages/LoginPage';

+ 1 - 0
src/pages/register.tsx

@@ -0,0 +1 @@
+export { RegisterPage as default } from '../client/modules/Auth/pages/RegisterPage';