import { json } from "@remix-run/node"; import { useLoaderData, Form, useActionData } from "@remix-run/react"; import { Page, Layout, Card, TextField, Checkbox, Button, Thumbnail, Spinner, Toast, Frame, Text, } from "@shopify/polaris"; import { useEffect, useState } from "react"; import { TitleBar } from "@shopify/app-bridge-react"; import { getTurn14AccessTokenFromMetafield } from "../utils/turn14Token.server"; import { authenticate } from "../shopify.server"; async function checkShopExists(shop) { try { const resp = await fetch( `https://backend.data4autos.com/checkisshopdataexists/${shop}` ); const data = await resp.json(); return data.status === 1; // ✅ true if shop exists, false otherwise } catch (err) { console.error("Error checking shop:", err); return false; // default to false if error } } export const loader = async ({ request }) => { // const accessToken = await getTurn14AccessTokenFromMetafield(request); const { admin } = await authenticate.admin(request); const { session } = await authenticate.admin(request); const shop = session.shop; var accessToken = "" try { accessToken = await getTurn14AccessTokenFromMetafield(request); } catch (err) { return json({ brands: [], collections: [], selectedBrandsFromShopify: [], shop ,err}); console.error("Error getting Turn14 access token:", err); // Proceeding with empty accessToken } // fetch brands const brandRes = await fetch("https://turn14.data4autos.com/v1/brands", { headers: { Authorization: `Bearer ${accessToken}`, "Content-Type": "application/json", }, }); const brandJson = await brandRes.json(); if (!brandRes.ok) { return json({ error: brandJson.error || "Failed to fetch brands" }, { status: 500 }); } // fetch Shopify collections const gqlRaw = await admin.graphql(` { collections(first: 100) { edges { node { id title } } } } `); const gql = await gqlRaw.json(); const collections = gql?.data?.collections?.edges.map(e => e.node) || []; 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: brandJson.data, collections, selectedBrandsFromShopify: brands || [], shop }); }; export const action = async ({ request }) => { const formData = await request.formData(); const selectedBrands = JSON.parse(formData.get("selectedBrands") || "[]"); const selectedOldBrands = JSON.parse(formData.get("selectedOldBrands") || "[]"); const { session } = await authenticate.admin(request); const shop = session.shop; // "veloxautomotive.myshopify.com" selectedBrands.forEach(brand => { delete brand.pricegroups; }); selectedOldBrands.forEach(brand => { delete brand.pricegroups; }); const resp = await fetch("https://backend.data4autos.com/managebrands", { method: "POST", headers: { "Content-Type": "application/json", "shop-domain": shop, }, body: JSON.stringify({ shop, selectedBrands, selectedOldBrands }), }); if (!resp.ok) { const err = await resp.text(); return json({ error: err }, { status: resp.status }); } const { processId, status } = await resp.json(); return json({ processId, status }); }; export default function BrandsPage() { const { brands, collections, selectedBrandsFromShopify, shop ,err} = useLoaderData(); console.log(err) // console.log(`selectedBrandsFromShopify: ${JSON.stringify(selectedBrandsFromShopify)}`); const actionData = useActionData() || {}; const [selectedIdsold, setSelectedIdsold] = useState([]) // const [selectedIds, setSelectedIds] = useState(() => { // const titles = new Set(collections.map(c => c.title.toLowerCase())); // return brands // .filter(b => titles.has(b.name.toLowerCase())) // .map(b => b.id); // }); const [selectedIds, setSelectedIds] = useState(() => { return selectedBrandsFromShopify.map(b => b.id); }); // console.log("Selected IDS : ", selectedIds) const [search, setSearch] = useState(""); const [filteredBrands, setFilteredBrands] = useState(brands); const [toastActive, setToastActive] = useState(false); const [polling, setPolling] = useState(false); const [status, setStatus] = useState(actionData.status || ""); const [Turn14Enabled, setTurn14Enabled] = useState(null); // null | true | false useEffect(() => { if (!shop) { console.log("⚠️ shop is undefined or empty"); return; } (async () => { const result = await checkShopExists(shop); console.log("✅ API status result:", result, "| shop:", shop); setTurn14Enabled(result); })(); }, [shop]); useEffect(() => { const selids = selectedIds // console.log("Selected IDS : ", selids) setSelectedIdsold(selids) }, [toastActive]); useEffect(() => { const term = search.toLowerCase(); setFilteredBrands(brands.filter(b => b.name.toLowerCase().includes(term))); }, [search, brands]); useEffect(() => { if (actionData.status) { setStatus(actionData.status); setToastActive(true); } }, [actionData.status]); const checkStatus = async () => { if (!actionData.processId) return; setPolling(true); const resp = await fetch( `https://backend.data4autos.com/managebrands/status/${actionData.processId}`, { headers: { "shop-domain": window.shopify.shop || "" } } ); const jsonBody = await resp.json(); setStatus( jsonBody.status + (jsonBody.detail ? ` (${jsonBody.detail})` : "") ); setPolling(false); }; const toggleSelect = id => setSelectedIds(prev => prev.includes(id) ? prev.filter(i => i !== id) : [...prev, id] ); const allFilteredSelected = filteredBrands.length > 0 && filteredBrands.every(b => selectedIds.includes(b.id)); const toggleSelectAll = () => { const ids = filteredBrands.map(b => b.id); if (allFilteredSelected) { setSelectedIds(prev => prev.filter(id => !ids.includes(id))); } else { setSelectedIds(prev => Array.from(new Set([...prev, ...ids]))); } }; var isSubmitting; // console.log("actionData", actionData); if (actionData.status) { isSubmitting = !actionData.status && !actionData.error && !actionData.processId; } else { isSubmitting = false; } // console.log("isSubmitting", isSubmitting); const toastMarkup = toastActive ? ( setToastActive(false)} /> ) : null; const selectedBrands = brands.filter(b => selectedIds.includes(b.id)); const selectedOldBrands = brands.filter(b => selectedIdsold.includes(b.id)); const shopDomain = (shop || "").split(".")[0]; const items = [ { icon: "⚙️", text: "Manage API settings", link: `https://admin.shopify.com/store/${shopDomain}/apps/d4a-turn14/app/settings` }, { icon: "🏷️", text: "Browse and import available brands", link: `https://admin.shopify.com/store/${shopDomain}/apps/d4a-turn14/app/brands` }, { icon: "📦", text: "Sync brand collections to Shopify", link: `https://admin.shopify.com/store/${shopDomain}/apps/d4a-turn14/app/managebrand` }, { icon: "🔐", text: "Handle secure Turn14 login credentials", link: `https://admin.shopify.com/store/${shopDomain}/apps/d4a-turn14/app/help` }, ]; // If Turn14 is explicitly NOT connected, show a lightweight call-to-action screen if (Turn14Enabled === false) { return (
Turn14 isn’t connected yet
This shop hasn’t been configured with Turn14 / Data4Autos. To get started, open Settings and complete the connection.
{/* Primary actions */}
Once connected, you’ll be able to browse brands and sync collections.
{/* Secondary links */}
); } // console.log("Selected Brands:", selectedBrands) return (
Data4Autos Turn14 Brands List
{/*

Turn 14 Status:{" "} {Turn14Enabled === true ? "✅ Turn14 x Shopify Connected!" : Turn14Enabled === false ? "❌ Turn14 x Shopify Connection Doesn't Exists" : "Checking..."}

*/}
{/* Left side - Search + Select All */}
{(actionData?.processId || false) && (

Process ID: {actionData.processId}

Status: {status || "—"}

)}
{/* Right side - Save Button */}
{/*
{filteredBrands.map((brand) => (
{/* Checkbox in top-right corner */}
toggleSelect(brand.id)} />
{/* Brand image */}
{/* Brand name */}
{brand.name}
))}
{toastMarkup}
); }