Skip to content

Instantly share code, notes, and snippets.

@elghorfi
Last active April 20, 2023 13:48
Show Gist options
  • Save elghorfi/8acce46b99f259393844417eace8148e to your computer and use it in GitHub Desktop.
Save elghorfi/8acce46b99f259393844417eace8148e to your computer and use it in GitHub Desktop.
{%- comment -%}
###############################################################################
[No Apps] Fully Customizable Sales Notification
for Shopify — COMPLETELY FREE
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
###############################################################################
# Paypal Me: https://paypal.me/elghorfimed #
# Buy Me A Coffee: #
# https://www.buymeacoffee.com/elghorfi #
###############################################################################
[email protected]
https://elghorfimed.medium.com/2b16c93535a2
###############################################################################
{%- endcomment -%}
<style>
#gf-sales-notification {
position: fixed;
max-width: 500px;
min-width: 350px;
left:0;
bottom:60px;
height: auto;
z-index: 99;
background: {{section.settings.background_color}};
padding: 15px;
margin: 20px;
visibility: hidden;
opacity: 0;
border: 1px solid #ddd;
transition: all 2s ease-in-out;
align-items: center;
gap:15px;
border-radius: {{ section.settings.border_radius }}px;
}
#gf-sales-notification a{
text-decoration: none;
}
#gf-sales-notification.style1 {
display: grid;
grid-template-columns: 120px 1fr;
}
#gf-sales-notification * {
color: {{ section.settings.font_color }};
}
#gf-sales-notification.no-image.style1 {
grid-template-columns: 1fr;
}
#gf-sales-notification.no-image .gf-img-wrapper{
display: none !important;
}
#gf-sales-notification.active,
#gf-sales-notification.customizer{
visibility: visible;
opacity: 1;
}
.gf-close {
{% if section.settings.close_button == false %}
display: none;
opacity: 0;
visibility: hidden;
{% endif %}
position: absolute;
top: 7px;
right: 0;
width: 20px;
height: 20px;
cursor: pointer;
}
.gf-close:hover svg * {
stroke: #111;
}
.gf-close svg{
width: 100%;
height:100%;
}
.gf-close svg *{
stroke: #aaa;
}
#gf-sales-notification.style1 .gf-img-wrapper{
width: 120px;
height: auto;
border-radius: 8px;
background: {{section.settings.image_background}};
padding: 20px 10px;
}
#gf-sales-notification.style1 .gf-img-wrapper img{
border-radius: 8px;
}
.gf-img-wrapper{
display: flex;
align-items: center;
}
#gf-sales-notification.style2 .gf-img-wrapper{
width: 60px;
height: auto;
padding: 0;
}
#gf-sales-notification.style2 .gf-img-wrapper img{
border-radius: 8px;
}
#gf-sales-notification.style2 .gf-info-title-wrapper {
display: flex;
gap: 20px;
align-items: center;
padding: 10px 5px;
background: {{section.settings.image_background}};
border-radius: 5px;
margin-top: 5px;
}
{% unless section.settings.product_name_truncate == "unset" %}
#gf-sales-notification.style2 .gf-info-title {
display: -webkit-box;
-webkit-line-clamp: {{ section.settings.product_name_truncate }};
-webkit-box-orient: vertical;
overflow: hidden;
}
{% endunless %}}
#gf-sales-notification.no-image .gf-img-wrapper{
display: none;
}
.gf-img-wrapper img{
width: 100%;
}
.gf-info-customer{
color: {{ section.settings.customer_font_color }} !important;
{% if section.settings.customer_bold_text %}
font-weight: bold;
{% endif %}
text-transform:{{ section.settings.customer_text_style }};
}
.gf-info-location{
color: {{ section.settings.location_font_color }} !important;
{% if section.settings.location_bold_text %}
font-weight: bold;
{% endif %}
text-transform:{{ section.settings.location_text_style }};
}
.gf-info-title{
color: {{ section.settings.product_name_font_color }} !important;
{% if section.settings.product_name_bold_text %}
font-weight: bold;
{% endif %}
{% if section.settings.product_name_underline %}
text-decoration: underline !important;
{% endif %}
font-size: {{ section.settings.product_name_font_size }}px;
text-transform:{{ section.settings.product_name_text_style }};
}
.gf-info-add-to-cart {
{% if section.settings.add_to_cart_button == false %}
display: none;
{% endif %}
background: {{ section.settings.add_to_cart_background }};
color: {{ section.settings.add_to_cart_color }} !important;
{% if section.settings.add_to_cart_bold_text %}
font-weight: bold;
{% endif %}
{% if section.settings.add_to_cart_uppercase %}
text-transform: uppercase;
{% endif %}
padding: 10px;
font-size: 13px;
cursor: pointer;
border: none;
outline: none;
border-radius: {{section.settings.add_to_cart_border_radius}}px;
float: {{section.settings.button_position}};
{% if section.settings.button_position == "right" %}
margin-top: 25px;
{% else %}
margin-top: 10px;
{% endif %}
}
.gf-info-add-to-cart:hover {
background: {{ section.settings.hover_add_to_cart_background}} !important;
color: {{ section.settings.hover_add_to_cart_color }} !important;
}
#gf-sales-notification.style2 .gf-time-ago {
position: absolute;
right: 20px;
}
@media (max-width: 520px){
#gf-sales-notification{
min-width: auto;
bottom:30px;
max-width: 90vw;
}
#gf-sales-notification.style2 .gf-info-title-wrapper{
gap: 10px;
}
}
</style>
{% assign allProducts = collections['all'].products %}
{% assign customProducts = section.blocks %}
{% assign locations = section.settings.locations_list | split: '|' %}
{% assign customers = section.settings.customers_list | split: ',' %}
<div id="{{ section.id }}">
{% if section.settings.notification_styles == "style1" %}
<div id="gf-sales-notification" class="style1 {% if section.settings.product_image == false %}no-image{% endif %} {% if content_for_header contains "Shopify.designMode" %} customizer{% endif %}">
<a class="gf-close" rel="nofollow">
<svg viewport="0 0 12 12" version="1.1" xmlns="http://www.w3.org/2000/svg"><line x1="1" y1="11" x2="11" y2="1" stroke-width="1"></line><line x1="1" y1="1" x2="11" y2="11" stroke-width="1"></line></svg>
</a>
<div class="gf-img-wrapper">
<a href="#" >
<img alt="Photo by Mikkel Bech on Unsplash" src="https://images.unsplash.com/photo-1532298229144-0ec0c57515c7?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=822&q=80" class="gf-img"/>
</a>
</div>
<div class="gf-info">
<div class="gf-info-wrapper">
<span class="gf-info-customer"> Mohamed </span>
in
<spam class="gf-info-location">
Lake Elsinore, CA
</spam>
recently purchased
<a class="gf-info-title" href="#">Midnight</a>
<small class="gf-time-ago"> 10 minutes ago</small>
</div>
<button class="gf-info-add-to-cart" product-id="#"> {{ section.settings.add_to_cart_text }} </button>
</div>
</div>
{% elsif section.settings.notification_styles == "style2" %}
<div id="gf-sales-notification" class="style2 {% if section.settings.product_image == false %}no-image{% endif %} {% if content_for_header contains "Shopify.designMode" %} customizer{% endif %}">
<a class="gf-close" rel="nofollow">
<svg viewport="0 0 12 12" version="1.1" xmlns="http://www.w3.org/2000/svg"><line x1="1" y1="11" x2="11" y2="1" stroke-width="1"></line><line x1="1" y1="1" x2="11" y2="11" stroke-width="1"></line></svg>
</a>
<div class="gf-info">
<div class="gf-info-wrapper">
<span class="gf-info-customer"> Mohamed </span>
in
<spam class="gf-info-location">
Lake Elsinore, CA
</spam>
recently purchased
</div>
<span class="gf-info-title-wrapper">
<div class="gf-img-wrapper">
<img alt="Photo by Mikkel Bech on Unsplash" src="https://images.unsplash.com/photo-1532298229144-0ec0c57515c7?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=822&q=80" class="gf-img"/>
</div>
<a class="gf-info-title" href="#">
Midnight
</a>
</span>
<small class="gf-time-ago"> 10 minutes ago</small>
<button class="gf-info-add-to-cart" product-id="#"> {{ section.settings.add_to_cart_text }} </button>
</div>
</div>
{% endif %}}
</div>
<script>
let gf = {
"customProducts": [],
"allProducts": [],
"locations": [],
"customers": [],
"excludeHandles": "{{ section.settings.exclude_products_by_handle }}"
}
let randomizeProducts = {{ section.settings.randomize_products }}
let notificationOffset = {{ section.settings.notification_offset }}
let notificationDelay = {{ section.settings.notification_delay }}
let notificationAddToCart = document.querySelector(".gf-info-add-to-cart")
let notificationWrapper = document.querySelector("#gf-sales-notification")
let notificationClose = document.querySelector(".gf-close")
{% for cP in customProducts %}
if(!gf.excludeHandles.includes("{{ cP.settings.select_product }}"))
gf.customProducts.push("{{ cP.settings.select_product }}");
{% endfor %}
{% for p in allProducts %}
if(!gf.excludeHandles.includes("{{ p.handle }}"))
gf.allProducts.push("{{ p.handle }}");
{% endfor %}
{% for c in customers %} gf.customers.push("{{ c }}"); {% endfor %}
{% for l in locations %} gf.locations.push("{{ l }}"); {% endfor %}
console.log(gf)
// Check if Setting is set to Random Products or Manual.
if(randomizeProducts){
setInterval(function () {
getProductData(gf.allProducts[getRandom(gf.allProducts.length)])
}, notificationOffset);
console.log("allProducts", gf.allProducts)
}else{
getProductData(gf.customProducts[getRandom(gf.customProducts.length)])
console.log("customProducts", gf.customProducts)
}
// Generate & feed Notification with data.
function generateNotification(product){
let notificationItemImg = document.querySelector(".gf-img-wrapper")
let notificationItemTitle = document.querySelector(".gf-info-title")
let notificationItemLocation = document.querySelector(".gf-info-location")
let notificationItemCustomer = document.querySelector(".gf-info-customer")
let notificationItemTimeAgo = document.querySelector(".gf-time-ago")
if(notificationItemTitle){
notificationItemTitle.innerHTML = product.title
notificationItemTitle.setAttribute('href', "/products/" + product.handle)
}
if(notificationItemImg){
if(notificationItemImg.querySelector("a"))
notificationItemImg.querySelector("a").setAttribute("href", "/products/" + product.handle)
if(notificationItemImg.querySelector("img"))
notificationItemImg.querySelector("img").setAttribute('src', product.image.src)
}
if(notificationItemLocation)
notificationItemLocation.innerHTML = gf.locations[getRandom(gf.locations.length)]
if(notificationItemCustomer)
notificationItemCustomer.innerHTML = gf.customers[getRandom(gf.customers.length)]
if(notificationAddToCart)
notificationAddToCart.setAttribute("product-id", product.variants[0].id)
if(notificationItemTimeAgo){
let timeAgo = getRandom(20)
notificationItemTimeAgo.innerHTML = timeAgo == 0 ? "" : `${timeAgo} minute${timeAgo < 10 ? '' : 's'} ago.`
}
if(notificationWrapper.classList.add)
notificationWrapper.classList.add('active')
setTimeout(function () {notificationWrapper.classList.remove('active')}, notificationDelay);
}
// Get Product Data
function getProductData(pID) {
fetch(`/products/${pID}.json`)
.then(response => response.json())
.then(data => generateNotification(data.product))
}
// Add To Cart
if(notificationAddToCart)
notificationAddToCart.addEventListener("click", function(event) {
event.target.innerHTML = "Adding"
let pId = event.target.getAttribute('product-id')
fetch('/cart/add.js', {
body: JSON.stringify({'id': pId, 'quantity':1}),
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-Requested-With':'xmlhttprequest'
},
method: 'POST'
}).then(function(response) {
return response.json();
}).then(function(json) {
event.target.innerHTML = "Added"
setTimeout(() => {
event.target.innerHTML = "{{ section.settings.add_to_cart_text }}"
}, 400);
}).catch(function(err) {
console.error(err)
})
});
// Close Notification
if(notificationClose)
notificationClose.addEventListener("click", function() {
notificationWrapper.classList.remove('active')
})
// Get Random Number
function getRandom(max){ return Math.floor(Math.random() * max) }
</script>
{% schema %}
{
"name": "Sales Notification",
"tag": "section",
"class": "sales-notification",
"settings": [
{
"type": "header",
"content": "Notification Styling"
},
{
"type": "select",
"label": "Notification Styles",
"id": "notification_styles",
"options": [
{
"label": "Style 1",
"value": "style1"
},
{
"label": "Style 2",
"value": "style2"
}
]
},
{
"type": "color_background",
"label": "Background Color",
"id": "background_color",
"default": "#fff"
},
{
"type": "color",
"label": "Font Color",
"id": "font_color",
"default": "#000"
},
{
"type": "color_background",
"label": "Image Background",
"id": "image_background",
"default": "#eee"
},
{
"type": "range",
"label": "Border Radius",
"id": "border_radius",
"default": 4,
"min": 0,
"max": 25,
"step": 1,
"unit": "px"
},
{
"type": "header",
"content": "Customer Name Styling"
},
{
"type": "color",
"label": "Customer Font Color",
"id": "customer_font_color",
"default": "#000"
},
{
"type": "checkbox",
"label": "Make Text Bold",
"id": "customer_bold_text"
},
{
"type": "select",
"label": "Text Style",
"id": "customer_text_style",
"options": [
{
"label": "Default",
"value": "unset"
},
{
"label": "Capitalize",
"value": "capitalize"
},
{
"label": "Uppercase",
"value": "uppercase"
},
{
"label": "Lowercase",
"value": "lowercase"
}
]
},
{
"type": "header",
"content": "Location Text Styling"
},
{
"type": "color",
"label": "Location Font Color",
"id": "location_font_color",
"default": "#000"
},
{
"type": "checkbox",
"label": "Make Text Bold",
"id": "location_bold_text"
},
{
"type": "select",
"label": "Text Style",
"id": "location_text_style",
"options": [
{
"label": "Default",
"value": "unset"
},
{
"label": "Capitalize",
"value": "capitalize"
},
{
"label": "Uppercase",
"value": "uppercase"
},
{
"label": "Lowercase",
"value": "lowercase"
}
]
},
{
"type": "header",
"content": "Product Name Styling"
},
{
"type": "color",
"label": "Product Name Font Color",
"id": "product_name_font_color",
"default": "#000"
},
{
"type": "range",
"label": "Font Size",
"id": "product_name_font_size",
"default": 15,
"min": 12,
"max": 25,
"step": 1,
"unit": "px"
},
{
"type": "checkbox",
"label": "Make Text Bold",
"id": "product_name_bold_text"
},
{
"type": "checkbox",
"label": "Text Underline",
"id": "product_name_underline"
},
{
"type": "select",
"label": "Text Style",
"id": "product_name_text_style",
"options": [
{
"label": "Default",
"value": "unset"
},
{
"label": "Capitalize",
"value": "capitalize"
},
{
"label": "Uppercase",
"value": "uppercase"
},
{
"label": "Lowercase",
"value": "lowercase"
}
]
},
{
"type": "select",
"label": "Product Name Truncate",
"id": "product_name_truncate",
"options": [
{
"label": "No Truncate",
"value": "unset"
},
{
"label": "1 Line",
"value": "1"
},
{
"label": "2 Lines",
"value": "2"
}
]
},
{
"type": "header",
"content": "Add To Card Styling"
},
{
"type": "color_background",
"label": "Background Color",
"id": "add_to_cart_background",
"default": "#000"
},
{
"type": "color",
"label": "Color",
"id": "add_to_cart_color",
"default": "#fff"
},
{
"type": "color_background",
"label": "Hover Background Color",
"id": "hover_add_to_cart_background",
"default": "#888"
},
{
"type": "color",
"label": "Hover Color",
"id": "hover_add_to_cart_color",
"default": "#fff"
},
{
"type": "checkbox",
"label": "Make Text Bold",
"id": "add_to_cart_bold_text"
},
{
"type": "checkbox",
"label": "Make Text Uppercase",
"id": "add_to_cart_uppercase"
},
{
"type": "range",
"label": "Border Radius",
"id": "add_to_cart_border_radius",
"default": 4,
"min": 0,
"max": 25,
"step": 1,
"unit": "px"
},
{
"type": "header",
"content": "Notification Settings"
},
{
"type": "checkbox",
"label": "Randomize Products",
"id": "randomize_products",
"default": false,
"info": "If checked, will do random Sale Notification from all products, else will pick the added ones."
},
{
"type": "checkbox",
"label": "Add To Cart Button",
"id": "add_to_cart_button",
"default": true,
"info": "Display Add To Cart Button"
},
{
"type": "radio",
"label": "Button Position",
"id": "button_position",
"default": "right",
"options": [
{
"label": "Left",
"value": "left"
},
{
"label": "Right",
"value": "right"
}
]
},
{
"type": "text",
"label": "Add To Cart Text",
"id": "add_to_cart_text",
"default": "Add To Cart",
"placeholder": "Add To Cart"
},
{
"type": "checkbox",
"label": "Close Button",
"id": "close_button",
"default": true,
"info": "Display Close Button"
},
{
"type": "checkbox",
"label": "Product Image",
"id": "product_image",
"default": true,
"info": "Display The Product Image"
},
{
"type": "textarea",
"label": "Exclude Products By Handle",
"id": "exclude_products_by_handle",
"info": "Exclude Products by handles, enter handles separated by comma ( , )",
"placeholder": "virtual-product, exclude-product-handle, ..."
},
{
"type": "text",
"label": "Notification Delay",
"id": "notification_delay",
"default": "5000",
"info": "Notification Delay, It means how much the notification shows up (ms)"
},
{
"type": "text",
"label": "Notification Offset",
"id": "notification_offset",
"default": "20000",
"info": "Notification Offset, means how much time between notifications (ms)"
},
{
"type": "textarea",
"label": "Customers List",
"id": "customers_list",
"info": "Enter Customers names separated by comma ( , )",
"placeholder": "John Loren, Simon Travolta, ...",
"default": "John Loren, Elena, Mohamed, Steve Harvey, EL, Silvador"
},
{
"type": "textarea",
"label": "Locations List",
"id": "locations_list",
"info": "Enter locations separated by pipe ( | )",
"placeholder": "Lake Elsinore, California | Lake Elsinore | NY | Canada | ...",
"default": "Morocco|Meknes City|NY|US|Canada|NewYork City|Florida|Alaska"
}
],
"blocks": [
{
"type": "product",
"name": "Product",
"settings": [
{
"type": "product",
"label": "Select Product",
"id": "select_product"
}
]
}
],
"presets": [
{
"name": "Sales Notification"
}
]
}
{% endschema %}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment