| import { useCallback, useEffect, useMemo, useState } from 'react' | |
| import useSWR from 'swr' | |
| import s from './base.module.css' | |
| import WorkspaceSelector from './workspace-selector' | |
| import SearchInput from './search-input' | |
| import PageSelector from './page-selector' | |
| import cn from '@/utils/classnames' | |
| import { preImportNotionPages } from '@/service/datasets' | |
| import { NotionConnector } from '@/app/components/datasets/create/step-one' | |
| import type { DataSourceNotionPageMap, DataSourceNotionWorkspace, NotionPage } from '@/models/common' | |
| import { useModalContext } from '@/context/modal-context' | |
| type NotionPageSelectorProps = { | |
| value?: string[] | |
| onSelect: (selectedPages: NotionPage[]) => void | |
| canPreview?: boolean | |
| previewPageId?: string | |
| onPreview?: (selectedPage: NotionPage) => void | |
| datasetId?: string | |
| } | |
| const NotionPageSelector = ({ | |
| value, | |
| onSelect, | |
| canPreview, | |
| previewPageId, | |
| onPreview, | |
| datasetId = '', | |
| }: NotionPageSelectorProps) => { | |
| const { data, mutate } = useSWR({ url: '/notion/pre-import/pages', datasetId }, preImportNotionPages) | |
| const [prevData, setPrevData] = useState(data) | |
| const [searchValue, setSearchValue] = useState('') | |
| const [currentWorkspaceId, setCurrentWorkspaceId] = useState('') | |
| const { setShowAccountSettingModal } = useModalContext() | |
| const notionWorkspaces = useMemo(() => { | |
| return data?.notion_info || [] | |
| }, [data?.notion_info]) | |
| const firstWorkspaceId = notionWorkspaces[0]?.workspace_id | |
| const currentWorkspace = notionWorkspaces.find(workspace => workspace.workspace_id === currentWorkspaceId) | |
| const getPagesMapAndSelectedPagesId: [DataSourceNotionPageMap, Set<string>, Set<string>] = useMemo(() => { | |
| const selectedPagesId = new Set<string>() | |
| const boundPagesId = new Set<string>() | |
| const pagesMap = notionWorkspaces.reduce((prev: DataSourceNotionPageMap, next: DataSourceNotionWorkspace) => { | |
| next.pages.forEach((page) => { | |
| if (page.is_bound) { | |
| selectedPagesId.add(page.page_id) | |
| boundPagesId.add(page.page_id) | |
| } | |
| prev[page.page_id] = { | |
| ...page, | |
| workspace_id: next.workspace_id, | |
| } | |
| }) | |
| return prev | |
| }, {}) | |
| return [pagesMap, selectedPagesId, boundPagesId] | |
| }, [notionWorkspaces]) | |
| const defaultSelectedPagesId = [...Array.from(getPagesMapAndSelectedPagesId[1]), ...(value || [])] | |
| const [selectedPagesId, setSelectedPagesId] = useState<Set<string>>(new Set(defaultSelectedPagesId)) | |
| if (prevData !== data) { | |
| setPrevData(data) | |
| setSelectedPagesId(new Set(defaultSelectedPagesId)) | |
| } | |
| const handleSearchValueChange = useCallback((value: string) => { | |
| setSearchValue(value) | |
| }, []) | |
| const handleSelectWorkspace = useCallback((workspaceId: string) => { | |
| setCurrentWorkspaceId(workspaceId) | |
| }, []) | |
| const handleSelectPages = (newSelectedPagesId: Set<string>) => { | |
| const selectedPages = Array.from(newSelectedPagesId).map(pageId => getPagesMapAndSelectedPagesId[0][pageId]) | |
| setSelectedPagesId(new Set(Array.from(newSelectedPagesId))) | |
| onSelect(selectedPages) | |
| } | |
| const handlePreviewPage = (previewPageId: string) => { | |
| if (onPreview) | |
| onPreview(getPagesMapAndSelectedPagesId[0][previewPageId]) | |
| } | |
| useEffect(() => { | |
| setCurrentWorkspaceId(firstWorkspaceId) | |
| }, [firstWorkspaceId]) | |
| return ( | |
| <div className='bg-gray-25 border border-gray-200 rounded-xl'> | |
| { | |
| data?.notion_info?.length | |
| ? ( | |
| <> | |
| <div className='flex items-center pl-[10px] pr-2 h-11 bg-white border-b border-b-gray-200 rounded-t-xl'> | |
| <WorkspaceSelector | |
| value={currentWorkspaceId || firstWorkspaceId} | |
| items={notionWorkspaces} | |
| onSelect={handleSelectWorkspace} | |
| /> | |
| <div className='mx-1 w-[1px] h-3 bg-gray-200' /> | |
| <div | |
| className={cn(s['setting-icon'], 'w-6 h-6 cursor-pointer')} | |
| onClick={() => setShowAccountSettingModal({ payload: 'data-source', onCancelCallback: mutate })} | |
| /> | |
| <div className='grow' /> | |
| <SearchInput | |
| value={searchValue} | |
| onChange={handleSearchValueChange} | |
| /> | |
| </div> | |
| <div className='rounded-b-xl overflow-hidden'> | |
| <PageSelector | |
| value={selectedPagesId} | |
| disabledValue={getPagesMapAndSelectedPagesId[2]} | |
| searchValue={searchValue} | |
| list={currentWorkspace?.pages || []} | |
| pagesMap={getPagesMapAndSelectedPagesId[0]} | |
| onSelect={handleSelectPages} | |
| canPreview={canPreview} | |
| previewPageId={previewPageId} | |
| onPreview={handlePreviewPage} | |
| /> | |
| </div> | |
| </> | |
| ) | |
| : ( | |
| <NotionConnector onSetting={() => setShowAccountSettingModal({ payload: 'data-source', onCancelCallback: mutate })} /> | |
| ) | |
| } | |
| </div> | |
| ) | |
| } | |
| export default NotionPageSelector | |