Skip to content

Commit

Permalink
Next.js playground, once all bugs are fixes we can send the PR for re…
Browse files Browse the repository at this point in the history
…view
  • Loading branch information
apedroferreira committed Feb 13, 2025
1 parent e67a3e3 commit fc4fa14
Show file tree
Hide file tree
Showing 14 changed files with 386 additions and 89 deletions.
9 changes: 7 additions & 2 deletions packages/toolpad-core/src/CRUD/FormPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -162,9 +162,13 @@ function FormPage<D extends DataModel>(props: FormPageProps<D>) {

const handleDateFieldChange = React.useCallback(
(name: string) => (value: Dayjs | null) => {
handleFormFieldChange(name, value?.toISOString() ?? null);
if (value?.isValid()) {
handleFormFieldChange(name, value.toISOString() ?? null);
} else if (formValues[name]) {
handleFormFieldChange(name, null);
}
},
[handleFormFieldChange],
[formValues, handleFormFieldChange],
);

const handleSelectFieldChange = React.useCallback(
Expand Down Expand Up @@ -193,6 +197,7 @@ function FormPage<D extends DataModel>(props: FormPageProps<D>) {
helperText={fieldError ?? ' '}
fullWidth
multiline={type === 'longString'}
minRows={type === 'longString' ? 2 : undefined}
/>
);
}
Expand Down
61 changes: 35 additions & 26 deletions packages/toolpad-core/src/CRUD/List.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ function List<D extends DataModel>(props: ListProps<D>) {
const routerContext = React.useContext(RouterContext);
const appWindowContext = React.useContext(WindowContext);

const appWindow = appWindowContext ?? window;
const appWindow = appWindowContext ?? (typeof window !== 'undefined' ? window : null);

const dialogs = useDialogs();
const notifications = useNotifications();
Expand Down Expand Up @@ -167,44 +167,50 @@ function List<D extends DataModel>(props: ListProps<D>) {
const [error, setError] = React.useState<Error | null>(null);

React.useEffect(() => {
const url = new URL(appWindow.location.href);
if (appWindow) {
const url = new URL(appWindow.location.href);

url.searchParams.set('page', String(paginationModel.page));
url.searchParams.set('pageSize', String(paginationModel.pageSize));
url.searchParams.set('page', String(paginationModel.page));
url.searchParams.set('pageSize', String(paginationModel.pageSize));

if (!appWindow.frameElement) {
appWindow.history.pushState({}, '', url);
if (!appWindow.frameElement) {
appWindow.history.pushState({}, '', url);
}
}
}, [appWindow, paginationModel.page, paginationModel.pageSize]);

React.useEffect(() => {
const url = new URL(appWindow.location.href);

if (
filterModel.items.length > 0 ||
(filterModel.quickFilterValues && filterModel.quickFilterValues.length > 0)
) {
url.searchParams.set('filter', JSON.stringify(filterModel));
} else {
url.searchParams.delete('filter');
}
if (appWindow) {
const url = new URL(appWindow.location.href);

if (
filterModel.items.length > 0 ||
(filterModel.quickFilterValues && filterModel.quickFilterValues.length > 0)
) {
url.searchParams.set('filter', JSON.stringify(filterModel));
} else {
url.searchParams.delete('filter');
}

if (!appWindow.frameElement) {
appWindow.history.pushState({}, '', url);
if (!appWindow.frameElement) {
appWindow.history.pushState({}, '', url);
}
}
}, [appWindow, filterModel]);

React.useEffect(() => {
const url = new URL(appWindow.location.href);
if (appWindow) {
const url = new URL(appWindow.location.href);

if (sortModel.length > 0) {
url.searchParams.set('sort', JSON.stringify(sortModel));
} else {
url.searchParams.delete('sort');
}
if (sortModel.length > 0) {
url.searchParams.set('sort', JSON.stringify(sortModel));
} else {
url.searchParams.delete('sort');
}

if (!appWindow.frameElement) {
appWindow.history.pushState({}, '', url);
if (!appWindow.frameElement) {
appWindow.history.pushState({}, '', url);
}
}
}, [appWindow, sortModel]);

Expand Down Expand Up @@ -360,8 +366,11 @@ function List<D extends DataModel>(props: ListProps<D>) {
sortingMode="server"
filterMode="server"
paginationMode="server"
paginationModel={paginationModel}
onPaginationModelChange={setPaginationModel}
sortModel={sortModel}
onSortModelChange={setSortModel}
filterModel={filterModel}
onFilterModelChange={setFilterModel}
onRowClick={handleRowClick}
loading={isLoading}
Expand Down
2 changes: 1 addition & 1 deletion packages/toolpad-core/src/CRUD/Show.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ function Show<D extends DataModel>(props: ShowProps<D>) {
return fieldValue ? dayjs(fieldValue as string).format('MMMM D, YYYY h:mm A') : '-';
}

return String(fieldValue) ?? '-';
return fieldValue ? String(fieldValue) : '-';
},
[data],
);
Expand Down
9 changes: 7 additions & 2 deletions packages/toolpad-core/src/Crud/FormPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -162,9 +162,13 @@ function FormPage<D extends DataModel>(props: FormPageProps<D>) {

const handleDateFieldChange = React.useCallback(
(name: string) => (value: Dayjs | null) => {
handleFormFieldChange(name, value?.toISOString() ?? null);
if (value?.isValid()) {
handleFormFieldChange(name, value.toISOString() ?? null);
} else if (formValues[name]) {
handleFormFieldChange(name, null);
}
},
[handleFormFieldChange],
[formValues, handleFormFieldChange],
);

const handleSelectFieldChange = React.useCallback(
Expand Down Expand Up @@ -193,6 +197,7 @@ function FormPage<D extends DataModel>(props: FormPageProps<D>) {
helperText={fieldError ?? ' '}
fullWidth
multiline={type === 'longString'}
minRows={type === 'longString' ? 2 : undefined}
/>
);
}
Expand Down
61 changes: 35 additions & 26 deletions packages/toolpad-core/src/Crud/List.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ function List<D extends DataModel>(props: ListProps<D>) {
const routerContext = React.useContext(RouterContext);
const appWindowContext = React.useContext(WindowContext);

const appWindow = appWindowContext ?? window;
const appWindow = appWindowContext ?? (typeof window !== 'undefined' ? window : null);

const dialogs = useDialogs();
const notifications = useNotifications();
Expand Down Expand Up @@ -167,44 +167,50 @@ function List<D extends DataModel>(props: ListProps<D>) {
const [error, setError] = React.useState<Error | null>(null);

React.useEffect(() => {
const url = new URL(appWindow.location.href);
if (appWindow) {
const url = new URL(appWindow.location.href);

url.searchParams.set('page', String(paginationModel.page));
url.searchParams.set('pageSize', String(paginationModel.pageSize));
url.searchParams.set('page', String(paginationModel.page));
url.searchParams.set('pageSize', String(paginationModel.pageSize));

if (!appWindow.frameElement) {
appWindow.history.pushState({}, '', url);
if (!appWindow.frameElement) {
appWindow.history.pushState({}, '', url);
}
}
}, [appWindow, paginationModel.page, paginationModel.pageSize]);

React.useEffect(() => {
const url = new URL(appWindow.location.href);

if (
filterModel.items.length > 0 ||
(filterModel.quickFilterValues && filterModel.quickFilterValues.length > 0)
) {
url.searchParams.set('filter', JSON.stringify(filterModel));
} else {
url.searchParams.delete('filter');
}
if (appWindow) {
const url = new URL(appWindow.location.href);

if (
filterModel.items.length > 0 ||
(filterModel.quickFilterValues && filterModel.quickFilterValues.length > 0)
) {
url.searchParams.set('filter', JSON.stringify(filterModel));
} else {
url.searchParams.delete('filter');
}

if (!appWindow.frameElement) {
appWindow.history.pushState({}, '', url);
if (!appWindow.frameElement) {
appWindow.history.pushState({}, '', url);
}
}
}, [appWindow, filterModel]);

React.useEffect(() => {
const url = new URL(appWindow.location.href);
if (appWindow) {
const url = new URL(appWindow.location.href);

if (sortModel.length > 0) {
url.searchParams.set('sort', JSON.stringify(sortModel));
} else {
url.searchParams.delete('sort');
}
if (sortModel.length > 0) {
url.searchParams.set('sort', JSON.stringify(sortModel));
} else {
url.searchParams.delete('sort');
}

if (!appWindow.frameElement) {
appWindow.history.pushState({}, '', url);
if (!appWindow.frameElement) {
appWindow.history.pushState({}, '', url);
}
}
}, [appWindow, sortModel]);

Expand Down Expand Up @@ -360,8 +366,11 @@ function List<D extends DataModel>(props: ListProps<D>) {
sortingMode="server"
filterMode="server"
paginationMode="server"
paginationModel={paginationModel}
onPaginationModelChange={setPaginationModel}
sortModel={sortModel}
onSortModelChange={setSortModel}
filterModel={filterModel}
onFilterModelChange={setFilterModel}
onRowClick={handleRowClick}
loading={isLoading}
Expand Down
2 changes: 1 addition & 1 deletion packages/toolpad-core/src/Crud/Show.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ function Show<D extends DataModel>(props: ShowProps<D>) {
return fieldValue ? dayjs(fieldValue as string).format('MMMM D, YYYY h:mm A') : '-';
}

return String(fieldValue) ?? '-';
return fieldValue ? String(fieldValue) : '-';
},
[data],
);
Expand Down
4 changes: 3 additions & 1 deletion playground/nextjs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@
"@types/node": "^20.17.16",
"@types/react": "^19.0.8",
"@types/react-dom": "^19.0.3",
"cookies-next": "^5.1.0",
"eslint-config-next": "15.1.6",
"next": "^15.1.6",
"next-auth": "5.0.0-beta.25",
"react": "^19.0.0",
"react-dom": "^19.0.0"
"react-dom": "^19.0.0",
"yup": "1.6.1"
}
}
20 changes: 19 additions & 1 deletion playground/nextjs/src/app/(dashboard)/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'use client';
import * as React from 'react';
import { usePathname, useParams } from 'next/navigation';
import Typography from '@mui/material/Typography';
import Stack from '@mui/material/Stack';
import MenuList from '@mui/material/MenuList';
Expand Down Expand Up @@ -157,9 +158,26 @@ function SidebarFooterAccount({ mini }: SidebarFooterProps) {
}

export default function DashboardPagesLayout(props: { children: React.ReactNode }) {
const pathname = usePathname();
const params = useParams();
const [orderId] = params.segments ?? [];

const title = React.useMemo(() => {
if (pathname === '/orders/new') {
return 'New Order';
}
if (orderId && pathname.includes('/edit')) {
return `Order ${orderId} - Edit`;
}
if (orderId) {
return `Order ${orderId}`;
}
return undefined;
}, [orderId, pathname]);

return (
<DashboardLayout slots={{ sidebarFooter: SidebarFooterAccount, toolbarAccount: () => null }}>
<PageContainer>{props.children}</PageContainer>
<PageContainer title={title}>{props.children}</PageContainer>
</DashboardLayout>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import * as React from 'react';
import { Crud } from '@toolpad/core/Crud';
import { ordersDataSource, Order } from '../../../../data/orders';

export default function OrdersCrudPage() {
return (
<Crud<Order>
dataSource={ordersDataSource}
rootPath="/orders"
initialPageSize={25}
defaultValues={{ itemCount: 1 }}
/>
);
}
6 changes: 0 additions & 6 deletions playground/nextjs/src/app/(dashboard)/orders/page.tsx

This file was deleted.

2 changes: 1 addition & 1 deletion playground/nextjs/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ const NAVIGATION: Navigation = [
title: 'Main items',
},
{
segment: '',
title: 'Dashboard',
icon: <DashboardIcon />,
},
{
segment: 'orders',
title: 'Orders',
icon: <ShoppingCartIcon />,
pattern: 'orders{/:orderId}*',
},
];

Expand Down
Loading

0 comments on commit fc4fa14

Please sign in to comment.