Skip to content

Commit

Permalink
feat(tables): separate users table and datatable logic
Browse files Browse the repository at this point in the history
  • Loading branch information
baaalint committed Sep 4, 2024
1 parent dad2e73 commit ba15e16
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 91 deletions.
3 changes: 3 additions & 0 deletions ui/src/atoms/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ export const usernameAtom = atom<string>('');
export const selectedUserAtom = atom<User>({ username: '', admin: false, token: '' });
export const comparisonUserAtom = atom<User>({ username: '', admin: false, token: '' });

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const selectedRowAtom = atom<any>({});


export const usersAtom = atom<DataRow<User>[]>([]);
export const createUserAtom = atom(
Expand Down
103 changes: 93 additions & 10 deletions ui/src/components/feature/UsersTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,21 @@
// limitations under the License.

import { usersAtom, usersWithFetchAtom } from '@atoms/apiAtoms'
import { selectedRowAtom } from '@atoms/index'
import { AddIcon, DeleteIcon } from '@chakra-ui/icons'
import { Button, Flex, useDisclosure, useToast } from '@chakra-ui/react'
import {
Button,
Drawer,
DrawerBody,
DrawerContent,
DrawerHeader,
Flex,
FormControl,
FormLabel,
Input,
useDisclosure,
useToast
} from '@chakra-ui/react'
import Breadcrumbs from '@components/shared/Breadcrumbs'
import DataTableComponent from '@components/shared/Datatable'
import FilterComponent from '@components/shared/Filter'
Expand All @@ -27,13 +40,11 @@ import AddEditUserModal from './AddEditUserModal'

const UsersTable: React.FC = () => {
const [selectedRows, setSelectedRows] = useState<User[]>([])
const [, fetchUsers] = useAtom(usersWithFetchAtom)

const [selectedRow, setSelectedRow] = useAtom(selectedRowAtom)
const [editRow, setEditRow] = useState<User>({ name: '', email: '', full_name: '' })
const [filterText, setFilterText] = useState('')
const [toggledClearRows, setToggleClearRows] = useState(false)

const { isOpen, onOpen, onClose } = useDisclosure()
const toast = useToast()
const [users] = useAtom(usersAtom)

const [columns] = useState([
Expand All @@ -42,6 +53,13 @@ const UsersTable: React.FC = () => {
{ name: 'Full Name', selector: (row: Partial<User>) => row.full_name ?? '', sortable: true }
])

const [, fetchUsers] = useAtom(usersWithFetchAtom)

const { isOpen: isModalOpen, onOpen: onModalOpen, onClose: onModalClose } = useDisclosure()
const { isOpen: isDrawerOpen, onOpen: onDrawerOpen, onClose: onDrawerClose } = useDisclosure()

const toast = useToast()

useEffect(() => {
fetchUsers()
}, [fetchUsers])
Expand All @@ -56,13 +74,17 @@ const UsersTable: React.FC = () => {
toast({ title: 'User added successfully.', status: 'success', duration: 3000, isClosable: true })
}
await fetchUsers()
onClose()
onDrawerClose()
} catch (error) {
console.error('Error saving user:', error)
toast({ title: 'Error saving user.', status: 'error', duration: 3000, isClosable: true })
}
}

const handleClearRows = useCallback(() => {
setToggleClearRows(!toggledClearRows)
}, [toggledClearRows])

const handleDelete = useCallback(async () => {
try {
await Promise.all(selectedRows.map(row => Client.deleteUser(row.name as string)))
Expand All @@ -73,7 +95,36 @@ const UsersTable: React.FC = () => {
console.error('Error deleting users:', error)
toast({ title: 'Error deleting users.', status: 'error', duration: 3000, isClosable: true })
}
}, [fetchUsers, selectedRows, toast])
handleClearRows()
}, [fetchUsers, selectedRows, toast, handleClearRows])

const handleUpdate = async () => {
try {
await Client.updateUser(selectedRow)
toast({
title: 'User updated.',
description: 'The user has been updated successfully.',
status: 'success',
duration: 3000,
isClosable: true
})
await fetchUsers()
onDrawerClose()
} catch (error) {
toast({
title: 'Error updating user.',
description: 'There was an error updating the user.',
status: 'error',
duration: 3000,
isClosable: true
})
}
}

const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const { name, value } = e.target
setSelectedRow({ ...selectedRow, [name]: value })
}

const contextActions = useMemo(
() => (
Expand All @@ -92,7 +143,7 @@ const UsersTable: React.FC = () => {
leftIcon={<AddIcon />}
onClick={() => {
setEditRow({ name: '', email: '', full_name: '' })
onOpen()
onModalOpen()
}}
>
New
Expand All @@ -115,11 +166,43 @@ const UsersTable: React.FC = () => {
data={users}
columns={columns as TableColumn<Partial<User>>[]}
contextActions={contextActions}
onSelectedRowChange={e => setSelectedRows(e.selectedRows)}
onSelectedRowChange={e => {
setSelectedRows(e.selectedRows)
}}
subheaderComponent={subHeaderComponentMemo}
filterText={filterText}
onOpenDrawer={() => {
onDrawerOpen()
}}
toggleClearRows={toggledClearRows}
/>
<AddEditUserModal isOpen={isOpen} onClose={onClose} onSave={handleSave} user={editRow} />
<AddEditUserModal isOpen={isModalOpen} onClose={onModalClose} onSave={handleSave} user={editRow} />
<Drawer placement="right" size={'xl'} isOpen={isDrawerOpen} onClose={onDrawerClose}>
<DrawerContent>
<DrawerHeader borderBottomWidth="1px">{selectedRow?.name} </DrawerHeader>
<DrawerBody>
<Flex height={250} gap={10}>
<Flex width={'100%'} flexDirection={'column'}>
<FormControl id="name" mb={4}>
<FormLabel>Name</FormLabel>
<Input type="text" name="name" value={selectedRow.name || ''} onChange={handleChange} />
</FormControl>
<FormControl id="email" mb={4}>
<FormLabel>Email</FormLabel>
<Input type="email" name="email" value={selectedRow.email || ''} onChange={handleChange} />
</FormControl>
<FormControl id="full_name" mb={4}>
<FormLabel>Full Name</FormLabel>
<Input type="text" name="full_name" value={selectedRow.full_name || ''} onChange={handleChange} />
</FormControl>
</Flex>
</Flex>
<Button marginTop={4} onClick={handleUpdate}>
Save changes
</Button>
</DrawerBody>
</DrawerContent>
</Drawer>
</Flex>
)
}
Expand Down
91 changes: 10 additions & 81 deletions ui/src/components/shared/Datatable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import { usersWithFetchAtom } from '@atoms/apiAtoms'
import { selectedUserAtom } from '@atoms/index'
import {
Box,
Button,
Drawer,
DrawerBody,
DrawerContent,
DrawerHeader,
Flex,
FormControl,
FormLabel,
Input,
useColorMode,
useDisclosure,
useToast
} from '@chakra-ui/react'
import Client from '@services/Api'
import { selectedRowAtom } from '@atoms/index'
import { Box, useColorMode } from '@chakra-ui/react'
import { colors } from '@shared/theme'
import { User } from '@shared/types'
import { useAtom } from 'jotai'
Expand Down Expand Up @@ -73,6 +57,8 @@ type Props = {
subheaderComponent?: React.ReactNode
filterText: string
user?: User
toggleClearRows: boolean
onOpenDrawer: () => void
}

const DataTableComponent = ({
Expand All @@ -82,18 +68,15 @@ const DataTableComponent = ({
contextActions,
onSelectedRowChange,
subheaderComponent,
filterText
filterText,
onOpenDrawer,
toggleClearRows
}: Props) => {
const { colorMode } = useColorMode()
const { isOpen, onOpen, onClose } = useDisclosure()
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const [selectedRow, setSelectedRow] = useState<Partial<any> | null>(null)
const [selectedUser, setSelectedUser] = useAtom<User>(selectedUserAtom)
const [, setSelectedRow] = useAtom<any>(selectedRowAtom)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const [filteredItems, setFilteredItems] = useState<Partial<any>[]>(data)
const [, fetchUsers] = useAtom(usersWithFetchAtom)

const toast = useToast()

useEffect(() => {
if (data) {
Expand All @@ -108,34 +91,6 @@ const DataTableComponent = ({
}
}, [filterText, data])

const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const { name, value } = e.target
setSelectedUser({ ...selectedUser, [name]: value })
}

const handleUpdateUser = async () => {
try {
await Client.updateUser(selectedUser)
toast({
title: 'User updated.',
description: 'The user has been updated successfully.',
status: 'success',
duration: 3000,
isClosable: true
})
await fetchUsers()
onClose()
} catch (error) {
toast({
title: 'Error updating user.',
description: 'There was an error updating the user.',
status: 'error',
duration: 3000,
isClosable: true
})
}
}

return (
<>
<Box boxShadow="md" borderRadius="md">
Expand All @@ -155,39 +110,13 @@ const DataTableComponent = ({
contextActions={contextActions}
highlightOnHover
pointerOnHover
clearSelectedRows={toggleClearRows}
onRowClicked={row => {
setSelectedRow(row)
setSelectedUser(row)
onOpen()
onOpenDrawer()
}}
/>
</Box>
<Drawer placement="right" size={'xl'} isOpen={isOpen} onClose={onClose}>
<DrawerContent>
<DrawerHeader borderBottomWidth="1px">{selectedUser?.name} </DrawerHeader>
<DrawerBody>
<Flex height={250} gap={10}>
<Flex width={'100%'} flexDirection={'column'}>
<FormControl id="name" mb={4}>
<FormLabel>Name</FormLabel>
<Input type="text" name="name" value={selectedUser.name || ''} onChange={handleChange} />
</FormControl>
<FormControl id="email" mb={4}>
<FormLabel>Email</FormLabel>
<Input type="email" name="email" value={selectedUser.email || ''} onChange={handleChange} />
</FormControl>
<FormControl id="full_name" mb={4}>
<FormLabel>Full Name</FormLabel>
<Input type="text" name="full_name" value={selectedUser.full_name || ''} onChange={handleChange} />
</FormControl>
</Flex>
</Flex>
<Button marginTop={4} onClick={handleUpdateUser}>
Save changes
</Button>
</DrawerBody>
</DrawerContent>
</Drawer>
</>
)
}
Expand Down

0 comments on commit ba15e16

Please sign in to comment.