diff --git a/app/routes/app._index.jsx b/app/routes/app._index.jsx index c14752a..b8f875c 100644 --- a/app/routes/app._index.jsx +++ b/app/routes/app._index.jsx @@ -90,7 +90,7 @@ export const action = async ({ request }) => { } ], trialDays: 7, # ✅ trialDays is a top-level argument! - test: false + test: true ) { confirmationUrl appSubscription { diff --git a/app/routes/app.brands.jsx b/app/routes/app.brands.jsx index 54c7138..203105e 100644 --- a/app/routes/app.brands.jsx +++ b/app/routes/app.brands.jsx @@ -38,36 +38,36 @@ async function checkShopExists(shop) { } export const loader = async ({ request }) => { - const accessToken = await getTurn14AccessTokenFromMetafield(request); + // const accessToken = await getTurn14AccessTokenFromMetafield(request); const { admin } = await authenticate.admin(request); - // 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 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) || []; + // // 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) || []; @@ -75,23 +75,23 @@ export const loader = async ({ 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; + // 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); + // let brands = []; + // try { + // brands = JSON.parse(rawValue); - } catch (err) { - console.error("❌ Failed to parse metafield value:", err); - } + // } catch (err) { + // console.error("❌ Failed to parse metafield value:", err); + // } @@ -99,7 +99,7 @@ export const loader = async ({ request }) => { const { session } = await authenticate.admin(request); const shop = session.shop; - return json({ brands: brandJson.data, collections, selectedBrandsFromShopify: brands || [], shop }); + return json({ brands: [], collections : [], selectedBrandsFromShopify: [], shop }); }; export const action = async ({ request }) => { @@ -340,7 +340,7 @@ if (Turn14Enabled === false) {
-
+ {/*

Turn 14 Status:{" "} {Turn14Enabled === true @@ -349,7 +349,7 @@ if (Turn14Enabled === false) { ? "❌ Turn14 x Shopify Connection Doesn't Exists" : "Checking..."}

-
+
*/} diff --git a/app/routes/app.brands_2808.jsx b/app/routes/app.brands_2808.jsx new file mode 100644 index 0000000..e95979e --- /dev/null +++ b/app/routes/app.brands_2808.jsx @@ -0,0 +1,457 @@ +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); + + // 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); + } + + + + + const { session } = await authenticate.admin(request); + const shop = session.shop; + + 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 } = useLoaderData(); + // 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} +
+ + ); +} diff --git a/app/routes/app.managebrand.jsx b/app/routes/app.managebrand.jsx index 612df03..4622fd0 100644 --- a/app/routes/app.managebrand.jsx +++ b/app/routes/app.managebrand.jsx @@ -532,14 +532,14 @@ export default function ManageBrandProducts() { -

+ {/*

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

+

*/} {brands.length === 0 ? (