App Installation
Once you click the install button in our DB Wishlist app page in the app store, you will be redirected to get the permission prior to installation. If you agree to give the permission, you can click on the install button.
Setup Guide
Online Store
When you are done installing, you will be redirected to the main page. If you are maintaining There we have provided a quick guide to set up the app for ready to use in a quick manner. Once you follow these steps, you can have the app featured without any hesitation.
Step 1
We have provided default settings for you. However, you can edit in the settings page as you prefer.
Step 2
You have to enable the app main widget embedded block in the theme editor. You will be directed to the theme editor by clicking on the button.
Step 3
Finally you have to enable the inline button widget in the product page. You will be directed to the theme editor by clicking on the button.
Hydrogen Store
Our app supports Hydrogen stores as well. Setting up is a bit different than for online stores. We have provided you the UI react component for you via NPM. The implementation is as follows.
Step 1
First install the app from the app store.
Step 2
Since the Hydrogen projects are based on react in Hydrogen framework, we have created an app UI component which has to be installed via NPM to the Hydrogen project base.
npm i db-wishlist-hydrogen
Step 3
First and foremost, let’s implement the logic and the UI component in the root.tsx file. In the root.tsx file, you have to implement the following functions.
async function loadWishlistSettings({context}: LoaderFunctionArgs) {
const {storefront} = context;
const wishlistSettings = await storefront.query(METAOBJECT_QUERY, {
variables: {
type: "devbranch_wishilist_settings",
first: 10
},
});
const wishlistSettingsFields = wishlistSettings.metaobjects.edges[0].node.fields;
return convertToWishlistSettings(wishlistSettingsFields);
}
function convertToWishlistSettings(metaobject: any) {
return {
wishlistButtonSettings: {
buttonStyle: metaobject.find((field: { key: string }) => field.key === 'wishlist_button_style')?.value || '',
showSocialCount: metaobject.find((field: { key: string }) => field.key === 'wishlist_show_social_count')?.value === 'true' ? true : false as boolean,
iconStyle: metaobject.find((field: { key: string }) => field.key === 'wishlist_icon_style')?.value || '',
beforeText: metaobject.find((field: { key: string }) => field.key === 'before_wishlisting_text')?.value || '',
beforeBackgroundColor: metaobject.find((field: { key: string }) => field.key === 'before_wishlisting_background_color')?.value || '',
beforeTextColor: metaobject.find((field: { key: string }) => field.key === 'before_wishlisting_text_color')?.value || '',
afterText: metaobject.find((field: { key: string }) => field.key === 'after_wishlisting_text')?.value || '',
afterBackgroundColor: metaobject.find((field: { key: string }) => field.key === 'after_wishlisting_background_color')?.value || '',
afterTextColor: metaobject.find((field: { key: string }) => field.key === 'after_wishlisting_text_color')?.value || '',
} as WishlistButtonSettingsType,
launchPointSettings: {
launchPoint: metaobject.find((field: { key: string }) => field.key === 'launch_point')?.value as LaunchPoint,
isNumberOfItemsDisplay: metaobject.find((field: { key: string }) => field.key === 'launch_point_is_number_of_items_display')?.value === "true" ? true : false as boolean,
floatingButtonPosition: metaobject.find((field: { key: string }) => field.key === 'launch_point_floating_button_position')?.value as FloatingButtonPosition,
isFloatingButtonTextDisplay: metaobject.find((field: { key: string }) => field.key === 'launch_point_is_floating_button_text_display')?.value === "true" ? true : false as boolean,
floatingButtonText: metaobject.find((field: { key: string }) => field.key === 'launch_point_floating_button_text')?.value || '',
floatingButtonBackgroundColor: metaobject.find((field: { key: string }) => field.key === 'launch_point_floating_button_background_color')?.value || '',
floatingButtonTextColor: metaobject.find((field: { key: string }) => field.key === 'launch_point_floating_button_text_color')?.value || '',
} as LaunchPointSettingsType,
wishlistPageSettings: {
title: metaobject.find((field: { key: string }) => field.key === 'wishlist_page_name')?.value || '',
backgroundColor: metaobject.find((field: { key: string }) => field.key === 'wishlist_page_background_color')?.value || '',
textColor: metaobject.find((field: { key: string }) => field.key === 'wishlist_page_text_color')?.value || '',
showProductCardBorder: metaobject.find((field: { key: string }) => field.key === 'wishlist_page_show_product_card_border')?.value === "true" ? true : false as boolean,
wishlistPageAddToCartButtonSettings: {
backgroundColor: metaobject.find((field: { key: string }) => field.key === 'wishlist_page_add_to_cart_button_background_color')?.value || '',
textColor: metaobject.find((field: { key: string }) => field.key === 'wishlist_page_add_to_cart_button_text_color')?.value || '',
borderRadius: metaobject.find((field: { key: string }) => field.key === 'wishlist_page_add_to_cart_button_border_radius')?.value || '',
textBeforeClick: metaobject.find((field: { key: string }) => field.key === 'wishlist_page_add_to_cart_button_before_text')?.value || '',
textAfterClick: metaobject.find((field: { key: string }) => field.key === 'wishlist_page_add_to_cart_button_after_text')?.value || '',
} as WishlistPageAddToCartButtonSettingsType,
} as WishlistPageSettingsType,
wishlistNudgeSettings: {
showNudge: metaobject.find((field: { key: string }) => field.key === 'wishlist_nudge_show')?.value === "true" ? true : false as boolean,
isIconDisplay: metaobject.find((field: { key: string }) => field.key === 'wishlist_nudge_icon_display')?.value === "true" ? true : false as boolean,
buttonText: metaobject.find((field: { key: string }) => field.key === 'wishlist_nudge_button_text')?.value || '',
buttonBackgroundColor: metaobject.find((field: { key: string }) => field.key === 'wishlist_nudge_button_background_color')?.value || '',
buttonTextColor: metaobject.find((field: { key: string }) => field.key === 'wishlist_nudge_button_text_color')?.value || '',
bodyText: metaobject.find((field: { key: string }) => field.key === 'wishlist_nudge_body_text')?.value || '',
} as WishlistNudgeSettingsType
} as WishlistSettingsType;
}
async function loadWishlistData(email: string, shop: string) {
const response = await fetch(
`${DB_WISHLIST_APP_URL}/api/v1/hydrogen-api?service=get&email=shehan@devbranch.net&shop=quickstart-f38de296.myshopify.com`,
{
headers: {
"Content-Type": "application/json",
},
}
);
const responseData = await response.json();
return responseData.result;
}
Then call them in the root loader function and return the wishlistDataSettings and wishlistData.
export async function loader(args: LoaderFunctionArgs) {
// Start fetching non-critical data without blocking time to first byte
const deferredData = loadDeferredData(args);
// Await the critical data required to render initial state of the page
const criticalData = await loadCriticalData(args);
const {storefront, env} = args.context;
const wishlistSettings = await loadWishlistSettings(args);
const wishlistData = await loadWishlistData('shehan@devbranch.net', 'quickstart-f38de296.myshopify.com');
return defer({
...deferredData,
...criticalData,
publicStoreDomain: env.PUBLIC_STORE_DOMAIN,
shop: getShopAnalytics({
storefront,
publicStorefrontId: env.PUBLIC_STOREFRONT_ID,
}),
consent: {
checkoutDomain: env.PUBLIC_CHECKOUT_DOMAIN,
storefrontAccessToken: env.PUBLIC_STOREFRONT_API_TOKEN,
withPrivacyBanner: true,
// localize the privacy banner
country: args.context.storefront.i18n.country,
language: args.context.storefront.i18n.language,
},
wishlistSettings,
wishlistData
});
}
Step 4
Now implement the action logic in the action function.
export async function action({request}: ActionFunctionArgs) {
const formData = await request.formData();
let responseWishlistDeleteData = {
status: "",
message: "",
};
try {
if (formData.has("wishlistDeleteId")) {
const parsedData = formData.get("wishlistDeleteId");
const wishlistDeleteId = JSON.parse(parsedData);
const response = await fetch(
`${DB_WISHLIST_APP_URL}/api/v1/hydrogen-api?service=delete&id=${wishlistDeleteId.itemId}&email=shehan@devbranch.net&shop=quickstart-f38de296.myshopify.com`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
id: wishlistDeleteId
}),
}
);
const responseData = await response.json();
if (response.ok) {
responseWishlistDeleteData = {
status: "success",
message: responseData.message || "Item deleted successfully",
};
} else {
responseWishlistDeleteData = {
status: "error",
message: responseData.message || "Failed to delete the item",
};
}
}
} catch (error) {
console.log("Error: ", error);
responseWishlistDeleteData = {
status: "error",
message: error.message || "An error occurred while deleting the item",
};
}
return json({ responseWishlistDeleteData });
}
Step 5
Apply the WishlistPage UI component in the Layout function.
export function Layout({children}: {children?: React.ReactNode}) {
const nonce = useNonce();
const data = useRouteLoaderData<RootLoader>('root');
return (
<html lang="en">
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<Meta />
<Links />
</head>
<body>
{data ? (
<Analytics.Provider
cart={data.cart}
shop={data.shop}
consent={data.consent}
>
<PageLayout {...data}>{children}</PageLayout>
<WishlistPage
wishlist={data.wishlistData}
settings={data.wishlistSettings}
/>
</Analytics.Provider>
) : (
children
)}
<ScrollRestoration nonce={nonce} />
<Scripts nonce={nonce} />
</body>
</html>
);
}
Step 6
Now we have to implement backend logic in the products.$handle.tsx file.
async function loadWishlistMetrics(product) {
const productId = product.id.replace("gid://shopify/Product/", "");
try {
const response = await fetch(
`${DB_WISHLIST_APP_URL}/api/v1/hydrogen-api?service=count&productId=${productId}&shop=quickstart-f38de296.myshopify.com`,
{
headers: {
"Content-Type": "application/json",
},
}
);
const responseData = await response.json();
if (response.ok) {
return responseData.result;
}
} catch (error) {
console.log("Error: ", error);
return null;
}
}
Then call the function in the loader function and return them.
export async function loader(args: LoaderFunctionArgs) {
// Start fetching non-critical data without blocking time to first byte
const deferredData = loadDeferredData(args);
// Await the critical data required to render initial state of the page
const criticalData = await loadCriticalData(args);
const { product } = criticalData;
const wishMetricsData = await loadWishlistMetrics(product);
return defer({...deferredData, ...criticalData, ...wishMetricsData});
}
Step 7
Now you can implement the UI component inside the ProductForm function.
<AddToWishlistButton
product={product}
selectedVariant={selectedVariant}
email={"email@example.com"}
/>
Step 8
You may have to allow the link of our base app under content security policy – https://db-wishlist-app-2426a7cce9e6.herokuapp.com/