PropertiesPanel.tsx 11.4 KB
import React from 'react';
import { ScrollArea } from '../../ui/scroll-area';
import { Input } from '../../ui/input';
import { Button } from '../../ui/button';
import { Label } from '../../ui/label';
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '../../ui/select';
import { Switch } from '../../ui/switch';
import type {
  LabelTemplate,
  LabelElement,
  LabelType,
  Rotation,
  Border,
} from '../../../types/labelTemplate';

interface PropertiesPanelProps {
  template: LabelTemplate;
  selectedElement: LabelElement | null;
  onTemplateChange: (patch: Partial<LabelTemplate>) => void;
  onElementChange: (id: string, patch: Partial<LabelElement>) => void;
  onDeleteElement?: (id: string) => void;
}

export function PropertiesPanel({
  template,
  selectedElement,
  onTemplateChange,
  onElementChange,
  onDeleteElement,
}: PropertiesPanelProps) {
  const panelStyle = { width: 288, minWidth: 288, maxWidth: 288 };
  const panelClass = "shrink-0 border-l border-gray-200 bg-white flex flex-col h-full";

  if (selectedElement) {
    return (
      <div className={panelClass} style={panelStyle}>
        <div className="px-3 py-2 border-b border-gray-200 font-semibold text-gray-800 bg-gray-50 border-l-[3px] border-l-[#1e3a8a]">
          Properties (Element)
        </div>
        <ScrollArea className="flex-1">
          <div className="p-3 space-y-3">
            <div className="grid grid-cols-2 gap-2">
              <div>
                <Label className="text-xs">X</Label>
                <Input
                  type="number"
                  value={selectedElement.x}
                  onChange={(e) =>
                    onElementChange(selectedElement.id, {
                      x: Number(e.target.value) || 0,
                    })
                  }
                  className="h-8 text-sm"
                />
              </div>
              <div>
                <Label className="text-xs">Y</Label>
                <Input
                  type="number"
                  value={selectedElement.y}
                  onChange={(e) =>
                    onElementChange(selectedElement.id, {
                      y: Number(e.target.value) || 0,
                    })
                  }
                  className="h-8 text-sm"
                />
              </div>
            </div>
            <div className="grid grid-cols-2 gap-2">
              <div>
                <Label className="text-xs">Width</Label>
                <Input
                  type="number"
                  value={selectedElement.width}
                  onChange={(e) =>
                    onElementChange(selectedElement.id, {
                      width: Math.max(1, Number(e.target.value) || 0),
                    })
                  }
                  className="h-8 text-sm"
                />
              </div>
              <div>
                <Label className="text-xs">Height</Label>
                <Input
                  type="number"
                  value={selectedElement.height}
                  onChange={(e) =>
                    onElementChange(selectedElement.id, {
                      height: Math.max(1, Number(e.target.value) || 0),
                    })
                  }
                  className="h-8 text-sm"
                />
              </div>
            </div>
            <div>
              <Label className="text-xs">Rotation</Label>
              <Select
                value={selectedElement.rotation}
                onValueChange={(v: Rotation) =>
                  onElementChange(selectedElement.id, { rotation: v })
                }
              >
                <SelectTrigger className="h-8 text-sm">
                  <SelectValue />
                </SelectTrigger>
                <SelectContent>
                  <SelectItem value="horizontal">horizontal</SelectItem>
                  <SelectItem value="vertical">vertical</SelectItem>
                </SelectContent>
              </Select>
            </div>
            <div>
              <Label className="text-xs">Border</Label>
              <Select
                value={selectedElement.border}
                onValueChange={(v: Border) =>
                  onElementChange(selectedElement.id, { border: v })
                }
              >
                <SelectTrigger className="h-8 text-sm">
                  <SelectValue />
                </SelectTrigger>
                <SelectContent>
                  <SelectItem value="none">none</SelectItem>
                  <SelectItem value="line">line</SelectItem>
                  <SelectItem value="dotted">dotted</SelectItem>
                </SelectContent>
              </Select>
            </div>
            <ElementConfigFields
              element={selectedElement}
              onChange={(config) =>
                onElementChange(selectedElement.id, { config: { ...selectedElement.config, ...config } })
              }
            />
            {onDeleteElement && (
              <div className="pt-4 border-t border-gray-200">
                <Button
                  variant="destructive"
                  className="w-full"
                  onClick={() => onDeleteElement(selectedElement.id)}
                >
                  Delete Element
                </Button>
              </div>
            )}
          </div>
        </ScrollArea>
      </div>
    );
  }

  return (
    <div className={panelClass} style={panelStyle}>
      <div className="px-3 py-2 border-b border-gray-200 font-semibold text-gray-800 bg-gray-50 border-l-[3px] border-l-[#1e3a8a]">
        Properties (Template)
      </div>
      <ScrollArea className="flex-1">
        <div className="p-3 space-y-3">
          <div>
            <Label className="text-xs">Template Name</Label>
            <Input
              value={template.name}
              onChange={(e) => onTemplateChange({ name: e.target.value })}
              className="h-8 text-sm mt-1"
            />
          </div>
          <div>
            <Label className="text-xs">Label Type</Label>
            <Select
              value={template.labelType}
              onValueChange={(v: LabelType) => onTemplateChange({ labelType: v })}
            >
              <SelectTrigger className="h-8 text-sm mt-1">
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="PRICE">PRICE</SelectItem>
                <SelectItem value="NUTRITION">NUTRITION</SelectItem>
                <SelectItem value="SHIPPING">SHIPPING</SelectItem>
              </SelectContent>
            </Select>
          </div>
          <div>
            <Label className="text-xs">Applied Location</Label>
            <Select
              value={template.appliedLocation}
              onValueChange={(v) => onTemplateChange({ appliedLocation: v })}
            >
              <SelectTrigger className="h-8 text-sm mt-1">
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="ALL">All Locations</SelectItem>
                <SelectItem value="loc-a">Location A</SelectItem>
                <SelectItem value="loc-b">Location B</SelectItem>
              </SelectContent>
            </Select>
          </div>
          <div className="grid grid-cols-2 gap-2">
            <div>
              <Label className="text-xs">Width</Label>
              <div className="h-8 text-sm flex items-center text-gray-600">
                {template.width} {template.unit}
              </div>
            </div>
            <div>
              <Label className="text-xs">Height</Label>
              <div className="h-8 text-sm flex items-center text-gray-600">
                {template.height} {template.unit}
              </div>
            </div>
          </div>
          <div className="flex items-center gap-2">
            <Switch
              checked={template.showRuler}
              onCheckedChange={(v) => onTemplateChange({ showRuler: v })}
            />
            <Label className="text-xs">Show Ruler</Label>
          </div>
        </div>
      </ScrollArea>
    </div>
  );
}

function ElementConfigFields({
  element,
  onChange,
}: {
  element: LabelElement;
  onChange: (config: Record<string, unknown>) => void;
}) {
  const cfg = element.config as Record<string, unknown>;
  const update = (key: string, value: unknown) =>
    onChange({ [key]: value });

  switch (element.type) {
    case 'TEXT_STATIC':
    case 'TEXT_PRODUCT':
    case 'TEXT_PRICE':
      return (
        <>
          <div>
            <Label className="text-xs">Text</Label>
            <Input
              value={(cfg.text as string) ?? ''}
              onChange={(e) => update('text', e.target.value)}
              className="h-8 text-sm mt-1"
            />
          </div>
          <div>
            <Label className="text-xs">Font Size</Label>
            <Input
              type="number"
              value={(cfg.fontSize as number) ?? 14}
              onChange={(e) => update('fontSize', Number(e.target.value) || 14)}
              className="h-8 text-sm mt-1"
            />
          </div>
          <div>
            <Label className="text-xs">Text Align</Label>
            <Select
              value={(cfg.textAlign as string) ?? 'left'}
              onValueChange={(v) => update('textAlign', v)}
            >
              <SelectTrigger className="h-8 text-sm mt-1">
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="left">Left</SelectItem>
                <SelectItem value="center">Center</SelectItem>
                <SelectItem value="right">Right</SelectItem>
              </SelectContent>
            </Select>
          </div>
        </>
      );
    case 'BARCODE':
      return (
        <>
          <div>
            <Label className="text-xs">Data</Label>
            <Input
              value={(cfg.data as string) ?? ''}
              onChange={(e) => update('data', e.target.value)}
              className="h-8 text-sm mt-1"
            />
          </div>
          <div>
            <Label className="text-xs">Orientation</Label>
            <Select
              value={(cfg.orientation as string) ?? 'horizontal'}
              onValueChange={(v) => update('orientation', v)}
            >
              <SelectTrigger className="h-8 text-sm mt-1">
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="horizontal">Horizontal</SelectItem>
                <SelectItem value="vertical">Vertical</SelectItem>
              </SelectContent>
            </Select>
          </div>
        </>
      );
    case 'QRCODE':
      return (
        <div>
          <Label className="text-xs">Data (URL)</Label>
          <Input
            value={(cfg.data as string) ?? ''}
            onChange={(e) => update('data', e.target.value)}
            className="h-8 text-sm mt-1"
          />
        </div>
      );
    case 'WEIGHT':
      return (
        <div>
          <Label className="text-xs">Value</Label>
          <Input
            type="number"
            value={(cfg.value as number) ?? 0}
            onChange={(e) => update('value', Number(e.target.value) || 0)}
            className="h-8 text-sm mt-1"
          />
        </div>
      );
    default:
      return (
        <div className="text-xs text-gray-500">
          Config for {element.type} (edit in code if needed)
        </div>
      );
  }
}