import { useMutation } from "@tanstack/react-query"; import { useCallback, useMemo, useState } from "react"; import { Pressable, ScrollView, Text, View } from "react-native"; import { usePaseo, useSettings, useWorkspaces, type WorkspaceRef, type PluginSidebarViewProps, } from "@getpaseo/plugin/client"; import { folders } from "../shared/preferences"; import { Heading, WorkspaceRow } from "./rows"; interface Move { reference: WorkspaceRef; from: string | null; } function folderLabel(key: string): string | null { return key === "unlabelled" ? null : key.slice("label:".length); } function Movable({ reference, folder, view, select, }: { reference: WorkspaceRef; folder: string | null; view: PluginSidebarViewProps; select: (move: Move) => void; }) { const pick = useCallback(() => select({ reference, from: folder }), [select, reference, folder]); return ( ); } export function Labels(view: PluginSidebarViewProps) { const paseo = usePaseo(); const settings = useSettings(folders); const [selected, select] = useState(null); const groups = useWorkspaces({ orderBy: "name", groupBy: (item) => item.labels.length ? item.labels.map((label) => `label:${label}`) : ["unlabelled"], }); const style = useMemo( () => ({ color: view.theme.colors.foreground, paddingHorizontal: 12 }), [view.theme], ); const move = useMutation({ mutationFn: async (destination: string | null) => { if (!selected) return; const workspace = paseo.workspaces.ref(selected.reference); // Add first: if adding fails the workspace keeps its original folder. if (destination && destination !== selected.from) await workspace.setLabel(destination, { assigned: true }); if (selected.from && selected.from !== destination) await workspace.setLabel(selected.from, { assigned: false }); select(null); }, }); const toggle = useCallback( (folder: string) => { if (settings.status !== "ready") return; void settings.save( { collapsed: settings.values.collapsed.includes(folder) ? settings.values.collapsed.filter((item) => item !== folder) : [...settings.values.collapsed, folder], }, settings.revision, ); }, [settings], ); const cancel = useCallback(() => select(null), []); if (settings.status === "loading") return Loading folders…; if (settings.status !== "ready") return ( {settings.error} {settings.status === "invalid" ? ( ) : null} ); return ( {selected ? ( Choose a destination folder ) : ( Long press a workspace or choose Move… )} {move.error ? {move.error.message} : null} {Array.from( new Set(["label:Inbox", "label:Later", "unlabelled", ...groups.map((group) => group.key)]), ).map((folder) => ( {groups .find((group) => group.key === folder) ?.items.map((reference) => ( ))} ))} {settings.saveError ? {settings.saveError} : null} ); } function Folder({ folder, view, selected, pending, move, collapsed, toggle, children, }: { folder: string; view: PluginSidebarViewProps; selected: boolean; pending: boolean; move: (folder: string | null) => void; collapsed: boolean; toggle: (folder: string) => void; children: import("react").ReactNode; }) { const toggleFolder = useCallback(() => toggle(folder), [toggle, folder]); const label = folderLabel(folder); const title = label ?? "Unlabelled"; const destination = useCallback(() => move(label), [move, label]); return ( {selected ? ( ) : null} {collapsed ? null : children} ); }