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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "goobs-frontend",
3
- "version": "0.7.65",
3
+ "version": "0.7.67",
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",
@@ -28,7 +28,7 @@
28
28
  "@mui/icons-material": "^5.16.6",
29
29
  "@mui/material": "^5.16.6",
30
30
  "@types/lodash": "^4.17.7",
31
- "goobs-cache": "^1.6.4",
31
+ "goobs-cache": "^1.7.0",
32
32
  "highlight.js": "^11.10.0",
33
33
  "lodash": "^4.17.21",
34
34
  "next": "14.2.5"
package/src/app/_app.tsx CHANGED
@@ -1,8 +1,8 @@
1
- import React from 'react'
2
- import type { AppProps } from 'next/app'
3
-
4
- const MyApp = ({ Component, pageProps }: AppProps) => {
5
- return <Component {...pageProps} />
6
- }
7
-
8
- export default MyApp
1
+ import React from 'react'
2
+ import type { AppProps } from 'next/app'
3
+
4
+ const MyApp = ({ Component, pageProps }: AppProps) => {
5
+ return <Component {...pageProps} />
6
+ }
7
+
8
+ export default MyApp
@@ -16,79 +16,77 @@ const useHelperFooter = (initialFormname?: string) => {
16
16
  initialFormname
17
17
  )
18
18
 
19
- const helperFooterAtom = session.atom<Record<
20
- string,
21
- HelperFooterMessage
22
- > | null>(null)
23
- const currentErrorIndexAtom = session.atom<number>(0)
19
+ const helperFooterAtom = useMemo(
20
+ () => session.atom<Record<string, HelperFooterMessage> | null>(null),
21
+ []
22
+ )
23
+ const currentErrorIndexAtom = useMemo(() => session.atom<number>(0), [])
24
+
25
+ const [helperFooters, setHelperFooters] = session.useAtom(helperFooterAtom)
26
+ const [currentErrorIndex, setCurrentErrorIndex] = session.useAtom(
27
+ currentErrorIndexAtom
28
+ )
29
+ const [helperFooterResult] = session.useAtom(
30
+ useMemo(
31
+ () => session.atom(`helperfooter:${initialFormname}`),
32
+ [initialFormname]
33
+ )
34
+ )
24
35
 
25
- const fetchHelperFooters = useCallback(async (): Promise<Record<
36
+ const fetchHelperFooters = useCallback((): Record<
26
37
  string,
27
38
  HelperFooterMessage
28
- > | null> => {
39
+ > | null => {
29
40
  console.log('useHelperFooter: fetchHelperFooters called')
30
41
  if (!initialFormname) {
31
42
  console.log('useHelperFooter: No formname provided, returning null')
32
43
  return null
33
44
  }
34
45
 
35
- const [helperFooters, setHelperFooters] = session.useAtom(helperFooterAtom)
36
-
37
- if (helperFooters === null) {
38
- const [helperFooterResult] = session.useAtom(
39
- session.atom(`helperfooter:${initialFormname}`)
40
- )
41
- console.log('useHelperFooter: helperFooterResult:', helperFooterResult)
42
-
43
- if (
44
- helperFooterResult &&
45
- typeof helperFooterResult === 'object' &&
46
- helperFooterResult !== null
47
- ) {
48
- const fetchedHelperFooters: Record<string, HelperFooterMessage> = {}
49
-
50
- for (const [key, value] of Object.entries(helperFooterResult)) {
51
- if (
52
- typeof value === 'object' &&
53
- value !== null &&
54
- 'status' in value &&
55
- 'statusMessage' in value &&
56
- 'spreadMessage' in value &&
57
- 'spreadMessagePriority' in value &&
58
- 'required' in value &&
59
- 'hasInput' in value
60
- ) {
61
- fetchedHelperFooters[key] = {
62
- status: value.status as 'error' | 'success' | 'emptyAndRequired',
63
- statusMessage: String(value.statusMessage),
64
- spreadMessage: String(value.spreadMessage),
65
- spreadMessagePriority: Number(value.spreadMessagePriority),
66
- required: Boolean(value.required),
67
- hasInput: Boolean(value.hasInput),
68
- }
46
+ if (
47
+ helperFooters === null &&
48
+ helperFooterResult &&
49
+ typeof helperFooterResult === 'object' &&
50
+ helperFooterResult !== null
51
+ ) {
52
+ const fetchedHelperFooters: Record<string, HelperFooterMessage> = {}
53
+
54
+ for (const [key, value] of Object.entries(helperFooterResult)) {
55
+ if (
56
+ typeof value === 'object' &&
57
+ value !== null &&
58
+ 'status' in value &&
59
+ 'statusMessage' in value &&
60
+ 'spreadMessage' in value &&
61
+ 'spreadMessagePriority' in value &&
62
+ 'required' in value &&
63
+ 'hasInput' in value
64
+ ) {
65
+ fetchedHelperFooters[key] = {
66
+ status: value.status as 'error' | 'success' | 'emptyAndRequired',
67
+ statusMessage: String(value.statusMessage),
68
+ spreadMessage: String(value.spreadMessage),
69
+ spreadMessagePriority: Number(value.spreadMessagePriority),
70
+ required: Boolean(value.required),
71
+ hasInput: Boolean(value.hasInput),
69
72
  }
70
73
  }
71
-
72
- console.log(
73
- 'useHelperFooter: Fetched helper footers:',
74
- fetchedHelperFooters
75
- )
76
- setHelperFooters(fetchedHelperFooters)
77
- return fetchedHelperFooters
78
74
  }
79
75
 
80
76
  console.log(
81
- 'useHelperFooter: Invalid helper footer result, returning null'
77
+ 'useHelperFooter: Fetched helper footers:',
78
+ fetchedHelperFooters
82
79
  )
83
- return null
80
+ setHelperFooters(fetchedHelperFooters)
81
+ return fetchedHelperFooters
84
82
  }
85
83
 
86
84
  return helperFooters
87
- }, [initialFormname, helperFooterAtom])
85
+ }, [helperFooters, helperFooterResult, initialFormname, setHelperFooters])
88
86
 
89
- const updateFormValidation = useCallback(async (): Promise<boolean> => {
87
+ const updateFormValidation = useCallback((): boolean => {
90
88
  console.log('useHelperFooter: updateFormValidation called')
91
- const fetchedHelperFooters = await fetchHelperFooters()
89
+ const fetchedHelperFooters = fetchHelperFooters()
92
90
 
93
91
  if (fetchedHelperFooters) {
94
92
  const errorFooters = Object.values(fetchedHelperFooters).filter(
@@ -100,7 +98,6 @@ const useHelperFooter = (initialFormname?: string) => {
100
98
  console.log('useHelperFooter: Error footers:', errorFooters)
101
99
 
102
100
  if (errorFooters.length === 0) {
103
- const [, setCurrentErrorIndex] = session.useAtom(currentErrorIndexAtom)
104
101
  setCurrentErrorIndex(0)
105
102
  console.log('useHelperFooter: No errors found, returning true')
106
103
  return true
@@ -110,9 +107,6 @@ const useHelperFooter = (initialFormname?: string) => {
110
107
  (a, b) => a.spreadMessagePriority - b.spreadMessagePriority
111
108
  )
112
109
 
113
- const [currentErrorIndex, setCurrentErrorIndex] = session.useAtom(
114
- currentErrorIndexAtom
115
- )
116
110
  if (currentErrorIndex >= errorFooters.length) {
117
111
  setCurrentErrorIndex(0)
118
112
  }
@@ -123,11 +117,11 @@ const useHelperFooter = (initialFormname?: string) => {
123
117
 
124
118
  console.log('useHelperFooter: No helper footers, returning true')
125
119
  return true
126
- }, [fetchHelperFooters, currentErrorIndexAtom])
120
+ }, [fetchHelperFooters, currentErrorIndex, setCurrentErrorIndex])
127
121
 
128
- const checkFormStatus = useCallback(async () => {
122
+ const checkFormStatus = useCallback(() => {
129
123
  console.log('useHelperFooter: checkFormStatus called')
130
- const fetchedHelperFooters = await fetchHelperFooters()
124
+ const fetchedHelperFooters = fetchHelperFooters()
131
125
  const status = fetchedHelperFooters
132
126
  ? Object.values(fetchedHelperFooters).every(
133
127
  value => !value.required || (value.required && value.hasInput)
@@ -137,9 +131,9 @@ const useHelperFooter = (initialFormname?: string) => {
137
131
  return status
138
132
  }, [fetchHelperFooters])
139
133
 
140
- const getEmptyRequiredFields = useCallback(async () => {
134
+ const getEmptyRequiredFields = useCallback(() => {
141
135
  console.log('useHelperFooter: getEmptyRequiredFields called')
142
- const fetchedHelperFooters = await fetchHelperFooters()
136
+ const fetchedHelperFooters = fetchHelperFooters()
143
137
  if (!fetchedHelperFooters) return []
144
138
  const emptyFields = Object.entries(fetchedHelperFooters)
145
139
  .filter(([, value]) => value.required && !value.hasInput)
@@ -148,9 +142,9 @@ const useHelperFooter = (initialFormname?: string) => {
148
142
  return emptyFields
149
143
  }, [fetchHelperFooters])
150
144
 
151
- const getCurrentErrorMessage = useCallback(async () => {
145
+ const getCurrentErrorMessage = useCallback(() => {
152
146
  console.log('useHelperFooter: getCurrentErrorMessage called')
153
- const fetchedHelperFooters = await fetchHelperFooters()
147
+ const fetchedHelperFooters = fetchHelperFooters()
154
148
  if (!fetchedHelperFooters) return undefined
155
149
  const errorFooters = Object.values(fetchedHelperFooters).filter(
156
150
  footer =>
@@ -158,14 +152,13 @@ const useHelperFooter = (initialFormname?: string) => {
158
152
  footer.required
159
153
  )
160
154
  if (errorFooters.length === 0) return undefined
161
- const [currentErrorIndex] = session.useAtom(currentErrorIndexAtom)
162
155
  const message = errorFooters[currentErrorIndex]?.spreadMessage
163
156
  console.log('useHelperFooter: Current error message:', message)
164
157
  return message
165
- }, [fetchHelperFooters, currentErrorIndexAtom])
158
+ }, [fetchHelperFooters, currentErrorIndex])
166
159
 
167
- const isFormValid = useCallback(async () => {
168
- const fetchedHelperFooters = await fetchHelperFooters()
160
+ const isFormValid = useCallback(() => {
161
+ const fetchedHelperFooters = fetchHelperFooters()
169
162
  if (!fetchedHelperFooters) return true
170
163
  const valid = Object.values(fetchedHelperFooters).every(
171
164
  footer =>
@@ -175,9 +168,9 @@ const useHelperFooter = (initialFormname?: string) => {
175
168
  return valid
176
169
  }, [fetchHelperFooters])
177
170
 
178
- const nextError = useCallback(async () => {
171
+ const nextError = useCallback(() => {
179
172
  console.log('useHelperFooter: nextError called')
180
- const fetchedHelperFooters = await fetchHelperFooters()
173
+ const fetchedHelperFooters = fetchHelperFooters()
181
174
  if (!fetchedHelperFooters) return
182
175
  const errorFooters = Object.values(fetchedHelperFooters).filter(
183
176
  footer =>
@@ -185,16 +178,13 @@ const useHelperFooter = (initialFormname?: string) => {
185
178
  footer.required
186
179
  )
187
180
  if (errorFooters.length > 0) {
188
- const [currentErrorIndex, setCurrentErrorIndex] = session.useAtom(
189
- currentErrorIndexAtom
190
- )
191
- setCurrentErrorIndex((currentErrorIndex + 1) % errorFooters.length)
181
+ setCurrentErrorIndex(prevIndex => (prevIndex + 1) % errorFooters.length)
192
182
  console.log(
193
183
  'useHelperFooter: New error index:',
194
184
  (currentErrorIndex + 1) % errorFooters.length
195
185
  )
196
186
  }
197
- }, [fetchHelperFooters, currentErrorIndexAtom])
187
+ }, [fetchHelperFooters, currentErrorIndex, setCurrentErrorIndex])
198
188
 
199
189
  const result = useMemo(
200
190
  () => ({
@@ -1,4 +1,4 @@
1
- import React, { useMemo, useCallback, useEffect, useState } from 'react'
1
+ import React, { useMemo, useCallback, 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'
@@ -74,9 +74,6 @@ const CustomButton: React.FC<CustomButtonProps> = React.memo(
74
74
  width,
75
75
  } = props
76
76
 
77
- const [isFormFinished, setIsFormFinished] = useState<boolean>(false)
78
- const [isCheckingForm, setIsCheckingForm] = useState<boolean>(true)
79
-
80
77
  const {
81
78
  updateFormValidation,
82
79
  checkFormStatus,
@@ -84,6 +81,9 @@ const CustomButton: React.FC<CustomButtonProps> = React.memo(
84
81
  fetchHelperFooters,
85
82
  } = useHelperFooter(formname)
86
83
 
84
+ const [isFormFinished, setIsFormFinished] = useState(false)
85
+ const [isCheckingForm, setIsCheckingForm] = useState(true)
86
+
87
87
  const checkFormState = useCallback(async (): Promise<void> => {
88
88
  console.log('CustomButton: Checking form state...')
89
89
  setIsCheckingForm(true)
@@ -110,11 +110,6 @@ const CustomButton: React.FC<CustomButtonProps> = React.memo(
110
110
  )
111
111
  }, [checkFormStatus, getEmptyRequiredFields, fetchHelperFooters])
112
112
 
113
- useEffect(() => {
114
- console.log('CustomButton: Performing initial check')
115
- checkFormState()
116
- }, [checkFormState])
117
-
118
113
  const handleButtonClick = useCallback(
119
114
  async (event: React.MouseEvent<HTMLButtonElement>): Promise<void> => {
120
115
  event.preventDefault()
@@ -1,12 +1,6 @@
1
1
  'use client'
2
2
 
3
- import React, {
4
- forwardRef,
5
- useImperativeHandle,
6
- useRef,
7
- useMemo,
8
- useCallback,
9
- } from 'react'
3
+ import React, { useMemo } from 'react'
10
4
  import { Close } from '@mui/icons-material'
11
5
  import { Dialog, IconButton, Box, DialogProps } from '@mui/material'
12
6
  import ContentSection, { ContentSectionProps } from '../../Content'
@@ -24,8 +18,6 @@ export interface PopupFormProps {
24
18
  description?: string
25
19
  /** The grid configuration for the form content */
26
20
  grids?: ContentSectionProps['grids']
27
- /** Callback function to handle form submission */
28
- onSubmit?: (event: React.FormEvent<HTMLFormElement>) => void
29
21
  /** Custom content to render inside the form */
30
22
  content?: React.ReactNode
31
23
  /** The type of popup to render ('dialog' or 'modal') */
@@ -52,160 +44,131 @@ export interface PopupFormProps {
52
44
  * popupType="dialog"
53
45
  * open={isOpen}
54
46
  * onClose={handleClose}
55
- * onSubmit={handleSubmit}
56
47
  * content={<LoginForm />}
57
48
  * width={400}
58
49
  * />
59
50
  */
60
- const PopupForm = forwardRef<HTMLFormElement, PopupFormProps>(
61
- (
62
- {
63
- title,
64
- description,
65
- grids,
66
- onSubmit,
67
- content,
68
- popupType,
69
- open,
70
- onClose,
71
- width = 450,
72
- },
73
- ref
74
- ) => {
75
- const internalFormRef = useRef<HTMLFormElement>(null)
76
-
77
- // Expose the internal form ref to the parent component
78
- useImperativeHandle(ref, () => internalFormRef.current as HTMLFormElement)
79
-
80
- /**
81
- * Memoized header grid configuration
82
- */
83
- const headerGrid: ContentSectionProps['grids'][0] = useMemo(
84
- () => ({
85
- grid: {
86
- gridconfig: {
51
+ const PopupForm: React.FC<PopupFormProps> = ({
52
+ title,
53
+ description,
54
+ grids,
55
+ content,
56
+ popupType,
57
+ open,
58
+ onClose,
59
+ width = 450,
60
+ }) => {
61
+ /**
62
+ * Memoized header grid configuration
63
+ */
64
+ const headerGrid: ContentSectionProps['grids'][0] = useMemo(
65
+ () => ({
66
+ grid: {
67
+ gridconfig: {
68
+ gridname: 'formHeader',
69
+ marginbottom: 1,
70
+ gridwidth: '100%',
71
+ },
72
+ },
73
+ typography: [
74
+ {
75
+ text: title,
76
+ fontvariant: 'merrih5',
77
+ fontcolor: 'black',
78
+ columnconfig: {
79
+ row: 1,
80
+ column: 1,
87
81
  gridname: 'formHeader',
88
- marginbottom: 1,
89
- gridwidth: '100%',
82
+ columnwidth: '100%',
83
+ alignment: 'left',
84
+ marginbottom: 1.5,
90
85
  },
91
86
  },
92
- typography: [
93
- {
94
- text: title,
95
- fontvariant: 'merrih5',
96
- fontcolor: 'black',
97
- columnconfig: {
98
- row: 1,
99
- column: 1,
100
- gridname: 'formHeader',
101
- columnwidth: '100%',
102
- alignment: 'left',
103
- marginbottom: 1.5,
104
- },
105
- },
106
- {
107
- text: description,
108
- fontvariant: 'merriparagraph',
109
- fontcolor: 'black',
110
- columnconfig: {
111
- row: 2,
112
- column: 1,
113
- alignment: 'left',
114
- gridname: 'formHeader',
115
- columnwidth: '100%',
116
- },
87
+ {
88
+ text: description,
89
+ fontvariant: 'merriparagraph',
90
+ fontcolor: 'black',
91
+ columnconfig: {
92
+ row: 2,
93
+ column: 1,
94
+ alignment: 'left',
95
+ gridname: 'formHeader',
96
+ columnwidth: '100%',
117
97
  },
118
- ] as ExtendedTypographyProps[],
119
- }),
120
- [title, description]
121
- )
122
-
123
- /**
124
- * Handle form submission
125
- * @param {React.FormEvent<HTMLFormElement>} event - The form submission event
126
- */
127
- const handleSubmit = useCallback(
128
- (event: React.FormEvent<HTMLFormElement>) => {
129
- event.preventDefault()
130
- if (onSubmit) {
131
- onSubmit(event)
132
- }
133
- },
134
- [onSubmit]
135
- )
98
+ },
99
+ ] as ExtendedTypographyProps[],
100
+ }),
101
+ [title, description]
102
+ )
136
103
 
137
- /**
138
- * Memoized header render function
139
- */
140
- const renderHeader = useMemo(
141
- () => <ContentSection grids={[headerGrid]} />,
142
- [headerGrid]
143
- )
104
+ /**
105
+ * Memoized header render function
106
+ */
107
+ const renderHeader = useMemo(
108
+ () => <ContentSection grids={[headerGrid]} />,
109
+ [headerGrid]
110
+ )
144
111
 
145
- /**
146
- * Memoized content render function
147
- */
148
- const renderContent = useMemo(
149
- () => (
150
- <Box
151
- // @ts-ignore
152
- sx={formContainerStyle}
153
- >
154
- <Box mb={0}>{renderHeader}</Box>
155
- <form onSubmit={handleSubmit} ref={internalFormRef}>
156
- {React.isValidElement(content)
157
- ? React.cloneElement(content as React.ReactElement, {
158
- onSubmit: handleSubmit,
159
- })
160
- : content || (grids && <ContentSection grids={grids} />)}
161
- </form>
162
- </Box>
163
- ),
164
- [renderHeader, handleSubmit, content, grids]
165
- )
112
+ /**
113
+ * Memoized content render function
114
+ */
115
+ const renderContent = useMemo(
116
+ () => (
117
+ <Box
118
+ // @ts-ignore
119
+ sx={formContainerStyle}
120
+ >
121
+ <Box mb={0}>{renderHeader}</Box>
122
+ {React.isValidElement(content)
123
+ ? React.cloneElement(content as React.ReactElement, {
124
+ onClose: onClose,
125
+ open: open,
126
+ })
127
+ : content || (grids && <ContentSection grids={grids} />)}
128
+ </Box>
129
+ ),
130
+ [renderHeader, content, grids, onClose, open]
131
+ )
166
132
 
167
- const dialogProps: DialogProps = {
168
- open: popupType === 'modal' ? true : open || false,
169
- onClose: popupType === 'modal' ? undefined : onClose,
170
- fullWidth: true,
171
- maxWidth: false,
172
- PaperProps: {
173
- style: {
174
- width: `${width}px`,
175
- },
133
+ const dialogProps: DialogProps = {
134
+ open: popupType === 'modal' ? true : open || false,
135
+ onClose: popupType === 'modal' ? undefined : onClose,
136
+ fullWidth: true,
137
+ maxWidth: false,
138
+ PaperProps: {
139
+ style: {
140
+ width: `${width}px`,
176
141
  },
177
- }
178
-
179
- if (popupType === 'modal') {
180
- return (
181
- <Dialog {...dialogProps} disableEscapeKeyDown hideBackdrop>
182
- {renderContent}
183
- </Dialog>
184
- )
185
- }
142
+ },
143
+ }
186
144
 
145
+ if (popupType === 'modal') {
187
146
  return (
188
- <Dialog {...dialogProps}>
189
- {onClose && (
190
- <IconButton
191
- size="small"
192
- onClick={onClose}
193
- sx={{
194
- position: 'absolute',
195
- right: 8,
196
- top: 8,
197
- color: theme => theme.palette.grey[500],
198
- }}
199
- >
200
- <Close />
201
- </IconButton>
202
- )}
147
+ <Dialog {...dialogProps} disableEscapeKeyDown hideBackdrop>
203
148
  {renderContent}
204
149
  </Dialog>
205
150
  )
206
151
  }
207
- )
208
152
 
209
- PopupForm.displayName = 'PopupForm'
153
+ return (
154
+ <Dialog {...dialogProps}>
155
+ {onClose && (
156
+ <IconButton
157
+ size="small"
158
+ onClick={onClose}
159
+ sx={{
160
+ position: 'absolute',
161
+ right: 8,
162
+ top: 8,
163
+ color: theme => theme.palette.grey[500],
164
+ }}
165
+ >
166
+ <Close />
167
+ </IconButton>
168
+ )}
169
+ {renderContent}
170
+ </Dialog>
171
+ )
172
+ }
210
173
 
211
174
  export default PopupForm