2025-08-29 02:47:12 +00:00

319 lines
11 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useState, useEffect } from "react";
import { json } from "@remix-run/node";
import { useLoaderData, useActionData, useSubmit } from "@remix-run/react";
import {
Page,
Layout,
Card,
BlockStack,
Text,
Badge,
InlineStack,
Image,
Divider,
Button,
Modal,
TextField,
Box,
Link,
} from "@shopify/polaris";
import { TitleBar } from "@shopify/app-bridge-react";
import data4autosLogo from "../assets/data4autos_logo.png"; // make sure this exists
import turn14DistributorLogo from "../assets/turn14-logo.png";
import { authenticate } from "../shopify.server"; // Shopify server authentication
import { Form } from "@remix-run/react";
// Loader to check subscription status
export const loader = async ({ request }) => {
const { admin } = await authenticate.admin(request);
// Query the current subscription status
const resp = await admin.graphql(`
query {
currentAppInstallation {
activeSubscriptions {
id
status
trialDays
createdAt
currentPeriodEnd
}
}
}
`);
const result = await resp.json();
const subscription = result.data.currentAppInstallation.activeSubscriptions[0] || null;
const { session } = await authenticate.admin(request);
const shop = session.shop;
// For new users, there's no subscription. We will show a "Not subscribed" message.
if (!subscription) {
return json({ redirectToBilling: true, subscription: null,shop });
}
// If no active or trial subscription, return redirect signal
if (subscription.status !== "ACTIVE" && subscription.status !== "TRIAL") {
return json({ redirectToBilling: true, subscription ,shop });
}
return json({ redirectToBilling: false, subscription,shop });
};
// Action to create subscription
export const action = async ({ request }) => {
console.log("Creating subscription...");
const { admin } = await authenticate.admin(request);
const createRes = await admin.graphql(`
mutation {
appSubscriptionCreate(
name: "Pro Plan",
returnUrl: "https://your-app.com/after-billing",
lineItems: [
{
plan: {
appRecurringPricingDetails: {
price: { amount: 19.99, currencyCode: USD },
interval: EVERY_30_DAYS
}
}
}
],
trialDays: 7, # ✅ trialDays is a top-level argument!
test: false
) {
confirmationUrl
appSubscription {
id
status
trialDays
}
userErrors {
field
message
}
}
}
`);
const data = await createRes.json();
console.log("Subscription creation response:", data);
if (data.errors || !data.data.appSubscriptionCreate.confirmationUrl) {
return json({ errors: ["Failed to create subscription."] }, { status: 400 });
}
console.log("Subscription created successfully:", data.data.appSubscriptionCreate.confirmationUrl);
return json({
confirmationUrl: data.data.appSubscriptionCreate.confirmationUrl
});
};
export default function Index() {
const actionData = useActionData();
const loaderData = useLoaderData();
const submit = useSubmit(); // Use submit to trigger the action
const [activeModal, setActiveModal] = useState(false);
const subscription = loaderData?.subscription;
const shop = loaderData?.shop;
// useEffect(() => {
// console.log("Action data:", actionData);
// // If we have a confirmation URL, redirect to it
// if (actionData?.confirmationUrl) {
// window.location.href = actionData.confirmationUrl; // Redirect to Shopify's billing confirmation page
// }
// }, [actionData]);
useEffect(() => {
if (actionData?.confirmationUrl) {
window.open(actionData.confirmationUrl, "_blank", "noopener,noreferrer");
setActiveModal(false); // close the modal
}
}, [actionData]);
const openModal = () => setActiveModal(true);
const closeModal = () => setActiveModal(false);
// const items = [
// { icon: "⚙️", text: "Manage API settings", link: "https://admin.shopify.com/store/veloxautomotive/apps/d4a-turn14/app/settings" },
// { icon: "🏷️", text: "Browse and import available brands", link: "https://admin.shopify.com/store/veloxautomotive/apps/d4a-turn14/app/brands" },
// { icon: "📦", text: "Sync brand collections to Shopify", link: "https://admin.shopify.com/store/veloxautomotive/apps/d4a-turn14/app/managebrand" },
// { icon: "🔐", text: "Handle secure Turn14 login credentials", link: "https://admin.shopify.com/store/veloxautomotive/apps/d4a-turn14/app/help" },
// ];
const shopDomain = (shop || "").split(".")[0];; // from the GraphQL query above
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` },
];
return (
<Page>
<TitleBar title="Data4Autos Turn14 Integration" />
<Layout>
<Layout.Section>
<Card padding="500">
<BlockStack gap="400">
<BlockStack gap="400" align="center">
{/* Centered Heading */}
<Text variant="headingLg" as="h1" alignment="center">
Welcome to your Turn14 Dashboard
</Text>
{/* Logos Row */}
<InlineStack gap="800" align="center" blockAlign="center">
<Image
source={data4autosLogo}
alt="Data4Autos Logo"
width={120}
/>
<Image
source={turn14DistributorLogo}
alt="Turn14 Distributors Logo"
width={200}
/>
</InlineStack>
</BlockStack>
<Divider />
<BlockStack gap="800">
<Text variant="headingMd" as="h3">
🚀 Data4Autos Turn14 Integration gives you the power to sync
product brands, manage collections, and automate catalog setup directly from
Turn14 to your Shopify store.
</Text>
<InlineStack gap="400">
<Text as="h3" variant="headingLg" fontWeight="medium">
{/* 🔧 */}
Use the left sidebar to:
</Text>
<Box
paddingBlockStart="800" // top padding
paddingBlockEnd="800" // bottom padding
style={{
display: "grid",
gridTemplateColumns: "repeat(4, 1fr)",
gap: "1rem",
}}
>
{items.map((item, index) => (
<Card key={index} padding="500" background="bg-surface-secondary">
<BlockStack align="center" gap="200">
<Text as="p" fontWeight="bold" alignment="center" tone="subdued" variant="bodyMd">
<span style={{ fontSize: "2rem" }}>{item.icon}</span>
</Text>
<a href={item?.link} target="_blank" style={{ textDecoration: "none", color: "primary" }}>
<Text as="h6" alignment="center" fontWeight="bold" variant="headingMd">
{item.text}
</Text>
</a>
</BlockStack>
</Card>
))}
</Box>
</InlineStack>
</BlockStack>
<Divider />
<BlockStack gap="400">
{/* Status Badge */}
<InlineStack align="center" gap="400">
<Badge tone="success">Status: Connected</Badge>
<Text tone="subdued">Shopify × Turn14</Text>
</InlineStack>
{/* Support Info */}
<Text tone="subdued" alignment="center">
Need help? Contact us at{" "}
<a href="mailto:support@data4autos.com">
support@data4autos.com
</a>
</Text>
{/* CTA Button */}
<Button
size="large"
variant="primary"
onClick={openModal}
fullWidth
>
{loaderData?.redirectToBilling
? "Proceed to Billing"
: "View Subscription Details"}
</Button>
</BlockStack>
</BlockStack>
</Card>
</Layout.Section>
</Layout>
{/* Modal for Subscription Info */}
<Modal
open={activeModal}
onClose={closeModal}
title="Subscription Details"
// primaryAction={{
// content: "Proceed to Billing",
// onAction: () => {
// submit(null, { method: "post", form: document.getElementById("billing-form") });
// },
// }}
primaryAction={{
content: "Proceed to Billing",
onAction: () => {
submit(null, { method: "post", form: document.getElementById("billing-form") });
},
}}
secondaryActions={[{ content: "Close", onAction: closeModal }]}
>
<Form id="billing-form" method="post">
<Modal.Section>
<BlockStack gap="100">
<TextField
label="Subscription Status"
value={subscription ? subscription.status : "No active subscription"}
disabled
/>
<TextField
label="Trial Days Left"
value={subscription?.trialDays ? `${subscription.trialDays} days left` : "No trial available"}
disabled
/>
<TextField
label="Subscription Plan"
value={subscription?.id ? "Pro Plan" : "Not subscribed"}
disabled
/>
<TextField
label="Trial Expiration Date"
value={subscription?.currentPeriodEnd ? new Date(subscription.currentPeriodEnd).toLocaleDateString() : "N/A"}
disabled
/>
</BlockStack>
</Modal.Section>
</Form>
</Modal>
</Page>
);
}