goobs-frontend 0.9.15 → 0.9.16

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "goobs-frontend",
3
- "version": "0.9.15",
3
+ "version": "0.9.16",
4
4
  "type": "module",
5
5
  "description": "A comprehensive React-based libary that extends the functionality of Material-UI",
6
6
  "license": "MIT",
@@ -4,6 +4,11 @@ import { Box, Paper } from '@mui/material'
4
4
  import { SxProps } from '@mui/system'
5
5
  import { authenticator } from 'otplib'
6
6
  import Typography from '../Typography'
7
+ import CustomButton, { CustomButtonProps } from '../Button'
8
+ import { CheckCircleOutline } from '@mui/icons-material'
9
+ import ConfirmationCodeInputs, {
10
+ ConfirmationCodeInputsProps,
11
+ } from '../ConfirmationCodeInput'
7
12
 
8
13
  /**
9
14
  * Props for the QRCodeComponent
@@ -14,6 +19,18 @@ import Typography from '../Typography'
14
19
  * @property {string} [title] - An optional title to display above the QR code
15
20
  * @property {SxProps} [sx] - Custom styles to apply to the component
16
21
  * @property {(secret: string) => void} [onSecretGenerated] - Callback function to receive the generated secret
22
+ * @property {boolean} [showVerifyButton] - Whether to show the verify button
23
+ * @property {() => void | Promise<void>} [onVerify] - Callback function for when the Verify button is clicked
24
+ * @property {() => void | Promise<void>} [onDisableVerification] - Required callback function for when verification is disabled
25
+ * @property {Partial<CustomButtonProps>} [verifyButtonProps] - Custom props for the Verify button
26
+ * @property {Partial<CustomButtonProps>} [disableVerificationButtonProps] - Custom props for the Disable Verification button
27
+ * @property {boolean} [showSuccessState] - Whether to show the success state UI
28
+ * @property {string} [successMessage] - Custom success message to display
29
+ * @property {boolean} [showConfirmationInput] - Whether to show the confirmation code input
30
+ * @property {string} [confirmationCode] - The current confirmation code value
31
+ * @property {(value: string) => void} [onConfirmationCodeChange] - Callback for when confirmation code changes
32
+ * @property {ConfirmationCodeInputsProps} [confirmationCodeProps] - Custom props for the confirmation code input
33
+ * @property {boolean} [showDisableConfirmation] - Whether to show the disable confirmation state
17
34
  */
18
35
  export interface QRCodeProps {
19
36
  username: string
@@ -22,6 +39,18 @@ export interface QRCodeProps {
22
39
  title?: string
23
40
  sx?: SxProps
24
41
  onSecretGenerated?: (secret: string) => void
42
+ showVerifyButton?: boolean
43
+ onVerify?: () => void | Promise<void>
44
+ onDisableVerification?: () => void | Promise<void>
45
+ verifyButtonProps?: Partial<CustomButtonProps>
46
+ disableVerificationButtonProps?: Partial<CustomButtonProps>
47
+ showSuccessState?: boolean
48
+ successMessage?: string
49
+ showConfirmationInput?: boolean
50
+ confirmationCode?: string
51
+ onConfirmationCodeChange?: (value: string) => void
52
+ confirmationCodeProps?: Partial<ConfirmationCodeInputsProps>
53
+ showDisableConfirmation?: boolean
25
54
  }
26
55
 
27
56
  /**
@@ -37,6 +66,18 @@ const QRCodeComponent: React.FC<QRCodeProps> = React.memo(
37
66
  title,
38
67
  sx,
39
68
  onSecretGenerated,
69
+ showVerifyButton = false,
70
+ onVerify,
71
+ onDisableVerification,
72
+ verifyButtonProps = {},
73
+ disableVerificationButtonProps = {},
74
+ showSuccessState = false,
75
+ successMessage = 'Verification Successful',
76
+ showConfirmationInput = false,
77
+ confirmationCode = '',
78
+ onConfirmationCodeChange,
79
+ confirmationCodeProps = {},
80
+ showDisableConfirmation = false,
40
81
  }) => {
41
82
  // Generate the secret and OTP auth URL
42
83
  const { secret, otpAuth } = useMemo(() => {
@@ -75,6 +116,128 @@ const QRCodeComponent: React.FC<QRCodeProps> = React.memo(
75
116
  )
76
117
  }
77
118
 
119
+ // If showing success state, render the success UI
120
+ if (showSuccessState) {
121
+ return (
122
+ <Box
123
+ display="flex"
124
+ flexDirection="column"
125
+ alignItems="center"
126
+ gap={2}
127
+ padding={3}
128
+ width="100%"
129
+ >
130
+ <CheckCircleOutline sx={{ fontSize: 60, color: 'green' }} />
131
+ <Typography
132
+ text={successMessage}
133
+ fontvariant="merrih5"
134
+ align="center"
135
+ />
136
+ <Box sx={{ display: 'flex', gap: 2, width: '100%' }}>
137
+ <CustomButton
138
+ text="Disable Verification"
139
+ fontcolor="white"
140
+ backgroundcolor="black"
141
+ width="100%"
142
+ height="40px"
143
+ variant="outlined"
144
+ {...disableVerificationButtonProps}
145
+ onClick={() => {
146
+ if (onDisableVerification) void onDisableVerification()
147
+ }}
148
+ />
149
+ </Box>
150
+ </Box>
151
+ )
152
+ }
153
+
154
+ // If showing disable confirmation state, render QR with confirmation input
155
+ if (showDisableConfirmation) {
156
+ return (
157
+ <Paper
158
+ elevation={3}
159
+ sx={{
160
+ p: 3,
161
+ display: 'inline-block',
162
+ maxWidth: '100%',
163
+ boxSizing: 'border-box',
164
+ ...sx,
165
+ }}
166
+ >
167
+ {title && (
168
+ <Typography
169
+ text={title}
170
+ fontvariant="merrih5"
171
+ align="center"
172
+ gutterBottom
173
+ />
174
+ )}
175
+ <Box
176
+ sx={{
177
+ display: 'flex',
178
+ justifyContent: 'center',
179
+ alignItems: 'center',
180
+ width: responsiveSize,
181
+ height: responsiveSize,
182
+ margin: 'auto',
183
+ }}
184
+ >
185
+ <QRCode
186
+ value={otpAuth}
187
+ size={responsiveSize}
188
+ style={{ height: 'auto', maxWidth: '100%', width: '100%' }}
189
+ aria-label={`QR Code for ${title || 'MFA Setup'}`}
190
+ data-testid="mfa-qrcode"
191
+ />
192
+ </Box>
193
+ <Box sx={{ mt: 2, textAlign: 'center' }}>
194
+ <Typography
195
+ text={`${appName}: ${username}`}
196
+ fontvariant="merriparagraph"
197
+ align="center"
198
+ />
199
+ </Box>
200
+
201
+ <Box
202
+ sx={{
203
+ mt: 3,
204
+ display: 'flex',
205
+ flexDirection: 'column',
206
+ alignItems: 'center',
207
+ gap: 2,
208
+ }}
209
+ >
210
+ <ConfirmationCodeInputs
211
+ isValid={false}
212
+ codeLength={6}
213
+ value={confirmationCode}
214
+ onChange={onConfirmationCodeChange}
215
+ showActionButtons={false}
216
+ onDisableVerification={() => {}}
217
+ {...confirmationCodeProps}
218
+ />
219
+
220
+ <CustomButton
221
+ text="Verify & Disable"
222
+ fontcolor="white"
223
+ backgroundcolor="black"
224
+ width="100%"
225
+ height="40px"
226
+ {...verifyButtonProps}
227
+ onClick={() => {
228
+ if (onVerify) void onVerify()
229
+ }}
230
+ disableButton={
231
+ verifyButtonProps?.disableButton ||
232
+ (confirmationCode.length < 6 ? 'true' : 'false')
233
+ }
234
+ />
235
+ </Box>
236
+ </Paper>
237
+ )
238
+ }
239
+
240
+ // Default QR code view with optional confirmation input and buttons
78
241
  return (
79
242
  <Paper
80
243
  elevation={3}
@@ -119,6 +282,44 @@ const QRCodeComponent: React.FC<QRCodeProps> = React.memo(
119
282
  align="center"
120
283
  />
121
284
  </Box>
285
+
286
+ {showConfirmationInput && (
287
+ <Box sx={{ mt: 3, display: 'flex', justifyContent: 'center' }}>
288
+ <ConfirmationCodeInputs
289
+ isValid={false}
290
+ codeLength={6}
291
+ value={confirmationCode}
292
+ onChange={onConfirmationCodeChange}
293
+ showActionButtons={false}
294
+ onDisableVerification={() => {}}
295
+ {...confirmationCodeProps}
296
+ />
297
+ </Box>
298
+ )}
299
+
300
+ {showVerifyButton && (
301
+ <Box
302
+ sx={{ mt: 3, display: 'flex', justifyContent: 'center', gap: 2 }}
303
+ >
304
+ <CustomButton
305
+ text="Verify Code"
306
+ fontcolor="white"
307
+ backgroundcolor="black"
308
+ width="100%"
309
+ height="40px"
310
+ {...verifyButtonProps}
311
+ onClick={() => {
312
+ if (onVerify) void onVerify()
313
+ }}
314
+ disableButton={
315
+ verifyButtonProps?.disableButton ||
316
+ (showConfirmationInput && confirmationCode.length < 6
317
+ ? 'true'
318
+ : 'false')
319
+ }
320
+ />
321
+ </Box>
322
+ )}
122
323
  </Paper>
123
324
  )
124
325
  }
@@ -148,8 +349,8 @@ export function verifyMFAToken(token: string, secret: string): boolean {
148
349
  // Configure authenticator options to match Microsoft Authenticator
149
350
  authenticator.options = {
150
351
  window: 1, // Allow codes from 1 step before and after
151
- digits: 6, // Microsoft Authenticator uses 6-digit codes
152
352
  step: 30, // 30-second interval for code generation
353
+ digits: 6, // Microsoft Authenticator uses 6-digit codes
153
354
  }
154
355
 
155
356
  return authenticator.verify({ token, secret })
@@ -229,9 +229,6 @@ const Typography = ({
229
229
  if (typeof actualVariant === 'string' && actualVariant.length > 0) {
230
230
  // First, try to get the variant from the theme
231
231
  try {
232
- // Log the actual variant being used
233
- console.log('Using variant:', actualVariant)
234
-
235
232
  // Check if we're using a custom font variant (e.g., 'merrih2')
236
233
  if (/^(arapey|inter|merri)/.test(actualVariant)) {
237
234
  // For custom variants, we need to check if they exist in the theme
@@ -246,7 +243,6 @@ const Typography = ({
246
243
  const themeVariant = themeTypography[
247
244
  actualVariant
248
245
  ] as TypographyVariantStyle
249
- console.log('Found theme variant:', themeVariant)
250
246
 
251
247
  if (themeVariant) {
252
248
  variantStyle = {
@@ -259,8 +255,6 @@ const Typography = ({
259
255
  }
260
256
  } else {
261
257
  // Custom variant not in theme, fallback to hardcoded styles
262
- console.log('Custom variant not found in theme, using fallback')
263
-
264
258
  const fontFamily = actualVariant.startsWith('arapey')
265
259
  ? 'arapey'
266
260
  : actualVariant.startsWith('inter')