Skip to content

Commit

Permalink
Setup router (#7)
Browse files Browse the repository at this point in the history
  • Loading branch information
ardier16 authored Dec 29, 2023
1 parent 2849088 commit fc4d7b9
Show file tree
Hide file tree
Showing 17 changed files with 241 additions and 130 deletions.
10 changes: 5 additions & 5 deletions src/common/AppNavbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import { ButtonProps, Divider, Stack } from '@mui/material'
import { ReactNode, useMemo } from 'react'
import { NavLink, useLocation } from 'react-router-dom'

import { Icons, Routes } from '@/enums'
import { Icons, RoutePaths } from '@/enums'
import { UiButton, UiIcon } from '@/ui'

interface NavbarLinkProps {
to: Routes
to: RoutePaths
children: ReactNode
}

Expand Down Expand Up @@ -37,15 +37,15 @@ const NavbarLink = ({ children, to }: NavbarLinkProps) => {
const AppNavbar = () => {
const navbarItems = useMemo(
() => [
{ route: Routes.Profiles, iconComponent: <UiIcon name={Icons.Wallet} size={6} /> },
{ route: Routes.Orgs, iconComponent: <UiIcon componentName='work' size={6} /> },
{ route: RoutePaths.Profiles, iconComponent: <UiIcon name={Icons.Wallet} size={6} /> },
{ route: RoutePaths.Orgs, iconComponent: <UiIcon componentName='work' size={6} /> },
],
[],
)

return (
<Stack spacing={4} py={1}>
<NavLink to={Routes.Profiles}>
<NavLink to={RoutePaths.Profiles}>
<Stack alignItems='center'>
<img src='/branding/logo.svg' alt={config.APP_NAME} />
</Stack>
Expand Down
13 changes: 9 additions & 4 deletions src/enums/routes.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
export enum Routes {
export enum RoutePaths {
Root = '/',
UiKit = '/ui-kit',
Profiles = '/profiles',
// FIXME: how to avoid * in the path?
Orgs = '/organisations/*',
OrgNew = '/organisations/new',
SignIn = '/sign-in',

Orgs = '/organisations',
OrgsList = '/organisations/list',
OrgsListAll = '/organisations/list/all',
OrgsListMy = '/organisations/list/my',
OrgsNew = '/organisations/new',
OrgsId = '/organisations/:id',
OrgsIdCheckProof = '/organisations/:id/check-proof',
}
1 change: 1 addition & 0 deletions src/helpers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ export * from './error-handler'
export * from './event-bus'
export * from './metamask'
export * from './promise'
export * from './router'
export * from './store'
3 changes: 3 additions & 0 deletions src/helpers/router.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const createDeepPath = (path: string) => {
return path.endsWith('*') ? path : `${path}/*`
}
1 change: 1 addition & 0 deletions src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export * from './interval'
export * from './loading'
export * from './metamask-zkp-snap'
export * from './provider'
export * from './router'
export * from './theme'
export * from './viewport'
export * from './web3'
15 changes: 15 additions & 0 deletions src/hooks/router.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { RouteObject, useRoutes } from 'react-router-dom'

import { RoutePaths } from '@/enums'
import { createDeepPath } from '@/helpers'

// HACK: reqact-router v6 doesn't support absolute paths in the nested routes
// Discussion: https://github.com/remix-run/react-router/discussions/9841
export const useNestedRoutes = (root: RoutePaths, routes: RouteObject[]) => {
return useRoutes(
routes.map(({ path, ...rest }) => ({
path: path && createDeepPath(path.replace(root, '')),
...rest,
})),
)
}
123 changes: 22 additions & 101 deletions src/pages/Orgs/index.tsx
Original file line number Diff line number Diff line change
@@ -1,106 +1,27 @@
import { Stack } from '@mui/material'
import { useCallback, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { Navigate, NavLink, Route, Routes } from 'react-router-dom'
import { Navigate } from 'react-router-dom'

import { loadOrgsAmount, OrgsRequestFilters, OrgsRequestFiltersMap } from '@/api'
import { PageListFilters, PageTitles } from '@/common'
import { Routes as RoutesPaths } from '@/enums'
import { useLoading } from '@/hooks'
import { UiButton, UiIcon, UiSwitch } from '@/ui'
import { RoutePaths } from '@/enums'
import { useNestedRoutes } from '@/hooks'

import { List } from './components'

enum OrgsRoutes {
All = 'all',
My = 'my',
}
import { OrgsId, OrgsList, OrgsNew } from './pages'

export default function Orgs() {
const { t } = useTranslation()

const [filter, setFilter] = useState<OrgsRequestFiltersMap>({})

const init = useCallback(async () => {
const { data } = await loadOrgsAmount()

return data
}, [])

const { data: orgsAmount } = useLoading<number | undefined>(undefined, init, {
loadOnMount: true,
})

return (
<Stack flex={1} gap={6}>
<PageTitles title={t('org-list.title')} subtitle={t('org-list.subtitle')} />
<PageListFilters
tabs={[
{
label: `All${orgsAmount ? ` (${orgsAmount})` : ''}`,
route: OrgsRoutes.All,
},
{
label: 'My Organizations',
route: OrgsRoutes.My,
},
]}
onSearchInput={(value: string) =>
setFilter(prev => ({
...prev,

// FIXME: remove this and add searching orgs by name in backend
[OrgsRequestFilters.UserDid]: value,
}))
}
actionBar={
<Stack direction='row' gap={4} justifyContent='space-between'>
<UiSwitch label='Show Only active' />

<NavLink to={RoutesPaths.OrgNew}>
<UiButton
variant='contained'
color='primary'
startIcon={<UiIcon componentName='add' />}
>
New Organization
</UiButton>
</NavLink>
</Stack>
}
/>

<Stack flex={1}>
<Routes>
<Route
path={OrgsRoutes.All}
element={
<List
filter={{
...filter,
}}
/>
}
/>
<Route
path={OrgsRoutes.My}
element={
<List
filter={{
...filter,

/**
* FIXME: get userDid from {@link useMetamaskZkpSnapContext}
*/
[OrgsRequestFilters.UserDid]: 'did:iden3:readonly:blabla',
}}
/>
}
/>

<Route path='*' element={<Navigate replace to={OrgsRoutes.All} />} />
</Routes>
</Stack>
</Stack>
)
return useNestedRoutes(RoutePaths.Orgs, [
{
index: true,
element: <Navigate replace to={RoutePaths.OrgsList} />,
},
{
path: RoutePaths.OrgsList,
element: <OrgsList />,
},
{
path: RoutePaths.OrgsNew,
element: <OrgsNew />,
},
{
path: RoutePaths.OrgsId,
element: <OrgsId />,
},
])
}
17 changes: 17 additions & 0 deletions src/pages/Orgs/pages/OrgsId/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { RoutePaths } from '@/enums'
import { useNestedRoutes } from '@/hooks'

import { OrgCheckProof, OrgRoot } from './pages'

export default function OrgsId() {
return useNestedRoutes(RoutePaths.OrgsId, [
{
index: true,
element: <OrgRoot />,
},
{
path: RoutePaths.OrgsIdCheckProof,
element: <OrgCheckProof />,
},
])
}
14 changes: 14 additions & 0 deletions src/pages/Orgs/pages/OrgsId/pages/OrgCheckProof/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Stack } from '@mui/material'
import { useParams } from 'react-router-dom'

import { PageTitles } from '@/common'

export default function OrgCheckProof() {
const { id } = useParams<{ id: string }>()

return (
<Stack flex={1}>
<PageTitles title={`OrgCheckProof ${id}`} subtitle='Some organization description' />
</Stack>
)
}
22 changes: 22 additions & 0 deletions src/pages/Orgs/pages/OrgsId/pages/OrgRoot/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Box, Stack } from '@mui/material'
import { generatePath, NavLink, useParams } from 'react-router-dom'

import { PageTitles } from '@/common'
import { RoutePaths } from '@/enums'
import { UiButton } from '@/ui'

export default function OrgRoot() {
const { id = null } = useParams<{ id: string }>()

return (
<Stack flex={1}>
<PageTitles title={`Organization ${id}`} subtitle='Some organization description' />

<Box mt={6}>
<NavLink to={generatePath(RoutePaths.OrgsIdCheckProof, { id })}>
<UiButton component='div'>Check proof</UiButton>
</NavLink>
</Box>
</Stack>
)
}
2 changes: 2 additions & 0 deletions src/pages/Orgs/pages/OrgsId/pages/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default as OrgCheckProof } from './OrgCheckProof'
export { default as OrgRoot } from './OrgRoot'
File renamed without changes.
File renamed without changes.
102 changes: 102 additions & 0 deletions src/pages/Orgs/pages/OrgsList/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { Stack } from '@mui/material'
import { useCallback, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { Navigate, NavLink } from 'react-router-dom'

import { loadOrgsAmount, OrgsRequestFilters, OrgsRequestFiltersMap } from '@/api'
import { PageListFilters, PageTitles } from '@/common'
import { RoutePaths } from '@/enums'
import { useLoading, useNestedRoutes } from '@/hooks'
import { UiButton, UiIcon, UiSwitch } from '@/ui'

import { List } from './components'

export default function OrgsList() {
const { t } = useTranslation()

const [filter, setFilter] = useState<OrgsRequestFiltersMap>({})
const routes = useNestedRoutes(RoutePaths.Orgs, [
{
index: true,
element: <Navigate replace to={RoutePaths.OrgsListAll} />,
},
{
path: RoutePaths.OrgsListAll,
element: (
<List
filter={{
...filter,
}}
/>
),
},
{
path: RoutePaths.OrgsListMy,
element: (
<List
filter={{
...filter,

/**
* FIXME: get userDid from {@link useMetamaskZkpSnapContext}
*/
[OrgsRequestFilters.UserDid]: 'did:iden3:readonly:blabla',
}}
/>
),
},
])

const init = useCallback(async () => {
const { data } = await loadOrgsAmount()

return data
}, [])

const { data: orgsAmount } = useLoading<number | undefined>(undefined, init, {
loadOnMount: true,
})

return (
<Stack flex={1} gap={6}>
<PageTitles title={t('org-list.title')} subtitle={t('org-list.subtitle')} />
<PageListFilters
tabs={[
{
label: `All${orgsAmount ? ` (${orgsAmount})` : ''}`,
route: RoutePaths.OrgsListAll,
},
{
label: 'My Organizations',
route: RoutePaths.OrgsListMy,
},
]}
onSearchInput={(value: string) =>
setFilter(prev => ({
...prev,

// FIXME: remove this and add searching orgs by name in backend
[OrgsRequestFilters.UserDid]: value,
}))
}
actionBar={
<Stack direction='row' gap={4} justifyContent='space-between'>
<UiSwitch label='Show Only active' />

<NavLink to={RoutePaths.OrgsNew}>
<UiButton
variant='contained'
color='primary'
startIcon={<UiIcon componentName='add' />}
>
New Organization
</UiButton>
</NavLink>
</Stack>
}
/>

<Stack flex={1}>{routes}</Stack>
</Stack>
)
}
11 changes: 11 additions & 0 deletions src/pages/Orgs/pages/OrgsNew/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Stack } from '@mui/material'

import { PageTitles } from '@/common'

export default function OrgsNew() {
return (
<Stack flex={1}>
<PageTitles title={'New organisation'} />
</Stack>
)
}
3 changes: 3 additions & 0 deletions src/pages/Orgs/pages/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { default as OrgsId } from './OrgsId'
export { default as OrgsList } from './OrgsList'
export { default as OrgsNew } from './OrgsNew'
Loading

0 comments on commit fc4d7b9

Please sign in to comment.