index.tsx 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. 'use client'
  2. import { useTranslation } from 'react-i18next'
  3. import { Fragment } from 'react'
  4. import { useSWRConfig } from 'swr'
  5. import {
  6. RiDeleteBinLine,
  7. RiLoopLeftLine,
  8. RiMoreFill,
  9. RiStickyNoteAddLine,
  10. } from '@remixicon/react'
  11. import { Menu, Transition } from '@headlessui/react'
  12. import { syncDataSourceNotion, updateDataSourceNotionAction } from '@/service/common'
  13. import Toast from '@/app/components/base/toast'
  14. type OperateProps = {
  15. payload: {
  16. id: string
  17. total: number
  18. }
  19. onAuthAgain: () => void
  20. }
  21. export default function Operate({
  22. payload,
  23. onAuthAgain,
  24. }: OperateProps) {
  25. const itemClassName = `
  26. flex px-3 py-2 hover:bg-gray-50 text-sm text-gray-700
  27. cursor-pointer
  28. `
  29. const itemIconClassName = `
  30. mr-2 mt-[2px] w-4 h-4 text-gray-500
  31. `
  32. const { t } = useTranslation()
  33. const { mutate } = useSWRConfig()
  34. const updateIntegrates = () => {
  35. Toast.notify({
  36. type: 'success',
  37. message: t('common.api.success'),
  38. })
  39. mutate({ url: 'data-source/integrates' })
  40. }
  41. const handleSync = async () => {
  42. await syncDataSourceNotion({ url: `/oauth/data-source/notion/${payload.id}/sync` })
  43. updateIntegrates()
  44. }
  45. const handleRemove = async () => {
  46. await updateDataSourceNotionAction({ url: `/data-source/integrates/${payload.id}/disable` })
  47. updateIntegrates()
  48. }
  49. return (
  50. <Menu as="div" className="relative inline-block text-left">
  51. {
  52. ({ open }) => (
  53. <>
  54. <Menu.Button className={`flex items-center justify-center w-8 h-8 rounded-lg hover:bg-gray-100 ${open && 'bg-gray-100'}`}>
  55. <RiMoreFill className='w-4 h-4' />
  56. </Menu.Button>
  57. <Transition
  58. as={Fragment}
  59. enter="transition ease-out duration-100"
  60. enterFrom="transform opacity-0 scale-95"
  61. enterTo="transform opacity-100 scale-100"
  62. leave="transition ease-in duration-75"
  63. leaveFrom="transform opacity-100 scale-100"
  64. leaveTo="transform opacity-0 scale-95"
  65. >
  66. <Menu.Items
  67. className="
  68. absolute right-0 top-9 w-60 max-w-80
  69. divide-y divide-gray-100 origin-top-right rounded-lg bg-white
  70. shadow-lg
  71. "
  72. >
  73. <div className="px-1 py-1">
  74. <Menu.Item>
  75. <div
  76. className={itemClassName}
  77. onClick={onAuthAgain}
  78. >
  79. <RiStickyNoteAddLine className={itemIconClassName} />
  80. <div>
  81. <div className='leading-5'>{t('common.dataSource.notion.changeAuthorizedPages')}</div>
  82. <div className='leading-5 text-xs text-gray-500'>
  83. {payload.total} {t('common.dataSource.notion.pagesAuthorized')}
  84. </div>
  85. </div>
  86. </div>
  87. </Menu.Item>
  88. <Menu.Item>
  89. <div className={itemClassName} onClick={handleSync}>
  90. <RiLoopLeftLine className={itemIconClassName} />
  91. <div className='leading-5'>{t('common.dataSource.notion.sync')}</div>
  92. </div>
  93. </Menu.Item>
  94. </div>
  95. <Menu.Item>
  96. <div className='p-1'>
  97. <div className={itemClassName} onClick={handleRemove}>
  98. <RiDeleteBinLine className={itemIconClassName} />
  99. <div className='leading-5'>{t('common.dataSource.notion.remove')}</div>
  100. </div>
  101. </div>
  102. </Menu.Item>
  103. </Menu.Items>
  104. </Transition>
  105. </>
  106. )
  107. }
  108. </Menu>
  109. )
  110. }