Files
modeling-app/src/Router.tsx

187 lines
4.7 KiB
TypeScript
Raw Normal View History

2023-07-27 18:59:40 -04:00
import { App } from './App'
import {
createBrowserRouter,
Outlet,
redirect,
RouterProvider,
} from 'react-router-dom'
2023-07-27 18:59:40 -04:00
import { ErrorPage } from './components/ErrorPage'
import { Settings } from './routes/Settings'
import Onboarding, {
onboardingRoutes,
onboardingPaths,
} from './routes/Onboarding'
2023-07-27 18:59:40 -04:00
import SignIn from './routes/SignIn'
import { Auth } from './Auth'
import { isTauri } from './lib/isTauri'
import Home from './routes/Home'
import { FileEntry, readDir, readTextFile } from '@tauri-apps/api/fs'
import makeUrlPathRelative from './lib/makeUrlPathRelative'
import {
initializeProjectDirectory,
isProjectDirectory,
PROJECT_ENTRYPOINT,
} from './lib/tauriFS'
import { metadata, type Metadata } from 'tauri-plugin-fs-extra-api'
import DownloadAppBanner from './components/DownloadAppBanner'
2023-07-27 18:59:40 -04:00
const prependRoutes =
(routesObject: Record<string, string>) => (prepend: string) => {
return Object.fromEntries(
Object.entries(routesObject).map(([constName, path]) => [
constName,
prepend + path,
])
)
}
export const paths = {
INDEX: '/',
HOME: '/home',
FILE: '/file',
SETTINGS: '/settings',
SIGN_IN: '/signin',
ONBOARDING: prependRoutes(onboardingPaths)(
'/onboarding'
) as typeof onboardingPaths,
}
export type IndexLoaderData = {
code: string | null
project?: ProjectWithEntryPointMetadata
}
export type ProjectWithEntryPointMetadata = FileEntry & {
entrypoint_metadata: Metadata
}
export type HomeLoaderData = {
projects: ProjectWithEntryPointMetadata[]
}
2023-07-27 18:59:40 -04:00
const router = createBrowserRouter([
{
path: paths.INDEX,
loader: () =>
isTauri() ? redirect(paths.HOME) : redirect(paths.FILE + '/new'),
},
{
path: paths.FILE + '/:id',
2023-07-27 18:59:40 -04:00
element: (
<Auth>
<Outlet />
2023-07-27 18:59:40 -04:00
<App />
{!isTauri() && import.meta.env.PROD && <DownloadAppBanner />}
2023-07-27 18:59:40 -04:00
</Auth>
),
errorElement: <ErrorPage />,
id: paths.FILE,
loader: async ({
request,
params,
}): Promise<IndexLoaderData | Response> => {
2023-07-27 18:59:40 -04:00
const store = localStorage.getItem('store')
if (store === null) {
return redirect(paths.ONBOARDING.INDEX)
2023-07-27 18:59:40 -04:00
} else {
const status = JSON.parse(store).state.onboardingStatus || ''
const notEnRouteToOnboarding =
!request.url.includes(paths.ONBOARDING.INDEX) &&
request.method === 'GET'
// '' is the initial state, 'done' and 'dismissed' are the final states
const hasValidOnboardingStatus =
(status !== undefined && status.length === 0) ||
!(status === 'done' || status === 'dismissed')
const shouldRedirectToOnboarding =
notEnRouteToOnboarding && hasValidOnboardingStatus
if (shouldRedirectToOnboarding) {
return redirect(makeUrlPathRelative(paths.ONBOARDING.INDEX) + status)
2023-07-27 18:59:40 -04:00
}
}
if (params.id && params.id !== 'new') {
// Note that PROJECT_ENTRYPOINT is hardcoded until we support multiple files
const code = await readTextFile(params.id + '/' + PROJECT_ENTRYPOINT)
const entrypoint_metadata = await metadata(
params.id + '/' + PROJECT_ENTRYPOINT
)
const children = await readDir(params.id)
return {
code,
project: {
name: params.id.slice(params.id.lastIndexOf('/') + 1),
path: params.id,
children,
entrypoint_metadata,
},
}
}
return {
code: '',
}
2023-07-27 18:59:40 -04:00
},
children: [
{
path: makeUrlPathRelative(paths.SETTINGS),
element: <Settings />,
},
{
path: makeUrlPathRelative(paths.ONBOARDING.INDEX),
element: <Onboarding />,
children: onboardingRoutes,
},
],
2023-07-27 18:59:40 -04:00
},
{
path: paths.HOME,
element: (
<Auth>
<Outlet />
<Home />
</Auth>
),
loader: async () => {
if (!isTauri()) {
return redirect(paths.FILE + '/new')
}
const projectDir = await initializeProjectDirectory()
const projectsNoMeta = (await readDir(projectDir.dir)).filter(
isProjectDirectory
)
const projects = await Promise.all(
projectsNoMeta.map(async (p) => ({
entrypoint_metadata: await metadata(
p.path + '/' + PROJECT_ENTRYPOINT
),
...p,
}))
)
return {
projects,
}
},
children: [
{
path: makeUrlPathRelative(paths.SETTINGS),
element: <Settings />,
},
],
},
2023-07-27 18:59:40 -04:00
{
path: paths.SIGN_IN,
2023-07-27 18:59:40 -04:00
element: <SignIn />,
},
])
/**
* All routes in the app, used in src/index.tsx
* @returns RouterProvider
*/
export const Router = () => {
return <RouterProvider router={router} />
}