backend_shopify_data4autos/app/routes/app.settings copy.jsx
2025-08-29 02:47:12 +00:00

312 lines
10 KiB
JavaScript

// app/routes/store-credentials.jsx
import { json, redirect } from "@remix-run/node";
import { useLoaderData, useActionData, Form } from "@remix-run/react";
import { useEffect, useState } from "react";
import {
Page,
Layout,
Card,
TextField,
Button,
TextContainer,
InlineError,
Text,
BlockStack,
InlineStack,
Box,
} from "@shopify/polaris";
import { TitleBar } from "@shopify/app-bridge-react";
import { authenticate } from "../shopify.server";
const SCOPES = [
"read_inventory",
"read_products",
"write_inventory",
"write_products",
"read_publications",
"write_publications",
].join(",");
const REDIRECT_URI = "https://backend.data4autos.com/auth/callback";
const CLIENT_ID = "b7534c980967bad619cfdb9d3f837cfa";
export const loader = async ({ request }) => {
const { admin } = await authenticate.admin(request);
const resp = await admin.graphql(`
{
shop {
id
name
metafield(namespace: "turn14", key: "credentials") { value }
}
}
`);
const { data } = await resp.json();
let creds = {};
if (data.shop.metafield?.value) {
try { creds = JSON.parse(data.shop.metafield.value); } catch { }
}
//creds = {};
return json({
shopName: data.shop.name,
shopId: data.shop.id,
savedCreds: creds,
});
};
// export const action = async ({ request }) => {
// const formData = await request.formData();
// const { admin } = await authenticate.admin(request);
// // ——— Handle Shopify-install trigger ———
// if (formData.get("install_shopify") === "1") {
// const shopName = formData.get("shop_name");
// const stateNonce = Math.random().toString(36).slice(2);
// const installUrl =
// `https://${shopName}.myshopify.com/admin/oauth/authorize` +
// `?client_id=${CLIENT_ID}` +
// `&scope=${SCOPES}` +
// `&redirect_uri=${encodeURIComponent(REDIRECT_URI)}` +
// `&state=${stateNonce}` +
// `&grant_options%5B%5D=per-user`;
// // return the URL instead of redirecting
// return json({ confirmationUrl: installUrl });
// }
// // ——— Otherwise handle Turn14 token exchange ———
// const clientId = formData.get("client_id");
// const clientSecret = formData.get("client_secret");
// const shopInfo = await admin.graphql(`{ shop { id } }`);
// const shopId = (await shopInfo.json()).data.shop.id;
// let tokenData;
// try {
// const tokenRes = await fetch("https://turn14.data4autos.com/v1/auth/token", {
// method: "POST",
// headers: { "Content-Type": "application/json" },
// body: JSON.stringify({
// grant_type: "client_credentials",
// client_id: clientId,
// client_secret: clientSecret,
// }),
// });
// tokenData = await tokenRes.json();
// if (!tokenRes.ok) {
// throw new Error(tokenData.error || "Failed to fetch Turn14 token");
// }
// } catch (err) {
// return json({ success: false, error: err.message });
// }
// // upsert as Shopify metafield
// const creds = {
// clientId,
// clientSecret,
// accessToken: tokenData.access_token,
// expiresAt: new Date(Date.now() + 3600 * 1000).toISOString(),
// };
// const mutation = `
// mutation {
// metafieldsSet(metafields: [{
// ownerId: "${shopId}",
// namespace: "turn14",
// key: "credentials",
// type: "json",
// value: "${JSON.stringify(creds).replace(/"/g, '\\"')}"
// }]) {
// userErrors { message }
// }
// }
// `;
// const saveRes = await admin.graphql(mutation);
// const saveJson = await saveRes.json();
// const errs = saveJson.data.metafieldsSet.userErrors;
// if (errs.length) {
// return json({ success: false, error: errs[0].message });
// }
// return json({ success: true, creds });
// };
export const action = async ({ request }) => {
const formData = await request.formData();
const { admin } = await authenticate.admin(request);
// ——— Turn14 token exchange ———
const clientId = formData.get("client_id");
const clientSecret = formData.get("client_secret");
const shopResp = await admin.graphql(`{ shop { id name } }`);
const shopJson = await shopResp.json();
const shopId = shopJson.data.shop.id;
const shopName = shopJson.data.shop.name;
let tokenData;
try {
const tokenRes = await fetch("https://turn14.data4autos.com/v1/auth/token", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
grant_type: "client_credentials",
client_id: clientId,
client_secret: clientSecret,
}),
});
tokenData = await tokenRes.json();
if (!tokenRes.ok) {
throw new Error(tokenData.error || "Failed to fetch Turn14 token");
}
} catch (err) {
return json({ success: false, error: err.message });
}
// ——— Upsert to Shopify metafield ———
const creds = {
clientId,
clientSecret,
accessToken: tokenData.access_token,
expiresAt: new Date(Date.now() + 3600 * 1000).toISOString(),
};
const mutation = `
mutation {
metafieldsSet(metafields: [{
ownerId: "${shopId}",
namespace: "turn14",
key: "credentials",
type: "json",
value: "${JSON.stringify(creds).replace(/"/g, '\\"')}"
}]) {
userErrors { message }
}
}
`;
const saveRes = await admin.graphql(mutation);
const saveJson = await saveRes.json();
const errs = saveJson.data.metafieldsSet.userErrors;
if (errs.length) {
return json({ success: false, error: errs[0].message });
}
// ——— Build the Shopify OAuth URL and return it ———
const stateNonce = Math.random().toString(36).slice(2);
const installUrl =
`https://${shopName}.myshopify.com/admin/oauth/authorize` +
`?client_id=${CLIENT_ID}` +
`&scope=${SCOPES}` +
`&redirect_uri=${encodeURIComponent(REDIRECT_URI)}` +
`&state=${stateNonce}`
//+ `&grant_options%5B%5D=per-user`;
return json({
success: true,
confirmationUrl: installUrl,
});
};
export default function StoreCredentials() {
const { shopName, shopId, savedCreds } = useLoaderData();
const actionData = useActionData();
useEffect(() => {
if (actionData?.confirmationUrl) {
window.open(actionData.confirmationUrl, "_blank", "noopener,noreferrer");
}
}, [actionData?.confirmationUrl]);
const [clientId, setClientId] = useState(actionData?.creds?.clientId || savedCreds.clientId || "");
const [clientSecret, setClientSecret] = useState(actionData?.creds?.clientSecret || savedCreds.clientSecret || "");
const connected = actionData?.success || Boolean(savedCreds.accessToken);
return (
<Page >
<TitleBar title="Turn14 & Shopify Connect" />
<div style={{ display: "flex", justifyContent: "center", textAlign: "center", paddingBottom: "20px" }}>
<Text as="h1" variant="headingLg">
Data4Autos Turn14 Integration
</Text>
</div>
<Layout>
<Layout.Section>
<div style={{ display: "flex", alignItems: "center", justifyContent: "center" }}>
<Box maxWidth="450px" width="100%" marginInline="auto" >
<Card sectioned padding="600">
<BlockStack gap="400">
<TextContainer spacing="tight">
<Text variant="headingLg" align="center" fontWeight="medium">Shop: {shopName}</Text>
</TextContainer>
{/* —— TURN14 FORM —— */}
<Form method="post">
<BlockStack gap="400" >
<BlockStack gap="200">
<input type="hidden" name="shop_name" value={shopName} />
<TextField
label="Turn14 Client ID"
name="client_id"
value={clientId}
onChange={setClientId}
autoComplete="off"
requiredIndicator
padding="200"
/>
</BlockStack>
<BlockStack gap="200">
<TextField
label="Turn14 Client Secret"
name="client_secret"
value={clientSecret}
onChange={setClientSecret}
autoComplete="off"
requiredIndicator
padding="200"
/>
</BlockStack>
<BlockStack gap="200">
<Button submit primary size="large"
variant="primary">
Connect Turn14
</Button>
</BlockStack>
</BlockStack>
</Form>
</BlockStack>
{actionData?.error && (
<TextContainer spacing="tight" style={{ marginTop: "1rem" }}>
<InlineError message={actionData.error} fieldID="client_id" />
</TextContainer>
)}
{connected && (
<TextContainer spacing="tight" style={{ marginTop: "1.5rem" }}>
<p style={{ color: "green", paddingTop: "5px" }}> Turn14 connected successfully!</p>
{/* —— SHOPIFY INSTALL FORM —— */}
{/* <Form method="post">
<input type="hidden" name="shop_name" value={shopName} />
<input type="hidden" name="install_shopify" value="1" />
<div style={{ marginTop: "1rem" }}>
<Button submit primary>
Connect to Shopify
</Button>
</div>
</Form> */}
</TextContainer>
)}
</Card>
</Box>
</div>
</Layout.Section>
</Layout >
</Page >
);
}