index.tsx 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  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/button'
  5. import { Header } from '@/components/layout/header'
  6. import { Main } from '@/components/layout/main'
  7. import { ProfileDropdown } from '@/components/profile-dropdown'
  8. import { Search } from '@/components/search'
  9. import { ThemeSwitch } from '@/components/theme-switch'
  10. import { UsersActionDialog } from './components/users-action-dialog'
  11. import { columns } from './components/users-columns'
  12. import { UsersDeleteDialog } from './components/users-delete-dialog'
  13. import { UsersInviteDialog } from './components/users-invite-dialog'
  14. import { UsersTable } from './components/users-table'
  15. import UsersContextProvider, {
  16. type UsersDialogType,
  17. } from './context/users-context'
  18. import { User, userListSchema } from './data/schema'
  19. import { users } from './data/users'
  20. export default function Users() {
  21. // Dialog states
  22. const [currentRow, setCurrentRow] = useState<User | null>(null)
  23. const [open, setOpen] = useDialogState<UsersDialogType>(null)
  24. // Parse user list
  25. const userList = userListSchema.parse(users)
  26. return (
  27. <UsersContextProvider value={{ open, setOpen, currentRow, setCurrentRow }}>
  28. {/* ===== Top Heading ===== */}
  29. <Header sticky>
  30. <Search />
  31. <div className='ml-auto flex items-center space-x-4'>
  32. <ThemeSwitch />
  33. <ProfileDropdown />
  34. </div>
  35. </Header>
  36. <Main>
  37. <div className='mb-2 flex items-center justify-between space-y-2 flex-wrap'>
  38. <div>
  39. <h2 className='text-2xl font-bold tracking-tight'>User List</h2>
  40. <p className='text-muted-foreground'>
  41. Manage your users and their roles here.
  42. </p>
  43. </div>
  44. <div className='flex gap-2'>
  45. <Button
  46. variant='outline'
  47. className='space-x-1'
  48. onClick={() => setOpen('invite')}
  49. >
  50. <span>Invite User</span> <IconMailPlus />
  51. </Button>
  52. <Button className='space-x-1' onClick={() => setOpen('add')}>
  53. <span>Add User</span> <IconUserPlus />
  54. </Button>
  55. </div>
  56. </div>
  57. <div className='-mx-4 flex-1 overflow-auto px-4 py-1 lg:flex-row lg:space-x-12 lg:space-y-0'>
  58. <UsersTable data={userList} columns={columns} />
  59. </div>
  60. </Main>
  61. <UsersActionDialog
  62. key='user-add'
  63. open={open === 'add'}
  64. onOpenChange={() => setOpen('add')}
  65. />
  66. <UsersInviteDialog
  67. key='user-invite'
  68. open={open === 'invite'}
  69. onOpenChange={() => setOpen('invite')}
  70. />
  71. {currentRow && (
  72. <>
  73. <UsersActionDialog
  74. key={`user-edit-${currentRow.id}`}
  75. open={open === 'edit'}
  76. onOpenChange={() => {
  77. setCurrentRow(null)
  78. setOpen('edit')
  79. }}
  80. currentRow={currentRow}
  81. />
  82. <UsersDeleteDialog
  83. key={`user-delete-${currentRow.id}`}
  84. open={open === 'delete'}
  85. onOpenChange={() => {
  86. setCurrentRow(null)
  87. setOpen('delete')
  88. }}
  89. currentRow={currentRow}
  90. />
  91. </>
  92. )}
  93. </UsersContextProvider>
  94. )
  95. }