import { ReactElement } from 'react'; import { faEye, faEyeSlash, faTrash } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Stack, Tooltip, Divider, Typography, Select, Option, Input, Button } from '@mui/joy'; import { useAppDispatch, useAppSelector } from '../../store/hooks'; import { focusTag, setTabIndex, selectSimilarTags } from '../../store/uiSlice'; import { selectSelectedTabs } from '../../store/selectors'; import { closeTab } from '../../chrome/chromeActions'; import { activateOrOpenTab } from '../../chrome/chromeNavigation'; import { addTag, deletePage, Page, removeTag, fetchPages, updateTodoCompletion, updateTodoPriority, updateTodoDueDate } from '../../db/pages'; import { CustomTagSelector } from '../tagSelector/CustomTagSelector'; import { useLiveQuery } from 'dexie-react-hooks'; import { setSimilarUrlsAsync } from '../../store/windowsSlice'; import { aggregateTags } from '../tagSelector/tag_utils'; import { fetchTagNames } from '../../db/tags'; import { logger } from '../../utils/logger'; import React from 'react'; interface MultiSelectActionsProps { selectedUrls: string[]; onClickTag?: (value: string) => void; } const MultiSelectActions = ({ selectedUrls, onClickTag = (_value: string) => {}, }: MultiSelectActionsProps): ReactElement => { const dispatch = useAppDispatch(); const tagOptions: string[] = useLiveQuery(fetchTagNames) as string[]; const tabs = useAppSelector(selectSelectedTabs); const tabUrls = tabs.map((tab) => tab.url).filter((x) => x !== undefined); const similarTags = useAppSelector(selectSimilarTags); const selectedPages = useLiveQuery(() => fetchPages(selectedUrls), [selectedUrls]) || []; const selectedTags = aggregateTags(selectedPages); const similarTagsList = Object.values(similarTags) .filter((tag) => !(tag.name in selectedTags)) .sort((a, b) => b.proportion - a.proportion); const allUrls = [...new Set([...selectedUrls, ...tabUrls.map((x) => x.normalized)]).values()]; if (allUrls.length === 0) { return <>; } const numSelected = allUrls.length; // Todo-specific section const todoPages = selectedPages.filter((p) => p.completionStatus !== undefined); const pendingCount = todoPages.filter((p) => p.completionStatus === 'pending').length; const completedCount = todoPages.filter((p) => p.completionStatus === 'completed').length; const handleBulkMarkComplete = () => { for (const p of todoPages) { updateTodoCompletion(p.nurl.normalized, 'completed') .catch((err: unknown) => logger.error('[MultiSelectActions] updateTodoCompletion failed', err)); } }; const handleBulkMarkPending = () => { for (const p of todoPages) { updateTodoCompletion(p.nurl.normalized, 'pending') .catch((err: unknown) => logger.error('[MultiSelectActions] updateTodoCompletion failed', err)); } }; const handleBulkPriority = (_: React.SyntheticEvent | null, val: number | null) => { for (const p of todoPages) { updateTodoPriority(p.nurl.normalized, val ?? undefined) .catch((err: unknown) => logger.error('[MultiSelectActions] updateTodoPriority failed', err)); } }; const handleBulkDueDate = (e: React.ChangeEvent) => { const val = e.target.value; for (const p of todoPages) { updateTodoDueDate(p.nurl.normalized, val ? new Date(val).getTime() : undefined) .catch((err: unknown) => logger.error('[MultiSelectActions] updateTodoDueDate failed', err)); } }; return (
{numSelected} {numSelected == 1 ? 'page' : 'pages'} selected
{ for (const tab of tabs) { closeTab(tab.id); } for (const url of selectedUrls) { deletePage(url); } dispatch(setSimilarUrlsAsync()); }} title="Forget Page" /> { for (const tab of tabs) { closeTab(tab.id); } }} title="Snooze Tabs" /> { for (const url of allUrls) { activateOrOpenTab(url); } }} title="Open Tabs" /> {todoPages.length > 0 && ( <> TODO FIELDS ({pendingCount} pending, {completedCount} done) Priority: Due date: )} APPLIED TAGS { if (value != '') { addTag(allUrls, value); dispatch(setSimilarUrlsAsync()); } }} onDelete={(value) => { if (value != '') { removeTag(allUrls, value); dispatch(setSimilarUrlsAsync()); } }} onClickTag={onClickTag} onDoubleClickTag={(value) => { dispatch(focusTag({ tag: value })); dispatch(setTabIndex(1)); }} multiSelect={true} /> {similarTagsList.length > 0 && ( <> SUGGESTED TAGS { if (value != '') { addTag(allUrls, value); dispatch(setSimilarUrlsAsync()); } }} onDelete={(value) => { if (value != '') { removeTag(allUrls, value); dispatch(setSimilarUrlsAsync()); } }} onClickTag={onClickTag} onDoubleClickTag={(value) => { dispatch(focusTag({ tag: value })); dispatch(setTabIndex(1)); }} multiSelect={true} hideAddButton={true} proposed={true} /> )}
); }; export default MultiSelectActions;