goobs-frontend 0.8.7 → 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.
Files changed (27) hide show
  1. package/package.json +15 -15
  2. package/src/components/Button/index.tsx +91 -109
  3. package/src/components/Checkbox/index.tsx +79 -0
  4. package/src/components/ConfirmationCodeInput/index.tsx +120 -46
  5. package/src/components/Content/Structure/checkbox/useCheckbox.tsx +65 -0
  6. package/src/components/Content/Structure/typography/useGridTypography.tsx +2 -0
  7. package/src/components/Content/index.tsx +5 -0
  8. package/src/components/DataGrid/Footer/index.tsx +169 -0
  9. package/src/components/DataGrid/Jotai/atom.ts +91 -0
  10. package/src/components/DataGrid/ManageColumn/index.tsx +211 -0
  11. package/src/components/DataGrid/ManageRow/index.tsx +348 -0
  12. package/src/components/DataGrid/Table/index.tsx +275 -0
  13. package/src/components/DataGrid/VerticalDivider/index.tsx +6 -0
  14. package/src/components/DataGrid/index.tsx +296 -0
  15. package/src/components/DataGrid/utils/useManageColumn.tsx +138 -0
  16. package/src/components/DataGrid/utils/useSearchbar.tsx +122 -0
  17. package/src/components/Dropdown/index.tsx +63 -14
  18. package/src/components/Form/DataGrid/index.tsx +72 -0
  19. package/src/components/Form/Popup/index.tsx +30 -63
  20. package/src/components/Grid/index.tsx +83 -101
  21. package/src/components/Nav/VerticalVariant/index.tsx +14 -10
  22. package/src/components/Searchbar/index.tsx +98 -42
  23. package/src/components/TextField/index.tsx +0 -1
  24. package/src/components/Toolbar/index.tsx +37 -19
  25. package/src/components/Typography/index.tsx +8 -4
  26. package/src/index.ts +16 -1
  27. package/src/components/ConfirmationCodeInput/utils/useCodeConfirmation.tsx +0 -150
@@ -0,0 +1,169 @@
1
+ 'use client'
2
+
3
+ import React, { useState } from 'react'
4
+ import { Box } from '@mui/material'
5
+ import { useAtomValue } from 'jotai'
6
+ import { columnVisibilityAtom } from '../Jotai/atom'
7
+ import { VerticalDivider } from '../VerticalDivider'
8
+ import TablePagination from '@mui/material/TablePagination'
9
+ import ManageColumn from '../ManageColumn'
10
+ import { ColumnDef } from '../Table'
11
+ import CustomButton from '../../Button'
12
+ import ShowHideEyeIcon from '@/components/Icons/ShowHideEye'
13
+
14
+ export interface CustomFooterProps {
15
+ page: number
16
+ pageSize: number
17
+ rowCount: number
18
+ onPageChange: (newPage: number) => void
19
+ onPageSizeChange: (newPageSize: number) => void
20
+ columns: ColumnDef[]
21
+ }
22
+
23
+ function CustomFooter({
24
+ page,
25
+ pageSize,
26
+ rowCount,
27
+ onPageChange,
28
+ onPageSizeChange,
29
+ columns,
30
+ }: CustomFooterProps) {
31
+ const [isOpen, setIsOpen] = useState(false)
32
+ const [checkboxWidth] = useState(45)
33
+ const columnVisibility = useAtomValue(columnVisibilityAtom)
34
+
35
+ const handleOpen = () => {
36
+ console.log('Footer handleOpen')
37
+ setIsOpen(true)
38
+ }
39
+
40
+ const handleClose = () => {
41
+ console.log('Footer handleClose')
42
+ setIsOpen(false)
43
+ }
44
+
45
+ // Calculate total width based on visible columns only
46
+ const totalWidth = columns.reduce((sum, col) => {
47
+ if (columnVisibility[col.field] !== false) {
48
+ return sum + (col.width || 150)
49
+ }
50
+ return sum
51
+ }, 0)
52
+
53
+ const totalPages = Math.ceil(rowCount / pageSize)
54
+
55
+ return (
56
+ <Box
57
+ className="custom-footer-container"
58
+ sx={{
59
+ width: `${totalWidth}px`,
60
+ minWidth: '100%',
61
+ height: '56px',
62
+ position: 'sticky',
63
+ left: 0,
64
+ marginLeft: `${checkboxWidth}px`,
65
+ }}
66
+ >
67
+ <Box
68
+ sx={{
69
+ display: 'flex',
70
+ justifyContent: 'space-between',
71
+ alignItems: 'center',
72
+ flexWrap: 'nowrap',
73
+ width: '100%',
74
+ height: '100%',
75
+ px: 2,
76
+ }}
77
+ >
78
+ <Box
79
+ sx={{
80
+ display: 'flex',
81
+ alignItems: 'center',
82
+ }}
83
+ className="left-box"
84
+ >
85
+ <Box sx={{ display: 'flex', alignItems: 'center', mr: '10px' }}>
86
+ <VerticalDivider />
87
+ </Box>
88
+ <Box
89
+ sx={{
90
+ display: 'flex',
91
+ alignItems: 'center',
92
+ gap: '8px',
93
+ pr: '8px',
94
+ }}
95
+ >
96
+ <CustomButton
97
+ onClick={handleOpen}
98
+ text="Manage Columns"
99
+ fontvariant="merriparagraph"
100
+ fontcolor="black"
101
+ icon={<ShowHideEyeIcon visible={true} />}
102
+ iconcolor="black"
103
+ iconlocation="left"
104
+ disableButton="false"
105
+ sx={{
106
+ minWidth: 'unset',
107
+ padding: '8px',
108
+ '& .MuiTypography-root': {
109
+ marginLeft: '16px',
110
+ },
111
+ }}
112
+ />
113
+ </Box>
114
+ <Box
115
+ sx={{
116
+ display: 'flex',
117
+ alignItems: 'center',
118
+ ml: '10px',
119
+ mr: '10px',
120
+ }}
121
+ >
122
+ <VerticalDivider />
123
+ </Box>
124
+ </Box>
125
+ <Box
126
+ sx={{
127
+ display: 'flex',
128
+ alignItems: 'center',
129
+ ml: 'auto',
130
+ }}
131
+ className="right-box"
132
+ >
133
+ <TablePagination
134
+ component="div"
135
+ count={rowCount}
136
+ page={page}
137
+ onPageChange={(_, newPage) => {
138
+ onPageChange(newPage)
139
+ }}
140
+ rowsPerPage={pageSize}
141
+ onRowsPerPageChange={event => {
142
+ const newPageSize = parseInt(event.target.value, 10)
143
+ onPageSizeChange(newPageSize)
144
+ }}
145
+ rowsPerPageOptions={[10, 25, 50, 100]}
146
+ slotProps={{
147
+ actions: {
148
+ previousButton: {
149
+ disabled: page === 0,
150
+ },
151
+ nextButton: {
152
+ disabled: page >= totalPages - 1,
153
+ },
154
+ },
155
+ }}
156
+ showFirstButton
157
+ showLastButton
158
+ labelDisplayedRows={({ from, to, count }) =>
159
+ `${from}-${to} of ${count !== -1 ? count : `more than ${to}`}`
160
+ }
161
+ />
162
+ </Box>
163
+ </Box>
164
+ <ManageColumn open={isOpen} handleClose={handleClose} columns={columns} />
165
+ </Box>
166
+ )
167
+ }
168
+
169
+ export default CustomFooter
@@ -0,0 +1,91 @@
1
+ import { atom } from 'jotai'
2
+ import { atomWithStorage } from 'jotai/utils'
3
+
4
+ interface ColumnVisibility {
5
+ [key: string]: boolean
6
+ }
7
+
8
+ // Create a persistent atom that saves to localStorage
9
+ export const columnVisibilityAtom = atomWithStorage<ColumnVisibility>(
10
+ 'columnVisibility',
11
+ {}
12
+ )
13
+
14
+ // Atom for managing initial column setup
15
+ export const columnsAtom = atom<string[]>([])
16
+
17
+ // Actions atom for updating visibility
18
+ export const columnVisibilityActions = atom(
19
+ null,
20
+ (
21
+ get,
22
+ set,
23
+ update: {
24
+ type: 'toggle' | 'setAll' | 'reset' | 'save'
25
+ field?: string
26
+ value?: boolean
27
+ newState?: ColumnVisibility
28
+ }
29
+ ) => {
30
+ const currentVisibility = get(columnVisibilityAtom)
31
+ const columns = get(columnsAtom)
32
+ let newVisibility: ColumnVisibility = {}
33
+
34
+ console.log('columnVisibilityActions - before:', {
35
+ type: update.type,
36
+ currentVisibility,
37
+ })
38
+
39
+ switch (update.type) {
40
+ case 'toggle': {
41
+ if (update.field) {
42
+ newVisibility = {
43
+ ...currentVisibility,
44
+ [update.field]: !currentVisibility[update.field],
45
+ }
46
+ console.log('columnVisibilityActions - toggle:', {
47
+ field: update.field,
48
+ before: currentVisibility[update.field],
49
+ after: newVisibility[update.field],
50
+ })
51
+ set(columnVisibilityAtom, newVisibility)
52
+ }
53
+ break
54
+ }
55
+
56
+ case 'setAll': {
57
+ columns.forEach(column => {
58
+ newVisibility[column] = !!update.value
59
+ })
60
+ console.log('columnVisibilityActions - setAll:', {
61
+ value: update.value,
62
+ newState: newVisibility,
63
+ })
64
+ set(columnVisibilityAtom, newVisibility)
65
+ break
66
+ }
67
+
68
+ case 'save': {
69
+ if (update.newState) {
70
+ console.log('columnVisibilityActions - save:', {
71
+ before: currentVisibility,
72
+ after: update.newState,
73
+ })
74
+ set(columnVisibilityAtom, update.newState)
75
+ }
76
+ break
77
+ }
78
+
79
+ case 'reset': {
80
+ columns.forEach(column => {
81
+ newVisibility[column] = true
82
+ })
83
+ console.log('columnVisibilityActions - reset:', newVisibility)
84
+ set(columnVisibilityAtom, newVisibility)
85
+ break
86
+ }
87
+ }
88
+
89
+ console.log('columnVisibilityActions - after:', get(columnVisibilityAtom))
90
+ }
91
+ )
@@ -0,0 +1,211 @@
1
+ 'use client'
2
+
3
+ import React from 'react'
4
+ import { Box, Popover, IconButton } from '@mui/material'
5
+ import { useManageColumn } from '../utils/useManageColumn'
6
+ import CustomButton from '../../Button'
7
+ import Searchbar from '../../Searchbar'
8
+ import Checkbox from '../../Checkbox'
9
+ import ShowHideEyeIcon from '../../Icons/ShowHideEye'
10
+ import { ColumnDef } from '../Table'
11
+ import Typography from '../../Typography'
12
+ import * as palette from '../../../styles/palette'
13
+
14
+ interface ManageColumnProps {
15
+ open?: boolean
16
+ handleClose?: () => void
17
+ columns: ColumnDef[]
18
+ }
19
+
20
+ function ManageColumns({
21
+ open = false,
22
+ handleClose = () => {},
23
+ columns,
24
+ }: ManageColumnProps) {
25
+ console.log('ManageColumns render:', { open, columns })
26
+
27
+ const {
28
+ handleAllCols,
29
+ toggleColumnState,
30
+ visibleColumns,
31
+ onSaveColumnView,
32
+ formatColumnName,
33
+ searchInput,
34
+ setSearchInput,
35
+ isAllChecked,
36
+ } = useManageColumn({
37
+ columns,
38
+ handleClose,
39
+ isPopupOpen: open,
40
+ })
41
+
42
+ const someColumnsVisible = React.useMemo(() => {
43
+ return (
44
+ columns.some(column => visibleColumns[column.field] === true) &&
45
+ !columns.every(column => visibleColumns[column.field] === true)
46
+ )
47
+ }, [columns, visibleColumns])
48
+
49
+ const handleEyeClick = (columnField: string) => {
50
+ console.log('Eye icon clicked:', {
51
+ field: columnField,
52
+ currentVisibility: visibleColumns[columnField],
53
+ allVisibility: visibleColumns,
54
+ })
55
+ toggleColumnState(columnField)
56
+ }
57
+
58
+ const handleCloseAndUpdate = () => {
59
+ console.log('handleCloseAndUpdate called')
60
+ handleClose?.()
61
+ setSearchInput('')
62
+ }
63
+
64
+ const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {
65
+ console.log('Search value changed:', e.target.value)
66
+ setSearchInput(e.target.value)
67
+ }
68
+
69
+ const filteredColumns = columns.filter(column => {
70
+ const matches = formatColumnName(column.field)
71
+ .toLowerCase()
72
+ .includes(searchInput.toLowerCase())
73
+ console.log('Filtering column:', {
74
+ field: column.field,
75
+ searchInput,
76
+ matches,
77
+ })
78
+ return matches
79
+ })
80
+
81
+ console.log('Rendering ManageColumns with:', {
82
+ filteredColumns,
83
+ searchInput,
84
+ visibleColumns,
85
+ })
86
+
87
+ const handleCheckboxChange = (event: React.ChangeEvent<HTMLInputElement>) => {
88
+ console.log('Checkbox clicked in ManageColumns:', {
89
+ checked: event.target.checked,
90
+ indeterminate: event.target.indeterminate,
91
+ eventTarget: event.target,
92
+ })
93
+ event.stopPropagation()
94
+ handleAllCols(event.target.checked)
95
+ }
96
+
97
+ return (
98
+ <Popover
99
+ id="manage-columns-popover"
100
+ open={Boolean(open)}
101
+ onClose={handleCloseAndUpdate}
102
+ anchorOrigin={{
103
+ vertical: 'center',
104
+ horizontal: 'center',
105
+ }}
106
+ transformOrigin={{
107
+ vertical: 'center',
108
+ horizontal: 'center',
109
+ }}
110
+ sx={{
111
+ '& .MuiPaper-root': {
112
+ border: `1px solid ${palette.black.main}`,
113
+ borderRadius: 2,
114
+ minWidth: '250px',
115
+ boxShadow: 24,
116
+ },
117
+ }}
118
+ >
119
+ <Box
120
+ sx={{
121
+ p: 2,
122
+ bgcolor: palette.white.main,
123
+ display: 'flex',
124
+ flexDirection: 'column',
125
+ }}
126
+ >
127
+ <Typography
128
+ text="Manage Columns"
129
+ fontvariant="merriparagraph"
130
+ fontcolor={palette.black.main}
131
+ align="center"
132
+ sx={{ mb: 0 }}
133
+ />
134
+ <Box sx={{ mt: 1, mb: 0 }}>
135
+ <Searchbar
136
+ value={searchInput}
137
+ onChange={handleSearchChange}
138
+ placeholder="Search Columns"
139
+ iconcolor={palette.black.main}
140
+ outlinecolor={palette.black.main}
141
+ />
142
+ </Box>
143
+ <Box
144
+ sx={{
145
+ display: 'flex',
146
+ alignItems: 'center',
147
+ mt: 0,
148
+ mb: 0,
149
+ justifyContent: 'space-between',
150
+ }}
151
+ >
152
+ <Typography
153
+ text="All Columns"
154
+ fontvariant="merriparagraph"
155
+ fontcolor={palette.black.main}
156
+ sx={{ fontWeight: 'bold' }}
157
+ />
158
+ <Box sx={{ marginRight: '-4px' }}>
159
+ <Checkbox
160
+ checked={isAllChecked}
161
+ indeterminate={someColumnsVisible && !isAllChecked}
162
+ onChange={handleCheckboxChange}
163
+ />
164
+ </Box>
165
+ </Box>
166
+ <Box
167
+ sx={{ maxHeight: '160px', overflowY: 'auto', marginBottom: '10px' }}
168
+ >
169
+ {filteredColumns.map((column, index) => {
170
+ const isVisible = visibleColumns[column.field] === true
171
+ console.log('Rendering column row:', {
172
+ field: column.field,
173
+ visible: isVisible,
174
+ })
175
+ return (
176
+ <Box
177
+ key={index}
178
+ sx={{ display: 'flex', alignItems: 'center', mb: 1 }}
179
+ >
180
+ <Typography
181
+ text={formatColumnName(column.field)}
182
+ fontvariant="merriparagraph"
183
+ fontcolor={palette.black.main}
184
+ sx={{ flexGrow: 1, mr: 1 }}
185
+ />
186
+ <IconButton
187
+ onClick={() => handleEyeClick(column.field)}
188
+ size="small"
189
+ >
190
+ <ShowHideEyeIcon visible={isVisible} />
191
+ </IconButton>
192
+ </Box>
193
+ )
194
+ })}
195
+ </Box>
196
+ <CustomButton
197
+ text="Save"
198
+ backgroundcolor={palette.black.main}
199
+ variant="contained"
200
+ fontcolor={palette.white.main}
201
+ fontvariant="merriparagraph"
202
+ sx={{ mt: 0 }}
203
+ fullWidth
204
+ onClick={onSaveColumnView}
205
+ />
206
+ </Box>
207
+ </Popover>
208
+ )
209
+ }
210
+
211
+ export default ManageColumns