-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathformHooks.ts
106 lines (100 loc) · 3.38 KB
/
formHooks.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
import { useState, useCallback, useMemo } from 'react';
import { ConfigurableProfile } from '../user';
type UserHook<T> = {
value: T;
onChange: (v: T) => void;
error: boolean;
valid: boolean;
check: () => boolean;
};
export const useStateWithValidate = <T>(initialValue: T, validate?: (value: T) => boolean): UserHook<T> => {
const [value, setValue] = useState<T>(initialValue);
const [edited, setEdited] = useState<boolean>(false);
const onChange = useCallback(
(v: T) => {
setEdited(true);
setValue(v);
},
[setEdited, setValue],
);
const valid = useMemo(() => (validate ? validate(value) : true), [value, validate]);
const check = useCallback(() => {
setEdited(true);
return valid;
}, [setEdited, valid]);
const error = useMemo(() => !valid && edited, [valid, edited]);
return {
value,
onChange,
error,
valid,
check,
};
};
// const hoge: React.FC<FormContentProp<number>> = (props) => {
// return <></>
// };
// 上記のように使う
export interface FormContentProps<T> {
value: T;
onChange: (newValue: T) => void;
error: boolean;
}
export type UserProfileHooks = {
[P in keyof ConfigurableProfile]: UserHook<ConfigurableProfile[P]>;
};
// user情報を操作するためのフックを返す.
const useUserHooks = (genFirstYear: number, user?: Partial<ConfigurableProfile>): UserProfileHooks => {
return {
//email: useStateWithValidate(user?.email ?? '', (value) => /^\S+@\S+$/.test(value)),
generation: useStateWithValidate(user?.generation ?? genFirstYear),
name: useStateWithValidate(user?.name ?? '', (value) => /^\S+\s\S+$/.test(value)),
kana: useStateWithValidate(user?.kana ?? '', (value) => /^[\u30A0-\u30FF]+\s[\u30A0-\u30FF]+$/.test(value)),
handle: useStateWithValidate(user?.handle ?? '', (value) => /^\S+$/.test(value)),
sex: useStateWithValidate(user?.sex ?? 'other'),
univName: useStateWithValidate(user?.univName ?? '', (value) => /^\S+$/.test(value)),
department: useStateWithValidate(user?.department ?? '', (value) => /^\S+$/.test(value)),
subject: useStateWithValidate(user?.subject ?? ''),
studentId: useStateWithValidate(user?.studentId ?? '', (value) => /^\S+$/.test(value)),
emergencyPhoneNumber: useStateWithValidate(user?.emergencyPhoneNumber ?? '', (value) => /^(0[5-9]0[0-9]{8}|0[1-9][1-9][0-9]{7})$/.test(value)),
otherCircles: useStateWithValidate(user?.otherCircles ?? ''),
workshops: useStateWithValidate(user?.workshops ?? [], (value) => value.length !== 0),
squads: useStateWithValidate(user?.squads ?? []),
discordId: useStateWithValidate(user?.discordId ?? '', (value) => /(^$)|(^.+#[0-9]{4}$)/.test(value)),
};
};
export type UserValidation = {
[P in keyof ConfigurableProfile]: boolean;
};
export const useUser = (
genFirstYear: number,
user?: Partial<ConfigurableProfile>,
): {
user: ConfigurableProfile;
valid: UserValidation;
userHooks: UserProfileHooks;
} => {
const userHooks = useUserHooks(genFirstYear, user);
const retUser = Object.entries(userHooks).reduce(
(prev, [k, v]) => ({
[k]: v?.value ?? true,
...prev,
}),
{},
) as ConfigurableProfile;
const valid = Object.entries(userHooks).reduce(
(prev, [k, v]) => ({
[k]: v?.valid ?? true,
...prev,
}),
{},
) as UserValidation;
return {
user: {
id: user?.id,
...retUser,
},
valid,
userHooks,
};
};