feat: reorganize tabs, add Article Details, and enhance filters/search

This commit is contained in:
Christian Vidal Wolf
2026-04-08 16:10:14 +02:00
parent 935cd5b510
commit 24042a6aed
7 changed files with 397 additions and 61 deletions
+13 -3
View File
@@ -1,6 +1,6 @@
import React, { useState } from 'react';
import { ExcelRow, COLUMNS } from '../types';
import { X, Sparkles, Save, Loader2, Languages, Package } from 'lucide-react';
import { X, Sparkles, Save, Loader2, Languages, Package, CheckCircle2 } from 'lucide-react';
import { generateGemini } from '../services/gemini';
import { cn } from '../lib/utils';
import { ConfirmModal } from './ConfirmModal';
@@ -35,6 +35,7 @@ export function EditPanel({ row, rowIndex, onSave, onClose, onCaptureState }: Ed
const [error, setError] = useState<string | null>(null);
const [isConfirmOpen, setIsConfirmOpen] = useState(false);
const [pendingGeminiField, setPendingGeminiField] = useState<keyof typeof formData | null>(null);
const [generatedFields, setGeneratedFields] = useState<Set<string>>(new Set());
const isModified = (field: keyof typeof formData) => {
const colMap: Record<string, number> = {
@@ -107,7 +108,8 @@ export function EditPanel({ row, rowIndex, onSave, onClose, onCaptureState }: Ed
if (formData.shortEn) {
prompt = `Translate exactly this short English product description into professional German for the toy market:\n\n${formData.shortEn}`;
} else if (formData.longDe) {
prompt = `Create a short version (2-4 sentences max) of the following German product description:\n\n${formData.longDe}`;
const targetChars = Math.round(formData.longDe.length * 0.3);
prompt = `Create a concise summary of the following German product description. The summary must be approximately ${targetChars} characters long (about 30% of the original). Preserve the most important commercial highlights and features in natural, professional German for B2B toy buyers. Do not use bullet points — write flowing prose.\n\nOriginal description:\n${formData.longDe}`;
} else {
prompt = `Based on the following product details, generate a short commercial description in German (2-4 sentences max).\n\n${baseContext}`;
}
@@ -115,7 +117,8 @@ export function EditPanel({ row, rowIndex, onSave, onClose, onCaptureState }: Ed
if (formData.shortDe) {
prompt = `Translate exactly this short German product description into professional English for the toy market:\n\n${formData.shortDe}`;
} else if (formData.longEn) {
prompt = `Create a short version (2-4 sentences max) of the following English product description:\n\n${formData.longEn}`;
const targetChars = Math.round(formData.longEn.length * 0.3);
prompt = `Create a concise summary of the following English product description. The summary must be approximately ${targetChars} characters long (about 30% of the original). Preserve the most important commercial highlights and features in natural, professional English for B2B toy buyers. Do not use bullet points — write flowing prose.\n\nOriginal description:\n${formData.longEn}`;
} else {
prompt = `Based on the following product details, generate a short commercial description in English (2-4 sentences max).\n\n${baseContext}`;
}
@@ -123,6 +126,7 @@ export function EditPanel({ row, rowIndex, onSave, onClose, onCaptureState }: Ed
const generatedText = await generateGemini(prompt, systemPrompt);
setFormData(prev => ({ ...prev, [field]: generatedText.trim() }));
setGeneratedFields(prev => new Set(prev).add(field));
} catch (err: any) {
setError(err.message || 'An error occurred during generation.');
} finally {
@@ -193,6 +197,12 @@ export function EditPanel({ row, rowIndex, onSave, onClose, onCaptureState }: Ed
{((field === 'longDe' && formData.longEn) || (field === 'longEn' && formData.longDe) || (field === 'shortDe' && formData.shortEn) || (field === 'shortEn' && formData.shortDe)) ? 'Translate with Gemini' : 'Generate with Gemini'}
</button>
</div>
{generatedFields.has(field) && (
<div className="flex items-center gap-1.5 text-[10px] text-emerald-400 bg-emerald-400/10 px-2 py-0.5 rounded w-fit animate-in fade-in slide-in-from-top-1 duration-300">
<CheckCircle2 className="w-3 h-3" />
AI Generated - You can still edit manually
</div>
)}
</div>
<textarea
value={formData[field]}