goobs-frontend 0.7.63 → 0.7.65
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +14 -14
- package/src/components/Button/hook/useHelperFooter.tsx +224 -0
- package/src/components/Button/index.tsx +186 -191
- package/src/components/ConfirmationCodeInput/index.tsx +7 -9
- package/src/components/Content/Structure/button/useButton.tsx +0 -2
- package/src/components/Nav/HorizontalVariant/index.tsx +13 -39
- package/src/components/StyledComponent/hooks/useInputHelperFooter.tsx +567 -0
- package/src/components/StyledComponent/hooks/usePhoneNumber.tsx +28 -12
- package/src/components/StyledComponent/hooks/useRequiredFieldsValidator.tsx +137 -0
- package/src/components/StyledComponent/index.tsx +28 -40
- package/src/components/TransferList/index.tsx +12 -4
- package/src/components/StyledComponent/helperfooter/useHelperFooter.tsx +0 -580
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { useCallback, useMemo, MutableRefObject } from 'react'
|
|
2
|
+
import { session } from 'goobs-cache'
|
|
3
|
+
import { StyledComponentProps } from '../index'
|
|
4
|
+
import { HelperFooterMessage } from './useInputHelperFooter'
|
|
5
|
+
|
|
6
|
+
type HelperFooterState = Record<string, HelperFooterMessage>
|
|
7
|
+
|
|
8
|
+
export const useRequiredFieldsValidator = (
|
|
9
|
+
formname: string,
|
|
10
|
+
components: StyledComponentProps[],
|
|
11
|
+
hasInputRef: MutableRefObject<boolean>
|
|
12
|
+
) => {
|
|
13
|
+
console.log('useRequiredFieldsValidator called with:', {
|
|
14
|
+
formname,
|
|
15
|
+
components,
|
|
16
|
+
hasInputRef,
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
const helperFootersAtom = session.atom<HelperFooterState>({})
|
|
20
|
+
const [helperFooters, setHelperFooters] = session.useAtom(helperFootersAtom)
|
|
21
|
+
|
|
22
|
+
const initializeComponentStatuses = useCallback(() => {
|
|
23
|
+
console.log('initializeComponentStatuses called')
|
|
24
|
+
|
|
25
|
+
const initialHelperFooters: HelperFooterState = { ...helperFooters }
|
|
26
|
+
|
|
27
|
+
components.forEach(component => {
|
|
28
|
+
if (
|
|
29
|
+
component.name &&
|
|
30
|
+
component.required &&
|
|
31
|
+
component.label &&
|
|
32
|
+
!initialHelperFooters[component.name]
|
|
33
|
+
) {
|
|
34
|
+
initialHelperFooters[component.name] = {
|
|
35
|
+
status: 'emptyAndRequired',
|
|
36
|
+
statusMessage: `${component.label} is required.`,
|
|
37
|
+
spreadMessage: `${component.label} is required.`,
|
|
38
|
+
spreadMessagePriority: component.spreadMessagePriority || 1,
|
|
39
|
+
required: true,
|
|
40
|
+
hasInput: false,
|
|
41
|
+
}
|
|
42
|
+
console.log(
|
|
43
|
+
`Created new helper footer for ${component.name}:`,
|
|
44
|
+
initialHelperFooters[component.name]
|
|
45
|
+
)
|
|
46
|
+
}
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
console.log('Setting helper footers in session atom')
|
|
50
|
+
setHelperFooters(initialHelperFooters)
|
|
51
|
+
|
|
52
|
+
console.log(`Initialized helper footers:`, initialHelperFooters)
|
|
53
|
+
}, [components, helperFooters, setHelperFooters])
|
|
54
|
+
|
|
55
|
+
const checkFormStatus = useCallback(() => {
|
|
56
|
+
console.log('checkFormStatus called')
|
|
57
|
+
const requiredComponents = components.filter(
|
|
58
|
+
component => component.required
|
|
59
|
+
)
|
|
60
|
+
console.log('Required components:', requiredComponents)
|
|
61
|
+
|
|
62
|
+
const allRequiredHaveInput = requiredComponents.every(
|
|
63
|
+
component =>
|
|
64
|
+
helperFooters[component.name || '']?.hasInput || hasInputRef.current
|
|
65
|
+
)
|
|
66
|
+
console.log('All required fields have input:', allRequiredHaveInput)
|
|
67
|
+
return allRequiredHaveInput
|
|
68
|
+
}, [components, hasInputRef, helperFooters])
|
|
69
|
+
|
|
70
|
+
const getEmptyRequiredFields = useCallback(() => {
|
|
71
|
+
console.log('getEmptyRequiredFields called')
|
|
72
|
+
|
|
73
|
+
const emptyFields = Object.entries(helperFooters)
|
|
74
|
+
.filter(
|
|
75
|
+
([, value]) => value.required && !value.hasInput && !hasInputRef.current
|
|
76
|
+
)
|
|
77
|
+
.map(([key]) => key)
|
|
78
|
+
console.log('Empty required fields:', emptyFields)
|
|
79
|
+
return emptyFields
|
|
80
|
+
}, [hasInputRef, helperFooters])
|
|
81
|
+
|
|
82
|
+
const validateRequiredField = useCallback(
|
|
83
|
+
(
|
|
84
|
+
name: string,
|
|
85
|
+
label: string,
|
|
86
|
+
required: boolean,
|
|
87
|
+
spreadMessagePriority: number
|
|
88
|
+
) => {
|
|
89
|
+
console.log(`validateRequiredField called for ${name}`)
|
|
90
|
+
|
|
91
|
+
if (required && !helperFooters[name]?.hasInput && !hasInputRef.current) {
|
|
92
|
+
console.log(`${name} is required and empty, updating helper footer`)
|
|
93
|
+
const newHelperFooter: HelperFooterMessage = {
|
|
94
|
+
status: 'emptyAndRequired',
|
|
95
|
+
statusMessage: `${label} is required.`,
|
|
96
|
+
spreadMessage: `${label} is required.`,
|
|
97
|
+
spreadMessagePriority,
|
|
98
|
+
required: true,
|
|
99
|
+
hasInput: false,
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
setHelperFooters(prev => ({
|
|
103
|
+
...prev,
|
|
104
|
+
[name]: newHelperFooter,
|
|
105
|
+
}))
|
|
106
|
+
|
|
107
|
+
console.log('Updated helperFooters:', {
|
|
108
|
+
...helperFooters,
|
|
109
|
+
[name]: newHelperFooter,
|
|
110
|
+
})
|
|
111
|
+
} else {
|
|
112
|
+
console.log(`${name} validation not needed or already has input`)
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
[hasInputRef, helperFooters, setHelperFooters]
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
const result = useMemo(
|
|
119
|
+
() => ({
|
|
120
|
+
checkFormStatus,
|
|
121
|
+
getEmptyRequiredFields,
|
|
122
|
+
validateRequiredField,
|
|
123
|
+
initializeComponentStatuses,
|
|
124
|
+
}),
|
|
125
|
+
[
|
|
126
|
+
checkFormStatus,
|
|
127
|
+
getEmptyRequiredFields,
|
|
128
|
+
validateRequiredField,
|
|
129
|
+
initializeComponentStatuses,
|
|
130
|
+
]
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
console.log('useRequiredFieldsValidator returning:', result)
|
|
134
|
+
return result
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export default useRequiredFieldsValidator
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import React, { useState, useRef, useEffect } from 'react'
|
|
4
4
|
import { Box, InputLabel, OutlinedInput, styled } from '@mui/material'
|
|
5
|
+
import { session } from 'goobs-cache'
|
|
5
6
|
import { useDropdown } from './hooks/useDropdown'
|
|
6
7
|
import { usePhoneNumber } from './hooks/usePhoneNumber'
|
|
7
8
|
import { useSplitButton } from './hooks/useSplitButton'
|
|
@@ -9,9 +10,10 @@ import { Typography } from './../Typography'
|
|
|
9
10
|
import { red, green } from '../../styles/palette'
|
|
10
11
|
import { StartAdornment, EndAdornment } from './adornment'
|
|
11
12
|
import {
|
|
12
|
-
|
|
13
|
+
useInputHelperFooter,
|
|
13
14
|
HelperFooterMessage,
|
|
14
|
-
} from './
|
|
15
|
+
} from './hooks/useInputHelperFooter'
|
|
16
|
+
import { useRequiredFieldsValidator } from './hooks/useRequiredFieldsValidator'
|
|
15
17
|
import labelStyles from '../../styles/StyledComponent/Label'
|
|
16
18
|
import { useHasInputEffect, usePreventAutocompleteEffect } from './useEffects'
|
|
17
19
|
|
|
@@ -94,6 +96,8 @@ export interface StyledComponentProps {
|
|
|
94
96
|
onOptionSelect?: (option: string) => void
|
|
95
97
|
/** Callback function when the input value changes */
|
|
96
98
|
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void
|
|
99
|
+
/** Priority of the spread message */
|
|
100
|
+
spreadMessagePriority?: number
|
|
97
101
|
}
|
|
98
102
|
|
|
99
103
|
/**
|
|
@@ -135,7 +139,6 @@ const StyledComponent: React.FC<StyledComponentProps> = props => {
|
|
|
135
139
|
value,
|
|
136
140
|
valuestatus,
|
|
137
141
|
placeholder,
|
|
138
|
-
required = false,
|
|
139
142
|
formname,
|
|
140
143
|
formSubmitted = false,
|
|
141
144
|
'aria-label': ariaLabel,
|
|
@@ -144,17 +147,22 @@ const StyledComponent: React.FC<StyledComponentProps> = props => {
|
|
|
144
147
|
'aria-describedby': ariaDescribedBy,
|
|
145
148
|
onOptionSelect,
|
|
146
149
|
onChange,
|
|
150
|
+
spreadMessagePriority,
|
|
147
151
|
} = props
|
|
148
152
|
|
|
149
|
-
const {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
153
|
+
const { validateField } = useInputHelperFooter()
|
|
154
|
+
const helperFooterAtom = session.atom<Record<string, HelperFooterMessage>>({})
|
|
155
|
+
const [helperFooterValue] = session.useAtom(helperFooterAtom)
|
|
156
|
+
|
|
157
|
+
const showErrorAtom = session.atom<boolean>(false)
|
|
158
|
+
const [showError, setShowError] = session.useAtom(showErrorAtom)
|
|
159
|
+
|
|
160
|
+
const hasInputRef = useRef(false)
|
|
161
|
+
|
|
162
|
+
useRequiredFieldsValidator(formname || '', [props], hasInputRef)
|
|
163
|
+
|
|
155
164
|
const [isFocused, setIsFocused] = useState(false)
|
|
156
165
|
const [hasInput, setHasInput] = useState(false)
|
|
157
|
-
const [showError, setShowError] = useState(false)
|
|
158
166
|
const [passwordVisible, setPasswordVisible] = useState(false)
|
|
159
167
|
const inputRefInternal = useRef<HTMLInputElement>(null)
|
|
160
168
|
const inputBoxRef = useRef<HTMLDivElement>(null)
|
|
@@ -164,8 +172,10 @@ const StyledComponent: React.FC<StyledComponentProps> = props => {
|
|
|
164
172
|
inputBoxRef,
|
|
165
173
|
onOptionSelect
|
|
166
174
|
)
|
|
167
|
-
const { phoneNumber, handlePhoneNumberChange
|
|
168
|
-
|
|
175
|
+
const { phoneNumber, handlePhoneNumberChange } = usePhoneNumber(
|
|
176
|
+
value || '',
|
|
177
|
+
componentvariant
|
|
178
|
+
)
|
|
169
179
|
const {
|
|
170
180
|
value: splitButtonValue,
|
|
171
181
|
handleIncrement,
|
|
@@ -175,24 +185,6 @@ const StyledComponent: React.FC<StyledComponentProps> = props => {
|
|
|
175
185
|
useHasInputEffect(value, valuestatus, setHasInput)
|
|
176
186
|
usePreventAutocompleteEffect(inputRefInternal)
|
|
177
187
|
|
|
178
|
-
/**
|
|
179
|
-
* Initialize required fields when the form name changes
|
|
180
|
-
*/
|
|
181
|
-
useEffect(() => {
|
|
182
|
-
if (formname) {
|
|
183
|
-
initializeRequiredFields(formname)
|
|
184
|
-
}
|
|
185
|
-
}, [formname, initializeRequiredFields])
|
|
186
|
-
|
|
187
|
-
/**
|
|
188
|
-
* Validate required field when relevant props change
|
|
189
|
-
*/
|
|
190
|
-
useEffect(() => {
|
|
191
|
-
if (required && formname && name && label) {
|
|
192
|
-
validateRequiredField(required, formname, name, label)
|
|
193
|
-
}
|
|
194
|
-
}, [required, formname, name, label, validateRequiredField])
|
|
195
|
-
|
|
196
188
|
/**
|
|
197
189
|
* Show error after a delay when form is submitted or input has value
|
|
198
190
|
*/
|
|
@@ -202,16 +194,11 @@ const StyledComponent: React.FC<StyledComponentProps> = props => {
|
|
|
202
194
|
}, 1000)
|
|
203
195
|
|
|
204
196
|
return () => clearTimeout(timer)
|
|
205
|
-
}, [formSubmitted, hasInput])
|
|
197
|
+
}, [formSubmitted, hasInput, setShowError])
|
|
206
198
|
|
|
207
|
-
/**
|
|
208
|
-
* Update phone number when componentvariant is 'phonenumber' and value changes
|
|
209
|
-
*/
|
|
210
199
|
useEffect(() => {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
}
|
|
214
|
-
}, [componentvariant, value, updatePhoneNumber])
|
|
200
|
+
hasInputRef.current = !!value
|
|
201
|
+
}, [value])
|
|
215
202
|
|
|
216
203
|
const currentHelperFooter = name ? helperFooterValue[name] : undefined
|
|
217
204
|
|
|
@@ -238,11 +225,12 @@ const StyledComponent: React.FC<StyledComponentProps> = props => {
|
|
|
238
225
|
}
|
|
239
226
|
|
|
240
227
|
setHasInput(!!e.target.value)
|
|
228
|
+
hasInputRef.current = !!e.target.value
|
|
241
229
|
|
|
242
230
|
const formData = new FormData()
|
|
243
231
|
formData.append(e.target.name, e.target.value)
|
|
244
232
|
if (name && label && formname) {
|
|
245
|
-
validateField(name, formData, label,
|
|
233
|
+
validateField(name, formData, label, formname, spreadMessagePriority)
|
|
246
234
|
}
|
|
247
235
|
}
|
|
248
236
|
|
|
@@ -261,7 +249,7 @@ const StyledComponent: React.FC<StyledComponentProps> = props => {
|
|
|
261
249
|
if (name && label && !hasInput && formname) {
|
|
262
250
|
const formData = new FormData()
|
|
263
251
|
formData.append(name, '')
|
|
264
|
-
validateField(name, formData, label,
|
|
252
|
+
validateField(name, formData, label, formname, spreadMessagePriority)
|
|
265
253
|
}
|
|
266
254
|
}
|
|
267
255
|
|
|
@@ -80,7 +80,9 @@ const TransferList: React.FC<TransferListProps> = ({
|
|
|
80
80
|
const newRight = right.concat(left)
|
|
81
81
|
setRight(newRight)
|
|
82
82
|
setLeft([])
|
|
83
|
-
|
|
83
|
+
if (onChange) {
|
|
84
|
+
onChange(newRight)
|
|
85
|
+
}
|
|
84
86
|
}
|
|
85
87
|
|
|
86
88
|
/**
|
|
@@ -92,7 +94,9 @@ const TransferList: React.FC<TransferListProps> = ({
|
|
|
92
94
|
setRight(newRight)
|
|
93
95
|
setLeft(newLeft)
|
|
94
96
|
setChecked(not(checked, leftChecked))
|
|
95
|
-
|
|
97
|
+
if (onChange) {
|
|
98
|
+
onChange(newRight)
|
|
99
|
+
}
|
|
96
100
|
}
|
|
97
101
|
|
|
98
102
|
/**
|
|
@@ -104,7 +108,9 @@ const TransferList: React.FC<TransferListProps> = ({
|
|
|
104
108
|
setLeft(newLeft)
|
|
105
109
|
setRight(newRight)
|
|
106
110
|
setChecked(not(checked, rightChecked))
|
|
107
|
-
|
|
111
|
+
if (onChange) {
|
|
112
|
+
onChange(newRight)
|
|
113
|
+
}
|
|
108
114
|
}
|
|
109
115
|
|
|
110
116
|
/**
|
|
@@ -114,7 +120,9 @@ const TransferList: React.FC<TransferListProps> = ({
|
|
|
114
120
|
const newLeft = left.concat(right)
|
|
115
121
|
setLeft(newLeft)
|
|
116
122
|
setRight([])
|
|
117
|
-
|
|
123
|
+
if (onChange) {
|
|
124
|
+
onChange([])
|
|
125
|
+
}
|
|
118
126
|
}
|
|
119
127
|
|
|
120
128
|
/**
|