flexprice/flexprice-front

add metadata display section in InvoiceDetail

开放

#370 创建于 2025年9月18日

 (1 条评论) (0 个反应) (1 位负责人)TypeScript (106 个派生)auto 404
good first issuehacktoberfestjavascriptreact

仓库指标

星标
 (32 个星标)
PR 合并指标
 (PR 指标待抓取)

描述

dd a dedicated Metadata section to the InvoiceDetail view/component to display invoice metadata (arbitrary key/value pairs).
This improves visibility and UX for billing-related metadata such as order ids, external references, or notes.


Goals

  • Show invoice metadata clearly in the Invoice detail page.
  • Provide copy-to-clipboard support for values.
  • Handle empty, long, or sensitive metadata gracefully.

Acceptance Criteria

  1. Section placement

    • Appears in InvoiceDetail below invoice header (or sidebar if layout allows).
    • Title: Metadata.
  2. Data

    • Source: invoice.metadata (Record<string, string | number | null>).
    • Show No metadata available if empty.
  3. Rendering

    • Two-column layout: key (left), value (right).
    • Humanize keys (e.g., external_order_idExternal order id).
    • Truncate long values; show full value in tooltip + allow copy.
  4. Interactions

    • Copy button for each value → copies full string to clipboard.
    • Tooltip on hover shows full value.
    • Accessible via keyboard with aria-labels.
  5. Styling

    • Use Tailwind + shadcn/ui.
    • Compact, scannable layout with consistent spacing.
    • Keys column fixed width; values truncated or wrapped.
  6. Edge cases

    • Null values → render as empty string.
    • Very long values → truncate + tooltip.
    • Sensitive keys (token, secret, password, cvv, ssn) → mask value with Hidden for security.
  7. Tests

    • Renders metadata list.
    • Shows “No metadata available” when empty.
    • Copy button copies correct value.
    • Sensitive keys are masked.

Implementation Notes

  • Create reusable InvoiceMetadata component.
  • Input: metadata?: Record<string, unknown>.
  • Isolated so it can be reused elsewhere.

Minimal Example (React + TS):

function humanizeKey(k: string) {
  return k.replace(/[_-]/g, " ").replace(/\b\w/g, c => c.toUpperCase());
}

function isSensitive(key: string) {
  return /(token|secret|password|ssn|cvv)/i.test(key);
}

贡献者指南