CRMTableHeader.tsx3.6 KBView on GitHub
import { SortableColumnHeader } from './sortable-column-header';
import type { CRMColumn } from '../store/crmSlice';
import { Reorder } from 'motion/react';
import { memo } from 'react';

const DEFAULT_COLUMN_WIDTH = 200;

interface CRMTableHeaderProps {
  columnsConfig: CRMColumn[];
  columnWidths: Record<string, number>;
  totalSize: number;
  onReorder: (newOrder: CRMColumn[]) => void;
  onUpdateColumn?: (column: CRMColumn) => void;
  onDeleteColumn?: (columnId: string) => void;
  onResizeStart?: (columnId: string, startX: number, startWidth: number) => void;
}

export const CRMTableHeader = memo(
  function CRMTableHeader({
    columnsConfig,
    columnWidths,
    totalSize,
    onReorder,
    onUpdateColumn,
    onDeleteColumn,
    onResizeStart,
  }: CRMTableHeaderProps) {
    const handleResizeStart = (columnId: string) => (e: React.MouseEvent | React.TouchEvent) => {
      e.preventDefault();
      const startX = 'touches' in e ? e.touches[0].clientX : e.clientX;
      const startWidth = columnWidths[columnId] || DEFAULT_COLUMN_WIDTH;
      onResizeStart?.(columnId, startX, startWidth);
    };

    return (
      <thead
        className="bg-background border-border sticky top-0 !z-[10] grid border-b"
        style={{
          width: totalSize,
        }}
      >
        <Reorder.Group
          as="tr"
          axis="x"
          values={columnsConfig}
          onReorder={onReorder}
          className="group hover:bg-transparent"
          style={{ display: 'flex', width: '100%' }}
        >
          {columnsConfig.map((colConfig) => {
            // Check if this is the company column (should always be pinned left)
            const isCompanyColumn = colConfig.id === 'primaryCompany';
            const currentSize = columnWidths[colConfig.id] || DEFAULT_COLUMN_WIDTH;

            return (
              <Reorder.Item
                key=[redacted]
                as="th"
                value={colConfig}
                dragListener={!colConfig.isFixed}
                className={`bg-background text-muted-foreground group flex shrink-0 items-center justify-center overflow-visible px-1 py-3 text-center align-middle [&:has([role=checkbox])]:pr-0 ${
                  isCompanyColumn ? 'sticky left-0 !z-[20]' : 'relative !z-[5]'
                } ${!colConfig.isFixed ? 'cursor-grab active:cursor-grabbing' : ''}`}
                style={{
                  width: currentSize,
                  flexBasis: currentSize,
                  minWidth: 0,
                  maxWidth: currentSize,
                }}
              >
                <SortableColumnHeader
                  colConfig={colConfig}
                  onUpdate={onUpdateColumn}
                  onDelete={onDeleteColumn}
                />
                <div
                  onMouseDown={handleResizeStart(colConfig.id)}
                  onTouchStart={handleResizeStart(colConfig.id)}
                  className="group/resizer absolute right-0 top-0 !z-[25] -mr-2 flex h-full w-4 cursor-col-resize touch-none select-none items-center justify-center"
                >
                  <div className="h-full w-[2px] bg-border transition-colors group-hover/resizer:bg-primary/50" />
                </div>
              </Reorder.Item>
            );
          })}
        </Reorder.Group>
      </thead>
    );
  },
  (prev, next) => {
    // 1. Check total size
    if (prev.totalSize !== next.totalSize) return false;

    // 2. Check columns config (order, new columns, etc)
    if (prev.columnsConfig !== next.columnsConfig) return false;

    // 3. Check column widths
    if (prev.columnWidths !== next.columnWidths) return false;

    return true;
  },
);