editable-column-header.tsx8.3 KBView on GitHub
/**
 * Editable Column Header Component
 * Allows users to edit column name, type, and description
 */

import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import {
  Braces,
  Calendar,
  CheckSquare,
  ChevronDown,
  Clock,
  Hash,
  Mail,
  Trash2,
  Type,
} from 'lucide-react';
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
import type { CRMColumn, ColumnType } from '../store/crmSlice';
import { Textarea } from '@/components/ui/textarea';
import { memo, useCallback, useState } from 'react';
import { Button } from '@/components/ui/button';
import { Label } from '@/components/ui/label';
import { Input } from '@/components/ui/input';

// Icon mapping for column types
export const getColumnIcon = (type: ColumnType) => {
  switch (type) {
    case 'text':
      return <Type className="h-4 w-4" />;
    case 'number':
      return <Hash className="h-4 w-4" />;
    case 'date':
      return <Calendar className="h-4 w-4" />;
    case 'json':
      return <Braces className="h-4 w-4" />;
    case 'checkbox':
      return <CheckSquare className="h-4 w-4" />;
    case 'select':
      return <ChevronDown className="h-4 w-4" />;
    case 'email':
      return <Mail className="h-4 w-4" />;
    case 'timeline':
      return <Clock className="h-4 w-4" />;
    default:
      return <Type className="h-4 w-4" />;
  }
};

interface EditableColumnHeaderProps {
  colConfig: CRMColumn;
  onUpdate: (updatedColumn: CRMColumn) => void;
  onDelete: (columnId: string) => void;
}

export const EditableColumnHeader = memo(
  ({ colConfig, onUpdate, onDelete }: EditableColumnHeaderProps) => {
    const [isOpen, setIsOpen] = useState(false);
    const [editingColumn, setEditingColumn] = useState<CRMColumn | null>(null);

    const handleOpenChange = useCallback(
      (open: boolean) => {
        if (open) {
          setEditingColumn({ ...colConfig });
          setIsOpen(true);
        } else {
          setIsOpen(false);
          setEditingColumn(null);
        }
      },
      [colConfig],
    );

    const handleSave = useCallback(() => {
      if (editingColumn) {
        onUpdate(editingColumn);
        setIsOpen(false);
        setEditingColumn(null);
      }
    }, [editingColumn, onUpdate]);

    const handleDelete = useCallback(() => {
      onDelete(colConfig.id);
      setIsOpen(false);
      setEditingColumn(null);
    }, [colConfig.id, onDelete]);

    return (
      <div className="flex min-w-0 items-center gap-2">
        <Popover open={isOpen} onOpenChange={handleOpenChange}>
          <PopoverTrigger asChild>
            <button className="flex min-w-0 flex-1 items-center gap-2 text-left hover:opacity-70">
              <div className="text-muted-foreground shrink-0">{getColumnIcon(colConfig.type)}</div>
              <span className="truncate font-medium">{colConfig.name}</span>
            </button>
          </PopoverTrigger>
          <PopoverContent className="w-96" align="start">
            {editingColumn && (
              <div className="space-y-4">
                <div>
                  <h4 className="mb-3 font-medium leading-none">Edit Column</h4>
                </div>
                <div className="space-y-2">
                  <Label htmlFor={`edit-name-${colConfig.id}`}>Column Name</Label>
                  <Input
                    id={`edit-name-${colConfig.id}`}
                    value={editingColumn.name}
                    onChange={(e) => setEditingColumn({ ...editingColumn, name: e.target.value })}
                    placeholder="Column name"
                  />
                </div>
                <div className="space-y-2">
                  <Label>Column Type</Label>
                  <DropdownMenu>
                    <DropdownMenuTrigger asChild>
                      <Button variant="outline" className="w-full justify-between">
                        <span className="flex items-center gap-2">
                          {getColumnIcon(editingColumn.type)}
                          <span className="capitalize">{editingColumn.type}</span>
                        </span>
                        <ChevronDown className="h-4 w-4" />
                      </Button>
                    </DropdownMenuTrigger>
                    <DropdownMenuContent className="w-full">
                      <DropdownMenuItem
                        onClick={() => setEditingColumn({ ...editingColumn, type: 'text' })}
                      >
                        <Type className="mr-2 h-4 w-4" />
                        Text
                      </DropdownMenuItem>
                      <DropdownMenuItem
                        onClick={() => setEditingColumn({ ...editingColumn, type: 'email' })}
                      >
                        <Mail className="mr-2 h-4 w-4" />
                        Email
                      </DropdownMenuItem>
                      <DropdownMenuItem
                        onClick={() => setEditingColumn({ ...editingColumn, type: 'number' })}
                      >
                        <Hash className="mr-2 h-4 w-4" />
                        Number
                      </DropdownMenuItem>
                      <DropdownMenuItem
                        onClick={() => setEditingColumn({ ...editingColumn, type: 'date' })}
                      >
                        <Calendar className="mr-2 h-4 w-4" />
                        Date
                      </DropdownMenuItem>
                      <DropdownMenuItem
                        onClick={() => setEditingColumn({ ...editingColumn, type: 'checkbox' })}
                      >
                        <CheckSquare className="mr-2 h-4 w-4" />
                        Checkbox
                      </DropdownMenuItem>
                      <DropdownMenuItem
                        onClick={() => setEditingColumn({ ...editingColumn, type: 'select' })}
                      >
                        <ChevronDown className="mr-2 h-4 w-4" />
                        Select
                      </DropdownMenuItem>
                      <DropdownMenuItem
                        onClick={() => setEditingColumn({ ...editingColumn, type: 'timeline' })}
                      >
                        <Clock className="mr-2 h-4 w-4" />
                        Timeline
                      </DropdownMenuItem>
                    </DropdownMenuContent>
                  </DropdownMenu>
                </div>
                <div className="space-y-2">
                  <Label htmlFor={`edit-description-${colConfig.id}`}>Description</Label>
                  <Textarea
                    id={`edit-description-${colConfig.id}`}
                    value={editingColumn.description}
                    onChange={(e) =>
                      setEditingColumn({ ...editingColumn, description: e.target.value })
                    }
                    placeholder="Add a description for this column..."
                    rows={3}
                  />
                </div>
                {colConfig.isFixed && (
                  <div className="bg-muted rounded-md p-3">
                    <p className="text-muted-foreground text-sm">
                      This is a fixed column and cannot be deleted.
                    </p>
                  </div>
                )}
                <div className="flex gap-2">
                  {!colConfig.isFixed && (
                    <Button
                      variant="destructive"
                      size="sm"
                      className="flex-1"
                      onClick={handleDelete}
                    >
                      <Trash2 className="mr-2 h-4 w-4" />
                      Delete
                    </Button>
                  )}
                  <Button
                    variant="outline"
                    size="sm"
                    className="flex-1"
                    onClick={() => {
                      setIsOpen(false);
                      setEditingColumn(null);
                    }}
                  >
                    Cancel
                  </Button>
                  <Button size="sm" className="flex-1" onClick={handleSave}>
                    Save
                  </Button>
                </div>
              </div>
            )}
          </PopoverContent>
        </Popover>
      </div>
    );
  },
);

EditableColumnHeader.displayName = 'EditableColumnHeader';