goobs-frontend 0.8.20 → 0.8.22

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.8.20",
3
+ "version": "0.8.22",
4
4
  "type": "module",
5
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.",
6
6
  "license": "MIT",
@@ -41,20 +41,20 @@
41
41
  "zod-formik-adapter": "^1.3.0"
42
42
  },
43
43
  "devDependencies": {
44
- "@next/eslint-plugin-next": "^15.1.3",
44
+ "@next/eslint-plugin-next": "^15.1.4",
45
45
  "@types/node": "^22.10.5",
46
- "@types/react": "19.0.3",
47
- "@types/react-dom": "^19.0.2",
46
+ "@types/react": "19.0.5",
47
+ "@types/react-dom": "^19.0.3",
48
48
  "@typescript-eslint/eslint-plugin": "^8.19.1",
49
49
  "@typescript-eslint/parser": "^8.19.1",
50
- "eslint": "^9.17.0",
50
+ "eslint": "^9.18.0",
51
51
  "eslint-config-next": "^15.1.4",
52
52
  "eslint-config-prettier": "^9.1.0",
53
53
  "eslint-plugin-prettier": "^5.2.1",
54
54
  "prettier": "^3.4.2",
55
55
  "react": "^19.0.0",
56
56
  "react-dom": "^19.0.0",
57
- "typescript": "^5.7.2"
57
+ "typescript": "^5.7.3"
58
58
  },
59
59
  "files": [
60
60
  "src"
@@ -15,6 +15,8 @@ interface ManageRowProps {
15
15
  handleClose?: () => void
16
16
  selectedRows?: string[]
17
17
  rows?: Array<{ [key: string]: unknown }>
18
+ // Update these to accept an array of strings if you want
19
+ // them to receive the selected row IDs directly:
18
20
  onDuplicate?: () => void
19
21
  onDelete?: () => void
20
22
  onManage?: () => void
@@ -37,11 +39,11 @@ function ManageRow({
37
39
  const handleActionSelection = (type: ModalType) => {
38
40
  switch (type) {
39
41
  case 'duplicate':
40
- onDuplicate?.()
42
+ onDuplicate?.() // We've already passed selectedRows from DataGrid
41
43
  handleClose()
42
44
  break
43
45
  case 'delete':
44
- onDelete?.()
46
+ onDelete?.() // same here
45
47
  handleClose()
46
48
  break
47
49
  case 'export':
@@ -20,20 +20,25 @@ function DataGrid({
20
20
  dropdowns,
21
21
  searchbarProps,
22
22
  error = null,
23
- onDuplicate,
24
- onDelete,
23
+ onDuplicate, // note type: (selectedIds: string[]) => void
24
+ onDelete, // note type: (selectedIds: string[]) => void
25
25
  onManage,
26
26
  onShow,
27
+ onSelectionChange, // (selectedIds: string[]) => void
27
28
  }: DatagridProps) {
29
+ // Local state
28
30
  const [rows, setRows] = useState<RowData[]>(providedRows || [])
29
31
  const [selectedRows, setSelectedRows] = useState<string[]>([])
30
32
  const [page, setPage] = useState(0)
31
33
  const [pageSize, setPageSize] = useState(10)
32
34
 
35
+ // Initialize columns/rows if needed
33
36
  useInitializeGrid({ columns, providedRows, setRows })
34
37
 
38
+ // 1) When row selection changes
35
39
  const handleSelectionChange = (newSelectedIds: string[]) => {
36
40
  setSelectedRows(newSelectedIds)
41
+ onSelectionChange?.(newSelectedIds)
37
42
  }
38
43
 
39
44
  const handleRowClick = (row: RowData) => {
@@ -54,22 +59,28 @@ function DataGrid({
54
59
  selectAllRows(rows, selectedRows, handleSelectionChange)
55
60
  }
56
61
 
62
+ // 2) Search logic
57
63
  const { filteredRows, updatedSearchbarProps } = useSearchbar({
58
64
  columns,
59
65
  rows,
60
66
  searchbarProps,
61
67
  })
62
68
 
69
+ // 3) Manage row logic
63
70
  const { handleManageRowClose, handleManage } = useManageRow({
64
71
  onManage,
65
72
  selectedRows,
66
73
  handleSelectionChange,
67
74
  })
68
75
 
76
+ // 4) Pagination
69
77
  const startIndex = page * pageSize
70
78
  const visibleRows = filteredRows.slice(startIndex, startIndex + pageSize)
71
79
 
72
- const allRowsSelected = rows.length > 0 && selectedRows.length === rows.length
80
+ // Determine if "all rows" are currently selected
81
+ const allRowsSelected =
82
+ rows.length > 0 &&
83
+ rows.every(r => selectedRows.includes(String(r._id ?? r.id)))
73
84
  const someRowsSelected =
74
85
  rows.length > 0 &&
75
86
  selectedRows.length > 0 &&
@@ -102,8 +113,16 @@ function DataGrid({
102
113
  <ManageRow
103
114
  selectedRows={selectedRows}
104
115
  rows={rows}
105
- onDuplicate={onDuplicate}
106
- onDelete={onDelete}
116
+ onDuplicate={
117
+ onDuplicate
118
+ ? () => onDuplicate(selectedRows) // pass the selected IDs
119
+ : undefined
120
+ }
121
+ onDelete={
122
+ onDelete
123
+ ? () => onDelete(selectedRows) // pass the selected IDs
124
+ : undefined
125
+ }
107
126
  onManage={handleManage}
108
127
  onShow={onShow}
109
128
  handleClose={handleManageRowClose}
@@ -44,12 +44,18 @@ export interface DatagridProps {
44
44
  columns: ColumnDef[]
45
45
  rows: RowData[]
46
46
  buttons?: CustomButtonProps[]
47
- dropdowns?: Omit<DropdownProps, 'onChange'>[]
48
- searchbarProps?: Omit<SearchbarProps, 'onChange' | 'value'>
47
+ dropdowns?: DropdownProps[]
48
+ searchbarProps?: SearchbarProps
49
49
  error?: Error | null
50
- onDuplicate?: () => void
51
- onDelete?: () => void
50
+
51
+ // Single or multi selection callbacks:
52
52
  onManage?: () => void
53
53
  onShow?: () => void
54
+
55
+ // This is critical: must accept selectedIds as an argument
56
+ onDuplicate?: (selectedIds: string[]) => void
57
+ onDelete?: (selectedIds: string[]) => void
58
+
59
+ // For capturing selection changes
54
60
  onSelectionChange?: (selectedIds: string[]) => void
55
61
  }
@@ -5,7 +5,11 @@ import { styled } from '@mui/material/styles'
5
5
 
6
6
  export interface NumberFieldProps extends Omit<TextFieldProps, 'onChange'> {
7
7
  initialValue?: string
8
- onChange?: () => void
8
+ /**
9
+ * Now accepts a standard ChangeEvent<HTMLInputElement>
10
+ * so parent can do e.g. (event) => parseInt(event.target.value) ...
11
+ */
12
+ onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void
9
13
  backgroundcolor?: string
10
14
  outlinecolor?: string
11
15
  fontcolor?: string
@@ -58,20 +62,24 @@ const NumberField: React.FC<NumberFieldProps> = ({
58
62
  const handleChange = useCallback(
59
63
  (event: React.ChangeEvent<HTMLInputElement>) => {
60
64
  const newValue = event.target.value.replace(/[^0-9]/g, '')
65
+
61
66
  if (newValue === '') {
62
67
  setValue('')
63
- onChange?.()
68
+ onChange?.(event) // Pass empty string up
64
69
  return
65
70
  }
71
+
66
72
  const numValue = parseInt(newValue, 10)
67
73
  if (min !== undefined && numValue < min) {
68
- setValue(min.toString())
74
+ setValue(String(min))
69
75
  } else if (max !== undefined && numValue > max) {
70
- setValue(max.toString())
76
+ setValue(String(max))
71
77
  } else {
72
78
  setValue(newValue)
73
79
  }
74
- onChange?.()
80
+
81
+ // Call parent's onChange so it knows about the new event/value
82
+ onChange?.(event)
75
83
  },
76
84
  [onChange, min, max]
77
85
  )
@@ -1,4 +1,4 @@
1
- // src\components\TransferList\index.tsx
1
+ // src/components/TransferList/index.tsx
2
2
  'use client'
3
3
 
4
4
  import React, { useEffect, useState } from 'react'
@@ -12,14 +12,12 @@ import Checkbox from '@mui/material/Checkbox'
12
12
  import Button from '@mui/material/Button'
13
13
  import Paper from '@mui/material/Paper'
14
14
  import { Box, Typography } from '@mui/material'
15
-
16
15
  import Dropdown, { DropdownOption } from '../Dropdown'
17
16
 
18
17
  /** Utility functions for array handling */
19
18
  function not(a: readonly string[], b: readonly string[]) {
20
19
  return a.filter(value => b.indexOf(value) === -1)
21
20
  }
22
-
23
21
  function intersection(a: readonly string[], b: readonly string[]) {
24
22
  return a.filter(value => b.indexOf(value) !== -1)
25
23
  }
@@ -59,6 +57,14 @@ export interface TransferListProps {
59
57
  dropdownOptions?: DropdownOption[]
60
58
  dropdownDataMap?: TransferListDropdownDataMap
61
59
 
60
+ /**
61
+ * A map from item-value to label.
62
+ * e.g. { "HIGH": "High Priority", "LOW": "Low Priority" }.
63
+ * If provided, we'll display `itemLabelMap[value]` in the list
64
+ * rather than the raw `value`.
65
+ */
66
+ itemLabelMap?: Record<string, string>
67
+
62
68
  /**
63
69
  * Fired whenever left/right arrays change (user clicks the arrows).
64
70
  * @param leftItems Updated array for the "left" column
@@ -92,8 +98,9 @@ const TransferList: React.FC<TransferListProps> = ({
92
98
  dropdownLabel,
93
99
  dropdownOptions = [],
94
100
  dropdownDataMap = {},
95
- onChange,
101
+ itemLabelMap,
96
102
 
103
+ onChange,
97
104
  leftTitle = 'Unassigned',
98
105
  rightTitle = 'Assigned',
99
106
  }) => {
@@ -161,7 +168,6 @@ const TransferList: React.FC<TransferListProps> = ({
161
168
  const handleToggle = (value: string) => () => {
162
169
  const currentIndex = checked.indexOf(value)
163
170
  const newChecked = [...checked]
164
-
165
171
  if (currentIndex === -1) {
166
172
  newChecked.push(value)
167
173
  } else {
@@ -234,6 +240,10 @@ const TransferList: React.FC<TransferListProps> = ({
234
240
  <List dense component="div" role="list">
235
241
  {items.map(value => {
236
242
  const labelId = `transfer-list-item-${value}-label`
243
+ const isChecked = checked.indexOf(value) !== -1
244
+ const displayedLabel =
245
+ itemLabelMap && itemLabelMap[value] ? itemLabelMap[value] : value
246
+
237
247
  return (
238
248
  <ListItemButton
239
249
  key={value}
@@ -242,15 +252,13 @@ const TransferList: React.FC<TransferListProps> = ({
242
252
  >
243
253
  <ListItemIcon>
244
254
  <Checkbox
245
- checked={checked.indexOf(value) !== -1}
255
+ checked={isChecked}
246
256
  tabIndex={-1}
247
257
  disableRipple
248
- inputProps={{
249
- 'aria-labelledby': labelId,
250
- }}
258
+ inputProps={{ 'aria-labelledby': labelId }}
251
259
  />
252
260
  </ListItemIcon>
253
- <ListItemText id={labelId} primary={value} />
261
+ <ListItemText id={labelId} primary={displayedLabel} />
254
262
  </ListItemButton>
255
263
  )
256
264
  })}
@@ -275,7 +283,7 @@ const TransferList: React.FC<TransferListProps> = ({
275
283
  )
276
284
  }
277
285
 
278
- // multipleSelection => show the dropdown above
286
+ // multipleSelection => show the dropdown above the list
279
287
  return (
280
288
  <Box sx={{ display: 'flex', flexDirection: 'column', width: '100%' }}>
281
289
  <Dropdown
@@ -295,14 +303,10 @@ const TransferList: React.FC<TransferListProps> = ({
295
303
 
296
304
  return (
297
305
  <CustomGrid
298
- container // We set "container" so our CustomGrid is the outer container
306
+ container
299
307
  spacing={2}
300
308
  alignItems="flex-start"
301
309
  columnconfig={[
302
- // We'll define a single "row" with 3 "columns": left, middle, right
303
- // row=1, column=1 => left
304
- // row=1, column=2 => middle
305
- // row=1, column=3 => right
306
310
  {
307
311
  row: 1,
308
312
  column: 1,