Add Resolve Items flow for unmatched Etsy sync titles

Reuses the missing-products modal on the Settings page: each unmatched
listing title can be aliased to an existing product or created with a
printing cost, then orders re-sync automatically to fill in costs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
dlawler489 2026-06-13 11:37:12 +10:00
parent e09f082420
commit acce14c000

View file

@ -2,7 +2,8 @@ import { useState, useEffect } from 'react';
import { useDispatch } from 'react-redux';
import { DataManager } from '../utils/dataManager';
import { setOrders } from '../store/slices/orderSlice';
import { Trash2, Download, RefreshCw, AlertTriangle, Database, Store, Link2, Unlink } from 'lucide-react';
import { MissingProductsModal } from '../components/MissingProductsModal';
import { Trash2, Download, RefreshCw, AlertTriangle, Database, Store, Link2, Unlink, Wrench } from 'lucide-react';
import toast from 'react-hot-toast';
import api from '../utils/api';
@ -40,6 +41,7 @@ const Settings = () => {
const [isConnecting, setIsConnecting] = useState(false);
const [isSyncing, setIsSyncing] = useState(false);
const [unmatchedItems, setUnmatchedItems] = useState<string[]>([]);
const [showResolveModal, setShowResolveModal] = useState(false);
useEffect(() => {
updateStorageSummary();
@ -230,17 +232,27 @@ const Settings = () => {
{unmatchedItems.length > 0 && (
<div className="bg-yellow-50 border border-yellow-200 rounded-lg p-4">
<p className="text-yellow-800 font-medium text-sm mb-2">
{unmatchedItems.length} item title(s) couldn't be matched to your product catalog
(their orders were synced without cost data):
</p>
<div className="flex items-start justify-between gap-4 mb-2">
<p className="text-yellow-800 font-medium text-sm">
{unmatchedItems.length} item title(s) couldn't be matched to your product catalog
(their orders were synced without cost data):
</p>
<button
onClick={() => setShowResolveModal(true)}
className="flex items-center gap-2 px-3 py-2 bg-yellow-600 text-white rounded-lg hover:bg-yellow-700 text-sm whitespace-nowrap"
>
<Wrench className="w-4 h-4" />
Resolve Items
</button>
</div>
<ul className="text-yellow-700 text-sm list-disc list-inside space-y-1">
{unmatchedItems.map((title, idx) => (
<li key={idx}>{title}</li>
))}
</ul>
<p className="text-yellow-700 text-xs mt-2">
Add these as products (or aliases on existing products) and sync again to fill in costs.
Click Resolve Items to match each title to an existing product (saved as an alias)
or create it with a printing cost then orders re-sync with costs automatically.
</p>
</div>
)}
@ -456,6 +468,20 @@ const Settings = () => {
<h2 className="text-xl font-semibold text-gray-900 mb-4">Application Settings</h2>
<p className="text-gray-600">Additional application settings will be available here in future updates.</p>
</div>
{/* Resolve unmatched Etsy items: map to existing products (alias) or create new */}
{showResolveModal && (
<MissingProductsModal
missingProducts={unmatchedItems.map(title => ({ title, quantity: 1 }))}
onClose={() => setShowResolveModal(false)}
onComplete={() => {
setShowResolveModal(false);
setUnmatchedItems([]);
toast.success('Products resolved — re-syncing orders with costs…');
handleEtsySync();
}}
/>
)}
</div>
);
};