Skip to content

Commit da2ba09

Browse files
committed
refactor: optimize states in users context
1 parent 47ec344 commit da2ba09

File tree

5 files changed

+95
-79
lines changed

5 files changed

+95
-79
lines changed

src/features/users/components/data-table-row-actions.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@ import {
1010
DropdownMenuShortcut,
1111
DropdownMenuTrigger,
1212
} from '@/components/ui/dropdown-menu'
13-
import { useUsersContext } from '../context/users-context'
13+
import { useUsers } from '../context/users-context'
1414
import { User } from '../data/schema'
1515

1616
interface DataTableRowActionsProps {
1717
row: Row<User>
1818
}
1919

2020
export function DataTableRowActions({ row }: DataTableRowActionsProps) {
21-
const { setOpen, setCurrentRow } = useUsersContext()
21+
const { setOpen, setCurrentRow } = useUsers()
2222
return (
2323
<>
2424
<DropdownMenu modal={false}>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { useUsers } from '../context/users-context'
2+
import { UsersActionDialog } from './users-action-dialog'
3+
import { UsersDeleteDialog } from './users-delete-dialog'
4+
import { UsersInviteDialog } from './users-invite-dialog'
5+
6+
export function UsersDialogs() {
7+
const { open, setOpen, currentRow, setCurrentRow } = useUsers()
8+
return (
9+
<>
10+
<UsersActionDialog
11+
key='user-add'
12+
open={open === 'add'}
13+
onOpenChange={() => setOpen('add')}
14+
/>
15+
16+
<UsersInviteDialog
17+
key='user-invite'
18+
open={open === 'invite'}
19+
onOpenChange={() => setOpen('invite')}
20+
/>
21+
22+
{currentRow && (
23+
<>
24+
<UsersActionDialog
25+
key={`user-edit-${currentRow.id}`}
26+
open={open === 'edit'}
27+
onOpenChange={() => {
28+
setOpen('edit')
29+
setTimeout(() => {
30+
setCurrentRow(null)
31+
}, 500)
32+
}}
33+
currentRow={currentRow}
34+
/>
35+
36+
<UsersDeleteDialog
37+
key={`user-delete-${currentRow.id}`}
38+
open={open === 'delete'}
39+
onOpenChange={() => {
40+
setOpen('delete')
41+
setTimeout(() => {
42+
setCurrentRow(null)
43+
}, 500)
44+
}}
45+
currentRow={currentRow}
46+
/>
47+
</>
48+
)}
49+
</>
50+
)
51+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { IconMailPlus, IconUserPlus } from '@tabler/icons-react'
2+
import { Button } from '@/components/ui/button'
3+
import { useUsers } from '../context/users-context'
4+
5+
export function UsersPrimaryButtons() {
6+
const { setOpen } = useUsers()
7+
return (
8+
<div className='flex gap-2'>
9+
<Button
10+
variant='outline'
11+
className='space-x-1'
12+
onClick={() => setOpen('invite')}
13+
>
14+
<span>Invite User</span> <IconMailPlus size={18} />
15+
</Button>
16+
<Button className='space-x-1' onClick={() => setOpen('add')}>
17+
<span>Add User</span> <IconUserPlus size={18} />
18+
</Button>
19+
</div>
20+
)
21+
}

src/features/users/context/users-context.tsx

+13-8
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import React from 'react'
1+
import React, { useState } from 'react'
2+
import useDialogState from '@/hooks/use-dialog-state'
23
import { User } from '../data/schema'
34

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

1516
interface Props {
1617
children: React.ReactNode
17-
value: UsersContextType
1818
}
1919

20-
export default function UsersContextProvider({ children, value }: Props) {
21-
return <UsersContext.Provider value={value}>{children}</UsersContext.Provider>
20+
export default function UsersProvider({ children }: Props) {
21+
const [open, setOpen] = useDialogState<UsersDialogType>(null)
22+
const [currentRow, setCurrentRow] = useState<User | null>(null)
23+
24+
return (
25+
<UsersContext value={{ open, setOpen, currentRow, setCurrentRow }}>
26+
{children}
27+
</UsersContext>
28+
)
2229
}
2330

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

2835
if (!usersContext) {
29-
throw new Error(
30-
'useUsersContext has to be used within <UsersContext.Provider>'
31-
)
36+
throw new Error('useUsers has to be used within <UsersContext>')
3237
}
3338

3439
return usersContext

src/features/users/index.tsx

+8-69
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,22 @@
1-
import { useState } from 'react'
2-
import { IconMailPlus, IconUserPlus } from '@tabler/icons-react'
3-
import useDialogState from '@/hooks/use-dialog-state'
4-
import { Button } from '@/components/ui/button'
51
import { Header } from '@/components/layout/header'
62
import { Main } from '@/components/layout/main'
73
import { ProfileDropdown } from '@/components/profile-dropdown'
84
import { Search } from '@/components/search'
95
import { ThemeSwitch } from '@/components/theme-switch'
10-
import { UsersActionDialog } from './components/users-action-dialog'
116
import { columns } from './components/users-columns'
12-
import { UsersDeleteDialog } from './components/users-delete-dialog'
13-
import { UsersInviteDialog } from './components/users-invite-dialog'
7+
import { UsersDialogs } from './components/users-dialogs'
8+
import { UsersPrimaryButtons } from './components/users-primary-buttons'
149
import { UsersTable } from './components/users-table'
15-
import UsersContextProvider, {
16-
type UsersDialogType,
17-
} from './context/users-context'
18-
import { User, userListSchema } from './data/schema'
10+
import UsersProvider from './context/users-context'
11+
import { userListSchema } from './data/schema'
1912
import { users } from './data/users'
2013

2114
export default function Users() {
22-
// Dialog states
23-
const [currentRow, setCurrentRow] = useState<User | null>(null)
24-
const [open, setOpen] = useDialogState<UsersDialogType>(null)
25-
2615
// Parse user list
2716
const userList = userListSchema.parse(users)
2817

2918
return (
30-
<UsersContextProvider value={{ open, setOpen, currentRow, setCurrentRow }}>
31-
{/* ===== Top Heading ===== */}
19+
<UsersProvider>
3220
<Header fixed>
3321
<Search />
3422
<div className='ml-auto flex items-center space-x-4'>
@@ -45,63 +33,14 @@ export default function Users() {
4533
Manage your users and their roles here.
4634
</p>
4735
</div>
48-
<div className='flex gap-2'>
49-
<Button
50-
variant='outline'
51-
className='space-x-1'
52-
onClick={() => setOpen('invite')}
53-
>
54-
<span>Invite User</span> <IconMailPlus size={18} />
55-
</Button>
56-
<Button className='space-x-1' onClick={() => setOpen('add')}>
57-
<span>Add User</span> <IconUserPlus size={18} />
58-
</Button>
59-
</div>
36+
<UsersPrimaryButtons />
6037
</div>
6138
<div className='-mx-4 flex-1 overflow-auto px-4 py-1 lg:flex-row lg:space-x-12 lg:space-y-0'>
6239
<UsersTable data={userList} columns={columns} />
6340
</div>
6441
</Main>
6542

66-
<UsersActionDialog
67-
key='user-add'
68-
open={open === 'add'}
69-
onOpenChange={() => setOpen('add')}
70-
/>
71-
72-
<UsersInviteDialog
73-
key='user-invite'
74-
open={open === 'invite'}
75-
onOpenChange={() => setOpen('invite')}
76-
/>
77-
78-
{currentRow && (
79-
<>
80-
<UsersActionDialog
81-
key={`user-edit-${currentRow.id}`}
82-
open={open === 'edit'}
83-
onOpenChange={() => {
84-
setOpen('edit')
85-
setTimeout(() => {
86-
setCurrentRow(null)
87-
}, 500)
88-
}}
89-
currentRow={currentRow}
90-
/>
91-
92-
<UsersDeleteDialog
93-
key={`user-delete-${currentRow.id}`}
94-
open={open === 'delete'}
95-
onOpenChange={() => {
96-
setOpen('delete')
97-
setTimeout(() => {
98-
setCurrentRow(null)
99-
}, 500)
100-
}}
101-
currentRow={currentRow}
102-
/>
103-
</>
104-
)}
105-
</UsersContextProvider>
43+
<UsersDialogs />
44+
</UsersProvider>
10645
)
10746
}

0 commit comments

Comments
 (0)