refactor(dashboard): change layout and page of auth to be url based instead of state based
This commit is contained in:
parent
5df9adf3f3
commit
372a76f485
11 changed files with 25 additions and 59 deletions
|
@ -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,
|
||||
|
|
|
@ -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,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');
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -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 };
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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('/');
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -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('/');
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -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,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
src/pages/login.tsx
Normal file
1
src/pages/login.tsx
Normal file
|
@ -0,0 +1 @@
|
|||
export { LoginPage as default } from '../client/modules/Auth/pages/LoginPage';
|
1
src/pages/register.tsx
Normal file
1
src/pages/register.tsx
Normal file
|
@ -0,0 +1 @@
|
|||
export { RegisterPage as default } from '../client/modules/Auth/pages/RegisterPage';
|
Loading…
Add table
Reference in a new issue