goobs-frontend 0.7.64 → 0.7.66

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,32 +1,19 @@
1
- import React, { useMemo, useCallback } from 'react'
1
+ import React, { useMemo, useCallback, useEffect, useState } 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
6
  import useHelperFooter from './hook/useHelperFooter'
7
7
 
8
- /**
9
- * Defines the possible alignment options for the button text.
10
- */
11
8
  export type ButtonAlignment = 'left' | 'center' | 'right'
12
9
 
13
- /**
14
- * Interface for the CustomButton component props.
15
- * Extends ButtonProps from Material-UI, omitting 'color' and 'variant'.
16
- */
17
10
  export interface CustomButtonProps
18
11
  extends Omit<ButtonProps, 'color' | 'variant'> {
19
- /** The text to display on the button */
20
12
  text?: string
21
- /** The background color of the button */
22
13
  backgroundcolor?: string
23
- /** The outline color of the button */
24
14
  outlinecolor?: string
25
- /** The font color of the button text */
26
15
  fontcolor?: string
27
- /** The alignment of the button text */
28
16
  fontlocation?: ButtonAlignment
29
- /** The variant of the font to use for the button text */
30
17
  fontvariant?:
31
18
  | 'arapeyh1'
32
19
  | 'arapeyh2'
@@ -55,167 +42,226 @@ export interface CustomButtonProps
55
42
  | 'merriparagraph'
56
43
  | 'merrihelperheader'
57
44
  | 'merrihelperfooter'
58
- /** The icon to display on the button */
59
45
  icon?: React.ReactNode | false
60
- /** The color of the icon */
61
46
  iconcolor?: string
62
- /** The size of the icon */
63
47
  iconsize?: string
64
- /** The location of the icon relative to the text */
65
48
  iconlocation?: 'left' | 'top' | 'right'
66
- /** The variant of the button */
67
49
  variant?: 'text' | 'outlined' | 'contained'
68
- /** The function to call when the button is clicked */
69
50
  onClick?: () => void
70
- /** The width of the button */
71
51
  width?: string
72
- /** The name of the form associated with this button */
73
52
  formname?: string
74
- /** The name attribute of the button */
75
53
  name?: string
76
54
  }
77
55
 
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
- */
84
- const CustomButton: React.FC<CustomButtonProps> = props => {
85
- const {
86
- text,
87
- variant,
88
- fontvariant = 'merriparagraph',
89
- icon,
90
- iconlocation,
91
- iconsize,
92
- type,
93
- onClick,
94
- fontcolor,
95
- name,
96
- formname,
97
- outlinecolor,
98
- backgroundcolor,
99
- fontlocation,
100
- iconcolor,
101
- width,
102
- } = props
103
-
104
- const { errorMessage, isFormValid, updateFormValidation } =
105
- useHelperFooter(formname)
106
-
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 => {
113
- if (icon === false) {
114
- return null
115
- }
116
- if (React.isValidElement(icon)) {
117
- return React.cloneElement(icon as React.ReactElement, {
118
- style: { fontSize: iconsize },
119
- })
120
- }
121
- return <StarIcon style={{ fontSize: iconsize }} />
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()
56
+ const CustomButton: React.FC<CustomButtonProps> = React.memo(
57
+ props => {
58
+ const {
59
+ text,
60
+ variant,
61
+ fontvariant = 'merriparagraph',
62
+ icon,
63
+ iconlocation,
64
+ iconsize,
65
+ type,
66
+ onClick,
67
+ fontcolor,
68
+ name,
69
+ formname,
70
+ outlinecolor,
71
+ backgroundcolor,
72
+ fontlocation,
73
+ iconcolor,
74
+ width,
75
+ } = props
76
+
77
+ const [isFormFinished, setIsFormFinished] = useState<boolean>(false)
78
+ const [isCheckingForm, setIsCheckingForm] = useState<boolean>(true)
79
+
80
+ const {
81
+ updateFormValidation,
82
+ checkFormStatus,
83
+ getEmptyRequiredFields,
84
+ fetchHelperFooters,
85
+ } = useHelperFooter(formname)
86
+
87
+ const checkFormState = useCallback(async (): Promise<void> => {
88
+ console.log('CustomButton: Checking form state...')
89
+ setIsCheckingForm(true)
90
+
91
+ const formStatus = await checkFormStatus()
92
+ const emptyFields = await getEmptyRequiredFields()
93
+ const helperFooters = await fetchHelperFooters()
94
+
95
+ console.log('CustomButton: Form status:', formStatus)
96
+ console.log('CustomButton: Empty fields:', emptyFields)
97
+ console.log('CustomButton: Helper footers:', helperFooters)
98
+
99
+ const newIsFormFinished =
100
+ formStatus &&
101
+ emptyFields.length === 0 &&
102
+ (!helperFooters || Object.keys(helperFooters).length === 0)
103
+
104
+ setIsFormFinished(newIsFormFinished)
105
+ setIsCheckingForm(false)
106
+
107
+ console.log(
108
+ 'CustomButton: Form status changed. Is form finished:',
109
+ newIsFormFinished
110
+ )
111
+ }, [checkFormStatus, getEmptyRequiredFields, fetchHelperFooters])
112
+
113
+ useEffect(() => {
114
+ console.log('CustomButton: Performing initial check')
115
+ checkFormState()
116
+ }, [checkFormState])
117
+
118
+ const handleButtonClick = useCallback(
119
+ async (event: React.MouseEvent<HTMLButtonElement>): Promise<void> => {
120
+ event.preventDefault()
121
+ console.log(
122
+ 'CustomButton: Button clicked. Is form finished:',
123
+ isFormFinished,
124
+ 'Is checking form:',
125
+ isCheckingForm
126
+ )
127
+ if (!isFormFinished || isCheckingForm) return
128
+
129
+ const validationResult = await updateFormValidation()
130
+ console.log('CustomButton: Validation result:', validationResult)
131
+ if (validationResult && onClick) {
132
+ onClick()
133
+ }
134
+ checkFormState()
135
+ },
136
+ [
137
+ isFormFinished,
138
+ isCheckingForm,
139
+ updateFormValidation,
140
+ onClick,
141
+ checkFormState,
142
+ ]
143
+ )
144
+
145
+ const renderIcon = useCallback((): React.ReactNode => {
146
+ if (icon === false) {
147
+ return null
148
+ }
149
+ if (React.isValidElement(icon)) {
150
+ return React.cloneElement(icon as React.ReactElement, {
151
+ style: { fontSize: iconsize },
152
+ })
136
153
  }
137
- },
138
- [updateFormValidation, onClick, formname]
139
- )
140
-
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
- )
157
-
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 && (
154
+ return <StarIcon style={{ fontSize: iconsize }} />
155
+ }, [icon, iconsize])
156
+
157
+ const buttonStyle = useMemo(
158
+ () => ({
159
+ minWidth: text ? 'auto' : 'fit-content',
160
+ paddingLeft: text ? '8px' : '0',
161
+ paddingRight: text ? '8px' : '0',
162
+ justifyContent: fontlocation || 'center',
163
+ backgroundColor: backgroundcolor,
164
+ border: outlinecolor ? `1px solid ${outlinecolor}` : undefined,
165
+ color: iconcolor,
166
+ width: width,
167
+ opacity: !isFormFinished || isCheckingForm ? 0.5 : 1,
168
+ }),
169
+ [
170
+ text,
171
+ fontlocation,
172
+ backgroundcolor,
173
+ outlinecolor,
174
+ iconcolor,
175
+ width,
176
+ isFormFinished,
177
+ isCheckingForm,
178
+ ]
179
+ )
180
+
181
+ const buttonContent = useMemo(
182
+ () => (
183
+ <Box display="flex" alignItems="center">
184
+ {iconlocation === 'left' && renderIcon()}
185
+ {text && (
186
+ <Typography
187
+ fontvariant={fontvariant}
188
+ fontcolor={fontcolor}
189
+ text={text}
190
+ />
191
+ )}
192
+ {iconlocation === 'right' && renderIcon()}
193
+ </Box>
194
+ ),
195
+ [iconlocation, renderIcon, text, fontvariant, fontcolor]
196
+ )
197
+
198
+ const messageComponent = useMemo(
199
+ () =>
200
+ !isFormFinished || isCheckingForm ? (
166
201
  <Typography
167
- fontvariant={fontvariant}
168
- fontcolor={fontcolor}
169
- text={text}
202
+ fontvariant="merrihelperfooter"
203
+ fontcolor={red.main}
204
+ text="Fill in required fields"
205
+ marginTop={0.5}
206
+ marginBottom={0}
207
+ align="center"
208
+ width="100%"
170
209
  />
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
- )
196
-
197
- return (
198
- <Box
199
- display="flex"
200
- flexDirection="column"
201
- alignItems="center"
202
- width={width}
203
- >
204
- <Button
205
- disableElevation
206
- variant={variant}
207
- startIcon={null}
208
- endIcon={null}
209
- type={type}
210
- name={name}
211
- onClick={handleButtonClick}
212
- style={buttonStyle}
210
+ ) : null,
211
+ [isFormFinished, isCheckingForm]
212
+ )
213
+
214
+ console.log(
215
+ `CustomButton: Rendering. Is form finished: ${isFormFinished} Is checking form: ${isCheckingForm}`
216
+ )
217
+
218
+ return (
219
+ <Box
220
+ display="flex"
221
+ flexDirection="column"
222
+ alignItems="center"
223
+ width={width}
213
224
  >
214
- {buttonContent}
215
- </Button>
216
- {errorMessageComponent}
217
- </Box>
218
- )
219
- }
225
+ <Button
226
+ disableElevation
227
+ variant={variant}
228
+ startIcon={null}
229
+ endIcon={null}
230
+ type={type}
231
+ name={name}
232
+ onClick={handleButtonClick}
233
+ style={buttonStyle}
234
+ disabled={!isFormFinished || isCheckingForm}
235
+ >
236
+ {buttonContent}
237
+ </Button>
238
+ {messageComponent}
239
+ </Box>
240
+ )
241
+ },
242
+ (prevProps, nextProps) => {
243
+ const propsAreEqual =
244
+ prevProps.text === nextProps.text &&
245
+ prevProps.variant === nextProps.variant &&
246
+ prevProps.fontvariant === nextProps.fontvariant &&
247
+ prevProps.icon === nextProps.icon &&
248
+ prevProps.iconlocation === nextProps.iconlocation &&
249
+ prevProps.iconsize === nextProps.iconsize &&
250
+ prevProps.type === nextProps.type &&
251
+ prevProps.onClick === nextProps.onClick &&
252
+ prevProps.fontcolor === nextProps.fontcolor &&
253
+ prevProps.name === nextProps.name &&
254
+ prevProps.formname === nextProps.formname &&
255
+ prevProps.outlinecolor === nextProps.outlinecolor &&
256
+ prevProps.backgroundcolor === nextProps.backgroundcolor &&
257
+ prevProps.fontlocation === nextProps.fontlocation &&
258
+ prevProps.iconcolor === nextProps.iconcolor &&
259
+ prevProps.width === nextProps.width
260
+ console.log('CustomButton: Props changed:', !propsAreEqual)
261
+ return propsAreEqual
262
+ }
263
+ )
264
+
265
+ CustomButton.displayName = 'CustomButton'
220
266
 
221
- export default React.memo(CustomButton)
267
+ export default CustomButton
@@ -4,7 +4,7 @@ import { Input, Box } from '@mui/material'
4
4
  import { useCodeConfirmation } from './utils/useCodeConfirmation'
5
5
  import { columnconfig } from '../../components/Grid'
6
6
  import { red, green } from '../../styles/palette'
7
- import { set } from 'goobs-cache'
7
+ import { session } from 'goobs-cache'
8
8
 
9
9
  export interface ConfirmationCodeInputsProps {
10
10
  identifier?: string
@@ -30,6 +30,9 @@ const ConfirmationCodeInputs: React.FC<ConfirmationCodeInputsProps> = ({
30
30
  'aria-invalid': ariaInvalid,
31
31
  ...props
32
32
  }) => {
33
+ const verificationCodeAtom = session.atom<string>('')
34
+ const [, setVerificationCode] = session.useAtom(verificationCodeAtom)
35
+
33
36
  const { handleCodeChange, handleKeyDown, combinedCode } = useCodeConfirmation(
34
37
  {
35
38
  codeLength,
@@ -73,19 +76,14 @@ const ConfirmationCodeInputs: React.FC<ConfirmationCodeInputsProps> = ({
73
76
  }
74
77
 
75
78
  /**
76
- * useEffect hook is used to set the verification code into an atom using goobs-cache.
79
+ * useEffect hook is used to set the verification code into the session atom using goobs-cache.
77
80
  * It sets the code whenever the combinedCode changes and the code is valid.
78
81
  */
79
82
  React.useEffect(() => {
80
83
  if (isValid) {
81
- set(
82
- 'verificationCode',
83
- 'codeStore',
84
- { type: 'string', value: combinedCode },
85
- 'client'
86
- )
84
+ setVerificationCode(combinedCode)
87
85
  }
88
- }, [combinedCode, isValid])
86
+ }, [combinedCode, isValid, setVerificationCode])
89
87
 
90
88
  return (
91
89
  <Box