import React, { useEffect, useState } from "react"; import { json } from "@remix-run/node"; import { useLoaderData, Form, useActionData } from "@remix-run/react"; import { Page, Layout, IndexTable, Card, Thumbnail, TextContainer, Spinner, Button, TextField, Banner, InlineError, Toast, Frame, ProgressBar, } from "@shopify/polaris"; import { authenticate } from "../shopify.server"; import { TitleBar } from "@shopify/app-bridge-react"; export const loader = async ({ request }) => { const { admin } = await authenticate.admin(request); const { getTurn14AccessTokenFromMetafield } = await import("../utils/turn14Token.server"); const accessToken = await getTurn14AccessTokenFromMetafield(request); const res = await admin.graphql(`{ shop { metafield(namespace: "turn14", key: "selected_brands") { value } } }`); const data = await res.json(); const rawValue = data?.data?.shop?.metafield?.value; let brands = []; try { brands = JSON.parse(rawValue); } catch (err) { console.error("❌ Failed to parse metafield value:", err); } return json({ brands, accessToken }); }; export const action = async ({ request }) => { const { admin } = await authenticate.admin(request); const formData = await request.formData(); const brandId = formData.get("brandId"); const rawCount = formData.get("productCount"); const productCount = parseInt(rawCount, 10) || 10; const { getTurn14AccessTokenFromMetafield } = await import("../utils/turn14Token.server"); const accessToken = await getTurn14AccessTokenFromMetafield(request); const { session } = await authenticate.admin(request); const shop = session.shop; const resp = await fetch("https://backend.data4autos.com/manageProducts", { method: "POST", headers: { "Content-Type": "application/json", "shop-domain": shop, }, body: JSON.stringify({ shop, brandID: brandId, turn14accessToken: accessToken, productCount }), }); console.log("Response from manageProducts:", resp.status, resp.statusText); if (!resp.ok) { const err = await resp.text(); return json({ error: err }, { status: resp.status }); } const { processId, status } = await resp.json(); console.log("Process ID:", processId, "Status:", status); return json({ success: true, processId, status }); }; export default function ManageBrandProducts() { const actionData = useActionData(); const { brands, accessToken } = useLoaderData(); const [expandedBrand, setExpandedBrand] = useState(null); const [itemsMap, setItemsMap] = useState({}); const [loadingMap, setLoadingMap] = useState({}); const [productCount, setProductCount] = useState("10"); const [initialLoad, setInitialLoad] = useState(true); const [toastActive, setToastActive] = useState(false); const [polling, setPolling] = useState(false); const [status, setStatus] = useState(actionData?.status || ""); const [processId, setProcessId] = useState(actionData?.processId || null); const [progress, setProgress] = useState(0); const [totalProducts, setTotalProducts] = useState(0); const [processedProducts, setProcessedProducts] = useState(0); const [currentProduct, setCurrentProduct] = useState(null); const [results, setResults] = useState([]); const [detail, setDetail] = useState(""); useEffect(() => { if (actionData?.processId) { setProcessId(actionData.processId); setStatus(actionData.status || "processing"); setToastActive(true); } }, [actionData]); const checkStatus = async () => { setPolling(true); try { const response = await fetch(`https://backend.data4autos.com/manageProducts/status/${processId}`); const data = await response.json(); setStatus(data.status); setDetail(data.detail); setProgress(data.progress); setTotalProducts(data.stats.total); setProcessedProducts(data.stats.processed); setCurrentProduct(data.current); if (data.results) { setResults(data.results); } // Continue polling if still processing if (data.status !== 'done' && data.status !== 'error') { setTimeout(checkStatus, 2000); } else { setPolling(false); } } catch (error) { setPolling(false); setStatus('error'); setDetail('Failed to check status'); console.error('Error checking status:', error); } }; useEffect(() => { let interval; if (status?.includes("processing") && processId) { interval = setInterval(checkStatus, 5000); } return () => clearInterval(interval); }, [status, processId]); const toggleAllBrands = async () => { for (const brand of brands) { await toggleBrandItems(brand.id); } }; useEffect(() => { if (initialLoad && brands.length > 0) { toggleAllBrands(); setInitialLoad(false); } }, [brands, initialLoad]); const toggleBrandItems = async (brandId) => { const isExpanded = expandedBrand === brandId; if (isExpanded) { setExpandedBrand(null); } else { setExpandedBrand(brandId); if (!itemsMap[brandId]) { setLoadingMap((prev) => ({ ...prev, [brandId]: true })); try { const res = await fetch(`https://turn14.data4autos.com/v1/items/brandallitems/${brandId}`, { headers: { Authorization: `Bearer ${accessToken}`, "Content-Type": "application/json", }, }); const data = await res.json(); const validItems = Array.isArray(data) ? data.filter(item => item && item.id && item.attributes) : []; setItemsMap((prev) => ({ ...prev, [brandId]: validItems })); } catch (err) { console.error("Error fetching items:", err); setItemsMap((prev) => ({ ...prev, [brandId]: [] })); } setLoadingMap((prev) => ({ ...prev, [brandId]: false })); } } }; const toastMarkup = toastActive ? ( setToastActive(false)} /> ) : null; return ( {brands.length === 0 ? (

No brands selected yet.

) : ( {brands.map((brand, index) => ( {brand.id} {itemsMap[brand.id]?.length || 0} ))} )} {brands.map( (brand) => expandedBrand === brand.id && ( {processId && (

Process ID: {processId}

Status: {status || "—"}

{progress > 0 && (

{processedProducts} of {totalProducts} products processed {currentProduct && ` - Current: ${currentProduct.name} (${currentProduct.number}/${currentProduct.total})`}

)}
{status === 'done' && results.length > 0 && (

Results: {results.length} products processed successfully

)} {status === 'error' && (
Error: {detail}
)}
)}
{loadingMap[brand.id] ? ( ) : (
setProductCount(value)} autoComplete="off" /> {( itemsMap[brand.id] && itemsMap[brand.id].length > 0 ? itemsMap[brand.id].filter(item => item && item.id) : [] ).map((item) => (

Part Number: {item?.attributes?.part_number || 'N/A'}

Category: {item?.attributes?.category || 'N/A'} > {item?.attributes?.subcategory || 'N/A'}

Price: ${item?.attributes?.price || '0.00'}

Description: {item?.attributes?.part_description || 'No description available'}

))}
)}
) )}
{toastMarkup}
); }