goobs-frontend 0.7.63 → 0.7.64
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 +1 -1
- package/src/components/Button/hook/useHelperFooter.tsx +251 -0
- package/src/components/Button/index.tsx +114 -165
- package/src/components/Content/Structure/button/useButton.tsx +0 -2
- package/src/components/StyledComponent/helperfooter/useHelperFooter.tsx +161 -103
- package/src/components/StyledComponent/hooks/usePhoneNumber.tsx +28 -12
- package/src/components/StyledComponent/index.tsx +4 -11
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "goobs-frontend",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.64",
|
|
4
4
|
"description": "A comprehensive React-based UI library built on Material-UI, offering a wide range of customizable components including grids, typography, buttons, cards, forms, navigation, pricing tables, steppers, tooltips, accordions, and more. Designed for building responsive and consistent user interfaces with advanced features like form validation, theming, and code syntax highlighting.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "./src/index.ts",
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import { useState, useEffect, useCallback, useMemo, useRef } from 'react'
|
|
2
|
+
import { get } from 'goobs-cache'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Represents the structure of a helper footer message.
|
|
6
|
+
* @interface HelperFooterMessage
|
|
7
|
+
*/
|
|
8
|
+
export interface HelperFooterMessage {
|
|
9
|
+
/** The status of the message, either 'error' or 'success'. */
|
|
10
|
+
status: 'error' | 'success'
|
|
11
|
+
/** A message describing the status. */
|
|
12
|
+
statusMessage: string
|
|
13
|
+
/** A message to be displayed to the user. */
|
|
14
|
+
spreadMessage: string
|
|
15
|
+
/** A number indicating the priority of the message. Lower numbers indicate higher priority. */
|
|
16
|
+
spreadMessagePriority: number
|
|
17
|
+
/** The name of the form associated with this message. */
|
|
18
|
+
formname: string
|
|
19
|
+
/** Indicates whether this message is required to be addressed. */
|
|
20
|
+
required: boolean
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* A type definition for the interval ID returned by setInterval.
|
|
25
|
+
*/
|
|
26
|
+
type IntervalID = ReturnType<typeof setInterval>
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* A custom hook for managing helper footer messages and form validation.
|
|
30
|
+
*
|
|
31
|
+
* @param {string} [initialFormname] - The initial name of the form to fetch helper footers for.
|
|
32
|
+
* @returns {Object} An object containing the current error message, form validity state, and functions to update and fetch form validation.
|
|
33
|
+
*/
|
|
34
|
+
const useHelperFooter = (initialFormname?: string) => {
|
|
35
|
+
/**
|
|
36
|
+
* State for storing the current error message.
|
|
37
|
+
*/
|
|
38
|
+
const [errorMessage, setErrorMessage] = useState<string | undefined>(
|
|
39
|
+
undefined
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* State for storing the current form validity.
|
|
44
|
+
*/
|
|
45
|
+
const [isFormValid, setIsFormValid] = useState<boolean>(true)
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* State for storing the current helper footers.
|
|
49
|
+
*/
|
|
50
|
+
const [helperFooters, setHelperFooters] = useState<HelperFooterMessage[]>([])
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Ref for storing the previous helper footers to compare against.
|
|
54
|
+
*/
|
|
55
|
+
const prevHelperFooters = useRef<HelperFooterMessage[]>([])
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Ref for storing the previous error message to compare against.
|
|
59
|
+
*/
|
|
60
|
+
const prevErrorMessage = useRef<string | undefined>(undefined)
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Ref for storing the previous form validity to compare against.
|
|
64
|
+
*/
|
|
65
|
+
const prevIsFormValid = useRef<boolean>(true)
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Ref for storing the interval ID for periodic helper footer fetching.
|
|
69
|
+
*/
|
|
70
|
+
const intervalIdRef = useRef<IntervalID | null>(null)
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Fetches helper footer messages from the cache.
|
|
74
|
+
*
|
|
75
|
+
* @param {string} [formname] - The name of the form to fetch helper footers for.
|
|
76
|
+
* @returns {Promise<HelperFooterMessage[]>} A promise that resolves to an array of HelperFooterMessage objects.
|
|
77
|
+
*/
|
|
78
|
+
const fetchHelperFooters = useCallback(
|
|
79
|
+
async (formname?: string): Promise<HelperFooterMessage[]> => {
|
|
80
|
+
const currentFormname = formname || initialFormname
|
|
81
|
+
if (!currentFormname) {
|
|
82
|
+
return []
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const helperFooterResult = await get(
|
|
86
|
+
'helperfooter',
|
|
87
|
+
currentFormname,
|
|
88
|
+
'client'
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
if (
|
|
92
|
+
helperFooterResult &&
|
|
93
|
+
typeof helperFooterResult === 'object' &&
|
|
94
|
+
'type' in helperFooterResult &&
|
|
95
|
+
helperFooterResult.type === 'json' &&
|
|
96
|
+
'value' in helperFooterResult &&
|
|
97
|
+
typeof helperFooterResult.value === 'object' &&
|
|
98
|
+
helperFooterResult.value !== null
|
|
99
|
+
) {
|
|
100
|
+
const fetchedHelperFooters = Object.entries(
|
|
101
|
+
helperFooterResult.value as Record<string, unknown>
|
|
102
|
+
)
|
|
103
|
+
.map(([key, value]): HelperFooterMessage | null => {
|
|
104
|
+
if (
|
|
105
|
+
typeof value === 'object' &&
|
|
106
|
+
value !== null &&
|
|
107
|
+
'status' in value &&
|
|
108
|
+
'statusMessage' in value &&
|
|
109
|
+
'spreadMessage' in value &&
|
|
110
|
+
'spreadMessagePriority' in value &&
|
|
111
|
+
'required' in value
|
|
112
|
+
) {
|
|
113
|
+
return {
|
|
114
|
+
status: value.status as 'error' | 'success',
|
|
115
|
+
statusMessage: String(value.statusMessage),
|
|
116
|
+
spreadMessage: String(value.spreadMessage),
|
|
117
|
+
spreadMessagePriority: Number(value.spreadMessagePriority),
|
|
118
|
+
required: Boolean(value.required),
|
|
119
|
+
formname: key,
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return null
|
|
123
|
+
})
|
|
124
|
+
.filter((value): value is HelperFooterMessage => value !== null)
|
|
125
|
+
|
|
126
|
+
if (
|
|
127
|
+
JSON.stringify(fetchedHelperFooters) !==
|
|
128
|
+
JSON.stringify(prevHelperFooters.current)
|
|
129
|
+
) {
|
|
130
|
+
setHelperFooters(fetchedHelperFooters)
|
|
131
|
+
prevHelperFooters.current = fetchedHelperFooters
|
|
132
|
+
}
|
|
133
|
+
return fetchedHelperFooters
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (helperFooters.length > 0) {
|
|
137
|
+
setHelperFooters([])
|
|
138
|
+
prevHelperFooters.current = []
|
|
139
|
+
}
|
|
140
|
+
return []
|
|
141
|
+
},
|
|
142
|
+
[initialFormname, helperFooters]
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Updates the form validation state based on the fetched helper footers.
|
|
147
|
+
*
|
|
148
|
+
* @param {string} [formname] - The name of the form to update validation for.
|
|
149
|
+
* @returns {Promise<boolean>} A promise that resolves to a boolean indicating whether the form is valid.
|
|
150
|
+
*/
|
|
151
|
+
const updateFormValidation = useCallback(
|
|
152
|
+
async (formname?: string): Promise<boolean> => {
|
|
153
|
+
const fetchedHelperFooters = await fetchHelperFooters(formname)
|
|
154
|
+
|
|
155
|
+
if (fetchedHelperFooters.length === 0) {
|
|
156
|
+
setErrorMessage(undefined)
|
|
157
|
+
setIsFormValid(true)
|
|
158
|
+
return true
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const errorFooters = fetchedHelperFooters.filter(
|
|
162
|
+
footer => footer.status === 'error' && footer.required
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
if (errorFooters.length > 0) {
|
|
166
|
+
const highestPriorityError = errorFooters.reduce((prev, current) =>
|
|
167
|
+
prev.spreadMessagePriority < current.spreadMessagePriority
|
|
168
|
+
? prev
|
|
169
|
+
: current
|
|
170
|
+
)
|
|
171
|
+
setErrorMessage(highestPriorityError.spreadMessage)
|
|
172
|
+
setIsFormValid(false)
|
|
173
|
+
return false
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
setErrorMessage(undefined)
|
|
177
|
+
setIsFormValid(true)
|
|
178
|
+
return true
|
|
179
|
+
},
|
|
180
|
+
[fetchHelperFooters]
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Effect to run form validation when the initial form name changes.
|
|
185
|
+
*/
|
|
186
|
+
useEffect(() => {
|
|
187
|
+
void updateFormValidation()
|
|
188
|
+
}, [initialFormname, updateFormValidation])
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Effect to set up periodic helper footer fetching.
|
|
192
|
+
*/
|
|
193
|
+
useEffect(() => {
|
|
194
|
+
if (initialFormname) {
|
|
195
|
+
const fetchAndUpdateHelperFooters = async () => {
|
|
196
|
+
await updateFormValidation(initialFormname)
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
void fetchAndUpdateHelperFooters()
|
|
200
|
+
intervalIdRef.current = setInterval(fetchAndUpdateHelperFooters, 1000)
|
|
201
|
+
|
|
202
|
+
return () => {
|
|
203
|
+
if (intervalIdRef.current) {
|
|
204
|
+
clearInterval(intervalIdRef.current)
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}, [initialFormname, updateFormValidation])
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Effect to update refs when error message or form validity changes.
|
|
212
|
+
*/
|
|
213
|
+
useEffect(() => {
|
|
214
|
+
if (
|
|
215
|
+
errorMessage !== prevErrorMessage.current ||
|
|
216
|
+
isFormValid !== prevIsFormValid.current
|
|
217
|
+
) {
|
|
218
|
+
prevErrorMessage.current = errorMessage
|
|
219
|
+
prevIsFormValid.current = isFormValid
|
|
220
|
+
}
|
|
221
|
+
}, [errorMessage, isFormValid])
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Memoized helper footers to prevent unnecessary re-renders.
|
|
225
|
+
*/
|
|
226
|
+
const memoizedHelperFooters = useMemo(() => helperFooters, [helperFooters])
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Memoized return value of the hook to prevent unnecessary re-renders.
|
|
230
|
+
*/
|
|
231
|
+
const returnValue = useMemo(
|
|
232
|
+
() => ({
|
|
233
|
+
errorMessage,
|
|
234
|
+
isFormValid,
|
|
235
|
+
updateFormValidation,
|
|
236
|
+
fetchHelperFooters,
|
|
237
|
+
helperFooters: memoizedHelperFooters,
|
|
238
|
+
}),
|
|
239
|
+
[
|
|
240
|
+
errorMessage,
|
|
241
|
+
isFormValid,
|
|
242
|
+
updateFormValidation,
|
|
243
|
+
fetchHelperFooters,
|
|
244
|
+
memoizedHelperFooters,
|
|
245
|
+
]
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
return returnValue
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
export default useHelperFooter
|
|
@@ -1,28 +1,32 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, { useMemo, useCallback } from 'react'
|
|
2
2
|
import { Button, Box, ButtonProps } from '@mui/material'
|
|
3
3
|
import StarIcon from '@mui/icons-material/Star'
|
|
4
4
|
import Typography from '../Typography'
|
|
5
5
|
import { red } from '../../styles/palette'
|
|
6
|
-
import
|
|
6
|
+
import useHelperFooter from './hook/useHelperFooter'
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Defines the possible alignment options for the button text.
|
|
10
|
+
*/
|
|
8
11
|
export type ButtonAlignment = 'left' | 'center' | 'right'
|
|
9
12
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
spreadMessagePriority: number
|
|
15
|
-
formname: string
|
|
16
|
-
required: boolean
|
|
17
|
-
}
|
|
18
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Interface for the CustomButton component props.
|
|
15
|
+
* Extends ButtonProps from Material-UI, omitting 'color' and 'variant'.
|
|
16
|
+
*/
|
|
19
17
|
export interface CustomButtonProps
|
|
20
18
|
extends Omit<ButtonProps, 'color' | 'variant'> {
|
|
19
|
+
/** The text to display on the button */
|
|
21
20
|
text?: string
|
|
21
|
+
/** The background color of the button */
|
|
22
22
|
backgroundcolor?: string
|
|
23
|
+
/** The outline color of the button */
|
|
23
24
|
outlinecolor?: string
|
|
25
|
+
/** The font color of the button text */
|
|
24
26
|
fontcolor?: string
|
|
27
|
+
/** The alignment of the button text */
|
|
25
28
|
fontlocation?: ButtonAlignment
|
|
29
|
+
/** The variant of the font to use for the button text */
|
|
26
30
|
fontvariant?:
|
|
27
31
|
| 'arapeyh1'
|
|
28
32
|
| 'arapeyh2'
|
|
@@ -51,18 +55,32 @@ export interface CustomButtonProps
|
|
|
51
55
|
| 'merriparagraph'
|
|
52
56
|
| 'merrihelperheader'
|
|
53
57
|
| 'merrihelperfooter'
|
|
58
|
+
/** The icon to display on the button */
|
|
54
59
|
icon?: React.ReactNode | false
|
|
60
|
+
/** The color of the icon */
|
|
55
61
|
iconcolor?: string
|
|
62
|
+
/** The size of the icon */
|
|
56
63
|
iconsize?: string
|
|
64
|
+
/** The location of the icon relative to the text */
|
|
57
65
|
iconlocation?: 'left' | 'top' | 'right'
|
|
66
|
+
/** The variant of the button */
|
|
58
67
|
variant?: 'text' | 'outlined' | 'contained'
|
|
68
|
+
/** The function to call when the button is clicked */
|
|
59
69
|
onClick?: () => void
|
|
60
|
-
|
|
70
|
+
/** The width of the button */
|
|
61
71
|
width?: string
|
|
72
|
+
/** The name of the form associated with this button */
|
|
62
73
|
formname?: string
|
|
74
|
+
/** The name attribute of the button */
|
|
63
75
|
name?: string
|
|
64
76
|
}
|
|
65
77
|
|
|
78
|
+
/**
|
|
79
|
+
* CustomButton component that extends Material-UI's Button with additional styling and functionality.
|
|
80
|
+
*
|
|
81
|
+
* @param props - The props for the CustomButton component
|
|
82
|
+
* @returns A React functional component
|
|
83
|
+
*/
|
|
66
84
|
const CustomButton: React.FC<CustomButtonProps> = props => {
|
|
67
85
|
const {
|
|
68
86
|
text,
|
|
@@ -83,111 +101,15 @@ const CustomButton: React.FC<CustomButtonProps> = props => {
|
|
|
83
101
|
width,
|
|
84
102
|
} = props
|
|
85
103
|
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
)
|
|
89
|
-
const [, setIsFormValid] = useState<boolean>(true)
|
|
90
|
-
const [hasBeenClicked, setHasBeenClicked] = useState<boolean>(false)
|
|
91
|
-
|
|
92
|
-
const fetchHelperFooters = useCallback(async (): Promise<
|
|
93
|
-
HelperFooterMessage[]
|
|
94
|
-
> => {
|
|
95
|
-
if (!formname) {
|
|
96
|
-
console.log('CustomButton: No formname provided, returning empty array')
|
|
97
|
-
return []
|
|
98
|
-
}
|
|
99
|
-
console.log('CustomButton: Fetching helper footers for formname:', formname)
|
|
100
|
-
|
|
101
|
-
// Wait for 2 seconds before fetching to allow time for cache update
|
|
102
|
-
await new Promise(resolve => setTimeout(resolve, 3000))
|
|
103
|
-
|
|
104
|
-
const helperFooterResult = await get('helperfooter', formname, 'client')
|
|
105
|
-
console.log('CustomButton: Helper footer result:', helperFooterResult)
|
|
106
|
-
|
|
107
|
-
if (
|
|
108
|
-
helperFooterResult &&
|
|
109
|
-
typeof helperFooterResult === 'object' &&
|
|
110
|
-
'type' in helperFooterResult &&
|
|
111
|
-
helperFooterResult.type === 'json' &&
|
|
112
|
-
'value' in helperFooterResult &&
|
|
113
|
-
typeof helperFooterResult.value === 'object' &&
|
|
114
|
-
helperFooterResult.value !== null
|
|
115
|
-
) {
|
|
116
|
-
const helperFooters = Object.entries(
|
|
117
|
-
helperFooterResult.value as Record<string, unknown>
|
|
118
|
-
)
|
|
119
|
-
.map(([key, value]): HelperFooterMessage | null => {
|
|
120
|
-
if (
|
|
121
|
-
typeof value === 'object' &&
|
|
122
|
-
value !== null &&
|
|
123
|
-
'status' in value &&
|
|
124
|
-
'statusMessage' in value &&
|
|
125
|
-
'spreadMessage' in value &&
|
|
126
|
-
'spreadMessagePriority' in value &&
|
|
127
|
-
'required' in value
|
|
128
|
-
) {
|
|
129
|
-
return {
|
|
130
|
-
status: value.status as 'error' | 'success',
|
|
131
|
-
statusMessage: String(value.statusMessage),
|
|
132
|
-
spreadMessage: String(value.spreadMessage),
|
|
133
|
-
spreadMessagePriority: Number(value.spreadMessagePriority),
|
|
134
|
-
required: Boolean(value.required),
|
|
135
|
-
formname: key,
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
return null
|
|
139
|
-
})
|
|
140
|
-
.filter((value): value is HelperFooterMessage => value !== null)
|
|
141
|
-
|
|
142
|
-
console.log('CustomButton: Valid helper footers:', helperFooters)
|
|
143
|
-
return helperFooters
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
console.log('CustomButton: No valid helper footers found in cache')
|
|
147
|
-
return []
|
|
148
|
-
}, [formname])
|
|
104
|
+
const { errorMessage, isFormValid, updateFormValidation } =
|
|
105
|
+
useHelperFooter(formname)
|
|
149
106
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
console.log('CustomButton: No helper footers found, form is valid')
|
|
157
|
-
setErrorMessage(undefined)
|
|
158
|
-
setIsFormValid(true)
|
|
159
|
-
return true
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
const errorFooters = helperFooters.filter(
|
|
163
|
-
footer => footer.status === 'error'
|
|
164
|
-
)
|
|
165
|
-
console.log('CustomButton: Error footers:', errorFooters)
|
|
166
|
-
|
|
167
|
-
if (errorFooters.length > 0) {
|
|
168
|
-
console.log('CustomButton: Found error footers, form is invalid')
|
|
169
|
-
const highestPriorityError = errorFooters.reduce((prev, current) =>
|
|
170
|
-
prev.spreadMessagePriority < current.spreadMessagePriority
|
|
171
|
-
? prev
|
|
172
|
-
: current
|
|
173
|
-
)
|
|
174
|
-
setErrorMessage(highestPriorityError.spreadMessage)
|
|
175
|
-
setIsFormValid(false)
|
|
176
|
-
return false
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
console.log('CustomButton: No error footers found, form is valid')
|
|
180
|
-
setErrorMessage(undefined)
|
|
181
|
-
setIsFormValid(true)
|
|
182
|
-
return true
|
|
183
|
-
}, [fetchHelperFooters])
|
|
184
|
-
|
|
185
|
-
useEffect(() => {
|
|
186
|
-
console.log('CustomButton: Running effect to update form validation')
|
|
187
|
-
void updateFormValidation()
|
|
188
|
-
}, [updateFormValidation])
|
|
189
|
-
|
|
190
|
-
const renderIcon = (): React.ReactNode => {
|
|
107
|
+
/**
|
|
108
|
+
* Renders the icon for the button based on the provided props.
|
|
109
|
+
*
|
|
110
|
+
* @returns {React.ReactNode} The rendered icon or null
|
|
111
|
+
*/
|
|
112
|
+
const renderIcon = useCallback((): React.ReactNode => {
|
|
191
113
|
if (icon === false) {
|
|
192
114
|
return null
|
|
193
115
|
}
|
|
@@ -197,24 +119,80 @@ const CustomButton: React.FC<CustomButtonProps> = props => {
|
|
|
197
119
|
})
|
|
198
120
|
}
|
|
199
121
|
return <StarIcon style={{ fontSize: iconsize }} />
|
|
200
|
-
}
|
|
122
|
+
}, [icon, iconsize])
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Handles the button click event. Prevents default behavior, validates the form,
|
|
126
|
+
* and calls the onClick prop if the form is valid.
|
|
127
|
+
*
|
|
128
|
+
* @param event - The mouse event from clicking the button
|
|
129
|
+
*/
|
|
130
|
+
const handleButtonClick = useCallback(
|
|
131
|
+
async (event: React.MouseEvent<HTMLButtonElement>): Promise<void> => {
|
|
132
|
+
event.preventDefault()
|
|
133
|
+
const validationResult = await updateFormValidation(formname)
|
|
134
|
+
if (validationResult && onClick) {
|
|
135
|
+
onClick()
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
[updateFormValidation, onClick, formname]
|
|
139
|
+
)
|
|
201
140
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
141
|
+
/**
|
|
142
|
+
* Memoized style object for the button.
|
|
143
|
+
*/
|
|
144
|
+
const buttonStyle = useMemo(
|
|
145
|
+
() => ({
|
|
146
|
+
minWidth: text ? 'auto' : 'fit-content',
|
|
147
|
+
paddingLeft: text ? '8px' : '0',
|
|
148
|
+
paddingRight: text ? '8px' : '0',
|
|
149
|
+
justifyContent: fontlocation || 'center',
|
|
150
|
+
backgroundColor: backgroundcolor,
|
|
151
|
+
border: outlinecolor ? `1px solid ${outlinecolor}` : undefined,
|
|
152
|
+
color: iconcolor,
|
|
153
|
+
width: width,
|
|
154
|
+
}),
|
|
155
|
+
[text, fontlocation, backgroundcolor, outlinecolor, iconcolor, width]
|
|
156
|
+
)
|
|
208
157
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
158
|
+
/**
|
|
159
|
+
* Memoized content for the button, including icon and text.
|
|
160
|
+
*/
|
|
161
|
+
const buttonContent = useMemo(
|
|
162
|
+
() => (
|
|
163
|
+
<Box display="flex" alignItems="center">
|
|
164
|
+
{iconlocation === 'left' && renderIcon()}
|
|
165
|
+
{text && (
|
|
166
|
+
<Typography
|
|
167
|
+
fontvariant={fontvariant}
|
|
168
|
+
fontcolor={fontcolor}
|
|
169
|
+
text={text}
|
|
170
|
+
/>
|
|
171
|
+
)}
|
|
172
|
+
{iconlocation === 'right' && renderIcon()}
|
|
173
|
+
</Box>
|
|
174
|
+
),
|
|
175
|
+
[iconlocation, renderIcon, text, fontvariant, fontcolor]
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Memoized error message component that displays when the form is invalid.
|
|
180
|
+
*/
|
|
181
|
+
const errorMessageComponent = useMemo(
|
|
182
|
+
() =>
|
|
183
|
+
!isFormValid && errorMessage ? (
|
|
184
|
+
<Typography
|
|
185
|
+
fontvariant="merrihelperfooter"
|
|
186
|
+
fontcolor={red.main}
|
|
187
|
+
text={errorMessage}
|
|
188
|
+
marginTop={0.5}
|
|
189
|
+
marginBottom={0}
|
|
190
|
+
align="center"
|
|
191
|
+
width="100%"
|
|
192
|
+
/>
|
|
193
|
+
) : null,
|
|
194
|
+
[errorMessage, isFormValid]
|
|
195
|
+
)
|
|
218
196
|
|
|
219
197
|
return (
|
|
220
198
|
<Box
|
|
@@ -231,42 +209,13 @@ const CustomButton: React.FC<CustomButtonProps> = props => {
|
|
|
231
209
|
type={type}
|
|
232
210
|
name={name}
|
|
233
211
|
onClick={handleButtonClick}
|
|
234
|
-
style={
|
|
235
|
-
minWidth: text ? 'auto' : 'fit-content',
|
|
236
|
-
paddingLeft: text ? '8px' : '0',
|
|
237
|
-
paddingRight: text ? '8px' : '0',
|
|
238
|
-
justifyContent: fontlocation || 'center',
|
|
239
|
-
backgroundColor: backgroundcolor,
|
|
240
|
-
border: outlinecolor ? `1px solid ${outlinecolor}` : undefined,
|
|
241
|
-
color: iconcolor,
|
|
242
|
-
width: width,
|
|
243
|
-
}}
|
|
212
|
+
style={buttonStyle}
|
|
244
213
|
>
|
|
245
|
-
|
|
246
|
-
{iconlocation === 'left' && renderIcon()}
|
|
247
|
-
{text && (
|
|
248
|
-
<Typography
|
|
249
|
-
fontvariant={fontvariant}
|
|
250
|
-
fontcolor={fontcolor}
|
|
251
|
-
text={text}
|
|
252
|
-
/>
|
|
253
|
-
)}
|
|
254
|
-
{iconlocation === 'right' && renderIcon()}
|
|
255
|
-
</Box>
|
|
214
|
+
{buttonContent}
|
|
256
215
|
</Button>
|
|
257
|
-
{
|
|
258
|
-
<Typography
|
|
259
|
-
fontvariant="merrihelperfooter"
|
|
260
|
-
fontcolor={red.main}
|
|
261
|
-
text={errorMessage}
|
|
262
|
-
marginTop={0.5}
|
|
263
|
-
marginBottom={0}
|
|
264
|
-
align="center"
|
|
265
|
-
width="100%"
|
|
266
|
-
/>
|
|
267
|
-
)}
|
|
216
|
+
{errorMessageComponent}
|
|
268
217
|
</Box>
|
|
269
218
|
)
|
|
270
219
|
}
|
|
271
220
|
|
|
272
|
-
export default CustomButton
|
|
221
|
+
export default React.memo(CustomButton)
|
|
@@ -33,7 +33,6 @@ const useButton = (grid: {
|
|
|
33
33
|
iconlocation,
|
|
34
34
|
variant,
|
|
35
35
|
onClick,
|
|
36
|
-
helperfooter,
|
|
37
36
|
columnconfig: itemColumnConfig,
|
|
38
37
|
cellconfig,
|
|
39
38
|
...restProps
|
|
@@ -72,7 +71,6 @@ const useButton = (grid: {
|
|
|
72
71
|
iconlocation={iconlocation}
|
|
73
72
|
variant={variant}
|
|
74
73
|
onClick={onClick}
|
|
75
|
-
helperfooter={helperfooter}
|
|
76
74
|
{...restProps}
|
|
77
75
|
/>
|
|
78
76
|
),
|
|
@@ -2,27 +2,53 @@
|
|
|
2
2
|
|
|
3
3
|
import { useCallback, useState, useMemo, useRef, useEffect } from 'react'
|
|
4
4
|
import { debounce } from 'lodash'
|
|
5
|
-
import { get, set, StringValue, JSONValue } from 'goobs-cache'
|
|
5
|
+
import { get, set, remove, StringValue, JSONValue } from 'goobs-cache'
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Validates if the given email string is in a valid email format.
|
|
9
|
+
* @param {string} email - The email string to validate.
|
|
10
|
+
* @returns {boolean} True if the email is valid, false otherwise.
|
|
11
|
+
*/
|
|
7
12
|
const isValidEmailFormat = (email: string): boolean => {
|
|
8
13
|
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/
|
|
9
14
|
return emailRegex.test(email)
|
|
10
15
|
}
|
|
11
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Represents the structure of a helper footer message.
|
|
19
|
+
*/
|
|
12
20
|
export interface HelperFooterMessage {
|
|
21
|
+
/** The status of the message: 'error', 'success', or 'emptyAndRequired'. */
|
|
13
22
|
status: 'error' | 'success' | 'emptyAndRequired'
|
|
23
|
+
/** A detailed message describing the status. */
|
|
14
24
|
statusMessage: string
|
|
25
|
+
/** A concise message for display purposes. */
|
|
15
26
|
spreadMessage: string
|
|
27
|
+
/** A number indicating the priority of the message. Lower numbers indicate higher priority. */
|
|
16
28
|
spreadMessagePriority: number
|
|
29
|
+
/** Indicates whether this field is required. */
|
|
17
30
|
required: boolean
|
|
18
31
|
}
|
|
19
32
|
|
|
33
|
+
/**
|
|
34
|
+
* A custom hook for managing helper footer messages and form validation.
|
|
35
|
+
* @returns {Object} An object containing functions and state for managing helper footers.
|
|
36
|
+
*/
|
|
20
37
|
export const useHelperFooter = () => {
|
|
21
38
|
const [helperFooterValue, setHelperFooterValue] = useState<
|
|
22
39
|
Record<string, HelperFooterMessage>
|
|
23
40
|
>({})
|
|
24
41
|
const helperFooterRef = useRef<Record<string, HelperFooterMessage>>({})
|
|
25
42
|
|
|
43
|
+
/**
|
|
44
|
+
* Handles the creation of error messages for generic fields.
|
|
45
|
+
* @param {FormData} formData - The form data containing the field value.
|
|
46
|
+
* @param {string} name - The name of the field.
|
|
47
|
+
* @param {string} label - The label of the field.
|
|
48
|
+
* @param {boolean} required - Whether the field is required.
|
|
49
|
+
* @param {string} formname - The name of the form.
|
|
50
|
+
* @returns {Promise<HelperFooterMessage | undefined>} A promise that resolves to a HelperFooterMessage or undefined.
|
|
51
|
+
*/
|
|
26
52
|
const handleGenericErrorCreation = useCallback(
|
|
27
53
|
async (
|
|
28
54
|
formData: FormData,
|
|
@@ -53,18 +79,22 @@ export const useHelperFooter = () => {
|
|
|
53
79
|
},
|
|
54
80
|
}
|
|
55
81
|
await set('helperfooter', formname, jsonValue, 'client')
|
|
56
|
-
console.log(
|
|
57
|
-
`Stored helper footer for ${name}:`,
|
|
58
|
-
message,
|
|
59
|
-
`storeName: ${formname}`
|
|
60
|
-
)
|
|
61
82
|
return message
|
|
83
|
+
} else {
|
|
84
|
+
await remove('helperfooter', formname, 'client')
|
|
62
85
|
}
|
|
63
86
|
return undefined
|
|
64
87
|
},
|
|
65
88
|
[]
|
|
66
89
|
)
|
|
67
90
|
|
|
91
|
+
/**
|
|
92
|
+
* Handles the creation of error messages for email fields.
|
|
93
|
+
* @param {FormData} formData - The form data containing the email value.
|
|
94
|
+
* @param {boolean} required - Whether the email field is required.
|
|
95
|
+
* @param {string} formname - The name of the form.
|
|
96
|
+
* @returns {Promise<HelperFooterMessage | undefined>} A promise that resolves to a HelperFooterMessage or undefined.
|
|
97
|
+
*/
|
|
68
98
|
const handleEmailErrorCreation = useCallback(
|
|
69
99
|
async (
|
|
70
100
|
formData: FormData,
|
|
@@ -101,24 +131,23 @@ export const useHelperFooter = () => {
|
|
|
101
131
|
}
|
|
102
132
|
|
|
103
133
|
if (message) {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
134
|
+
if (message.status === 'success') {
|
|
135
|
+
await remove('helperfooter', formname, 'client')
|
|
136
|
+
} else {
|
|
137
|
+
const jsonValue: JSONValue = {
|
|
138
|
+
type: 'json',
|
|
139
|
+
value: {
|
|
140
|
+
email: {
|
|
141
|
+
status: message.status,
|
|
142
|
+
statusMessage: message.statusMessage,
|
|
143
|
+
spreadMessage: message.spreadMessage,
|
|
144
|
+
spreadMessagePriority: message.spreadMessagePriority,
|
|
145
|
+
required: message.required,
|
|
146
|
+
},
|
|
113
147
|
},
|
|
114
|
-
}
|
|
148
|
+
}
|
|
149
|
+
await set('helperfooter', formname, jsonValue, 'client')
|
|
115
150
|
}
|
|
116
|
-
await set('helperfooter', formname, jsonValue, 'client')
|
|
117
|
-
console.log(
|
|
118
|
-
`Stored helper footer for email:`,
|
|
119
|
-
message,
|
|
120
|
-
`storeName: ${formname}`
|
|
121
|
-
)
|
|
122
151
|
}
|
|
123
152
|
|
|
124
153
|
return message
|
|
@@ -126,6 +155,13 @@ export const useHelperFooter = () => {
|
|
|
126
155
|
[]
|
|
127
156
|
)
|
|
128
157
|
|
|
158
|
+
/**
|
|
159
|
+
* Handles the creation of error messages for password fields.
|
|
160
|
+
* @param {FormData} formData - The form data containing the password value.
|
|
161
|
+
* @param {boolean} required - Whether the password field is required.
|
|
162
|
+
* @param {string} formname - The name of the form.
|
|
163
|
+
* @returns {Promise<HelperFooterMessage | undefined>} A promise that resolves to a HelperFooterMessage or undefined.
|
|
164
|
+
*/
|
|
129
165
|
const handlePasswordErrorCreation = useCallback(
|
|
130
166
|
async (
|
|
131
167
|
formData: FormData,
|
|
@@ -133,24 +169,15 @@ export const useHelperFooter = () => {
|
|
|
133
169
|
formname: string
|
|
134
170
|
): Promise<HelperFooterMessage | undefined> => {
|
|
135
171
|
const password = formData.get('verifyPassword') as string
|
|
136
|
-
console.log('handlePasswordErrorCreation - Password:', password)
|
|
137
172
|
|
|
138
173
|
const debouncedPasswordStorage = debounce(async () => {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
'client'
|
|
147
|
-
)
|
|
148
|
-
console.log('Password stored successfully')
|
|
149
|
-
} else {
|
|
150
|
-
console.log('No password to store')
|
|
151
|
-
}
|
|
152
|
-
} catch (error) {
|
|
153
|
-
console.error('Error interacting with goobs-cache:', error)
|
|
174
|
+
if (password) {
|
|
175
|
+
await set(
|
|
176
|
+
'validate',
|
|
177
|
+
formname,
|
|
178
|
+
{ type: 'string', value: password } as StringValue,
|
|
179
|
+
'client'
|
|
180
|
+
)
|
|
154
181
|
}
|
|
155
182
|
}, 2000)
|
|
156
183
|
|
|
@@ -193,24 +220,23 @@ export const useHelperFooter = () => {
|
|
|
193
220
|
}
|
|
194
221
|
|
|
195
222
|
if (message) {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
223
|
+
if (message.status === 'success') {
|
|
224
|
+
await remove('helperfooter', formname, 'client')
|
|
225
|
+
} else {
|
|
226
|
+
const jsonValue: JSONValue = {
|
|
227
|
+
type: 'json',
|
|
228
|
+
value: {
|
|
229
|
+
verifyPassword: {
|
|
230
|
+
status: message.status,
|
|
231
|
+
statusMessage: message.statusMessage,
|
|
232
|
+
spreadMessage: message.spreadMessage,
|
|
233
|
+
spreadMessagePriority: message.spreadMessagePriority,
|
|
234
|
+
required: message.required,
|
|
235
|
+
},
|
|
205
236
|
},
|
|
206
|
-
}
|
|
237
|
+
}
|
|
238
|
+
await set('helperfooter', formname, jsonValue, 'client')
|
|
207
239
|
}
|
|
208
|
-
await set('helperfooter', formname, jsonValue, 'client')
|
|
209
|
-
console.log(
|
|
210
|
-
`Stored helper footer for verifyPassword:`,
|
|
211
|
-
message,
|
|
212
|
-
`storeName: ${formname}`
|
|
213
|
-
)
|
|
214
240
|
}
|
|
215
241
|
|
|
216
242
|
return message
|
|
@@ -218,6 +244,13 @@ export const useHelperFooter = () => {
|
|
|
218
244
|
[]
|
|
219
245
|
)
|
|
220
246
|
|
|
247
|
+
/**
|
|
248
|
+
* Handles the creation of error messages for password confirmation fields.
|
|
249
|
+
* @param {FormData} formData - The form data containing the confirmation password value.
|
|
250
|
+
* @param {boolean} required - Whether the confirmation password field is required.
|
|
251
|
+
* @param {string} formname - The name of the form.
|
|
252
|
+
* @returns {Promise<HelperFooterMessage | undefined>} A promise that resolves to a HelperFooterMessage or undefined.
|
|
253
|
+
*/
|
|
221
254
|
const handleConfirmPasswordErrorCreation = useCallback(
|
|
222
255
|
async (
|
|
223
256
|
formData: FormData,
|
|
@@ -225,10 +258,6 @@ export const useHelperFooter = () => {
|
|
|
225
258
|
formname: string
|
|
226
259
|
): Promise<HelperFooterMessage | undefined> => {
|
|
227
260
|
const confirmPassword = formData.get('confirmPassword') as string
|
|
228
|
-
console.log(
|
|
229
|
-
'handleConfirmPasswordErrorCreation - Confirm Password:',
|
|
230
|
-
confirmPassword
|
|
231
|
-
)
|
|
232
261
|
|
|
233
262
|
let message: HelperFooterMessage | undefined
|
|
234
263
|
|
|
@@ -243,11 +272,9 @@ export const useHelperFooter = () => {
|
|
|
243
272
|
} else if (confirmPassword) {
|
|
244
273
|
let verifyPasswordResult
|
|
245
274
|
try {
|
|
246
|
-
console.log('Retrieving password from goobs-cache...')
|
|
247
275
|
verifyPasswordResult = await get('validate', formname, 'client')
|
|
248
|
-
console.log('Retrieved password result:', verifyPasswordResult)
|
|
249
276
|
} catch (error) {
|
|
250
|
-
|
|
277
|
+
// Error handling
|
|
251
278
|
}
|
|
252
279
|
|
|
253
280
|
let verifyPassword: string | undefined
|
|
@@ -260,9 +287,6 @@ export const useHelperFooter = () => {
|
|
|
260
287
|
typeof verifyPasswordResult.value === 'string'
|
|
261
288
|
) {
|
|
262
289
|
verifyPassword = verifyPasswordResult.value
|
|
263
|
-
console.log('Verify password retrieved:', verifyPassword)
|
|
264
|
-
} else {
|
|
265
|
-
console.log('Invalid or missing verify password result')
|
|
266
290
|
}
|
|
267
291
|
|
|
268
292
|
if (!verifyPassword) {
|
|
@@ -293,24 +317,23 @@ export const useHelperFooter = () => {
|
|
|
293
317
|
}
|
|
294
318
|
|
|
295
319
|
if (message) {
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
320
|
+
if (message.status === 'success') {
|
|
321
|
+
await remove('helperfooter', formname, 'client')
|
|
322
|
+
} else {
|
|
323
|
+
const jsonValue: JSONValue = {
|
|
324
|
+
type: 'json',
|
|
325
|
+
value: {
|
|
326
|
+
confirmPassword: {
|
|
327
|
+
status: message.status,
|
|
328
|
+
statusMessage: message.statusMessage,
|
|
329
|
+
spreadMessage: message.spreadMessage,
|
|
330
|
+
spreadMessagePriority: message.spreadMessagePriority,
|
|
331
|
+
required: message.required,
|
|
332
|
+
},
|
|
305
333
|
},
|
|
306
|
-
}
|
|
334
|
+
}
|
|
335
|
+
await set('helperfooter', formname, jsonValue, 'client')
|
|
307
336
|
}
|
|
308
|
-
await set('helperfooter', formname, jsonValue, 'client')
|
|
309
|
-
console.log(
|
|
310
|
-
`Stored helper footer for confirmPassword:`,
|
|
311
|
-
message,
|
|
312
|
-
`storeName: ${formname}`
|
|
313
|
-
)
|
|
314
337
|
}
|
|
315
338
|
|
|
316
339
|
return message
|
|
@@ -318,6 +341,13 @@ export const useHelperFooter = () => {
|
|
|
318
341
|
[]
|
|
319
342
|
)
|
|
320
343
|
|
|
344
|
+
/**
|
|
345
|
+
* Handles the creation of error messages for phone number fields.
|
|
346
|
+
* @param {FormData} formData - The form data containing the phone number value.
|
|
347
|
+
* @param {boolean} required - Whether the phone number field is required.
|
|
348
|
+
* @param {string} formname - The name of the form.
|
|
349
|
+
* @returns {Promise<HelperFooterMessage | undefined>} A promise that resolves to a HelperFooterMessage or undefined.
|
|
350
|
+
*/
|
|
321
351
|
const handlePhoneNumberErrorCreation = useCallback(
|
|
322
352
|
async (
|
|
323
353
|
formData: FormData,
|
|
@@ -363,24 +393,23 @@ export const useHelperFooter = () => {
|
|
|
363
393
|
}
|
|
364
394
|
|
|
365
395
|
if (message) {
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
396
|
+
if (message.status === 'success') {
|
|
397
|
+
await remove('helperfooter', formname, 'client')
|
|
398
|
+
} else {
|
|
399
|
+
const jsonValue: JSONValue = {
|
|
400
|
+
type: 'json',
|
|
401
|
+
value: {
|
|
402
|
+
phoneNumber: {
|
|
403
|
+
status: message.status,
|
|
404
|
+
statusMessage: message.statusMessage,
|
|
405
|
+
spreadMessage: message.spreadMessage,
|
|
406
|
+
spreadMessagePriority: message.spreadMessagePriority,
|
|
407
|
+
required: message.required,
|
|
408
|
+
},
|
|
375
409
|
},
|
|
376
|
-
}
|
|
410
|
+
}
|
|
411
|
+
await set('helperfooter', formname, jsonValue, 'client')
|
|
377
412
|
}
|
|
378
|
-
await set('helperfooter', formname, jsonValue, 'client')
|
|
379
|
-
console.log(
|
|
380
|
-
`Stored helper footer for phoneNumber:`,
|
|
381
|
-
message,
|
|
382
|
-
`storeName: ${formname}`
|
|
383
|
-
)
|
|
384
413
|
}
|
|
385
414
|
|
|
386
415
|
return message
|
|
@@ -388,6 +417,11 @@ export const useHelperFooter = () => {
|
|
|
388
417
|
[]
|
|
389
418
|
)
|
|
390
419
|
|
|
420
|
+
/**
|
|
421
|
+
* Updates the helper footer state with new validation results.
|
|
422
|
+
* @param {string} name - The name of the field.
|
|
423
|
+
* @param {HelperFooterMessage | undefined} validationResult - The validation result for the field.
|
|
424
|
+
*/
|
|
391
425
|
const updateHelperFooter = useCallback(
|
|
392
426
|
(name: string, validationResult: HelperFooterMessage | undefined): void => {
|
|
393
427
|
if (validationResult) {
|
|
@@ -410,9 +444,12 @@ export const useHelperFooter = () => {
|
|
|
410
444
|
[]
|
|
411
445
|
)
|
|
412
446
|
|
|
447
|
+
/**
|
|
448
|
+
* Initializes required fields for a given form.
|
|
449
|
+
* @param {string} formname - The name of the form.
|
|
450
|
+
*/
|
|
413
451
|
const initializeRequiredFields = useCallback(
|
|
414
452
|
async (formname: string) => {
|
|
415
|
-
console.log(`Initializing required fields for ${formname}`)
|
|
416
453
|
const fields = await get('helperfooter', formname, 'client')
|
|
417
454
|
if (
|
|
418
455
|
fields &&
|
|
@@ -425,7 +462,6 @@ export const useHelperFooter = () => {
|
|
|
425
462
|
([field, message]) => {
|
|
426
463
|
if (message && typeof message === 'object' && 'status' in message) {
|
|
427
464
|
updateHelperFooter(field, message as HelperFooterMessage)
|
|
428
|
-
console.log(`Initialized required field ${field}:`, message)
|
|
429
465
|
}
|
|
430
466
|
}
|
|
431
467
|
)
|
|
@@ -434,6 +470,14 @@ export const useHelperFooter = () => {
|
|
|
434
470
|
[updateHelperFooter]
|
|
435
471
|
)
|
|
436
472
|
|
|
473
|
+
/**
|
|
474
|
+
* Validates a specific field in the form.
|
|
475
|
+
* @param {string} name - The name of the field.
|
|
476
|
+
* @param {FormData} formData - The form data containing the field value.
|
|
477
|
+
* @param {string} label - The label of the field.
|
|
478
|
+
* @param {boolean} required - Whether the field is required.
|
|
479
|
+
* @param {string} formname - The name of the form.
|
|
480
|
+
*/
|
|
437
481
|
const validateField = useCallback(
|
|
438
482
|
async (
|
|
439
483
|
name: string,
|
|
@@ -442,7 +486,6 @@ export const useHelperFooter = () => {
|
|
|
442
486
|
required: boolean,
|
|
443
487
|
formname: string
|
|
444
488
|
) => {
|
|
445
|
-
console.log(`Validating field: ${name}`)
|
|
446
489
|
let validationResult: HelperFooterMessage | undefined
|
|
447
490
|
|
|
448
491
|
switch (name) {
|
|
@@ -485,7 +528,6 @@ export const useHelperFooter = () => {
|
|
|
485
528
|
}
|
|
486
529
|
|
|
487
530
|
updateHelperFooter(name, validationResult)
|
|
488
|
-
console.log(`Validation result for ${name}:`, validationResult)
|
|
489
531
|
},
|
|
490
532
|
[
|
|
491
533
|
handleEmailErrorCreation,
|
|
@@ -497,9 +539,15 @@ export const useHelperFooter = () => {
|
|
|
497
539
|
]
|
|
498
540
|
)
|
|
499
541
|
|
|
542
|
+
/**
|
|
543
|
+
* Validates a required field in the form.
|
|
544
|
+
* @param {boolean} required - Whether the field is required.
|
|
545
|
+
* @param {string} formname - The name of the form.
|
|
546
|
+
* @param {string} name - The name of the field.
|
|
547
|
+
* @param {string} label - The label of the field.
|
|
548
|
+
*/
|
|
500
549
|
const validateRequiredField = useCallback(
|
|
501
550
|
(required: boolean, formname: string, name: string, label: string) => {
|
|
502
|
-
console.log(`Validating required field: ${name}`)
|
|
503
551
|
if (required && formname && name && label) {
|
|
504
552
|
const emptyFormData = new FormData()
|
|
505
553
|
emptyFormData.append(name, '')
|
|
@@ -509,6 +557,13 @@ export const useHelperFooter = () => {
|
|
|
509
557
|
[validateField]
|
|
510
558
|
)
|
|
511
559
|
|
|
560
|
+
/**
|
|
561
|
+
* A custom hook to determine whether to show an error message.
|
|
562
|
+
* @param {boolean} formSubmitted - Whether the form has been submitted.
|
|
563
|
+
* @param {boolean} hasInput - Whether the field has input.
|
|
564
|
+
* @param {boolean} isFocused - Whether the field is currently focused.
|
|
565
|
+
* @returns {boolean} Whether to show the error message.
|
|
566
|
+
*/
|
|
512
567
|
const useShowErrorEffect = (
|
|
513
568
|
formSubmitted: boolean,
|
|
514
569
|
hasInput: boolean,
|
|
@@ -519,15 +574,18 @@ export const useHelperFooter = () => {
|
|
|
519
574
|
useEffect(() => {
|
|
520
575
|
const shouldShowError = formSubmitted || (hasInput && !isFocused)
|
|
521
576
|
setShowError(shouldShowError)
|
|
522
|
-
console.log('Show error state updated:', shouldShowError)
|
|
523
577
|
}, [formSubmitted, hasInput, isFocused])
|
|
524
578
|
|
|
525
579
|
return showError
|
|
526
580
|
}
|
|
527
581
|
|
|
582
|
+
/**
|
|
583
|
+
* Fetches helper footer messages for a given form.
|
|
584
|
+
* @param {string} formname - The name of the form.
|
|
585
|
+
* @returns {Promise<HelperFooterMessage[]>} A promise that resolves to an array of HelperFooterMessages.
|
|
586
|
+
*/
|
|
528
587
|
const fetchHelperFooters = useCallback(
|
|
529
588
|
async (formname: string): Promise<HelperFooterMessage[]> => {
|
|
530
|
-
console.log(`Fetching helper footers for ${formname}`)
|
|
531
589
|
const helperFooters = await get('helperfooter', formname, 'client')
|
|
532
590
|
if (
|
|
533
591
|
helperFooters &&
|
|
@@ -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,
|
|
@@ -164,8 +164,10 @@ const StyledComponent: React.FC<StyledComponentProps> = props => {
|
|
|
164
164
|
inputBoxRef,
|
|
165
165
|
onOptionSelect
|
|
166
166
|
)
|
|
167
|
-
const { phoneNumber, handlePhoneNumberChange
|
|
168
|
-
|
|
167
|
+
const { phoneNumber, handlePhoneNumberChange } = usePhoneNumber(
|
|
168
|
+
value || '',
|
|
169
|
+
componentvariant
|
|
170
|
+
)
|
|
169
171
|
const {
|
|
170
172
|
value: splitButtonValue,
|
|
171
173
|
handleIncrement,
|
|
@@ -204,15 +206,6 @@ const StyledComponent: React.FC<StyledComponentProps> = props => {
|
|
|
204
206
|
return () => clearTimeout(timer)
|
|
205
207
|
}, [formSubmitted, hasInput])
|
|
206
208
|
|
|
207
|
-
/**
|
|
208
|
-
* Update phone number when componentvariant is 'phonenumber' and value changes
|
|
209
|
-
*/
|
|
210
|
-
useEffect(() => {
|
|
211
|
-
if (componentvariant === 'phonenumber' && value) {
|
|
212
|
-
updatePhoneNumber(value)
|
|
213
|
-
}
|
|
214
|
-
}, [componentvariant, value, updatePhoneNumber])
|
|
215
|
-
|
|
216
209
|
const currentHelperFooter = name ? helperFooterValue[name] : undefined
|
|
217
210
|
|
|
218
211
|
/**
|