Skip to content

Commit

Permalink
new: add pending topups to dashboard
Browse files Browse the repository at this point in the history
Allows to keep track of previous topups, unpaid and waiting for admin
approval. Additionally, information screen of unpaid topups allow to
cancel or pay them.
  • Loading branch information
vaab authored and SeddikKadi committed Oct 7, 2023
1 parent 8b7b9d1 commit 9bc3cc0
Show file tree
Hide file tree
Showing 10 changed files with 415 additions and 72 deletions.
2 changes: 1 addition & 1 deletion src/assets/main.scss
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ body {
font-weight: normal;
text-transform: uppercase;
line-height: 16px;
padding-bottom: 1em !important;
padding-bottom: 1em;
}

.custom-button {
Expand Down
103 changes: 98 additions & 5 deletions src/components/ConfirmPaymentModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@
{
transactionDetail: $gettext("Transaction details"),
paymentConfirmation: $gettext("Payment confirmation"),
topup: $gettext("Top-up details"),
}[$modal.args?.value[0].type]
}}
</p>
<button
class="delete"
aria-label="close"
@click="$modal.close()"
@click="closeAndRefresh()"
></button>
</header>

Expand All @@ -27,14 +28,22 @@
? $gettext("Transaction sent")
: $gettext("Transaction processed"),
paymentConfirmation: $gettext("Payment sent"),
topup: $gettext("Top-up requested"),
}[$modal.args?.value[0].type]
}}
</p>
<div class="confirm-icon-container">
<div
v-if="$modal.args?.value[0].type == 'topup'"
class="confirm-icon-container mb-2"
>
<fa-icon icon="plus-circle" class="confirm-icon fa-thin" />
</div>
<div v-else class="confirm-icon-container">
<fa-icon icon="fa-check" class="confirm-icon fa-thin" />
</div>

<p
v-if="$modal.args?.value[0].type != 'topup'"
class="
amount
custom-card-destinataire
Expand All @@ -53,8 +62,37 @@
}))($modal.args?.value[0].transaction)
}}
</p>

<h2 class="frame3-sub-title">
<p
v-else
class="
amount
custom-card-destinataire
has-text-weight-bold
is-size-4
"
>
{{
((t) =>
$gettext("Requested %{amount}", {
amount: `${numericFormat(t.amount)} ${t.currency}`,
}))($modal.args?.value[0].transaction)
}}
</p>
<h2
v-if="$modal.args?.value[0].type == 'topup'"
class="frame3-sub-title"
>
{{
$modal.args?.value[0].transaction.paid
? $gettext(
"This top-up request is waiting for an administrator of your local currency to validate it"
)
: $gettext(
"This top-up request is waiting for you to pay it or cancel it"
)
}}
</h2>
<h2 v-else class="frame3-sub-title">
{{
$modal.args?.value[0].transaction.amount < 0
? $gettext("to")
Expand Down Expand Up @@ -84,10 +122,32 @@
is-justify-content-flex-end
"
>
<div
v-if="
$modal.args?.value[0].type == 'topup' &&
!$modal.args?.value[0].transaction.paid
"
class="ml-2 mr-2"
>
<button
class="button custom-button-modal has-text-weight-medium"
:title="$gettext('Cancel')"
@click="cancelTopUpRequest"
>
<span>{{ $gettext("Cancel") }}</span>
</button>
<button
class="button custom-button-modal has-text-weight-medium"
:title="$gettext('Pay')"
@click="payTopUpRequest"
>
<span>{{ $gettext("Pay") }}</span>
</button>
</div>
<button
class="button custom-button-modal has-text-weight-medium"
:title="$gettext('Ok')"
@click="$modal.close()"
@click="closeAndRefresh()"
>
<span>{{ $gettext("Ok") }}</span>
</button>
Expand All @@ -99,6 +159,7 @@
import { Options, Vue } from "vue-class-component"
import { mapGetters } from "vuex"
import moment from "moment"
import { UIError } from "../exception"

@Options({
name: "ConfirmPaymentModal",
Expand All @@ -110,6 +171,38 @@
).format("YYYY-MM-DD HH:mm:ssZ")
},
},
methods: {
payTopUpRequest(): void {
// XXXvlab: we would need to launch regular checks
// here to acknowledge the payment
window.open(
this.$modal.args?.value[0].transaction.jsonData.odoo.order_url,
"_blank"
)
},
async cancelTopUpRequest(): Promise<void> {
this.$loading.show()
try {
await this.$modal.args?.value[0].transaction.cancel()
} catch (err) {
throw new UIError(
this.$gettext(
"An error occured while deleting transaction, please try again or contact an administrator"
),
err
)
} finally {
this.$loading.hide()
this.closeAndRefresh()
}
},
// XXXvlab: the refresh is unnecessary in most case, and
// should occur only when needed.
closeAndRefresh(): void {
this.$modal.close("refreshTopUpList")
this.$lokapi.flushBackendCaches()
},
},
})
export default class ConfirmPaymentModal extends Vue {}
</script>
Expand Down
20 changes: 13 additions & 7 deletions src/components/MoneyCreditModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@
<script lang="ts">
import { Options, Vue } from "vue-class-component"
import { mapGetters } from "vuex"
import { UIError } from "../exception"
import BankAccountItem from "./BankAccountItem.vue"
Expand All @@ -193,6 +194,7 @@
creditOrderUrl: "",
selectedCreditAccount: null,
showCreditRefreshNotification: false,
willRequireTransactionRefresh: false,
amount: "",
}
},
Expand Down Expand Up @@ -273,16 +275,19 @@
this.amount
)
this.creditOrderUrl = url.order_url
} catch (error) {
console.log("Payment failed:", error)
this.$msg.error(
} catch (err) {
throw new UIError(
this.$gettext(
"An unexpected issue occurred while attempting to top up your account"
)
),
err
)
} finally {
this.$loading.hide()
}
this.$lokapi.flushBackendCaches()
this.$store.dispatch("fetchAccounts")
this.willRequireTransactionRefresh = true
},
navigateToCreditOrder(): void {
window.open(this.creditOrderUrl, "_blank")
Expand All @@ -291,13 +296,14 @@
this.showCreditRefreshNotification = true
},
closeAndRefresh(): void {
this.close(true)
this.willRequireTransactionRefresh = true
this.close()
this.$lokapi.flushBackendCaches()
this.$store.dispatch("fetchAccounts")
},
close(refreshTransactions: boolean): void {
close(): void {
this.showCreditRefreshNotification = false
this.$modal.close(refreshTransactions)
this.$modal.close(this.willRequireTransactionRefresh)
},
setFocus() {
this.$nextTick(() => {
Expand Down
123 changes: 123 additions & 0 deletions src/components/PendingTopUp.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
<template>
<loading
v-if="!pendingPaidTopUpList.length && !pendingUnpaidTopUpList.length"
v-model:active="isPendingTopUpLoading"
:can-cancel="false"
:is-full-page="false"
/>
<div class="section-card" v-if="pendingUnpaidTopUpList.length">
<h2 class="custom-card-title">
{{ $gettext("Unpaid top-up requests") }}
</h2>
<p class="top-up-info">
{{
$gettext("The following top up requests needs to be paid or canceled")
}}
</p>
<TransactionItem
v-for="topup in pendingUnpaidTopUpList"
:key="topup"
:transaction="topup"
@click="openModal(topup)"
/>
</div>
<div class="section-card" v-if="pendingPaidTopUpList.length">
<h2 class="custom-card-title">
{{ $gettext("Top up waiting admin validation") }}
</h2>
<p class="top-up-info">
{{
$gettext(
"The following top up have been paid and are waiting for an administrator of your local currency to validate them."
)
}}
</p>
<TransactionItem
v-for="topup in pendingPaidTopUpList"
:key="topup"
:transaction="topup"
@click="openModal(topup)"
/>
</div>
</template>

<script lang="ts">
import { mapGetters } from "vuex"
import { Options, Vue } from "vue-class-component"
import Loading from "vue-loading-overlay"
import TransactionItem from "./TransactionItem.vue"
import { UIError } from "../exception"
import "vue-loading-overlay/dist/css/index.css"
@Options({
name: "PendingTopUp",
components: {
Loading,
TransactionItem,
},
props: {
refreshToggle: Boolean,
account: Object,
},
data(this: any) {
return {
pendingTopUpList: [],
isPendingTopUpLoading: false,
}
},
async mounted() {
await this.fetchTopUpList()
},
computed: {
pendingPaidTopUpList() {
return this.pendingTopUpList.filter((topup: any) => topup.paid)
},
pendingUnpaidTopUpList() {
return this.pendingTopUpList.filter((topup: any) => !topup.paid)
},
...mapGetters(["numericFormat", "relativeDateFormat", "dateFormat"]),
},
methods: {
async fetchTopUpList() {
this.isPendingTopUpLoading = true
try {
this.pendingTopUpList = await this.account._obj.getPendingTopUp()
} catch (err) {
throw new UIError(
this.$gettext(
"unexpected server error occured while fetching pending topup list"
),
err
)
} finally {
this.isPendingTopUpLoading = false
}
},
async openModal(transactionObject: any) {
const result = await this.$modal.open("ConfirmPaymentModal", {
transaction: transactionObject,
type: "topup",
})
if (result === "refreshTopUpList") {
this.fetchTopUpList()
}
},
},
watch: {
refreshToggle: async function () {
this.fetchTopUpList()
},
isPendingTopUpLoading(newVal: boolean) {
this.$emit("triggerTransactionRefresh", newVal)
},
},
})
export default class PendingTopUp extends Vue {}
</script>
<style lang="scss" scoped>
.top-up-info {
font-style: italic;
}
</style>
13 changes: 8 additions & 5 deletions src/components/TheBankAccountList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
}}</router-link>
{{ $gettext("to create one.") }}
</p>
<div v-else-if="activeVirtualAccounts.length !== 0">
<div class="section-card" v-else-if="activeVirtualAccounts.length !== 0">
<h2 class="custom-card-title">
{{ $gettext("your accounts") }}
</h2>
Expand All @@ -73,19 +73,22 @@
</BankAccountItem>
</div>
</div>
<div class="inactive" v-if="inactiveVirtualAccounts.length > 0">
<div
class="inactive section-card"
v-if="inactiveVirtualAccounts.length > 0"
>
<h2 class="custom-card-title">
{{ $gettext("your pending accounts") }}
</h2>
<div class="mb-4 ml-5 is-italic">
<p>
{{
$gettext(
"The accounts listed below have been subjected to " +
"a creation request. Once the creation request is" +
" approved, these accounts will become usable."
)
}}
</div>
</p>
<BankAccountItem
v-for="account in inactiveVirtualAccounts"
:bal="account.bal"
Expand Down Expand Up @@ -166,7 +169,7 @@
@import "../assets/custom-variables.scss";
.refresh {
margin-top: -9px;
margin-top: -1.5em;
z-index: 1;
}
.active-refresh-button {
Expand Down
Loading

0 comments on commit 9bc3cc0

Please sign in to comment.