Created
August 26, 2020 22:28
-
-
Save panoply/4055c6870e6baacc6b60c9b4f9d51d30 to your computer and use it in GitHub Desktop.
Mithril Shopify Cart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Modules */ | |
import m from 'mithril' | |
import stream from 'mithril/stream' | |
export default class CartAPI { | |
stream = stream('') | |
constructor () { | |
this.get() | |
} | |
/** | |
* Gets the cart data. | |
* | |
* @param {string} api | |
*/ | |
async get () { | |
const response = await m.request({ | |
method: 'GET', | |
url: '/cart.json' | |
}) | |
if (!response) return response | |
this.stream(response) | |
this.count() | |
return response | |
} | |
async update (data) { | |
const response = await m.request({ | |
method: 'POST', | |
url: '/cart/update.js', | |
data | |
}) | |
this.stream(response) | |
this.count() | |
return response | |
} | |
/** | |
* @param {object} data | |
*/ | |
add (data) { | |
return m.request({ | |
method: 'POST', | |
url: '/cart/add.js', | |
body: data | |
}).then(response => { | |
this.get() | |
this.count() | |
}).catch(console.error) | |
} | |
change (data) { | |
console.log(data) | |
return m.request({ | |
method: 'POST', | |
url: '/cart/change.js', | |
body: data | |
}).then(response => { | |
this.stream(response) | |
this.count() | |
}).catch(console.error) | |
} | |
async clear (data) { | |
const response = await m.request({ | |
method: 'POST', | |
url: '/cart/clear.js', | |
data | |
}) | |
this.stream(response) | |
this.count() | |
return response | |
} | |
async shipping (data) { | |
const response = await m.request({ | |
method: 'POST', | |
url: '/cart/shipping_rates.json', | |
body: data | |
}) | |
return response | |
} | |
async discount (data) { | |
const response = await m.request({ | |
method: 'POST', | |
url: '/cart/shipping_rates.json', | |
body: data | |
}) | |
return response | |
} | |
async bogo (data) { | |
const response = await m.request({ | |
method: 'POST', | |
url: '/cart/shipping_rates.json', | |
data | |
}) | |
return response | |
} | |
/** | |
* Cart items count | |
* Updates all span items that contain the cart | |
* item count | |
* | |
*/ | |
count () { | |
const { item_count } = this.stream() | |
const elements = document.querySelectorAll('span[data-cart="count"]') | |
for (const element of elements) element.innerText = item_count | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import m from 'mithril' | |
export default { | |
view: () => m('.cart__empty.d-flex', [ | |
m('.align-self-center.text-center.m-auto', [ | |
m('svg.icon', [ | |
m('use[xlink:href="#thumbs-down"]') | |
]), | |
m('.title.pt-2', 'Your Cart is Empty') | |
]) | |
]) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Modules */ | |
import m from 'mithril' | |
import { money } from '../../application/Utilities' | |
/* Partials */ | |
import CartAPI from './api' | |
import Empty from './empty' | |
import LineItem from './line-item' | |
export const AjaxCart = (() => { | |
const api = new CartAPI() | |
// console.log(api.stream()) | |
return { | |
api, | |
render: (element) => { | |
const { flag_path } = Object | |
.values(App.locale.countries) | |
.find(({ code }) => code === 'SE') | |
m.mount(element, { | |
oninit: ({ state }) => { | |
state.paymentText = 'Shipping & Payment' | |
state.paymentIcon = 'payment' | |
state.paymentFallback = false | |
}, | |
view: ({ state }) => api.stream().item_count === 0 ? m(Empty) : [ | |
m('.row.jc-center.ac-center', [ | |
m('.col-12', [ | |
// LINE ITEM | |
m(LineItem, { api }), | |
// SUB TOTAL | |
m('.row.jc-between.ai-center.py-2.cart__total', [ | |
m('.col-auto.cart__label', 'SUBTOTAL'), | |
m('.col-auto.cart__price', money(api.stream().total_price)) | |
]), | |
// SHIPPING | |
m('.row.jc-between.ai-center.py-2.cart__shipping', [ | |
m('.col-auto', [ | |
m('span.pr-2.cart__label', 'Shipping to'), | |
m(`img.flag[src="${flag_path}"]`) | |
]), | |
m('.col-auto', [ | |
m('.span.cart__price', api.stream().shipping_rate !== 0 | |
? 'FREE' | |
: 'FREE') | |
]) | |
]), | |
// CART TOTAL | |
m('.row.jc-between.ai-center.py-2.cart__total', [ | |
m('.col-auto.cart__label', 'TOTAL'), | |
m('.col-auto.cart__price', money(api.stream().total_price)) | |
]), | |
/* m(Charity, { | |
currency: currency, | |
total_price: api.cart().total_price | |
}), */ | |
/* m(Checkout, { | |
currency: locale().currency | |
}) */ | |
m('button.mt-3.cart__checkout[type="submit"][name="checkout"]', { | |
onclick: ({ | |
currentTarget: { | |
lastElementChild | |
} | |
}) => { | |
state.paymentIcon = 'loading' | |
state.paymentText = 'Securing Checkout' | |
setTimeout(() => { | |
state.paymentText = 'Redirecting' | |
state.paymentIcon = 'tick' | |
m.redraw() | |
}, 2000) | |
setTimeout(() => { | |
state.paymentFallback = true | |
m.redraw() | |
}, 6000) | |
return location.replace('https://www.brixtoltextiles.com/checkout') | |
} | |
}, [ | |
m('svg.icon', m(`use[xlink:href="#${state.paymentIcon}"]`)), | |
m('span', `${state.paymentText}`) | |
]), | |
state.paymentFallback ? m('.mt-3', [ | |
m('a.h6.d-block.text-center[href="/cart"]', 'Goto Checkout') | |
]) : null | |
]) | |
]) | |
] | |
}) | |
} | |
} | |
})() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import m from 'mithril' | |
import Quantity from './quantity' | |
import Remove from './remove' | |
import { imgSrc, money } from '../../application/Utilities' | |
export default { | |
oninit () { | |
this.line = 1 | |
}, | |
view: ({ | |
state: { | |
line | |
}, | |
attrs: { | |
api | |
} | |
}) => api.stream().items ? api.stream().items.map((item, index) => [ | |
m('.row.jc-between.ai-center.cart__line-item', [ | |
m('button.remove[type="button"]', { | |
onclick: () => api.change({ line: line, quantity: 0 }) | |
}, m('svg.icon-close[viewBox="0 0 24 30"][xmlns="http://www.w3.org/2000/svg"]', [ | |
m('path[d=M20.827 4.357l-.707-.707-8.131 8.132L3.857 3.65l-.707.707 8.132 8.132-8.132 8.132.707.707 8.132-8.132 8.131 8.132.707-.707-8.131-8.132z]') | |
])), | |
m('.col-auto.px-0', [ | |
m(`img.img-fluid[src="${imgSrc(item.image, 420)}"]`, { | |
onclick: event => { | |
event.preventDefault() | |
return Turbolinks.visit(item.url) | |
} | |
}) | |
]), | |
m('.col', [ | |
m('ul.d-block.mb-2', { onclick: () => Turbolinks.visit(item.url) }, [ | |
m('li.title', item.product_title), | |
m('li.variant', item.variant_title) | |
]), | |
m('.row.jc-between', [ | |
m('.col-auto', [ | |
m(Quantity, { | |
api, | |
data: { | |
id: item.id, | |
index: index + line, | |
quantity: item.quantity, | |
min_quantity: item.min_quantity ? item.min_quantity : false | |
} | |
}) | |
]), | |
m('.col-auto.cart__price', [ | |
item.discounts.length >= 1 ? [ | |
item.quantity === 1 && item.discounts.length === 1 ? [ | |
m('s', item.discounted_price), | |
m('.d-block', 'FREE') | |
] : item.quantity > item.discounts.length ? [ | |
m('span', ( | |
item.original_price * item.quantity | |
) - ( | |
item.discounted_price * item.discounts.length | |
)), | |
m('.d-block', [ | |
m('small', [ | |
m('span', 'Save: ') | |
]), | |
m('span', item.discounted_price * item.discounts.length) | |
]) | |
] : [ | |
m('s', item.original_line_price), | |
m('.d-block', 'FREE') | |
] | |
] : money(item.line_price) | |
]) | |
]) | |
]) | |
]) | |
]) : null | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.cart { | |
font-family: var(--heading-font-family); | |
&__header { | |
height: 49px; | |
color: $black; | |
font-family: var(--heading-font-family); | |
//border-bottom: 0.01em solid $black-600; | |
.icon { | |
width: 20px; | |
height: 20px; | |
} | |
.item-count { | |
.counter { | |
position: absolute; | |
top: 7px; | |
right: 0; | |
width: 16px; | |
height: 16px; | |
border-radius: 100%; | |
background: red; | |
color: $white; | |
text-align: center; | |
font-size: 0.825rem; | |
font-weight: 500; | |
line-height: 16px; | |
z-index: 2; | |
font-family: Arial; | |
} | |
.cart { | |
position: absolute; | |
right: 8px; | |
top: 10px; | |
z-index: 1; | |
.icon-cart { | |
width: 25px; | |
fill: $white; | |
} | |
} | |
} | |
} | |
&__checkout, | |
&__shipping, | |
&__price, | |
&__label { | |
text-transform: uppercase; | |
font-size: 0.945rem; | |
} | |
&__total { | |
border-bottom: 1px solid $gray-200; | |
} | |
&__shipping { | |
border-bottom: 1px solid $gray-200; | |
.flag { | |
width: 16px; | |
} | |
} | |
&__line-item { | |
border-bottom: 1px solid $gray-200; | |
img { | |
display: block; | |
margin: 0 auto; | |
width: 100%; | |
max-width: 90px; | |
border-right: 1px solid $gray-300; | |
} | |
.details { | |
height: 100%; | |
} | |
.title { | |
text-transform: uppercase; | |
font-size: 0.945rem; | |
color: $black-300; | |
font-family: inherit; | |
&:hover, | |
&:focus { | |
text-decoration: underline; | |
cursor: pointer; | |
} | |
} | |
.variant { | |
text-transform: uppercase; | |
font-size: 0.945rem; | |
color: $gray-500; | |
font-family: inherit; | |
} | |
.remove { | |
position: absolute; | |
top: 5px; | |
right: 10px; | |
.icon-close { | |
width: 15px; | |
fill: $gray-500; | |
&:hover, | |
&:focus { | |
fill: $black; | |
} | |
} | |
} | |
&--property { | |
font-size: 0.75rem; | |
text-transform: uppercase; | |
color: #999; | |
.icon { | |
width: 8px; | |
height: 8px; | |
svg { | |
fill: #333; | |
} | |
} | |
} | |
} | |
&__checkout { | |
background-color: transparent; //lighten($black-600, 5%); //$green; | |
border-radius: 4px; | |
border: 1px solid lighten($black-600, 5%); | |
padding: 0 24px; | |
max-width: 100%; | |
width: 100%; | |
text-align: center; | |
color: $black-600; | |
height: 45px; | |
text-transform: uppercase; | |
cursor: pointer; | |
.additional-checkout-button { | |
border-radius: 4px; | |
width: 100%; | |
cursor: pointer !important; | |
} | |
@include media-breakpoint-up(md) { | |
&:hover { | |
background-color: lighten($green, 7%); | |
} | |
} | |
.icon { | |
position: absolute; | |
top: 10px; | |
right: 17px; | |
width: 25px; | |
height: 25px; | |
fill: $black-600; | |
} | |
&--or { | |
color: #222; | |
font-weight: 600; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment