goobs-frontend 0.8.5 → 0.8.7

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,7 @@
1
1
  {
2
2
  "name": "goobs-frontend",
3
- "version": "0.8.5",
3
+ "version": "0.8.7",
4
+ "type": "module",
4
5
  "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
6
  "license": "MIT",
6
7
  "main": "./src/index.ts",
@@ -18,35 +19,35 @@
18
19
  "lint": "next lint"
19
20
  },
20
21
  "dependencies": {
21
- "@emotion/cache": "^11.13.1",
22
- "@emotion/react": "^11.13.3",
23
- "@emotion/styled": "^11.13.0",
24
- "@mui/icons-material": "^6.1.4",
25
- "@mui/material": "^6.1.4",
26
- "@types/lodash": "^4.17.12",
22
+ "@emotion/cache": "^11.13.5",
23
+ "@emotion/react": "^11.13.5",
24
+ "@emotion/styled": "^11.13.5",
25
+ "@mui/icons-material": "^6.1.8",
26
+ "@mui/material": "^6.1.8",
27
+ "@types/lodash": "^4.17.13",
27
28
  "highlight.js": "^11.10.0",
28
- "jotai": "^2.10.1",
29
+ "jotai": "^2.10.3",
29
30
  "lodash": "^4.17.21",
30
- "next": "14.2.15",
31
+ "next": "15.0.3",
31
32
  "otplib": "^12.0.1",
32
33
  "react-datepicker": "^7.5.0",
33
34
  "react-qr-code": "^2.0.15"
34
35
  },
35
36
  "devDependencies": {
36
- "@next/eslint-plugin-next": "^14.2.15",
37
- "@types/node": "^22.7.7",
38
- "@types/react": "18.3.11",
37
+ "@next/eslint-plugin-next": "^15.0.3",
38
+ "@types/node": "^22.10.0",
39
+ "@types/react": "18.3.12",
39
40
  "@types/react-dom": "^18.3.1",
40
- "@typescript-eslint/eslint-plugin": "^8.10.0",
41
- "@typescript-eslint/parser": "^8.10.0",
42
- "eslint": "^9.13.0",
43
- "eslint-config-next": "^14.2.15",
41
+ "@typescript-eslint/eslint-plugin": "^8.16.0",
42
+ "@typescript-eslint/parser": "^8.16.0",
43
+ "eslint": "^9.15.0",
44
+ "eslint-config-next": "^15.0.3",
44
45
  "eslint-config-prettier": "^9.1.0",
45
46
  "eslint-plugin-prettier": "^5.2.1",
46
- "prettier": "^3.3.3",
47
+ "prettier": "^3.4.1",
47
48
  "react": "^18.3.1",
48
49
  "react-dom": "^18.3.1",
49
- "typescript": "^5.6.3"
50
+ "typescript": "^5.7.2"
50
51
  },
51
52
  "files": [
52
53
  "src"
@@ -19,7 +19,6 @@ export interface CustomButtonProps extends ButtonProps {
19
19
 
20
20
  const CustomButton: React.FC<CustomButtonProps> = React.memo(
21
21
  props => {
22
- console.log('[trace-button] CustomButton: Rendering component', { props })
23
22
  const {
24
23
  text,
25
24
  variant,
@@ -40,7 +39,6 @@ const CustomButton: React.FC<CustomButtonProps> = React.memo(
40
39
  const handleButtonClick = (
41
40
  event: React.MouseEvent<HTMLButtonElement>
42
41
  ): void => {
43
- console.log('[trace-button] CustomButton: Button clicked')
44
42
  event.preventDefault()
45
43
  onClick?.(event)
46
44
  }
@@ -63,13 +61,6 @@ const CustomButton: React.FC<CustomButtonProps> = React.memo(
63
61
  })
64
62
  : null
65
63
 
66
- console.log('[trace-button] CustomButton: Rendering button', {
67
- variant,
68
- style: buttonStyle,
69
- disableButton,
70
- isDisabled,
71
- })
72
-
73
64
  const buttonContent = (
74
65
  <>
75
66
  {iconlocation === 'above' && IconComponent}
@@ -140,15 +131,9 @@ const CustomButton: React.FC<CustomButtonProps> = React.memo(
140
131
  prevProps.iconlocation === nextProps.iconlocation &&
141
132
  prevProps.fontlocation === nextProps.fontlocation
142
133
 
143
- console.log('[trace-button] CustomButton: Props comparison', {
144
- propsAreEqual,
145
- prevProps: Object.keys(prevProps),
146
- nextProps: Object.keys(nextProps),
147
- })
148
134
  return propsAreEqual
149
135
  }
150
136
  )
151
137
 
152
138
  CustomButton.displayName = 'CustomButton'
153
- console.log('[trace-button] CustomButton: Component defined')
154
139
  export default CustomButton
@@ -1,11 +1,10 @@
1
1
  'use client'
2
2
  import React from 'react'
3
- import PhoneNumberField, {
4
- PhoneNumberFieldProps,
5
- } from './../../../PhoneNumberField'
3
+ import PhoneNumberField from '../../../PhoneNumberField'
6
4
  import { columnconfig, cellconfig } from '../../../Grid'
5
+ import { TextFieldProps } from '@mui/material'
7
6
 
8
- export interface ExtendedPhoneNumberFieldProps extends PhoneNumberFieldProps {
7
+ export type ExtendedPhoneNumberFieldProps = TextFieldProps & {
9
8
  columnconfig?: Partial<columnconfig>
10
9
  cellconfig?: cellconfig
11
10
  }
@@ -1,15 +1,14 @@
1
+ 'use client'
1
2
  import React from 'react'
2
- import TextField, {
3
- CustomTextFieldProps,
4
- } from '../../../../components/TextField'
3
+ import TextField from '../../../../components/TextField'
5
4
  import { columnconfig, cellconfig } from '../../../Grid'
5
+ import { TextFieldProps } from '@mui/material'
6
6
 
7
7
  type ExtendedColumnConfig = Omit<columnconfig, 'component'> & {
8
8
  component?: columnconfig['component']
9
9
  }
10
10
 
11
- export interface ExtendedTextFieldProps
12
- extends Omit<CustomTextFieldProps, 'columnconfig'> {
11
+ export type ExtendedTextFieldProps = TextFieldProps & {
13
12
  columnconfig?: ExtendedColumnConfig
14
13
  cellconfig?: cellconfig
15
14
  }
@@ -24,15 +23,6 @@ const useTextField = (grid: {
24
23
  index: number
25
24
  ): columnconfig => {
26
25
  const {
27
- name,
28
- label,
29
- placeholder,
30
- value,
31
- onChange,
32
- onFocus,
33
- onBlur,
34
- error,
35
- InputProps,
36
26
  columnconfig: itemColumnConfig,
37
27
  cellconfig,
38
28
  ...restProps
@@ -54,21 +44,7 @@ const useTextField = (grid: {
54
44
  cellconfig: {
55
45
  ...cellconfig,
56
46
  },
57
- component: (
58
- <TextField
59
- key={`textfield-${index}`}
60
- name={name}
61
- label={label}
62
- placeholder={placeholder}
63
- value={value}
64
- onChange={onChange}
65
- onFocus={onFocus}
66
- onBlur={onBlur}
67
- error={error}
68
- InputProps={InputProps}
69
- {...restProps}
70
- />
71
- ),
47
+ component: <TextField key={`textfield-${index}`} {...restProps} />,
72
48
  }
73
49
 
74
50
  return mergedConfig
@@ -1,6 +1,6 @@
1
1
  'use client'
2
2
 
3
- import React, { useState } from 'react'
3
+ import React, { useState, useEffect } from 'react'
4
4
  import {
5
5
  Select,
6
6
  MenuItem,
@@ -8,9 +8,12 @@ import {
8
8
  InputLabel,
9
9
  SelectProps,
10
10
  FormHelperText,
11
- Typography,
11
+ Box,
12
+ CircularProgress,
12
13
  } from '@mui/material'
13
14
  import { styled } from '@mui/material/styles'
15
+ import { black, white } from '../../styles/palette'
16
+ import Typography from '../Typography'
14
17
 
15
18
  export interface SimpleDropdownOption {
16
19
  value: string
@@ -40,37 +43,62 @@ export interface DropdownProps extends Omit<SelectProps, 'onChange'> {
40
43
  onFocus?: SelectProps['onFocus']
41
44
  }
42
45
 
46
+ const StyledBox = styled(Box)(() => ({
47
+ position: 'relative',
48
+ width: '100%',
49
+ height: '50px',
50
+ marginTop: '5px',
51
+ }))
52
+
43
53
  const StyledFormControl = styled(FormControl)<{
44
54
  backgroundcolor?: string
45
55
  outlinecolor?: string
46
- }>(({ theme, backgroundcolor, outlinecolor }) => ({
47
- width: '100%',
56
+ }>(({ outlinecolor }) => ({
57
+ position: 'absolute',
58
+ top: 0,
59
+ left: 0,
60
+ right: 0,
61
+ bottom: 0,
48
62
  '& .MuiOutlinedInput-root': {
49
- backgroundColor: backgroundcolor || theme.palette.background.paper,
63
+ backgroundColor: white.main,
64
+ height: '45px',
50
65
  '& fieldset': {
51
- borderColor: outlinecolor || theme.palette.primary.main,
66
+ borderColor: outlinecolor || black.main,
52
67
  },
53
68
  '&:hover fieldset': {
54
- borderColor: outlinecolor || theme.palette.primary.main,
69
+ borderColor: outlinecolor || black.main,
55
70
  },
56
71
  '&.Mui-focused fieldset': {
57
- borderColor: outlinecolor || theme.palette.primary.main,
72
+ borderColor: outlinecolor || black.main,
58
73
  },
59
74
  },
60
75
  }))
61
76
 
62
77
  const StyledInputLabel = styled(InputLabel)<{ shrunkfontcolor?: string }>(
63
- ({ theme, shrunkfontcolor }) => ({
78
+ () => ({
79
+ color: black.main,
64
80
  '&.Mui-focused': {
65
- color: shrunkfontcolor || theme.palette.primary.main,
81
+ color: black.main,
82
+ },
83
+ '&.MuiInputLabel-shrink': {
84
+ transform: 'translate(13px, -7px) scale(0.75)',
85
+ color: black.main,
66
86
  },
67
87
  })
68
88
  )
69
89
 
70
- const StyledMenuItem = styled(MenuItem)(({ theme }) => ({
90
+ const StyledMenuItem = styled(MenuItem)(() => ({
71
91
  display: 'flex',
72
92
  flexDirection: 'column',
73
93
  alignItems: 'flex-start',
94
+ backgroundColor: white.main,
95
+ }))
96
+
97
+ const LoadingContainer = styled(Box)(() => ({
98
+ display: 'flex',
99
+ justifyContent: 'center',
100
+ alignItems: 'center',
101
+ height: '50px',
74
102
  }))
75
103
 
76
104
  const capitalizeFirstLetter = (string: string) => {
@@ -94,23 +122,33 @@ const Dropdown: React.FC<DropdownProps> = ({
94
122
  onFocus,
95
123
  ...rest
96
124
  }) => {
97
- const [selectedValue, setSelectedValue] = useState(() => {
125
+ const [selectedValue, setSelectedValue] = useState<string>('')
126
+ const [isLoading, setIsLoading] = useState(true)
127
+
128
+ useEffect(() => {
98
129
  const defaultOption = options.find(option => option.value === defaultValue)
99
- return defaultOption ? defaultOption.value : ''
100
- })
130
+ setSelectedValue(defaultOption ? defaultOption.value : '')
131
+ setIsLoading(false)
132
+ }, [defaultValue, options])
101
133
 
102
134
  const handleChange: SelectProps['onChange'] = (event, child) => {
103
135
  const newValue = event.target.value as string
104
136
  setSelectedValue(newValue)
105
- onChange?.(event, child)
137
+ if (onChange) {
138
+ onChange(event, child)
139
+ }
106
140
  }
107
141
 
108
142
  const handleBlur: SelectProps['onBlur'] = event => {
109
- onBlur?.(event)
143
+ if (onBlur) {
144
+ onBlur(event)
145
+ }
110
146
  }
111
147
 
112
148
  const handleFocus: SelectProps['onFocus'] = event => {
113
- onFocus?.(event)
149
+ if (onFocus) {
150
+ onFocus(event)
151
+ }
114
152
  }
115
153
 
116
154
  const renderMenuItem = (option: DropdownOption) => {
@@ -118,48 +156,107 @@ const Dropdown: React.FC<DropdownProps> = ({
118
156
  if (!('attribute1' in option)) {
119
157
  return (
120
158
  <MenuItem key={option.value} value={option.value}>
121
- {label}
159
+ <Typography fontvariant="merriparagraph" text={label} />
122
160
  </MenuItem>
123
161
  )
124
162
  } else {
125
163
  return (
126
164
  <StyledMenuItem key={option.value} value={option.value}>
127
- <Typography variant="body1">{label}</Typography>
128
- <Typography variant="caption" color="textSecondary">
129
- {option.attribute1}
130
- {option.attribute2 && ` | ${option.attribute2}`}
131
- </Typography>
165
+ <Typography fontvariant="merriparagraph" text={label} />
166
+ <Typography
167
+ fontvariant="merriparagraph"
168
+ text={`${option.attribute1}${option.attribute2 ? ` | ${option.attribute2}` : ''}`}
169
+ fontcolor="textSecondary"
170
+ />
132
171
  </StyledMenuItem>
133
172
  )
134
173
  }
135
174
  }
136
175
 
176
+ if (isLoading) {
177
+ return (
178
+ <LoadingContainer>
179
+ <CircularProgress size={24} />
180
+ </LoadingContainer>
181
+ )
182
+ }
183
+
137
184
  return (
138
- <StyledFormControl
139
- backgroundcolor={backgroundcolor}
140
- outlinecolor={outlinecolor}
141
- error={error}
142
- required={required}
143
- >
144
- <StyledInputLabel id={`${name}-label`} shrunkfontcolor={shrunkfontcolor}>
145
- {label}
146
- </StyledInputLabel>
147
- <Select
148
- labelId={`${name}-label`}
149
- value={selectedValue}
150
- onChange={handleChange}
151
- onBlur={handleBlur}
152
- onFocus={handleFocus}
153
- label={label}
154
- sx={{ color: fontcolor }}
155
- name={name}
156
- aria-labelledby={`${name}-label`}
157
- {...rest}
185
+ <StyledBox>
186
+ <StyledFormControl
187
+ backgroundcolor={backgroundcolor}
188
+ outlinecolor={outlinecolor}
189
+ error={error}
190
+ required={required}
191
+ fullWidth
158
192
  >
159
- {options.map(renderMenuItem)}
160
- </Select>
161
- {helperText && <FormHelperText>{helperText}</FormHelperText>}
162
- </StyledFormControl>
193
+ <StyledInputLabel
194
+ id={`${name}-label`}
195
+ shrunkfontcolor={shrunkfontcolor}
196
+ >
197
+ {label}
198
+ </StyledInputLabel>
199
+ <Select
200
+ labelId={`${name}-label`}
201
+ value={selectedValue}
202
+ onChange={handleChange}
203
+ onBlur={handleBlur}
204
+ onFocus={handleFocus}
205
+ label={label}
206
+ sx={{
207
+ color: fontcolor || black.main,
208
+ height: '45px',
209
+ backgroundColor: white.main,
210
+ '& .MuiSelect-select': {
211
+ paddingTop: '10px',
212
+ paddingBottom: '10px',
213
+ },
214
+ '& .MuiSvgIcon-root': {
215
+ color: black.main,
216
+ },
217
+ '& .MuiOutlinedInput-notchedOutline': {
218
+ borderColor: black.main,
219
+ },
220
+ '&:hover .MuiOutlinedInput-notchedOutline': {
221
+ borderColor: black.main,
222
+ },
223
+ '&.Mui-focused .MuiOutlinedInput-notchedOutline': {
224
+ borderColor: black.main,
225
+ },
226
+ '& .MuiInputBase-input': {
227
+ color: black.main,
228
+ },
229
+ '& .MuiInputBase-input::placeholder': {
230
+ color: black.main,
231
+ opacity: 1,
232
+ },
233
+ '& .MuiPaper-root': {
234
+ backgroundColor: white.main,
235
+ },
236
+ '& .MuiMenu-list': {
237
+ backgroundColor: white.main,
238
+ },
239
+ }}
240
+ MenuProps={{
241
+ PaperProps: {
242
+ sx: {
243
+ backgroundColor: white.main,
244
+ },
245
+ },
246
+ }}
247
+ name={name}
248
+ aria-labelledby={`${name}-label`}
249
+ {...rest}
250
+ >
251
+ {options.map(renderMenuItem)}
252
+ </Select>
253
+ {helperText && (
254
+ <FormHelperText>
255
+ <Typography fontvariant="merriparagraph" text={helperText} />
256
+ </FormHelperText>
257
+ )}
258
+ </StyledFormControl>
259
+ </StyledBox>
163
260
  )
164
261
  }
165
262
 
@@ -2,78 +2,43 @@
2
2
  import React, { useState, useEffect } from 'react'
3
3
  import { Box, Tabs, Tab } from '@mui/material'
4
4
  import { NavProps, SubNav, View } from '../index'
5
+ import { usePathname } from 'next/navigation'
5
6
 
6
- /**
7
- * Represents the possible alignment options for the horizontal navigation.
8
- */
9
7
  type Alignment = 'left' | 'center' | 'right' | 'inherit' | 'justify'
10
8
 
11
- /**
12
- * Represents the structure of an active tab value.
13
- */
14
9
  export interface ActiveTabValue {
15
- /** The unique identifier of the active tab. */
16
- tabId: string
10
+ tabId: string | false
17
11
  }
18
12
 
19
- /**
20
- * Props for the HorizontalVariant component.
21
- */
22
13
  export interface HorizontalVariantProps {
23
- /** An array of navigation items, sub-navigation items, or views. */
24
14
  items: (NavProps | SubNav | View)[]
25
- /** The height of the navigation bar. Defaults to '80px'. */
26
15
  height?: string
27
- /** The alignment of the navigation items. Defaults to 'left'. */
28
16
  alignment?: Alignment
29
- /** A unique name for this navigation component. Used for state management. */
30
17
  navname?: string
31
18
  }
32
19
 
33
- /**
34
- * HorizontalVariant component that renders a horizontal navigation bar.
35
- * It supports dynamic tab management, routing, and custom click handlers.
36
- *
37
- * @param {HorizontalVariantProps} props - The props for the HorizontalVariant component.
38
- * @returns {JSX.Element} The rendered HorizontalVariant component.
39
- */
40
20
  function HorizontalVariant({
41
21
  items,
42
22
  height = '80px',
43
23
  alignment = 'left',
44
24
  navname = '',
45
25
  }: HorizontalVariantProps) {
46
- /**
47
- * State to keep track of active tab values for different navigation components.
48
- */
49
26
  const [activeTabValues, setActiveTabValues] = useState<
50
27
  Record<string, ActiveTabValue>
51
28
  >({})
29
+ const pathname = usePathname()
52
30
 
53
- /**
54
- * Effect hook to initialize the active tab values when the component mounts.
55
- */
56
31
  useEffect(() => {
57
- if (!activeTabValues[navname]) {
58
- const firstTab = items.find(item => 'orientation' in item) as
59
- | NavProps
60
- | undefined
61
- if (firstTab && firstTab.title) {
62
- setActiveTabValues(prev => ({
63
- ...prev,
64
- [navname]: { tabId: firstTab.title as string },
65
- }))
66
- }
67
- }
68
- }, [items, navname, activeTabValues])
32
+ const currentTab = items.find(
33
+ item => 'orientation' in item && item.route === pathname
34
+ ) as NavProps | undefined
35
+
36
+ setActiveTabValues(prev => ({
37
+ ...prev,
38
+ [navname]: { tabId: currentTab?.title || false },
39
+ }))
40
+ }, [items, navname, pathname])
69
41
 
70
- /**
71
- * Handles tab change events.
72
- * Updates the active tab values in the state.
73
- *
74
- * @param {React.SyntheticEvent} event - The event object.
75
- * @param {string} newValue - The new value of the selected tab.
76
- */
77
42
  const handleTabChange = (event: React.SyntheticEvent, newValue: string) => {
78
43
  setActiveTabValues(prev => ({
79
44
  ...prev,
@@ -81,12 +46,6 @@ function HorizontalVariant({
81
46
  }))
82
47
  }
83
48
 
84
- /**
85
- * Handles click events on individual tabs.
86
- * Supports different trigger types: route, onClick, and routeonhorizontal.
87
- *
88
- * @param {NavProps} tab - The tab object that was clicked.
89
- */
90
49
  const handleTabClick = (tab: NavProps) => {
91
50
  if (tab.trigger === 'route') {
92
51
  if (tab.route) {
@@ -116,7 +75,7 @@ function HorizontalVariant({
116
75
  }}
117
76
  >
118
77
  <Tabs
119
- value={activeTabValues[navname]?.tabId || ''}
78
+ value={activeTabValues[navname]?.tabId || false}
120
79
  onChange={handleTabChange}
121
80
  aria-label="nav tabs"
122
81
  sx={{
@@ -136,8 +95,8 @@ function HorizontalVariant({
136
95
  return (
137
96
  <Tab
138
97
  key={tab.title}
139
- value={tab.title}
140
- label={tab.title}
98
+ value={tab.title || ''}
99
+ label={tab.title || ''}
141
100
  onClick={() => handleTabClick(tab)}
142
101
  sx={{
143
102
  minHeight: 0,
@@ -1,45 +1,6 @@
1
1
  'use client'
2
- import React, { useState, useCallback } from 'react'
3
- import { TextField, TextFieldProps } from '@mui/material'
4
- import { styled } from '@mui/material/styles'
5
-
6
- export interface PhoneNumberFieldProps
7
- extends Omit<TextFieldProps, 'onChange'> {
8
- initialValue?: string
9
- onChange?: () => void
10
- backgroundcolor?: string
11
- outlinecolor?: string
12
- fontcolor?: string
13
- label?: string
14
- }
15
-
16
- const StyledTextField = styled(TextField)<{
17
- backgroundcolor?: string
18
- outlinecolor?: string
19
- fontcolor?: string
20
- }>(({ theme, backgroundcolor, outlinecolor, fontcolor }) => ({
21
- '& .MuiOutlinedInput-root': {
22
- backgroundColor: backgroundcolor || theme.palette.background.paper,
23
- '& fieldset': {
24
- borderColor: outlinecolor || theme.palette.primary.main,
25
- },
26
- '&:hover fieldset': {
27
- borderColor: outlinecolor || theme.palette.primary.main,
28
- },
29
- '&.Mui-focused fieldset': {
30
- borderColor: outlinecolor || theme.palette.primary.main,
31
- },
32
- },
33
- '& .MuiInputLabel-root': {
34
- color: fontcolor || theme.palette.text.primary,
35
- '&.Mui-focused': {
36
- color: fontcolor || theme.palette.primary.main,
37
- },
38
- },
39
- '& .MuiInputBase-input': {
40
- color: fontcolor || theme.palette.text.primary,
41
- },
42
- }))
2
+ import React, { useCallback, useMemo, useState } from 'react'
3
+ import { Box, TextField as MuiTextField, TextFieldProps } from '@mui/material'
43
4
 
44
5
  const formatPhoneNumber = (value: string): string => {
45
6
  const digits = value.replace(/\D/g, '')
@@ -57,47 +18,110 @@ const formatPhoneNumber = (value: string): string => {
57
18
  return formattedNumber.trim()
58
19
  }
59
20
 
60
- const PhoneNumberField: React.FC<PhoneNumberFieldProps> = ({
61
- initialValue = '',
62
- onChange,
63
- backgroundcolor,
64
- outlinecolor,
65
- fontcolor,
66
- label = 'Phone Number',
67
- ...rest
68
- }) => {
21
+ const PhoneNumberField: React.FC<TextFieldProps> = React.memo(props => {
22
+ const {
23
+ name,
24
+ label = 'Phone Number',
25
+ placeholder,
26
+ onChange,
27
+ onFocus,
28
+ onBlur,
29
+ value = '',
30
+ error,
31
+ ...restProps
32
+ } = props
33
+
69
34
  const [phoneNumber, setPhoneNumber] = useState(
70
- formatPhoneNumber(initialValue)
35
+ formatPhoneNumber(value as string)
71
36
  )
72
37
 
73
- const handlePhoneNumberChange = useCallback(
74
- (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
38
+ const handleChange = useCallback(
39
+ (e: React.ChangeEvent<HTMLInputElement>) => {
75
40
  const input = e.target.value
76
41
  let strippedInput = input.replace(/^\+1\s?/, '').replace(/\D/g, '')
77
42
  strippedInput = strippedInput.slice(0, 10)
78
43
  const formattedValue =
79
44
  strippedInput.length > 0 ? formatPhoneNumber(strippedInput) : '+1 '
80
45
  setPhoneNumber(formattedValue)
81
- onChange?.()
46
+ if (onChange) {
47
+ onChange(e)
48
+ }
82
49
  },
83
50
  [onChange]
84
51
  )
85
52
 
53
+ const handleFocus = useCallback(
54
+ (e: React.FocusEvent<HTMLInputElement>) => {
55
+ if (onFocus) {
56
+ onFocus(e)
57
+ }
58
+ },
59
+ [onFocus]
60
+ )
61
+
62
+ const handleBlur = useCallback(
63
+ (e: React.FocusEvent<HTMLInputElement>) => {
64
+ if (onBlur) {
65
+ onBlur(e)
66
+ }
67
+ },
68
+ [onBlur]
69
+ )
70
+
71
+ const handleClick = useCallback((e: React.MouseEvent<HTMLDivElement>) => {
72
+ e.preventDefault()
73
+ }, [])
74
+
75
+ const inputProps = useMemo(
76
+ () => ({
77
+ style: {
78
+ height: '40px',
79
+ padding: '8px 14px',
80
+ },
81
+ }),
82
+ []
83
+ )
84
+
85
+ const InputProps = useMemo(
86
+ () => ({
87
+ style: {
88
+ height: '45px',
89
+ },
90
+ }),
91
+ []
92
+ )
93
+
86
94
  return (
87
- <StyledTextField
88
- label={label}
89
- value={phoneNumber}
90
- onChange={handlePhoneNumberChange}
91
- backgroundcolor={backgroundcolor}
92
- outlinecolor={outlinecolor}
93
- fontcolor={fontcolor}
94
- fullWidth
95
- inputProps={{
96
- maxLength: 16,
95
+ <Box
96
+ sx={{
97
+ display: 'flex',
98
+ flexDirection: 'column',
99
+ justifyContent: 'center',
100
+ width: '100%',
101
+ marginTop: '5px',
102
+ height: '70px',
97
103
  }}
98
- {...rest}
99
- />
104
+ onClick={handleClick}
105
+ >
106
+ <MuiTextField
107
+ name={name}
108
+ label={label}
109
+ placeholder={placeholder}
110
+ onChange={handleChange}
111
+ onFocus={handleFocus}
112
+ onBlur={handleBlur}
113
+ value={phoneNumber}
114
+ error={error}
115
+ fullWidth
116
+ variant="outlined"
117
+ inputProps={inputProps}
118
+ InputProps={InputProps}
119
+ {...restProps}
120
+ />
121
+ </Box>
100
122
  )
101
- }
123
+ })
124
+
125
+ PhoneNumberField.displayName = 'PhoneNumberField'
102
126
 
103
127
  export default PhoneNumberField
@@ -1,6 +1,6 @@
1
1
  'use client'
2
- import React, { useState, useCallback, useMemo } from 'react'
3
- import { Box, Paper, SelectChangeEvent } from '@mui/material'
2
+ import React, { useState, useCallback, useMemo, useEffect } from 'react'
3
+ import { Box, Paper, SelectChangeEvent, CircularProgress } from '@mui/material'
4
4
  import InfoIcon from '@mui/icons-material/Info'
5
5
  import CheckCircleIcon from '@mui/icons-material/CheckCircle'
6
6
  import { Typography } from '../Typography'
@@ -72,17 +72,37 @@ export interface PricingProps {
72
72
  const PricingTable: React.FC<PricingProps> = props => {
73
73
  const router = useRouter()
74
74
  const [selectedPackageIndex, setSelectedPackageIndex] = useState(0)
75
+ const [selectedPackage, setSelectedPackage] = useState('')
76
+ const [isLoading, setIsLoading] = useState(true)
75
77
 
76
78
  const config = useMemo(() => {
77
79
  return { ...defaultConfig, ...props }
78
80
  }, [props])
79
81
 
82
+ useEffect(() => {
83
+ const timer = setTimeout(() => {
84
+ setIsLoading(false)
85
+ }, 100) // Simulating a 100ms loading time
86
+
87
+ return () => clearTimeout(timer)
88
+ }, [])
89
+
90
+ useEffect(() => {
91
+ if (
92
+ config.packagecolumns?.packagenames &&
93
+ config.packagecolumns.packagenames.length > 0
94
+ ) {
95
+ setSelectedPackage(config.packagecolumns.packagenames[0])
96
+ }
97
+ }, [config.packagecolumns?.packagenames])
98
+
80
99
  const handlePackageChange = useCallback(
81
100
  (event: SelectChangeEvent<unknown>) => {
82
101
  const newValue = event.target.value as string
83
102
  const newIndex =
84
103
  config.packagecolumns?.packagenames?.indexOf(newValue) ?? 0
85
104
  setSelectedPackageIndex(newIndex)
105
+ setSelectedPackage(newValue)
86
106
  console.log('Package selection changed to:', newValue)
87
107
  },
88
108
  [config.packagecolumns?.packagenames]
@@ -116,7 +136,7 @@ const PricingTable: React.FC<PricingProps> = props => {
116
136
  value: name,
117
137
  label: name,
118
138
  }))}
119
- defaultValue={config.packagecolumns.packagenames?.[0] || ''}
139
+ defaultValue={selectedPackage}
120
140
  backgroundcolor={semiTransparentBlack.main}
121
141
  outlinecolor={black.main}
122
142
  fontcolor={black.main}
@@ -276,10 +296,46 @@ const PricingTable: React.FC<PricingProps> = props => {
276
296
  }
277
297
 
278
298
  return { headerColumnConfigs, featureColumnConfigs }
279
- }, [config, selectedPackageIndex, router, handlePackageChange])
299
+ }, [
300
+ config,
301
+ selectedPackageIndex,
302
+ selectedPackage,
303
+ router,
304
+ handlePackageChange,
305
+ ])
280
306
 
281
307
  const { headerColumnConfigs, featureColumnConfigs } = renderColumnConfigs()
282
308
 
309
+ if (isLoading) {
310
+ return (
311
+ <CustomGrid
312
+ gridconfig={{
313
+ gridwidth: '100%',
314
+ alignment: 'center',
315
+ }}
316
+ columnconfig={[
317
+ {
318
+ row: 1,
319
+ column: 1,
320
+ alignment: 'center',
321
+ component: (
322
+ <Box
323
+ display="flex"
324
+ justifyContent="center"
325
+ alignItems="center"
326
+ height="350px"
327
+ width="100%"
328
+ overflow="auto"
329
+ >
330
+ <CircularProgress size={240} thickness={2} />
331
+ </Box>
332
+ ),
333
+ },
334
+ ]}
335
+ />
336
+ )
337
+ }
338
+
283
339
  return (
284
340
  <Paper
285
341
  elevation={1}
@@ -1,11 +1,8 @@
1
+ 'use client'
1
2
  import React, { useCallback, useMemo } from 'react'
2
3
  import { Box, TextField as MuiTextField, TextFieldProps } from '@mui/material'
3
4
 
4
- export interface CustomTextFieldProps extends Omit<TextFieldProps, 'name'> {
5
- name: string
6
- }
7
-
8
- const TextField: React.FC<CustomTextFieldProps> = React.memo(props => {
5
+ const TextField: React.FC<TextFieldProps> = React.memo(props => {
9
6
  const {
10
7
  name,
11
8
  label,
@@ -16,7 +13,6 @@ const TextField: React.FC<CustomTextFieldProps> = React.memo(props => {
16
13
  value,
17
14
  error,
18
15
  sx,
19
- InputProps,
20
16
  ...restProps
21
17
  } = props
22
18
 
@@ -64,31 +60,27 @@ const TextField: React.FC<CustomTextFieldProps> = React.memo(props => {
64
60
  []
65
61
  )
66
62
 
67
- const mergedInputProps = useMemo(
63
+ const slotProps = useMemo(
68
64
  () => ({
69
- ...InputProps,
70
- style: {
71
- ...inputStyle,
72
- ...InputProps?.style,
65
+ input: {
66
+ style: inputStyle,
73
67
  },
74
- }),
75
- [InputProps, inputStyle]
76
- )
77
-
78
- const labelStyle = useMemo(
79
- () => ({
80
- '&.MuiInputLabel-shrink': {
81
- top: '0px',
82
- left: '0px',
83
- },
84
- '&:not(.MuiInputLabel-shrink)': {
85
- transform: 'scale(1)',
86
- transformOrigin: 'top left',
87
- top: '9px',
88
- left: '12px',
68
+ inputLabel: {
69
+ sx: {
70
+ '&.MuiInputLabel-shrink': {
71
+ top: '0px',
72
+ left: '0px',
73
+ },
74
+ '&:not(.MuiInputLabel-shrink)': {
75
+ transform: 'scale(1)',
76
+ transformOrigin: 'top left',
77
+ top: '9px',
78
+ left: '12px',
79
+ },
80
+ },
89
81
  },
90
82
  }),
91
- []
83
+ [inputStyle]
92
84
  )
93
85
 
94
86
  return (
@@ -99,7 +91,7 @@ const TextField: React.FC<CustomTextFieldProps> = React.memo(props => {
99
91
  justifyContent: 'center',
100
92
  width: '100%',
101
93
  marginTop: '5px',
102
- height: '62px',
94
+ height: '70px',
103
95
  ...sx,
104
96
  }}
105
97
  onClick={handleClick}
@@ -113,10 +105,7 @@ const TextField: React.FC<CustomTextFieldProps> = React.memo(props => {
113
105
  onBlur={handleBlur}
114
106
  value={value}
115
107
  error={error}
116
- InputProps={mergedInputProps}
117
- InputLabelProps={{
118
- sx: labelStyle,
119
- }}
108
+ slotProps={slotProps}
120
109
  fullWidth
121
110
  variant="outlined"
122
111
  {...restProps}
package/src/index.ts CHANGED
@@ -71,7 +71,6 @@ import { ExtendedImageProps } from './components/Content/Structure/image/useImag
71
71
  import { ExtendedConfirmationCodeInputsProps } from './components/Content/Structure/confirmationinput/useConfirmationInput'
72
72
  import { ExtendedRadioGroupProps } from './components/Content/Structure/radiogroup/useRadioGroup'
73
73
  import { ExtendedPhoneNumberFieldProps } from './components/Content/Structure/phoneNumber/usePhoneNumber'
74
- import { CustomTextFieldProps } from './components/TextField'
75
74
  // Colors
76
75
  import {
77
76
  moss,
@@ -268,7 +267,6 @@ export type { CustomToolbarComponentProps }
268
267
  export type { TransferListComponentProps }
269
268
  export type { StyledTooltipComponentProps }
270
269
  export type { DropdownOption }
271
- export type { CustomTextFieldProps }
272
270
 
273
271
  // New type exports
274
272
  export type { DateFieldProps }