← back to Norma

components/drafts/DraftCard.tsx

121 lines

'use client';

import { useState } from 'react';
import { ChevronDown, ChevronRight } from 'lucide-react';
import { useOrg } from '@/components/OrgProvider';
import DraftEditor, { type DraftData, type DraftStatus } from './DraftEditor';

interface DraftCardProps {
  draft: DraftData;
  onDraftUpdated: (updated: Partial<DraftData>) => void;
}

const STATUS_STYLE: Record<DraftStatus, { cls: string; label: string }> = {
  draft:    { cls: 'badge-warning', label: 'Draft'     },
  review:   { cls: 'badge',         label: 'In Review' },
  approved: { cls: 'badge-success', label: 'Approved'  },
  sent:     { cls: 'badge-success', label: 'Sent'      },
};

/* Strip HTML tags to a plain-text snippet */
function previewSnippet(html: string | undefined | null, maxLen = 100): string {
  if (!html) return '';
  const plain = html
    .replace(/<[^>]+>/g, ' ')
    .replace(/\s+/g, ' ')
    .trim();
  if (plain.length <= maxLen) return plain;
  return plain.slice(0, maxLen).trimEnd() + '...';
}

export default function DraftCard({ draft, onDraftUpdated }: DraftCardProps) {
  const [expanded, setExpanded] = useState(false);
  const { org } = useOrg();
  const lanes = org?.lanes ?? {};
  const lane = lanes[draft.lane] ?? { label: draft.lane, color: '#888', description: '' };
  const laneClass = `lane-${draft.lane.toLowerCase()}` as 'lane-a' | 'lane-b' | 'lane-c';
  const statusMeta = STATUS_STYLE[draft.status] ?? STATUS_STYLE.draft;
  const snippet = previewSnippet(draft.body_html);

  if (expanded) {
    return (
      <DraftEditor
        draft={draft}
        onClose={() => setExpanded(false)}
        onDraftUpdated={onDraftUpdated}
      />
    );
  }

  return (
    <button
      type="button"
      onClick={() => setExpanded(true)}
      className="w-full text-left hover-lift focus-ring"
      style={{
        backgroundColor: 'var(--color-surface)',
        border: '1px solid var(--color-border)',
        borderTop: `3px solid ${lane.color}`,
        borderRadius: 'var(--radius-md)',
        padding: '0.625rem 0.75rem 0.625rem',
        cursor: 'pointer',
        display: 'block',
        outline: 'none',
      }}
      aria-label={`Open editor for Lane ${draft.lane}: ${draft.subject}`}
    >
      <div className="flex items-center gap-2 min-w-0">
        {/* Lane badge — left */}
        <span className={`badge ${laneClass} shrink-0`} aria-label={`Lane ${draft.lane}`}>
          {draft.lane}
        </span>

        {/* Subject + snippet — center */}
        <div className="flex-1 min-w-0 text-left">
          <p
            className="text-sm font-medium truncate"
            style={{ color: 'var(--color-text)' }}
          >
            {draft.subject || (
              <span style={{ color: 'var(--color-text-muted)' }}>
                {lane.label} — No subject yet
              </span>
            )}
          </p>
          {snippet && (
            <p
              className="text-xs truncate mt-0.5"
              style={{ color: 'var(--color-text-muted)' }}
            >
              {snippet}
            </p>
          )}
        </div>

        {/* Status badge — right */}
        <div className="flex items-center gap-2 shrink-0">
          <span
            className={`badge ${statusMeta.cls}`}
            style={{ letterSpacing: '0.05em', fontSize: '0.7rem' }}
          >
            {statusMeta.label}
          </span>
          <ChevronRight
            size={14}
            style={{ color: 'var(--color-text-muted)' }}
            aria-hidden="true"
          />
        </div>
      </div>

      {/* Lane description sub-line */}
      <p className="text-xs mt-1 ml-10" style={{ color: 'var(--color-text-muted)' }}>
        {lane.description}
      </p>
    </button>
  );
}

/* Named export for the chevron used in SessionCard collapse */
export { ChevronDown };