Skip to content

Commit 1c350c3

Browse files
committed
refactor: рефакторинг формы подачи пьесы
1 parent d667b5f commit 1c350c3

File tree

13 files changed

+111
-113
lines changed

13 files changed

+111
-113
lines changed

src/components/play-proposal-layout/image/index.ts

-1
This file was deleted.

src/components/play-proposal-layout/image/play-proposal-layout-image.module.css

-13
This file was deleted.

src/components/play-proposal-layout/image/play-proposal-layout-image.tsx

-21
This file was deleted.
+10-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,10 @@
1-
export { default } from './play-proposal-layout';
1+
import PlayProposalLayoutColumn from './column/play-proposal-layout-column';
2+
import PlayProposalForm from './form/play-proposal-layout-form';
3+
import { PlayProposalLayout as BaseComponent } from './play-proposal-layout';
4+
5+
const PlayProposalLayout = Object.assign(BaseComponent, {
6+
Column: PlayProposalLayoutColumn,
7+
Form: PlayProposalForm,
8+
});
9+
10+
export default PlayProposalLayout;
Loading
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,30 @@
1+
@value tablet-portrait from "shared/styles/media.module.css";
2+
13
.layout {
24
display: grid;
35
grid-template-columns: repeat(2, 1fr);
46

5-
@media (max-width: $tablet-portrait) {
7+
@media tablet-portrait {
68
padding: 0 24px;
79
grid-template-columns: 100%;
810
}
11+
12+
&::before {
13+
position: sticky;
14+
top: var(--height-navbar-tablet-portrait);
15+
display: block;
16+
width: 660px;
17+
height: calc(100vh - var(--height-navbar-tablet-portrait));
18+
background-image: url("./play-proposal-layout.assets/artwork-tablet-portrait.jpg");
19+
background-size: cover;
20+
content: "";
21+
22+
@media tablet-portrait {
23+
position: static;
24+
width: calc(100% + 24px);
25+
height: 152px;
26+
margin-top: 10px;
27+
background-image: url("./play-proposal-layout.assets/artwork-mobile.jpg");
28+
}
29+
}
930
}
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,10 @@
11
import classNames from 'classnames/bind';
22

3-
import PlayProposalLayoutColumn from './column/play-proposal-layout-column';
4-
import PlayProposalForm from './form/play-proposal-layout-form';
5-
import PlayProposalLayoutImage from './image/play-proposal-layout-image';
6-
73
import styles from './play-proposal-layout.module.css';
84

95
const cx = classNames.bind(styles);
106

11-
interface IPlayProposalLayoutProps {
12-
children: React.ReactNode
13-
}
14-
15-
const PlayProposalLayout = (props: IPlayProposalLayoutProps): JSX.Element => {
7+
export const PlayProposalLayout: React.FC = (props) => {
168
const { children } = props;
179

1810
return (
@@ -21,9 +13,3 @@ const PlayProposalLayout = (props: IPlayProposalLayoutProps): JSX.Element => {
2113
</main>
2214
);
2315
};
24-
25-
PlayProposalLayout.Image = PlayProposalLayoutImage;
26-
PlayProposalLayout.Column = PlayProposalLayoutColumn;
27-
PlayProposalLayout.Form = PlayProposalForm;
28-
29-
export default PlayProposalLayout;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './phone-number-input';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { DEFAULT_MASK_RULES } from 'react-hook-mask';
2+
3+
import TextInput from 'components/ui/text-input';
4+
5+
import type { TextInputProps } from 'components/ui/text-input';
6+
7+
const maskGenerator = {
8+
rules: DEFAULT_MASK_RULES,
9+
generateMask: (value: string) => value.startsWith('+') ? '+7 999 999 99 99' : '8 999 999 99 99',
10+
};
11+
12+
type PhoneNumberInputProps = Omit<TextInputProps, 'mask'>
13+
14+
export const PhoneNumberInput: React.FC<PhoneNumberInputProps> = (props) => (
15+
<TextInput
16+
{...props}
17+
type="tel"
18+
placeholder="Номер телефона"
19+
mask={maskGenerator}
20+
/>
21+
);

src/components/ui/text-input/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
export { default } from './text-input';
2+
export * from './text-input';

src/components/ui/text-input/text-input.tsx

+47-11
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,78 @@
11
import classNames from 'classnames/bind';
2+
import { useMemo } from 'react';
3+
import { MaskedInput, createDefaultMaskGenerator } from 'react-hook-mask';
24

3-
import type { ChangeEvent, InputHTMLAttributes } from 'react';
5+
import type { MaskGenerator } from 'react-hook-mask';
46

57
import styles from './text-input.module.css';
68

79
const cx = classNames.bind(styles);
810

9-
interface ITextInputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'onChange'> {
11+
type Mask = string | MaskGenerator
12+
13+
export interface TextInputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange' | 'value'> {
14+
value: string
1015
errorText?: string
1116
onChange?: (value: string) => void
1217
inputRef?: React.RefObject<HTMLInputElement>
18+
mask?: Mask
1319
}
1420

15-
const TextInput = (props: ITextInputProps): JSX.Element => {
21+
const TextInput: React.VFC<TextInputProps> = (props) => {
1622
const {
1723
errorText,
1824
onChange,
1925
inputRef,
26+
mask,
2027
...restProps
2128
} = props;
2229

23-
const handleChange = ({ target: { value } }: ChangeEvent<HTMLInputElement>) => {
30+
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
2431
if (!onChange) {
2532
return;
2633
}
2734

35+
const {
36+
target: {
37+
value,
38+
}
39+
} = event;
40+
2841
onChange(value);
2942
};
3043

44+
const commonProps = {
45+
ref: inputRef,
46+
type: 'text',
47+
className: cx('input', { invalid: !!errorText }),
48+
...restProps,
49+
};
50+
51+
const maskGenerator = useMemo(() => {
52+
switch (typeof mask) {
53+
case 'string':
54+
return createDefaultMaskGenerator(mask);
55+
case 'object':
56+
return mask;
57+
default:
58+
return;
59+
}
60+
}, [mask]);
61+
3162
return (
3263
<>
33-
<input
34-
ref={inputRef}
35-
type="text"
36-
className={cx('input', { invalid: !!errorText })}
37-
onChange={handleChange}
38-
{...restProps}
39-
/>
64+
{mask ? (
65+
<MaskedInput
66+
onChange={onChange}
67+
maskGenerator={maskGenerator}
68+
{...commonProps}
69+
/>
70+
) : (
71+
<input
72+
onChange={handleChange}
73+
{...commonProps}
74+
/>
75+
)}
4076
{errorText && (
4177
<p className={cx('error')}>
4278
{errorText}

src/pages/form/form.tsx

+8-50
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
import entries from 'lodash/entries';
22
import Error from 'next/error';
3-
import Image from 'next/image';
43
import Link from 'next/link';
54
import { useRouter } from 'next/router';
65
import { useState } from 'react';
7-
import { useIMask } from 'react-imask';
86

97
import { AppLayout } from 'components/app-layout';
108
import { FormField } from 'components/form-field';
@@ -15,6 +13,7 @@ import { Button } from 'components/ui/button2';
1513
import { FileInput } from 'components/ui/file-input';
1614
import Form from 'components/ui/form';
1715
import { Icon } from 'components/ui/icon';
16+
import { PhoneNumberInput } from 'components/ui/phone-number-input';
1817
import TextInput from 'components/ui/text-input';
1918
import { usePersistentData } from 'providers/persistent-data-provider';
2019
import { postParticipation } from 'services/api/participation';
@@ -45,31 +44,6 @@ const initialFormValues: ParticipationFormFields = {
4544
file: null,
4645
};
4746

48-
const phoneMaskOptions = {
49-
mask: [
50-
{
51-
mask: '+0 000 000-00-00',
52-
startsWith: '7',
53-
},
54-
{
55-
mask: '+0DD',
56-
blocks: {
57-
DD: {
58-
mask: /^[\d- ()]{0,15}$/
59-
},
60-
},
61-
startsWith: '',
62-
},
63-
],
64-
dispatch: function (appended: string, dynamicMasked: { value: string; compiledMasks: { startsWith: string }[] }) {
65-
const number = (dynamicMasked.value + appended).replace(/\D/g,'');
66-
67-
return dynamicMasked.compiledMasks.find(function (m) {
68-
return number.indexOf(m.startsWith) === 0;
69-
});
70-
}
71-
};
72-
7347
const validate = (values: ParticipationFormFields) => {
7448
const errors = {} as Record<keyof ParticipationFormFields, string>;
7549

@@ -94,7 +68,7 @@ const validate = (values: ParticipationFormFields) => {
9468
} else if (!validYearRegexp.test(values.birthYear)) {
9569
errors.birthYear = 'Убедитесь, что это значение больше либо равно 1900';
9670
} else if (values.birthYear > CURRENT_YEAR) {
97-
errors.birthYear = `Убедитесь, что это значение больше либо равно ${CURRENT_YEAR}`;
71+
errors.birthYear = `Убедитесь, что это значение меньше либо равно ${CURRENT_YEAR}`;
9872
}
9973

10074
if (!values.city.length) {
@@ -128,7 +102,7 @@ const validate = (values: ParticipationFormFields) => {
128102
} else if (!validYearRegexp.test(values.year)) {
129103
errors.year = 'Убедитесь, что это значение больше либо равно 1900';
130104
} else if (values.year > CURRENT_YEAR) {
131-
errors.year = `Убедитесь, что это значение больше либо равно ${CURRENT_YEAR}`;
105+
errors.year = `Убедитесь, что это значение меньше либо равно ${CURRENT_YEAR}`;
132106
}
133107

134108
if (!values.file) {
@@ -146,15 +120,6 @@ const Participation = () => {
146120
});
147121
const { settings } = usePersistentData();
148122

149-
const { ref: phoneNumberInputRef } = useIMask<typeof phoneMaskOptions>(phoneMaskOptions, {
150-
onAccept: (value) => {
151-
if (form.values.phoneNumber === value) {
152-
return;
153-
}
154-
form.setFieldValue('phoneNumber', value);
155-
},
156-
});
157-
158123
const router = useRouter();
159124

160125
const handleSubmitError = (error: unknown) => {
@@ -215,14 +180,6 @@ const Participation = () => {
215180
title="Подать пьесу"
216181
/>
217182
<PlayProposalLayout>
218-
<PlayProposalLayout.Image>
219-
<Image
220-
src="/images/form/play-script.jpg"
221-
alt="Напечатанная читка в руках человека"
222-
layout="fill"
223-
objectFit="cover"
224-
/>
225-
</PlayProposalLayout.Image>
226183
<PlayProposalLayout.Column>
227184
<PlayProposalTitle/>
228185
<PlayProposalLayout.Form>
@@ -262,6 +219,7 @@ const Participation = () => {
262219
<TextInput
263220
value={form.values.birthYear}
264221
placeholder="Год рождения"
222+
mask="9999"
265223
errorText={form.touched.birthYear ? form.errors.birthYear : ''}
266224
onChange={(value) => form.setFieldValue('birthYear', value)}
267225
/>
@@ -285,10 +243,8 @@ const Participation = () => {
285243
caption="Номер телефона"
286244
hiddenCaption
287245
>
288-
<TextInput
289-
inputRef={phoneNumberInputRef}
290-
type="tel"
291-
placeholder="Номер телефона"
246+
<PhoneNumberInput
247+
value={form.values.phoneNumber}
292248
errorText={form.touched.phoneNumber ? form.errors.phoneNumber : ''}
293249
/>
294250
</FormField>
@@ -299,6 +255,7 @@ const Participation = () => {
299255
hiddenCaption
300256
>
301257
<TextInput
258+
type="email"
302259
value={form.values.email}
303260
placeholder="E-mail"
304261
errorText={form.touched.email ? form.errors.email : ''}
@@ -329,6 +286,7 @@ const Participation = () => {
329286
<TextInput
330287
value={form.values.year}
331288
placeholder="Год написания"
289+
mask="9999"
332290
errorText={form.touched.year ? form.errors.year : ''}
333291
onChange={(value) => form.setFieldValue('year', value)}
334292
/>

0 commit comments

Comments
 (0)