Skip to content

Commit b2f4381

Browse files
committed
massive change to pages router and Mui full integration
1 parent fba0c00 commit b2f4381

28 files changed

+5193
-520
lines changed

.gitattributes

Lines changed: 0 additions & 2 deletions
This file was deleted.

README.md

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,48 @@
1-
# Next React Lab
1+
# Material UI - Next.js Pages Router example in TypeScript
22

3-
To launch next app
4-
> npm run dev
3+
## How to use
54

5+
Download the example [or clone the repo](https://github.com/mui/material-ui):
66

7-
To connect PlanetSclae
8-
> pscale connect NOM_DE_BASE main --port 3309
7+
<!-- #default-branch-switch -->
98

10-
To link the database with prisma to see what happen
11-
> npx prisma studio
9+
```bash
10+
curl https://codeload.github.com/mui/material-ui/tar.gz/master | tar -xz --strip=2 material-ui-master/examples/material-ui-nextjs-pages-router-ts
11+
cd material-ui-nextjs-pages-router-ts
12+
```
13+
14+
Install it and run:
15+
16+
```bash
17+
npm install
18+
npm run dev
19+
```
20+
21+
or:
22+
23+
<!-- #default-branch-switch -->
24+
25+
[![Edit on StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/mui/material-ui/tree/master/examples/material-ui-nextjs-pages-router-ts)
26+
27+
[![Edit on CodeSandbox](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/github/mui/material-ui/tree/master/examples/material-ui-nextjs-pages-router-ts)
28+
29+
## The idea behind the example
30+
31+
**Note:** This example is set up to use the Next.js Pages Router.
32+
As of Next.js 13.4, the newer App Router pattern is stable.
33+
We recommend starting new projects with the [Material UI with Next.js (App Router) example](https://github.com/mui/material-ui/tree/master/examples/material-ui-nextjs-ts) unless you need (or prefer) the Pages Router.
34+
35+
The project uses [Next.js](https://github.com/vercel/next.js), which is a framework for server-rendered React apps.
36+
It includes `@mui/material` and its peer dependencies, including [Emotion](https://emotion.sh/docs/introduction), the default style engine in Material UI v5. If you prefer, you can [use styled-components instead](https://mui.com/material-ui/guides/interoperability/#styled-components).
37+
38+
## The link component
39+
40+
The [example folder](https://github.com/mui/material-ui/tree/HEAD/examples/material-ui-nextjs-pages-router-ts) provides an adapter for the use of [Next.js's Link component](https://nextjs.org/docs/api-reference/next/link) with MUI.
41+
More information [in the documentation](https://mui.com/material-ui/guides/routing/#next-js).
42+
43+
## What's next?
44+
45+
<!-- #default-branch-switch -->
46+
47+
You now have a working example project.
48+
You can head back to the documentation and continue by browsing the [templates](https://mui.com/material-ui/getting-started/templates/) section.

components/form.tsx

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
// REACT
2+
import { useState } from 'react';
3+
// MUI
4+
import CssBaseline from '@mui/material/CssBaseline';
5+
import Box from '@mui/material/Box';
6+
import Container from '@mui/material/Container';
7+
import TextField from '@mui/material/TextField';
8+
import Select, { SelectChangeEvent } from '@mui/material/Select';
9+
import MenuItem from '@mui/material/MenuItem';
10+
11+
import FormControl from '@mui/material/FormControl';
12+
import InputLabel from '@mui/material/InputLabel';
13+
14+
import FormControlLabel from '@mui/material/FormControlLabel';
15+
import Switch, { SwitchProps } from '@mui/material/Switch';
16+
import styled from '@emotion/styled';
17+
import FormGroup from '@mui/material/FormGroup';
18+
import Button from '@mui/material/Button';
19+
20+
21+
22+
// FAMILLE DICTIONNAIRE
23+
const family_list = [
24+
'mamifère',
25+
'reptile',
26+
'insecte',
27+
'poisson',
28+
'molusque',
29+
'oiseau',
30+
];
31+
32+
// SWITCH LEGENDAIRE
33+
const SwitchLegendary = styled((props: SwitchProps) => (
34+
<Switch focusVisibleClassName=".Mui-focusVisible" disableRipple {...props} />
35+
))(({ theme }) => ({
36+
width: 42,
37+
height: 26,
38+
padding: 0,
39+
'& .MuiSwitch-switchBase': {
40+
padding: 0,
41+
margin: 2,
42+
transitionDuration: '300ms',
43+
'&.Mui-checked': {
44+
transform: 'translateX(16px)',
45+
color: '#fff',
46+
'& + .MuiSwitch-track': {
47+
backgroundColor: theme.palette.mode === 'dark' ? '#2ECA45' : '#65C466',
48+
opacity: 1,
49+
border: 0,
50+
},
51+
'&.Mui-disabled + .MuiSwitch-track': {
52+
opacity: 0.5,
53+
},
54+
},
55+
'&.Mui-focusVisible .MuiSwitch-thumb': {
56+
color: '#33cf4d',
57+
border: '6px solid #fff',
58+
},
59+
'&.Mui-disabled .MuiSwitch-thumb': {
60+
color:
61+
theme.palette.mode === 'light'
62+
? theme.palette.grey[100]
63+
: theme.palette.grey[600],
64+
},
65+
'&.Mui-disabled + .MuiSwitch-track': {
66+
opacity: theme.palette.mode === 'light' ? 0.7 : 0.3,
67+
},
68+
},
69+
'& .MuiSwitch-thumb': {
70+
boxSizing: 'border-box',
71+
width: 22,
72+
height: 22,
73+
},
74+
'& .MuiSwitch-track': {
75+
borderRadius: 26 / 2,
76+
backgroundColor: theme.palette.mode === 'light' ? '#E9E9EA' : '#39393D',
77+
opacity: 1,
78+
transition: theme.transitions.create(['background-color'], {
79+
duration: 500,
80+
}),
81+
},
82+
}));
83+
84+
85+
86+
export function AddAnimalForm() {
87+
// input database
88+
const [name, set_name] = useState('');
89+
const [family, set_family] = useState('');
90+
const [age, set_age] = useState(0);
91+
const [mythic, set_mythic] = useState(false);
92+
93+
const handle_change_family = (event: SelectChangeEvent) => {
94+
set_family(event.target.value as string);
95+
};
96+
97+
const handle_change_name = (event: any) => {
98+
set_name(event.target.value as string);
99+
};
100+
101+
const handle_change_age = (event: any) => {
102+
if(isNaN(event.target.value) === false && event.target.value > 0) {
103+
set_age(Number(event.target.value));
104+
}
105+
};
106+
107+
const handle_change_mythic = (event: any) => {
108+
console.log("mythic",event.target.checked);
109+
set_mythic(event.target.checked as boolean);
110+
};
111+
112+
const handle_submit = async (e:any) => {
113+
e.preventDefault()
114+
const body = { name, family, age, mythic, boolean:false }
115+
try {
116+
const response = await fetch('/api/animal', {
117+
method: 'POST',
118+
headers: { 'Content-Type': 'application/json' },
119+
body: JSON.stringify(body)
120+
})
121+
if (response.status !== 200) {
122+
console.log('something went wrong')
123+
//set an error banner here
124+
} else {
125+
resetForm()
126+
console.log('form submitted successfully !!!')
127+
//set a success banner here
128+
}
129+
console.log("response", response);
130+
console.log("response.status", response.status);
131+
//check response, if success is false, dont take them to success page
132+
} catch (error) {
133+
console.log('there was an error submitting', error)
134+
}
135+
console.log("body", body);
136+
}
137+
138+
const resetForm = () => {
139+
set_name('')
140+
set_family('')
141+
set_age(0)
142+
set_mythic(false)
143+
}
144+
145+
return (
146+
<>
147+
<CssBaseline />
148+
<form action="#" method="POST" onSubmit={(e) => handle_submit(e)}>
149+
<Container maxWidth="sm">
150+
<Box sx={{ p:2, bgcolor: 'yellow', margin: 3, borderRadius: 5, border: 5, borderColor: 'purple'}}>
151+
{/* title */}
152+
<Box sx={{p:1, maxWidth: 190}}>Créez votre créature</Box>
153+
{/* name */}
154+
<Box sx={{p:1}}>
155+
<TextField id="name" label="Nom de la bête" variant="outlined" value={name} onChange={handle_change_name}/>
156+
</Box>
157+
{/* family */}
158+
<Box sx={{p:1, maxWidth: 130}}>
159+
<FormControl fullWidth>
160+
<InputLabel id="family_label">Famille</InputLabel>
161+
<Select labelId="family_label" id="family" label="Famille" value={family} onChange={handle_change_family}>
162+
{family_list.map((elem) => (
163+
<MenuItem
164+
key={elem}
165+
value={elem}>
166+
{elem}
167+
</MenuItem>
168+
169+
))}
170+
</Select>
171+
</FormControl>
172+
</Box>
173+
{/* age */}
174+
<Box sx={{p:1}}>
175+
<TextField id="age" label="Age de la bête" variant="outlined" value={age} onChange={handle_change_age}/>
176+
</Box>
177+
{/* légendaire */}
178+
{/* need FromGroup to put the switch bellow the previous element */}
179+
<Box sx={{p:1}}>
180+
<FormGroup>
181+
<FormControlLabel
182+
control={<SwitchLegendary sx={{ m: 1 }} onChange={handle_change_mythic}/>}
183+
label={mythic === true ? "Légendaire" : "Ordinaire"}
184+
/>
185+
</FormGroup>
186+
</Box>
187+
{/* submit */}
188+
<Box sx={{p:1}}>
189+
{check_data_before_send(name, family, age) === false ? <Button >Ceci n'est pas une bête</Button> : <Button type='submit'>envoyer la bête</Button>}
190+
191+
</Box>
192+
</Box>
193+
</Container>
194+
</form>
195+
</>
196+
);
197+
}
198+
199+
200+
function check_data_before_send(name:string, family: string, age:number) {
201+
if(name.length < 1) {
202+
return false;
203+
}
204+
205+
if(family.length < 1) {
206+
return false;
207+
}
208+
209+
if(age < 1) {
210+
return false;
211+
}
212+
return true;
213+
}

components/layout.tsx

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// import React from "react";
2+
3+
4+
5+
import { Menu } from "./menu";
6+
7+
8+
9+
// https://nextjs.org/docs/pages/building-your-application/routing/pages-and-layouts#layout-pattern
10+
export default function Layout({
11+
children,
12+
}: {
13+
children: React.ReactNode;
14+
}) {
15+
const style = {
16+
background: "magenta",
17+
color: "purple",
18+
fontFamily : "sans-serif",
19+
}
20+
return (
21+
<div style={style}>
22+
<h1>Laboratoire II Next JS</h1>
23+
<Menu/>
24+
{children}
25+
</div>
26+
);
27+
}

components/menu.tsx

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// MUI
2+
import AppBar from '@mui/material/AppBar';
3+
import Container from '@mui/material/Container';
4+
import Box from '@mui/material/Box';
5+
import Button from '@mui/material/Button';
6+
import { styled } from '@mui/material/styles';
7+
8+
const menu = [['Accueil', '/'], ['à propos', '/about'], ['Database', '/database']];
9+
10+
11+
const ButtonCustom = styled(Button) ({
12+
textTransform: 'none'
13+
});
14+
15+
/**
16+
* see default value MUI : https://mui.com/material-ui/customization/default-theme/?expand-path=$.breakpoints.values
17+
keys: Array(5)
18+
0: "xs"
19+
1: "sm"
20+
2: "md"
21+
3: "lg"
22+
4: "xl"
23+
*/
24+
25+
export function Menu() {
26+
return <>
27+
<AppBar position="static" sx={{background:'yellow'}}>
28+
<Container maxWidth="xl">
29+
<Box sx={{ flexGrow: 1, display: {sm: 'flex' } }}>
30+
{/* <Box sx={{ flexGrow: 1, display: { xs: 'none', md: 'flex' } }}> */}
31+
32+
{menu.map((elem) => (
33+
<ButtonCustom
34+
key={elem[0]}
35+
href={elem[1]}
36+
sx={{ my: 1, background: 'yellow', color: 'magenta', display: 'block' }}
37+
>
38+
{elem[0]}
39+
</ButtonCustom>
40+
))}
41+
</Box>
42+
</Container>
43+
</AppBar>
44+
</>
45+
}

next.config.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/** @type {import('next').NextConfig} */
2+
module.exports = {
3+
reactStrictMode: true,
4+
};

0 commit comments

Comments
 (0)