Skip to content

React19 nextjs15 #11

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

Merged
merged 6 commits into from
Aug 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,13 @@ If you prefer Tailwind css, check this: [Tailwind-CSS-Version](https://github.co

## Clone this repository for React 19.x with NextJs 15.x or React 18.x with NextJs 14.x

- Clone React19-Next15-MUI6-TS-Starter:
- `git clone -b react19-nextjs15 https://github.com/AlexStack/nextjs-materia-mui-typescript-hook-form-scaffold-boilerplate-starter.git react19-nextjs15-mui6-ts-starter`
- Clone React18-Next14-MUI5-TS-Starter:
- `git clone -b nextjs14 https://github.com/AlexStack/nextjs-materia-mui-typescript-hook-form-scaffold-boilerplate-starter.git react18-nextjs14-mui5-ts-starter`
- Clone & install React19-Next15-MUI6-TS-Starter:
- `git clone -b react19-nextjs15 https://github.com/AlexStack/nextjs-materia-mui-typescript-hook-form-scaffold-boilerplate-starter.git react19-nextjs15-mui6-ts-starter && cd react19-nextjs15-mui6-ts-starter && yarn install && yarn dev -p 3005`
- Open <http://localhost:3005>
- Note: React 19 is not released yet, there are some warnings in the console, please ignore them.
- Clone & install React18-Next14-MUI5-TS-Starter:
- `git clone -b nextjs14 https://github.com/AlexStack/nextjs-materia-mui-typescript-hook-form-scaffold-boilerplate-starter.git react18-nextjs14-mui5-ts-starter && cd react18-nextjs14-mui5-ts-starter && yarn install && yarn dev -p 3005`
- Open <http://localhost:3005>

## Features

Expand Down
15 changes: 8 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",
"@hookform/resolvers": "^3.3.1",
"@mui/icons-material": "^5.14.9",
"@mui/material": "^5.14.10",
"@mui/icons-material": "next",
"@mui/material": "next",
"dayjs": "^1.11.10",
"next": "^15.0.0-rc.0",
"react": "^19.0.0-rc-512b09b2-20240718",
"react-dom": "^19.0.0-rc-512b09b2-20240718",
"react-hook-form": "^7.46.2",
"next": "rc",
"react": "rc",
"react-dom": "rc",
"react-hook-form": "^7.52.2",
"react-icons": "^4.10.1",
"zod": "^3.22.4"
},
Expand All @@ -38,11 +38,12 @@
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@types/react": "^18.2.15",
"@types/jest": "^29.5.12",
"@typescript-eslint/eslint-plugin": "^5.62.0",
"@typescript-eslint/parser": "^5.62.0",
"autoprefixer": "^10.4.14",
"eslint": "^8.45.0",
"eslint-config-next": "^15.0.0-rc.0",
"eslint-config-next": "rc",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-simple-import-sort": "^7.0.0",
"eslint-plugin-unused-imports": "^2.0.0",
Expand Down
7 changes: 7 additions & 0 deletions src/app/error.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable @next/next/no-img-element */
'use client'; // Error components must be Client Components

import WarningIcon from '@mui/icons-material/Warning';
Expand Down Expand Up @@ -29,6 +30,12 @@ export default function Error({
<Button onClick={reset}>Try again</Button>
</Box>
<a href='/?slug=homepage'>Back to home</a>
<div>
<img
src='https://img.freepik.com/free-vector/500-internal-server-error-concept-illustration_114360-1905.jpg'
alt='500'
/>
</div>
</Box>
</section>
</main>
Expand Down
13 changes: 13 additions & 0 deletions src/app/not-found.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
/* eslint-disable @next/next/no-img-element */
'use client';

import { Box } from '@mui/material';
import { Metadata } from 'next';
import { usePathname } from 'next/navigation';
import * as React from 'react';
import { RiAlarmWarningFill } from 'react-icons/ri';

Expand All @@ -8,6 +12,7 @@ export const metadata: Metadata = {
};

export default function NotFound() {
const pathname = usePathname();
return (
<main>
<Box sx={{ textAlign: 'center' }}>
Expand All @@ -17,8 +22,16 @@ export default function NotFound() {
className='drop-shadow-glow animate-flicker text-red-500'
/>
<h1>Page Not Found</h1>
{/* <div>{window.location.href} NOT exists</div> */}
<div>{pathname} NOT exists</div>
<h5>change this in app/not-found.tsx</h5>
<a href='/'>Back to home</a>
<div>
<img
src='https://img.freepik.com/free-vector/404-error-with-person-looking-concept-illustration_114360-7922.jpg'
alt='404'
/>
</div>
</div>
</Box>
</main>
Expand Down
2 changes: 1 addition & 1 deletion src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { NpmData, PageParams } from '@/types';

const loadDataFromApi = async (slug?: string) => {
if (slug === 'testError500') {
throw new Error('This is mock a ssr 500 test error');
throw new Error('This is mock a SSR 500 test error');
}

// Fetch & cache data from 2 remote APIs test
Expand Down
45 changes: 9 additions & 36 deletions src/components/Homepage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import AutoAwesome from '@mui/icons-material/AutoAwesome';
import { Box, Typography } from '@mui/material';
import Link from 'next/link';

import { ClientProvider } from '@/hooks/useClientContext';

import DisplayRandomPicture from '@/components/shared/DisplayRandomPicture';
import PageFooter from '@/components/shared/PageFooter';
import ReactActionForm from '@/components/shared/ReactActionForm';
import ReactHookForm from '@/components/shared/ReactHookForm';
import BottomLinks from '@/components/homepage/BottomLinks';
import DisplayRandomPicture from '@/components/homepage/DisplayRandomPicture';
import PageFooter from '@/components/homepage/PageFooter';
import ReactActionForm from '@/components/homepage/ReactActionForm';
import ReactHookForm from '@/components/homepage/ReactHookForm';
import ClientSideWrapper from '@/components/shared/ClientSideWrapper';

import { FETCH_API_CTX_VALUE, SITE_CONFIG } from '@/constants';

Expand Down Expand Up @@ -67,39 +67,12 @@ export default function Homepage({
Test local NextJs API /api/test POST method (client-side
component)
</h4>
<ClientProvider defaultValue={FETCH_API_CTX_VALUE}>
<ClientSideWrapper defaultContextValue={FETCH_API_CTX_VALUE}>
<ReactActionForm />
<ReactHookForm />
<DisplayRandomPicture />
</ClientProvider>
</Box>

<Box sx={{ m: 5 }}>
<Link
href='https://github.com/AlexStack/nextjs-materia-mui-typescript-hook-form-scaffold-boilerplate-starter'
target='_blank'
>
See the Github repository page
</Link>
</Box>
<Box sx={{ m: 5, a: { color: 'red' } }}>
<Link
href='https://vercel.com/new/clone?s=https%3A%2F%2Fgithub.com%2FAlexStack%2Fnextjs-materia-mui-typescript-hook-form-scaffold-boilerplate-starter&showOptionalTeamCreation=false'
target='_blank'
>
Click here to deploy a demo site to your Vercel in 1 minute
</Link>
</Box>

<Box sx={{ m: 5 }}>
<Link href='/test-page-not-exists'>
Test 404 page not found (mock file not exists)
</Link>
</Box>
<Box sx={{ m: 5 }}>
<a href='/?slug=testError500'>
Test 500 error page (mock server side throw error)
</a>
<BottomLinks />
</ClientSideWrapper>
</Box>
</Box>
</section>
Expand Down
84 changes: 84 additions & 0 deletions src/components/homepage/BottomLinks.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
'use client';

import { Box } from '@mui/material';
import Link from 'next/link';
import * as React from 'react';

import { useSharedUtilContext } from '@/hooks/useSharedUtilContext';

const BottomLinks = () => {
const { openConfirmDialog } = useSharedUtilContext();

return (
<section>
<Box sx={{ m: 5 }}>
<Link
href='https://github.com/AlexStack/nextjs-materia-mui-typescript-hook-form-scaffold-boilerplate-starter'
target='_blank'
>
See the Github repository page
</Link>
</Box>
<Box sx={{ m: 5, a: { color: 'red' } }}>
<Link
href='https://vercel.com/new/clone?s=https%3A%2F%2Fgithub.com%2FAlexStack%2Fnextjs-materia-mui-typescript-hook-form-scaffold-boilerplate-starter&showOptionalTeamCreation=false'
target='_blank'
onClick={(e) => {
e.preventDefault();
openConfirmDialog({
title: 'Copy this repository to your Vercel',
content:
'Please make sure you have a Vercel account and login first',
onConfirm: () => {
window.open((e.target as HTMLAnchorElement).href, '_blank');
},
hideCancelButton: true,
});
}}
>
Click here to deploy a demo site to your Vercel in 1 minute
</Link>
</Box>

<Box sx={{ m: 5 }}>
<Link
href='/test-page-not-exists'
onClick={(e) => {
e.preventDefault();
openConfirmDialog({
title: 'Mock a page not found',
content:
'This is an URL not exists, click OK you will see a custom 404 error page. You can also test the 404 page by typing a random URL in the browser address bar.',
onConfirm: () => {
window.open((e.target as HTMLAnchorElement).href, '_blank');
},
hideCancelButton: true,
});
}}
>
Test 404 page not found (mock file not exists)
</Link>
</Box>
<Box sx={{ m: 5 }}>
<a
href='/?slug=testError500'
onClick={(e) => {
e.preventDefault();
openConfirmDialog({
title: 'Mock a server side error',
content:
'This is mock throw a server side error, click OK you will see a custom 500 error page. ',
onConfirm: () => {
window.open((e.target as HTMLAnchorElement).href, '_blank');
},
});
}}
>
Test 500 error page (mock server side throw error)
</a>
</Box>
</section>
);
};

export default BottomLinks;
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,20 @@ import { purple } from '@mui/material/colors';
import Stack from '@mui/material/Stack';
import React, { useEffect, useState, useTransition } from 'react';

import { useAlertBar } from '@/hooks/useAlertBar';
import { useClientContext } from '@/hooks/useClientContext';
import { useSharedUtilContext } from '@/hooks/useSharedUtilContext';

import SubmitButton from '@/components/shared/SubmitButton';

import { FetchApiContext } from '@/constants';
import { consoleLog } from '@/utils/shared/console-log';
import { getApiResponse } from '@/utils/shared/get-api-response';

const DisplayRandomPicture = () => {
const [imageUrl, setImageUrl] = useState('');
const [error, setError] = useState('');
const { fetchCount, updateClientCtx } = useClientContext<FetchApiContext>();
const { setAlertBarProps, renderAlertBar } = useAlertBar();
const { setAlertBarProps } = useSharedUtilContext();
const renderCountRef = React.useRef(0);
const [isPending, startTransition] = useTransition();

Expand Down Expand Up @@ -52,6 +53,9 @@ const DisplayRandomPicture = () => {
setAlertBarProps({
message: 'A random picture fetched successfully',
severity: 'info',
onClose: () => {
consoleLog('Alert bar closed');
},
});
} catch (error) {
const errorMsg =
Expand Down Expand Up @@ -121,7 +125,6 @@ const DisplayRandomPicture = () => {
</Avatar>
</StyledRefreshButton>
)}
{renderAlertBar()}
</Stack>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import { purple } from '@mui/material/colors';
import React, { useActionState, useOptimistic } from 'react';
import { z, ZodError } from 'zod';

import { useAlertBar } from '@/hooks/useAlertBar';
import { useClientContext } from '@/hooks/useClientContext';
import { useSharedUtilContext } from '@/hooks/useSharedUtilContext';

import SubmitButton from '@/components/shared/SubmitButton';

Expand Down Expand Up @@ -51,7 +51,7 @@ const ReactActionForm: React.FC = () => {
FormValues | undefined
>(undefined);

const { setAlertBarProps, renderAlertBar } = useAlertBar();
const { setAlertBarProps } = useSharedUtilContext();

const { fetchCount, updateClientCtx } = useClientContext<FetchApiContext>();
const [formErrors, setFormErrors] = React.useState<Record<string, string>>(
Expand Down Expand Up @@ -184,7 +184,7 @@ const ReactActionForm: React.FC = () => {
justifyContent='center'
alignItems='center'
>
<div>Total fetch count from React Context:</div>
<div>Total fetch count from ReactActionForm.tsx:</div>
<Avatar
sx={{
bgcolor: purple[500],
Expand All @@ -198,8 +198,6 @@ const ReactActionForm: React.FC = () => {
</Avatar>
</Stack>
</Box>

{renderAlertBar()}
</StyledForm>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,8 @@ import React, { useEffect } from 'react';
import { Controller, SubmitHandler, useForm } from 'react-hook-form';
import { z } from 'zod';

import { useAlertBar } from '@/hooks/useAlertBar';
import { useClientContext } from '@/hooks/useClientContext';
import useConfirmationDialog from '@/hooks/useConfirmDialog';
import { useSharedUtilContext } from '@/hooks/useSharedUtilContext';

import SubmitButton from '@/components/shared/SubmitButton';

Expand Down Expand Up @@ -52,10 +51,7 @@ const ReactHookForm: React.FC = () => {
const [apiResult, setApiResult] = React.useState<FormValues>();
const [isSubmitting, setIsSubmitting] = React.useState(false);

const { setAlertBarProps, renderAlertBar } = useAlertBar();

const { openConfirmDialog, renderConfirmationDialog } =
useConfirmationDialog();
const { setAlertBarProps, openConfirmDialog } = useSharedUtilContext();

const {
handleSubmit,
Expand Down Expand Up @@ -195,10 +191,6 @@ const ReactHookForm: React.FC = () => {
Test MUI confirmation dialog
</Button>
</Box>

{renderAlertBar()}

{renderConfirmationDialog()}
</StyledForm>
);
};
Expand Down
Loading
Loading