goobs-frontend 0.7.60 → 0.7.61

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.60",
3
+ "version": "0.7.61",
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",
@@ -1,89 +1,42 @@
1
1
  'use client'
2
2
  import React, { useState, useEffect } from 'react'
3
- import { Box, Tabs, styled, Tab } from '@mui/material'
3
+ import { Box, Tabs, Tab } from '@mui/material'
4
4
  import { get, set, JSONValue } from 'goobs-cache'
5
5
  import { NavProps, SubNav, View } from '../index'
6
6
 
7
- // Define the possible alignment values for the navigation
7
+ /**
8
+ * Represents the possible alignment options for the horizontal navigation.
9
+ */
8
10
  type Alignment = 'left' | 'center' | 'right' | 'inherit' | 'justify'
9
11
 
10
12
  /**
11
- * Interface representing the active tab value
13
+ * Represents the structure of an active tab value.
12
14
  */
13
15
  export interface ActiveTabValue {
16
+ /** The unique identifier of the active tab. */
14
17
  tabId: string
15
18
  }
16
19
 
17
20
  /**
18
- * Interface for the props of the HorizontalVariant component
21
+ * Props for the HorizontalVariant component.
19
22
  */
20
23
  export interface HorizontalVariantProps {
21
- items: (NavProps | SubNav | View)[] // Array of navigation items
22
- height?: string // Optional height of the navigation
23
- alignment?: Alignment // Optional alignment of the navigation
24
- navname?: string // Optional name for the navigation
25
- }
26
-
27
- /**
28
- * Styled component for the Tab, extending MUI's Tab with custom props
29
- */
30
- const StyledTab = styled(Tab, {
31
- shouldForwardProp: prop =>
32
- prop !== 'height' && prop !== 'hasleftborder' && prop !== 'hasrightborder',
33
- })<NavProps & { height?: string }>(
34
- ({ height = '80px', hasleftborder = 'false', hasrightborder = 'false' }) => ({
35
- minHeight: 0,
36
- textTransform: 'none',
37
- border: 'none',
38
- boxSizing: 'border-box',
39
- backgroundColor: 'black',
40
- color: '#fff',
41
- fontWeight: 500,
42
- fontFamily: 'Merriweather',
43
- fontSize: 16,
44
- height: height,
45
- '&:hover': {
46
- backgroundColor: 'rgba(255, 255, 255, 0.1)',
47
- },
48
- '& .MuiTouchRipple-root': {
49
- color: '#fff',
50
- },
51
- '&.Mui-selected': {
52
- color: '#fff',
53
- backgroundColor: 'rgba(255, 255, 255, 0.2)',
54
- },
55
- '& .MuiSvgIcon-root': {
56
- color: '#fff',
57
- },
58
- ...(hasleftborder === 'true' && {
59
- borderLeft: '1px solid white',
60
- }),
61
- ...(hasrightborder === 'true' && {
62
- borderRight: '1px solid white',
63
- }),
64
- })
65
- )
66
-
67
- /**
68
- * Styled component for the horizontal navigation container
69
- */
70
- const HorizontalNavContainer = styled(Box)<{
24
+ /** An array of navigation items, sub-navigation items, or views. */
25
+ items: (NavProps | SubNav | View)[]
26
+ /** The height of the navigation bar. Defaults to '80px'. */
71
27
  height?: string
28
+ /** The alignment of the navigation items. Defaults to 'left'. */
72
29
  alignment?: Alignment
73
- }>(({ height = '80px', alignment = 'left' }) => ({
74
- flexGrow: 1,
75
- bgcolor: 'black',
76
- display: 'flex',
77
- height: height,
78
- justifyContent: alignment,
79
- paddingLeft: '5px',
80
- paddingRight: '5px',
81
- }))
30
+ /** A unique name for this navigation component. Used for state management. */
31
+ navname?: string
32
+ }
82
33
 
83
34
  /**
84
- * HorizontalVariant component for rendering a horizontal navigation bar
85
- * @param {HorizontalVariantProps} props - The props for the component
86
- * @returns {JSX.Element} The rendered HorizontalVariant component
35
+ * HorizontalVariant component that renders a horizontal navigation bar.
36
+ * It supports dynamic tab management, routing, and custom click handlers.
37
+ *
38
+ * @param {HorizontalVariantProps} props - The props for the HorizontalVariant component.
39
+ * @returns {JSX.Element} The rendered HorizontalVariant component.
87
40
  */
88
41
  function HorizontalVariant({
89
42
  items,
@@ -91,13 +44,20 @@ function HorizontalVariant({
91
44
  alignment = 'left',
92
45
  navname,
93
46
  }: HorizontalVariantProps) {
94
- // State to store active tab values
47
+ /**
48
+ * State to keep track of active tab values for different navigation components.
49
+ */
95
50
  const [activeTabValues, setActiveTabValues] = useState<
96
51
  Record<string, ActiveTabValue | null>
97
52
  >({})
98
53
 
99
- // Effect to fetch active tab values from cache on component mount
54
+ /**
55
+ * Effect hook to fetch and set the active tab values when the component mounts.
56
+ */
100
57
  useEffect(() => {
58
+ /**
59
+ * Asynchronously fetches the active tab values from the cache.
60
+ */
101
61
  const fetchActiveTabValues = async () => {
102
62
  const result = await get('activeTabValues', 'client')
103
63
  if (result && typeof result === 'object' && 'value' in result) {
@@ -111,9 +71,11 @@ function HorizontalVariant({
111
71
  }, [])
112
72
 
113
73
  /**
114
- * Handle tab change event
115
- * @param {React.SyntheticEvent} event - The event object
116
- * @param {string} newValue - The new value of the selected tab
74
+ * Handles tab change events.
75
+ * Updates the active tab values in the state and cache.
76
+ *
77
+ * @param {React.SyntheticEvent} event - The event object.
78
+ * @param {string} newValue - The new value of the selected tab.
117
79
  */
118
80
  const handleTabChange = async (
119
81
  event: React.SyntheticEvent,
@@ -124,7 +86,6 @@ function HorizontalVariant({
124
86
  [navname ?? '']: { tabId: newValue },
125
87
  }
126
88
  setActiveTabValues(updatedActiveTabValues)
127
- // Store updated values in cache with 30 minutes expiration
128
89
  await set(
129
90
  'activeTabValues',
130
91
  { type: 'json', value: updatedActiveTabValues } as JSONValue,
@@ -134,8 +95,10 @@ function HorizontalVariant({
134
95
  }
135
96
 
136
97
  /**
137
- * Handle tab click event based on the tab's trigger type
138
- * @param {NavProps} tab - The tab object that was clicked
98
+ * Handles click events on individual tabs.
99
+ * Supports different trigger types: route, onClick, and routeonhorizontal.
100
+ *
101
+ * @param {NavProps} tab - The tab object that was clicked.
139
102
  */
140
103
  const handleTabClick = (tab: NavProps) => {
141
104
  if (tab.trigger === 'route') {
@@ -154,9 +117,19 @@ function HorizontalVariant({
154
117
  }
155
118
 
156
119
  return (
157
- <HorizontalNavContainer height={height} alignment={alignment}>
120
+ <Box
121
+ sx={{
122
+ flexGrow: 1,
123
+ bgcolor: 'black',
124
+ display: 'flex',
125
+ height: height,
126
+ justifyContent: alignment,
127
+ paddingLeft: '5px',
128
+ paddingRight: '5px',
129
+ }}
130
+ >
158
131
  <Tabs
159
- value={activeTabValues[navname ?? '']?.tabId || false}
132
+ value={activeTabValues?.[navname ?? '']?.tabId || false}
160
133
  onChange={handleTabChange}
161
134
  aria-label="nav tabs"
162
135
  sx={{
@@ -171,35 +144,56 @@ function HorizontalVariant({
171
144
  }}
172
145
  >
173
146
  {items.map((item: NavProps | SubNav | View) => {
174
- // Only render NavProps items as tabs
175
147
  if ('orientation' in item) {
176
148
  const tab = item as NavProps
177
149
  return (
178
- <StyledTab
150
+ <Tab
179
151
  key={tab.title}
180
152
  value={tab.title}
181
153
  label={tab.title}
182
- hasleftborder={tab.hasleftborder}
183
- hasrightborder={tab.hasrightborder}
184
- height={height}
185
- orientation={tab.orientation}
154
+ onClick={() => handleTabClick(tab)}
186
155
  sx={{
156
+ minHeight: 0,
157
+ textTransform: 'none',
158
+ border: 'none',
159
+ boxSizing: 'border-box',
160
+ backgroundColor: 'black',
161
+ color: '#fff',
162
+ fontWeight: 500,
163
+ fontFamily: 'Merriweather',
164
+ fontSize: 16,
165
+ height: height,
166
+ '&:hover': {
167
+ backgroundColor: 'rgba(255, 255, 255, 0.1)',
168
+ },
169
+ '& .MuiTouchRipple-root': {
170
+ color: '#fff',
171
+ },
172
+ '&.Mui-selected': {
173
+ color: '#fff',
174
+ backgroundColor: 'rgba(255, 255, 255, 0.2)',
175
+ },
176
+ '& .MuiSvgIcon-root': {
177
+ color: '#fff',
178
+ },
179
+ ...(tab.hasleftborder === 'true' && {
180
+ borderLeft: '1px solid white',
181
+ }),
182
+ ...(tab.hasrightborder === 'true' && {
183
+ borderRight: '1px solid white',
184
+ }),
187
185
  width: 'auto',
188
186
  justifyContent: 'center',
189
187
  alignItems: 'center',
190
188
  px: 4,
191
189
  }}
192
- onClick={() => handleTabClick(tab)}
193
- title={tab.title}
194
- route={tab.route}
195
- navname={tab.navname}
196
190
  />
197
191
  )
198
192
  }
199
193
  return null
200
194
  })}
201
195
  </Tabs>
202
- </HorizontalNavContainer>
196
+ </Box>
203
197
  )
204
198
  }
205
199
 
@@ -25,23 +25,47 @@ import {
25
25
  } from '../../../styles/palette'
26
26
  import { Typography } from './../../Typography'
27
27
 
28
+ /**
29
+ * Props for the VerticalVariant component.
30
+ */
28
31
  export interface VerticalVariantProps {
32
+ /** An array of navigation items, sub-navigation items, or views. */
29
33
  items: (NavProps | SubNav | View)[]
34
+ /** Determines whether to show the search bar. */
30
35
  showSearchbar: boolean
36
+ /** Determines whether to show the dropdown. */
31
37
  showDropdown: boolean
38
+ /** Determines whether to show the title. */
32
39
  showTitle: boolean
40
+ /** Determines whether to show a divider line. */
33
41
  showLine: boolean
42
+ /** The title of the vertical navigation. */
34
43
  verticalNavTitle: string
44
+ /** The label for the dropdown. */
35
45
  dropdownLabel: string
46
+ /** The label for the search bar. */
36
47
  searchbarLabel: string
48
+ /** The anchor position of the drawer ('left' or 'right'). */
37
49
  anchor: 'left' | 'right'
50
+ /** An array of expanded navigation items. */
38
51
  expandedNavs: string[]
52
+ /** Function to set the expanded navigation items. */
39
53
  setExpandedNavs: React.Dispatch<React.SetStateAction<string[]>>
54
+ /** An array of expanded sub-navigation items. */
40
55
  expandedSubnavs: string[]
56
+ /** Function to set the expanded sub-navigation items. */
41
57
  setExpandedSubnavs: React.Dispatch<React.SetStateAction<string[]>>
58
+ /** The width of the vertical navigation drawer. */
42
59
  verticalNavWidth: string
43
60
  }
44
61
 
62
+ /**
63
+ * VerticalVariant component that renders a vertical navigation drawer.
64
+ * It supports nested navigation items, sub-navigation items, and views.
65
+ *
66
+ * @param {VerticalVariantProps} props - The props for the VerticalVariant component.
67
+ * @returns {JSX.Element} The rendered VerticalVariant component.
68
+ */
45
69
  function VerticalVariant({
46
70
  items,
47
71
  showSearchbar,
@@ -60,10 +84,19 @@ function VerticalVariant({
60
84
  }: VerticalVariantProps) {
61
85
  const router = useRouter()
62
86
 
87
+ /**
88
+ * Extracts navigation options from the items array.
89
+ */
63
90
  const navOptions = items
64
91
  .filter((item): item is NavProps => 'title' in item && 'subnavs' in item)
65
92
  .map(nav => nav.title ?? '')
66
93
 
94
+ /**
95
+ * Handles click events on navigation items.
96
+ * Supports different trigger types: route and onClick.
97
+ *
98
+ * @param {NavProps} nav - The navigation item that was clicked.
99
+ */
67
100
  const handleNavClick = (nav: NavProps) => {
68
101
  console.log('Clicked Nav:', nav.title)
69
102
  if (nav.trigger === 'route') {
@@ -77,6 +110,14 @@ function VerticalVariant({
77
110
  }
78
111
  }
79
112
 
113
+ /**
114
+ * Recursively renders navigation items, sub-navigation items, and views.
115
+ *
116
+ * @param {NavProps | SubNav | View} item - The item to render.
117
+ * @param {number} level - The nesting level of the item.
118
+ * @param {string} [activeAndHoverColor] - The color to use for active and hover states.
119
+ * @returns {JSX.Element | null} The rendered item or null if the item type is not recognized.
120
+ */
80
121
  const renderItem = (
81
122
  item: NavProps | SubNav | View,
82
123
  level: number,
@@ -12,7 +12,6 @@ const defaultConfig: PricingProps = {
12
12
  gridname: 'pricingtableheader',
13
13
  alignment: 'center' as Alignment,
14
14
  margintop: 1,
15
- marginbottom: 0,
16
15
  gridwidth: '100%',
17
16
  },
18
17
  // Configuration for the table title
@@ -23,15 +22,11 @@ const defaultConfig: PricingProps = {
23
22
  column: 1,
24
23
  gridname: 'pricingtableheader',
25
24
  alignment: 'left' as Alignment,
26
- marginleft: 1,
25
+ marginleft: 3,
26
+ marginbottom: 1,
27
27
  mobilewidth: '100%',
28
28
  tabletwidth: '100%',
29
29
  computerwidth: '100%',
30
- cellconfig: {
31
- border: 'none',
32
- minHeight: '40px',
33
- width: '100%',
34
- },
35
30
  },
36
31
  },
37
32
  // Configuration for package columns
@@ -41,16 +36,9 @@ const defaultConfig: PricingProps = {
41
36
  column: 2,
42
37
  gridname: 'pricingtableheader',
43
38
  alignment: 'center' as Alignment,
44
- marginleft: 1,
45
- marginbottom: 1,
46
39
  mobilewidth: '80%',
47
- tabletwidth: '45%',
48
- computerwidth: '45%',
49
- cellconfig: {
50
- border: 'none',
51
- minHeight: '40px',
52
- width: '100%',
53
- },
40
+ tabletwidth: '48%',
41
+ computerwidth: '48%',
54
42
  },
55
43
  },
56
44
  // Configuration for monthly pricing
@@ -60,15 +48,10 @@ const defaultConfig: PricingProps = {
60
48
  row: 2,
61
49
  column: 1,
62
50
  mobilewidth: '100%',
63
- tabletwidth: '45%',
64
- computerwidth: '45%',
51
+ tabletwidth: '48%',
52
+ computerwidth: '48%',
65
53
  gridname: 'pricingtableheader',
66
54
  alignment: 'center' as Alignment,
67
- cellconfig: {
68
- border: 'none',
69
- minHeight: '40px',
70
- width: '100%',
71
- },
72
55
  },
73
56
  },
74
57
  // Configuration for annual pricing
@@ -78,15 +61,10 @@ const defaultConfig: PricingProps = {
78
61
  row: 2,
79
62
  column: 2,
80
63
  mobilewidth: '100%',
81
- tabletwidth: '45%',
82
- computerwidth: '45%',
64
+ tabletwidth: '48%',
65
+ computerwidth: '48%',
83
66
  gridname: 'pricingtableheader',
84
67
  alignment: 'center' as Alignment,
85
- cellconfig: {
86
- border: 'none',
87
- minHeight: '40px',
88
- width: '100%',
89
- },
90
68
  },
91
69
  },
92
70
  // Configuration for the feature grid
@@ -105,15 +83,10 @@ const defaultConfig: PricingProps = {
105
83
  row: 1,
106
84
  column: 1,
107
85
  mobilewidth: '80%',
108
- tabletwidth: '50%',
109
- computerwidth: '50%',
86
+ tabletwidth: '48%',
87
+ computerwidth: '48%',
110
88
  gridname: 'pricingtablefeatures',
111
89
  alignment: 'left' as Alignment,
112
- marginleft: 1,
113
- cellconfig: {
114
- border: 'solid',
115
- minHeight: '40px',
116
- },
117
90
  },
118
91
  tiedtopackage: {
119
92
  tiedtopackages: 'true',
@@ -121,34 +94,24 @@ const defaultConfig: PricingProps = {
121
94
  row: 1,
122
95
  column: 2,
123
96
  mobilewidth: '20%',
124
- tabletwidth: '50%',
125
- computerwidth: '50%',
97
+ tabletwidth: '48%',
98
+ computerwidth: '48%',
126
99
  gridname: 'pricingtablefeatures',
127
100
  alignment: 'center' as Alignment,
128
- cellconfig: {
129
- border: 'solid',
130
- minHeight: '40px',
131
- },
132
101
  },
133
102
  },
134
103
  subfeatures: [
135
104
  {
136
105
  title: 'Pricing Table',
137
- titlelink: '',
138
106
  infopopuptext: 'Pricing table subfeature info',
139
107
  columnconfig: {
140
108
  row: 2,
141
109
  column: 1,
142
110
  mobilewidth: '80%',
143
- tabletwidth: '50%',
144
- computerwidth: '50%',
111
+ tabletwidth: '48%',
112
+ computerwidth: '48%',
145
113
  gridname: 'pricingtablefeatures',
146
114
  alignment: 'left' as Alignment,
147
- marginleft: 3,
148
- cellconfig: {
149
- border: 'solid',
150
- minHeight: '40px',
151
- },
152
115
  },
153
116
  tiedtopackage: {
154
117
  tiedtopackages: 'true',
@@ -156,14 +119,10 @@ const defaultConfig: PricingProps = {
156
119
  row: 2,
157
120
  column: 2,
158
121
  mobilewidth: '20%',
159
- tabletwidth: '50%',
160
- computerwidth: '50%',
122
+ tabletwidth: '48%',
123
+ computerwidth: '48%',
161
124
  gridname: 'pricingtablefeatures',
162
125
  alignment: 'center' as Alignment,
163
- cellconfig: {
164
- border: 'solid',
165
- minHeight: '40px',
166
- },
167
126
  },
168
127
  },
169
128
  },
@@ -175,15 +134,10 @@ const defaultConfig: PricingProps = {
175
134
  row: 3,
176
135
  column: 1,
177
136
  mobilewidth: '80%',
178
- tabletwidth: '50%',
179
- computerwidth: '50%',
137
+ tabletwidth: '48%',
138
+ computerwidth: '48%',
180
139
  gridname: 'pricingtablefeatures',
181
140
  alignment: 'left' as Alignment,
182
- marginleft: 3,
183
- cellconfig: {
184
- border: 'solid',
185
- minHeight: '40px',
186
- },
187
141
  },
188
142
  tiedtopackage: {
189
143
  tiedtopackages: 'true',
@@ -191,14 +145,10 @@ const defaultConfig: PricingProps = {
191
145
  row: 3,
192
146
  column: 2,
193
147
  mobilewidth: '20%',
194
- tabletwidth: '50%',
195
- computerwidth: '50%',
148
+ tabletwidth: '48%',
149
+ computerwidth: '48%',
196
150
  gridname: 'pricingtablefeatures',
197
151
  alignment: 'center' as Alignment,
198
- cellconfig: {
199
- border: 'solid',
200
- minHeight: '40px',
201
- },
202
152
  },
203
153
  },
204
154
  },
@@ -211,15 +161,10 @@ const defaultConfig: PricingProps = {
211
161
  row: 4,
212
162
  column: 1,
213
163
  mobilewidth: '80%',
214
- tabletwidth: '50%',
215
- computerwidth: '50%',
164
+ tabletwidth: '48%',
165
+ computerwidth: '48%',
216
166
  gridname: 'pricingtablefeatures',
217
167
  alignment: 'left' as Alignment,
218
- marginleft: 1,
219
- cellconfig: {
220
- border: 'solid',
221
- minHeight: '40px',
222
- },
223
168
  },
224
169
  tiedtopackage: {
225
170
  tiedtopackages: 'true',
@@ -227,14 +172,10 @@ const defaultConfig: PricingProps = {
227
172
  row: 4,
228
173
  column: 2,
229
174
  mobilewidth: '20%',
230
- tabletwidth: '50%',
231
- computerwidth: '50%',
175
+ tabletwidth: '48%',
176
+ computerwidth: '48%',
232
177
  gridname: 'pricingtablefeatures',
233
178
  alignment: 'center' as Alignment,
234
- cellconfig: {
235
- border: 'solid',
236
- minHeight: '40px',
237
- },
238
179
  },
239
180
  },
240
181
  subfeatures: [
@@ -247,14 +188,9 @@ const defaultConfig: PricingProps = {
247
188
  column: 1,
248
189
  mobilewidth: '80%',
249
190
  tabletwidth: '50%',
250
- computerwidth: '50%',
191
+ computerwidth: '48%',
251
192
  gridname: 'pricingtablefeatures',
252
193
  alignment: 'left' as Alignment,
253
- marginleft: 3,
254
- cellconfig: {
255
- border: 'solid',
256
- minHeight: '40px',
257
- },
258
194
  },
259
195
  tiedtopackage: {
260
196
  tiedtopackages: 'true',
@@ -262,14 +198,10 @@ const defaultConfig: PricingProps = {
262
198
  row: 5,
263
199
  column: 2,
264
200
  mobilewidth: '20%',
265
- tabletwidth: '50%',
266
- computerwidth: '50%',
201
+ tabletwidth: '48%',
202
+ computerwidth: '48%',
267
203
  gridname: 'pricingtablefeatures',
268
204
  alignment: 'center' as Alignment,
269
- cellconfig: {
270
- border: 'solid',
271
- minHeight: '40px',
272
- },
273
205
  },
274
206
  },
275
207
  },
@@ -281,15 +213,10 @@ const defaultConfig: PricingProps = {
281
213
  row: 6,
282
214
  column: 1,
283
215
  mobilewidth: '80%',
284
- tabletwidth: '50%',
285
- computerwidth: '50%',
216
+ tabletwidth: '48%',
217
+ computerwidth: '48%',
286
218
  gridname: 'pricingtablefeatures',
287
219
  alignment: 'left' as Alignment,
288
- marginleft: 3,
289
- cellconfig: {
290
- border: 'solid',
291
- minHeight: '40px',
292
- },
293
220
  },
294
221
  tiedtopackage: {
295
222
  tiedtopackages: 'true',
@@ -297,14 +224,10 @@ const defaultConfig: PricingProps = {
297
224
  row: 6,
298
225
  column: 2,
299
226
  mobilewidth: '20%',
300
- tabletwidth: '50%',
301
- computerwidth: '50%',
227
+ tabletwidth: '48%',
228
+ computerwidth: '48%',
302
229
  gridname: 'pricingtablefeatures',
303
230
  alignment: 'center' as Alignment,
304
- cellconfig: {
305
- border: 'solid',
306
- minHeight: '40px',
307
- },
308
231
  },
309
232
  },
310
233
  },
@@ -319,15 +242,12 @@ const defaultConfig: PricingProps = {
319
242
  row: 7,
320
243
  column: 2,
321
244
  mobilewidth: '100%',
322
- tabletwidth: '50%',
323
- computerwidth: '50%',
245
+ marginbottom: 1,
246
+ marginright: 1,
247
+ tabletwidth: '100%',
248
+ computerwidth: '48%',
324
249
  gridname: 'pricingtablefeatures',
325
250
  alignment: 'center' as Alignment,
326
- cellconfig: {
327
- border: 'none',
328
- minHeight: '50px',
329
- width: '50%',
330
- },
331
251
  },
332
252
  },
333
253
  }
@@ -1,5 +1,5 @@
1
1
  'use client'
2
- import React, { useState } from 'react'
2
+ import React from 'react'
3
3
  import { Box, Paper } from '@mui/material'
4
4
  import InfoIcon from '@mui/icons-material/Info'
5
5
  import CheckCircleIcon from '@mui/icons-material/CheckCircle'
@@ -87,9 +87,6 @@ const PricingTable: React.FC<PricingProps> = props => {
87
87
  // Merge default config with provided props
88
88
  const config: PricingProps = { ...defaultConfig, ...props }
89
89
 
90
- // State for selected package
91
- const [selectedPackage] = useState<string>('goobs-frontend-unlimited')
92
-
93
90
  const router = useRouter()
94
91
 
95
92
  /**
@@ -125,10 +122,10 @@ const PricingTable: React.FC<PricingProps> = props => {
125
122
  shrunklabellocation="above"
126
123
  componentvariant="dropdown"
127
124
  shrunkfontcolor={black.main}
128
- value={selectedPackage}
129
125
  outlinecolor={black.main}
130
126
  backgroundcolor={semiTransparentBlack.main}
131
- options={['ThothOS']}
127
+ defaultOption="ThothOS"
128
+ options={['ThothOS', 'ThothOS Pro', 'ThothOS Enterprise']}
132
129
  />
133
130
  ),
134
131
  })
@@ -142,7 +139,7 @@ const PricingTable: React.FC<PricingProps> = props => {
142
139
  <Typography
143
140
  text={config.monthlyprice.prices}
144
141
  fontcolor={black.main}
145
- fontvariant="merrih6"
142
+ fontvariant="merrih5"
146
143
  />
147
144
  ),
148
145
  })
@@ -156,7 +153,7 @@ const PricingTable: React.FC<PricingProps> = props => {
156
153
  <Typography
157
154
  text={config.annualprice.annualprices}
158
155
  fontcolor={black.main}
159
- fontvariant="merrih6"
156
+ fontvariant="merrih5"
160
157
  />
161
158
  ),
162
159
  })
@@ -203,7 +200,6 @@ const PricingTable: React.FC<PricingProps> = props => {
203
200
  const tiedConfig: columnconfig = {
204
201
  ...feature.tiedtopackage.columnconfig,
205
202
  cellconfig: {
206
- border: 'solid',
207
203
  minHeight: '40px',
208
204
  },
209
205
  component: feature.tiedtopackage.tiedtopackages ? (
@@ -225,7 +221,7 @@ const PricingTable: React.FC<PricingProps> = props => {
225
221
  <Typography
226
222
  text={subFeature.title}
227
223
  fontcolor={black.main}
228
- fontvariant="merrih6"
224
+ fontvariant="merriparagraph"
229
225
  noWrap
230
226
  />
231
227
  {subFeature.infopopuptext && (
@@ -252,7 +248,6 @@ const PricingTable: React.FC<PricingProps> = props => {
252
248
  const tiedConfig: columnconfig = {
253
249
  ...subFeature.tiedtopackage.columnconfig,
254
250
  cellconfig: {
255
- border: 'solid',
256
251
  minHeight: '40px',
257
252
  },
258
253
  component: subFeature.tiedtopackage.tiedtopackages ? (
@@ -281,6 +276,7 @@ const PricingTable: React.FC<PricingProps> = props => {
281
276
  fontcolor={white.main}
282
277
  backgroundcolor={black.main}
283
278
  href={buttonLink}
279
+ width="100%"
284
280
  onClick={() => router.push(buttonLink)}
285
281
  text={config.buttoncolumns.buttontexts}
286
282
  />
@@ -22,7 +22,8 @@ export const useDropdown = (
22
22
  const [filteredOptions, setFilteredOptions] = useState<string[]>([])
23
23
  const [selectedOption, setSelectedOption] = useState('')
24
24
  const [isDropdownFocused, setIsDropdownFocused] = useState(false)
25
- const { componentvariant, options, value } = props
25
+
26
+ const { componentvariant, options, value, defaultOption } = props
26
27
 
27
28
  useEffect(() => {
28
29
  if (componentvariant === 'dropdown' && options) {
@@ -33,15 +34,19 @@ export const useDropdown = (
33
34
  useEffect(() => {
34
35
  if (value !== undefined) {
35
36
  setSelectedOption(value)
37
+ } else if (defaultOption !== undefined) {
38
+ setSelectedOption(defaultOption)
39
+ } else if (options && options.length > 0) {
40
+ setSelectedOption(options[0])
36
41
  }
37
- }, [value])
42
+ }, [value, defaultOption, options])
38
43
 
39
44
  const handleDropdownClick = useCallback(() => {
40
45
  if (componentvariant === 'dropdown') {
41
46
  setAnchorEl(inputBoxRef.current)
42
- setIsDropdownOpen(!isDropdownOpen)
47
+ setIsDropdownOpen(prev => !prev)
43
48
  }
44
- }, [componentvariant, inputBoxRef, isDropdownOpen])
49
+ }, [componentvariant, inputBoxRef])
45
50
 
46
51
  const handleOptionSelect = useCallback((option: string) => {
47
52
  setSelectedOption(option)
@@ -57,11 +62,7 @@ export const useDropdown = (
57
62
  [componentvariant]
58
63
  )
59
64
 
60
- if (componentvariant !== 'dropdown') {
61
- return {}
62
- }
63
-
64
- const renderMenu = anchorEl !== null && isDropdownOpen !== undefined && (
65
+ const renderMenu = (
65
66
  <Menu
66
67
  anchorEl={anchorEl}
67
68
  open={isDropdownOpen}
@@ -77,12 +78,13 @@ export const useDropdown = (
77
78
  <StyledSelectMenu
78
79
  key={option}
79
80
  onClick={() => handleOptionSelect(option)}
81
+ selected={option === selectedOption}
80
82
  >
81
83
  {option}
82
84
  </StyledSelectMenu>
83
85
  ))
84
86
  ) : (
85
- <div>No Options Found</div>
87
+ <MenuItem disabled>No Options Found</MenuItem>
86
88
  )}
87
89
  </Menu>
88
90
  )
@@ -47,6 +47,7 @@ export interface StyledComponentProps {
47
47
  | 'date'
48
48
  | 'splitbutton'
49
49
  options?: readonly string[]
50
+ defaultOption?: string
50
51
  helperfooter?: HelperFooterMessage
51
52
  placeholder?: string
52
53
  minRows?: number
@@ -112,14 +113,6 @@ const StyledComponent: React.FC<StyledComponentProps> = props => {
112
113
  'aria-describedby': ariaDescribedBy,
113
114
  } = props
114
115
 
115
- console.log('StyledComponent: Initializing with props', {
116
- name,
117
- label,
118
- required,
119
- formname,
120
- formSubmitted,
121
- })
122
-
123
116
  const { validateField, validateRequiredField, helperFooterValue } =
124
117
  useHelperFooter()
125
118
  const [isFocused, setIsFocused] = useState(false)
@@ -128,8 +121,7 @@ const StyledComponent: React.FC<StyledComponentProps> = props => {
128
121
  const inputRefInternal = useRef<HTMLInputElement>(null)
129
122
  const inputBoxRef = useRef<HTMLDivElement>(null)
130
123
 
131
- // Custom hooks
132
- const { renderMenu, selectedOption, isDropdownOpen } = useDropdown(
124
+ const { renderMenu, selectedOption, handleDropdownClick } = useDropdown(
133
125
  props,
134
126
  inputBoxRef
135
127
  )
@@ -141,7 +133,6 @@ const StyledComponent: React.FC<StyledComponentProps> = props => {
141
133
  handleDecrement,
142
134
  } = useSplitButton(props)
143
135
 
144
- // useEffect hooks
145
136
  useHasInputEffect(value, valuestatus, setHasInput)
146
137
  usePreventAutocompleteEffect(inputRefInternal)
147
138
 
@@ -160,24 +151,13 @@ const StyledComponent: React.FC<StyledComponentProps> = props => {
160
151
  }, [formSubmitted, hasInput])
161
152
 
162
153
  const currentHelperFooter = name ? helperFooterValue[name] : undefined
163
- console.log('StyledComponent: Current helper footer', currentHelperFooter)
164
154
 
165
- /**
166
- * Handle the change event of the input element.
167
- * @param e The change event.
168
- */
169
155
  const handleChange = (
170
156
  e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
171
157
  ) => {
172
- console.log('StyledComponent: handleChange called', {
173
- name: e.target.name,
174
- value: e.target.value,
175
- })
176
-
177
158
  if (componentvariant === 'phonenumber') {
178
159
  handlePhoneNumberChange(e)
179
160
  } else if (componentvariant === 'splitbutton') {
180
- // Only allow numbers for splitbutton
181
161
  const numValue = e.target.value.replace(/[^0-9]/g, '')
182
162
  e.target.value = numValue
183
163
  }
@@ -187,37 +167,17 @@ const StyledComponent: React.FC<StyledComponentProps> = props => {
187
167
  const formData = new FormData()
188
168
  formData.append(e.target.name, e.target.value)
189
169
  if (name && label && formname) {
190
- console.log('StyledComponent: Calling validateField', {
191
- name,
192
- label,
193
- required,
194
- formname,
195
- })
196
170
  validateField(name, formData, label, required, formname)
197
171
  }
198
172
  }
199
173
 
200
- /**
201
- * Handle the focus event of the input element.
202
- */
203
174
  const handleFocus = () => {
204
- console.log('StyledComponent: handleFocus called')
205
175
  setIsFocused(true)
206
176
  }
207
177
 
208
- /**
209
- * Handle the blur event of the input element.
210
- */
211
178
  const handleBlur = () => {
212
- console.log('StyledComponent: handleBlur called')
213
179
  setIsFocused(false)
214
180
  if (name && label && !hasInput && formname) {
215
- console.log('StyledComponent: Calling validateField on blur', {
216
- name,
217
- label,
218
- required,
219
- formname,
220
- })
221
181
  const formData = new FormData()
222
182
  formData.append(name, '')
223
183
  validateField(name, formData, label, required, formname)
@@ -233,9 +193,6 @@ const StyledComponent: React.FC<StyledComponentProps> = props => {
233
193
  !!label
234
194
  const hasPlaceholder = !!placeholder
235
195
 
236
- /**
237
- * Determine if the label should be shrunk based on various conditions.
238
- */
239
196
  const shouldShrinkLabel =
240
197
  isFocused ||
241
198
  isDropdownVariant ||
@@ -244,14 +201,6 @@ const StyledComponent: React.FC<StyledComponentProps> = props => {
244
201
  hasInput ||
245
202
  componentvariant === 'phonenumber'
246
203
 
247
- console.log('StyledComponent: Rendering', {
248
- name,
249
- showError,
250
- hasHelperFooter: !!currentHelperFooter,
251
- helperFooterStatus: currentHelperFooter?.status,
252
- helperFooterMessage: currentHelperFooter?.statusMessage,
253
- })
254
-
255
204
  return (
256
205
  <Box
257
206
  sx={{
@@ -349,6 +298,7 @@ const StyledComponent: React.FC<StyledComponentProps> = props => {
349
298
  onChange={handleChange}
350
299
  onFocus={handleFocus}
351
300
  onBlur={handleBlur}
301
+ onClick={isDropdownVariant ? handleDropdownClick : undefined}
352
302
  fullWidth
353
303
  multiline={componentvariant === 'multilinetextfield'}
354
304
  label={label}
@@ -370,7 +320,7 @@ const StyledComponent: React.FC<StyledComponentProps> = props => {
370
320
  componentvariant === 'phonenumber'
371
321
  }
372
322
  />
373
- {isDropdownVariant && isDropdownOpen && renderMenu}
323
+ {isDropdownVariant && renderMenu}
374
324
  </Box>
375
325
  </Box>
376
326
  {showError && currentHelperFooter?.statusMessage && (
@@ -18,7 +18,6 @@ export const useHasInputEffect = (
18
18
  ) => {
19
19
  useEffect(() => {
20
20
  const hasInput = !!value || !!valuestatus
21
- console.log('useHasInputEffect: Setting hasInput to', hasInput)
22
21
  setHasInput(hasInput)
23
22
  }, [value, valuestatus, setHasInput])
24
23
  }
@@ -39,16 +38,12 @@ export const usePreventAutocompleteEffect = (
39
38
  inputRefInternal: React.RefObject<HTMLInputElement>
40
39
  ) => {
41
40
  useEffect(() => {
42
- console.log('usePreventAutocompleteEffect: Starting effect')
43
41
  const input = inputRefInternal.current
44
42
  if (input) {
45
- console.log('usePreventAutocompleteEffect: Setting input attributes')
46
43
  input.setAttribute('autocomplete', 'new-password')
47
44
  input.setAttribute('autocorrect', 'off')
48
45
  input.setAttribute('autocapitalize', 'none')
49
46
  input.setAttribute('spellcheck', 'false')
50
- } else {
51
- console.log('usePreventAutocompleteEffect: Input ref is null')
52
47
  }
53
48
  }, [inputRefInternal])
54
49
  }