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,567 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useCallback, useMemo, useEffect } from 'react'
|
|
4
|
+
import { debounce } from 'lodash'
|
|
5
|
+
import { session } from 'goobs-cache'
|
|
6
|
+
|
|
7
|
+
const isValidEmailFormat = (email: string): boolean => {
|
|
8
|
+
console.log('Validating email format:', email)
|
|
9
|
+
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/
|
|
10
|
+
const isValid = emailRegex.test(email)
|
|
11
|
+
console.log('Email format is valid:', isValid)
|
|
12
|
+
return isValid
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface HelperFooterMessage {
|
|
16
|
+
status: 'error' | 'success' | 'emptyAndRequired'
|
|
17
|
+
statusMessage: string
|
|
18
|
+
spreadMessage: string
|
|
19
|
+
spreadMessagePriority: number
|
|
20
|
+
required: boolean
|
|
21
|
+
hasInput?: boolean
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const useInputHelperFooter = () => {
|
|
25
|
+
console.log('useInputHelperFooter hook called')
|
|
26
|
+
|
|
27
|
+
const helperFooterAtom = session.atom<
|
|
28
|
+
| Record<string, HelperFooterMessage>
|
|
29
|
+
| Promise<Record<string, HelperFooterMessage>>
|
|
30
|
+
>({})
|
|
31
|
+
const validateAtom = session.atom<string>('')
|
|
32
|
+
|
|
33
|
+
const handleGenericErrorCreation = useCallback(
|
|
34
|
+
async (
|
|
35
|
+
formData: FormData,
|
|
36
|
+
name: string,
|
|
37
|
+
label: string,
|
|
38
|
+
formname: string,
|
|
39
|
+
priority?: number
|
|
40
|
+
): Promise<HelperFooterMessage | undefined> => {
|
|
41
|
+
console.log('handleGenericErrorCreation called:', {
|
|
42
|
+
name,
|
|
43
|
+
label,
|
|
44
|
+
formname,
|
|
45
|
+
priority,
|
|
46
|
+
})
|
|
47
|
+
const value = formData.get(name) as string
|
|
48
|
+
console.log('Form data value:', value)
|
|
49
|
+
if (!value || !value.trim()) {
|
|
50
|
+
console.log('Value is empty or whitespace')
|
|
51
|
+
const message: HelperFooterMessage = {
|
|
52
|
+
status: 'error',
|
|
53
|
+
statusMessage: `${label} is required. Please enter a ${label.toLowerCase()}.`,
|
|
54
|
+
spreadMessage: `${label} is required.`,
|
|
55
|
+
spreadMessagePriority: priority ?? 1,
|
|
56
|
+
required: true,
|
|
57
|
+
}
|
|
58
|
+
console.log('Created error message:', message)
|
|
59
|
+
const [, setHelperFooter] = session.useAtom(helperFooterAtom)
|
|
60
|
+
setHelperFooter(prev => {
|
|
61
|
+
if (prev instanceof Promise) {
|
|
62
|
+
return prev
|
|
63
|
+
}
|
|
64
|
+
return { ...prev, [name]: message }
|
|
65
|
+
})
|
|
66
|
+
return message
|
|
67
|
+
} else {
|
|
68
|
+
console.log('Value is not empty, removing helper footer from cache')
|
|
69
|
+
const [, setHelperFooter] = session.useAtom(helperFooterAtom)
|
|
70
|
+
setHelperFooter(prev => {
|
|
71
|
+
if (prev instanceof Promise) {
|
|
72
|
+
return prev
|
|
73
|
+
}
|
|
74
|
+
const newState = { ...prev }
|
|
75
|
+
delete newState[name]
|
|
76
|
+
return newState
|
|
77
|
+
})
|
|
78
|
+
}
|
|
79
|
+
console.log('Returning undefined (no error)')
|
|
80
|
+
return undefined
|
|
81
|
+
},
|
|
82
|
+
[helperFooterAtom]
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
const handleEmailErrorCreation = useCallback(
|
|
86
|
+
async (
|
|
87
|
+
formData: FormData,
|
|
88
|
+
formname: string
|
|
89
|
+
): Promise<HelperFooterMessage | undefined> => {
|
|
90
|
+
console.log('handleEmailErrorCreation called:', { formname })
|
|
91
|
+
const email = formData.get('email') as string
|
|
92
|
+
console.log('Email value:', email)
|
|
93
|
+
let message: HelperFooterMessage | undefined
|
|
94
|
+
|
|
95
|
+
if (!email || !email.trim()) {
|
|
96
|
+
console.log('Email is empty or whitespace')
|
|
97
|
+
message = {
|
|
98
|
+
status: 'error',
|
|
99
|
+
statusMessage: 'Please enter an email address.',
|
|
100
|
+
spreadMessage: 'Email is required.',
|
|
101
|
+
spreadMessagePriority: 1,
|
|
102
|
+
required: true,
|
|
103
|
+
}
|
|
104
|
+
} else if (!isValidEmailFormat(email)) {
|
|
105
|
+
console.log('Email format is invalid')
|
|
106
|
+
message = {
|
|
107
|
+
status: 'error',
|
|
108
|
+
statusMessage: 'Please enter a valid email address.',
|
|
109
|
+
spreadMessage: 'Invalid email format.',
|
|
110
|
+
spreadMessagePriority: 1,
|
|
111
|
+
required: true,
|
|
112
|
+
}
|
|
113
|
+
} else {
|
|
114
|
+
console.log('Email is valid')
|
|
115
|
+
message = {
|
|
116
|
+
status: 'success',
|
|
117
|
+
statusMessage: 'Email is valid.',
|
|
118
|
+
spreadMessage: 'Email is valid.',
|
|
119
|
+
spreadMessagePriority: 1,
|
|
120
|
+
required: true,
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (message) {
|
|
125
|
+
console.log('Message created:', message)
|
|
126
|
+
const [, setHelperFooter] = session.useAtom(helperFooterAtom)
|
|
127
|
+
if (message.status === 'success') {
|
|
128
|
+
console.log('Removing helper footer from cache')
|
|
129
|
+
setHelperFooter(prev => {
|
|
130
|
+
if (prev instanceof Promise) {
|
|
131
|
+
return prev
|
|
132
|
+
}
|
|
133
|
+
const newState = { ...prev }
|
|
134
|
+
delete newState['email']
|
|
135
|
+
return newState
|
|
136
|
+
})
|
|
137
|
+
} else {
|
|
138
|
+
setHelperFooter(prev => {
|
|
139
|
+
if (prev instanceof Promise) {
|
|
140
|
+
return prev
|
|
141
|
+
}
|
|
142
|
+
return { ...prev, email: message! }
|
|
143
|
+
})
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
console.log('Returning message:', message)
|
|
148
|
+
return message
|
|
149
|
+
},
|
|
150
|
+
[helperFooterAtom]
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
const handlePasswordErrorCreation = useCallback(
|
|
154
|
+
async (
|
|
155
|
+
formData: FormData,
|
|
156
|
+
formname: string
|
|
157
|
+
): Promise<HelperFooterMessage | undefined> => {
|
|
158
|
+
console.log('handlePasswordErrorCreation called:', { formname })
|
|
159
|
+
const password = formData.get('verifyPassword') as string
|
|
160
|
+
console.log('Password value:', password ? '[REDACTED]' : 'empty')
|
|
161
|
+
|
|
162
|
+
const [, setValidate] = session.useAtom(validateAtom)
|
|
163
|
+
const debouncedPasswordStorage = debounce(() => {
|
|
164
|
+
if (password) {
|
|
165
|
+
console.log('Storing password in cache (debounced)')
|
|
166
|
+
setValidate(password)
|
|
167
|
+
}
|
|
168
|
+
}, 2000)
|
|
169
|
+
|
|
170
|
+
debouncedPasswordStorage()
|
|
171
|
+
|
|
172
|
+
let message: HelperFooterMessage | undefined
|
|
173
|
+
|
|
174
|
+
if (!password || !password.trim()) {
|
|
175
|
+
console.log('Password is empty or whitespace')
|
|
176
|
+
message = {
|
|
177
|
+
status: 'error',
|
|
178
|
+
statusMessage: 'Password is required.',
|
|
179
|
+
spreadMessage: 'Password is required.',
|
|
180
|
+
spreadMessagePriority: 2,
|
|
181
|
+
required: true,
|
|
182
|
+
}
|
|
183
|
+
} else {
|
|
184
|
+
const passwordRegex =
|
|
185
|
+
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/
|
|
186
|
+
const passwordComplexityStatus: 'error' | 'success' =
|
|
187
|
+
passwordRegex.test(password) ? 'success' : 'error'
|
|
188
|
+
console.log('Password complexity status:', passwordComplexityStatus)
|
|
189
|
+
|
|
190
|
+
if (passwordComplexityStatus === 'error') {
|
|
191
|
+
message = {
|
|
192
|
+
status: 'error',
|
|
193
|
+
statusMessage:
|
|
194
|
+
'Password must include at least 8 characters, one uppercase letter, one lowercase letter, one number, and one special character.',
|
|
195
|
+
spreadMessage: 'Invalid password.',
|
|
196
|
+
spreadMessagePriority: 1,
|
|
197
|
+
required: true,
|
|
198
|
+
}
|
|
199
|
+
} else {
|
|
200
|
+
message = {
|
|
201
|
+
status: 'success',
|
|
202
|
+
statusMessage: 'Password meets all requirements.',
|
|
203
|
+
spreadMessage: 'Password is valid.',
|
|
204
|
+
spreadMessagePriority: 1,
|
|
205
|
+
required: true,
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (message) {
|
|
211
|
+
console.log('Message created:', message)
|
|
212
|
+
const [, setHelperFooter] = session.useAtom(helperFooterAtom)
|
|
213
|
+
if (message.status === 'success') {
|
|
214
|
+
console.log('Removing helper footer from cache')
|
|
215
|
+
setHelperFooter(prev => {
|
|
216
|
+
if (prev instanceof Promise) {
|
|
217
|
+
return prev
|
|
218
|
+
}
|
|
219
|
+
const newState = { ...prev }
|
|
220
|
+
delete newState['verifyPassword']
|
|
221
|
+
return newState
|
|
222
|
+
})
|
|
223
|
+
} else {
|
|
224
|
+
setHelperFooter(prev => {
|
|
225
|
+
if (prev instanceof Promise) {
|
|
226
|
+
return prev
|
|
227
|
+
}
|
|
228
|
+
return { ...prev, verifyPassword: message }
|
|
229
|
+
})
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
console.log('Returning message:', message)
|
|
234
|
+
return message
|
|
235
|
+
},
|
|
236
|
+
[helperFooterAtom, validateAtom]
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
const handleConfirmPasswordErrorCreation = useCallback(
|
|
240
|
+
async (
|
|
241
|
+
formData: FormData,
|
|
242
|
+
formname: string
|
|
243
|
+
): Promise<HelperFooterMessage | undefined> => {
|
|
244
|
+
console.log('handleConfirmPasswordErrorCreation called:', { formname })
|
|
245
|
+
const confirmPassword = formData.get('confirmPassword') as string
|
|
246
|
+
console.log(
|
|
247
|
+
'Confirm password value:',
|
|
248
|
+
confirmPassword ? '[REDACTED]' : 'empty'
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
let message: HelperFooterMessage | undefined
|
|
252
|
+
|
|
253
|
+
if (!confirmPassword || !confirmPassword.trim()) {
|
|
254
|
+
console.log('Confirm password is empty or whitespace')
|
|
255
|
+
message = {
|
|
256
|
+
status: 'error',
|
|
257
|
+
statusMessage: 'Please confirm your password.',
|
|
258
|
+
spreadMessage: 'Password confirmation is required.',
|
|
259
|
+
spreadMessagePriority: 3,
|
|
260
|
+
required: true,
|
|
261
|
+
}
|
|
262
|
+
} else {
|
|
263
|
+
const [verifyPassword] = session.useAtom(validateAtom)
|
|
264
|
+
console.log('Fetched verify password from session atom')
|
|
265
|
+
|
|
266
|
+
if (!verifyPassword) {
|
|
267
|
+
console.log('Verify password not found')
|
|
268
|
+
message = {
|
|
269
|
+
status: 'error',
|
|
270
|
+
statusMessage: 'Please enter your password first.',
|
|
271
|
+
spreadMessage: 'Password not set.',
|
|
272
|
+
spreadMessagePriority: 3,
|
|
273
|
+
required: true,
|
|
274
|
+
}
|
|
275
|
+
} else if (confirmPassword !== verifyPassword) {
|
|
276
|
+
console.log('Passwords do not match')
|
|
277
|
+
message = {
|
|
278
|
+
status: 'error',
|
|
279
|
+
statusMessage: 'Passwords do not match.',
|
|
280
|
+
spreadMessage: 'Passwords do not match.',
|
|
281
|
+
spreadMessagePriority: 3,
|
|
282
|
+
required: true,
|
|
283
|
+
}
|
|
284
|
+
} else {
|
|
285
|
+
console.log('Passwords match')
|
|
286
|
+
message = {
|
|
287
|
+
status: 'success',
|
|
288
|
+
statusMessage: 'Passwords match.',
|
|
289
|
+
spreadMessage: 'Passwords match.',
|
|
290
|
+
spreadMessagePriority: 3,
|
|
291
|
+
required: true,
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
if (message) {
|
|
297
|
+
console.log('Message created:', message)
|
|
298
|
+
const [, setHelperFooter] = session.useAtom(helperFooterAtom)
|
|
299
|
+
if (message.status === 'success') {
|
|
300
|
+
console.log('Removing helper footer from cache')
|
|
301
|
+
setHelperFooter(prev => {
|
|
302
|
+
if (prev instanceof Promise) {
|
|
303
|
+
return prev
|
|
304
|
+
}
|
|
305
|
+
const newState = { ...prev }
|
|
306
|
+
delete newState['confirmPassword']
|
|
307
|
+
return newState
|
|
308
|
+
})
|
|
309
|
+
} else {
|
|
310
|
+
setHelperFooter(prev => {
|
|
311
|
+
if (prev instanceof Promise) {
|
|
312
|
+
return prev
|
|
313
|
+
}
|
|
314
|
+
return { ...prev, confirmPassword: message }
|
|
315
|
+
})
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
console.log('Returning message:', message)
|
|
320
|
+
return message
|
|
321
|
+
},
|
|
322
|
+
[helperFooterAtom, validateAtom]
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
const handlePhoneNumberErrorCreation = useCallback(
|
|
326
|
+
async (
|
|
327
|
+
formData: FormData,
|
|
328
|
+
formname: string
|
|
329
|
+
): Promise<HelperFooterMessage | undefined> => {
|
|
330
|
+
console.log('handlePhoneNumberErrorCreation called:', { formname })
|
|
331
|
+
const phoneNumber = formData.get('phoneNumber') as string
|
|
332
|
+
console.log('Phone number value:', phoneNumber)
|
|
333
|
+
let message: HelperFooterMessage | undefined
|
|
334
|
+
|
|
335
|
+
if (!phoneNumber || !phoneNumber.trim()) {
|
|
336
|
+
console.log('Phone number is empty or whitespace')
|
|
337
|
+
message = {
|
|
338
|
+
status: 'error',
|
|
339
|
+
statusMessage:
|
|
340
|
+
'Phone number is required. Please enter a phone number.',
|
|
341
|
+
spreadMessage: 'Phone number is required.',
|
|
342
|
+
spreadMessagePriority: 3,
|
|
343
|
+
required: true,
|
|
344
|
+
}
|
|
345
|
+
} else {
|
|
346
|
+
const digitsOnly = phoneNumber.replace(/[^\d]/g, '')
|
|
347
|
+
const length = digitsOnly.length
|
|
348
|
+
console.log('Phone number length (digits only):', length)
|
|
349
|
+
if (
|
|
350
|
+
(length === 10 && !digitsOnly.startsWith('1')) ||
|
|
351
|
+
(length === 11 && digitsOnly.startsWith('1'))
|
|
352
|
+
) {
|
|
353
|
+
console.log('Phone number is valid')
|
|
354
|
+
message = {
|
|
355
|
+
status: 'success',
|
|
356
|
+
statusMessage: 'Phone number is valid.',
|
|
357
|
+
spreadMessage: 'Phone number is valid.',
|
|
358
|
+
spreadMessagePriority: 1,
|
|
359
|
+
required: true,
|
|
360
|
+
}
|
|
361
|
+
} else {
|
|
362
|
+
console.log('Phone number is invalid')
|
|
363
|
+
message = {
|
|
364
|
+
status: 'error',
|
|
365
|
+
statusMessage:
|
|
366
|
+
'Please enter a valid 10-digit phone number or a 10-digit number starting with 1.',
|
|
367
|
+
spreadMessage: 'Invalid phone number format.',
|
|
368
|
+
spreadMessagePriority: 1,
|
|
369
|
+
required: true,
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
if (message) {
|
|
375
|
+
console.log('Message created:', message)
|
|
376
|
+
const [, setHelperFooter] = session.useAtom(helperFooterAtom)
|
|
377
|
+
if (message.status === 'success') {
|
|
378
|
+
console.log('Removing helper footer from cache')
|
|
379
|
+
setHelperFooter(prev => {
|
|
380
|
+
if (prev instanceof Promise) {
|
|
381
|
+
return prev
|
|
382
|
+
}
|
|
383
|
+
const newState = { ...prev }
|
|
384
|
+
delete newState['phoneNumber']
|
|
385
|
+
return newState
|
|
386
|
+
})
|
|
387
|
+
} else {
|
|
388
|
+
setHelperFooter(prev => {
|
|
389
|
+
if (prev instanceof Promise) {
|
|
390
|
+
return prev
|
|
391
|
+
}
|
|
392
|
+
return { ...prev, phoneNumber: message }
|
|
393
|
+
})
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
console.log('Returning message:', message)
|
|
398
|
+
return message
|
|
399
|
+
},
|
|
400
|
+
[helperFooterAtom]
|
|
401
|
+
)
|
|
402
|
+
|
|
403
|
+
const updateHelperFooter = useCallback(
|
|
404
|
+
(name: string, validationResult: HelperFooterMessage | undefined): void => {
|
|
405
|
+
console.log('updateHelperFooter called:', { name, validationResult })
|
|
406
|
+
const [, setHelperFooter] = session.useAtom(helperFooterAtom)
|
|
407
|
+
if (validationResult) {
|
|
408
|
+
console.log('Updating helper footer with new validation result')
|
|
409
|
+
setHelperFooter(prev => {
|
|
410
|
+
if (prev instanceof Promise) {
|
|
411
|
+
return prev
|
|
412
|
+
}
|
|
413
|
+
return { ...prev, [name]: validationResult }
|
|
414
|
+
})
|
|
415
|
+
} else {
|
|
416
|
+
console.log('Removing field from helper footer')
|
|
417
|
+
setHelperFooter(prev => {
|
|
418
|
+
if (prev instanceof Promise) {
|
|
419
|
+
return prev
|
|
420
|
+
}
|
|
421
|
+
const newState = { ...prev }
|
|
422
|
+
delete newState[name]
|
|
423
|
+
return newState
|
|
424
|
+
})
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
console.log('Setting new helper footer value')
|
|
428
|
+
},
|
|
429
|
+
[helperFooterAtom]
|
|
430
|
+
)
|
|
431
|
+
|
|
432
|
+
const validateField = useCallback(
|
|
433
|
+
async (
|
|
434
|
+
name: string,
|
|
435
|
+
formData: FormData,
|
|
436
|
+
label: string,
|
|
437
|
+
formname: string,
|
|
438
|
+
priority?: number
|
|
439
|
+
) => {
|
|
440
|
+
console.log('validateField called:', { name, label, formname, priority })
|
|
441
|
+
let validationResult: HelperFooterMessage | undefined
|
|
442
|
+
|
|
443
|
+
switch (name) {
|
|
444
|
+
case 'email':
|
|
445
|
+
console.log('Validating email field')
|
|
446
|
+
validationResult = await handleEmailErrorCreation(formData, formname)
|
|
447
|
+
break
|
|
448
|
+
case 'verifyPassword':
|
|
449
|
+
console.log('Validating password field')
|
|
450
|
+
validationResult = await handlePasswordErrorCreation(
|
|
451
|
+
formData,
|
|
452
|
+
formname
|
|
453
|
+
)
|
|
454
|
+
break
|
|
455
|
+
case 'confirmPassword':
|
|
456
|
+
console.log('Validating confirm password field')
|
|
457
|
+
validationResult = await handleConfirmPasswordErrorCreation(
|
|
458
|
+
formData,
|
|
459
|
+
formname
|
|
460
|
+
)
|
|
461
|
+
break
|
|
462
|
+
case 'phoneNumber':
|
|
463
|
+
console.log('Validating phone number field')
|
|
464
|
+
validationResult = await handlePhoneNumberErrorCreation(
|
|
465
|
+
formData,
|
|
466
|
+
formname
|
|
467
|
+
)
|
|
468
|
+
break
|
|
469
|
+
default:
|
|
470
|
+
console.log('Validating generic field')
|
|
471
|
+
validationResult = await handleGenericErrorCreation(
|
|
472
|
+
formData,
|
|
473
|
+
name,
|
|
474
|
+
label,
|
|
475
|
+
formname,
|
|
476
|
+
priority
|
|
477
|
+
)
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
console.log('Validation result:', validationResult)
|
|
481
|
+
updateHelperFooter(name, validationResult)
|
|
482
|
+
},
|
|
483
|
+
[
|
|
484
|
+
handleEmailErrorCreation,
|
|
485
|
+
handlePasswordErrorCreation,
|
|
486
|
+
handleConfirmPasswordErrorCreation,
|
|
487
|
+
handlePhoneNumberErrorCreation,
|
|
488
|
+
handleGenericErrorCreation,
|
|
489
|
+
updateHelperFooter,
|
|
490
|
+
]
|
|
491
|
+
)
|
|
492
|
+
|
|
493
|
+
const useShowErrorEffect = (
|
|
494
|
+
formSubmitted: boolean,
|
|
495
|
+
hasInput: boolean,
|
|
496
|
+
isFocused: boolean
|
|
497
|
+
): boolean => {
|
|
498
|
+
console.log('useShowErrorEffect called:', {
|
|
499
|
+
formSubmitted,
|
|
500
|
+
hasInput,
|
|
501
|
+
isFocused,
|
|
502
|
+
})
|
|
503
|
+
const showErrorAtom = session.atom<boolean>(false)
|
|
504
|
+
const [showError, setShowError] = session.useAtom(showErrorAtom)
|
|
505
|
+
|
|
506
|
+
useEffect(() => {
|
|
507
|
+
const shouldShowError = formSubmitted || (hasInput && !isFocused)
|
|
508
|
+
console.log('Calculating shouldShowError:', {
|
|
509
|
+
shouldShowError,
|
|
510
|
+
formSubmitted,
|
|
511
|
+
hasInput,
|
|
512
|
+
isFocused,
|
|
513
|
+
})
|
|
514
|
+
setShowError(shouldShowError)
|
|
515
|
+
}, [formSubmitted, hasInput, isFocused, setShowError])
|
|
516
|
+
|
|
517
|
+
console.log('Returning showError:', showError)
|
|
518
|
+
return showError
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
const fetchHelperFooters = useCallback(
|
|
522
|
+
async (formname: string): Promise<HelperFooterMessage[]> => {
|
|
523
|
+
console.log('fetchHelperFooters called:', { formname })
|
|
524
|
+
const [helperFooters] = session.useAtom(helperFooterAtom)
|
|
525
|
+
console.log('Fetched helper footers from session atom:', helperFooters)
|
|
526
|
+
|
|
527
|
+
if (helperFooters instanceof Promise) {
|
|
528
|
+
return []
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
const filteredHelperFooters = Object.values(helperFooters).filter(
|
|
532
|
+
(item): item is HelperFooterMessage => {
|
|
533
|
+
const isValidHelperFooter =
|
|
534
|
+
typeof item === 'object' &&
|
|
535
|
+
item !== null &&
|
|
536
|
+
'status' in item &&
|
|
537
|
+
'statusMessage' in item &&
|
|
538
|
+
'spreadMessage' in item &&
|
|
539
|
+
'spreadMessagePriority' in item &&
|
|
540
|
+
'required' in item
|
|
541
|
+
console.log('Checking if item is valid HelperFooterMessage:', {
|
|
542
|
+
item,
|
|
543
|
+
isValid: isValidHelperFooter,
|
|
544
|
+
})
|
|
545
|
+
return isValidHelperFooter
|
|
546
|
+
}
|
|
547
|
+
)
|
|
548
|
+
console.log('Filtered helper footers:', filteredHelperFooters)
|
|
549
|
+
return filteredHelperFooters
|
|
550
|
+
},
|
|
551
|
+
[helperFooterAtom]
|
|
552
|
+
)
|
|
553
|
+
|
|
554
|
+
const result = useMemo(
|
|
555
|
+
() => ({
|
|
556
|
+
validateField,
|
|
557
|
+
useShowErrorEffect,
|
|
558
|
+
fetchHelperFooters,
|
|
559
|
+
}),
|
|
560
|
+
[validateField, fetchHelperFooters]
|
|
561
|
+
)
|
|
562
|
+
|
|
563
|
+
console.log('useInputHelperFooter returning result:', result)
|
|
564
|
+
return result
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
export default useInputHelperFooter
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import React, { useState, useCallback } from 'react'
|
|
1
|
+
import React, { useState, useCallback, useEffect } from 'react'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Formats a string of digits into a US phone number format
|
|
4
|
+
* Formats a string of digits into a US phone number format.
|
|
5
|
+
* The "+1" country code is always added at the beginning.
|
|
5
6
|
*
|
|
6
7
|
* @param {string} value - The input string to be formatted.
|
|
7
|
-
* @returns {string} A formatted phone number string
|
|
8
|
+
* @returns {string} A formatted phone number string.
|
|
8
9
|
*
|
|
9
10
|
* @example
|
|
10
11
|
* formatPhoneNumber("1234567890") // returns "+1 123-456-7890"
|
|
@@ -14,6 +15,7 @@ export const formatPhoneNumber = (value: string): string => {
|
|
|
14
15
|
const digits = value.replace(/\D/g, '')
|
|
15
16
|
const limitedDigits = digits.slice(0, 10)
|
|
16
17
|
let formattedNumber = '+1 '
|
|
18
|
+
|
|
17
19
|
if (limitedDigits.length > 0) {
|
|
18
20
|
formattedNumber += limitedDigits.slice(0, 3)
|
|
19
21
|
if (limitedDigits.length > 3) {
|
|
@@ -23,13 +25,14 @@ export const formatPhoneNumber = (value: string): string => {
|
|
|
23
25
|
}
|
|
24
26
|
}
|
|
25
27
|
}
|
|
26
|
-
return formattedNumber
|
|
28
|
+
return formattedNumber.trim()
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
/**
|
|
30
32
|
* A custom React hook for managing and formatting a phone number input.
|
|
31
33
|
*
|
|
32
34
|
* @param {string} [initialValue=''] - The initial value of the phone number.
|
|
35
|
+
* @param {string} [componentvariant=''] - The variant of the component.
|
|
33
36
|
* @returns {Object} An object containing the current phone number state and functions to update it.
|
|
34
37
|
* @property {string} phoneNumber - The current formatted phone number.
|
|
35
38
|
* @property {function} handlePhoneNumberChange - A function to handle changes to the phone number input.
|
|
@@ -38,11 +41,10 @@ export const formatPhoneNumber = (value: string): string => {
|
|
|
38
41
|
* @example
|
|
39
42
|
* const { phoneNumber, handlePhoneNumberChange, updatePhoneNumber } = usePhoneNumber();
|
|
40
43
|
*/
|
|
41
|
-
export const usePhoneNumber = (
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
*/
|
|
44
|
+
export const usePhoneNumber = (
|
|
45
|
+
initialValue: string = '',
|
|
46
|
+
componentvariant: string = ''
|
|
47
|
+
) => {
|
|
46
48
|
const [phoneNumber, setPhoneNumber] = useState(
|
|
47
49
|
formatPhoneNumber(initialValue)
|
|
48
50
|
)
|
|
@@ -55,9 +57,14 @@ export const usePhoneNumber = (initialValue: string = '') => {
|
|
|
55
57
|
const handlePhoneNumberChange = useCallback(
|
|
56
58
|
(e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
|
57
59
|
const input = e.target.value
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
60
|
+
let strippedInput = input.replace(/^\+1\s?/, '').replace(/\D/g, '')
|
|
61
|
+
|
|
62
|
+
// Ensure we don't exceed 10 digits
|
|
63
|
+
strippedInput = strippedInput.slice(0, 10)
|
|
64
|
+
|
|
65
|
+
// Only format if there's actual input beyond "+1 "
|
|
66
|
+
const formattedValue =
|
|
67
|
+
strippedInput.length > 0 ? formatPhoneNumber(strippedInput) : '+1 '
|
|
61
68
|
setPhoneNumber(formattedValue)
|
|
62
69
|
},
|
|
63
70
|
[]
|
|
@@ -72,6 +79,15 @@ export const usePhoneNumber = (initialValue: string = '') => {
|
|
|
72
79
|
setPhoneNumber(formatPhoneNumber(newValue))
|
|
73
80
|
}, [])
|
|
74
81
|
|
|
82
|
+
/**
|
|
83
|
+
* Update phone number when componentvariant is 'phonenumber' and value changes
|
|
84
|
+
*/
|
|
85
|
+
useEffect(() => {
|
|
86
|
+
if (componentvariant === 'phonenumber' && initialValue) {
|
|
87
|
+
updatePhoneNumber(initialValue)
|
|
88
|
+
}
|
|
89
|
+
}, [componentvariant, initialValue, updatePhoneNumber])
|
|
90
|
+
|
|
75
91
|
return {
|
|
76
92
|
phoneNumber,
|
|
77
93
|
handlePhoneNumberChange,
|