✨(demo) use modal to show create form
Now that we have a modal component, let's use it to display our creation form.
This commit is contained in:
committed by
Jean-Baptiste PENRATH
parent
7913075faf
commit
86138df8fe
@@ -1,4 +1,9 @@
|
|||||||
import { Button, CunninghamProvider, Select } from "@openfun/cunningham-react";
|
import {
|
||||||
|
Button,
|
||||||
|
CunninghamProvider,
|
||||||
|
Select,
|
||||||
|
useModal,
|
||||||
|
} from "@openfun/cunningham-react";
|
||||||
import React, { useEffect, useMemo, useState } from "react";
|
import React, { useEffect, useMemo, useState } from "react";
|
||||||
import { Create } from "./Create";
|
import { Create } from "./Create";
|
||||||
import { Home } from "./Home";
|
import { Home } from "./Home";
|
||||||
@@ -29,14 +34,7 @@ const THEMES: Record<Theme, Record<Variant, string | undefined>> = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export enum Page {
|
export type PageProps = ReturnType<typeof useModal>;
|
||||||
HOME,
|
|
||||||
CREATE,
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface PageProps {
|
|
||||||
changePage: (page: Page) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const preferredScheme = window.matchMedia("(prefers-color-scheme: dark)")
|
const preferredScheme = window.matchMedia("(prefers-color-scheme: dark)")
|
||||||
.matches
|
.matches
|
||||||
@@ -54,7 +52,7 @@ export const App = () => {
|
|||||||
preferredScheme.variant,
|
preferredScheme.variant,
|
||||||
);
|
);
|
||||||
const activeTheme = useMemo(() => THEMES[theme][variant], [theme, variant]);
|
const activeTheme = useMemo(() => THEMES[theme][variant], [theme, variant]);
|
||||||
const [page, setPage] = useState<Page>(Page.HOME);
|
const modal = useModal();
|
||||||
const handleThemeChange = (event: MediaQueryListEvent) => {
|
const handleThemeChange = (event: MediaQueryListEvent) => {
|
||||||
const nextVariant = event.matches ? Variant.DARK : Variant.LIGHT;
|
const nextVariant = event.matches ? Variant.DARK : Variant.LIGHT;
|
||||||
if (THEMES[theme][nextVariant] !== undefined) {
|
if (THEMES[theme][nextVariant] !== undefined) {
|
||||||
@@ -92,8 +90,8 @@ export const App = () => {
|
|||||||
alt="Background pattern"
|
alt="Background pattern"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{page === Page.HOME && <Home changePage={(p) => setPage(p)} />}
|
<Home modal={modal} />
|
||||||
{page === Page.CREATE && <Create changePage={(p) => setPage(p)} />}
|
<Create {...modal} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="theme-switch">
|
<div className="theme-switch">
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import {
|
|||||||
DateRangePicker,
|
DateRangePicker,
|
||||||
FileUploader,
|
FileUploader,
|
||||||
Input,
|
Input,
|
||||||
|
Modal,
|
||||||
|
ModalSize,
|
||||||
Radio,
|
Radio,
|
||||||
RadioGroup,
|
RadioGroup,
|
||||||
Select,
|
Select,
|
||||||
@@ -16,10 +18,10 @@ import {
|
|||||||
VariantType,
|
VariantType,
|
||||||
} from "@openfun/cunningham-react";
|
} from "@openfun/cunningham-react";
|
||||||
import { faker } from "@faker-js/faker";
|
import { faker } from "@faker-js/faker";
|
||||||
|
import { PageProps } from "./App";
|
||||||
import { Character, database, randomDates } from "./Character";
|
import { Character, database, randomDates } from "./Character";
|
||||||
import { Page, PageProps } from "./App";
|
|
||||||
|
|
||||||
export const Create = ({ changePage }: PageProps) => {
|
export const Create = (props: PageProps) => {
|
||||||
const { toast } = useToastProvider();
|
const { toast } = useToastProvider();
|
||||||
|
|
||||||
const submit: React.FormEventHandler<HTMLFormElement> = (e) => {
|
const submit: React.FormEventHandler<HTMLFormElement> = (e) => {
|
||||||
@@ -40,102 +42,104 @@ export const Create = ({ changePage }: PageProps) => {
|
|||||||
};
|
};
|
||||||
database.unshift(character);
|
database.unshift(character);
|
||||||
|
|
||||||
changePage(Page.HOME);
|
props.close();
|
||||||
toast("Character created successfully", VariantType.SUCCESS);
|
toast("Character created successfully", VariantType.SUCCESS);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form className="page__create clr-greyscale-900" onSubmit={submit}>
|
<Modal {...props} size={ModalSize.LARGE} closeOnClickOutside>
|
||||||
<h1>Add a character</h1>
|
<form className="page__create clr-greyscale-900" onSubmit={submit}>
|
||||||
<div className="card">
|
<h1>Add a character</h1>
|
||||||
<h3 className="fw-bold fs-h3">General Information</h3>
|
<div className="card">
|
||||||
<Alert type={VariantType.INFO}>
|
<h3 className="fw-bold fs-h3">General Information</h3>
|
||||||
You are about to add a new character to the collection
|
<Alert type={VariantType.INFO}>
|
||||||
</Alert>
|
You are about to add a new character to the collection
|
||||||
<Input
|
</Alert>
|
||||||
name="name"
|
<Input
|
||||||
label="Name"
|
name="name"
|
||||||
text="Enter first and last name"
|
label="Name"
|
||||||
fullWidth={true}
|
text="Enter first and last name"
|
||||||
required
|
fullWidth={true}
|
||||||
/>
|
required
|
||||||
<Select
|
|
||||||
name="sex"
|
|
||||||
label="Sex"
|
|
||||||
fullWidth={true}
|
|
||||||
options={[
|
|
||||||
{
|
|
||||||
label: "Female",
|
|
||||||
value: "female",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Male",
|
|
||||||
value: "male",
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
<DatePicker name="birthdate" label="Birth Date" fullWidth={true} />
|
|
||||||
<DateRangePicker
|
|
||||||
name="appearance_dates"
|
|
||||||
startLabel="First appearance"
|
|
||||||
endLabel="Last appearance"
|
|
||||||
fullWidth={true}
|
|
||||||
/>
|
|
||||||
<Checkbox name="is_guest" label="This character is a guest" />
|
|
||||||
</div>
|
|
||||||
<div className="card mt-l">
|
|
||||||
<h3 className="fw-bold fs-h3">Bio</h3>
|
|
||||||
<Alert type={VariantType.WARNING}>
|
|
||||||
Please be exhaustive, every detail counts!
|
|
||||||
</Alert>
|
|
||||||
<TextArea
|
|
||||||
name="bio"
|
|
||||||
label="Biography"
|
|
||||||
text="Enter a detailed biography"
|
|
||||||
fullWidth={true}
|
|
||||||
rows={8}
|
|
||||||
/>
|
|
||||||
<RadioGroup>
|
|
||||||
<Radio
|
|
||||||
label="Appeared between 0 and 5 times"
|
|
||||||
name="occurences"
|
|
||||||
value="A"
|
|
||||||
/>
|
/>
|
||||||
<Radio
|
<Select
|
||||||
label="Appeared between 6 and 10 times"
|
name="sex"
|
||||||
name="occurences"
|
label="Sex"
|
||||||
value="B"
|
fullWidth={true}
|
||||||
|
options={[
|
||||||
|
{
|
||||||
|
label: "Female",
|
||||||
|
value: "female",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Male",
|
||||||
|
value: "male",
|
||||||
|
},
|
||||||
|
]}
|
||||||
/>
|
/>
|
||||||
<Radio
|
<DatePicker name="birthdate" label="Birth Date" fullWidth={true} />
|
||||||
label="Appeared between 10 and 20 times"
|
<DateRangePicker
|
||||||
name="occurences"
|
name="appearance_dates"
|
||||||
value="C"
|
startLabel="First appearance"
|
||||||
|
endLabel="Last appearance"
|
||||||
|
fullWidth={true}
|
||||||
/>
|
/>
|
||||||
<Radio
|
<Checkbox name="is_guest" label="This character is a guest" />
|
||||||
label="Appeared between 20+ times"
|
</div>
|
||||||
name="occurences"
|
<div className="card mt-l">
|
||||||
value="D"
|
<h3 className="fw-bold fs-h3">Bio</h3>
|
||||||
|
<Alert type={VariantType.WARNING}>
|
||||||
|
Please be exhaustive, every detail counts!
|
||||||
|
</Alert>
|
||||||
|
<TextArea
|
||||||
|
name="bio"
|
||||||
|
label="Biography"
|
||||||
|
text="Enter a detailed biography"
|
||||||
|
fullWidth={true}
|
||||||
|
rows={8}
|
||||||
/>
|
/>
|
||||||
</RadioGroup>
|
<RadioGroup>
|
||||||
<Switch name="is_public" label="Make this character public" />
|
<Radio
|
||||||
|
label="Appeared between 0 and 5 times"
|
||||||
<div>
|
name="occurences"
|
||||||
<h4>Add pictures</h4>
|
value="A"
|
||||||
|
|
||||||
<div className="mt-s">
|
|
||||||
<FileUploader
|
|
||||||
fullWidth={true}
|
|
||||||
text="JPG, PNG or GIF - Max file size 2MB"
|
|
||||||
multiple={true}
|
|
||||||
/>
|
/>
|
||||||
|
<Radio
|
||||||
|
label="Appeared between 6 and 10 times"
|
||||||
|
name="occurences"
|
||||||
|
value="B"
|
||||||
|
/>
|
||||||
|
<Radio
|
||||||
|
label="Appeared between 10 and 20 times"
|
||||||
|
name="occurences"
|
||||||
|
value="C"
|
||||||
|
/>
|
||||||
|
<Radio
|
||||||
|
label="Appeared between 20+ times"
|
||||||
|
name="occurences"
|
||||||
|
value="D"
|
||||||
|
/>
|
||||||
|
</RadioGroup>
|
||||||
|
<Switch name="is_public" label="Make this character public" />
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h4>Add pictures</h4>
|
||||||
|
|
||||||
|
<div className="mt-s">
|
||||||
|
<FileUploader
|
||||||
|
fullWidth={true}
|
||||||
|
text="JPG, PNG or GIF - Max file size 2MB"
|
||||||
|
multiple={true}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div className="mt-l">
|
||||||
<div className="mt-l">
|
<Button fullWidth={true} type="submit">
|
||||||
<Button fullWidth={true} type="submit">
|
Add character
|
||||||
Add character
|
</Button>
|
||||||
</Button>
|
</div>
|
||||||
</div>
|
</form>
|
||||||
</form>
|
</Modal>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,14 +3,15 @@ import {
|
|||||||
Button,
|
Button,
|
||||||
DataGrid,
|
DataGrid,
|
||||||
SortModel,
|
SortModel,
|
||||||
VariantType,
|
|
||||||
usePagination,
|
usePagination,
|
||||||
useToastProvider,
|
useToastProvider,
|
||||||
|
VariantType,
|
||||||
} from "@openfun/cunningham-react";
|
} from "@openfun/cunningham-react";
|
||||||
import { Page, PageProps } from "./App";
|
|
||||||
|
import { PageProps } from "./App";
|
||||||
import { database } from "./Character";
|
import { database } from "./Character";
|
||||||
|
|
||||||
export const Home = ({ changePage }: PageProps) => {
|
export const Home = ({ modal }: { modal: PageProps }) => {
|
||||||
const { toast } = useToastProvider();
|
const { toast } = useToastProvider();
|
||||||
const [rowSelection, setRowSelection] = useState({});
|
const [rowSelection, setRowSelection] = useState({});
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
@@ -21,6 +22,7 @@ export const Home = ({ changePage }: PageProps) => {
|
|||||||
sort: "desc",
|
sort: "desc",
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const [rows, setRows] = useState<typeof database>([]);
|
const [rows, setRows] = useState<typeof database>([]);
|
||||||
const [refresh, setRefresh] = useState(1);
|
const [refresh, setRefresh] = useState(1);
|
||||||
|
|
||||||
@@ -49,7 +51,7 @@ export const Home = ({ changePage }: PageProps) => {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}, [pagination.page, sortModel, refresh]);
|
}, [pagination.page, sortModel, modal.isOpen, refresh]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="page__home">
|
<div className="page__home">
|
||||||
@@ -70,7 +72,7 @@ export const Home = ({ changePage }: PageProps) => {
|
|||||||
<Button
|
<Button
|
||||||
color="primary"
|
color="primary"
|
||||||
icon={<span className="material-icons">movie</span>}
|
icon={<span className="material-icons">movie</span>}
|
||||||
onClick={() => changePage(Page.CREATE)}
|
onClick={modal.open}
|
||||||
>
|
>
|
||||||
Add character
|
Add character
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ p {
|
|||||||
// App
|
// App
|
||||||
html {
|
html {
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
padding-bottom: 5rem;
|
|
||||||
background: linear-gradient(153deg, var(--c--theme--colors--greyscale-100) 0%, var(--c--theme--colors--greyscale-000) 100%);
|
background: linear-gradient(153deg, var(--c--theme--colors--greyscale-100) 0%, var(--c--theme--colors--greyscale-000) 100%);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,6 +94,10 @@ html[data-theme="blueney"] {
|
|||||||
|
|
||||||
// Create
|
// Create
|
||||||
.page__create {
|
.page__create {
|
||||||
|
max-width: 960px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding-bottom: 5rem;
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin: 4rem 0;
|
margin: 4rem 0;
|
||||||
@@ -104,6 +107,7 @@ html[data-theme="blueney"] {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 1.5rem;
|
gap: 1.5rem;
|
||||||
|
text-align: left;
|
||||||
|
|
||||||
h3, h4 {
|
h3, h4 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user