11<template >
2- <div class =" flex flex-col p-6" >
3- <div
4- class =" flex items-center gap-2"
5- :class =" { 'text-red-500': isInsufficientCredits }"
6- >
7- <i
8- :class =" [
9- 'text-2xl',
10- isInsufficientCredits ? 'pi pi-exclamation-triangle' : ''
11- ]"
12- />
13- <h2 class =" text-2xl font-semibold" >
14- {{
15- $t(
16- isInsufficientCredits
17- ? 'credits.topUp.insufficientTitle'
18- : 'credits.topUp.title'
19- )
20- }}
21- </h2 >
2+ <div class =" flex flex-col w-96 p-2 gap-10" >
3+ <div v-if =" isInsufficientCredits" class =" flex flex-col gap-4" >
4+ <h1 class =" text-2xl font-medium leading-normal my-0" >
5+ {{ $t('credits.topUp.insufficientTitle') }}
6+ </h1 >
7+ <p class =" text-base my-0" >
8+ {{ $t('credits.topUp.insufficientMessage') }}
9+ </p >
2210 </div >
2311
24- <!-- Error Message -->
25- <p v-if =" isInsufficientCredits" class =" text-lg text-muted mt-6" >
26- {{ $t('credits.topUp.insufficientMessage') }}
27- </p >
28-
2912 <!-- Balance Section -->
30- <div class =" flex justify-between items-center mt-8" >
31- <div class =" flex flex-col gap-2" >
32- <div class =" text-muted" >{{ $t('credits.yourCreditBalance') }}</div >
13+ <div class =" flex justify-between items-center" >
14+ <div class =" flex flex-col gap-2 w-full" >
15+ <div class =" text-muted text-base" >
16+ {{ $t('credits.yourCreditBalance') }}
17+ </div >
18+ <div class =" flex items-center justify-between w-full" >
19+ <div class =" flex items-center gap-2" >
20+ <Tag
21+ severity =" secondary"
22+ icon =" pi pi-dollar"
23+ rounded
24+ class =" text-amber-400 p-1"
25+ />
26+ <span class =" text-2xl" >{{ formattedBalance }}</span >
27+ </div >
28+ <Button
29+ outlined
30+ severity =" secondary"
31+ :label =" $t('credits.topUp.seeDetails')"
32+ icon =" pi pi-arrow-up-right"
33+ @click =" handleSeeDetails"
34+ />
35+ </div >
36+ </div >
37+ </div >
38+
39+ <!-- Amount Input Section -->
40+ <div class =" flex flex-col gap-2" >
41+ <span class =" text-muted text-sm"
42+ >{{ $t('credits.topUp.quickPurchase') }}:</span
43+ >
44+ <div class =" grid grid-cols-[2fr_1fr] gap-2" >
45+ <template v-for =" amount in amountOptions " :key =" amount " >
46+ <div class =" flex items-center gap-2" >
47+ <Tag
48+ severity =" secondary"
49+ icon =" pi pi-dollar"
50+ rounded
51+ class =" text-amber-400 p-1"
52+ />
53+ <span class =" text-xl" >{{ amount }}</span >
54+ </div >
55+ <Button
56+ :severity ="
57+ preselectedAmountOption === amount ? 'primary' : 'secondary'
58+ "
59+ :outlined =" preselectedAmountOption !== amount"
60+ :label =" $t('credits.topUp.buyNow')"
61+ @click =" handleBuyNow(amount)"
62+ />
63+ </template >
64+
3365 <div class =" flex items-center gap-2" >
3466 <Tag
3567 severity =" secondary"
3668 icon =" pi pi-dollar"
3769 rounded
3870 class =" text-amber-400 p-1"
3971 />
40- <span class =" text-2xl" >{{ formattedBalance }}</span >
72+ <InputNumber
73+ v-model =" customAmount"
74+ :min =" 1"
75+ :max =" 1000"
76+ :step =" 1"
77+ show-buttons
78+ :allow-empty =" false"
79+ :highlight-on-focus =" true"
80+ pt:pc-input-text:root =" w-24"
81+ @blur ="
82+ (e: InputNumberBlurEvent) => (customAmount = Number(e.value))
83+ "
84+ @input ="
85+ (e: InputNumberInputEvent) => (customAmount = Number(e.value))
86+ "
87+ />
4188 </div >
42- </div >
43- <Button
44- text
45- severity =" secondary"
46- :label =" $t('credits.creditsHistory')"
47- icon =" pi pi-arrow-up-right"
48- @click =" handleSeeDetails"
49- />
50- </div >
51-
52- <!-- Amount Input Section -->
53- <div class =" flex flex-col gap-2 mt-8" >
54- <div >
55- <span class =" text-muted" >{{ $t('credits.topUp.addCredits') }}</span >
56- <span class =" text-muted text-sm ml-1" >{{
57- $t('credits.topUp.maxAmount')
58- }}</span >
59- </div >
60- <div class =" flex items-center gap-2" >
61- <Tag
89+ <ProgressSpinner v-if =" loading" class =" w-8 h-8" />
90+ <Button
91+ v-else
92+ :label =" $t('credits.topUp.buyNow')"
6293 severity =" secondary"
63- icon =" pi pi-dollar"
64- rounded
65- class =" text-amber-400 p-1"
66- />
67- <InputNumber
68- v-model =" amount"
69- :min =" 1"
70- :max =" 1000"
71- :step =" 1"
72- mode =" currency"
73- currency =" USD"
74- show-buttons
75- @blur =" handleBlur"
76- @input =" handleInput"
94+ outlined
95+ @click =" handleBuyNow(customAmount)"
7796 />
7897 </div >
7998 </div >
80- <div class =" flex justify-end mt-8" >
81- <ProgressSpinner v-if =" loading" class =" w-8 h-8" />
82- <Button
83- v-else
84- severity =" primary"
85- :label =" $t('credits.topUp.buyNow')"
86- :disabled =" !amount || amount > 1000"
87- :pt =" {
88- root: { class: 'px-8' }
89- }"
90- @click =" handleBuyNow"
91- />
92- </div >
9399 </div >
94100</template >
95101
96102<script setup lang="ts">
97103import Button from ' primevue/button'
98- import InputNumber from ' primevue/inputnumber'
104+ import InputNumber , {
105+ type InputNumberBlurEvent ,
106+ type InputNumberInputEvent
107+ } from ' primevue/inputnumber'
99108import ProgressSpinner from ' primevue/progressspinner'
100109import Tag from ' primevue/tag'
101110import { computed , onBeforeUnmount , ref } from ' vue'
102111
103112import { useFirebaseAuthStore } from ' @/stores/firebaseAuthStore'
104113import { formatMetronomeCurrency , usdToMicros } from ' @/utils/formatUtil'
105114
106- defineProps <{
115+ const {
116+ isInsufficientCredits = false ,
117+ amountOptions = [5 , 10 , 20 , 50 ],
118+ preselectedAmountOption = 10
119+ } = defineProps <{
107120 isInsufficientCredits? : boolean
121+ amountOptions? : number []
122+ preselectedAmountOption? : number
108123}>()
109124
110125const authStore = useFirebaseAuthStore ()
111- const amount = ref <number >(9.99 )
126+ const customAmount = ref <number >(100 )
112127const didClickBuyNow = ref (false )
113128const loading = computed (() => authStore .loading )
114129
115- const handleBlur = (e : any ) => {
116- if (e .target .value ) {
117- amount .value = parseFloat (e .target .value )
118- }
119- }
120-
121- const handleInput = (e : any ) => {
122- amount .value = e .value
123- }
124-
125130const formattedBalance = computed (() => {
126131 if (! authStore .balance ) return ' 0.000'
127132 return formatMetronomeCurrency (authStore .balance .amount_micros , ' usd' )
@@ -133,11 +138,9 @@ const handleSeeDetails = async () => {
133138 window .open (response .billing_portal_url , ' _blank' )
134139}
135140
136- const handleBuyNow = async () => {
137- if (! amount .value ) return
138-
141+ const handleBuyNow = async (amount : number ) => {
139142 const response = await authStore .initiateCreditPurchase ({
140- amount_micros: usdToMicros (amount . value ),
143+ amount_micros: usdToMicros (amount ),
141144 currency: ' usd'
142145 })
143146
0 commit comments