"use client"; import { IconX, IconDeviceFloppy, IconBookmark } from "@tabler/icons-react"; import type { Icon } from "@tabler/icons-react"; import { useCallback } from "react"; import { Button } from "@kandev/ui/button"; import { SavedQueryLoadStatus, type SavedQueryLoadState } from "./saved-query-load-status"; import { cn } from "@/lib/utils"; import { PR_PRESETS, ISSUE_PRESETS, type PresetOption, type PresetGroup } from "./search-bar"; import type { SavedPreset } from "./saved-preset-model"; import { useTranslation } from "react-i18next"; import { useResponsiveBreakpoint } from "@/hooks/use-responsive-breakpoint"; import { SavedQueryDefaultButton } from "@/components/integrations/saved-query-default-button"; import { SavedTaskViewDeleteConfirmation } from "@/components/confirmation/saved-task-view-delete-confirmation"; import { useSavedTaskViewDeleteConfirmation, type SavedTaskViewDeleteTarget, } from "@/components/confirmation/use-saved-task-view-delete-confirmation"; export type SidebarSelection = { kind: "pr" | "issue"; source: "preset" | "saved"; id: string; }; export type SidebarSelectionRequest = | SidebarSelection | { kind: SidebarSelection["kind"]; source: "kind-switch" }; export type PresetsSidebarProps = { selected: SidebarSelection; onSelect: (request: SidebarSelectionRequest) => void; savedPresets: SavedPreset[]; onDeleteSaved: (id: string) => void; canSaveCurrent: boolean; onSaveCurrent: () => void; onToggleSavedDefault: (preset: SavedPreset) => void; defaultMutationPendingId: string | null; prPresets?: PresetOption[]; issuePresets?: PresetOption[]; savedQueryLoad?: SavedQueryLoadState; }; function KindToggle({ kind, onChange, }: { kind: "pr" | "issue"; onChange: (k: "pr" | "issue") => void; }) { const { t } = useTranslation(); return (
{(["pr", "issue"] as const).map((value) => ( ))}
); } function SectionHeader({ title }: { title: string }) { return (
{title}
); } function PresetItem({ label, Icon, active, onClick, trailing, }: { label: string; Icon: Icon; active: boolean; onClick: () => void; trailing?: React.ReactNode; }) { return (
{trailing}
); } function PresetGroupList({ presets, group, selected, onSelect, kind, }: { presets: PresetOption[]; group: PresetGroup; selected: SidebarSelection; onSelect: (s: SidebarSelection) => void; kind: "pr" | "issue"; }) { const { t } = useTranslation(); const items = presets.filter((p) => p.group === group); if (items.length === 0) return null; return ( <> {items.map((p) => ( onSelect({ kind, source: "preset", id: p.value })} /> ))} ); } function SavedSection({ saved, selected, onSelect, onDelete, kind, onToggleSavedDefault, defaultMutationPendingId, savedQueryLoad, }: { saved: SavedPreset[]; selected: SidebarSelection; onSelect: (s: SidebarSelection) => void; onDelete: (id: string) => void; kind: "pr" | "issue"; onToggleSavedDefault: (preset: SavedPreset) => void; defaultMutationPendingId: string | null; savedQueryLoad?: SavedQueryLoadState; }) { const { t } = useTranslation(); const deletion = useSavedTaskViewDeleteConfirmation(saved); const { isMobile } = useResponsiveBreakpoint(); const defaultMutationPending = defaultMutationPendingId !== null; return ( <> {savedQueryLoad && } {saved.length === 0 && !savedQueryLoad?.loading && !savedQueryLoad?.error && (
{t("github:noSavedQueriesYet")}
)} {saved.map((preset) => ( onSelect({ kind, source: "saved", id: preset.id })} onDelete={onDelete} onToggleDefault={() => void onToggleSavedDefault(preset)} /> ))} {isMobile && deletion.target && ( { if (!open) deletion.close(); }} onConfirm={onDelete} /> )} ); } type GitHubSavedDeletion = { target: SavedTaskViewDeleteTarget | null; anchorRef: React.RefObject; close: () => void; registerAnchor: (id: string, element: HTMLButtonElement | null) => void; request: (target: SavedTaskViewDeleteTarget) => void; }; function GitHubSavedPresetEntry({ preset, active, deletion, defaultMutationPending, defaultMutationPendingForPreset, onSelect, onDelete, onToggleDefault, }: { preset: SavedPreset; active: boolean; deletion: GitHubSavedDeletion; defaultMutationPending: boolean; defaultMutationPendingForPreset: boolean; onSelect: () => void; onDelete: (id: string) => void; onToggleDefault: () => void; }) { const { t } = useTranslation(); const { isMobile } = useResponsiveBreakpoint(); if (!isMobile && deletion.target?.id === preset.id) { return (
{ if (!open) deletion.close(); }} onConfirm={onDelete} />
); } const deleteLabel = t("integrations:deleteSavedQueryNamed", { label: preset.label }); const accessibleDeleteLabel = defaultMutationPending ? t("integrations:savedQueryDefaultUpdateInProgress", { action: deleteLabel }) : deleteLabel; return ( } /> ); } export function PresetsSidebar({ selected, onSelect, savedPresets, onDeleteSaved, canSaveCurrent, onSaveCurrent, onToggleSavedDefault, defaultMutationPendingId, prPresets = PR_PRESETS, issuePresets = ISSUE_PRESETS, savedQueryLoad, }: PresetsSidebarProps) { const { t } = useTranslation(); const presets = selected.kind === "pr" ? prPresets : issuePresets; const saved = savedPresets.filter((p) => p.kind === selected.kind); const onKindChange = useCallback( (kind: "pr" | "issue") => { if (kind === selected.kind) return; onSelect({ kind, source: "kind-switch" }); }, [onSelect, selected.kind], ); return ( ); }