+
+ {(actionData?.processId || false) && (
+
+
+ Process ID: {actionData.processId}
+
+
+ Status: {status || "β"}
+
+
+
+ )}
- {/* Left side - Search + Select All */}
-
- {(actionData?.processId || false) && (
-
-
- Process ID: {actionData.processId}
-
-
- Status: {status || "β"}
-
-
+
+
- )}
-
-
+
+
+
+
- {/* Right side - Save Button */}
-
@@ -432,22 +680,20 @@ export default function BrandsPage() {
display: "grid",
gridTemplateColumns: "repeat(auto-fill, minmax(220px, 1fr))",
gap: 16,
- marginTop: "120px"
}}
>
{filteredBrands.map((brand) => (
- {/* Checkbox in top-right corner */}
toggleSelect(brand.id)}
+ disabled={!isSubscribed}
/>
- {/* Brand image */}
- {/* Brand name */}
-
@@ -473,4 +726,4 @@ export default function BrandsPage() {
);
-}
+}
\ No newline at end of file
diff --git a/app/routes/app.managebrand copy 3.jsx b/app/routes/app.managebrand copy 3.jsx
new file mode 100644
index 0000000..8d25160
--- /dev/null
+++ b/app/routes/app.managebrand copy 3.jsx
@@ -0,0 +1,1000 @@
+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,
+ Select,
+ ProgressBar,
+ Checkbox,
+ Text,
+ ChoiceList,
+ Popover,
+ OptionList,
+} from "@shopify/polaris";
+import { authenticate } from "../shopify.server";
+import { TitleBar } from "@shopify/app-bridge-react";
+
+const styles = {
+ gridContainer: {
+ display: 'grid',
+ gridTemplateColumns: '1fr 1fr', // Two equal columns
+ gap: '10px', // Space between items
+ },
+ gridItem: {
+ display: 'flex',
+ flexDirection: 'column',
+ },
+ gridFullWidthItem: {
+ gridColumn: 'span 2', // This takes up the full width (for Description)
+ display: 'flex',
+ flexDirection: 'column',
+ },
+};
+
+
+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 { getTurn14AccessTokenFromMetafield } = await import("../utils/turn14Token.server");
+
+
+
+ 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 });
+ console.error("Error getting Turn14 access token:", err);
+ // Proceeding with empty accessToken
+ }
+
+
+
+
+
+
+ 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, shop });
+};
+
+
+const makes_list_raw = [
+ 'Alfa Romeo',
+ 'Ferrari',
+ 'Dodge',
+ 'Subaru',
+ 'Toyota',
+ 'Volkswagen',
+ 'Volvo',
+ 'Audi',
+ 'BMW',
+ 'Buick',
+ 'Cadillac',
+ 'Chevrolet',
+ 'Chrysler',
+ 'CX Automotive',
+ 'Nissan',
+ 'Ford',
+ 'Hyundai',
+ 'Infiniti',
+ 'Lexus',
+ 'Mercury',
+ 'Mazda',
+ 'Oldsmobile',
+ 'Plymouth',
+ 'Pontiac',
+ 'Rolls-Royce',
+ 'Eagle',
+ 'Lincoln',
+ 'Mercedes-Benz',
+ 'GMC',
+ 'Saab',
+ 'Honda',
+ 'Saturn',
+ 'Mitsubishi',
+ 'Isuzu',
+ 'Jeep',
+ 'AM General',
+ 'Geo',
+ 'Suzuki',
+ 'E. P. Dutton, Inc.',
+ 'Land Rover',
+ 'PAS, Inc',
+ 'Acura',
+ 'Jaguar',
+ 'Lotus',
+ 'Grumman Olson',
+ 'Porsche',
+ 'American Motors Corporation',
+ 'Kia',
+ 'Lamborghini',
+ 'Panoz Auto-Development',
+ 'Maserati',
+ 'Saleen',
+ 'Aston Martin',
+ 'Dabryan Coach Builders Inc',
+ 'Federal Coach',
+ 'Vector',
+ 'Bentley',
+ 'Daewoo',
+ 'Qvale',
+ 'Roush Performance',
+ 'Autokraft Limited',
+ 'Bertone',
+ 'Panther Car Company Limited',
+ 'Texas Coach Company',
+ 'TVR Engineering Ltd',
+ 'Morgan',
+ 'MINI',
+ 'Yugo',
+ 'BMW Alpina',
+ 'Renault',
+ 'Bitter Gmbh and Co. Kg',
+ 'Scion',
+ 'Maybach',
+ 'Lambda Control Systems',
+ 'Merkur',
+ 'Peugeot',
+ 'Spyker',
+ 'London Coach Co Inc',
+ 'Hummer',
+ 'Bugatti',
+ 'Pininfarina',
+ 'Shelby',
+ 'Saleen Performance',
+ 'smart',
+ 'Tecstar, LP',
+ 'Kenyon Corporation Of America',
+ 'Avanti Motor Corporation',
+ 'Bill Dovell Motor Car Company',
+ 'Import Foreign Auto Sales Inc',
+ 'S and S Coach Company E.p. Dutton',
+ 'Superior Coaches Div E.p. Dutton',
+ 'Vixen Motor Company',
+ 'Volga Associated Automobile',
+ 'Wallace Environmental',
+ 'Import Trade Services',
+ 'J.K. Motors',
+ 'Panos',
+ 'Quantum Technologies',
+ 'London Taxi',
+ 'Red Shift Ltd.',
+ 'Ruf Automobile Gmbh',
+ 'Excalibur Autos',
+ 'Mahindra',
+ 'VPG',
+ 'Fiat',
+ 'Sterling',
+ 'Azure Dynamics',
+ 'McLaren Automotive',
+ 'Ram',
+ 'CODA Automotive',
+ 'Fisker',
+ 'Tesla',
+ 'Mcevoy Motors',
+ 'BYD',
+ 'ASC Incorporated',
+ 'SRT',
+ 'CCC Engineering',
+ 'Mobility Ventures LLC',
+ 'Pagani',
+ 'Genesis',
+ 'Karma',
+ 'Koenigsegg',
+ 'Aurora Cars Ltd',
+ 'RUF Automobile',
+ 'Dacia',
+ 'STI',
+ 'Daihatsu',
+ 'Polestar',
+ 'Kandi',
+ 'Rivian',
+ 'Lucid',
+ 'JBA Motorcars, Inc.',
+ 'Lordstown',
+ 'Vinfast',
+ 'INEOS Automotive',
+ 'Bugatti Rimac',
+ 'Grumman Allied Industries',
+ 'Environmental Rsch and Devp Corp',
+ 'Evans Automobiles',
+ 'Laforza Automobile Inc',
+ 'General Motors',
+ 'Consulier Industries Inc',
+ 'Goldacre',
+ 'Isis Imports Ltd',
+ 'PAS Inc - GMC'
+];
+
+
+
+const makes_list = makes_list_raw.sort();
+
+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 selectedProductIds = JSON.parse(formData.get("selectedProductIds") || "[]");
+ 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,
+ selectedProductIds
+ }),
+ });
+
+ 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 { shop, 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("");
+
+
+
+
+ const [Turn14Enabled, setTurn14Enabled] = useState("12345"); // 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(() => {
+ 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/brandallitemswithfitment/${brandId}`, {
+ headers: {
+ Authorization: `Bearer ${accessToken}`,
+ "Content-Type": "application/json",
+ },
+ });
+ const data = await res.json();
+ const dataitems = data.items
+ const validItems = Array.isArray(dataitems)
+ ? dataitems.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;
+
+
+
+
+
+
+
+
+
+
+ const [filters, setFilters] = useState({ make: '', model: '', year: '', drive: '', baseModel: '' });
+ const [filterregulatstock, setfilterregulatstock] = useState(false)
+
+ const [isFilter_EnableZeroStock, set_isFilter_EnableZeroStock] = useState(true)
+ const [isFilter_IncludeLtlFreightRequired, setisFilter_IncludeLtlFreightRequired] = useState(true)
+ const [isFilter_Excludeclearance_item, setisFilter_Excludeclearance_item] = useState(false)
+ const [isFilter_Excludeair_freight_prohibited, setisFilter_Excludeair_freight_prohibited] = useState(false)
+ const [isFilter_IncludeProductWithNoImages, setisFilter_IncludeProductWithNoImages] = useState(true)
+
+ const handleFilterChange = (field) => (value) => {
+ setFilters((prev) => ({ ...prev, [field]: value }));
+ };
+
+
+
+ const applyFitmentFilters = (items) => {
+ return items.filter((item) => {
+ const tags = item?.attributes?.fitmmentTags || {};
+ const productName = item?.attributes?.product_name || '';
+ const brand = item?.attributes?.brand || '';
+ const partDescription = item?.attributes?.part_description || '';
+ const descriptions = item?.attributes?.descriptions || [];
+
+ const makeMatch = !filters.make || tags.make?.includes(filters.make) || productName.includes(filters.make) || brand.includes(filters.make) || descriptions.some((desc) => desc.description.includes(filters.make));
+
+
+ const modelMatch = !filters.model || tags.model?.includes(filters.model) || productName.includes(filters.model) || brand.includes(filters.model) || descriptions.some((desc) => desc.description.includes(filters.model));
+ // console.log(`Model check result: ${modelMatch}`);
+
+ const yearMatch = !filters.year || tags.year?.includes(filters.year) || productName.includes(filters.year) || brand.includes(filters.year) || descriptions.some((desc) => desc.description.includes(filters.year));
+ /// console.log(`Year check result: ${yearMatch}`);
+
+ const driveMatch = !filters.drive || tags.drive?.includes(filters.drive) || productName.includes(filters.drive) || brand.includes(filters.drive) || descriptions.some((desc) => desc.description.includes(filters.drive));
+ // console.log(`Drive check result: ${driveMatch}`);
+
+ const baseModelMatch = !filters.baseModel || tags.baseModel?.includes(filters.baseModel) || productName.includes(filters.baseModel) || brand.includes(filters.baseModel) || descriptions.some((desc) => desc.description.includes(filters.baseModel));
+ // console.log(`Base Model check result: ${baseModelMatch}`);
+
+ // Combine all the conditions
+ var isMatch = makeMatch && modelMatch && yearMatch && driveMatch && baseModelMatch// && item.attributes.regular_stock
+ if (filterregulatstock) {
+ isMatch = isMatch && item?.attributes?.regular_stock
+ }
+
+
+ if (!isFilter_EnableZeroStock) {
+ isMatch = isMatch && item?.inventoryQuantity > 0;
+ }
+ if (!isFilter_IncludeLtlFreightRequired) {
+ isMatch = isMatch && item?.attributes?.ltl_freight_required !== true;
+ }
+
+ if (isFilter_Excludeclearance_item) {
+ isMatch = isMatch && item?.attributes?.clearance_item !== true;
+ }
+ if (isFilter_Excludeair_freight_prohibited) {
+ isMatch = isMatch && item?.attributes?.air_freight_prohibited !== true;
+ }
+
+ if (!isFilter_IncludeProductWithNoImages) {
+ isMatch = isMatch && item?.attributes?.files && item?.attributes?.files.length > 0;
+ }
+
+
+ return isMatch;
+ });
+ };
+
+
+
+
+ const selectedProductIds = []
+
+
+
+ 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` },
+ ];
+
+
+
+ const [popoverActive, setPopoverActive] = useState(false);
+
+ const togglePopover = () => setPopoverActive((active) => !active);
+
+
+ const activator = (
+
+ );
+ // If Turn14 is explicitly NOT connected, show a lightweight call-to-action screen
+ if (Turn14Enabled === false) {
+ // Fallback if items array is not loaded yet
+ const safeItems = Array.isArray(items) && items.length >= 4 ? items : [
+ { link: "#", icon: "π", text: "Connect Turn14" },
+ { link: "#", icon: "βοΈ", text: "Settings" },
+ { link: "#", icon: "β", text: "Help" },
+ { link: "#", icon: "π", text: "Documentation" }
+ ];
+ 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 */}
+
+
+
+
+
+
+
+ );
+ }
+
+
+ return (
+
+
+
+
+ {/*
+ Turn 14 Status:{" "}
+ {Turn14Enabled === true
+ ? "β
Turn14 x Shopify Connected!"
+ : Turn14Enabled === false
+ ? "β Turn14 x Shopify Connection Doesn't Exists"
+ : "Checking..."}
+
*/}
+
+ {brands.length === 0 ? (
+
+
+ No brands selected yet.
+
+
+ ) : (
+
+
+ Brand ID },
+ { title: Brand Name
},
+ { title: Brand Logo
},
+ { title: Action
},
+ { title: Products Count
},
+ ]}
+ selectable={false}
+ >
+ {brands.map((brand, index) => {
+
+ return (
+
+
+ {brand.id}
+ {brand.name}
+
+
+
+
+
+
+
+
+ {itemsMap[brand.id]?.length || 0}
+
+
+
+ )
+ })}
+
+
+
+ )}
+
+ {brands.map((brand) => {
+ const filteredItems = applyFitmentFilters(itemsMap[brand.id] || []);
+ // console.log("Filtered items for brand", brand.id, ":", filteredItems.map((item) => item.id));
+ const uniqueTags = {
+ make: new Set(),
+ model: new Set(),
+ year: new Set(),
+ drive: new Set(),
+ baseModel: new Set(),
+ };
+
+ (itemsMap[brand.id] || []).forEach(item => {
+ const tags = item?.attributes?.fitmmentTags || {};
+ Object.keys(uniqueTags).forEach(key => {
+ (tags[key] || []).forEach(val => uniqueTags[key].add(val));
+ });
+ });
+
+ return (
+
+ 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] ? (
+
+ ) : (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ({
+ label: m,
+ value: m,
+ })),
+ ]}
+ selected={filters.make}
+ allowMultiple
+ />
+
+
+
+
+
+
+
+ {filteredItems.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'}
+ Inventory Quantity: {item?.inventoryQuantity || 'N/A'}
+ Regular Stock : {item?.attributes?.regular_stock === true ? "YES" : "NO" || 'N/A'}
+ LTL Freight Required : {item?.attributes?.ltl_freight_required === true ? "YES" : "NO" || 'N/A'}
+ Is Clearance Item : {item?.attributes?.is_clearance_item === true ? "YES" : "NO" || 'N/A'}
+ Is Air Freight Prohibited : {item?.attributes?.is_air_freight_prohibited === true ? "YES" : "NO" || 'N/A'}
+ No. Of Images : {item?.attributes?.files.length || 'N/A'}
+
+ */}
+
+
+
+ {/* Part Number */}
+
+ Part Number: {item?.attributes?.part_number || 'N/A'}
+
+
+ {/* Category & Subcategory */}
+
+ Category: {item?.attributes?.category || 'N/A'} > {item?.attributes?.subcategory || 'N/A'}
+
+
+ {/* Price */}
+
+ Price: ${item?.attributes?.price || '0.00'}
+
+
+ {/* Description (1 column) */}
+
+ Description: {item?.attributes?.part_description || 'No description available'}
+
+
+ {/* Inventory Quantity */}
+
+ Inventory Quantity: {item?.inventoryQuantity || 'N/A'}
+
+
+ {/* Regular Stock */}
+
+ Regular Stock: {item?.attributes?.regular_stock === true ? "YES" : "NO" || 'N/A'}
+
+
+ {/* LTL Freight Required */}
+
+ LTL Freight Required: {item?.attributes?.ltl_freight_required === true ? "YES" : "NO" || 'N/A'}
+
+
+ {/* Clearance Item */}
+
+ Is Clearance Item: {item?.attributes?.is_clearance_item === true ? "YES" : "NO" || 'N/A'}
+
+
+ {/* Air Freight Prohibited */}
+
+ Is Air Freight Prohibited: {item?.attributes?.is_air_freight_prohibited === true ? "YES" : "NO" || 'N/A'}
+
+
+ {/* Number of Images */}
+
+ No. Of Images: {item?.attributes?.files.length || 'N/A'}
+
+
+
+
+
+
+
+ ))}
+
+
+ )}
+
+
+ )
+ )
+ })}
+
+ {toastMarkup}
+
+
+ );
+}
\ No newline at end of file
diff --git a/app/routes/app.managebrand.jsx b/app/routes/app.managebrand.jsx
index 8d25160..261a965 100644
--- a/app/routes/app.managebrand.jsx
+++ b/app/routes/app.managebrand.jsx
@@ -1,6 +1,6 @@
-import React, { useEffect, useState } from "react";
+import React, { useEffect, useMemo, useState } from "react";
import { json } from "@remix-run/node";
-import { useLoaderData, Form, useActionData } from "@remix-run/react";
+import { useLoaderData, Form, useActionData, useNavigate } from "@remix-run/react";
import {
Page,
Layout,
@@ -12,78 +12,176 @@ import {
Button,
TextField,
Banner,
- InlineError,
Toast,
Frame,
Select,
ProgressBar,
Checkbox,
Text,
- ChoiceList,
Popover,
OptionList,
+ InlineStack,
} from "@shopify/polaris";
import { authenticate } from "../shopify.server";
import { TitleBar } from "@shopify/app-bridge-react";
+const PLAN_NAME = "Starter Sync";
+const ALLOWED_STATUSES = ["ACTIVE", "TRIAL"];
+
const styles = {
gridContainer: {
- display: 'grid',
- gridTemplateColumns: '1fr 1fr', // Two equal columns
- gap: '10px', // Space between items
+ display: "grid",
+ gridTemplateColumns: "1fr 1fr",
+ gap: "10px",
},
gridItem: {
- display: 'flex',
- flexDirection: 'column',
+ display: "flex",
+ flexDirection: "column",
},
gridFullWidthItem: {
- gridColumn: 'span 2', // This takes up the full width (for Description)
- display: 'flex',
- flexDirection: 'column',
+ gridColumn: "span 2",
+ display: "flex",
+ flexDirection: "column",
},
};
-
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
+ return data.status === 1;
} catch (err) {
console.error("Error checking shop:", err);
- return false; // default to false if error
+ return false;
}
}
+function getIntervalLabel(interval) {
+ switch (interval) {
+ case "ANNUAL":
+ return "Every 12 months";
+ case "EVERY_30_DAYS":
+ return "Every 30 days";
+ default:
+ return interval || "N/A";
+ }
+}
+function formatMoney(amount, currencyCode = "USD") {
+ if (amount == null) return "N/A";
+ return `${currencyCode} ${Number(amount).toFixed(2)}`;
+}
+
+function formatDate(date) {
+ if (!date) return "N/A";
+ return new Date(date).toLocaleDateString(undefined, {
+ year: "numeric",
+ month: "short",
+ day: "numeric",
+ });
+}
+
+async function getSubscriptionDetails(request) {
+ const { admin, session } = await authenticate.admin(request);
+ const shop = session.shop;
+
+ const resp = await admin.graphql(`
+ query CurrentSubscriptionDetails {
+ currentAppInstallation {
+ activeSubscriptions {
+ id
+ name
+ status
+ test
+ createdAt
+ trialDays
+ currentPeriodEnd
+ lineItems {
+ id
+ plan {
+ pricingDetails {
+ __typename
+ ... on AppRecurringPricing {
+ interval
+ price {
+ amount
+ currencyCode
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ `);
+
+ const result = await resp.json();
+
+ const subscriptions =
+ result?.data?.currentAppInstallation?.activeSubscriptions || [];
+
+ const subscription =
+ subscriptions.find((sub) => ALLOWED_STATUSES.includes(sub.status)) ||
+ subscriptions[0] ||
+ null;
+
+ const recurringPricing =
+ subscription?.lineItems?.find(
+ (item) =>
+ item?.plan?.pricingDetails?.__typename === "AppRecurringPricing"
+ )?.plan?.pricingDetails || null;
+
+ const isSubscribed =
+ !!subscription && ALLOWED_STATUSES.includes(subscription.status);
+
+ return {
+ shop,
+ isSubscribed,
+ subscription: subscription
+ ? {
+ id: subscription.id,
+ name: subscription.name || PLAN_NAME,
+ status: subscription.status,
+ test: subscription.test ?? false,
+ createdAt: subscription.createdAt,
+ trialDays: subscription.trialDays ?? 0,
+ currentPeriodEnd: subscription.currentPeriodEnd,
+ interval: recurringPricing?.interval || null,
+ priceAmount: recurringPricing?.price?.amount || null,
+ currencyCode: recurringPricing?.price?.currencyCode || "USD",
+ }
+ : null,
+ };
+}
export const loader = async ({ request }) => {
-
-
- const { getTurn14AccessTokenFromMetafield } = await import("../utils/turn14Token.server");
-
-
+ const { getTurn14AccessTokenFromMetafield } = await import(
+ "../utils/turn14Token.server"
+ );
const { admin } = await authenticate.admin(request);
const { session } = await authenticate.admin(request);
const shop = session.shop;
- var accessToken = ""
+ const { isSubscribed, subscription } = await getSubscriptionDetails(request);
+
+ let accessToken = "";
try {
accessToken = await getTurn14AccessTokenFromMetafield(request);
} catch (err) {
- return json({ brands: [], collections: [], selectedBrandsFromShopify: [], shop });
console.error("Error getting Turn14 access token:", err);
- // Proceeding with empty accessToken
+ return json({
+ brands: [],
+ accessToken: "",
+ shop,
+ isSubscribed,
+ subscription,
+ });
}
-
-
-
-
-
const res = await admin.graphql(`{
shop {
metafield(namespace: "turn14", key: "selected_brands") {
@@ -96,179 +194,195 @@ export const loader = async ({ request }) => {
let brands = [];
try {
- brands = JSON.parse(rawValue);
+ brands = JSON.parse(rawValue || "[]");
} catch (err) {
console.error("β Failed to parse metafield value:", err);
}
-
-
-
- return json({ brands, accessToken, shop });
+ return json({
+ brands,
+ accessToken,
+ shop,
+ isSubscribed,
+ subscription,
+ });
};
-
const makes_list_raw = [
- 'Alfa Romeo',
- 'Ferrari',
- 'Dodge',
- 'Subaru',
- 'Toyota',
- 'Volkswagen',
- 'Volvo',
- 'Audi',
- 'BMW',
- 'Buick',
- 'Cadillac',
- 'Chevrolet',
- 'Chrysler',
- 'CX Automotive',
- 'Nissan',
- 'Ford',
- 'Hyundai',
- 'Infiniti',
- 'Lexus',
- 'Mercury',
- 'Mazda',
- 'Oldsmobile',
- 'Plymouth',
- 'Pontiac',
- 'Rolls-Royce',
- 'Eagle',
- 'Lincoln',
- 'Mercedes-Benz',
- 'GMC',
- 'Saab',
- 'Honda',
- 'Saturn',
- 'Mitsubishi',
- 'Isuzu',
- 'Jeep',
- 'AM General',
- 'Geo',
- 'Suzuki',
- 'E. P. Dutton, Inc.',
- 'Land Rover',
- 'PAS, Inc',
- 'Acura',
- 'Jaguar',
- 'Lotus',
- 'Grumman Olson',
- 'Porsche',
- 'American Motors Corporation',
- 'Kia',
- 'Lamborghini',
- 'Panoz Auto-Development',
- 'Maserati',
- 'Saleen',
- 'Aston Martin',
- 'Dabryan Coach Builders Inc',
- 'Federal Coach',
- 'Vector',
- 'Bentley',
- 'Daewoo',
- 'Qvale',
- 'Roush Performance',
- 'Autokraft Limited',
- 'Bertone',
- 'Panther Car Company Limited',
- 'Texas Coach Company',
- 'TVR Engineering Ltd',
- 'Morgan',
- 'MINI',
- 'Yugo',
- 'BMW Alpina',
- 'Renault',
- 'Bitter Gmbh and Co. Kg',
- 'Scion',
- 'Maybach',
- 'Lambda Control Systems',
- 'Merkur',
- 'Peugeot',
- 'Spyker',
- 'London Coach Co Inc',
- 'Hummer',
- 'Bugatti',
- 'Pininfarina',
- 'Shelby',
- 'Saleen Performance',
- 'smart',
- 'Tecstar, LP',
- 'Kenyon Corporation Of America',
- 'Avanti Motor Corporation',
- 'Bill Dovell Motor Car Company',
- 'Import Foreign Auto Sales Inc',
- 'S and S Coach Company E.p. Dutton',
- 'Superior Coaches Div E.p. Dutton',
- 'Vixen Motor Company',
- 'Volga Associated Automobile',
- 'Wallace Environmental',
- 'Import Trade Services',
- 'J.K. Motors',
- 'Panos',
- 'Quantum Technologies',
- 'London Taxi',
- 'Red Shift Ltd.',
- 'Ruf Automobile Gmbh',
- 'Excalibur Autos',
- 'Mahindra',
- 'VPG',
- 'Fiat',
- 'Sterling',
- 'Azure Dynamics',
- 'McLaren Automotive',
- 'Ram',
- 'CODA Automotive',
- 'Fisker',
- 'Tesla',
- 'Mcevoy Motors',
- 'BYD',
- 'ASC Incorporated',
- 'SRT',
- 'CCC Engineering',
- 'Mobility Ventures LLC',
- 'Pagani',
- 'Genesis',
- 'Karma',
- 'Koenigsegg',
- 'Aurora Cars Ltd',
- 'RUF Automobile',
- 'Dacia',
- 'STI',
- 'Daihatsu',
- 'Polestar',
- 'Kandi',
- 'Rivian',
- 'Lucid',
- 'JBA Motorcars, Inc.',
- 'Lordstown',
- 'Vinfast',
- 'INEOS Automotive',
- 'Bugatti Rimac',
- 'Grumman Allied Industries',
- 'Environmental Rsch and Devp Corp',
- 'Evans Automobiles',
- 'Laforza Automobile Inc',
- 'General Motors',
- 'Consulier Industries Inc',
- 'Goldacre',
- 'Isis Imports Ltd',
- 'PAS Inc - GMC'
+ "Alfa Romeo",
+ "Ferrari",
+ "Dodge",
+ "Subaru",
+ "Toyota",
+ "Volkswagen",
+ "Volvo",
+ "Audi",
+ "BMW",
+ "Buick",
+ "Cadillac",
+ "Chevrolet",
+ "Chrysler",
+ "CX Automotive",
+ "Nissan",
+ "Ford",
+ "Hyundai",
+ "Infiniti",
+ "Lexus",
+ "Mercury",
+ "Mazda",
+ "Oldsmobile",
+ "Plymouth",
+ "Pontiac",
+ "Rolls-Royce",
+ "Eagle",
+ "Lincoln",
+ "Mercedes-Benz",
+ "GMC",
+ "Saab",
+ "Honda",
+ "Saturn",
+ "Mitsubishi",
+ "Isuzu",
+ "Jeep",
+ "AM General",
+ "Geo",
+ "Suzuki",
+ "E. P. Dutton, Inc.",
+ "Land Rover",
+ "PAS, Inc",
+ "Acura",
+ "Jaguar",
+ "Lotus",
+ "Grumman Olson",
+ "Porsche",
+ "American Motors Corporation",
+ "Kia",
+ "Lamborghini",
+ "Panoz Auto-Development",
+ "Maserati",
+ "Saleen",
+ "Aston Martin",
+ "Dabryan Coach Builders Inc",
+ "Federal Coach",
+ "Vector",
+ "Bentley",
+ "Daewoo",
+ "Qvale",
+ "Roush Performance",
+ "Autokraft Limited",
+ "Bertone",
+ "Panther Car Company Limited",
+ "Texas Coach Company",
+ "TVR Engineering Ltd",
+ "Morgan",
+ "MINI",
+ "Yugo",
+ "BMW Alpina",
+ "Renault",
+ "Bitter Gmbh and Co. Kg",
+ "Scion",
+ "Maybach",
+ "Lambda Control Systems",
+ "Merkur",
+ "Peugeot",
+ "Spyker",
+ "London Coach Co Inc",
+ "Hummer",
+ "Bugatti",
+ "Pininfarina",
+ "Shelby",
+ "Saleen Performance",
+ "smart",
+ "Tecstar, LP",
+ "Kenyon Corporation Of America",
+ "Avanti Motor Corporation",
+ "Bill Dovell Motor Car Company",
+ "Import Foreign Auto Sales Inc",
+ "S and S Coach Company E.p. Dutton",
+ "Superior Coaches Div E.p. Dutton",
+ "Vixen Motor Company",
+ "Volga Associated Automobile",
+ "Wallace Environmental",
+ "Import Trade Services",
+ "J.K. Motors",
+ "Panos",
+ "Quantum Technologies",
+ "London Taxi",
+ "Red Shift Ltd.",
+ "Ruf Automobile Gmbh",
+ "Excalibur Autos",
+ "Mahindra",
+ "VPG",
+ "Fiat",
+ "Sterling",
+ "Azure Dynamics",
+ "McLaren Automotive",
+ "Ram",
+ "CODA Automotive",
+ "Fisker",
+ "Tesla",
+ "Mcevoy Motors",
+ "BYD",
+ "ASC Incorporated",
+ "SRT",
+ "CCC Engineering",
+ "Mobility Ventures LLC",
+ "Pagani",
+ "Genesis",
+ "Karma",
+ "Koenigsegg",
+ "Aurora Cars Ltd",
+ "RUF Automobile",
+ "Dacia",
+ "STI",
+ "Daihatsu",
+ "Polestar",
+ "Kandi",
+ "Rivian",
+ "Lucid",
+ "JBA Motorcars, Inc.",
+ "Lordstown",
+ "Vinfast",
+ "INEOS Automotive",
+ "Bugatti Rimac",
+ "Grumman Allied Industries",
+ "Environmental Rsch and Devp Corp",
+ "Evans Automobiles",
+ "Laforza Automobile Inc",
+ "General Motors",
+ "Consulier Industries Inc",
+ "Goldacre",
+ "Isis Imports Ltd",
+ "PAS Inc - GMC",
];
-
-
const makes_list = makes_list_raw.sort();
export const action = async ({ request }) => {
+ const { isSubscribed } = await getSubscriptionDetails(request);
+
+ if (!isSubscribed) {
+ return json(
+ {
+ error:
+ "An active subscription or free trial is required to add products.",
+ },
+ { status: 403 }
+ );
+ }
+
const { admin } = await authenticate.admin(request);
const formData = await request.formData();
const brandId = formData.get("brandId");
const rawCount = formData.get("productCount");
- const selectedProductIds = JSON.parse(formData.get("selectedProductIds") || "[]");
+ const selectedProductIds = JSON.parse(
+ formData.get("selectedProductIds") || "[]"
+ );
const productCount = parseInt(rawCount, 10) || 10;
- const { getTurn14AccessTokenFromMetafield } = await import("../utils/turn14Token.server");
+ const { getTurn14AccessTokenFromMetafield } = await import(
+ "../utils/turn14Token.server"
+ );
const accessToken = await getTurn14AccessTokenFromMetafield(request);
const { session } = await authenticate.admin(request);
@@ -285,11 +399,12 @@ export const action = async ({ request }) => {
brandID: brandId,
turn14accessToken: accessToken,
productCount,
- selectedProductIds
+ selectedProductIds,
}),
});
console.log("Response from manageProducts:", resp.status, resp.statusText);
+
if (!resp.ok) {
const err = await resp.text();
return json({ error: err }, { status: resp.status });
@@ -297,12 +412,16 @@ export const action = async ({ request }) => {
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 { shop, brands, accessToken } = useLoaderData();
+ const navigate = useNavigate();
+ const { shop, brands, accessToken, isSubscribed, subscription } =
+ useLoaderData();
+
const [expandedBrand, setExpandedBrand] = useState(null);
const [itemsMap, setItemsMap] = useState({});
const [loadingMap, setLoadingMap] = useState({});
@@ -318,11 +437,30 @@ export default function ManageBrandProducts() {
const [currentProduct, setCurrentProduct] = useState(null);
const [results, setResults] = useState([]);
const [detail, setDetail] = useState("");
+ const [Turn14Enabled, setTurn14Enabled] = useState("12345");
+ const [filters, setFilters] = useState({
+ make: "",
+ model: "",
+ year: "",
+ drive: "",
+ baseModel: "",
+ });
+ const [filterregulatstock, setfilterregulatstock] = useState(false);
+ const [isFilter_EnableZeroStock, set_isFilter_EnableZeroStock] =
+ useState(true);
+ const [isFilter_IncludeLtlFreightRequired, setisFilter_IncludeLtlFreightRequired] =
+ useState(true);
+ const [isFilter_Excludeclearance_item, setisFilter_Excludeclearance_item] =
+ useState(false);
+ const [
+ isFilter_Excludeair_freight_prohibited,
+ setisFilter_Excludeair_freight_prohibited,
+ ] = useState(false);
+ const [isFilter_IncludeProductWithNoImages, setisFilter_IncludeProductWithNoImages] =
+ useState(true);
-
-
- const [Turn14Enabled, setTurn14Enabled] = useState("12345"); // null | true | false
+ const [popoverActive, setPopoverActive] = useState(false);
useEffect(() => {
if (!shop) {
@@ -337,8 +475,6 @@ export default function ManageBrandProducts() {
})();
}, [shop]);
-
-
useEffect(() => {
if (actionData?.processId) {
setProcessId(actionData.processId);
@@ -348,35 +484,39 @@ export default function ManageBrandProducts() {
}, [actionData]);
const checkStatus = async () => {
+ if (!processId) return;
+
setPolling(true);
try {
- const response = await fetch(`https://backend.data4autos.com/manageProducts/status/${processId}`);
+ 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);
+ setTotalProducts(data.stats?.total || 0);
+ setProcessedProducts(data.stats?.processed || 0);
setCurrentProduct(data.current);
if (data.results) {
setResults(data.results);
}
- // Continue polling if still processing
- if (data.status !== 'done' && data.status !== 'error') {
+ 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);
+ setStatus("error");
+ setDetail("Failed to check status");
+ console.error("Error checking status:", error);
}
};
+
useEffect(() => {
let interval;
if (status?.includes("processing") && processId) {
@@ -392,13 +532,15 @@ export default function ManageBrandProducts() {
};
useEffect(() => {
- if (initialLoad && brands.length > 0) {
+ if (initialLoad && brands.length > 0 && isSubscribed) {
toggleAllBrands();
setInitialLoad(false);
}
- }, [brands, initialLoad]);
+ }, [brands, initialLoad, isSubscribed]);
const toggleBrandItems = async (brandId) => {
+ if (!isSubscribed) return;
+
const isExpanded = expandedBrand === brandId;
if (isExpanded) {
setExpandedBrand(null);
@@ -407,16 +549,19 @@ export default function ManageBrandProducts() {
if (!itemsMap[brandId]) {
setLoadingMap((prev) => ({ ...prev, [brandId]: true }));
try {
- const res = await fetch(`https://turn14.data4autos.com/v1/items/brandallitemswithfitment/${brandId}`, {
- headers: {
- Authorization: `Bearer ${accessToken}`,
- "Content-Type": "application/json",
- },
- });
+ const res = await fetch(
+ `https://turn14.data4autos.com/v1/items/brandallitemswithfitment/${brandId}`,
+ {
+ headers: {
+ Authorization: `Bearer ${accessToken}`,
+ "Content-Type": "application/json",
+ },
+ }
+ );
const data = await res.json();
- const dataitems = data.items
+ const dataitems = data.items;
const validItems = Array.isArray(dataitems)
- ? dataitems.filter(item => item && item.id && item.attributes)
+ ? dataitems.filter((item) => item && item.id && item.attributes)
: [];
setItemsMap((prev) => ({ ...prev, [brandId]: validItems }));
} catch (err) {
@@ -430,133 +575,159 @@ export default function ManageBrandProducts() {
const toastMarkup = toastActive ? (
setToastActive(false)}
/>
) : null;
-
-
-
-
-
-
-
-
-
- const [filters, setFilters] = useState({ make: '', model: '', year: '', drive: '', baseModel: '' });
- const [filterregulatstock, setfilterregulatstock] = useState(false)
-
- const [isFilter_EnableZeroStock, set_isFilter_EnableZeroStock] = useState(true)
- const [isFilter_IncludeLtlFreightRequired, setisFilter_IncludeLtlFreightRequired] = useState(true)
- const [isFilter_Excludeclearance_item, setisFilter_Excludeclearance_item] = useState(false)
- const [isFilter_Excludeair_freight_prohibited, setisFilter_Excludeair_freight_prohibited] = useState(false)
- const [isFilter_IncludeProductWithNoImages, setisFilter_IncludeProductWithNoImages] = useState(true)
-
const handleFilterChange = (field) => (value) => {
setFilters((prev) => ({ ...prev, [field]: value }));
};
-
-
const applyFitmentFilters = (items) => {
return items.filter((item) => {
const tags = item?.attributes?.fitmmentTags || {};
- const productName = item?.attributes?.product_name || '';
- const brand = item?.attributes?.brand || '';
- const partDescription = item?.attributes?.part_description || '';
+ const productName = item?.attributes?.product_name || "";
+ const brand = item?.attributes?.brand || "";
const descriptions = item?.attributes?.descriptions || [];
- const makeMatch = !filters.make || tags.make?.includes(filters.make) || productName.includes(filters.make) || brand.includes(filters.make) || descriptions.some((desc) => desc.description.includes(filters.make));
+ const makeMatch =
+ !filters.make ||
+ tags.make?.includes(filters.make) ||
+ productName.includes(filters.make) ||
+ brand.includes(filters.make) ||
+ descriptions.some((desc) => desc.description.includes(filters.make));
+ const modelMatch =
+ !filters.model ||
+ tags.model?.includes(filters.model) ||
+ productName.includes(filters.model) ||
+ brand.includes(filters.model) ||
+ descriptions.some((desc) => desc.description.includes(filters.model));
- const modelMatch = !filters.model || tags.model?.includes(filters.model) || productName.includes(filters.model) || brand.includes(filters.model) || descriptions.some((desc) => desc.description.includes(filters.model));
- // console.log(`Model check result: ${modelMatch}`);
+ const yearMatch =
+ !filters.year ||
+ tags.year?.includes(filters.year) ||
+ productName.includes(filters.year) ||
+ brand.includes(filters.year) ||
+ descriptions.some((desc) => desc.description.includes(filters.year));
- const yearMatch = !filters.year || tags.year?.includes(filters.year) || productName.includes(filters.year) || brand.includes(filters.year) || descriptions.some((desc) => desc.description.includes(filters.year));
- /// console.log(`Year check result: ${yearMatch}`);
+ const driveMatch =
+ !filters.drive ||
+ tags.drive?.includes(filters.drive) ||
+ productName.includes(filters.drive) ||
+ brand.includes(filters.drive) ||
+ descriptions.some((desc) => desc.description.includes(filters.drive));
- const driveMatch = !filters.drive || tags.drive?.includes(filters.drive) || productName.includes(filters.drive) || brand.includes(filters.drive) || descriptions.some((desc) => desc.description.includes(filters.drive));
- // console.log(`Drive check result: ${driveMatch}`);
+ const baseModelMatch =
+ !filters.baseModel ||
+ tags.baseModel?.includes(filters.baseModel) ||
+ productName.includes(filters.baseModel) ||
+ brand.includes(filters.baseModel) ||
+ descriptions.some((desc) =>
+ desc.description.includes(filters.baseModel)
+ );
- const baseModelMatch = !filters.baseModel || tags.baseModel?.includes(filters.baseModel) || productName.includes(filters.baseModel) || brand.includes(filters.baseModel) || descriptions.some((desc) => desc.description.includes(filters.baseModel));
- // console.log(`Base Model check result: ${baseModelMatch}`);
+ let isMatch =
+ makeMatch && modelMatch && yearMatch && driveMatch && baseModelMatch;
- // Combine all the conditions
- var isMatch = makeMatch && modelMatch && yearMatch && driveMatch && baseModelMatch// && item.attributes.regular_stock
if (filterregulatstock) {
- isMatch = isMatch && item?.attributes?.regular_stock
+ isMatch = isMatch && item?.attributes?.regular_stock;
}
-
if (!isFilter_EnableZeroStock) {
isMatch = isMatch && item?.inventoryQuantity > 0;
}
if (!isFilter_IncludeLtlFreightRequired) {
isMatch = isMatch && item?.attributes?.ltl_freight_required !== true;
}
-
if (isFilter_Excludeclearance_item) {
isMatch = isMatch && item?.attributes?.clearance_item !== true;
}
if (isFilter_Excludeair_freight_prohibited) {
- isMatch = isMatch && item?.attributes?.air_freight_prohibited !== true;
+ isMatch =
+ isMatch && item?.attributes?.air_freight_prohibited !== true;
}
-
if (!isFilter_IncludeProductWithNoImages) {
- isMatch = isMatch && item?.attributes?.files && item?.attributes?.files.length > 0;
+ isMatch =
+ isMatch &&
+ item?.attributes?.files &&
+ item?.attributes?.files.length > 0;
}
-
return isMatch;
});
};
-
-
-
- const selectedProductIds = []
-
-
-
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` },
+ {
+ 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`,
+ },
];
-
-
- const [popoverActive, setPopoverActive] = useState(false);
-
const togglePopover = () => setPopoverActive((active) => !active);
-
const activator = (
-