npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@bogos/freegifts-hydrogen

v0.1.0

Published

BOGOS: Free gift & Buy X Get Y - Hydrogen

Downloads

6

Readme

BOGOS: Freegifts Hydrogen App

Requirements

Installation

Step 1: Getting started

  1. Navigate to your working directory.

    cd <directory>
  2. Install BOGOS: Free gift package

    npm i @bogos/freegifts-hydrogen

Step 2: Integration

  1. Open file containing event to render cart component (This event should be rendered on every single page), and add this basic integration:

    import {BOGOS} from '@bogos/freegifts-hydrogen';
    ...
    <Await resolve={data.cart}>
        {(cart) => (
            <>
                <BOGOS
                    cart={cart}
                    customerAccessToken={CUSTOMER_ACCESS_TOKEN}
    
                    publicStoreDomain={PUBLIC_STORE_DOMAIN}
                    publicStorefrontApiToken={PUBLIC_STORE_FRONT_API_TOKEN}
                    publicStorefrontApiVersion={PUBLIC_STOREFRONT_API_VERSION}
                    bogosAccessToken={BOGOS_ACCESS_TOKEN}
                />
            ...
            </>
        )}
    </Await>
    ...
    • Details of BOGOS component properties
    import { Cart, Customer } from "@shopify/hydrogen/storefront-api-types";
    
    interface BOGOSProps {
        cart: Cart;
        customerAccessToken?: string;
        publicStoreDomain: string;
        publicStorefrontApiToken: string;
        publicStorefrontApiVersion: string;
        bogosAccessToken: string;
    
        customer?: Customer;
        others?: OthersSetting;
        renderCart?: Function;
    }
    
  2. Find Checkout button, and add bogosCheckCartValid function to prevent gift invalid after checkout.

    import {bogosCheckCartValid} from '@bogos/freegifts-hydrogen';
    
    async function {your_function_checkout} (args) {
        ...
        await bogosCheckCartValid({});
        ...
    }
    • Details of bogosCheckCartValid function
    export type BogosCheckCartValidParams = {
        cart?: Cart | FGObject; /* If you don't want to fetch catch again */
        reloadIfInvalid?: boolean; /* Default: true. You don't want to reload page if invalid */
        callback?: (isValidCart: boolean) => void; /* If you want to do something after BOGOS check */
    };
    
    export declare const bogosCheckCartValid: (params: BogosCheckCartValidParams) => Promise<boolean>;

Step 3: Details of Other settings for BOGOS

export type OthersSetting = {
    isPopUp?: boolean;
    customGiftImgSize?: string;
    enableToastAdded?: boolean;
    scaTextNotifySuccess?: string;
    localesFormat?: string;
    currencyCode?: string;
    currencyRate?: number;
    useRateForOffer?: boolean;
    disableBogosAttrCart?: boolean;
    disableReloadCartUpdated?: boolean;
    renderCart?: Function;
    useCart?: boolean;
    useCustomer?: boolean;
    prefixProduct?: string;
    numberOrders?: number;
    toFixed?: number;
    debug?: boolean;
};

Step 4: Integration customize

  1. Gift Icon

    • Details of BOGOSGiftIcon
    type GiftItem = {
        id: number;
        discount_type: 'percentage' | 'fixed_amount';
        discount_value: number;
        original_price: number;  // Original price - price before discount
        price: number;           // Discount price - price after discount
        title: string;
        thumbnail?: string;
    };
    
    type GiftProduct = {
        id: number;
        title: string;
        handle: string;
        thumbnail?: string;
        belongs_to_offer: string;
        variants: GiftItem[];
    };
       
    type FilterVariant = {
        id: string | number;
        title: string;
        price?: string | number;
    };
    
    type ProductInfo = {
        id: string | number;
        handle: string;
        title: string;
        price_max?: string | number;
        collections?: {
            id: string | number;
            title?: string;
        }[];
        product_type?: string;
        vendor?: string;
        variants?: FilterVariant[];
    };
    
    interface BOGOSGiftIconProps {
        product: ProductInfo;
        selectedVariant?: FilterVariant;
        enableForAllCondition?: boolean; /* Default false - only use with specific product condition */
        page: "collection" | "product";
    };
    
    /* Example Collection page or page has list products */
    <div ...>
        ...
        {products.map(product => (
            <div>
                ...
                <div style={{position: 'relative'}}>
                    ...
                    <BOGOSGiftIcon
                        product={{
                            id: product.id,
                            handle: product.handle,
                            title: product.title,
                        }}
                        page="collection"
                    />
                    ...
                </div>
                ...
            </div>
        ))}
        ...
    </div>
       
    /* Example Product page */
    <div ...> 
        ...
        <h1 style={{width: 'fit-content', position: 'relative'}}>
            {title}
            <BOGOSGiftIcon
                product={{
                    id: product.id,
                    handle: product.handle,
                    title: product.title,
                }}
                page="product"
            />
        </h1>
        ...
    </div>
    • Gift-icon customization (Use it in case you want to handle the customization of gift icon instead of using BOGOS default component)
    /* Other type check above */
    export interface BogosCheckProductHasGiftsParams {
        product: ProductInfo;
        selectedVariant?: FilterVariant;
        enableForAllCondition?: boolean;
    }
    
    /* Return the gift product associated with purchasing the product from product page */
    export declare const bogosCheckProductHasGifts: async ({ 
        product, 
        selectedVariant, 
        enableForAllCondition, 
    }: BogosCheckProductHasGiftsParams) => GiftProduct[];
    
    export const GiftIcon = (props: Props) => {
        /* States */
        const [gifts, setGifts] = useState<GiftProduct[]>([]);
    
        /* Vars */
        const event = "fg-data:loaded";
    
        const handleGiftIcon = async (e?: Event) => {
            try {
                setGifts(await bogosCheckProductHasGifts(props));
            } catch (e) {}
        };
    
        useEffect(() => {
            handleGiftIcon();
        }, [props.selectedVariant?.id]);
    
        useEffect(() => {
            /* This event will run on the next render */
            handleGiftIcon();
            /* This event is used after fetching BOGOS' data to get information of gift icon (only run once) */
            document.addEventListener(event, handleGiftIcon);
    
            return () => {
                document.removeEventListener(event, handleGiftIcon);
            };
        }, []);
    
        const renderGiftIcon = useCallback(() => {
            const gift_icon = typeof window !== "undefined" &&
                window?.FGSECOMAPP?.appearance?.gift_icon?.product_page?.gift_icon;
    
            /* Check if gift icon can be shown or not */
            if (gifts?.length > 0 && gift_icon && gift_icon?.status) {
                const giftIcon = window.FGSECOMAPP?.giftIcon; // or other icon you want to show
            }
               
            // render gift icons
        }, [gifts]);
    
        return <Fragment>{renderGiftIcon()}</Fragment>;
    };
  2. Gift thumbnail

    • Details of BOGOSGiftThumbnail
    /* Other type check above */
       
    interface Props {
        product: ProductInfo;
        selectedVariant?: FilterVariant;
        enableForAllCondition?: boolean;
        numberGiftsThumbnail?: number; /* Default: 3. Number of gift images can be shown per thumbnail */
        arrows?: boolean;
        dots?: boolean;
        prefixProduct?: string; /* Default: "/products/". Path name product */
    }
    
    /* Example Product page */
    <div ...> 
        ...
        <BOGOSGiftThumbnail
            product={{
                id: product.id,
                handle: product.handle,
                title: product.title,
            }}
            arrows={false}
        />
        {{ add_to_cart_btn }}
        ...
    </div>
    • Gift-thumbnail customization (Use it in case you want to handle the customization of gift thumbnail instead of using BOGOS default component)
    /* Other type check above */
    export interface BogosCheckProductHasGiftsParams {
        product: ProductInfo;
        selectedVariant?: FilterVariant;
        enableForAllCondition?: boolean;
    }
    
    /* Return the gift product associated with purchasing the product from product page */
    export declare const bogosCheckProductHasGifts: async ({ 
        product, 
        selectedVariant, 
        enableForAllCondition, 
    }: BogosCheckProductHasGiftsParams) => GiftProduct[];
    
    export const GiftThumbnail = (props: Props) => {
        /* States */
        const [gifts, setGifts] = useState<GiftProduct[]>([]);
    
        /* Vars */
        const event = "fg-data:loaded";
    
        const handleGiftThumbnail = (e?: Event) => {
            try {
                const gifts = await bogosCheckProductHasGifts(props);
                renderGiftThumbnail(gifts);
            } catch (e) {}
        };
    
        useEffect(() => {
            handleGiftThumbnail();
        }, [props.selectedVariant?.id]);
    
        useEffect(() => {
            /* This event will run on the next render */
            handleGiftThumbnail();
            /* This event is used after fetching BOGOS' data to get information of gift thumbnail (only run once) */
            document.addEventListener(event, handleGiftThumbnail);
    
            return () => {
                document.removeEventListener(event, handleGiftThumbnail);
            };
        }, []);
    
        const renderGiftThumbnail = useCallback(() => {
            const gift_thumbnail = typeof window !== "undefined" &&
                window?.FGSECOMAPP?.appearance?.gift_icon?.product_page?.gift_thumbnail;
                   
            /* Check if gift thumbnail can be shown or not */
            if (gifts?.length > 0 && gift_thumbnail && gift_thumbnail?.status) {
                   
            }
               
            // render gift thumbnail
        }, [gifts]);
    
        return <Fragment>{renderGiftThumbnail()}</Fragment>;
    };
  3. Cart message

    • Details of BOGOSCartMessage
    /* Other type check above */
       
    interface Props {
        delay?: number; /* Default: 3000 (ms). Time delay between auto scroll cart message */
        toFixed?: number; /* Default: 2. Number after '.' E.g: 100.00*/
    }
    
    /* Example */
    <div className={className}>
        <BOGOSCartMessage
            delay={5000}
        />
    
        <CartEmpty ... />
        <CartDetails ... />
    </div>
    • Cart message customization (Use it in case you want to handle the customization of cart message instead of using BOGOS default component)
    /* Other type check above */
    export interface BOGOSCartMessageParams {
        toFixed?: number;
    }
    
    /* return cart message can be shown */
    export declare const bogosCheckCartMessage: ({ toFixed, }: BOGOSCartMessageParams) => string[]; 
    
    export const CartMessage = (props: Props) => {
        /* States */
        const [msgs, setMsgs] = useState<{value: string}[]>([]);
    
        /* Vars */
        const event = "fg-cart:end-process";
    
        const handleCartMsg = (e?: Event) => {
            try {
            const msgs = e
                ? (e as CustomEvent)?.detail?.data
                : (typeof window !== "undefined" && window?.FGSECOMAPP?.cart_message) ?? [];
                setMsgs(msgs);
            } catch (e) {}
        };
    
        useEffect(() => {
            /* This event will run on the next render */
            handleGiftCartMsg();
            /* This event is used after fetching BOGOS' data to get information of cart message (only run once) */
            document.addEventListener(event, handleGiftCartMsg);
    
            return () => {
                document.removeEventListener(event, handleGiftCartMsg);
            };
        }, []);
    
        const renderCartMsg = useCallback(() => {
            const promotion_message = typeof window !== "undefined" &&
                window?.FGSECOMAPP?.appearance?.promotion_message;
         
            /* Check if cart message can be shown or not */
            if (
                messages?.length > 0 &&
                promotion_message &&
                promotion_message?.show_on_cart_page
            ) {
               
            }
               
            // render gift thumbnail
        }, [msgs]);
    
        return <Fragment>{renderCartMsg()}</Fragment>;
    };

Step 5: Other integration for BOGOS: Free Gift

  1. Hide gift product (cloned product) from your headless store

    • If you use products query, you should add : query: "tag_not:bogos-gift"
    products (
        ...,
        query: "tag_not:bogos-gift"
    ) {
    ...
    }
    • For collection and product page, you can import bogosCheckGift and use returned value to skip gift products or replace to other pages
    import {bogosCheckGift} from '@bogos/freegifts-hydrogen';
    • Details of bogosCheckGift
    export type ProductObject = {
        handle?: string;
        tags?: string[];
    };
    
    /* item can be product handle */
    export declare const bogosCheckGift: (item: string | ProductObject) => boolean;
  2. Customize gift popup/slider

    Change isPopup to true and listen event:

    type GiftItem = {
        id: number;
        discount_type: 'percentage' | 'fixed_amount';
        discount_value: number;
        original_price: number;  // Original price - price before discount
        price: number;           // Discount price - price after discount
        title: string;
        thumbnail?: string;
    };
    
    type GiftProduct = {
        id: number;
        title: string;
        handle: string;
        thumbnail?: string;
        belongs_to_offer: string;
        variants: GiftItem[];
    };
    
    export declare const bogosProcessAddGift: (variantID: number | string, quantity: number, offerId: string) => void;
    
    document.addEventListener("fg-gifts:show-slider", (e) => {
        console.log((e as CustomEvent).detail.arrGiftShow);
        /* render gift slider with arrGiftShow: GiftProduct[] */
        /* use bogosProcessAddGift when click add to cart from popup to process BOGOS */
    });
       
  3. Details of other event listeners

    • fg-gifts:updated
    document.addEventListener("fg-gifts:updated", (e) => {
        /* use this function to re-render cart with disableReloadCartUpdated: true */
        console.log((e as CustomEvent).detail);
        /* render gift slider with detail: { 
            is_auto?: boolean,
            popup?: gift can be shown 
            add?: gift can be added to cart
            update?: gift already in cart need to update
        } */
    });
    • fg-cart:auto-updated
    document.addEventListener("fg-gifts:updated", (e) => {
        /* use this function to re-render cart with disableReloadCartUpdated: true when gifts are auto updated (add/remove) */
        console.log((e as CustomEvent).detail);
        /* detail: { 
            popup?: gift can be shown 
            add?: gift can be added to cart
            update?: gift already in cart need to update
        } */
    });
    document.addEventListener("fg-gifts:added", (e) => {
        /* use this function to re-render cart with disableReloadCartUpdated: true */
        console.log((e as CustomEvent).detail);
        /* render gift slider with detail: { 
            is_auto?: boolean,
            gift?: {
                variant_id,
                quantity
            } gift added from popup
        } */
    });
  4. Some features is not available on this version yet

    • Stop the offer when the gift is out of stock
    • Draft-Order API

Notice

Publish gift/cloned product to Headless channel (or other channels you want BOGOS package to work with)

  • After creating/editing offer, please make sure that the gift/cloned product is available on Headless channel in order for the offer to work.

Support

BOGOS: Free Gift - [email protected]

OR

You can contact our live-chat supporters in app on Shopify Admin.