goobs-frontend 0.7.65 → 0.7.67

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.
@@ -1,4 +1,6 @@
1
- import React, { useState, useCallback, useEffect } from 'react'
1
+ 'use client'
2
+
3
+ import React, { useState, useCallback } from 'react'
2
4
 
3
5
  /**
4
6
  * Formats a string of digits into a US phone number format.
@@ -37,9 +39,10 @@ export const formatPhoneNumber = (value: string): string => {
37
39
  * @property {string} phoneNumber - The current formatted phone number.
38
40
  * @property {function} handlePhoneNumberChange - A function to handle changes to the phone number input.
39
41
  * @property {function} updatePhoneNumber - A function to directly update the phone number.
42
+ * @property {function} checkAndUpdatePhoneNumber - A function to check and update the phone number based on component variant and initial value.
40
43
  *
41
44
  * @example
42
- * const { phoneNumber, handlePhoneNumberChange, updatePhoneNumber } = usePhoneNumber();
45
+ * const { phoneNumber, handlePhoneNumberChange, updatePhoneNumber, checkAndUpdatePhoneNumber } = usePhoneNumber();
43
46
  */
44
47
  export const usePhoneNumber = (
45
48
  initialValue: string = '',
@@ -58,10 +61,8 @@ export const usePhoneNumber = (
58
61
  (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
59
62
  const input = e.target.value
60
63
  let strippedInput = input.replace(/^\+1\s?/, '').replace(/\D/g, '')
61
-
62
64
  // Ensure we don't exceed 10 digits
63
65
  strippedInput = strippedInput.slice(0, 10)
64
-
65
66
  // Only format if there's actual input beyond "+1 "
66
67
  const formattedValue =
67
68
  strippedInput.length > 0 ? formatPhoneNumber(strippedInput) : '+1 '
@@ -80,9 +81,10 @@ export const usePhoneNumber = (
80
81
  }, [])
81
82
 
82
83
  /**
83
- * Update phone number when componentvariant is 'phonenumber' and value changes
84
+ * Checks and updates the phone number based on component variant and initial value.
85
+ * This function replaces the useEffect from the original implementation.
84
86
  */
85
- useEffect(() => {
87
+ const checkAndUpdatePhoneNumber = useCallback(() => {
86
88
  if (componentvariant === 'phonenumber' && initialValue) {
87
89
  updatePhoneNumber(initialValue)
88
90
  }
@@ -92,5 +94,6 @@ export const usePhoneNumber = (
92
94
  phoneNumber,
93
95
  handlePhoneNumberChange,
94
96
  updatePhoneNumber,
97
+ checkAndUpdatePhoneNumber,
95
98
  }
96
99
  }
@@ -1,82 +1,107 @@
1
- import { useCallback, useMemo, MutableRefObject } from 'react'
1
+ 'use client'
2
+
3
+ import { useCallback, useMemo, MutableRefObject, useRef } from 'react'
2
4
  import { session } from 'goobs-cache'
3
5
  import { StyledComponentProps } from '../index'
4
6
  import { HelperFooterMessage } from './useInputHelperFooter'
7
+ import { ClientLogger } from 'goobs-testing'
5
8
 
6
9
  type HelperFooterState = Record<string, HelperFooterMessage>
7
10
 
8
11
  export const useRequiredFieldsValidator = (
9
12
  formname: string,
10
13
  components: StyledComponentProps[],
11
- hasInputRef: MutableRefObject<boolean>
14
+ hasInputRef: MutableRefObject<boolean>,
15
+ helperFooterAtom: ReturnType<typeof session.atom<HelperFooterState>>
12
16
  ) => {
13
- console.log('useRequiredFieldsValidator called with:', {
17
+ ClientLogger.debug('useRequiredFieldsValidator called', {
14
18
  formname,
15
- components,
16
- hasInputRef,
19
+ componentsCount: components.length,
20
+ hasInputRefCurrent: hasInputRef.current,
17
21
  })
18
22
 
19
- const helperFootersAtom = session.atom<HelperFooterState>({})
20
- const [helperFooters, setHelperFooters] = session.useAtom(helperFootersAtom)
23
+ const [helperFooters, setHelperFooters] = session.useAtom(helperFooterAtom)
24
+ const failedAttempts = useRef<Record<string, number>>({})
21
25
 
22
26
  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
- )
27
+ ClientLogger.debug('initializeComponentStatuses called')
28
+
29
+ try {
30
+ const initialHelperFooters: HelperFooterState = {
31
+ ...(helperFooters || {}),
46
32
  }
47
- })
48
33
 
49
- console.log('Setting helper footers in session atom')
50
- setHelperFooters(initialHelperFooters)
34
+ components.forEach(component => {
35
+ if (
36
+ component.name &&
37
+ component.required &&
38
+ component.label &&
39
+ !initialHelperFooters[component.name]
40
+ ) {
41
+ initialHelperFooters[component.name] = {
42
+ status: 'emptyAndRequired',
43
+ statusMessage: `${component.label} is required.`,
44
+ spreadMessage: `${component.label} is required.`,
45
+ spreadMessagePriority: component.spreadMessagePriority || 1,
46
+ required: true,
47
+ hasInput: false,
48
+ }
49
+ ClientLogger.debug(`Created new helper footer`, {
50
+ componentName: component.name,
51
+ helperFooter: initialHelperFooters[component.name],
52
+ })
53
+ }
54
+ })
55
+
56
+ ClientLogger.debug('Setting helper footers in session atom')
57
+ setHelperFooters(initialHelperFooters)
51
58
 
52
- console.log(`Initialized helper footers:`, initialHelperFooters)
59
+ ClientLogger.debug(`Initialized helper footers`, { initialHelperFooters })
60
+ } catch (error) {
61
+ ClientLogger.error('Error in initializeComponentStatuses', { error })
62
+ }
53
63
  }, [components, helperFooters, setHelperFooters])
54
64
 
55
65
  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
66
+ ClientLogger.debug('checkFormStatus called')
67
+ try {
68
+ const requiredComponents = components.filter(
69
+ component => component.required
70
+ )
71
+ ClientLogger.debug('Required components', {
72
+ count: requiredComponents.length,
73
+ })
74
+
75
+ const allRequiredHaveInput = requiredComponents.every(
76
+ component =>
77
+ helperFooters[component.name || '']?.hasInput || hasInputRef.current
78
+ )
79
+ ClientLogger.debug('All required fields have input', {
80
+ allRequiredHaveInput,
81
+ })
82
+ return allRequiredHaveInput
83
+ } catch (error) {
84
+ ClientLogger.error('Error in checkFormStatus', { error })
85
+ return false
86
+ }
68
87
  }, [components, hasInputRef, helperFooters])
69
88
 
70
89
  const getEmptyRequiredFields = useCallback(() => {
71
- console.log('getEmptyRequiredFields called')
90
+ ClientLogger.debug('getEmptyRequiredFields called')
72
91
 
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
92
+ try {
93
+ const emptyFields = Object.entries(helperFooters)
94
+ .filter(
95
+ ([, value]) =>
96
+ value.required && !value.hasInput && !hasInputRef.current
97
+ )
98
+ .map(([key]) => key)
99
+ ClientLogger.debug('Empty required fields', { emptyFields })
100
+ return emptyFields
101
+ } catch (error) {
102
+ ClientLogger.error('Error in getEmptyRequiredFields', { error })
103
+ return []
104
+ }
80
105
  }, [hasInputRef, helperFooters])
81
106
 
82
107
  const validateRequiredField = useCallback(
@@ -86,30 +111,58 @@ export const useRequiredFieldsValidator = (
86
111
  required: boolean,
87
112
  spreadMessagePriority: number
88
113
  ) => {
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,
114
+ ClientLogger.debug('validateRequiredField called', {
115
+ name,
116
+ label,
117
+ required,
118
+ spreadMessagePriority,
119
+ })
120
+
121
+ try {
122
+ if (failedAttempts.current[name] && failedAttempts.current[name] >= 3) {
123
+ ClientLogger.warn('Validation attempts exceeded for field', {
124
+ name,
125
+ attempts: failedAttempts.current[name],
126
+ })
127
+ return
100
128
  }
101
129
 
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`)
130
+ if (
131
+ required &&
132
+ !helperFooters[name]?.hasInput &&
133
+ !hasInputRef.current
134
+ ) {
135
+ ClientLogger.debug(
136
+ `${name} is required and empty, updating helper footer`
137
+ )
138
+ const newHelperFooter: HelperFooterMessage = {
139
+ status: 'emptyAndRequired',
140
+ statusMessage: `${label} is required.`,
141
+ spreadMessage: `${label} is required.`,
142
+ spreadMessagePriority,
143
+ required: true,
144
+ hasInput: false,
145
+ }
146
+
147
+ setHelperFooters((prev: HelperFooterState) => ({
148
+ ...prev,
149
+ [name]: newHelperFooter,
150
+ }))
151
+
152
+ ClientLogger.debug('Updated helperFooters', {
153
+ name,
154
+ newHelperFooter,
155
+ })
156
+
157
+ failedAttempts.current[name] = (failedAttempts.current[name] || 0) + 1
158
+ } else {
159
+ ClientLogger.debug(
160
+ `${name} validation not needed or already has input`
161
+ )
162
+ }
163
+ } catch (error) {
164
+ ClientLogger.error('Error in validateRequiredField', { error, name })
165
+ failedAttempts.current[name] = (failedAttempts.current[name] || 0) + 1
113
166
  }
114
167
  },
115
168
  [hasInputRef, helperFooters, setHelperFooters]
@@ -130,7 +183,7 @@ export const useRequiredFieldsValidator = (
130
183
  ]
131
184
  )
132
185
 
133
- console.log('useRequiredFieldsValidator returning:', result)
186
+ ClientLogger.debug('useRequiredFieldsValidator returning', { result })
134
187
  return result
135
188
  }
136
189
 
@@ -1,3 +1,5 @@
1
+ 'use client'
2
+
1
3
  import { useState, useCallback } from 'react'
2
4
  import React from 'react'
3
5
 
@@ -1,6 +1,6 @@
1
1
  'use client'
2
2
 
3
- import { useState, useCallback, useEffect } from 'react'
3
+ import { useState, useCallback } from 'react'
4
4
  import { StyledComponentProps } from '../index'
5
5
 
6
6
  /**
@@ -9,16 +9,9 @@ import { StyledComponentProps } from '../index'
9
9
  * @returns An object containing the value and handlers for the split button.
10
10
  */
11
11
  export const useSplitButton = (props: StyledComponentProps) => {
12
- const [value, setValue] = useState('0')
13
-
14
- /**
15
- * Update the value state when the value prop changes.
16
- */
17
- useEffect(() => {
18
- if (props.value !== undefined) {
19
- setValue(props.value)
20
- }
21
- }, [props.value])
12
+ const [value, setValue] = useState(() => {
13
+ return props.value !== undefined ? props.value : '0'
14
+ })
22
15
 
23
16
  /**
24
17
  * Increment the value by 1.
@@ -57,10 +50,21 @@ export const useSplitButton = (props: StyledComponentProps) => {
57
50
  setValue(numValue === '' ? '0' : numValue)
58
51
  }, [])
59
52
 
53
+ /**
54
+ * Update the value state when the value prop changes.
55
+ * This function replaces the useEffect from the original implementation.
56
+ */
57
+ const updateValueFromProps = useCallback(() => {
58
+ if (props.value !== undefined) {
59
+ setValue(props.value)
60
+ }
61
+ }, [props.value])
62
+
60
63
  return {
61
64
  value,
62
65
  handleIncrement,
63
66
  handleDecrement,
64
67
  handleChange,
68
+ updateValueFromProps,
65
69
  }
66
70
  }