ChemPal Documentation - v0.0.13-beta.5
    Preparing search index...

    Variable HistoryPanelConst

    HistoryPanel: FC = ...

    HistoryPanel component that displays past search queries, when they were executed, and how many results were returned. History is persisted in chrome.storage.local (same mechanism as user settings / cache). Clicking a query re-triggers the search via the app context's pendingSearchQuery.

    // Rendered inside the drawer's tab panel:
    <HistoryPanel />
    // Displays:
    // 3 searches
    // acetone Mar 26, 2:15 PM — 12 results
    // sodium chloride Mar 25, 9:00 AM — 8 results
    // benzene Mar 24, 4:30 PM — 5 results
    const HistoryPanel: FC = () => {
    const [history, setHistory] = useState<SearchHistoryEntry[]>([]);
    const { setPendingSearchQuery, setDrawerTab, setSearchFilters, setSelectedSuppliers, setPanel } =
    useAppContext();

    useEffect(() => {
    const loadHistory = async () => {
    try {
    const entries = await getSearchHistory();
    setHistory(entries);
    } catch (error) {
    console.warn("Failed to load search history:", error);
    }
    };
    loadHistory();
    }, []);

    /**
    * Clears all search history entries from both local state and
    * `chrome.storage.local`, resetting the panel to its empty state.
    * @example
    * ```ts
    * handleClearHistory();
    * // chrome.storage.local.search_history => []
    * // UI shows "No search history yet."
    * ```
    * @source
    */
    const handleClearHistory = async () => {
    try {
    await clearSearchHistory();
    setHistory([]);
    } catch (error) {
    console.warn("Failed to clear search history:", error);
    }
    };

    /**
    * Re-executes a previous search by setting the pending search query
    * in the app context and closing the drawer.
    * @param query - The search term to re-run (e.g. `"sodium chloride"`)
    * @example
    * ```ts
    * handleReSearch("acetone");
    * // Sets pendingSearchQuery to "acetone"
    * // Sets drawerTab to -1 (closes drawer)
    * ```
    * @source
    */
    const handleReSearch = (entry: SearchHistoryEntry) => {
    // Restore filters that were active when this search was originally executed
    if (entry.filters) {
    setSearchFilters(entry.filters);
    }
    if (entry.selectedSuppliers) {
    setSelectedSuppliers(entry.selectedSuppliers);
    }
    setPendingSearchQuery(entry.query);
    setDrawerTab(DRAWER_INDEX.CLOSED); // Close the drawer
    setPanel?.(PANEL.RESULTS); // Navigate to results panel
    };

    const getFilterSummary = (entry: SearchHistoryEntry): string | null => {
    const parts: string[] = [];
    if (entry.filters) {
    if (entry.filters.availability.length > 0)
    parts.push(`Availability: ${entry.filters.availability.join(", ")}`);
    if (entry.filters.country.length > 0)
    parts.push(`Country: ${entry.filters.country.join(", ")}`);
    if (entry.filters.shippingType.length > 0)
    parts.push(`Shipping: ${entry.filters.shippingType.join(", ")}`);
    }
    if (entry.selectedSuppliers && entry.selectedSuppliers.length > 0) {
    parts.push(`Suppliers: ${entry.selectedSuppliers.length} selected`);
    }
    return parts.length > 0 ? parts.join("\n") : null;
    };

    return (
    <Box className={styles["history-panel"]}>
    <Box className={styles["history-panel__header"]}>
    <Typography variant="caption" color="text.secondary">
    {history.length} {history.length === 1 ? "search" : "searches"}
    </Typography>
    {history.length > 0 && (
    <Tooltip title="Clear history">
    <IconButton
    size="small"
    onClick={handleClearHistory}
    className={styles["history-panel__clear-btn"]}
    >
    <DeleteIcon className={styles["history-panel__clear-icon"]} />
    </IconButton>
    </Tooltip>
    )}
    </Box>
    {history.length === 0 ? (
    <Typography
    variant="caption"
    color="text.secondary"
    className={styles["history-panel__empty"]}
    >
    No search history yet.
    </Typography>
    ) : (
    <List dense disablePadding>
    {history.map((entry, idx) => (
    <ListItem
    key={`${entry.timestamp}-${idx}`}
    divider
    className={styles["history-panel__list-item"]}
    >
    <ListItemText
    primary={
    <Box sx={{ display: "flex", alignItems: "center", gap: 0.5 }}>
    <Link
    component="button"
    variant="body2"
    onClick={() => handleReSearch(entry)}
    sx={{ fontWeight: "bold" }}
    className={styles["history-panel__link"]}
    >
    {entry.query}
    </Link>
    {getFilterSummary(entry) && (
    <Tooltip title={getFilterSummary(entry)!} sx={{ whiteSpace: "pre-line" }}>
    <FilterListIcon sx={{ fontSize: 14, color: "text.secondary" }} />
    </Tooltip>
    )}
    </Box>
    }
    secondary={`${formatTimestamp(entry.timestamp)} — ${entry.resultCount} result${entry.resultCount !== 1 ? "s" : ""}`}
    slotProps={{
    secondary: {
    variant: "caption",
    className: styles["history-panel__secondary-text"],
    },
    }}
    className={styles["history-panel__list-item-text"]}
    />
    </ListItem>
    ))}
    </List>
    )}
    </Box>
    );
    };