import { ComponentProps, ElementType, ReactNode } from 'react'; import { Badge } from '../badge.mjs'; import * as react_jsx_runtime from 'react/jsx-runtime'; import 'class-variance-authority/types'; import 'class-variance-authority'; /** * Who is viewing the board. Drives every permission on the page. * - `system-admin` — receiver / triage owner: vote, triage (Decline / * Start work / status changes). Cannot create requests. * - `staff` — requester / voter (company admin, advisor, staff): vote, * create requests. Cannot triage. */ type FeedbackRole = "system-admin" | "staff"; /** The signed-in user — used to scope the "my requests" filter. */ interface FeedbackCurrentUser { name: string; /** Display role label, e.g. "Admin", "Advisor". */ role: string; } /** * What kind of request this is. * - `idea` / `enhancement` — demand-driven, **votable**. * - `bug` — a defect; **not votable** and treated as top priority. */ type FeedbackType = "idea" | "enhancement" | "bug"; /** Whether a request type accepts upvotes. Bugs are triaged by severity, not votes. */ declare const isVotable: (type: FeedbackType) => boolean; type Priority = "low" | "medium" | "high" | "critical"; type FeedbackStatus = "new" | "in-progress" | "resolved" | "declined"; interface FeedbackReporter { name: string; email: string; /** Job title / position, e.g. "Senior Advisor". */ title: string; /** Optional avatar image URL — falls back to initials when absent. */ avatar?: string; } interface FeedbackAttachment { name: string; size: number; /** Image attachments carry a preview URL so they render as a thumbnail. */ previewUrl?: string; } interface FeedbackItem { id: string; title: string; type: FeedbackType; area: string; priority: Priority; status: FeedbackStatus; reporter: FeedbackReporter; problemStatement: string; /** Ideas / enhancements: the desired outcome ("ideal outcome" in the form). */ proposedSolution?: string; /** Steps to reproduce the defect (multi-line). */ stepsToReproduce?: string; /** How often it happens — display label, e.g. "Every time". */ frequency?: string; /** How much it blocks the user — display label, e.g. "I'm blocked". */ impact?: string; /** How the user works around the gap today. */ workaround?: string; /** Who would benefit — display labels, e.g. ["My team", "My clients"]. */ beneficiaries?: string[]; attachments: FeedbackAttachment[]; votes: number; /** ISO 8601 timestamp */ createdAt: string; /** Optional screenshot of the screen this request relates to. */ previewImage?: string; } declare function getInitials(name: string): string; declare function formatCreatedAt(iso: string): string; declare function formatFileSize(bytes: number): string; type BadgeVariant = ComponentProps["variant"]; declare const TYPE_META: Record; declare const PRIORITY_META: Record; declare const STATUS_META: Record; /** Default signed-in user per role — used to scope the "My requests" filter. */ declare const MOCK_CURRENT_USERS: Record; declare const MOCK_FEEDBACK: FeedbackItem[]; declare const EMPTY_FEEDBACK: FeedbackItem[]; interface FeedbackNewRequestPayload { title: string; type: FeedbackType; area: string; problemStatement: string; stepsToReproduce?: string; frequency?: string; impact?: string; proposedSolution?: string; workaround?: string; beneficiaries?: string[]; previewImage?: File | null; } interface FeedbackNewRequestProps { open: boolean; onOpenChange: (open: boolean) => void; /** * Fired when the user submits the intake form. May return a promise — the form * awaits it and keeps the submit button busy until it settles. On success the * host closes the drawer; if it rejects, the form stays open and `onError` * fires. The form never closes on its own. */ onSubmit?: (payload: FeedbackNewRequestPayload) => void | Promise; /** * Fired when `onSubmit` rejects. The drawer stays open so the user can retry — * the host decides how (or whether) to surface the failure. */ onError?: (error: unknown) => void; } /** * Broker-facing intake form, presented as a right-side slide-out. The follow-up * questions adapt to the request type: a **bug** asks for reproduction + * frequency + impact, while an **idea / enhancement** asks for the desired * outcome, the current workaround, and who it benefits. */ declare function FeedbackNewRequest({ open, onOpenChange, onSubmit, onError, }: FeedbackNewRequestProps): react_jsx_runtime.JSX.Element; interface FeedbackBoardProps { items?: FeedbackItem[]; /** * Viewer role. Drives the filter set and the detail-drawer triage actions. * Creation is open to every role — only triage (approve/decline) is admin-only. */ role?: FeedbackRole; /** Signed-in user — scopes the "My requests" filter. Defaults to the role's mock user. */ currentUser?: FeedbackCurrentUser; /** Render the built-in page top bar. Pass `false` when a host supplies its own. */ showTopBar?: boolean; /** Fires when the "Load more" button is pressed (host fetches the next page). */ onLoadMore?: () => void; /** Whether more items can be loaded — shows the "Load more" button. */ hasMore?: boolean; /** Whether a load-more fetch is in flight — disables the button. */ isLoadingMore?: boolean; /** Controlled status filter. */ status?: string; onStatusChange?: (value: string) => void; /** Controlled type filter. */ type?: string; onTypeChange?: (value: string) => void; /** Controlled search query. */ query?: string; onQueryChange?: (value: string) => void; /** * Fired when a new request is submitted — receives the full intake payload. * May return a promise: the drawer only closes, resets, and shows the success * toast once it resolves. If it rejects, the drawer stays open and `onError` * fires — the board never assumes the submission succeeded. */ onSubmit?: (payload: FeedbackNewRequestPayload) => void | Promise; /** * Fired when admin confirms approval. May return a promise — the detail * drawer stays open until it resolves and closes on success only; a rejection * fires `onError` and keeps the drawer open. */ onApprove?: (item: FeedbackItem, priority: string) => void | Promise; /** * Fired when admin clicks Decline. May return a promise — the detail drawer * stays open until it resolves and closes on success only; a rejection fires * `onError` and keeps the drawer open. */ onDecline?: (item: FeedbackItem) => void | Promise; /** * Fired when any async action (`onSubmit` / `onApprove` / `onDecline`) * rejects. The originating drawer stays open; the host decides how to surface * the failure (e.g. an error toast). The board shows no failure UI itself. */ onError?: (error: unknown) => void; /** Fired when the upvote button is toggled. */ onUpvote?: (item: FeedbackItem) => void; } /** * The complete back-office feedback page. An upvote board (Ideation A) wired to a * right-side intake form: both roles get the "New request" action. Submitting * forwards the payload via `onSubmit`; the form only closes, resets, and confirms * with a toast once the host resolves it. A rejected submission leaves the drawer * open and fires `onError` instead — the host owns failure feedback. Role drives * triage only — System Admin additionally gets approve / decline actions in the * detail drawer, which likewise close on success and fire `onError` on failure. */ declare function FeedbackBoard({ items, role, currentUser, showTopBar, onLoadMore, hasMore, isLoadingMore, status, onStatusChange, type, onTypeChange, query, onQueryChange, onSubmit, onApprove, onDecline, onError, onUpvote, }: FeedbackBoardProps): react_jsx_runtime.JSX.Element; interface FeedbackIdeationAProps { items?: FeedbackItem[]; title?: string; /** Fires when the toolbar's "New request" button is pressed (open to every role). */ onNewRequest?: () => void; /** Viewer role — drives the toolbar (filters + New request) and detail actions. */ role?: FeedbackRole; /** Signed-in user — scopes the "My requests" filter. Defaults to the role's mock user. */ currentUser?: FeedbackCurrentUser; /** * Render the built-in page top bar. Default `true` (standalone use). Pass * `false` when a host app supplies its own top bar — the board then fills its * parent (`h-full`) instead of the viewport (`h-screen`). */ showTopBar?: boolean; /** Fires when the "Load more" button is pressed (host fetches the next page). */ onLoadMore?: () => void; /** Whether more items can be loaded — shows the "Load more" button. */ hasMore?: boolean; /** Whether a load-more fetch is in flight — disables the button. */ isLoadingMore?: boolean; /** * Controlled status filter. When provided together with `onStatusChange`, * the component skips client-side filtering — the host is responsible for * passing pre-displayed `items` (e.g. from a server call). */ status?: string; onStatusChange?: (value: string) => void; /** Controlled type filter (same controlled semantics as `status`). */ type?: string; onTypeChange?: (value: string) => void; /** Controlled search query (same controlled semantics as `status`). */ query?: string; onQueryChange?: (value: string) => void; /** * Fired when admin confirms approval (priority chosen). May return a promise — * the detail drawer stays open until it resolves and closes on success only. */ onApprove?: (item: FeedbackItem, priority: string) => void | Promise; /** * Fired when admin clicks Decline. May return a promise — the detail drawer * stays open until it resolves and closes on success only. */ onDecline?: (item: FeedbackItem) => void | Promise; /** * Fired when `onApprove` or `onDecline` rejects. The detail drawer stays open; * the host decides how to surface the failure. */ onError?: (error: unknown) => void; /** Fired when the upvote button is toggled on a row. */ onUpvote?: (item: FeedbackItem) => void; } /** * Ideation A — an upvote board. The toolbar (tabs + search + New request) sits on * one line above a list of full-width rows: upvote control on the left, * title/tags/details in the middle, a preview of the related screen on the right. */ declare function FeedbackIdeationA({ items, title, onNewRequest, role, currentUser, showTopBar, onLoadMore, hasMore, isLoadingMore, status: statusProp, onStatusChange: onStatusChangeProp, type: typeProp, onTypeChange: onTypeChangeProp, query: queryProp, onQueryChange: onQueryChangeProp, onApprove, onDecline, onError, onUpvote, }: FeedbackIdeationAProps): react_jsx_runtime.JSX.Element; interface ApproveRequestDialogProps { open: boolean; onOpenChange: (open: boolean) => void; /** Title of the request being approved — shown in the prompt. */ requestTitle: string; /** * Fired with the chosen priority when the admin confirms. May return a * promise — the confirm button stays busy until it settles, and the dialog * stays open if it rejects so the admin can retry. The host owns closing the * surrounding sheet on success. */ onConfirm: (priority: string) => void | Promise; } /** * Approval step for the System Admin: accepting a request requires setting a * priority (required) and may carry a note. Uses chips + textarea (no Base UI * Select/Radio inside the dialog, which have known portal issues). */ declare function ApproveRequestDialog({ open, onOpenChange, requestTitle, onConfirm, }: ApproveRequestDialogProps): react_jsx_runtime.JSX.Element; interface ChipOption { value: string; label: string; } interface ChipQuestionProps { /** The question shown above the chips. */ label: string; /** Optional supporting line under the question. */ hint?: string; /** Marks the question required — appends a red asterisk to the label. */ required?: boolean; options: ChipOption[]; /** Multi-select when true, single-select otherwise. */ multiple?: boolean; /** string for single-select, string[] for multi-select. */ value?: string | string[]; onValueChange?: (value: string | string[]) => void; /** Revealed below the chips — used for the "Other…" free-text input. */ footer?: ReactNode; } /** * A single chip question: a label and a wrap of tappable chips. Bounded, * content-agnostic — drives the low-effort intake form. Single- or multi-select. */ declare function ChipQuestion({ label, hint, required, options, multiple, value, onValueChange, footer, }: ChipQuestionProps): react_jsx_runtime.JSX.Element; interface FeedbackAttachmentsProps { item: FeedbackItem; } /** * Attachments section for the detail drawer. Shows the related screen * (`previewImage`) and any uploads as one unified list of rows — a single, * consistent way images appear. Renders nothing when there's nothing to show. */ declare function FeedbackAttachments({ item }: FeedbackAttachmentsProps): react_jsx_runtime.JSX.Element | null; interface FeedbackDetailSheetProps { item: FeedbackItem | null; open: boolean; onOpenChange: (open: boolean) => void; /** Viewer role. Triage actions (Decline / Start work) show for `system-admin` only. */ role?: FeedbackRole; /** * Fired when the admin confirms approval with a priority. May return a * promise — the sheet stays open until it resolves and closes on success * only; a rejection keeps the sheet open for a retry. */ onApprove?: (item: FeedbackItem, priority: string) => void | Promise; /** * Fired when the admin clicks Decline. May return a promise — the sheet stays * open until it resolves and closes on success only. */ onDecline?: (item: FeedbackItem) => void | Promise; /** * Fired when `onApprove` or `onDecline` rejects. The sheet stays open so the * admin can retry — the host decides how to surface the failure. */ onError?: (error: unknown) => void; } declare function FeedbackDetailSheet({ item, open, onOpenChange, role, onApprove, onDecline, onError, }: FeedbackDetailSheetProps): react_jsx_runtime.JSX.Element | null; interface FeedbackEmptyStateProps { description?: string; } declare function FeedbackEmptyState({ description, }: FeedbackEmptyStateProps): react_jsx_runtime.JSX.Element; interface FeedbackRequestRowProps { item: FeedbackItem; /** Fires when the row is clicked (anywhere except the upvote or image). */ onSelect?: (item: FeedbackItem) => void; /** Fires when the upvote button is toggled. */ onUpvote?: (item: FeedbackItem) => void; } declare function FeedbackRequestRow({ item, onSelect, onUpvote, }: FeedbackRequestRowProps): react_jsx_runtime.JSX.Element; interface FeedbackTopBarProps { title?: string; /** Show the "New request" action button. Off when the action lives elsewhere (e.g. a toolbar). */ showAction?: boolean; } declare function FeedbackTopBar({ title, showAction, }: FeedbackTopBarProps): react_jsx_runtime.JSX.Element; interface FieldLabelProps { htmlFor?: string; /** Appends a red asterisk to mark the field required. */ required?: boolean; /** Appends a muted "(optional)" suffix. */ optional?: boolean; children: ReactNode; } /** * Form field label with a consistent required (`*`) / optional marker. Keeps the * required-asterisk and "(optional)" treatment identical across every feedback * form field. */ declare function FieldLabel({ htmlFor, required, optional, children, }: FieldLabelProps): react_jsx_runtime.JSX.Element; interface LabeledFieldProps { /** Field label text. */ label: ReactNode; htmlFor?: string; required?: boolean; optional?: boolean; /** The control(s) the label describes. */ children: ReactNode; } /** * A vertical form field: a `FieldLabel` above its control(s). Standardises the * label-over-control spacing used across the feedback forms. */ declare function LabeledField({ label, htmlFor, required, optional, children, }: LabeledFieldProps): react_jsx_runtime.JSX.Element; interface IdeationAToolbarProps { status?: string; onStatusChange?: (value: string) => void; /** Active request-type filter: `all`, `idea`, `enhancement`, or `bug`. */ type?: string; onTypeChange?: (value: string) => void; query?: string; onQueryChange?: (value: string) => void; /** Fired when "New request" is pressed. */ onNewRequest?: () => void; /** Viewer role — picks the filter set. Creation is open to every role, so it does not gate the button. */ role?: FeedbackRole; } declare function IdeationAToolbar({ status, onStatusChange, type, onTypeChange, query, onQueryChange, onNewRequest, role, }: IdeationAToolbarProps): react_jsx_runtime.JSX.Element; interface PriorityBadgeProps { priority: Priority; } declare function PriorityBadge({ priority }: PriorityBadgeProps): react_jsx_runtime.JSX.Element; interface ReporterCellProps { reporter: FeedbackReporter; } declare function ReporterCell({ reporter }: ReporterCellProps): react_jsx_runtime.JSX.Element; interface ScreenshotUploadProps { /** Called whenever the selected file changes (or is removed). */ onFileChange?: (file: File | null) => void; } /** * Optional screenshot attachment for the intake form. Wraps the DS `UploadCard` * and, once a file is picked, swaps the drop zone for a thumbnail preview with * the filename, size, and a remove control. Manages the object-URL lifecycle so * previews don't leak. */ declare function ScreenshotUpload({ onFileChange }: ScreenshotUploadProps): react_jsx_runtime.JSX.Element; interface StatusBadgeProps { status: FeedbackStatus; } declare function StatusBadge({ status }: StatusBadgeProps): react_jsx_runtime.JSX.Element; interface TypeBadgeProps { type: FeedbackType; withIcon?: boolean; } declare function TypeBadge({ type, withIcon }: TypeBadgeProps): react_jsx_runtime.JSX.Element; export { ApproveRequestDialog, type ApproveRequestDialogProps, type BadgeVariant, type ChipOption, ChipQuestion, type ChipQuestionProps, EMPTY_FEEDBACK, type FeedbackAttachment, FeedbackAttachments, type FeedbackAttachmentsProps, FeedbackBoard, type FeedbackBoardProps, type FeedbackCurrentUser, FeedbackDetailSheet, type FeedbackDetailSheetProps, FeedbackEmptyState, type FeedbackEmptyStateProps, FeedbackIdeationA, type FeedbackIdeationAProps, type FeedbackItem, FeedbackNewRequest, type FeedbackNewRequestPayload, type FeedbackNewRequestProps, type FeedbackReporter, FeedbackRequestRow, type FeedbackRequestRowProps, type FeedbackRole, type FeedbackStatus, FeedbackTopBar, type FeedbackTopBarProps, type FeedbackType, FieldLabel, type FieldLabelProps, IdeationAToolbar, type IdeationAToolbarProps, LabeledField, type LabeledFieldProps, MOCK_CURRENT_USERS, MOCK_FEEDBACK, PRIORITY_META, type Priority, PriorityBadge, type PriorityBadgeProps, ReporterCell, type ReporterCellProps, STATUS_META, ScreenshotUpload, type ScreenshotUploadProps, StatusBadge, type StatusBadgeProps, TYPE_META, TypeBadge, type TypeBadgeProps, formatCreatedAt, formatFileSize, getInitials, isVotable };