180 lines
6.4 KiB
JavaScript
180 lines
6.4 KiB
JavaScript
import { authenticate, unauthenticated } from "../shopify.server";
|
|
|
|
const jsonResponse = (data, status = 200) => {
|
|
return new Response(JSON.stringify(data), {
|
|
status,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"Access-Control-Allow-Origin": "*",
|
|
"Cache-Control": "no-store",
|
|
},
|
|
});
|
|
};
|
|
|
|
async function ensureDefinition(admin) {
|
|
console.log(">>> [DEBUG] Triggering Metaobject Definition Creation...");
|
|
const mutation = `#graphql
|
|
mutation CreateMetaobjectDefinition($definition: MetaobjectDefinitionCreateInput!) {
|
|
metaobjectDefinitionCreate(definition: $definition) {
|
|
metaobjectDefinition { type }
|
|
userErrors { field message }
|
|
}
|
|
}
|
|
`;
|
|
|
|
const variables = {
|
|
definition: {
|
|
name: "Product Review",
|
|
type: "custom_product_review",
|
|
access: { storefront: "PUBLIC_READ" },
|
|
capabilities: { publishable: { enabled: true } },
|
|
fieldDefinitions: [
|
|
{ name: "Product ID", key: "product_id", type: "single_line_text_field", required: true },
|
|
{ name: "Customer Name", key: "customer_name", type: "single_line_text_field" },
|
|
{ name: "Review Content", key: "content", type: "multi_line_text_field" },
|
|
{ name: "Rating", key: "rating", type: "single_line_text_field" }
|
|
]
|
|
}
|
|
};
|
|
|
|
const response = await admin.graphql(mutation, { variables });
|
|
const result = await response.json();
|
|
console.log(">>> [DEBUG] Creation Result:", JSON.stringify(result));
|
|
return result;
|
|
}
|
|
|
|
export const loader = async ({ request }) => {
|
|
try {
|
|
const { admin, session } = await authenticate.public.appProxy(request);
|
|
const url = new URL(request.url);
|
|
const productId = url.searchParams.get("productId");
|
|
|
|
if (!productId) return jsonResponse([]);
|
|
|
|
const query = `#graphql
|
|
query getReviews($query: String!) {
|
|
metaobjects(first: 50, type: "custom_product_review", query: $query) {
|
|
edges { node { fields { key value } } }
|
|
}
|
|
}
|
|
`;
|
|
|
|
const response = await admin.graphql(query, {
|
|
variables: { query: `product_id:${productId}` },
|
|
});
|
|
|
|
const data = await response.json();
|
|
|
|
// Check for "No definition" error
|
|
const isMissing = data.errors?.some(e => e.message.toLowerCase().includes("metaobject definition")) || !data.data?.metaobjects;
|
|
if (isMissing) {
|
|
console.log(">>> [DEBUG] Loader: Definition missing. Attempting to create...");
|
|
await ensureDefinition(admin);
|
|
return jsonResponse([]);
|
|
}
|
|
|
|
const reviews = (data.data?.metaobjects?.edges || []).map((edge) => {
|
|
const fields = {};
|
|
edge.node.fields.forEach((f) => { fields[f.key] = f.value; });
|
|
return {
|
|
name: fields.customer_name || "Anonymous",
|
|
review: fields.content || "",
|
|
rating: fields.rating || "5",
|
|
};
|
|
});
|
|
|
|
return jsonResponse(reviews);
|
|
} catch (err) {
|
|
console.error(">>> [ERROR] Loader:", err.message);
|
|
return jsonResponse([]);
|
|
}
|
|
};
|
|
|
|
export const action = async ({ request }) => {
|
|
try {
|
|
console.log(">>> [DEBUG] Action: Review Submission Started");
|
|
const { admin, session } = await authenticate.public.appProxy(request);
|
|
const url = new URL(request.url);
|
|
const customerId = url.searchParams.get("logged_in_customer_id");
|
|
|
|
if (!customerId) return jsonResponse({ error: "Please log in to leave a review." });
|
|
|
|
const formData = await request.formData();
|
|
const productId = formData.get("productId");
|
|
const name = formData.get("name");
|
|
const review = formData.get("review");
|
|
|
|
// 1. Purchase Check
|
|
const orderQuery = `#graphql
|
|
query getOrders($query: String!) {
|
|
orders(first: 10, query: $query) {
|
|
edges { node { lineItems(first: 20) { edges { node { product { id } } } } } }
|
|
}
|
|
}
|
|
`;
|
|
|
|
const orderResponse = await admin.graphql(orderQuery, {
|
|
variables: { query: `customer_id:${customerId}` }
|
|
});
|
|
|
|
const orderData = await orderResponse.json();
|
|
const hasPurchased = (orderData.data?.orders?.edges || []).some(o =>
|
|
o.node.lineItems.edges.some(i => i.node.product?.id?.includes(productId))
|
|
);
|
|
|
|
// if (!hasPurchased) {
|
|
// console.log(">>> [DEBUG] Action: No purchase history found for Customer ID:", customerId);
|
|
// return jsonResponse({ error: "Only verified buyers can leave a review. (Note: It may take a few minutes for new orders to sync)" });
|
|
// }
|
|
|
|
// 2. Save Review
|
|
const saveMutation = `#graphql
|
|
mutation create($m: MetaobjectCreateInput!) { metaobjectCreate(metaobject: $m) { metaobject { id } userErrors { field message } } }
|
|
`;
|
|
|
|
const saveResponse = await admin.graphql(saveMutation, {
|
|
variables: {
|
|
m: {
|
|
type: "custom_product_review",
|
|
fields: [
|
|
{ key: "product_id", value: String(productId) },
|
|
{ key: "customer_name", value: String(name) },
|
|
{ key: "content", value: String(review) },
|
|
{ key: "rating", value: "5" }
|
|
]
|
|
}
|
|
}
|
|
});
|
|
|
|
const result = await saveResponse.json();
|
|
console.log(">>> [DEBUG] Save Result:", JSON.stringify(result));
|
|
|
|
// Check for "No definition" error
|
|
const userErrors = result.data?.metaobjectCreate?.userErrors || [];
|
|
const isMissing = result.errors?.some(e => e.message.toLowerCase().includes("metaobject definition")) ||
|
|
userErrors.some(e => e.message.toLowerCase().includes("metaobject definition")) ||
|
|
result.data?.metaobjectCreate === null;
|
|
|
|
if (isMissing) {
|
|
console.log(">>> [DEBUG] Action: Definition missing. Creating structure...");
|
|
const createResult = await ensureDefinition(admin);
|
|
const creationError = createResult.data?.metaobjectDefinitionCreate?.userErrors?.[0]?.message;
|
|
|
|
if (creationError && !creationError.includes("already exists")) {
|
|
return jsonResponse({ error: `Database Creation Error: ${creationError}` });
|
|
}
|
|
return jsonResponse({ error: "SUCCESS: Database structure created! Please click Submit Review one last time to save your review." });
|
|
}
|
|
|
|
const errors = result.data?.metaobjectCreate?.userErrors;
|
|
if (errors && errors.length > 0) {
|
|
return jsonResponse({ error: errors[0].message });
|
|
}
|
|
|
|
console.log(">>> [DEBUG] Action: Review Saved Successfully!");
|
|
return jsonResponse({ success: true });
|
|
} catch (err) {
|
|
console.error(">>> [ERROR] Action Exception:", err.message);
|
|
return jsonResponse({ error: "Connection issue. Please refresh the page and try again." });
|
|
}
|
|
}; |