"use client"; import React, { useState, useEffect } from "react"; import { IconPlus, IconChevronDown, IconX, IconRefresh } from "@tabler/icons-react"; import { motion, AnimatePresence } from "motion/react"; import { cn } from "../lib/utils"; import { useHashRoute } from "../lib/routing"; import { setActiveAccountId, getAccountDisplayName, } from "../services/accountService"; import { fetchManagedAccounts, createManagedAccount, updateManagedAccount } from "../services/accountsService"; import { getAuthUser } from "../lib/appwrite"; import { parseEbayAccount } from "../services/ebayParserService"; import { DataTable } from "../components/dashboard/ui/DataTable"; export const AccountsPage = () => { const { navigate } = useHashRoute(); const [accounts, setAccounts] = useState([]); const [loading, setLoading] = useState(true); const [showAdvanced, setShowAdvanced] = useState(false); const [showAddForm, setShowAddForm] = useState(false); const [formError, setFormError] = useState(""); const [formSuccess, setFormSuccess] = useState(""); const [formLoading, setFormLoading] = useState(false); // Parse-State für Zwei-Phasen-Flow const [parsedData, setParsedData] = useState(null); const [parsing, setParsing] = useState(false); const [parsingError, setParsingError] = useState(""); // Refresh-State pro Account const [refreshingAccountId, setRefreshingAccountId] = useState(null); const [refreshToast, setRefreshToast] = useState({ show: false, message: "", type: "success" }); // Form-Felder (nur noch URL) const [formData, setFormData] = useState({ account_url: "", }); // Accounts laden useEffect(() => { loadAccounts(); }, []); async function loadAccounts() { setLoading(true); try { const authUser = await getAuthUser(); if (!authUser) { setAccounts([]); return; } const loadedAccounts = await fetchManagedAccounts(authUser.$id); setAccounts(loadedAccounts); } catch (e) { console.error("Fehler beim Laden der Accounts:", e); setAccounts([]); } finally { setLoading(false); } } const handleSelectAccount = (account) => { const accountId = account.$id || account.id; setActiveAccountId(accountId); // Navigiere zurück zum Dashboard navigate("/"); }; const handleRefreshAccount = async (account) => { const accountId = account.$id || account.id; const accountUrl = account.account_url; if (!accountUrl) { setRefreshToast({ show: true, message: "Account hat keine URL zum Aktualisieren.", type: "error" }); setTimeout(() => setRefreshToast({ show: false, message: "", type: "success" }), 3000); return; } setRefreshingAccountId(accountId); try { // URL erneut parsen const parsedData = await parseEbayAccount(accountUrl); // Account in DB aktualisieren // WICHTIG: Nur Felder setzen, die nicht leer sind und sich geändert haben // Leere account_platform_account_id würde Unique-Index-Konflikte verursachen const updatePayload = {}; // Nur market setzen, wenn nicht leer if (parsedData.market && parsedData.market.trim()) { updatePayload.account_platform_market = parsedData.market; } // Nur sellerId setzen, wenn nicht leer (verhindert Unique-Index-Konflikte mit leerem String) if (parsedData.sellerId && parsedData.sellerId.trim()) { updatePayload.account_platform_account_id = parsedData.sellerId; } // Shop-Name und account_sells können auch leer sein (optional) updatePayload.account_shop_name = parsedData.shopName || null; updatePayload.account_sells = parsedData.stats?.itemsSold ?? null; // account_status wird weggelassen (wie beim Erstellen) // Grund: Schema-Konflikt - Enum-Feld akzeptiert weder String noch Array im Update // TODO: Schema in Appwrite prüfen und korrigieren, dann account_status wieder hinzufügen // Setze account_updated_at auf aktuelle Zeit updatePayload.account_updated_at = new Date().toISOString(); await updateManagedAccount(accountId, updatePayload); // Accounts-Liste neu laden (in-place Update) await loadAccounts(); // Success-Toast setRefreshToast({ show: true, message: "Account aktualisiert", type: "success" }); setTimeout(() => setRefreshToast({ show: false, message: "", type: "success" }), 3000); } catch (e) { console.error("Fehler beim Aktualisieren des Accounts:", e); let errorMessage = "Update fehlgeschlagen"; if (e.message?.includes("Parsing") || e.message?.includes("URL")) { errorMessage = "Parsing fehlgeschlagen"; } setRefreshToast({ show: true, message: errorMessage, type: "error" }); setTimeout(() => setRefreshToast({ show: false, message: "", type: "success" }), 3000); } finally { setRefreshingAccountId(null); } }; const handleAddAccount = () => { setShowAddForm(true); setFormError(""); setFormSuccess(""); }; const handleCloseForm = () => { setShowAddForm(false); setFormError(""); setFormSuccess(""); setParsedData(null); setParsingError(""); // Form zurücksetzen setFormData({ account_url: "", }); }; const handleFormChange = (field, value) => { setFormData((prev) => ({ ...prev, [field]: value })); // Clear errors beim Eingeben if (formError) setFormError(""); if (parsingError) setParsingError(""); }; const handleParseUrl = async () => { const url = formData.account_url?.trim(); if (!url) { setParsingError("Bitte gib eine eBay-URL ein."); return; } setParsing(true); setParsingError(""); setFormError(""); try { const result = await parseEbayAccount(url); setParsedData(result); setParsingError(""); } catch (e) { setParsingError(e.message || "Bitte gib eine gültige eBay-URL ein."); setParsedData(null); } finally { setParsing(false); } }; const handleFormSubmit = async (e) => { e.preventDefault(); // Wenn noch nicht geparst, zuerst parsen if (!parsedData) { await handleParseUrl(); return; } // Save-Phase: Account in DB speichern setFormError(""); setFormSuccess(""); setFormLoading(true); try { const authUser = await getAuthUser(); if (!authUser) { setFormError("Nicht eingeloggt. Bitte neu anmelden."); return; } // Payload aus parsedData zusammenstellen const accountSellsValue = parsedData.stats?.itemsSold ?? null; const newAccount = await createManagedAccount(authUser.$id, { account_url: formData.account_url.trim(), account_platform_account_id: parsedData.sellerId, account_platform_market: parsedData.market, account_shop_name: parsedData.shopName, account_sells: accountSellsValue, // account_status wird nicht mehr gesendet (optional, Schema-Problem in Appwrite) }); // Erfolg: Liste refreshen await loadAccounts(); // Wenn dies das erste Account ist, setze es als aktiv if (accounts.length === 0) { setActiveAccountId(newAccount.$id); } setFormSuccess("Account erfolgreich erstellt!"); setTimeout(() => { handleCloseForm(); }, 1500); } catch (e) { // Fehlerbehandlung const errorMessage = e.message || "Fehler beim Erstellen des Accounts. Bitte versuche es erneut."; setFormError(errorMessage); } finally { setFormLoading(false); } }; // Spalten für die Tabelle const columns = [ "Account Name", "Platform", "Platform Account ID", "Market", "Account URL", "Sales", "Last Scan", ...(showAdvanced ? ["Owner User ID"] : []), "Action", ]; const renderCell = (col, row) => { if (col === "Action") { const accountId = row.$id || row.id; const isRefreshing = refreshingAccountId === accountId; return (
); } if (col === "Account Name") { return getAccountDisplayName(row) || "-"; } if (col === "Platform") { return row.account_platform || "-"; } if (col === "Platform Account ID") { return row.account_platform_account_id || "-"; } if (col === "Market") { return row.account_platform_market || "-"; } if (col === "Account URL") { const url = row.account_url; if (!url) return "-"; return ( {url.length > 40 ? `${url.substring(0, 40)}...` : url} ); } if (col === "Sales") { const sales = row.account_sells; if (sales === null || sales === undefined) return "-"; // Format number with thousand separators return new Intl.NumberFormat("de-DE").format(sales); } if (col === "Last Scan") { const lastScan = row.account_updated_at; if (!lastScan) return "-"; try { const date = new Date(lastScan); return date.toLocaleString("de-DE", { day: "2-digit", month: "2-digit", year: "numeric", hour: "2-digit", minute: "2-digit", }); } catch (e) { return "-"; } } if (col === "Owner User ID") { return row.account_owner_user_id || "-"; } return "-"; }; return (
{/* Header */}

Accounts

Verwalte deine Plattform-Accounts

{/* Hilfe-Panel */}

Account hinzufügen

eBay Account URL (Pflichtfeld) : Gib einfach die eBay-URL zum Verkäuferprofil oder Shop ein. Alle weiteren Informationen (Market, Seller ID, Shop Name) werden automatisch erkannt.
Market (Auto) : Wird automatisch aus der URL extrahiert (z.B. DE, US, UK). Du musst nichts eingeben.
eBay Seller ID (Auto) : Wird automatisch erkannt. Dies ist die eindeutige Verkäufer-Kennung von eBay und verhindert Duplikate.
Shop Name (Auto) : Öffentlich sichtbarer Name des Shops. Wird automatisch aus der URL/Seite extrahiert.
Sales (Auto) : Anzahl der verkauften Artikel wird automatisch aus dem eBay-Profil gelesen.
So funktioniert's:{" "} Gib einfach die eBay-URL ein und klicke auf "Account hinzufügen". Das System liest alle notwendigen Informationen automatisch aus. Du musst keine technischen Felder manuell ausfüllen.
{/* Advanced Toggle */}
{/* Toast Notification */} {refreshToast.show && ( {refreshToast.message} )} {/* Tabelle */}
{loading ? (
Loading accounts...
) : ( )}
{/* Add Account Form Modal */} {showAddForm && ( e.stopPropagation()} className="relative w-full max-w-2xl rounded-2xl border border-[var(--line)] bg-white p-6 shadow-xl dark:bg-neutral-800" > {/* Close Button */} {/* Form Header */}

Add Account

{/* Error/Success Messages */} {parsingError && (
{parsingError}
)} {formError && (
{formError}
)} {formSuccess && (
{formSuccess}
)} {/* Form */}
{/* Phase 1: URL Input */}
handleFormChange("account_url", e.target.value)} placeholder="https://www.ebay.de/usr/..." required disabled={parsing || formLoading} className="w-full rounded-lg border border-[var(--line)] bg-white px-3 py-2 text-sm text-[var(--text)] outline-none transition-colors focus:border-blue-500 disabled:opacity-50 disabled:cursor-not-allowed dark:bg-neutral-900" />

Füge den Link zum eBay-Verkäuferprofil oder Shop ein. Wir lesen die Account-Daten automatisch aus.

{/* Phase 2: Preview (wenn parsedData vorhanden) */} {parsedData && (

Account-Informationen (automatisch erkannt)

Automatisch erkannter Marktplatz (z.B. DE oder US).

Eindeutige Verkäufer-ID von eBay. Wird für Abgleich und Duplikat-Erkennung verwendet.

Öffentlich sichtbarer Name des Shops auf eBay.

Automatisch aus dem eBay-Profil gelesen.

Gesamtzahl der verkauften Artikel.

)} {/* Form Actions */}
{parsedData ? ( ) : ( )}
)}
); };