Skip to content

Commit 2ab79b2

Browse files
Refactor into a hooks
1 parent 46f265a commit 2ab79b2

File tree

3 files changed

+232
-187
lines changed

3 files changed

+232
-187
lines changed

src/components/Admin/Dashboard/index.tsx

Lines changed: 3 additions & 187 deletions
Original file line numberDiff line numberDiff line change
@@ -3,34 +3,17 @@ import loadable from '@loadable/component';
33
import React, { useEffect, useState } from 'react';
44

55
import {
6-
Button,
76
Card,
8-
Collapse,
97
DatePicker,
10-
Form,
118
InputNumber,
12-
List,
13-
Modal,
14-
Select,
15-
Skeleton,
169
Switch,
17-
Typography,
18-
message,
1910
Flex,
2011
} from 'antd';
21-
import { EditOutlined, SaveOutlined } from '@ant-design/icons';
2212

23-
import { CommonService, CookieService, IText, TextService, TextType } from '../../../services';
13+
import { CookieService, IText, TextService, TextType } from '../../../services';
2414
import { FestivalService, IFestival } from '../../../services/admin/festival';
2515

2616
import {
27-
CANCEL,
28-
DASHBOARD_ADD_TEXT,
29-
DASHBOARD_MODAL_NEW_TEXT_TITLE,
30-
DASHBOARD_MODAL_TEXT,
31-
DASHBOARD_MODAL_TEXT_RULE,
32-
DASHBOARD_MODAL_TYPE,
33-
DASHBOARD_MODAL_TYPE_RULE,
3417
DASHBOARD_PLACEHOLDER_LATITUDE,
3518
DASHBOARD_PLACEHOLDER_LONGITUDE,
3619
DASHBOARD_SHOW_HOME_INFORMATION,
@@ -40,30 +23,13 @@ import {
4023
DASHBOARD_TITLE_GPS_COORDS,
4124
DASHBOARD_TITLE_INFORMATION,
4225
} from './Dashboard.constants';
43-
import { MODAL_ADD_TEXT, MODAL_CANCEL_TEXT } from '../Admin.constants';
44-
import { showErrorFormMessage } from '../../../lib/validation';
26+
import DashboardText from '../DashboardText';
4527

4628
const Navigation = loadable(() => import('../../../pages/admin/Navigation'));
47-
const TinyMceEditor = loadable(() => import('../TinyMceEditor'));
48-
const { Option } = Select;
4929
const { RangePicker } = DatePicker;
5030

5131
type NoUndefinedRangeValueType<DateType> = [DateType | null, DateType | null] | null;
5232

53-
const selectTextType = [
54-
{ text: 'Musique', value: TextType.music },
55-
{ text: 'Court-métrage', value: TextType.movie },
56-
{ text: 'Concours', value: TextType.contest },
57-
{ text: 'Association', value: TextType.association },
58-
{ text: 'Mazette c’est qui', value: TextType.team },
59-
{ text: 'Adhérer', value: TextType.adhere },
60-
{ text: 'Boire et manger', value: TextType.food },
61-
{ text: 'Venir au festival', value: TextType.journey },
62-
{ text: 'Accueil', value: TextType.home },
63-
{ text: 'Info', value: TextType.info },
64-
{ text: 'Editions précédentes', value: TextType.previousEdition },
65-
];
66-
6733
const Dashboard: React.FC = () => {
6834
const [isTextLoading, setIsTextLoading] = useState<boolean>(false);
6935
const [texts, setTexts] = useState<IText[]>([]);
@@ -72,11 +38,6 @@ const Dashboard: React.FC = () => {
7238
const [festival, setFestival] = useState<IFestival>({} as IFestival);
7339
const [toggleLoading, setToggleLoading] = useState<{ [x: string]: boolean }>({});
7440

75-
const [addRowModalVisible, setAddRowModalVisible] = useState<boolean>(false);
76-
const [editingId, setEditingId] = useState<number>(0);
77-
const [formRowAddition] = Form.useForm();
78-
const [formRowEdition] = Form.useForm();
79-
8041
useEffect(() => {
8142
setIsTextLoading(true);
8243
TextService.getAll()
@@ -89,101 +50,6 @@ const Dashboard: React.FC = () => {
8950
});
9051
}, [newTexts]);
9152

92-
const isEditing = (item: IText): boolean => item.id === editingId;
93-
94-
const saveRow = async (id: number): Promise<void> => {
95-
const hideLoadingMessage = message.loading('Modification en cours', 0);
96-
formRowEdition
97-
.validateFields()
98-
.then((row) => {
99-
TextService.update(id, row)
100-
.then((res) => {
101-
const index = texts.findIndex((text) => text.id === id);
102-
setNewTexts(
103-
texts.splice(index, 1, {
104-
...texts[index],
105-
...res,
106-
})
107-
);
108-
message.success('Modification effectuée', 2.5);
109-
})
110-
.catch((err) => message.error(`Erreur lors de la modification: ${err}`, 2.5))
111-
.finally(() => {
112-
hideLoadingMessage();
113-
formRowEdition.resetFields();
114-
});
115-
})
116-
.catch(() => showErrorFormMessage())
117-
.finally(() => {
118-
hideLoadingMessage();
119-
setEditingId(0);
120-
});
121-
};
122-
123-
const editRow = (item: Partial<IText>): void => {
124-
formRowEdition.setFieldsValue({
125-
text: '',
126-
...item,
127-
});
128-
setEditingId(item.id || 0);
129-
};
130-
131-
const cancel = (): void => setEditingId(0);
132-
133-
const renderListTextItem = (item: IText, key: number): React.ReactNode => {
134-
const editable = isEditing(item);
135-
return (
136-
<List.Item key={key} className="inline-flex items-center justify-between w-full">
137-
{editable ? (
138-
<Form.Item
139-
className="w-full"
140-
name="text"
141-
initialValue={item.text}>
142-
<TinyMceEditor textareaName="text" initialValue={item.text} form={formRowEdition} />
143-
</Form.Item>
144-
) : (
145-
<div className="w-full whitespace-pre-line" dangerouslySetInnerHTML={{ __html: item.text }} />
146-
)}
147-
{editable ? (
148-
<span className="flex flex-col items-center ml-4 gap-2">
149-
<Button icon={<SaveOutlined />} onClick={() => saveRow(item.id)} />
150-
<Typography.Link onClick={cancel} className="text-nowrap">
151-
{CANCEL}
152-
</Typography.Link>
153-
</span>
154-
) : (
155-
<Button icon={<EditOutlined />} onClick={() => editRow(item)} />
156-
)}
157-
</List.Item>
158-
);
159-
};
160-
161-
const handleOkModal = async (): Promise<void> => {
162-
const hideLoadingMessage = message.loading('Ajout en cours', 0);
163-
formRowAddition
164-
.validateFields()
165-
.then((values) => {
166-
TextService.create(values)
167-
.then((text) => {
168-
setTexts([...texts, text]);
169-
message.success('Texte ajouté', 2.5);
170-
})
171-
.catch((err) => message.error(`Erreur lors de l'ajout: ${err}`, 2.5))
172-
.finally(() => {
173-
hideLoadingMessage();
174-
formRowAddition.resetFields();
175-
});
176-
setAddRowModalVisible(false);
177-
})
178-
.catch(() => {
179-
showErrorFormMessage();
180-
})
181-
.finally(() => hideLoadingMessage());
182-
};
183-
184-
const collapseTitle = (textType: string): string =>
185-
CommonService.capitalize(selectTextType.find((item) => item.value === textType)?.text || '');
186-
18753
const updateInformationsVisibility = (checked: boolean): void => {
18854
if (infoText) {
18955
TextService.update(infoText.id, {
@@ -255,28 +121,7 @@ const Dashboard: React.FC = () => {
255121
<Navigation>
256122
<div className="grid grid-cols-12 gap-2 md:gap-5">
257123
<Card bordered={false} className="rounded-lg col-span-12 lg:col-span-8">
258-
<Button type="primary" className="my-4 button" onClick={() => setAddRowModalVisible(true)}>
259-
{DASHBOARD_ADD_TEXT}
260-
</Button>
261-
<Collapse
262-
accordion={true}
263-
onChange={cancel}
264-
defaultActiveKey={0}
265-
items={Object.values(TextType).map((textType) => ({
266-
key: textType,
267-
label: collapseTitle(textType),
268-
children: (
269-
<Skeleton avatar={true} active={true} loading={isTextLoading}>
270-
<Form form={formRowEdition} component={false}>
271-
<List
272-
dataSource={texts.filter((value) => value.type === textType)}
273-
renderItem={renderListTextItem}
274-
/>
275-
</Form>
276-
</Skeleton>
277-
),
278-
}))}
279-
/>
124+
<DashboardText isLoading={isTextLoading} texts={texts} setTexts={setTexts} setNewTexts={setNewTexts} />
280125
</Card>
281126
<Card bordered={false} className="rounded-lg col-span-12 lg:col-span-4">
282127
<div className="space-y-4">
@@ -337,35 +182,6 @@ const Dashboard: React.FC = () => {
337182
</div>
338183
</Card>
339184
</div>
340-
<Modal
341-
title={DASHBOARD_MODAL_NEW_TEXT_TITLE}
342-
open={addRowModalVisible}
343-
okText={MODAL_ADD_TEXT}
344-
onCancel={() => setAddRowModalVisible(false)}
345-
cancelText={MODAL_CANCEL_TEXT}
346-
okButtonProps={{ className: 'button' }}
347-
onOk={handleOkModal}>
348-
<Form form={formRowAddition}>
349-
<Form.Item
350-
label={DASHBOARD_MODAL_TEXT}
351-
name="text"
352-
rules={[{ required: true, message: DASHBOARD_MODAL_TEXT_RULE }]}>
353-
<TinyMceEditor textareaName="text" form={formRowAddition} />
354-
</Form.Item>
355-
<Form.Item
356-
label={DASHBOARD_MODAL_TYPE}
357-
name="type"
358-
rules={[{ required: true, message: DASHBOARD_MODAL_TYPE_RULE }]}>
359-
<Select>
360-
{selectTextType.map((type, key) => (
361-
<Option key={key} value={type.value}>
362-
{type.text}
363-
</Option>
364-
))}
365-
</Select>
366-
</Form.Item>
367-
</Form>
368-
</Modal>
369185
</Navigation>
370186
);
371187
};
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
import React, { Dispatch, SetStateAction } from 'react';
2+
import { Button, Collapse, Form, List, Modal, Select, Skeleton, Typography } from 'antd';
3+
import {
4+
CANCEL,
5+
DASHBOARD_ADD_TEXT,
6+
DASHBOARD_MODAL_NEW_TEXT_TITLE,
7+
DASHBOARD_MODAL_TEXT, DASHBOARD_MODAL_TEXT_RULE, DASHBOARD_MODAL_TYPE, DASHBOARD_MODAL_TYPE_RULE
8+
} from '../Dashboard/Dashboard.constants';
9+
import { IText, TextType } from '../../../services';
10+
import { MODAL_ADD_TEXT, MODAL_CANCEL_TEXT } from '../Admin.constants';
11+
import TinyMceEditor from '../TinyMceEditor';
12+
import { EditOutlined, SaveOutlined } from '@ant-design/icons';
13+
import { useDashboardText } from './useDashboardText.hook';
14+
15+
interface DashboardTextProps {
16+
isLoading: boolean;
17+
texts: IText[],
18+
setTexts: Dispatch<SetStateAction<IText[]>>
19+
setNewTexts: Dispatch<SetStateAction<IText[]>>
20+
}
21+
22+
const DashboardText: React.FC<DashboardTextProps> = ({ isLoading, texts, setTexts, setNewTexts }) => {
23+
const { isEditing,
24+
saveRow,
25+
editRow,
26+
cancel,
27+
collapseTitle,
28+
addRowModalVisible,
29+
handleOkModal,
30+
setAddRowModalVisible,
31+
formRowAddition,
32+
formRowEdition,
33+
selectTextType,
34+
} = useDashboardText({ texts, setTexts, setNewTexts });
35+
36+
const renderListTextItem = (item: IText, key: number): React.ReactNode => {
37+
const editable = isEditing(item);
38+
return (
39+
<List.Item key={key} className="inline-flex items-center justify-between w-full">
40+
{editable ? (
41+
<Form.Item
42+
className="w-full"
43+
name="text"
44+
initialValue={item.text}>
45+
<TinyMceEditor textareaName="text" initialValue={item.text} form={formRowEdition} />
46+
</Form.Item>
47+
) : (
48+
<div className="w-full whitespace-pre-line" dangerouslySetInnerHTML={{ __html: item.text }} />
49+
)}
50+
{editable ? (
51+
<span className="flex flex-col items-center ml-4 gap-2">
52+
<Button icon={<SaveOutlined />} onClick={() => saveRow(item.id)} />
53+
<Typography.Link onClick={cancel} className="text-nowrap">
54+
{CANCEL}
55+
</Typography.Link>
56+
</span>
57+
) : (
58+
<Button icon={<EditOutlined />} onClick={() => editRow(item)} />
59+
)}
60+
</List.Item>
61+
);
62+
};
63+
64+
return (
65+
<>
66+
<Button type="primary" className="my-4 button" onClick={() => setAddRowModalVisible(true)}>
67+
{DASHBOARD_ADD_TEXT}
68+
</Button>
69+
<Collapse
70+
accordion={true}
71+
onChange={cancel}
72+
defaultActiveKey={0}
73+
items={Object.values(TextType).map((textType) => ({
74+
key: textType,
75+
label: collapseTitle(textType),
76+
children: (
77+
<Skeleton avatar={true} active={true} loading={isLoading}>
78+
<Form form={formRowEdition} component={false}>
79+
<List
80+
dataSource={texts.filter(({ type }) => type === textType)}
81+
renderItem={renderListTextItem}
82+
/>
83+
</Form>
84+
</Skeleton>
85+
),
86+
}))}
87+
/>
88+
89+
<Modal
90+
title={DASHBOARD_MODAL_NEW_TEXT_TITLE}
91+
open={addRowModalVisible}
92+
okText={MODAL_ADD_TEXT}
93+
onCancel={() => setAddRowModalVisible(false)}
94+
cancelText={MODAL_CANCEL_TEXT}
95+
okButtonProps={{ className: 'button' }}
96+
onOk={handleOkModal}>
97+
<Form form={formRowAddition}>
98+
<Form.Item
99+
label={DASHBOARD_MODAL_TEXT}
100+
name="text"
101+
rules={[{ required: true, message: DASHBOARD_MODAL_TEXT_RULE }]}>
102+
<TinyMceEditor textareaName="text" form={formRowAddition}/>
103+
</Form.Item>
104+
<Form.Item
105+
label={DASHBOARD_MODAL_TYPE}
106+
name="type"
107+
rules={[{ required: true, message: DASHBOARD_MODAL_TYPE_RULE }]}>
108+
<Select>
109+
{selectTextType.map(({ value, text }, key) => (
110+
<Select.Option key={key} value={value}>
111+
{text}
112+
</Select.Option>
113+
))}
114+
</Select>
115+
</Form.Item>
116+
</Form>
117+
</Modal>
118+
119+
</>
120+
);
121+
};
122+
123+
export default DashboardText;

0 commit comments

Comments
 (0)