97 lines
3.3 KiB
TypeScript
97 lines
3.3 KiB
TypeScript
"use client";
|
|
|
|
import {
|
|
BottomSheetRoot,
|
|
BottomSheetBackdrop,
|
|
BottomSheetPositioner,
|
|
BottomSheetContent,
|
|
BottomSheetHeader,
|
|
BottomSheetTitle,
|
|
BottomSheetCloseButton,
|
|
BottomSheetBody,
|
|
Icon,
|
|
ListRoot,
|
|
ListItem,
|
|
ListContent,
|
|
ListTitle,
|
|
} from "@seed-design/react";
|
|
import type { Category } from "@/api/schemas";
|
|
import { accountingStrings as s } from "./strings";
|
|
|
|
export interface CategorizeSheetProps {
|
|
open: boolean;
|
|
onOpenChange: (open: boolean) => void;
|
|
categories: Category[];
|
|
/** The transaction's current category (main or sub) — highlighted in the list. */
|
|
selected?: string;
|
|
onSelect: (category: Category) => void;
|
|
}
|
|
|
|
const closeSvg = (
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={1.8} strokeLinecap="round">
|
|
<path d="M6 6l12 12M18 6L6 18" />
|
|
</svg>
|
|
);
|
|
|
|
const checkSvg = (
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round">
|
|
<path d="M5 12.5l4.5 4.5L19 7" />
|
|
</svg>
|
|
);
|
|
|
|
/**
|
|
* Category picker bottom sheet (ports `CategoryPickerSheet` from
|
|
* `ios/Mercury/Features/Planner/PlannerEditViews.swift`, opened from the
|
|
* transaction detail's Ангилал row): a titled list of all categories,
|
|
* tap-to-select, checkmark on the current pick.
|
|
*/
|
|
export function CategorizeSheet({ open, onOpenChange, categories, selected, onSelect }: CategorizeSheetProps) {
|
|
return (
|
|
<BottomSheetRoot open={open} onOpenChange={onOpenChange}>
|
|
<BottomSheetBackdrop />
|
|
<BottomSheetPositioner>
|
|
<BottomSheetContent>
|
|
<BottomSheetHeader style={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
|
|
<BottomSheetTitle>{s.categoryPicker.title}</BottomSheetTitle>
|
|
<BottomSheetCloseButton aria-label={s.categoryPicker.cancel}>
|
|
<Icon svg={closeSvg} size="16px" />
|
|
</BottomSheetCloseButton>
|
|
</BottomSheetHeader>
|
|
<BottomSheetBody style={{ maxHeight: "60vh", overflowY: "auto" }}>
|
|
<ListRoot>
|
|
{categories.map((cat) => {
|
|
const isSelected = cat.name === selected;
|
|
return (
|
|
<ListItem key={cat.name} style={{ padding: 0 }}>
|
|
<button
|
|
type="button"
|
|
onClick={() => onSelect(cat)}
|
|
style={{
|
|
display: "flex",
|
|
width: "100%",
|
|
alignItems: "center",
|
|
justifyContent: "space-between",
|
|
background: "none",
|
|
border: "none",
|
|
textAlign: "left",
|
|
cursor: "pointer",
|
|
padding: "12px 4px",
|
|
font: "inherit",
|
|
color: "inherit",
|
|
}}
|
|
>
|
|
<ListContent>
|
|
<ListTitle>{cat.name}</ListTitle>
|
|
</ListContent>
|
|
{isSelected && <Icon svg={checkSvg} size="18px" />}
|
|
</button>
|
|
</ListItem>
|
|
);
|
|
})}
|
|
</ListRoot>
|
|
</BottomSheetBody>
|
|
</BottomSheetContent>
|
|
</BottomSheetPositioner>
|
|
</BottomSheetRoot>
|
|
);
|
|
}
|