goobs-frontend 0.7.64 → 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 +174 -201
- package/src/components/Button/index.tsx +208 -162
- package/src/components/ConfirmationCodeInput/index.tsx +7 -9
- package/src/components/Nav/HorizontalVariant/index.tsx +13 -39
- package/src/components/StyledComponent/hooks/useInputHelperFooter.tsx +567 -0
- package/src/components/StyledComponent/hooks/useRequiredFieldsValidator.tsx +137 -0
- package/src/components/StyledComponent/index.tsx +26 -31
- package/src/components/TransferList/index.tsx +12 -4
- package/src/components/StyledComponent/helperfooter/useHelperFooter.tsx +0 -638
|
@@ -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
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
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
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
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=
|
|
168
|
-
fontcolor={
|
|
169
|
-
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
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
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
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
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
|
|
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 {
|
|
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
|
|
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
|
-
|
|
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
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client'
|
|
2
|
-
import React, {
|
|
2
|
+
import React, { useEffect } from 'react'
|
|
3
3
|
import { Box, Tabs, Tab } from '@mui/material'
|
|
4
|
-
import {
|
|
4
|
+
import { session } from 'goobs-cache'
|
|
5
5
|
import { NavProps, SubNav, View } from '../index'
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -47,58 +47,32 @@ function HorizontalVariant({
|
|
|
47
47
|
/**
|
|
48
48
|
* State to keep track of active tab values for different navigation components.
|
|
49
49
|
*/
|
|
50
|
-
const
|
|
50
|
+
const activeTabValuesAtom = session.atom<
|
|
51
51
|
Record<string, ActiveTabValue | null>
|
|
52
52
|
>({})
|
|
53
|
+
const [activeTabValues, setActiveTabValues] =
|
|
54
|
+
session.useAtom(activeTabValuesAtom)
|
|
53
55
|
|
|
54
56
|
/**
|
|
55
|
-
* Effect hook to
|
|
57
|
+
* Effect hook to initialize the active tab values when the component mounts.
|
|
56
58
|
*/
|
|
57
59
|
useEffect(() => {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
*/
|
|
61
|
-
const fetchActiveTabValues = async () => {
|
|
62
|
-
const result = await get('activeTabValues', 'tabStore', 'client')
|
|
63
|
-
if (
|
|
64
|
-
result &&
|
|
65
|
-
typeof result === 'object' &&
|
|
66
|
-
'type' in result &&
|
|
67
|
-
result.type === 'json' &&
|
|
68
|
-
'value' in result &&
|
|
69
|
-
typeof result.value === 'object'
|
|
70
|
-
) {
|
|
71
|
-
setActiveTabValues(
|
|
72
|
-
result.value as Record<string, ActiveTabValue | null>
|
|
73
|
-
)
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
fetchActiveTabValues()
|
|
60
|
+
// The initialization is now handled by the session atom
|
|
61
|
+
// No need to fetch from cache as it's automatically handled by goobs-cache
|
|
78
62
|
}, [])
|
|
79
63
|
|
|
80
64
|
/**
|
|
81
65
|
* Handles tab change events.
|
|
82
|
-
* Updates the active tab values in the state
|
|
66
|
+
* Updates the active tab values in the state.
|
|
83
67
|
*
|
|
84
68
|
* @param {React.SyntheticEvent} event - The event object.
|
|
85
69
|
* @param {string} newValue - The new value of the selected tab.
|
|
86
70
|
*/
|
|
87
|
-
const handleTabChange =
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
) => {
|
|
91
|
-
const updatedActiveTabValues = {
|
|
92
|
-
...activeTabValues,
|
|
71
|
+
const handleTabChange = (event: React.SyntheticEvent, newValue: string) => {
|
|
72
|
+
setActiveTabValues(prev => ({
|
|
73
|
+
...prev,
|
|
93
74
|
[navname ?? '']: { tabId: newValue },
|
|
94
|
-
}
|
|
95
|
-
setActiveTabValues(updatedActiveTabValues)
|
|
96
|
-
await set(
|
|
97
|
-
'activeTabValues',
|
|
98
|
-
'tabStore',
|
|
99
|
-
{ type: 'json', value: updatedActiveTabValues } as JSONValue,
|
|
100
|
-
'client'
|
|
101
|
-
)
|
|
75
|
+
}))
|
|
102
76
|
}
|
|
103
77
|
|
|
104
78
|
/**
|