Skip to content

Commit 9e36778

Browse files
committed
storybook: add Advanced Customization story
1 parent 5182f88 commit 9e36778

1 file changed

Lines changed: 247 additions & 0 deletions

File tree

Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
import AutoStoriesIcon from '@mui/icons-material/AutoStories';
2+
import ReviewsIcon from '@mui/icons-material/Reviews';
3+
import { Rating, Stack } from '@mui/material';
4+
import React from 'react';
5+
import type { InputProps } from 'react-admin';
6+
import {
7+
AutocompleteInput,
8+
Create,
9+
Datagrid,
10+
DateField,
11+
Edit,
12+
Labeled,
13+
Layout,
14+
List,
15+
NumberField,
16+
ReferenceArrayField,
17+
ReferenceField,
18+
ReferenceInput,
19+
Show,
20+
SimpleForm,
21+
SimpleList,
22+
SimpleShowLayout,
23+
TabbedShowLayout,
24+
TextField,
25+
TextInput,
26+
WithRecord,
27+
WrapperField,
28+
defaultDarkTheme,
29+
defaultLightTheme,
30+
required,
31+
useInput,
32+
} from 'react-admin';
33+
import ResourceGuesser from '../../core/ResourceGuesser';
34+
import FieldGuesser from '../../field/FieldGuesser';
35+
import { HydraAdmin } from '../../hydra';
36+
import InputGuesser from '../../input/InputGuesser';
37+
38+
export default {
39+
title: 'Admin/Custom/AdvancedCustomization',
40+
parameters: {
41+
layout: 'fullscreen',
42+
},
43+
};
44+
45+
const BookCreate = () => (
46+
<Create>
47+
<SimpleForm sx={{ maxWidth: 500 }}>
48+
<InputGuesser source="title" helperText={false} />
49+
<InputGuesser source="author" helperText={false} />
50+
<TextInput
51+
source="description"
52+
multiline
53+
helperText={false}
54+
validate={required()}
55+
/>
56+
<Stack direction="row" gap={2} width="100%">
57+
<InputGuesser source="isbn" label="ISBN" helperText={false} />
58+
<InputGuesser source="publicationDate" helperText={false} />
59+
</Stack>
60+
</SimpleForm>
61+
</Create>
62+
);
63+
64+
const BookEdit = () => (
65+
<Edit warnWhenUnsavedChanges>
66+
<SimpleForm sx={{ maxWidth: 500 }}>
67+
<InputGuesser source="title" helperText={false} />
68+
<InputGuesser source="author" helperText={false} />
69+
<TextInput
70+
source="description"
71+
multiline
72+
helperText={false}
73+
validate={required()}
74+
/>
75+
<Stack direction="row" gap={2} width="100%">
76+
<InputGuesser source="isbn" label="ISBN" helperText={false} />
77+
<InputGuesser source="publicationDate" helperText={false} />
78+
</Stack>
79+
</SimpleForm>
80+
</Edit>
81+
);
82+
83+
const BookShow = () => (
84+
<Show>
85+
<TabbedShowLayout>
86+
<TabbedShowLayout.Tab label="main">
87+
<TextField source="title" variant="h5" />
88+
<TextField source="author" variant="body1" />
89+
<TextField source="description" variant="body1" />
90+
<SimpleShowLayout direction="row" gap={2} sx={{ p: 0 }}>
91+
<TextField source="isbn" label="ISBN" variant="body1" />
92+
<DateField source="publicationDate" variant="body1" />
93+
</SimpleShowLayout>
94+
</TabbedShowLayout.Tab>
95+
<TabbedShowLayout.Tab label="reviews">
96+
<ReferenceArrayField source="reviews" reference="reviews" label={false}>
97+
<SimpleList
98+
primaryText="%{body}"
99+
secondaryText="by %{author} on %{publicationDate}"
100+
sx={{ pt: 0, '& .MuiListItemButton-root': { p: 0 } }}
101+
leftAvatar={(review) =>
102+
review.author
103+
.split(' ')
104+
.map((name: string) => name[0])
105+
.join('')
106+
}
107+
// eslint-disable-next-line react/no-unstable-nested-components
108+
tertiaryText={(review) => (
109+
<Rating value={review.rating} readOnly size="small" />
110+
)}
111+
/>
112+
</ReferenceArrayField>
113+
</TabbedShowLayout.Tab>
114+
</TabbedShowLayout>
115+
</Show>
116+
);
117+
118+
const BookList = () => (
119+
<List sort={{ field: 'publicationDate', order: 'DESC' }}>
120+
<Datagrid>
121+
<FieldGuesser source="isbn" label="ISBN" />
122+
<FieldGuesser source="title" />
123+
<FieldGuesser source="author" />
124+
<FieldGuesser source="publicationDate" />
125+
<NumberField source="reviews.length" label="Reviews" />
126+
</Datagrid>
127+
</List>
128+
);
129+
130+
const RatingInput = (props: InputProps) => {
131+
const { field } = useInput(props);
132+
return (
133+
<Rating
134+
{...field}
135+
onChange={(_event, value) => {
136+
field.onChange(value);
137+
}}
138+
/>
139+
);
140+
};
141+
142+
const filterToBookQuery = (searchText: string) => ({
143+
title: `%${searchText}%`,
144+
});
145+
146+
const ReviewCreate = () => (
147+
<Create>
148+
<SimpleForm
149+
sx={{ maxWidth: 500 }}
150+
defaultValues={{ publicationDate: new Date() }}>
151+
<InputGuesser source="author" helperText={false} />
152+
<ReferenceInput source="book" reference="books">
153+
<AutocompleteInput
154+
helperText={false}
155+
filterToQuery={filterToBookQuery}
156+
/>
157+
</ReferenceInput>
158+
<Labeled label="Rating">
159+
<RatingInput source="rating" />
160+
</Labeled>
161+
<InputGuesser source="body" multiline helperText={false} />
162+
</SimpleForm>
163+
</Create>
164+
);
165+
166+
const ReviewEdit = () => (
167+
<Edit warnWhenUnsavedChanges>
168+
<SimpleForm sx={{ maxWidth: 500 }}>
169+
<InputGuesser source="author" helperText={false} />
170+
<ReferenceInput source="book" reference="books">
171+
<AutocompleteInput
172+
helperText={false}
173+
filterToQuery={filterToBookQuery}
174+
/>
175+
</ReferenceInput>
176+
<Labeled label="Rating">
177+
<RatingInput source="rating" />
178+
</Labeled>
179+
<InputGuesser source="body" multiline helperText={false} />
180+
<Labeled label="Publication date">
181+
<DateField source="publicationDate" showTime />
182+
</Labeled>
183+
</SimpleForm>
184+
</Edit>
185+
);
186+
187+
const ReviewShow = () => (
188+
<Show>
189+
<SimpleShowLayout>
190+
<FieldGuesser source="author" />
191+
<ReferenceField source="book" reference="books" />
192+
<FieldGuesser source="body" />
193+
<Labeled label="Rating">
194+
<WithRecord
195+
render={(review) => (
196+
<Rating value={review.rating} readOnly size="small" />
197+
)}
198+
/>
199+
</Labeled>
200+
<DateField showTime source="publicationDate" />
201+
</SimpleShowLayout>
202+
</Show>
203+
);
204+
205+
const ReviewList = () => (
206+
<List sort={{ field: 'publicationDate', order: 'DESC' }}>
207+
<Datagrid>
208+
<FieldGuesser source="author" />
209+
<ReferenceField source="book" reference="books" />
210+
<WrapperField label="Rating">
211+
<WithRecord
212+
render={(review) => (
213+
<Rating value={review.rating} readOnly size="small" />
214+
)}
215+
/>
216+
</WrapperField>
217+
<DateField showTime source="publicationDate" />
218+
</Datagrid>
219+
</List>
220+
);
221+
222+
export const AdvancedCustomization = () => (
223+
<HydraAdmin
224+
entrypoint={process.env.ENTRYPOINT}
225+
layout={Layout}
226+
theme={defaultLightTheme}
227+
darkTheme={defaultDarkTheme}>
228+
<ResourceGuesser
229+
name="books"
230+
list={BookList}
231+
show={BookShow}
232+
edit={BookEdit}
233+
create={BookCreate}
234+
recordRepresentation="name"
235+
icon={AutoStoriesIcon}
236+
/>
237+
<ResourceGuesser
238+
name="reviews"
239+
list={ReviewList}
240+
show={ReviewShow}
241+
edit={ReviewEdit}
242+
create={ReviewCreate}
243+
recordRepresentation="id"
244+
icon={ReviewsIcon}
245+
/>
246+
</HydraAdmin>
247+
);

0 commit comments

Comments
 (0)