'use client'
import { Check, ChevronsUpDown, Star } from 'lucide-react'
import { useMemo, useState } from 'react'
import { Button } from '@/components/ui/button'
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
} from '@/components/ui/command'
import { Label } from '@/components/ui/label'
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'
import { Switch } from '@/components/ui/switch'
import { cn } from '@/lib/utils'
// ── Toggle field ──────────────────────────────────────────────
export function ToggleField({
label,
checked,
value,
onChange,
disabled,
}: {
label: string
/** Boolean checked state */
checked?: boolean
/** Number or string (0/1 or '0'/'1') — converted to boolean automatically */
value?: number | string
onChange: (v: boolean) => void
disabled?: boolean
}) {
const isChecked = checked ?? (value === 1 || value === '1')
return (
)
}
// ── Interaction Type Combobox ──────────────────────────────────
export function InteractionTypeCombobox({
value,
onChange,
types,
disabled,
}: {
value: string
onChange: (v: string) => void
types: string[]
disabled?: boolean
}) {
const [open, setOpen] = useState(false)
const [inputValue, setInputValue] = useState('')
const filtered = useMemo(() => {
if (!inputValue.trim()) return types.slice(0, 50)
const q = inputValue.toLowerCase()
return types.filter((t) => t.toLowerCase().includes(q)).slice(0, 50)
}, [types, inputValue])
return (
{inputValue.trim() ? (
) : (
'No types found.'
)}
{filtered.map((t) => (
{
onChange(t)
setOpen(false)
setInputValue('')
}}
>
{t}
))}
)
}
// ── Move Page Combobox with smart suggestions ─────────────────
export function MovePageCombobox({
value,
onChange,
pages,
currentPageId,
suggestedPageIds,
}: {
value: number | null
onChange: (id: number | null) => void
pages: { id: number; caption: string }[]
currentPageId: number
/** Page IDs to show first as suggestions (from move-suggestions.ts) */
suggestedPageIds?: number[]
}) {
const [open, setOpen] = useState(false)
const options = useMemo(() => pages.filter((p) => p.id !== currentPageId), [pages, currentPageId])
const selectedPage = value ? pages.find((p) => p.id === value) : null
// Build suggested pages list
const suggested = useMemo(() => {
if (!suggestedPageIds?.length) return []
const pageMap = new Map(options.map((p) => [p.id, p]))
return suggestedPageIds.map((id) => pageMap.get(id)).filter(Boolean) as {
id: number
caption: string
}[]
}, [suggestedPageIds, options])
// Non-suggested pages (exclude those already in suggestions)
const suggestedSet = useMemo(() => new Set(suggested.map((s) => s.id)), [suggested])
const remaining = useMemo(
() => options.filter((p) => !suggestedSet.has(p.id)),
[options, suggestedSet],
)
return (
No page found.
{/* Suggested pages */}
{suggested.length > 0 && (
{suggested.map((page) => (
{
onChange(page.id)
setOpen(false)
}}
>
#{page.id}
{page.caption}
))}
)}
{/* All pages */}
0 ? 'All pages' : undefined}>
{remaining.map((page) => (
{
onChange(page.id)
setOpen(false)
}}
>
#{page.id}
{page.caption}
))}
)
}