goobs-frontend 0.8.8 → 0.8.9

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.
@@ -1,6 +1,6 @@
1
1
  'use client'
2
2
  import React, { useState, useEffect } from 'react'
3
- import { Box, Alert, CircularProgress } from '@mui/material'
3
+ import { Box, Alert } from '@mui/material'
4
4
  import { useAtom, useSetAtom } from 'jotai'
5
5
  import {
6
6
  columnVisibilityAtom,
@@ -28,11 +28,17 @@ export interface DatagridProps {
28
28
  error?: Error | null
29
29
  onDuplicate?: () => void
30
30
  onDelete?: () => void
31
+ onManage?: () => void
32
+ onShow?: () => void
31
33
  checkboxSelection?: boolean
32
34
  selectedRows?: string[]
33
35
  onSelectionChange?: (selectedIds: string[]) => void
34
36
  }
35
37
 
38
+ interface ExtendedRowData extends RowData {
39
+ _id: string
40
+ }
41
+
36
42
  function DataGrid({
37
43
  columns,
38
44
  rows: providedRows,
@@ -43,14 +49,23 @@ function DataGrid({
43
49
  error = null,
44
50
  onDuplicate,
45
51
  onDelete,
52
+ onManage,
53
+ onShow,
54
+ selectedRows: externalSelectedRows,
55
+ onSelectionChange: externalOnSelectionChange,
46
56
  }: DatagridProps) {
47
- console.log('DataGrid render:', { columns, providedRows })
57
+ console.log('DataGrid render:', {
58
+ columns,
59
+ providedRows,
60
+ externalSelectedRows,
61
+ })
48
62
 
49
- const [rows, setRows] = useState<RowData[]>(providedRows || [])
63
+ const [rows, setRows] = useState<ExtendedRowData[]>(
64
+ (providedRows as ExtendedRowData[]) || []
65
+ )
50
66
  const [page, setPage] = useState(0)
51
67
  const [pageSize, setPageSize] = useState(10)
52
- const [selectedRows, setSelectedRows] = useState<string[]>([])
53
- const [manageRowOpen, setManageRowOpen] = useState(false)
68
+ const [internalSelectedRows, setInternalSelectedRows] = useState<string[]>([])
54
69
  const [searchValue, setSearchValue] = useState('')
55
70
  const tableRef = React.useRef(null)
56
71
  const initialized = React.useRef(false)
@@ -72,7 +87,6 @@ function DataGrid({
72
87
  setSearchValue,
73
88
  })
74
89
 
75
- // Update Jotai visibility state when search changes columns visibility
76
90
  useEffect(() => {
77
91
  if (tags.length > 0) {
78
92
  const newVisibility: { [key: string]: boolean } = {}
@@ -88,16 +102,14 @@ function DataGrid({
88
102
  }, [searchVisibleColumns, columns, updateVisibility, tags])
89
103
 
90
104
  useEffect(() => {
91
- setRows(providedRows || [])
105
+ setRows((providedRows as ExtendedRowData[]) || [])
92
106
  }, [providedRows])
93
107
 
94
- // Initialize columns and visibility in Jotai
95
108
  useEffect(() => {
96
109
  if (!initialized.current) {
97
110
  console.log('Initializing columns and visibility:', columns)
98
111
  setColumns(columns.map(col => col.field))
99
112
 
100
- // Initialize visibility for new columns
101
113
  const initialVisibility: { [key: string]: boolean } = {}
102
114
  columns.forEach(column => {
103
115
  if (columnVisibility[column.field] === undefined) {
@@ -120,20 +132,42 @@ function DataGrid({
120
132
  }
121
133
  }, [columns, setColumns, columnVisibility, updateVisibility])
122
134
 
123
- const handleRowClick = (row: RowData) => {
135
+ const selectedRows = externalSelectedRows || internalSelectedRows
136
+
137
+ const handleSelectionChange = (newSelectedIds: string[]) => {
138
+ console.log('Selection changed:', {
139
+ previous: selectedRows,
140
+ new: newSelectedIds,
141
+ timestamp: new Date().toISOString(),
142
+ })
143
+
144
+ if (externalOnSelectionChange) {
145
+ externalOnSelectionChange(newSelectedIds)
146
+ } else {
147
+ setInternalSelectedRows(newSelectedIds)
148
+ }
149
+ }
150
+
151
+ const handleRowClick = (row: ExtendedRowData) => {
124
152
  console.log('Row clicked:', row)
125
- const newSelection = selectedRows.includes(row.id)
126
- ? selectedRows.filter(id => id !== row.id)
127
- : [...selectedRows, row.id]
153
+ const newSelection = selectedRows.includes(row._id)
154
+ ? selectedRows.filter(id => id !== row._id)
155
+ : [...selectedRows, row._id]
128
156
 
129
- setSelectedRows(newSelection)
130
- setManageRowOpen(newSelection.length > 0)
157
+ handleSelectionChange(newSelection)
158
+ }
159
+
160
+ const handleManageRowClose = () => {
161
+ if (!onManage) {
162
+ handleSelectionChange([])
163
+ }
131
164
  }
132
165
 
133
- const handleSelectionChange = (selectedIds: string[]) => {
134
- console.log('Selection changed:', selectedIds)
135
- setSelectedRows(selectedIds)
136
- setManageRowOpen(selectedIds.length > 0)
166
+ const handleManage = () => {
167
+ console.log('DataGrid handleManage called with selectedRows:', selectedRows)
168
+ if (onManage) {
169
+ onManage()
170
+ }
137
171
  }
138
172
 
139
173
  const updatedSearchbarProps = {
@@ -142,7 +176,6 @@ function DataGrid({
142
176
  onChange: handleSearchChange,
143
177
  }
144
178
 
145
- // Get visible columns based on both Jotai state and search
146
179
  const visibleColumns = columns.filter(column => {
147
180
  const isVisibleInJotai = columnVisibility[column.field] !== false
148
181
  const isVisibleInSearch =
@@ -158,9 +191,11 @@ function DataGrid({
158
191
  return isVisible
159
192
  })
160
193
 
161
- // Calculate visible rows based on current page and pageSize
162
194
  const startIndex = page * pageSize
163
- const visibleRows = filteredRows.slice(startIndex, startIndex + pageSize)
195
+ const visibleRows = (filteredRows as ExtendedRowData[]).slice(
196
+ startIndex,
197
+ startIndex + pageSize
198
+ )
164
199
 
165
200
  console.log('DataGrid rendering with:', {
166
201
  visibleColumns,
@@ -170,24 +205,11 @@ function DataGrid({
170
205
  selectedRows,
171
206
  })
172
207
 
173
- if (loading) {
174
- return (
175
- <Box
176
- sx={{
177
- position: 'relative',
178
- marginTop: '60px',
179
- display: 'flex',
180
- justifyContent: 'center',
181
- alignItems: 'center',
182
- height: 'calc(100vh - 60px)',
183
- width: 'calc(100vh)',
184
- backgroundColor: woad.main,
185
- }}
186
- >
187
- <CircularProgress />
188
- </Box>
189
- )
190
- }
208
+ const updatedColumns = columns.map(column => ({
209
+ ...column,
210
+ headerName:
211
+ column.field === 'name' ? 'Administration Company' : column.headerName,
212
+ }))
191
213
 
192
214
  return (
193
215
  <>
@@ -216,6 +238,19 @@ function DataGrid({
216
238
  buttons={buttons}
217
239
  dropdowns={dropdowns}
218
240
  searchbarProps={updatedSearchbarProps}
241
+ middleComponent={
242
+ selectedRows.length > 0 ? (
243
+ <ManageRow
244
+ selectedRows={selectedRows}
245
+ rows={rows}
246
+ onDuplicate={onDuplicate}
247
+ onDelete={onDelete}
248
+ onManage={handleManage}
249
+ onShow={onShow}
250
+ handleClose={handleManageRowClose}
251
+ />
252
+ ) : null
253
+ }
219
254
  />
220
255
 
221
256
  <Box
@@ -225,11 +260,12 @@ function DataGrid({
225
260
  width: '100%',
226
261
  display: 'flex',
227
262
  flexDirection: 'column',
263
+ alignItems: 'flex-start',
228
264
  }}
229
265
  >
230
266
  <Table
231
267
  ref={tableRef}
232
- columns={visibleColumns}
268
+ columns={updatedColumns}
233
269
  rows={visibleRows}
234
270
  loading={loading}
235
271
  page={page}
@@ -253,13 +289,6 @@ function DataGrid({
253
289
  />
254
290
  </Box>
255
291
  </Box>
256
-
257
- <ManageRow
258
- open={manageRowOpen}
259
- handleClose={() => setManageRowOpen(false)}
260
- onDuplicate={onDuplicate}
261
- onDelete={onDelete}
262
- />
263
292
  </>
264
293
  )
265
294
  }
@@ -34,6 +34,8 @@ export interface DropdownProps extends Omit<SelectProps, 'onChange'> {
34
34
  outlinecolor?: string
35
35
  fontcolor?: string
36
36
  shrunkfontcolor?: string
37
+ unshrunkfontcolor?: string
38
+ shrunklabelposition?: 'onNotch' | 'aboveNotch'
37
39
  onChange?: SelectProps['onChange']
38
40
  error?: boolean
39
41
  helperText?: string
@@ -46,7 +48,7 @@ export interface DropdownProps extends Omit<SelectProps, 'onChange'> {
46
48
  const StyledBox = styled(Box)(() => ({
47
49
  position: 'relative',
48
50
  width: '100%',
49
- height: '50px',
51
+ height: '40px',
50
52
  marginTop: '5px',
51
53
  }))
52
54
 
@@ -74,18 +76,50 @@ const StyledFormControl = styled(FormControl)<{
74
76
  },
75
77
  }))
76
78
 
77
- const StyledInputLabel = styled(InputLabel)<{ shrunkfontcolor?: string }>(
78
- () => ({
79
- color: black.main,
80
- '&.Mui-focused': {
81
- color: black.main,
82
- },
83
- '&.MuiInputLabel-shrink': {
84
- transform: 'translate(13px, -7px) scale(0.75)',
85
- color: black.main,
86
- },
87
- })
88
- )
79
+ const StyledInputLabel = styled(InputLabel, {
80
+ shouldForwardProp: prop =>
81
+ prop !== 'shrunkfontcolor' &&
82
+ prop !== 'unshrunkfontcolor' &&
83
+ prop !== 'shrunklabelposition' &&
84
+ prop !== 'hasvalue',
85
+ })<{
86
+ shrunkfontcolor?: string
87
+ unshrunkfontcolor?: string
88
+ shrunklabelposition?: 'onNotch' | 'aboveNotch'
89
+ hasvalue: 'true' | 'false'
90
+ }>(({ shrunkfontcolor, unshrunkfontcolor, shrunklabelposition, hasvalue }) => ({
91
+ color: unshrunkfontcolor || black.main,
92
+ transform:
93
+ hasvalue === 'true'
94
+ ? shrunklabelposition === 'aboveNotch'
95
+ ? 'translate(13px, -20px) scale(0.75)'
96
+ : 'translate(13px, -7px) scale(0.75)'
97
+ : 'translate(14px, 12px)',
98
+ '&.Mui-focused': {
99
+ transform:
100
+ hasvalue === 'true'
101
+ ? shrunklabelposition === 'aboveNotch'
102
+ ? 'translate(13px, -20px) scale(0.75)'
103
+ : 'translate(13px, -7px) scale(0.75)'
104
+ : 'translate(14px, 12px)',
105
+ color:
106
+ hasvalue === 'true'
107
+ ? shrunkfontcolor || black.main
108
+ : unshrunkfontcolor || black.main,
109
+ },
110
+ '&.MuiInputLabel-shrink': {
111
+ transform:
112
+ hasvalue === 'true'
113
+ ? shrunklabelposition === 'aboveNotch'
114
+ ? 'translate(0px, -20px) scale(0.75)'
115
+ : 'translate(13px, -7px) scale(0.75)'
116
+ : 'translate(14px, 12px)',
117
+ color:
118
+ hasvalue === 'true'
119
+ ? shrunkfontcolor || black.main
120
+ : unshrunkfontcolor || black.main,
121
+ },
122
+ }))
89
123
 
90
124
  const StyledMenuItem = styled(MenuItem)(() => ({
91
125
  display: 'flex',
@@ -113,6 +147,8 @@ const Dropdown: React.FC<DropdownProps> = ({
113
147
  outlinecolor,
114
148
  fontcolor,
115
149
  shrunkfontcolor,
150
+ unshrunkfontcolor,
151
+ shrunklabelposition = 'onNotch',
116
152
  onChange,
117
153
  error = false,
118
154
  helperText,
@@ -124,16 +160,21 @@ const Dropdown: React.FC<DropdownProps> = ({
124
160
  }) => {
125
161
  const [selectedValue, setSelectedValue] = useState<string>('')
126
162
  const [isLoading, setIsLoading] = useState(true)
163
+ const [hasSelection, setHasSelection] = useState(false)
127
164
 
128
165
  useEffect(() => {
129
166
  const defaultOption = options.find(option => option.value === defaultValue)
130
- setSelectedValue(defaultOption ? defaultOption.value : '')
167
+ if (defaultOption) {
168
+ setSelectedValue(defaultOption.value)
169
+ setHasSelection(true)
170
+ }
131
171
  setIsLoading(false)
132
172
  }, [defaultValue, options])
133
173
 
134
174
  const handleChange: SelectProps['onChange'] = (event, child) => {
135
175
  const newValue = event.target.value as string
136
176
  setSelectedValue(newValue)
177
+ setHasSelection(true)
137
178
  if (onChange) {
138
179
  onChange(event, child)
139
180
  }
@@ -193,6 +234,9 @@ const Dropdown: React.FC<DropdownProps> = ({
193
234
  <StyledInputLabel
194
235
  id={`${name}-label`}
195
236
  shrunkfontcolor={shrunkfontcolor}
237
+ unshrunkfontcolor={unshrunkfontcolor}
238
+ shrunklabelposition={shrunklabelposition}
239
+ hasvalue={hasSelection ? 'true' : 'false'}
196
240
  >
197
241
  {label}
198
242
  </StyledInputLabel>
@@ -216,6 +260,11 @@ const Dropdown: React.FC<DropdownProps> = ({
216
260
  },
217
261
  '& .MuiOutlinedInput-notchedOutline': {
218
262
  borderColor: black.main,
263
+ legend: {
264
+ width: hasSelection ? '0.01px' : 'auto',
265
+ display:
266
+ shrunklabelposition === 'aboveNotch' ? 'none' : 'inherit',
267
+ },
219
268
  },
220
269
  '&:hover .MuiOutlinedInput-notchedOutline': {
221
270
  borderColor: black.main,
@@ -11,6 +11,15 @@ export interface FormDataGridProps {
11
11
  }
12
12
 
13
13
  function FormDataGrid({ title, description, datagrid }: FormDataGridProps) {
14
+ console.log('FormDataGrid props:', {
15
+ title,
16
+ description,
17
+ datagridProps: {
18
+ onManage: datagrid.onManage,
19
+ selectedRows: datagrid.selectedRows,
20
+ },
21
+ })
22
+
14
23
  return (
15
24
  <Box
16
25
  sx={{
@@ -7,48 +7,18 @@ import ContentSection, { ContentSectionProps } from '../../Content'
7
7
  import { formContainerStyle } from './../../../styles/Form'
8
8
  import { ExtendedTypographyProps } from '../../Content/Structure/typography/useGridTypography'
9
9
 
10
- /**
11
- * Props for the PopupForm component.
12
- * @interface PopupFormProps
13
- */
14
10
  export interface PopupFormProps {
15
- /** The title of the popup form */
16
11
  title?: string
17
- /** The description of the popup form */
18
12
  description?: string
19
- /** The grid configuration for the form content */
20
13
  grids?: ContentSectionProps['grids']
21
- /** Custom content to render inside the form */
22
14
  content?: React.ReactNode
23
- /** The type of popup to render ('dialog' or 'modal') */
24
15
  popupType: 'dialog' | 'modal'
25
- /** Whether the popup is open (only applicable for 'dialog' type) */
26
16
  open?: boolean
27
- /** Callback function to handle closing the popup (only applicable for 'dialog' type) */
28
17
  onClose?: () => void
29
- /** The width of the popup form in pixels */
30
18
  width?: number
31
19
  }
32
20
 
33
- /**
34
- * PopupForm Component
35
- *
36
- * A flexible popup form component that can be rendered as either a dialog or a modal.
37
- * It supports custom content, grids, and header configuration.
38
- *
39
- * @component
40
- * @example
41
- * <PopupForm
42
- * title="Login"
43
- * description="Please enter your credentials"
44
- * popupType="dialog"
45
- * open={isOpen}
46
- * onClose={handleClose}
47
- * content={<LoginForm />}
48
- * width={400}
49
- * />
50
- */
51
- const PopupForm: React.FC<PopupFormProps> = ({
21
+ function PopupForm({
52
22
  title,
53
23
  description,
54
24
  grids,
@@ -57,12 +27,9 @@ const PopupForm: React.FC<PopupFormProps> = ({
57
27
  open,
58
28
  onClose,
59
29
  width = 450,
60
- }) => {
61
- /**
62
- * Memoized header grid configuration
63
- */
64
- const headerGrid: ContentSectionProps['grids'][0] = useMemo(
65
- () => ({
30
+ }: PopupFormProps) {
31
+ const headerGrid = useMemo(
32
+ (): ContentSectionProps['grids'][0] => ({
66
33
  grid: {
67
34
  gridconfig: {
68
35
  gridname: 'formHeader',
@@ -101,29 +68,26 @@ const PopupForm: React.FC<PopupFormProps> = ({
101
68
  [title, description]
102
69
  )
103
70
 
104
- /**
105
- * Memoized header render function
106
- */
107
71
  const renderHeader = useMemo(
108
72
  () => <ContentSection grids={[headerGrid]} />,
109
73
  [headerGrid]
110
74
  )
111
75
 
112
- /**
113
- * Memoized content render function
114
- */
115
76
  const renderContent = useMemo(
116
77
  () => (
117
- <Box
118
- // @ts-ignore
119
- sx={formContainerStyle}
120
- >
78
+ <Box sx={formContainerStyle}>
121
79
  <Box mb={0}>{renderHeader}</Box>
122
80
  {React.isValidElement(content)
123
- ? React.cloneElement(content as React.ReactElement, {
124
- onClose: onClose,
125
- open: open,
126
- })
81
+ ? React.cloneElement(
82
+ content as React.ReactElement<{
83
+ onClose?: () => void
84
+ open?: boolean
85
+ }>,
86
+ {
87
+ onClose,
88
+ open,
89
+ }
90
+ )
127
91
  : content || (grids && <ContentSection grids={grids} />)}
128
92
  </Box>
129
93
  ),
@@ -131,7 +95,7 @@ const PopupForm: React.FC<PopupFormProps> = ({
131
95
  )
132
96
 
133
97
  const dialogProps: DialogProps = {
134
- open: popupType === 'modal' ? true : open || false,
98
+ open: popupType === 'modal' ? true : (open ?? false),
135
99
  onClose: popupType === 'modal' ? undefined : onClose,
136
100
  fullWidth: true,
137
101
  maxWidth: false,
@@ -142,16 +106,8 @@ const PopupForm: React.FC<PopupFormProps> = ({
142
106
  },
143
107
  }
144
108
 
145
- if (popupType === 'modal') {
146
- return (
147
- <Dialog {...dialogProps} disableEscapeKeyDown hideBackdrop>
148
- {renderContent}
149
- </Dialog>
150
- )
151
- }
152
-
153
- return (
154
- <Dialog {...dialogProps}>
109
+ const modalContent = (
110
+ <>
155
111
  {onClose && (
156
112
  <IconButton
157
113
  size="small"
@@ -167,8 +123,19 @@ const PopupForm: React.FC<PopupFormProps> = ({
167
123
  </IconButton>
168
124
  )}
169
125
  {renderContent}
170
- </Dialog>
126
+ </>
171
127
  )
128
+
129
+ if (popupType === 'modal') {
130
+ return (
131
+ <Dialog {...dialogProps} disableEscapeKeyDown hideBackdrop>
132
+ {modalContent}
133
+ </Dialog>
134
+ )
135
+ }
136
+
137
+ return <Dialog {...dialogProps}>{modalContent}</Dialog>
172
138
  }
173
139
 
140
+ // Export the component directly
174
141
  export default PopupForm