flexprice/flexprice-front

add metadata display section in InvoiceDetail

Open

#370 opened on Sep 18, 2025

 (1 comment) (0 reactions) (1 assignee)TypeScript (106 forks)auto 404
good first issuehacktoberfestjavascriptreact

Repository metrics

Stars
 (32 stars)
PR merge metrics
 (PR metrics pending)

Description

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);
}

Contributor guide