Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TAS-2815] ✨ Implement Christmas campaign #1990

Merged
merged 9 commits into from
Dec 20, 2024
19 changes: 19 additions & 0 deletions src/assets/css/_transitions.scss
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,22 @@
transition-timing-function: ease-in;
}
}

.scroll-up- {
&enter {
transform: translateY(100%);
}
&leave-to {
transform: translateY(-100%);
}

&enter-active,
&leave-active {
transition-property: opacity, transform !important;
transition-duration: 2s;
}
&enter-active,
&leave-active {
transition-timing-function: cubic-bezier(0.7, 0, 0.25, 1);
}
}
2 changes: 1 addition & 1 deletion src/components/SiteMenuForMobile.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<div class="fixed inset-0 z-50 bg-black bg-opacity-[30%]">
<div
class="flex flex-col items-center gap-[22px] w-full bg-white pl-[16px] pr-[8px] py-[28px]"
class="flex flex-col items-center gap-[22px] w-full bg-white pl-[16px] pr-[8px] pt-[40px] pb-[28px]"
>
<header
class="flex items-center justify-between w-full text-like-green mb-[10px]"
Expand Down
130 changes: 130 additions & 0 deletions src/components/SiteTopBanner.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
<template>
<Transition @enter="handleBannerEnter" @leave="handleBannerLeave">
<div
v-if="isShowBanner"
:class="[
'relative',
'top-0',
'z-[500]',

'flex',
'items-center',
'justify-center',

'overflow-hidden',

'w-full',
'h-[40px]',

'text-white',
'bg-like-green',
]"
>
<Transition name="scroll-up">
<div
:key="activeMessage"
:class="[
'absolute',
'inset-0',

'flex',
'justify-center',
'items-center',

'text-[14px]',
'text-center',
]"
v-text="activeMessage"
/>
</Transition>

<ButtonV2
preset="plain"
size="small"
class="absolute translate-y-[-50%] right-[12px] top-1/2"
@click="closeBanner"
>
<IconClose class="transform scale-75 laptop:scale-100" />
</ButtonV2>
</div>
</Transition>
</template>

<script>
const LAST_CLOSED_AT_KEY = 'site-top-banner-last-closed-at';

export default {
name: 'SiteTopBanner',
props: {
messages: {
type: Array,
default: () => [],
},
interval: {
type: Number,
default: 4000,
},
},
data() {
return {
isShowBanner: false,
activeMessageIndex: 0,
};
},
computed: {
activeMessage() {
return this.messages[this.activeMessageIndex];
},
},
mounted() {
this.showBannerIfPossible();
},
beforeDestroy() {
this.clearInterval();
},
methods: {
handleBannerEnter(el, done) {
this.$gsap.gsap.from(el, {
height: 0,
duration: 0.5,
onComplete: done,
});
},
handleBannerLeave(el, done) {
this.$gsap.gsap.to(el, {
height: 0,
duration: 0.5,
onComplete: done,
});
},
nextMessage() {
this.activeMessageIndex =
(this.activeMessageIndex + 1) % this.messages.length;
},
clearInterval() {
if (this.messageInterval) {
clearInterval(this.messageInterval);
this.messageInterval = null;
}
},
closeBanner() {
this.isShowBanner = false;
try {
window.localStorage.setItem(LAST_CLOSED_AT_KEY, Date.now());
} finally {
this.clearInterval();
}
},
showBannerIfPossible() {
try {
const lastClosedTime = window.localStorage.getItem(LAST_CLOSED_AT_KEY);
const oneDay = 24 * 60 * 60 * 1000;
if (!lastClosedTime || Date.now() - lastClosedTime >= oneDay) {
this.isShowBanner = true;
this.messageInterval = setInterval(this.nextMessage, this.interval);
}
} catch {}
},
},
};
</script>
15 changes: 15 additions & 0 deletions src/components/SiteTopBannerForChristmas.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<template>
<SiteTopBanner
:messages="[
$t('christmas_campaign_text_1'),
$t('christmas_campaign_text_2'),
$t('christmas_campaign_text_3'),
]"
/>
</template>

<script>
export default {
name: 'SiteTopBannerForChristmas',
};
</script>
1 change: 1 addition & 0 deletions src/layouts/default.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<template>
<div class="flex flex-col items-stretch min-h-screen">
<SiteTopBannerForChristmas />
<!-- <AlertBanner
v-if="getRouteBaseName($route) !== 'nft-class-classId' && $route.params.classId !== alertBannerNFTClassId"
:primary-button-text="$t('alert_banner_actions_purchase')"
Expand Down
1 change: 1 addition & 0 deletions src/layouts/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<AlertBanner v-if="uiIsChainUpgrading">{{
$t('notice_chain_upgrading')
}}</AlertBanner>
<SiteTopBannerForChristmas />

<nuxt
:class="[
Expand Down
6 changes: 6 additions & 0 deletions src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@
"cart_item_free_not_supported": "Free items cannot be added to cart",
"cart_item_tipping": "Price includes a tip of {amount} USD",
"cart_purchase_channel": "via {from}",
"christmas_campaign_text_1": "🎄 Christmas exclusive discount until DEC 31 🎄",
"christmas_campaign_text_2": "⭐️ Enjoy 15% off on order over $9 USD ⭐️",
"christmas_campaign_text_3": "Code \"XMASREAD\" will be applied automatically",
"civic_dashboard_v3_about_url": "https://docs.like.co/user-guide/civic-liker",
"civic_dashboard_v3_banner_book_nft": "NFT BOOK",
"civic_dashboard_v3_banner_book_nft_description": "unleashes the potential value of ebooks, elevating the essence of books, making them books, yet no longer just books",
Expand Down Expand Up @@ -981,11 +984,14 @@
"language": "Language",
"title": "Settings"
},
"shopping_cart_checkoutd": "Checkout",
"shopping_cart_checkout_button_by_card": "Checkout by card",
"shopping_cart_checkout_button_by_LIKE": "Checkout by LIKE",
"shopping_cart_empty_notice": "Shopping cart is empty",
"shopping_cart_empty_notice_button": "Browse Bookstore",
"shopping_cart_error_insufficient_balance": "Insufficient balance, you only have {balance}",
"shopping_cart_list_coupon_title": "Discount (if applicable)",
"shopping_cart_list_coupon_text": "Calculated at next step",
"shopping_cart_list_header_item": "Item",
"shopping_cart_list_header_price": "Price",
"shopping_cart_list_header_quantity": "Quantity",
Expand Down
6 changes: 6 additions & 0 deletions src/locales/zh-Hant.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@
"cart_item_free_not_supported": "購物車暫不支援免費收藏",
"cart_item_tipping": "單價已含小額打賞 {amount} USD",
"cart_purchase_channel": "透過 {from}",
"christmas_campaign_text_1": "🎄 聖誕限時優惠至12月31號 🎄",
"christmas_campaign_text_2": "⭐️ 凡購買滿 $9 USD 即享全單85折 ⭐️",
"christmas_campaign_text_3": "優惠碼 \"XMASREAD\" 將自動套用",
"civic_dashboard_v3_about_url": "https://docs.like.co/v/zh/user-guide/civic-liker",
"civic_dashboard_v3_banner_book_nft": "NFT BOOK",
"civic_dashboard_v3_banner_book_nft_description": "Liker Land 也解放電子書的潛在價值,昇華書的本質,令書不再只是書。",
Expand Down Expand Up @@ -981,11 +984,14 @@
"language": "介面語言",
"title": "設定"
},
"shopping_cart_checkout": "結帳",
"shopping_cart_checkout_button_by_card": "以信用卡結帳",
"shopping_cart_checkout_button_by_LIKE": "以 LIKE 結帳",
"shopping_cart_empty_notice": "購物車是空的",
"shopping_cart_empty_notice_button": "瀏覽書店",
"shopping_cart_error_insufficient_balance": "餘額不足,你只有 {balance}",
"shopping_cart_list_coupon_title": "優惠(如適用)",
"shopping_cart_list_coupon_text": "將於下一步計算",
"shopping_cart_list_header_item": "購物明細",
"shopping_cart_list_header_price": "單價",
"shopping_cart_list_header_quantity": "數量",
Expand Down
75 changes: 55 additions & 20 deletions src/pages/shopping-cart/book.vue
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,16 @@
<footer
class="grid grid-cols-6 items-center gap-[1em] mt-[1em] text-right"
>
<div
class="col-span-3 sm:col-span-4 text-medium-gray text-[14px] font-200"
>
{{ $t('shopping_cart_list_coupon_title') }}
</div>
<div
class="col-span-3 sm:col-span-2 text-medium-gray text-[14px] font-400"
>
{{ $t('shopping_cart_list_coupon_text') }}
</div>
<div class="col-span-3 sm:col-span-4 text-gray-4a">
{{ $t('shopping_cart_list_total_price') }}
</div>
Expand All @@ -84,25 +94,24 @@
</footer>

<div class="flex justify-end mt-[2em]">
<div class="flex gap-[1em]">
<ButtonV2
v-if="giftInfo"
class="min-w-[120px]"
preset="outline"
:text="$t('nft_edition_select_confirm_button_text_gift')"
@click="handleClickGiftButton"
>
<template #prepend>
<IconGift class="w-[16px]" />
</template>
</ButtonV2>
<EventModalCollectMethodButton
:title="$t('shopping_cart_checkout_button_by_card')"
type="stripe"
:price="formattedFiatPrice"
@click="_ => handleClickCheckoutByFiatButton()"
/>
</div>
<ButtonV2
v-if="giftInfo"
class="min-w-[120px]"
preset="outline"
:text="$t('nft_edition_select_confirm_button_text_gift')"
@click="handleClickGiftButton"
>
<template #prepend>
<IconGift class="w-[16px]" />
</template>
</ButtonV2>
</div>
<div class="grid w-full grid-cols-6">
<ButtonV2
class="w-full col-span-3 col-start-4 sm:col-span-2 sm:col-start-5"
:text="$t('shopping_cart_checkout')"
@click="handleClickCheckoutByFiatButton()"
/>
</div>
</CardV2>

Expand Down Expand Up @@ -145,6 +154,9 @@
import nftMixin from '~/mixins/nft';
import alertMixin from '~/mixins/alert';

const CHRISTMAS_CAMPAIGN_MIN_SPEND = 9;
const CHRISTMAS_CAMPAIGN_COUPON = 'XMASREAD';

export default {
name: 'ShoppingCartPage',
filters: {
Expand Down Expand Up @@ -219,9 +231,32 @@
return totalPrice + (unitPrice * item.quantity || 0);
}, 0);
},
totalItemPriceInUSD() {
return this.shoppingCartBookItems.reduce((totalPrice, item) => {
let itemPrice = 0;
if (item.collectionId) {
itemPrice = this.getNFTCollectionPriceByCollectionId(
item.collectionId
);
} else {
const edition = this.getNFTBookStorePriceByClassIdAndIndex(
item.productId,
item.classId ? item.priceIndex : undefined
);
itemPrice = edition?.price || 0;
}
return totalPrice + (itemPrice * item.quantity || 0);
}, 0);
},
formattedFiatPrice() {
return formatNumberWithUSD(this.totalNFTPriceInUSD);
},
getApplicableCoupon() {
if (this.coupon) return this.coupon;
return this.totalItemPriceInUSD > CHRISTMAS_CAMPAIGN_MIN_SPEND
? CHRISTMAS_CAMPAIGN_COUPON
: '';
},
},
mounted() {
logPurchaseFlowEvent(this, 'view_cart', this.purchaseEventParams);
Expand Down Expand Up @@ -352,7 +387,7 @@
fbClickId: this.fbClickId,
items: this.shoppingCartBookItems,
email: this.walletEmail,
coupon: this.coupon,
coupon: this.getApplicableCoupon,
giftInfo,
},
{
Expand All @@ -373,7 +408,7 @@
throw new Error('Failed to get purchase link');
}
} catch (error) {
console.error(error);

Check warning on line 411 in src/pages/shopping-cart/book.vue

View workflow job for this annotation

GitHub Actions / CI

Unexpected console statement
this.alertPromptError(error);
}
},
Expand Down
Loading