vkashti / app / admin / layout / page.tsx
page.tsx
Raw
'use client';

import { useState, useEffect, useCallback, useMemo, memo, useReducer, Suspense } from 'react';
import { createClient } from '@/utils/supabase/client';
import { FaPlus, FaEdit, FaTrash, FaChair } from 'react-icons/fa';
import { Database } from '@/types_db';
import { debounce } from 'lodash';

// Types
type TableRow = Omit<Database['public']['Tables']['tables']['Row'], 'width' | 'height'> & {
  width?: number;
  height?: number;
};

type FormDataType = Omit<TableRow, 'id' | 'created_at' | 'updated_at'>;

// Action types for reducer
type TableAction = 
  | { type: 'SET_TABLES'; payload: TableRow[] }
  | { type: 'ADD_TABLE'; payload: TableRow }
  | { type: 'UPDATE_TABLE'; payload: { id: number; table: Partial<TableRow> } }
  | { type: 'DELETE_TABLE'; payload: number }
  | { type: 'TEMP_UPDATE_POSITION'; payload: { id: number; x: number; y: number } }
  | { type: 'TEMP_UPDATE_SIZE'; payload: { id: number; width: number; height: number; capacity: number } };

// Reducer for table state management
function tableReducer(state: TableRow[], action: TableAction): TableRow[] {
  switch (action.type) {
    case 'SET_TABLES':
      return action.payload;
    case 'ADD_TABLE':
      return [...state, action.payload];
    case 'UPDATE_TABLE':
      return state.map(table => 
        table.id === action.payload.id 
          ? { ...table, ...action.payload.table } 
          : table
      );
    case 'DELETE_TABLE':
      return state.filter(table => table.id !== action.payload);
    case 'TEMP_UPDATE_POSITION':
      return state.map(table => 
        table.id === action.payload.id 
          ? { ...table, position_x: action.payload.x, position_y: action.payload.y } 
          : table
      );
    case 'TEMP_UPDATE_SIZE':
      return state.map(table => 
        table.id === action.payload.id 
          ? { 
              ...table, 
              width: action.payload.width, 
              height: action.payload.height,
              capacity: action.payload.capacity
            } 
          : table
      );
    default:
      return state;
  }
}

// Custom hook for table data management
function useTableData() {
  const supabase = createClient();
  const [tables, dispatch] = useReducer(tableReducer, []);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  // Fetch tables
  const fetchTables = useCallback(async () => {
    setLoading(true);
    try {
      const { data, error } = await supabase
        .from('tables')
        .select('*')
        .order('id');
      
      if (error) throw error;
      
      // Transform the data to match the TableRow type
      const transformedData: TableRow[] = (data || []).map(table => ({
        ...table,
        width: table.width || undefined,
        height: table.height || undefined
      }));
      
      dispatch({ type: 'SET_TABLES', payload: transformedData });
    } catch (err: any) {
      setError(err.message);
      console.error('Error fetching tables:', err);
    } finally {
      setLoading(false);
    }
  }, [supabase]);

  // Create table
  const createTable = useCallback(async (tableData: FormDataType) => {
    try {
      const { data, error } = await supabase
        .from('tables')
        .insert(tableData)
        .select()
        .single();
      
      if (error) throw error;
      
      // Transform the data to match the TableRow type
      const transformedData: TableRow = {
        ...data,
        width: data.width || undefined,
        height: data.height || undefined
      };
      
      dispatch({ type: 'ADD_TABLE', payload: transformedData });
      return { success: true };
    } catch (err: any) {
      setError(err.message);
      console.error('Error creating table:', err);
      return { success: false, error: err.message };
    }
  }, [supabase]);

  // Update table
  const updateTable = useCallback(async (id: number, tableData: Partial<Omit<TableRow, 'id'>>) => {
    try {
      const { error } = await supabase
        .from('tables')
        .update({
          ...tableData,
          updated_at: new Date().toISOString()
        })
        .eq('id', id);
      
      if (error) throw error;
      dispatch({ 
        type: 'UPDATE_TABLE', 
        payload: { id, table: { ...tableData, updated_at: new Date().toISOString() }} 
      });
      return { success: true };
    } catch (err: any) {
      setError(err.message);
      console.error('Error updating table:', err);
      return { success: false, error: err.message };
    }
  }, [supabase]);

  // Delete table
  const deleteTable = useCallback(async (id: number) => {
    try {
      const { error } = await supabase
        .from('tables')
        .delete()
        .eq('id', id);
      
      if (error) throw error;
      dispatch({ type: 'DELETE_TABLE', payload: id });
      return { success: true };
    } catch (err: any) {
      setError(err.message);
      console.error('Error deleting table:', err);
      return { success: false, error: err.message };
    }
  }, [supabase]);

  // Update table position temporarily (for dragging)
  const updateTablePosition = useCallback((id: number, x: number, y: number) => {
    dispatch({ type: 'TEMP_UPDATE_POSITION', payload: { id, x, y } });
  }, []);

  // Update table size temporarily (for resizing)
  const updateTableSize = useCallback((id: number, width: number, height: number, capacity: number) => {
    dispatch({ type: 'TEMP_UPDATE_SIZE', payload: { id, width, height, capacity } });
  }, []);

  return {
    tables,
    loading,
    error,
    fetchTables,
    createTable,
    updateTable,
    deleteTable,
    updateTablePosition,
    updateTableSize,
    setError
  };
}

// Memoized Grid component
const Grid = memo(({ width, height }: { width: number; height: number }) => {
  // Calculate grid cells only when dimensions change
  const gridCells = useMemo(() => {
    const rows = Math.floor(height / 20);
    const cols = Math.floor(width / 20);
    
    return Array.from({ length: rows }).map((_, rowIndex) => (
      Array.from({ length: cols }).map((_, colIndex) => (
        <div 
          key={`grid-${rowIndex}-${colIndex}`}
          className="border border-gray-100 select-none"
          style={{ 
            width: 20, 
            height: 20,
            gridRow: rowIndex + 1,
            gridColumn: colIndex + 1
          }}
        />
      ))
    ));
  }, [width, height]);

  return (
    <div className="absolute inset-0 grid grid-cols-[repeat(auto-fill,_20px)] grid-rows-[repeat(auto-fill,_20px)] select-none">
      {gridCells}
    </div>
  );
});

Grid.displayName = 'Grid';

// Table component
const Table = memo(({ 
  table, 
  isSelected, 
  isDragging,
  isResizing,
  onSelect, 
  onDragStart, 
  onDragEnd, 
  onResizeStart 
}: { 
  table: TableRow; 
  isSelected: boolean;
  isDragging: boolean;
  isResizing: boolean;
  onSelect: (table: TableRow) => void;
  onDragStart: (id: number) => void;
  onDragEnd: (e: React.MouseEvent, id: number) => void;
  onResizeStart: (e: React.MouseEvent, id: number, direction: string) => void;
}) => {
  // Track mouse position to distinguish between clicks and drags
  const [mouseDownPos, setMouseDownPos] = useState<{x: number, y: number} | null>(null);
  
  return (
    <div
      className={`absolute flex flex-col items-center justify-center border-2 rounded shadow-md cursor-move select-none ${
        isSelected
          ? 'border-blue-500 bg-blue-100'
          : 'border-amber-500 bg-amber-50'
      }`}
      style={{
        left: table.position_x,
        top: table.position_y,
        width: table.width || (table.capacity >= 6 ? 80 : 60),
        height: table.height || (table.capacity >= 6 ? 80 : 60),
        zIndex: isDragging || isResizing ? 10 : 1,
        userSelect: 'none' // Prevent text selection
      }}
      onClick={(e) => {
        if (!isResizing) {
          e.stopPropagation();
          // Only handle as a click if we haven't moved much
          if (mouseDownPos) {
            const dx = Math.abs(e.clientX - mouseDownPos.x);
            const dy = Math.abs(e.clientY - mouseDownPos.y);
            if (dx < 5 && dy < 5) {
              onSelect(table);
            }
          }
        }
      }}
      onMouseDown={(e) => {
        e.stopPropagation();
        // Save the position where mouse down happened
        setMouseDownPos({x: e.clientX, y: e.clientY});
        // We'll initiate drag only if mouse actually moves
        // This prevents drag start on simple click
      }}
      onMouseMove={(e) => {
        if (mouseDownPos) {
          const dx = Math.abs(e.clientX - mouseDownPos.x);
          const dy = Math.abs(e.clientY - mouseDownPos.y);
          // Start drag only if mouse has moved a bit
          if (dx > 5 || dy > 5) {
            onDragStart(table.id);
            setMouseDownPos(null); // Reset the position
          }
        }
      }}
      onMouseUp={(e) => {
        e.stopPropagation();
        setMouseDownPos(null); // Reset the position
        if (isDragging) {
          onDragEnd(e, table.id);
        }
      }}
      onMouseLeave={() => {
        // Reset on mouse leave to avoid state issues
        setMouseDownPos(null);
      }}
    >
      <FaChair className="text-amber-600 text-xl mb-1 pointer-events-none" />
      <span className="text-sm font-medium text-amber-800 pointer-events-none">{table.label}</span>
      <span className="text-xs text-amber-600 pointer-events-none">{table.capacity} места</span>
      
      {/* Resize handle */}
      <div 
        className="absolute bottom-0 right-0 w-4 h-4 bg-amber-500 rounded-bl cursor-se-resize"
        style={{ 
          transform: 'translate(50%, 50%)',
          zIndex: 20
        }}
        onMouseDown={(e) => {
          e.stopPropagation();
          onResizeStart(e, table.id, 'bottomRight');
        }}
      />
    </div>
  );
});

Table.displayName = 'Table';

// TableForm component
const TableForm = memo(({
  formData,
  isEditing,
  selectedTable,
  onInputChange,
  onSubmit,
  onCancel
}: {
  formData: FormDataType;
  isEditing: boolean;
  selectedTable: TableRow | null;
  onInputChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
  onSubmit: () => void;
  onCancel: () => void;
}) => {
  return (
    <div className="border rounded p-4 bg-white shadow-sm">
      <h2 className="text-lg font-semibold mb-4">
        {isEditing ? `Редактиране на маса ${selectedTable?.label}` : 'Добавяне на нова маса'}
      </h2>
      <div className="space-y-4">
        <div>
          <label className="block text-sm font-medium mb-1">Име на масата</label>
          <input
            type="text"
            name="label"
            value={formData.label}
            onChange={onInputChange}
            className="w-full border rounded py-2 px-3 bg-white"
            placeholder="напр. Т1, Маса 1"
          />
        </div>
        <div>
          <label className="block text-sm font-medium mb-1">Позиция X</label>
          <input
            type="number"
            name="position_x"
            value={formData.position_x}
            onChange={onInputChange}
            className="w-full border rounded py-2 px-3 bg-white"
          />
        </div>
        <div>
          <label className="block text-sm font-medium mb-1">Позиция Y</label>
          <input
            type="number"
            name="position_y"
            value={formData.position_y}
            onChange={onInputChange}
            className="w-full border rounded py-2 px-3 bg-white"
          />
        </div>
        <div>
          <label className="block text-sm font-medium mb-1">Брой места</label>
          <input
            type="number"
            name="capacity"
            min="1"
            value={formData.capacity}
            onChange={onInputChange}
            className="w-full border rounded py-2 px-3 bg-white"
          />
        </div>
        <div>
          <label className="block text-sm font-medium mb-1">Ширина (px)</label>
          <input
            type="number"
            name="width"
            min="40"
            value={formData.width}
            onChange={onInputChange}
            className="w-full border rounded py-2 px-3 bg-white"
          />
        </div>
        <div>
          <label className="block text-sm font-medium mb-1">Височина (px)</label>
          <input
            type="number"
            name="height"
            min="40"
            value={formData.height}
            onChange={onInputChange}
            className="w-full border rounded py-2 px-3 bg-white"
          />
        </div>
        <div className="flex gap-2">
          <button
            onClick={onSubmit}
            className="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded flex-1"
          >
            {isEditing ? 'Запази промените' : 'Създай маса'}
          </button>
          <button
            onClick={onCancel}
            className="bg-gray-300 hover:bg-gray-400 px-4 py-2 rounded"
          >
            Отказ
          </button>
        </div>
      </div>
    </div>
  );
});

TableForm.displayName = 'TableForm';

// TableInfo component
const TableInfo = memo(({
  table,
  onEdit,
  onDelete,
  onBack
}: {
  table: TableRow;
  onEdit?: (table: TableRow) => void;
  onDelete?: (id: number) => void;
  onBack: () => void;
}) => {
  // Get the base URL for the current environment
  const baseUrl = typeof window !== 'undefined' ? window.location.origin : '';
  const orderUrl = `${baseUrl}/menu?table=${table.id}`;
  
  // State for copy notification
  const [showCopyNotification, setShowCopyNotification] = useState(false);
  
  const handleCopyUrl = () => {
    navigator.clipboard.writeText(orderUrl);
    setShowCopyNotification(true);
    setTimeout(() => setShowCopyNotification(false), 2000);
  };

  return (
    <div>
      <div className="flex items-center mb-4">
        <button
          onClick={onBack}
          className="text-gray-600 hover:text-gray-800 mr-2"
        >
          <svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
            <path fillRule="evenodd" d="M9.707 14.707a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 1.414L7.414 9H15a1 1 0 110 2H7.414l2.293 2.293a1 1 0 010 1.414z" clipRule="evenodd" />
          </svg>
        </button>
        <h2 className="text-lg font-semibold">Информация за маса</h2>
      </div>
      <div className="space-y-2">
        <p><span className="font-medium">Име:</span> {table.label}</p>
        <p><span className="font-medium">Брой места:</span> {table.capacity} места</p>
        
        <div className="mt-4 p-3 bg-amber-50 rounded border border-amber-200 relative">
          <p className="text-sm font-medium text-amber-800 mb-2">Клиентски URL за поръчка:</p>
          <div className="flex items-center gap-2">
            <input
              type="text"
              readOnly
              value={orderUrl}
              className="flex-1 text-sm p-2 border rounded bg-white font-mono"
            />
            <button
              onClick={handleCopyUrl}
              className="text-amber-600 hover:text-amber-800 p-2 hover:bg-amber-100 rounded"
              title="Copy URL"
            >
              <svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
                <path d="M8 3a1 1 0 011-1h2a1 1 0 110 2H9a1 1 0 01-1-1z" />
                <path d="M6 3a2 2 0 00-2 2v11a2 2 0 002 2h8a2 2 0 002-2V5a2 2 0 00-2-2 3 3 0 01-3 3H9a3 3 0 01-3-3z" />
              </svg>
            </button>
          </div>
          
          {/* Copy notification toast */}
          {showCopyNotification && (
            <div className="absolute bottom-full left-1/2 transform -translate-x-1/2 mb-2 bg-green-100 text-green-800 px-3 py-1 rounded-full text-sm font-medium shadow-sm">
              URL копиран!
            </div>
          )}
        </div>

        <div className="pt-4 flex gap-2">
          {onEdit && (
            <button
              onClick={() => onEdit(table)}
              className="flex items-center gap-1 bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded"
            >
              <FaEdit /> Редактирай
            </button>
          )}
          
          {onDelete && (
            <button
              onClick={() => onDelete(table.id)}
              className="flex items-center gap-1 bg-red-500 hover:bg-red-600 text-white px-4 py-2 rounded"
            >
              <FaTrash /> Изтрий
            </button>
          )}
        </div>
      </div>
    </div>
  );
});

TableInfo.displayName = 'TableInfo';

// Fix the TablesList component type
type TableListItem = Pick<TableRow, 'id' | 'label' | 'capacity'>;

// TablesList component
const TablesList = memo(({
  tables,
  onEdit,
  onDelete,
  onSelect
}: {
  tables: TableListItem[];
  onEdit?: (table: TableListItem) => void;
  onDelete?: (id: number) => void;
  onSelect: (table: TableListItem) => void;
}) => {
  return (
    <div>
      <h2 className="text-lg font-semibold mb-4">Списък с маси</h2>
      <div className="space-y-2 max-h-[500px] overflow-auto">
        {tables.map(table => (
          <div 
            key={table.id} 
            className="p-2 border rounded hover:bg-amber-50 cursor-pointer flex justify-between items-center"
            onClick={() => onSelect(table)}
          >
            <div>
              <span className="font-medium">{table.label}</span>
              <span className="text-sm text-gray-500 ml-2">({table.capacity} места)</span>
            </div>
            <div className="flex gap-2">
              {onEdit && (
                <button
                  onClick={(e) => {
                    e.stopPropagation();
                    onEdit(table);
                  }}
                  className="text-gray-600 hover:text-gray-800"
                >
                  <FaEdit />
                </button>
              )}
              
              {onDelete && (
                <button
                  onClick={(e) => {
                    e.stopPropagation();
                    onDelete(table.id);
                  }}
                  className="text-gray-600 hover:text-gray-800"
                >
                  <FaTrash />
                </button>
              )}
            </div>
          </div>
        ))}
      </div>
    </div>
  );
});

TablesList.displayName = 'TablesList';

// Main component
function TableLayoutContent() {
  // State from custom hook
  const {
    tables,
    loading,
    error,
    fetchTables,
    createTable,
    updateTable,
    deleteTable,
    updateTablePosition,
    updateTableSize,
    setError
  } = useTableData();

  // UI state
  const [selectedTable, setSelectedTable] = useState<TableRow | null>(null);
  const [isEditing, setIsEditing] = useState(false);
  const [isCreating, setIsCreating] = useState(false);
  const [draggingTable, setDraggingTable] = useState<number | null>(null);
  const [isDragging, setIsDragging] = useState(false);
  const [zoom, setZoom] = useState(1);
  const [isResizing, setIsResizing] = useState(false);
  const [resizingTable, setResizingTable] = useState<number | null>(null);
  const [resizeDirection, setResizeDirection] = useState<string | null>(null);
  const [viewMode, setViewMode] = useState<'diagram' | 'list'>('diagram'); // View mode toggle
  const [isEditMode, setIsEditMode] = useState(false); // New state for edit mode toggle

  // Form state with default values
  const [formData, setFormData] = useState<FormDataType>({
    label: '',
    position_x: 0,
    position_y: 0,
    capacity: 1,
    width: 60,
    height: 60
  });

  // Calculate canvas dimensions (memoized)
  const { width, height } = useMemo(() => {
    if (tables.length === 0) return { width: 800, height: 600 };
    
    const maxX = Math.max(...tables.map(t => t.position_x)) + 100;
    const maxY = Math.max(...tables.map(t => t.position_y)) + 100;
    
    return {
      width: Math.max(800, maxX),
      height: Math.max(600, maxY)
    };
  }, [tables]);

  // Load tables on component mount
  useEffect(() => {
    fetchTables();
  }, [fetchTables]);

  // Debounced position update to reduce API calls during drag
  const debouncedUpdatePosition = useCallback(
    debounce(async (id: number, x: number, y: number) => {
      await updateTable(id, { position_x: x, position_y: y });
    }, 500),
    [updateTable]
  );

  // Debounced size update to reduce API calls during resize
  const debouncedUpdateSize = useCallback(
    debounce(async (id: number, width: number, height: number, capacity: number) => {
      await updateTable(id, { width, height, capacity });
    }, 500),
    [updateTable]
  );

  // Handle form input changes
  const handleInputChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
    const { name, value } = e.target;
    setFormData(prev => ({
      ...prev,
      [name]: name === 'capacity' || name === 'position_x' || name === 'position_y' || name === 'width' || name === 'height'
        ? parseInt(value) || 0 
        : value
    }));
  }, []);

  // Reset form to default values
  const resetForm = useCallback(() => {
    setFormData({
      label: '',
      position_x: 0,
      position_y: 0,
      capacity: 1,
      width: 60,
      height: 60
    });
  }, []);

  // Submit form handler (create or update)
  const handleSubmitForm = useCallback(async () => {
    if (isEditing && selectedTable) {
      const result = await updateTable(selectedTable.id, formData);
      if (result.success) {
        setIsEditing(false);
        setSelectedTable(null);
        resetForm();
      }
    } else if (isCreating) {
      const result = await createTable(formData);
      if (result.success) {
        setIsCreating(false);
        resetForm();
      }
    }
  }, [isEditing, isCreating, selectedTable, formData, updateTable, createTable, resetForm]);

  // Cancel form handler
  const handleCancelForm = useCallback(() => {
    setIsEditing(false);
    setIsCreating(false);
    setSelectedTable(null);
    resetForm();
  }, [resetForm]);

  // Handle delete table with confirmation
  const handleDeleteTable = useCallback((id: number) => {
    if (confirm('Сигурен ли сте, че искате да изтриете тази маса?')) {
      deleteTable(id);
      if (selectedTable?.id === id) {
        setSelectedTable(null);
        setIsEditing(false);
      }
    }
  }, [deleteTable, selectedTable]);

  // Modified to split table selection from table editing
  const handleSelectTable = useCallback((table: TableRow) => {
    setSelectedTable(table);
    setFormData({
      label: table.label,
      position_x: table.position_x,
      position_y: table.position_y,
      capacity: table.capacity,
      width: table.width || 60,
      height: table.height || 60
    });
    setIsEditing(false);
    setIsCreating(false);
  }, []);

  // Start editing a table
  const handleEditTable = useCallback((table: TableRow) => {
    handleSelectTable(table);
    setIsEditing(true);
  }, [handleSelectTable]);

  // Handle drag start - only if in edit mode
  const handleDragStart = useCallback((e: React.MouseEvent | number, id?: number) => {
    // Don't allow dragging if not in edit mode
    if (!isEditMode) return;
    
    // Accept either (event, id) or just (id)
    const tableId = typeof e === 'number' ? e : id;
    if (typeof tableId !== 'number') return;
    
    setDraggingTable(tableId);
    setIsDragging(true);
  }, [isEditMode]);

  // Handle drag end - save position to database
  const handleDragEnd = useCallback((e: React.MouseEvent, id: number) => {
    if (!isDragging) return;
    
    setIsDragging(false);
    setDraggingTable(null);
    
    const canvas = document.getElementById('layout-canvas');
    if (!canvas) return;
    
    const rect = canvas.getBoundingClientRect();
    const newX = Math.round((e.clientX - rect.left) / zoom);
    const newY = Math.round((e.clientY - rect.top) / zoom);
    
    // Update in Supabase (debounced)
    debouncedUpdatePosition(id, newX, newY);
  }, [isDragging, zoom, debouncedUpdatePosition]);

  // Handle canvas click to create a new table
  const handleCanvasClick = useCallback((e: React.MouseEvent) => {
    if (isDragging || isResizing || isEditing || isCreating) return;
    
    const canvas = document.getElementById('layout-canvas');
    if (!canvas) return;
    
    const rect = canvas.getBoundingClientRect();
    const posX = Math.round((e.clientX - rect.left) / zoom);
    const posY = Math.round((e.clientY - rect.top) / zoom);
    
    setFormData(prev => ({
      ...prev,
      position_x: posX,
      position_y: posY
    }));
    
    setIsCreating(true);
    setSelectedTable(null);
  }, [isDragging, isResizing, isEditing, isCreating, zoom]);

  // Handle resize start - only if in edit mode
  const handleResizeStart = useCallback((e: React.MouseEvent, id: number, direction: string) => {
    // Don't allow resizing if not in edit mode
    if (!isEditMode) return;
    
    e.stopPropagation();
    setResizingTable(id);
    setIsResizing(true);
    setResizeDirection(direction);
  }, [isEditMode]);

  // Handle mouse move for dragging
  const handleMouseMove = useCallback((e: React.MouseEvent) => {
    if (isDragging && draggingTable !== null) {
      const canvas = document.getElementById('layout-canvas');
      if (!canvas) return;
      
      const rect = canvas.getBoundingClientRect();
      const newX = Math.round((e.clientX - rect.left) / zoom);
      const newY = Math.round((e.clientY - rect.top) / zoom);
      
      updateTablePosition(draggingTable, newX, newY);
    }
  }, [isDragging, draggingTable, zoom, updateTablePosition]);

  // Add document event listeners for resize
  useEffect(() => {
    const handleMouseMove = (e: MouseEvent) => {
      if (!isResizing || resizingTable === null) return;
      
      const canvas = document.getElementById('layout-canvas');
      if (!canvas) return;
      
      const rect = canvas.getBoundingClientRect();
      const table = tables.find(t => t.id === resizingTable);
      if (!table) return;
      
      const mouseX = (e.clientX - rect.left) / zoom;
      const mouseY = (e.clientY - rect.top) / zoom;
      
      if (resizeDirection === 'bottomRight') {
        const width = Math.max(40, Math.round(mouseX - table.position_x));
        const height = Math.max(40, Math.round(mouseY - table.position_y));
        
        // Calculate capacity based on area
        const area = width * height;
        const newCapacity = Math.max(1, Math.round(area / 900));
        
        updateTableSize(resizingTable, width, height, newCapacity);
      }
    };

    const handleMouseUp = async () => {
      if (!isResizing || resizingTable === null) return;
      
      const table = tables.find(t => t.id === resizingTable);
      if (table) {
        debouncedUpdateSize(
          resizingTable, 
          table.width || 60, 
          table.height || 60, 
          table.capacity
        );
      }
      
      setIsResizing(false);
      setResizingTable(null);
      setResizeDirection(null);
    };

    if (isResizing) {
      document.addEventListener('mousemove', handleMouseMove);
      document.addEventListener('mouseup', handleMouseUp);
    }
    
    return () => {
      document.removeEventListener('mousemove', handleMouseMove);
      document.removeEventListener('mouseup', handleMouseUp);
    };
  }, [isResizing, resizingTable, resizeDirection, tables, zoom, updateTableSize, debouncedUpdateSize]);

  // Update the tablesList useMemo to use the new type
  const tablesList = useMemo<TableListItem[]>(() => {
    return tables.map(({ id, label, capacity }) => ({ id, label, capacity }));
  }, [tables]);

  // Add this function that was missing
  const handleCreateTable = () => {
    setIsCreating(true);
    setIsEditing(false);
    setSelectedTable(null);
    // Reset form data
    setFormData({
      label: '',
      position_x: 100,
      position_y: 100,
      capacity: 1,
      width: 60,
      height: 60
    });
  };

  // Toggle edit mode
  const toggleEditMode = useCallback(() => {
    setIsEditMode(prev => !prev);
    
    // If turning off edit mode, cancel any ongoing edits
    if (isEditMode) {
      setIsEditing(false);
      setIsCreating(false);
      setSelectedTable(null);
      setIsDragging(false);
      setDraggingTable(null);
      setIsResizing(false);
      setResizingTable(null);
    }
  }, [isEditMode]);

  return (
    <div className="container mx-auto px-0 py-0">
        {error && (
          <div className="bg-red-50 text-red-700 p-4 rounded-lg mb-6">
            {error}
          </div>
        )}

      {/* View mode and edit mode toggles */}
      <div className="mb-6 p-3 shadow bg-white rounded-lg">
        <div className="flex justify-between items-center">
          <div className="flex gap-3 items-center">
            {/* Edit mode toggle - changed to ghost button */}
            <button
              onClick={toggleEditMode}
              className={`flex items-center gap-1 px-3 py-1 rounded-md text-sm border ${
                isEditMode 
                  ? 'border-gray-300 text-gray-700' 
                  : 'border-gray-200 text-gray-600'
              } hover:bg-gray-50`}
              title={isEditMode ? "Режим на редактиране" : "Режим на преглед"}
            >
              {isEditMode ? (
                <>
                  <FaEdit className="h-4 w-4" />
                  <span className="hidden sm:inline">Режим на редактиране</span>
                </>
              ) : (
                <>
                  <svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4" viewBox="0 0 20 20" fill="currentColor">
                    <path d="M10 12a2 2 0 100-4 2 2 0 000 4z" />
                    <path fillRule="evenodd" d="M.458 10C1.732 5.943 5.522 3 10 3s8.268 2.943 9.542 7c-1.274 4.057-5.064 7-9.542 7S1.732 14.057.458 10zM14 10a4 4 0 11-8 0 4 4 0 018 0z" clipRule="evenodd" />
                  </svg>
                  <span className="hidden sm:inline">Режим на преглед</span>
                </>
              )}
            </button>
          
            {/* View mode toggle - only shown on mobile */}
            <button
              onClick={() => setViewMode(viewMode === 'diagram' ? 'list' : 'diagram')}
              className="md:hidden flex items-center gap-1 px-3 py-1 rounded-md text-sm border border-gray-300 text-gray-700 hover:bg-gray-50"
              title={viewMode === 'diagram' ? "Превключи към списък" : "Превключи към диаграма"}
            >
              {viewMode === 'diagram' ? (
                <>
                  <svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4" viewBox="0 0 20 20" fill="currentColor">
                    <path fillRule="evenodd" d="M3 4a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zm0 4a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zm0 4a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zm0 4a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1z" clipRule="evenodd" />
                  </svg>
                  <span className="hidden sm:inline md:hidden">Превключи към списък</span>
                </>
              ) : (
                <>
                  <svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4" viewBox="0 0 20 20" fill="currentColor">
                    <path fillRule="evenodd" d="M3 5a2 2 0 012-2h10a2 2 0 012 2v10a2 2 0 01-2 2H5a2 2 0 01-2-2V5zm2-2h10v10H5V3z" clipRule="evenodd" />
                  </svg>
                  <span className="hidden sm:inline md:hidden">Превключи към диаграма</span>
                </>
              )}
            </button>
            
            {/* Zoom controls - only visible when in diagram view (hidden on mobile when in list view) */}
            <div className={`flex items-center border border-gray-300 rounded-lg overflow-hidden ${viewMode === 'list' ? 'hidden md:flex' : ''}`}>
              <button
                onClick={() => setZoom(prev => Math.max(0.5, prev - 0.1))}
                className="px-2 py-1 bg-gray-50 hover:bg-gray-100 text-gray-700 text-sm"
              >
                -
              </button>
              <span className="px-2 py-1 bg-white text-xs sm:text-sm">
                {Math.round(zoom * 100)}%
              </span>
              <button
                onClick={() => setZoom(prev => Math.min(2, prev + 0.1))}
                className="px-2 py-1 bg-gray-50 hover:bg-gray-100 text-gray-700 text-sm"
              >
                +
              </button>
            </div>
          </div>
        </div>
      </div>

      <div className="flex flex-col md:flex-row gap-6">
        {/* Canvas for layout - hidden when in list view */}
        <div className={`w-full md:w-[70%] bg-white rounded-lg shadow-md overflow-hidden ${viewMode === 'list' ? 'hidden md:block' : ''}`}>
          {loading ? (
            <div className="flex items-center justify-center h-96">
              <div className="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-orange-500"></div>
              <span className="ml-3 text-gray-600">Зареждане...</span>
            </div>
          ) : (
            <div
              className="relative overflow-auto border border-gray-200 bg-gray-50"
              style={{ height: '650px' }}
              onMouseMove={handleMouseMove}
              onMouseUp={() => {
                setIsDragging(false);
                setDraggingTable(null);
              }}
              onClick={isEditMode ? handleCanvasClick : undefined}
            >
              <div
                id="layout-canvas"
                className="relative"
                style={{
                  width: `${width * zoom}px`,
                  height: `${height * zoom}px`,
                  transformOrigin: 'top left',
                  transform: `scale(${zoom})`,
                  background: 'white'
                }}
              >
                {tables.map(table => (
                  <div
                    key={table.id}
                    className={`absolute border ${
                      selectedTable?.id === table.id
                        ? 'border-orange-500 bg-orange-50'
                        : 'border-gray-400 bg-gray-100'
                    } rounded-md text-center flex flex-col justify-center items-center ${isEditMode ? 'cursor-pointer' : ''} transition-colors hover:bg-gray-200`}
                    style={{
                      left: `${table.position_x}px`,
                      top: `${table.position_y}px`,
                      width: `${table.width || 60}px`,
                      height: `${table.height || 60}px`
                    }}
                    onClick={e => {
                      e.stopPropagation();
                      // Allow selecting tables even in view mode, but not for editing
                      handleSelectTable(table);
                    }}
                    onMouseDown={e => {
                      if (isEditMode && !isResizing) handleDragStart(e, table.id);
                    }}
                  >
                    <span className="font-medium text-sm truncate max-w-full px-2">
                      {table.label}
                    </span>
                    <span className="text-xs text-gray-600">
                      {table.capacity} {table.capacity === 1 ? 'място' : 'места'}
                    </span>

                    {/* Resize handle - only visible in edit mode */}
                    {isEditMode && (
                      <div
                        className="absolute bottom-0 right-0 w-4 h-4 bg-gray-300 cursor-se-resize rounded-bl-md"
                        onMouseDown={e => {
                          e.stopPropagation();
                          handleResizeStart(e, table.id, 'bottomRight');
                        }}
                      />
                    )}
                  </div>
                ))}
              </div>
            </div>
          )}
        </div>

        {/* Sidebar - shown differently on mobile based on viewMode */}
        <div className={`w-full md:w-[30%] bg-white p-4 rounded-lg shadow-md ${viewMode === 'diagram' ? 'hidden md:block' : ''}`}>
          {/* Controls - only show Add Table button in edit mode */}
          {!isEditing && !isCreating && isEditMode && (
            <div className="mb-4">
              <button
                onClick={handleCreateTable}
                className="flex items-center justify-center gap-2 px-4 py-2.5 bg-orange-500 text-white rounded-lg hover:bg-orange-600 transition-colors w-full"
              >
                <FaPlus className="text-sm" />
                <span>Добави Маса</span>
              </button>
            </div>
          )}
          
          {/* Only show form when in edit mode */}
          {isEditMode && (isEditing || isCreating) && (
            <TableForm
              formData={formData}
              isEditing={isEditing}
              selectedTable={selectedTable}
              onInputChange={handleInputChange}
              onSubmit={handleSubmitForm}
              onCancel={handleCancelForm}
            />
          )}

          {selectedTable && !isEditing && (
            <TableInfo
              table={selectedTable}
              onEdit={isEditMode ? handleEditTable : undefined}
              onDelete={isEditMode ? handleDeleteTable : undefined}
              onBack={() => setSelectedTable(null)}
            />
          )}

          {!selectedTable && !isEditing && !isCreating && tables.length > 0 && (
            <TablesList
              tables={tablesList}
              onEdit={isEditMode ? (tableInfo) => {
                const fullTable = tables.find(t => t.id === tableInfo.id);
                if (fullTable) handleEditTable(fullTable);
              } : undefined}
              onDelete={isEditMode ? handleDeleteTable : undefined}
              onSelect={(tableInfo) => {
                const fullTable = tables.find(t => t.id === tableInfo.id);
                if (fullTable) handleSelectTable(fullTable);
              }}
            />
          )}
        </div>
      </div>
    </div>
  );
}

export default function TableLayoutPage() {
  return (
    <Suspense fallback={<></>}>
      <TableLayoutContent />
    </Suspense>
  );
}