index.tsx 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. import {
  2. useCallback,
  3. useState,
  4. } from 'react'
  5. import { useTranslation } from 'react-i18next'
  6. import { useChatWithHistoryContext } from '../context'
  7. import List from './list'
  8. import AppIcon from '@/app/components/base/app-icon'
  9. import Button from '@/app/components/base/button'
  10. import { Edit05 } from '@/app/components/base/icons/src/vender/line/general'
  11. import type { ConversationItem } from '@/models/share'
  12. import Confirm from '@/app/components/base/confirm'
  13. import RenameModal from '@/app/components/base/chat/chat-with-history/sidebar/rename-modal'
  14. const Sidebar = () => {
  15. const { t } = useTranslation()
  16. const {
  17. appData,
  18. pinnedConversationList,
  19. conversationList,
  20. handleNewConversation,
  21. currentConversationId,
  22. handleChangeConversation,
  23. handlePinConversation,
  24. handleUnpinConversation,
  25. conversationRenaming,
  26. handleRenameConversation,
  27. handleDeleteConversation,
  28. isMobile,
  29. } = useChatWithHistoryContext()
  30. const [showConfirm, setShowConfirm] = useState<ConversationItem | null>(null)
  31. const [showRename, setShowRename] = useState<ConversationItem | null>(null)
  32. const handleOperate = useCallback((type: string, item: ConversationItem) => {
  33. if (type === 'pin')
  34. handlePinConversation(item.id)
  35. if (type === 'unpin')
  36. handleUnpinConversation(item.id)
  37. if (type === 'delete')
  38. setShowConfirm(item)
  39. if (type === 'rename')
  40. setShowRename(item)
  41. }, [handlePinConversation, handleUnpinConversation])
  42. const handleCancelConfirm = useCallback(() => {
  43. setShowConfirm(null)
  44. }, [])
  45. const handleDelete = useCallback(() => {
  46. if (showConfirm)
  47. handleDeleteConversation(showConfirm.id, { onSuccess: handleCancelConfirm })
  48. }, [showConfirm, handleDeleteConversation, handleCancelConfirm])
  49. const handleCancelRename = useCallback(() => {
  50. setShowRename(null)
  51. }, [])
  52. const handleRename = useCallback((newName: string) => {
  53. if (showRename)
  54. handleRenameConversation(showRename.id, newName, { onSuccess: handleCancelRename })
  55. }, [showRename, handleRenameConversation, handleCancelRename])
  56. return (
  57. <div className='shrink-0 h-full flex flex-col w-[240px] border-r border-r-gray-100'>
  58. {
  59. !isMobile && (
  60. <div className='shrink-0 flex p-4'>
  61. <AppIcon
  62. className='mr-3'
  63. size='small'
  64. iconType={appData?.site.icon_type}
  65. icon={appData?.site.icon}
  66. background={appData?.site.icon_background}
  67. imageUrl={appData?.site.icon_url}
  68. />
  69. <div className='py-1 text-base font-semibold text-gray-800'>
  70. {appData?.site.title}
  71. </div>
  72. </div>
  73. )
  74. }
  75. <div className='shrink-0 p-4'>
  76. <Button
  77. variant='secondary-accent'
  78. className='justify-start w-full'
  79. onClick={handleNewConversation}
  80. >
  81. <Edit05 className='mr-2 w-4 h-4' />
  82. {t('share.chat.newChat')}
  83. </Button>
  84. </div>
  85. <div className='grow px-4 py-2 overflow-y-auto'>
  86. {
  87. !!pinnedConversationList.length && (
  88. <div className='mb-4'>
  89. <List
  90. isPin
  91. title={t('share.chat.pinnedTitle') || ''}
  92. list={pinnedConversationList}
  93. onChangeConversation={handleChangeConversation}
  94. onOperate={handleOperate}
  95. currentConversationId={currentConversationId}
  96. />
  97. </div>
  98. )
  99. }
  100. {
  101. !!conversationList.length && (
  102. <List
  103. title={(pinnedConversationList.length && t('share.chat.unpinnedTitle')) || ''}
  104. list={conversationList}
  105. onChangeConversation={handleChangeConversation}
  106. onOperate={handleOperate}
  107. currentConversationId={currentConversationId}
  108. />
  109. )
  110. }
  111. </div>
  112. <div className='px-4 pb-4 text-xs text-gray-400'>
  113. © {appData?.site.copyright || appData?.site.title} {(new Date()).getFullYear()}
  114. </div>
  115. {!!showConfirm && (
  116. <Confirm
  117. title={t('share.chat.deleteConversation.title')}
  118. content={t('share.chat.deleteConversation.content') || ''}
  119. isShow
  120. onCancel={handleCancelConfirm}
  121. onConfirm={handleDelete}
  122. />
  123. )}
  124. {showRename && (
  125. <RenameModal
  126. isShow
  127. onClose={handleCancelRename}
  128. saveLoading={conversationRenaming}
  129. name={showRename?.name || ''}
  130. onSave={handleRename}
  131. />
  132. )}
  133. </div>
  134. )
  135. }
  136. export default Sidebar