import { ReactElement, useMemo } from 'react'; import { useAppDispatch, useAppSelector } from '../../store/hooks'; import { Stack, Box, Tooltip, Typography } from '@mui/joy'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faCartPlus, faEye, faEyeSlash, faBoxOpen } from '@fortawesome/free-solid-svg-icons'; import { faSquare, faSquareCheck, faSquareMinus } from '@fortawesome/free-regular-svg-icons'; import { formatDistance } from 'date-fns'; import { selectTabs, Tab } from '../../store/windowsSlice'; import { closeTab } from '../../chrome/chromeActions'; import { activateOrOpenTab } from '../../chrome/chromeNavigation'; import { stash, stashTabs, unstash } from '../../db/pages'; import { addMultiToSelection, clearSelectionAndSelectMulti, removeMultiFromSelection, selectSelectedUrls, } from '../../store/uiSlice'; import { uniqBy } from 'lodash'; interface WindowGroupHeaderProps { title?: string; accessTime?: number; tabs?: Tab[]; // Explicit tabs (from window grouping) urls: string[]; // Normalized URLs pageCount?: number; allStashed?: boolean; } const WindowGroupHeader = ({ title, accessTime, tabs, urls, pageCount, allStashed, }: WindowGroupHeaderProps): ReactElement => { const dispatch = useAppDispatch(); // ... (selectors) // ... (relevantTabs / combinedTabs logic - kept, not replacing here to keep context small if possible, but I need to replace the component body start anyway for destructuring) // Re-implementing the function body start to injecting destructuring: const selectedUrls = useAppSelector(selectSelectedUrls); const allTabsMap = useAppSelector(selectTabs); // Find all open tabs that match the URLs in this group // This helps us support "Snooze" and "Stash" (close) even if the group is "Archived" const relevantTabs = useMemo(() => { const matchingTabs: Tab[] = []; const urlSet = new Set(urls); if (urlSet.size === 0) return []; Object.values(allTabsMap).forEach(tab => { if (tab?.url?.normalized && urlSet.has(tab.url.normalized)) { matchingTabs.push(tab); } }); return matchingTabs; }, [allTabsMap, urls]); // Combine explicit tabs with discovered tabs const combinedTabs = useMemo(() => { const explicit = tabs || []; return uniqBy([...explicit, ...relevantTabs], 'id'); }, [tabs, relevantTabs]); const allSelected = urls.length > 0 && urls.every((url) => selectedUrls.includes(url)); const someSelected = urls.some((url) => selectedUrls.includes(url)); const indeterminate = someSelected && !allSelected; const handleSelectAll = (e: React.MouseEvent) => { e.stopPropagation(); if (allSelected) { dispatch(removeMultiFromSelection(urls)); } else { dispatch(addMultiToSelection(urls)); } }; const handleOpenAll = (e: React.MouseEvent) => { e.stopPropagation(); urls.forEach(url => { // Find if we have an open tab for this URL const tab = combinedTabs.find(t => t.url?.normalized === url); if (tab) { activateOrOpenTab(url, tab.windowId, tab.id); } else { activateOrOpenTab(url); } }); }; const handleStashAll = (e: React.MouseEvent) => { e.stopPropagation(); if (allStashed) { unstash(urls); } else { // Record stash in DB stash(urls); // Close all open instances combinedTabs.forEach(tab => closeTab(tab.id)); } }; const handleSnoozeAll = (e: React.MouseEvent) => { e.stopPropagation(); combinedTabs.forEach(tab => closeTab(tab.id)); }; return ( { dispatch( clearSelectionAndSelectMulti({ urls: urls.map(u => ({ normalized: u } as any)), }) ); }} onDoubleClick={(e) => { e.stopPropagation(); const targetTab = combinedTabs[0]; if (targetTab?.windowId) { chrome.windows.update(targetTab.windowId, { focused: true }); // Optionally activate the tab? // chrome.tabs.update(targetTab.id, { active: true }); } else if (urls.length > 0) { // Window is not open, restore it chrome.windows.create({ url: urls, focused: true }); } }} >
{title || `Window (${pageCount || urls.length} pages)`} {accessTime && (
{formatDistance(accessTime, new Date(), { addSuffix: true })}
)} {/* Actions are available if we have URLs to act on. For Close/Stash, we need combineTabs to be non-empty ideally, but Stash(DB) works without tabs. Open works without tabs. So we largely always show them? Maybe hide Snooze if no tabs? */} {urls.length > 0 && ( <> {combinedTabs.length > 0 && ( )} )}
); }; export default WindowGroupHeader;