File extension customer page
import '@shopify/ui-extensions/preact';
import {render} from 'preact';
import {useEffect, useState} from 'preact/hooks';
export default async () => {
render(<FullPageExtension />, document.body);
};
function FullPageExtension() {
const [wishlist, setWishlist] = useState([]);
const [loading, setLoading] = useState(false);
const [removeLoading, setRemoveLoading] = useState({
id: null,
loading: false,
});
async function fetchWishlist() {
setLoading(true);
try {
const token = await shopify.sessionToken.get();
const res = await fetch('/apps/wishlist/api', {
headers: {
Authorization: `Bearer ${token}`,
},
});
const data2 = await res.json();
setWishlist(data2);
const productIds = [
'gid://shopify/Product/7156668629077',
'gid://shopify/Product/7156669775957',
'gid://shopify/Product/7156669546581',
'gid://shopify/Product/7156670300245',
'gid://shopify/Product/7242516856917',
];
const data = await shopify.query(
`query wishlistProducts($ids: [ID!]!) {
nodes(ids: $ids) {
... on Product {
id
title
onlineStoreUrl
handle
priceRange {
minVariantPrice {
amount
currencyCode
}
}
featuredImage {
url
}
}
}
}`,
{
variables: {
ids: productIds,
},
}
);
setLoading(false);
setWishlist(data.data?.nodes || []);
} catch (error) {
setLoading(false);
console.log(error);
}
}
async function deleteWishlistItem(id) {
// Simulate a server request
setRemoveLoading({loading: true, id});
return new Promise((resolve) => {
setTimeout(() => {
// Send a request to your server to delete the wishlist item
setWishlist(wishlist.filter((item) => item.id !== id));
setRemoveLoading({loading: false, id: null});
resolve();
}, 750);
});
}
useEffect(() => {
fetchWishlist();
}, []);
return (
<s-page heading="Wishlist">
{/* <s-button slot="breadcrumb-actions" href="/account">
Повернутися в профіль
</s-button> */}
<s-grid gridTemplateColumns="1fr 1fr 1fr" gap="base">
{!loading &&
wishlist.length > 0 &&
wishlist.map((product) => {
return (
<s-section key={product.id}>
<s-stack direction="block" gap="base" paddingBlockEnd="large">
<s-image src={product.featuredImage.url} />
<s-stack direction="block" gap="small-500">
<s-text color="subdued">{product.title}</s-text>
<s-text type="strong">
{shopify.i18n.formatCurrency(
product.priceRange.minVariantPrice.amount,
{
currency:
product.priceRange.minVariantPrice.currencyCode,
}
)}
</s-text>
</s-stack>
</s-stack>
<s-button slot="primary-action" href={product.onlineStoreUrl}>
View product
</s-button>
<s-button
slot="secondary-actions"
loading={
removeLoading.loading && product.id === removeLoading.id
}
onClick={() => {
deleteWishlistItem(product.id);
}}
>
Remove
</s-button>
</s-section>
);
})}
{!loading && wishlist.length === 0 && (
<s-text>No items in your wishlist.</s-text>
)}
</s-grid>
</s-page>
);
}
When sending the request, I get an error. Development is being done in dev mode via a tunnel.
TypeError: Failed to construct 'Request': Failed to parse URL from /apps/wishlist/api
at Gt.eval [as fetch] (eval at self.addEventListener.once (data:,self.addEventListener('message'%2Ce%3D%3E%7Btry%7Beval(e.data)%7Dcatch(err)%7Bthrow%20new%20Error('ExtensionSandboxError%3A%20'%2Berr.message)%7D%7D%2C%7Bonce%3Atrue%7D)%3B:1:41), <anonymous>:1:170268)
at eval (FullPageExtension.jsx:40:9)
at Generator.next (<anonymous>)
I need to retrieve the products that a user has added to their wishlist.