fix: added cards list

This commit is contained in:
Shariq Ansari 2024-11-14 19:53:49 +05:30
parent d96b313fba
commit e1c64ed3f0
4 changed files with 254 additions and 5 deletions

View file

@ -107,7 +107,7 @@ const removeCard = (card) => {
message: 'Are you sure you want to remove this card?', message: 'Are you sure you want to remove this card?',
actions: [ actions: [
{ {
label: 'Delete', label: 'Remove',
variant: 'solid', variant: 'solid',
theme: 'red', theme: 'red',
onClick: (close) => { onClick: (close) => {

View file

@ -0,0 +1,18 @@
<template>
<svg width="16" height="16" fill="none" viewBox="0 0 16 16">
<g class="es-line-reload" clip-path="url(#a)">
<path
fill="currentColor"
fill-rule="evenodd"
d="M9.743 2.189a6 6 0 0 0-6.558 2.596.5.5 0 0 0 .844.535 5 5 0 0 1 9.12 1.683l-1.187-.686a.5.5 0 0 0-.5.866l2.165 1.25a.5.5 0 0 0 .683-.183l1.25-2.165a.5.5 0 0 0-.866-.5l-.603 1.044a6 6 0 0 0-4.348-4.44ZM3.356 9.024l1.189.687a.5.5 0 0 0 .5-.866L2.88 7.595a.5.5 0 0 0-.683.183L.947 9.943a.5.5 0 1 0 .866.5l.603-1.044a6 6 0 0 0 10.9 1.816.5.5 0 0 0-.844-.536 5 5 0 0 1-9.116-1.655Z"
class="Union"
clip-rule="evenodd"
/>
</g>
<defs>
<clipPath id="a" class="a">
<path fill="currentColor" d="M.25 0h16v16h-16z" />
</clipPath>
</defs>
</svg>
</template>

View file

@ -7,7 +7,7 @@
<ListView <ListView
:columns="columns" :columns="columns"
:rows="rows" :rows="rows"
row-key="name" row-key="id"
:options="{ :options="{
selectable: false, selectable: false,
}" }"

View file

@ -1,7 +1,238 @@
<template> <template>
<div class="flex h-full flex-col py-11 px-[68px] gap-8 overflow-y-auto"> <div class="flex h-full flex-col py-11 px-[68px] gap-8 overflow-y-auto">
<h2 class="flex gap-2 text-xl font-semibold leading-5"> <div class="flex justify-between items-center">
{{ 'Cards' }} <h2 class="flex gap-2 text-xl font-semibold leading-5">
</h2> {{ 'Cards' }}
</h2>
<div class="flex gap-2">
<Button :loading="cards.loading" @click="cards.reload()">
<template #icon>
<RefreshIcon class="h-4 w-4" />
</template>
</Button>
<Button label="Add Card" variant="solid" @click="showAddCardModal = true">
<template #prefix>
<FeatherIcon name="plus" class="h-4 w-4" />
</template>
</Button>
</div>
</div>
<div>
<ListView
:columns="columns"
:rows="rows"
row-key="id"
:options="{
selectable: false,
showTooltip: false,
}"
>
<ListHeader />
<ListRows>
<ListRow
v-for="row in rows"
:key="row.id"
v-slot="{ column, item }"
:row="row"
>
<ListRowItem :item="item" :align="column.align">
<div
v-if="column.key == 'last_4'"
class="flex items-center gap-2 text-base"
>
<component :is="cardBrandIcon(item.brand)" class="h-6 w-6" />
<div>{{ item.last_4 }}</div>
<Badge
v-if="item.default"
label="Default"
variant="outline"
theme="green"
/>
</div>
<Dropdown
v-else-if="column.key == 'actions' && !item.is_default"
:options="item.options"
>
<button
class="flex items-center rounded bg-gray-100 px-1 py-0.5 hover:bg-gray-200"
>
<FeatherIcon name="more-horizontal" class="h-4 w-4" />
</button>
</Dropdown>
</ListRowItem>
</ListRow>
</ListRows>
</ListView>
</div>
</div> </div>
<AddCardModal
v-if="showAddCardModal"
v-model="showAddCardModal"
@success="
() => {
showAddCardModal = false
cards.reload()
}
"
/>
</template> </template>
<script setup>
import AddCardModal from '@/components/AddCardModal.vue'
import RefreshIcon from '@/icons/RefreshIcon.vue'
import {
ListView,
ListHeader,
ListRows,
ListRow,
ListRowItem,
Dropdown,
Button,
Badge,
Tooltip,
FeatherIcon,
createResource,
} from 'frappe-ui'
import { useTimeAgo } from '@vueuse/core'
import { createDialog } from '@/dialogs.js'
import { cardBrandIcon } from '@/utils'
import { ref, computed } from 'vue'
const showAddCardModal = ref(false)
const cards = createResource({
url: 'frappe.integrations.frappe_providers.frappecloud_billing.api',
params: { method: 'billing.get_payment_methods' },
auto: true,
})
const columns = [
{
label: 'Name on Card',
key: 'name_on_card',
},
{
label: 'Card',
key: 'last_4',
width: 1.5,
},
{
label: 'Expiry',
key: 'expiry_month',
width: 0.5,
},
{
label: 'Mandated',
key: 'stripe_mandate_id',
align: 'center',
width: 1,
},
{
label: '',
key: 'alert',
align: 'right',
},
{
label: '',
key: 'creation',
align: 'right',
},
{
label: '',
key: 'actions',
align: 'right',
width: 0.5,
},
]
const rows = computed(() => {
if (!cards.data) return []
return cards.data.map((card) => {
return {
id: card.name,
name_on_card: card.name_on_card,
last_4: {
brand: card.brand,
last_4: `•••• ${card.last_4}`,
default: card.is_default,
},
expiry_month: `${
card.expiry_month < 10 ? `0${card.expiry_month}` : card.expiry_month
}/${card.expiry_year}`,
stripe_mandate_id: card.stripe_mandate_id
? h(FeatherIcon, {
name: 'check-circle',
class: 'h-4 w-4 text-green-600',
})
: null,
alert:
card.is_default && card.stripe_payment_method
? h(
Tooltip,
{
text: 'The last payment failed on this card. Please use a different card.',
},
() =>
h(FeatherIcon, {
name: 'alert-circle',
class: 'h-4 w-4 text-red-600',
}),
)
: null,
creation: useTimeAgo(card.creation).value,
actions: {
is_default: card.is_default,
options: [
{
label: 'Set as default',
onClick: () => setAsDefault(card.name),
condition: () => !card.is_default,
},
{
label: 'Remove',
onClick: () => removeCard(card.name),
},
],
},
}
})
})
const setAsDefault = (card) => {
createResource({
url: 'frappe.integrations.frappe_providers.frappecloud_billing.api',
params: { method: 'billing.set_as_default', data: { name: card } },
auto: true,
onSuccess: () => {
cards.reload()
},
})
}
const removeCard = (card) => {
createDialog({
title: 'Remove Card',
message: 'Are you sure you want to remove this card?',
actions: [
{
label: 'Remove',
variant: 'solid',
theme: 'red',
onClick: (close) => {
createResource({
url: 'frappe.integrations.frappe_providers.frappecloud_billing.api',
params: {
method: 'billing.remove_payment_method',
data: { name: card },
},
auto: true,
onSuccess: () => {
cards.reload()
close()
},
})
},
},
],
})
}
</script>