LabelTemplatesView.tsx 6.1 KB
import React, { useState, useCallback, useEffect } from 'react';
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from '../ui/table';
import { Input } from '../ui/input';
import { Button } from '../ui/button';
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '../ui/select';
import { Plus, Pencil } from 'lucide-react';
import { getTemplateList, getTemplate } from '../../lib/labelTemplateStorage';
import type { LabelTemplate } from '../../types/labelTemplate';
import { LabelTemplateEditor } from './LabelTemplateEditor';

export function LabelTemplatesView() {
  const [templates, setTemplates] = useState<LabelTemplate[]>(() => getTemplateList());
  const [viewMode, setViewMode] = useState<'list' | 'editor'>('list');
  const [editingTemplateId, setEditingTemplateId] = useState<string | null>(null);
  const [search, setSearch] = useState('');
  const [locationFilter, setLocationFilter] = useState('all');

  const refreshList = useCallback(() => {
    setTemplates(getTemplateList());
  }, []);

  useEffect(() => {
    if (viewMode === 'list') refreshList();
  }, [viewMode, refreshList]);

  const filtered = templates.filter((t) => {
    const matchSearch =
      !search || t.name.toLowerCase().includes(search.toLowerCase());
    const matchLoc =
      locationFilter === 'all' || t.appliedLocation === locationFilter;
    return matchSearch && matchLoc;
  });

  const handleNewTemplate = () => {
    setEditingTemplateId(null);
    setViewMode('editor');
  };

  const handleEditTemplate = (id: string) => {
    setEditingTemplateId(id);
    setViewMode('editor');
  };

  const handleCloseEditor = () => {
    setViewMode('list');
    setEditingTemplateId(null);
  };

  if (viewMode === 'editor') {
    const initialTemplate =
      editingTemplateId ? getTemplate(editingTemplateId) : null;
    return (
      <div className="h-[calc(100vh-8rem)] min-h-[500px] flex flex-col">
        <LabelTemplateEditor
          templateId={editingTemplateId}
          initialTemplate={initialTemplate}
          onClose={handleCloseEditor}
          onSaved={refreshList}
        />
      </div>
    );
  }

  return (
    <div className="space-y-6">
      {/* Controls: Search, Location, New Label Template — 单行 + 圆角 + 细边框 + 统一高度 40px,黄色按钮无边框、靠右 */}
      <div className="flex flex-wrap items-center gap-3" style={{ height: 40 }}>
        <Input
          placeholder="Search"
          className="bg-white border border-black rounded-lg w-[180px] shrink-0 py-0 leading-normal"
          style={{ height: 40 }}
          value={search}
          onChange={(e) => setSearch(e.target.value)}
        />
        <Select value={locationFilter} onValueChange={setLocationFilter}>
          <SelectTrigger
            className="bg-white border border-black rounded-lg w-[180px] shrink-0 py-0"
            style={{ height: 40 }}
          >
            <SelectValue placeholder="Location" />
          </SelectTrigger>
          <SelectContent>
            <SelectItem value="all">All Locations</SelectItem>
            <SelectItem value="ALL">ALL</SelectItem>
            <SelectItem value="loc-a">Location A</SelectItem>
            <SelectItem value="loc-b">Location B</SelectItem>
          </SelectContent>
        </Select>
        <Button
          className="bg-blue-600 hover:bg-blue-700 text-white font-medium rounded-lg px-6 border-0 shrink-0 ml-auto py-0 min-h-0"
          style={{ height: 40 }}
          onClick={handleNewTemplate}
        >
          New Label Template <Plus className="ml-1 w-4 h-4" />
        </Button>
      </div>

      {/* Warning Banner */}
      <div className="text-red-600 font-bold italic text-sm md:text-base">
        ***One or more templates have incomplete labels attached to them.
        <br />
        Go to Labels view to see which labels are missing fields.
      </div>

      {/* Table */}
      <div className="rounded-md border bg-white shadow-sm">
        <Table>
          <TableHeader>
            <TableRow className="bg-gray-50 hover:bg-gray-50">
              <TableHead className="font-bold text-gray-900 w-[180px]">
                Label Template
              </TableHead>
              <TableHead className="font-bold text-gray-900 w-[120px]">
                Location
              </TableHead>
              <TableHead className="font-bold text-gray-900">Contents</TableHead>
              <TableHead className="font-bold text-gray-900 w-[150px]">
                Size
              </TableHead>
              <TableHead className="font-bold text-gray-900 w-[100px]">
                Actions
              </TableHead>
            </TableRow>
          </TableHeader>
          <TableBody>
            {filtered.length === 0 ? (
              <TableRow>
                <TableCell colSpan={5} className="text-center text-gray-500 py-8">
                  No templates yet. Click &quot;New Label Template&quot; to create one.
                </TableCell>
              </TableRow>
            ) : (
              filtered.map((t) => (
                <TableRow
                  key={t.id}
                  className="hover:bg-gray-50 cursor-pointer"
                  onClick={() => handleEditTemplate(t.id)}
                >
                  <TableCell className="font-medium">{t.name}</TableCell>
                  <TableCell>{t.appliedLocation}</TableCell>
                  <TableCell className="text-sm text-gray-600">
                    {t.elements.length} element(s)
                  </TableCell>
                  <TableCell>
                    {t.width}×{t.height} {t.unit}
                  </TableCell>
                  <TableCell onClick={(e) => e.stopPropagation()}>
                    <Button
                      variant="outline"
                      size="sm"
                      onClick={() => handleEditTemplate(t.id)}
                    >
                      <Pencil className="w-3 h-3 mr-1" />
                      Edit
                    </Button>
                  </TableCell>
                </TableRow>
              ))
            )}
          </TableBody>
        </Table>
      </div>
    </div>
  );
}