Skip to content

Commit

Permalink
refactor: optimize states in users context
Browse files Browse the repository at this point in the history
  • Loading branch information
satnaing committed Dec 26, 2024
1 parent 47ec344 commit da2ba09
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 79 deletions.
4 changes: 2 additions & 2 deletions src/features/users/components/data-table-row-actions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ import {
DropdownMenuShortcut,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu'
import { useUsersContext } from '../context/users-context'
import { useUsers } from '../context/users-context'
import { User } from '../data/schema'

interface DataTableRowActionsProps {
row: Row<User>
}

export function DataTableRowActions({ row }: DataTableRowActionsProps) {
const { setOpen, setCurrentRow } = useUsersContext()
const { setOpen, setCurrentRow } = useUsers()
return (
<>
<DropdownMenu modal={false}>
Expand Down
51 changes: 51 additions & 0 deletions src/features/users/components/users-dialogs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { useUsers } from '../context/users-context'
import { UsersActionDialog } from './users-action-dialog'
import { UsersDeleteDialog } from './users-delete-dialog'
import { UsersInviteDialog } from './users-invite-dialog'

export function UsersDialogs() {
const { open, setOpen, currentRow, setCurrentRow } = useUsers()
return (
<>
<UsersActionDialog
key='user-add'
open={open === 'add'}
onOpenChange={() => setOpen('add')}
/>

<UsersInviteDialog
key='user-invite'
open={open === 'invite'}
onOpenChange={() => setOpen('invite')}
/>

{currentRow && (
<>
<UsersActionDialog
key={`user-edit-${currentRow.id}`}
open={open === 'edit'}
onOpenChange={() => {
setOpen('edit')
setTimeout(() => {
setCurrentRow(null)
}, 500)
}}
currentRow={currentRow}
/>

<UsersDeleteDialog
key={`user-delete-${currentRow.id}`}
open={open === 'delete'}
onOpenChange={() => {
setOpen('delete')
setTimeout(() => {
setCurrentRow(null)
}, 500)
}}
currentRow={currentRow}
/>
</>
)}
</>
)
}
21 changes: 21 additions & 0 deletions src/features/users/components/users-primary-buttons.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { IconMailPlus, IconUserPlus } from '@tabler/icons-react'
import { Button } from '@/components/ui/button'
import { useUsers } from '../context/users-context'

export function UsersPrimaryButtons() {
const { setOpen } = useUsers()
return (
<div className='flex gap-2'>
<Button
variant='outline'
className='space-x-1'
onClick={() => setOpen('invite')}
>
<span>Invite User</span> <IconMailPlus size={18} />
</Button>
<Button className='space-x-1' onClick={() => setOpen('add')}>
<span>Add User</span> <IconUserPlus size={18} />
</Button>
</div>
)
}
21 changes: 13 additions & 8 deletions src/features/users/context/users-context.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React from 'react'
import React, { useState } from 'react'
import useDialogState from '@/hooks/use-dialog-state'
import { User } from '../data/schema'

export type UsersDialogType = 'invite' | 'add' | 'edit' | 'delete'
Expand All @@ -14,21 +15,25 @@ const UsersContext = React.createContext<UsersContextType | null>(null)

interface Props {
children: React.ReactNode
value: UsersContextType
}

export default function UsersContextProvider({ children, value }: Props) {
return <UsersContext.Provider value={value}>{children}</UsersContext.Provider>
export default function UsersProvider({ children }: Props) {
const [open, setOpen] = useDialogState<UsersDialogType>(null)
const [currentRow, setCurrentRow] = useState<User | null>(null)

return (
<UsersContext value={{ open, setOpen, currentRow, setCurrentRow }}>
{children}
</UsersContext>
)
}

// eslint-disable-next-line react-refresh/only-export-components
export const useUsersContext = () => {
export const useUsers = () => {
const usersContext = React.useContext(UsersContext)

if (!usersContext) {
throw new Error(
'useUsersContext has to be used within <UsersContext.Provider>'
)
throw new Error('useUsers has to be used within <UsersContext>')
}

return usersContext
Expand Down
77 changes: 8 additions & 69 deletions src/features/users/index.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,22 @@
import { useState } from 'react'
import { IconMailPlus, IconUserPlus } from '@tabler/icons-react'
import useDialogState from '@/hooks/use-dialog-state'
import { Button } from '@/components/ui/button'
import { Header } from '@/components/layout/header'
import { Main } from '@/components/layout/main'
import { ProfileDropdown } from '@/components/profile-dropdown'
import { Search } from '@/components/search'
import { ThemeSwitch } from '@/components/theme-switch'
import { UsersActionDialog } from './components/users-action-dialog'
import { columns } from './components/users-columns'
import { UsersDeleteDialog } from './components/users-delete-dialog'
import { UsersInviteDialog } from './components/users-invite-dialog'
import { UsersDialogs } from './components/users-dialogs'
import { UsersPrimaryButtons } from './components/users-primary-buttons'
import { UsersTable } from './components/users-table'
import UsersContextProvider, {
type UsersDialogType,
} from './context/users-context'
import { User, userListSchema } from './data/schema'
import UsersProvider from './context/users-context'
import { userListSchema } from './data/schema'
import { users } from './data/users'

export default function Users() {
// Dialog states
const [currentRow, setCurrentRow] = useState<User | null>(null)
const [open, setOpen] = useDialogState<UsersDialogType>(null)

// Parse user list
const userList = userListSchema.parse(users)

return (
<UsersContextProvider value={{ open, setOpen, currentRow, setCurrentRow }}>
{/* ===== Top Heading ===== */}
<UsersProvider>
<Header fixed>
<Search />
<div className='ml-auto flex items-center space-x-4'>
Expand All @@ -45,63 +33,14 @@ export default function Users() {
Manage your users and their roles here.
</p>
</div>
<div className='flex gap-2'>
<Button
variant='outline'
className='space-x-1'
onClick={() => setOpen('invite')}
>
<span>Invite User</span> <IconMailPlus size={18} />
</Button>
<Button className='space-x-1' onClick={() => setOpen('add')}>
<span>Add User</span> <IconUserPlus size={18} />
</Button>
</div>
<UsersPrimaryButtons />
</div>
<div className='-mx-4 flex-1 overflow-auto px-4 py-1 lg:flex-row lg:space-x-12 lg:space-y-0'>
<UsersTable data={userList} columns={columns} />
</div>
</Main>

<UsersActionDialog
key='user-add'
open={open === 'add'}
onOpenChange={() => setOpen('add')}
/>

<UsersInviteDialog
key='user-invite'
open={open === 'invite'}
onOpenChange={() => setOpen('invite')}
/>

{currentRow && (
<>
<UsersActionDialog
key={`user-edit-${currentRow.id}`}
open={open === 'edit'}
onOpenChange={() => {
setOpen('edit')
setTimeout(() => {
setCurrentRow(null)
}, 500)
}}
currentRow={currentRow}
/>

<UsersDeleteDialog
key={`user-delete-${currentRow.id}`}
open={open === 'delete'}
onOpenChange={() => {
setOpen('delete')
setTimeout(() => {
setCurrentRow(null)
}, 500)
}}
currentRow={currentRow}
/>
</>
)}
</UsersContextProvider>
<UsersDialogs />
</UsersProvider>
)
}

0 comments on commit da2ba09

Please sign in to comment.