Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

User Management #45

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
47 changes: 47 additions & 0 deletions components/CenteredThemeBackground/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import Box from '@mui/material/Box'
import Layout from 'components/Layout'
import { ReactNode } from 'react'
import mr_logo from 'public/images/sidebar/mercy_relief_logo.png'
import { MR_GRAY_1 } from 'styles/theme'

type CenteredThemeBackgroundProps = {
children: ReactNode
}

// TODO get actual image
const BACKGROUND_IMAGE = 'red'

function CenteredThemeBackground({ children }: CenteredThemeBackgroundProps) {
return (
<Layout enableSidebar={false}>
<Box sx={{ display: 'flex', flex: 1, background: BACKGROUND_IMAGE }}>
<Box
sx={{
display: 'flex',
flex: 1,
flexDirection: 'column',
margin: 'auto',
maxWidth: 500,
paddingRight: { sm: 8, xs: 2 },
paddingLeft: { sm: 8, xs: 2 },
paddingTop: 20,
paddingBottom: 20,
borderRadius: { sm: 4, xs: 0 },
background: MR_GRAY_1,
}}
>
<Box
component="img"
src={mr_logo.src}
alt="Mercy Relief Logo"
style={{ objectFit: 'fill', margin: 'auto', width: '50%' }}
/>
{children}
</Box>
</Box>
</Layout>
)
}
3

export default CenteredThemeBackground
39 changes: 25 additions & 14 deletions components/Layout/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import Head from 'next/head'
import { ReactNode } from 'react'
import { Fragment, ReactNode } from 'react'
import theme from 'styles/theme'
import { ThemeProvider } from '@mui/material/styles'
import CssBaseline from '@mui/material/CssBaseline'
Expand All @@ -8,9 +8,31 @@ import { Box } from '@mui/system'

type Props = {
children: ReactNode
enableSidebar?: boolean
}

const Layout = ({ children }: Props) => {
const Layout = ({ children, enableSidebar }: Props) => {
enableSidebar = enableSidebar ?? true

const sidebarWithChildren = !enableSidebar ? (
children
) : (
<Fragment>
<Sidebar />
<Box
component="main"
sx={{
flexGrow: 1,
margin: '0 24px',
height: '100%',
maxWidth: `calc(100vw - ${DRAWER_WIDTH}px - 48px)`,
}}
>
{children}
</Box>
</Fragment>
)

return (
<div>
<Head>
Expand All @@ -33,18 +55,7 @@ const Layout = ({ children }: Props) => {
}}
>
<CssBaseline />
<Sidebar />
<Box
component="main"
sx={{
flexGrow: 1,
margin: '0 24px',
height: '100%',
maxWidth: `calc(100vw - ${DRAWER_WIDTH}px - 48px)`,
}}
>
{children}
</Box>
{sidebarWithChildren}
</Box>
</ThemeProvider>
</main>
Expand Down
22 changes: 16 additions & 6 deletions pages/_app.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
import type { ReactElement, ReactNode } from 'react'
import type { NextPage } from 'next'
import type { AppProps } from 'next/app'
import Layout from 'components/Layout'

function MyApp({ Component, pageProps }: AppProps) {
return (
<Layout>
<Component {...pageProps} />
</Layout>
)
// ref: https://nextjs.org/docs/basic-features/layouts
export type NextPageWithLayout<P = unknown, IP = P> = NextPage<P, IP> & {
getLayout?: (page: ReactElement) => ReactNode
}

type AppPropsWithLayout = AppProps & {
Component: NextPageWithLayout
}

function MyApp({ Component, pageProps }: AppPropsWithLayout) {
// Use the layout defined at the page level, if available
const getLayout = Component.getLayout ?? ((page) => <Layout>{page}</Layout>)

return getLayout(<Component {...pageProps} />)
}

export default MyApp
23 changes: 23 additions & 0 deletions pages/dashboard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import type {NextPage} from "next";
import Box from "@mui/material/Box";
import Sidebar from "../components/Sidebar";
import Typography from "@mui/material/Typography";

// TODO: make these into properties pulled from the current user
const name = "John";
const role = "Super Admin";

const Dashboard: NextPage = () => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

think for this page u don't need to add the sidebar? also what is this page suppose to be? if its the first landing page i think u can move this to index
Screen Shot 2023-02-01 at 6 58 34 PM

return (
/* TODO: This minHeight should be unnecessary when the layout is flex */
<Box sx={{ minHeight: '100vh', display: 'flex' }}>
<Sidebar/>
<Box>
<Typography sx={{ marginTop: 2 }} variant="h6">{`Welcome, ${name}!`}</Typography>
<Typography sx={{ marginTop: 1 }} variant="subtitle2">{`Role: ${role}`}</Typography>
</Box>
</Box>
)
}

export default Dashboard;
35 changes: 35 additions & 0 deletions pages/forgot-password.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import Box from '@mui/material/Box'
import Typography from '@mui/material/Typography'
import Button from '@mui/material/Button'
import TextField from '@mui/material/TextField'
import type { NextPageWithLayout } from './_app'
import CenteredThemeBackground from 'components/CenteredThemeBackground'

const ForgotPassword: NextPageWithLayout = () => {
return (
<Box sx={{ display: 'flex', flexDirection: 'column' }}>
<Typography
sx={{ marginTop: 3, marginBottom: 1, alignSelf: 'center' }}
variant="subtitle1"
fontWeight="bold"
>
Request for Password Reset
</Typography>
<TextField
sx={{ marginTop: 2 }}
id="email"
label="Email Address"
type="email"
/>
<Button sx={{ marginTop: 2 }} variant="contained">
Send Reset Link
</Button>
</Box>
)
}

ForgotPassword.getLayout = (page) => {
return <CenteredThemeBackground>{page}</CenteredThemeBackground>
}

export default ForgotPassword
40 changes: 40 additions & 0 deletions pages/login.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import Box from '@mui/material/Box'
import Typography from '@mui/material/Typography'
import Button from '@mui/material/Button'
import TextField from '@mui/material/TextField'
import type { NextPageWithLayout } from './_app'
import CenteredThemeBackground from 'components/CenteredThemeBackground'
import Link from 'next/link'
import Alert from '@mui/material/Alert'

const Login: NextPageWithLayout = () => {
return (
<Box sx={{ display: 'flex', flexDirection: 'column' }}>
<TextField sx={{ marginTop: 12 }} id="email" label="Email Address" />
<TextField
sx={{ marginTop: 3, marginBottom: 2 }}
id="password"
label="Password"
type="password"
/>
<Link href="/ForgotPassword">Forget Password?</Link>
<Button sx={{ marginTop: 3 }} variant="contained">
SIGN IN
</Button>
<Alert sx={{ marginTop: 3 }} severity="error">
<Typography variant="subtitle2" fontWeight="bold">
Login Failed!
</Typography>
<Typography variant="body2">
Email address/password not found
</Typography>
</Alert>
</Box>
)
}

Login.getLayout = (page) => {
return <CenteredThemeBackground>{page}</CenteredThemeBackground>
}

export default Login
41 changes: 41 additions & 0 deletions pages/reset-password.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import Box from '@mui/material/Box'
import Typography from '@mui/material/Typography'
import Button from '@mui/material/Button'
import TextField from '@mui/material/TextField'
import type { NextPageWithLayout } from './_app'
import CenteredThemeBackground from 'components/CenteredThemeBackground'

const ResetPassword: NextPageWithLayout = () => {
return (
<Box sx={{ display: 'flex', flexDirection: 'column' }}>
<Typography
sx={{ marginTop: 3, marginBottom: 1 }}
variant="subtitle1"
fontWeight="bold"
>
Reset Password
</Typography>
<TextField
sx={{ marginTop: 2 }}
id="new-password"
label="New Password"
type="password"
/>
<TextField
sx={{ marginTop: 2 }}
id="confirm-new-password"
label="Confirm New Password"
type="password"
/>
<Button sx={{ marginTop: 2 }} variant="contained">
Reset Password
</Button>
</Box>
)
}

ResetPassword.getLayout = (page) => {
return <CenteredThemeBackground>{page}</CenteredThemeBackground>
}

export default ResetPassword
74 changes: 74 additions & 0 deletions pages/settings.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import type { NextPage } from 'next'
import Box from '@mui/material/Box'
import Tabs from '@mui/material/Tabs'
import Tab from '@mui/material/Tab'
import { ReactNode, useState } from 'react'
import Person from '@mui/icons-material/Person'
import TextField from '@mui/material/TextField'
import Button from '@mui/material/Button'
import Alert from '@mui/material/Alert'
import Lock from '@mui/icons-material/Lock'
import Container from '@mui/material/Container'

const Account = () => {
return (
<Box sx={{ display: 'flex', flexDirection: 'column' }}>
{/* TODO Prefill based on Account information */}
<Box component="img" src="unlinked"></Box>
<TextField sx={{ marginTop: 2 }} label="Full Name" />
<TextField sx={{ marginTop: 2 }} label="Email Address" />
<Button sx={{ marginTop: 2, alignSelf: 'end' }} variant="contained">
Save Changes
</Button>
</Box>
)
}

const ChangePassword = () => {
return (
<Box>
<Button sx={{ marginTop: 2 }} variant="contained">
Request for password reset
</Button>
<Alert sx={{ marginTop: 2 }} severity="info">
A reset link has been sent to your email!
</Alert>
</Box>
)
}

interface IconTextProps {
icon: ReactNode
text: string
}

const IconText = ({ icon, text }: IconTextProps) => {
return (
<Box sx={{ display: 'inline-flex', alignItems: 'center' }}>
{icon}
<Box sx={{ marginLeft: 1 }}>{text}</Box>
</Box>
)
}

const Settings: NextPage = () => {
const [value, setValue] = useState(0)
return (
<Container sx={{ display: 'flex', flexDirection: 'column', flex: 1 }}>
<Box sx={{ flex: 1, paddingTop: 20, margin: 'auto 0' }}>
<Tabs value={value} onChange={(_, v) => setValue(v)}>
<Tab label={<IconText icon={<Person />} text="Account" />} />
<Tab label={<IconText icon={<Lock />} text="Change Password" />} />
</Tabs>
<Box hidden={value !== 0}>
<Account />
</Box>
<Box hidden={value !== 1}>
<ChangePassword />
</Box>
</Box>
</Container>
)
}

export default Settings
Loading