"Route" folder
Each new route (aka page, basically) should have its own folder within the `pages` (or `app` if NextJS) directory
Last updated
Each new route (aka page, basically) should have its own folder within the `pages` (or `app` if NextJS) directory
Last updated
🎥 Watch "Pages" style guide video here.
For any new route, a "route" folder should be made.
The contents of the "route" folder are:
layout.tsx
This is the "layout" file, and is a layer that wraps the "page" file.
Having separate "layout" and "page" layers provides us more flexibility (NextJS v13+ pattern)
For example, in the future, we may want very different layouts for different sections of the app (e.g. "marketing pages" (totally different layout/UI/UX/etc.), login/register page (maybe no header or footer nav on this page), onboarding pages, etc.)
NOTE: Currently, we just have a single (reusable) PageLayout, which is essentially what all of our "logged in"/"app" page layouts will be.
NOTE2: For now, the contents of this layout file will be essentially the same for each route.
Eventually, once we've moved from Chakra to MUI at the site layout level, then we will utilize the "header" prop (e.g. pass the title for the page, and likely eventually doing some data fetching and performing other logic here to have more going on in the page header area than simply text saying the name of the page)
// layout.tsx
import { MuiThemeProvider } from '~/style/MuiThemeProvider';
import { PageLayout } from '@components/layout/_pages/PageLayout';
import Page from './page';
interface LayoutProps {}
export default function Layout({}: LayoutProps) {
return (
<MuiThemeProvider>
<PageLayout header={null}>
<Page />
</PageLayout>
</MuiThemeProvider>
);
}
page.tsx
This is the "page" file. It is a layer that is wrapped by the "layout" file, and ultimately imports components, which are laid out in the return/render area.
Having separate "layout" and "page" layers provides us more flexibility (NextJS v13+ pattern)
NOTE: If there is a state that needs to be shared between imported components, this file is where that state lives. (The state is created here, and then passed down to the necessary components as props)
External data should generally NOT be shared between components via prop passing. Instead, each individual component that needs the data should have the data fetching request within it
(these requests are de-duped, so only one request will ultimately be made -- see the Data Fetching section for more information on this)
// page.tsx
interface PageProps {}
export default function Page({}: PageProps) {
// any necessary page-level data fetching (however, most data fetching should be done in individual components, not here)
return (
<>
// components (usually local) should be imported and arranged here
</>
)
}
index.ts
Exports the route (which is essentially the "page", but it is wrappd in a layout, so we actually export the "layout" file (layout.tsx
))
// index.ts
export { default } from "./layout.tsx"
_config
(optional)This file exists for convenience and houses the "configuration" for any files within the "route" folder to use, if the route is a "main route" (e.g. /team-members, /files, /contacts, /projects, etc.).
It acts as the single location for imports for types/schemas/etc. (from a "router" folder) that are related to the route, ultimately re-assigning the imported TDoc
, TCreate
, TUpdate
, etc. to a local TDoc
, TCreate
, TUpdate
, etc.
That way, layout.tsx, page.tsx,
and any files within the _components
folder can import these local types/schemas/etc., rather than needing to import from the "router" folder for each file.
This way, if file organization/naming schemas/etc. related to the "router" folder files changes, only this config file undergoes changes (not every single file that would otherwise be importing from the "router" folder)
// _config.ts
// - change [router] to the appropriate "router" folder
// - this file is still undergoing changes, but this is the current setup
import {
TDoc as TDocBase,
TDocCreate as TDocCreateBase,
TDocUpdate as TDocUpdateBase,
} from '~/api/routers/[router]/types';
import { schema, schemaCreate, schemaUpdate } from '~/api/routers/[router]/schema';
import { resource } from '~/api/routers/[router]/router';
import { TypeSingularPlural } from '~/types/_mui';
export type TDoc = TDocBase;
export type TDocCreate = TDocCreateBase;
export type TDocUpdate = TDocUpdateBase;
export type TypeSingular = 'file'; // update
export type TypePlural = typeof resource;
export const TYPE: TypeSingularPlural & { display: { singular: string; plural: string } } = {
singular: 'file', // update
plural: 'files', // update
display: {
singular: 'File', // update
plural: 'Files', // update
},
} as const;
export const DATA_TESTID = `pod-${TYPE.singular}`;
export const SCHEMA = schema;
export const SCHEMA_CREATE = schemaCreate;
export const SCHEMA_UPDATE = schemaUpdate;
_components
(optional)The components in here are "local components". Components live here if they are unique to this route.
Examples:
(1) route-specific implementations of base/reusable "UI" components
(from @components)
(aka "data components" or "wrapper components")
<PodX>
route-specific implementation of <Pod>
from @components
(does some data fetching and possibly other logic, ultimately creating the props that it passes to the base "UI" <Pod>
component)
<TableX>
, <IconButtonMoreInfoX>
, etc.
(2) completely unique / custom-built components that are only used within this route
(no base/reusable version needs to be created)
NOTE: We are still using "old MUI" <Pod>
and <Table>
base/reusable components (from ~/components/_mui
, so this process is a little difficult until I get Pod, Table, etc. all Storybook-ized. Here is a video that goes over the issues you will come across when creating new routes with these "old MUI" components.