Skip to content

Commit

Permalink
✨ Add coupon section in book and collection (#101)
Browse files Browse the repository at this point in the history
* ✨ Add coupon section in book and collection

* ✨ Add coupon section in purchase link generation

* ✨ Add coupon column in order table
  • Loading branch information
williamchong authored Jan 31, 2024
1 parent 71cf1c2 commit 0db1325
Show file tree
Hide file tree
Showing 2 changed files with 205 additions and 4 deletions.
105 changes: 103 additions & 2 deletions pages/nft-book-store/collection/status/[collectionId].vue
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,64 @@
</template>
</UCard>

<UCard
:ui="{
header: { base: 'flex justify-between items-center' },
body: { padding: '' }
}"
>
<template #header>
<h4 class="text-sm font-bold font-mono">
Coupon codes
</h4>
</template>

<UTable
:columns="[
{ key: 'id', label: 'code', sortable: true },
{ key: 'discount', label: 'discount multiplier' },
{ key: 'expireTs', label: 'expireTs' },
]"
:rows="couponsTableRows"
/>
<h5>New Coupon</h5>
<UFormGroup
label="New coupon code"
:ui="{ label: { base: 'font-mono font-bold' } }"
>
<UInput
v-model="newCoupon.id"
placeholder="coupon_code"
/>
</UFormGroup>
<UFormGroup
label="Coupon discount multiplier, 0.01x - 1x"
:ui="{ label: { base: 'font-mono font-bold' } }"
>
<UInput
v-model="newCoupon.discount"
type="number"
min="0.01"
max="1"
/>
</UFormGroup>
<UFormGroup
label="Coupon expire date"
:ui="{ label: { base: 'font-mono font-bold' } }"
>
<UInput
v-model="newCoupon.expireTs"
type="date"
/>
</UFormGroup>

<UButton
label="Add"
:disabled="!(newCoupon.id && newCoupon.discount)"
@click="addCouponCode"
/>
</UCard>

<UCard :ui="{ body: { base: 'space-y-8' } }">
<template #header>
<h3 class="font-bold font-mono">
Expand Down Expand Up @@ -406,6 +464,10 @@
<UInput v-model="fromChannel" placeholder="Channel ID" />
</UFormGroup>

<UFormGroup v-if="Object.keys(coupons).length" label="Active coupon" hint="Optional">
<USelect v-model="activeCoupon" :options="[''].concat(Object.keys(coupons))" />
</UFormGroup>

<UButton
class="font-mono break-all"
:label="`${purchaseLink}`"
Expand Down Expand Up @@ -467,6 +529,7 @@ const error = ref('')
const isLoading = ref(false)
const collectionId = ref(route.params.collectionId)
const fromChannel = ref<string | undefined>(undefined)
const activeCoupon = ref('')
const collectionListingInfo = ref<any>({})
const ordersData = ref<any>({})
const connectStatus = ref<any>({})
Expand All @@ -476,6 +539,12 @@ const searchInput = ref('')
const moderatorWallets = ref<string[]>([])
const moderatorWalletsGrants = ref<any>({})
const coupons = ref<any>({})
const newCoupon = ref<any>({
id: '',
discount: 1.0,
expireTs: ''
})
const notificationEmails = ref<string[]>([])
const moderatorWalletInput = ref('')
const notificationEmailInput = ref('')
Expand All @@ -495,6 +564,7 @@ const purchaseLink = computed(() => {
const payload: Record<string, string> = {
from: fromChannel.value || ''
}
if (activeCoupon.value) { payload.coupon = activeCoupon.value }
const queryString = `?${new URLSearchParams(payload).toString()}`
const likerLandLink = `https://${IS_TESTNET ? 'rinkeby.' : ''}liker.land/nft/collection/${collectionId.value}${queryString}`
const apiLink = `https://api.${IS_TESTNET ? 'rinkeby.' : ''}like.co/likernft/book/collection/purchase/${collectionId.value}/new${queryString}`
Expand Down Expand Up @@ -536,6 +606,17 @@ const purchaseList = computed(() => {
return []
})
const couponsTableRows = computed(() => {
if (!coupons.value) {
return []
}
return Object.entries(coupons.value).map(([id, value]) => ({
id,
expireTs: (value as any).expireTs ? new Date((value as any).expireTs) : '',
discount: (value as any).discount
}))
})
const shippingRatesTableRows = computed(() => {
if (!collectionListingInfo.value.shippingRates) {
return []
Expand All @@ -559,6 +640,7 @@ const orderTableColumns = computed(() => {
columns.push(
{ key: 'from', label: 'Sales Channel', sortable: true },
{ key: 'price', label: 'Price', sortable: true },
{ key: 'coupon', label: 'Coupon Applied', sortable: false },
{ key: 'email', label: 'Buyer Email', sortable: true },
{ key: 'wallet', label: 'Buyer Wallet', sortable: true },
{ key: 'message', label: 'Buyer Message', sortable: false }
Expand Down Expand Up @@ -652,6 +734,7 @@ const ordersTableRows = computed(() => purchaseList.value?.map((p: any, index: n
shortenWallet: shortenWalletAddress(p.wallet),
priceName: p.priceName,
price: p.price || 0,
coupon: p.coupon || '',
message: p.message || '',
from: p.from || '',
actions: getOrdersTableActionItems(p)
Expand Down Expand Up @@ -751,7 +834,8 @@ onMounted(async () => {
const {
moderatorWallets: classModeratorWallets,
notificationEmails: classNotificationEmails,
connectedWallets: classConnectedWallets
connectedWallets: classConnectedWallets,
coupons: classCoupons
} = collectionListingInfo.value as any
moderatorWallets.value = classModeratorWallets
notificationEmails.value = classNotificationEmails
Expand All @@ -760,6 +844,7 @@ onMounted(async () => {
if (stripeConnectWallet.value !== ownerWallet.value) {
stripeConnectWalletInput.value = stripeConnectWallet.value
}
coupons.value = classCoupons || {}
const { data: orders, error: fetchOrdersError } = await useFetch(`${LIKE_CO_API}/likernft/book/collection/purchase/${collectionId.value}/orders`,
{
headers: {
Expand Down Expand Up @@ -825,6 +910,21 @@ async function hardSetStatusToCompleted (purchase: any) {
collectionListingInfo.value.pendingNFTCount -= 1
}
function addCouponCode () {
console.log(coupons.value)
coupons.value[newCoupon.value.id] = {
discount: newCoupon.value.discount,
expireTs: newCoupon.value.expireTs ? new Date(newCoupon.value.expireTs).getTime() : null,
email: newCoupon.value.email
}
newCoupon.value = {
id: '',
discount: 1.0,
expireTs: ''
}
updateSettings()
}
function addModeratorWallet () {
if (!moderatorWalletInput.value) { return }
moderatorWallets.value.push(moderatorWalletInput.value)
Expand Down Expand Up @@ -872,7 +972,8 @@ async function updateSettings () {
notificationEmails,
connectedWallets,
hideDownload,
mustClaimToView
mustClaimToView,
coupons
})
} catch (err) {
const errorData = (err as any).data || err
Expand Down
104 changes: 102 additions & 2 deletions pages/nft-book-store/status/[classId].vue
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,64 @@
</template>
</UCard>

<UCard
:ui="{
header: { base: 'flex justify-between items-center' },
body: { padding: '' }
}"
>
<template #header>
<h4 class="text-sm font-bold font-mono">
Coupon codes
</h4>
</template>

<UTable
:columns="[
{ key: 'id', label: 'code', sortable: true },
{ key: 'discount', label: 'discount multiplier' },
{ key: 'expireTs', label: 'expireTs' },
]"
:rows="couponsTableRows"
/>
<h5>New Coupon</h5>
<UFormGroup
label="New coupon code"
:ui="{ label: { base: 'font-mono font-bold' } }"
>
<UInput
v-model="newCoupon.id"
placeholder="coupon_code"
/>
</UFormGroup>
<UFormGroup
label="Coupon discount multiplier, 0.01x - 1x"
:ui="{ label: { base: 'font-mono font-bold' } }"
>
<UInput
v-model="newCoupon.discount"
type="number"
min="0.01"
max="1"
/>
</UFormGroup>
<UFormGroup
label="Coupon expire date"
:ui="{ label: { base: 'font-mono font-bold' } }"
>
<UInput
v-model="newCoupon.expireTs"
type="date"
/>
</UFormGroup>

<UButton
label="Add"
:disabled="!(newCoupon.id && newCoupon.discount)"
@click="addCouponCode"
/>
</UCard>

<UCard :ui="{ body: { base: 'space-y-8' } }">
<template #header>
<h3 class="font-bold font-mono">
Expand Down Expand Up @@ -528,6 +586,10 @@
<UInput v-model="fromChannel" placeholder="Channel ID" />
</UFormGroup>

<UFormGroup v-if="Object.keys(coupons).length" label="Active coupon" hint="Optional">
<USelect v-model="activeCoupon" :options="[''].concat(Object.keys(coupons))" />
</UFormGroup>

<UButton
class="font-mono break-all"
:label="`${purchaseLink}`"
Expand Down Expand Up @@ -589,6 +651,7 @@ const isLoading = ref(false)
const classId = ref(route.params.classId)
const fromChannel = ref<string | undefined>(undefined)
const priceIndex = ref(0)
const activeCoupon = ref('')
const classListingInfo = ref<any>({})
const prices = ref<any[]>([])
const isUpdatingPricesOrder = ref(false)
Expand All @@ -600,6 +663,12 @@ const searchInput = ref('')
const moderatorWallets = ref<string[]>([])
const moderatorWalletsGrants = ref<any>({})
const coupons = ref<any>({})
const newCoupon = ref<any>({
id: '',
discount: 1.0,
expireTs: ''
})
const notificationEmails = ref<string[]>([])
const moderatorWalletInput = ref('')
const notificationEmailInput = ref('')
Expand All @@ -620,6 +689,7 @@ const purchaseLink = computed(() => {
from: fromChannel.value || '',
price_index: priceIndex.value.toString()
}
if (activeCoupon.value) { payload.coupon = activeCoupon.value }
const queryString = `?${new URLSearchParams(payload).toString()}`
const apiLink = `https://api.${IS_TESTNET ? 'rinkeby.' : ''}like.co/likernft/book/purchase/${classId.value}/new${queryString}`
const likerLandLink = `https://${IS_TESTNET ? 'rinkeby.' : ''}liker.land/nft/class/${classId.value}${queryString}`
Expand Down Expand Up @@ -661,6 +731,17 @@ const purchaseList = computed(() => {
return []
})
const couponsTableRows = computed(() => {
if (!coupons.value) {
return []
}
return Object.entries(coupons.value).map(([id, value]) => ({
id,
expireTs: (value as any).expireTs ? new Date((value as any).expireTs) : '',
discount: (value as any).discount
}))
})
const shippingRatesTableRows = computed(() => {
if (!classListingInfo.value.shippingRates) {
return []
Expand All @@ -685,6 +766,7 @@ const orderTableColumns = computed(() => {
{ key: 'from', label: 'Sales Channel', sortable: true },
{ key: 'price', label: 'Price', sortable: true },
{ key: 'priceName', label: 'Price Name', sortable: false },
{ key: 'coupon', label: 'Coupon Applied', sortable: false },
{ key: 'email', label: 'Buyer Email', sortable: true },
{ key: 'wallet', label: 'Buyer Wallet', sortable: true },
{ key: 'message', label: 'Buyer Message', sortable: false }
Expand Down Expand Up @@ -794,6 +876,7 @@ const ordersTableRows = computed(() => purchaseList.value?.map((p: any, index: n
shortenWallet: shortenWalletAddress(p.wallet),
priceName: p.priceName,
price: p.price || 0,
coupon: p.coupon || '',
message: p.message || '',
from: p.from || '',
actions: getOrdersTableActionItems(p)
Expand Down Expand Up @@ -902,7 +985,8 @@ onMounted(async () => {
notificationEmails: classNotificationEmails,
connectedWallets: classConnectedWallets,
mustClaimToView: classMustClaimToView,
hideDownload: classHideDownload
hideDownload: classHideDownload,
coupons: classCoupons
} = classData.value as any
moderatorWallets.value = classModeratorWallets
notificationEmails.value = classNotificationEmails
Expand All @@ -913,6 +997,7 @@ onMounted(async () => {
}
mustClaimToView.value = classMustClaimToView
hideDownload.value = classHideDownload
coupons.value = classCoupons || {}
const { data: orders, error: fetchOrdersError } = await useFetch(`${LIKE_CO_API}/likernft/book/purchase/${classId.value}/orders`,
{
headers: {
Expand Down Expand Up @@ -1018,6 +1103,20 @@ async function hardSetStatusToCompleted (purchase: any) {
classListingInfo.value.pendingNFTCount -= 1
}
function addCouponCode () {
coupons.value[newCoupon.value.id] = {
discount: newCoupon.value.discount,
expireTs: newCoupon.value.expireTs ? new Date(newCoupon.value.expireTs).getTime() : null,
email: newCoupon.value.email
}
newCoupon.value = {
id: '',
discount: 1.0,
expireTs: ''
}
updateSettings()
}
function addModeratorWallet () {
if (!moderatorWalletInput.value) { return }
moderatorWallets.value.push(moderatorWalletInput.value)
Expand Down Expand Up @@ -1065,7 +1164,8 @@ async function updateSettings () {
notificationEmails,
connectedWallets,
hideDownload,
mustClaimToView
mustClaimToView,
coupons
})
} catch (err) {
const errorData = (err as any).data || err
Expand Down

0 comments on commit 0db1325

Please sign in to comment.