1
1
<template >
2
- <section class =" universal-card" >
2
+ <section class =" universal-card experimental-styles-within " >
3
3
<h2 >{{ formatMessage(messages.subscriptionTitle) }}</h2 >
4
4
<p >{{ formatMessage(messages.subscriptionDescription) }}</p >
5
5
<div class =" universal-card recessed" >
88
88
v-if =" midasCharge && midasCharge.status === 'failed'"
89
89
class =" ml-auto flex flex-row-reverse items-center gap-2"
90
90
>
91
+ <ButtonStyled v-if =" midasCharge && midasCharge.status === 'failed'" >
92
+ <button
93
+ @click ="
94
+ () => {
95
+ $refs.midasPurchaseModal.show();
96
+ }
97
+ "
98
+ >
99
+ <UpdatedIcon />
100
+ Update method
101
+ </button >
102
+ </ButtonStyled >
103
+ <ButtonStyled type =" transparent" circular >
104
+ <OverflowMenu
105
+ :dropdown-id =" `${baseId}-cancel-midas`"
106
+ :options =" [
107
+ {
108
+ id: 'cancel',
109
+ action: () => {
110
+ cancelSubscriptionId = midasSubscription.id;
111
+ $refs.modalCancel.show();
112
+ },
113
+ },
114
+ ]"
115
+ >
116
+ <MoreVerticalIcon />
117
+ <template #cancel ><XIcon /> Cancel</template >
118
+ </OverflowMenu >
119
+ </ButtonStyled >
120
+ </div >
121
+ <ButtonStyled v-else-if =" midasCharge && midasCharge.status !== 'cancelled'" >
91
122
<button
92
- v-if =" midasCharge && midasCharge.status === 'failed'"
93
- class =" iconified-button raised-button"
123
+ class =" ml-auto"
94
124
@click ="
95
125
() => {
96
- purchaseModalStep = 0 ;
97
- $refs.purchaseModal .show();
126
+ cancelSubscriptionId = midasSubscription.id ;
127
+ $refs.modalCancel .show();
98
128
}
99
129
"
100
130
>
101
- <UpdatedIcon />
102
- Update method
131
+ <XIcon /> Cancel
103
132
</button >
104
- <OverflowMenu
105
- class =" btn icon-only transparent"
106
- :options =" [
107
- {
108
- id: 'cancel',
109
- action: () => {
110
- cancelSubscriptionId = midasSubscription.id;
111
- $refs.modalCancel.show();
112
- },
113
- },
114
- ]"
115
- >
116
- <MoreVerticalIcon />
117
- <template #cancel ><XIcon /> Cancel</template >
118
- </OverflowMenu >
119
- </div >
120
- <button
121
- v-else-if =" midasCharge && midasCharge.status !== 'cancelled'"
122
- class =" iconified-button raised-button !ml-auto"
123
- @click ="
124
- () => {
125
- cancelSubscriptionId = midasSubscription.id;
126
- $refs.modalCancel.show();
127
- }
128
- "
129
- >
130
- <XIcon /> Cancel
131
- </button >
132
- <button
133
+ </ButtonStyled >
134
+ <ButtonStyled
133
135
v-else-if =" midasCharge && midasCharge.status === 'cancelled'"
134
- class =" btn btn-purple btn-large ml-auto"
135
- @click =" cancelSubscription(midasSubscription.id, false)"
136
+ color =" purple"
136
137
>
137
- <RightArrowIcon /> Resubscribe
138
- </button >
139
- <button
140
- v-else
141
- class =" btn btn-purple btn-large ml-auto"
142
- @click ="
143
- () => {
144
- purchaseModalStep = 0;
145
- $refs.purchaseModal.show();
146
- }
147
- "
148
- >
149
- <RightArrowIcon />
150
- Subscribe
151
- </button >
138
+ <button class =" ml-auto" @click =" cancelSubscription(midasSubscription.id, false)" >
139
+ Resubscribe <RightArrowIcon />
140
+ </button >
141
+ </ButtonStyled >
142
+ <ButtonStyled v-else color =" purple" size =" large" >
143
+ <button
144
+ class =" ml-auto"
145
+ @click ="
146
+ () => {
147
+ $refs.midasPurchaseModal.show();
148
+ }
149
+ "
150
+ >
151
+ Subscribe <RightArrowIcon />
152
+ </button >
153
+ </ButtonStyled >
152
154
</div >
153
155
</div >
154
156
</div >
282
284
getPyroCharge(subscription).status !== 'cancelled' &&
283
285
getPyroCharge(subscription).status !== 'failed'
284
286
"
285
- type =" standard"
286
- @click =" showPyroCancelModal(subscription.id)"
287
287
>
288
- <button class = " text-contrast " >
288
+ <button @click = " showPyroCancelModal(subscription.id) " >
289
289
<XIcon />
290
290
Cancel
291
291
</button >
292
292
</ButtonStyled >
293
+ <ButtonStyled
294
+ v-if ="
295
+ getPyroCharge(subscription) &&
296
+ getPyroCharge(subscription).status !== 'cancelled' &&
297
+ getPyroCharge(subscription).status !== 'failed'
298
+ "
299
+ color =" green"
300
+ color-fill =" text"
301
+ >
302
+ <button @click =" showPyroUpgradeModal(subscription)" >
303
+ <ArrowBigUpDashIcon />
304
+ Upgrade
305
+ </button >
306
+ </ButtonStyled >
293
307
<ButtonStyled
294
308
v-else-if ="
295
309
getPyroCharge(subscription) &&
296
310
(getPyroCharge(subscription).status === 'cancelled' ||
297
311
getPyroCharge(subscription).status === 'failed')
298
312
"
299
- type =" standard"
300
313
color =" green"
301
- @click =" resubscribePyro(subscription.id)"
302
314
>
303
- <button class =" text-contrast" >Resubscribe</button >
315
+ <button @click =" resubscribePyro(subscription.id)" >
316
+ Resubscribe <RightArrowIcon />
317
+ </button >
304
318
</ButtonStyled >
305
319
</div >
306
320
</div >
312
326
</div >
313
327
</section >
314
328
315
- <section class =" universal-card" >
329
+ <section class =" universal-card experimental-styles-within " >
316
330
<ConfirmModal
317
331
ref =" modal_confirm"
318
332
:title =" formatMessage(deleteModalMessages.title)"
321
335
@proceed =" removePaymentMethod(removePaymentMethodIndex)"
322
336
/>
323
337
<PurchaseModal
324
- ref =" purchaseModal "
338
+ ref =" midasPurchaseModal "
325
339
:product =" midasProduct"
326
340
:country =" country"
327
341
:publishable-key =" config.public.stripePublishableKey"
342
356
:payment-methods =" paymentMethods"
343
357
:return-url =" `${config.public.siteUrl}/settings/billing`"
344
358
/>
359
+ <PurchaseModal
360
+ ref =" pyroPurchaseModal"
361
+ :product =" upgradeProducts"
362
+ :country =" country"
363
+ custom-server
364
+ :existing-subscription =" currentSubscription"
365
+ :existing-plan =" currentProduct"
366
+ :publishable-key =" config.public.stripePublishableKey"
367
+ :send-billing-request ="
368
+ async (body) =>
369
+ await useBaseFetch(`billing/subscription/${currentSubscription.id}`, {
370
+ internal: true,
371
+ method: `PATCH`,
372
+ body: body,
373
+ })
374
+ "
375
+ :renewal-date =" currentSubRenewalDate"
376
+ :on-error ="
377
+ (err) =>
378
+ data.$notify({
379
+ group: 'main',
380
+ title: 'An error occurred',
381
+ type: 'error',
382
+ text: err.message ?? (err.data ? err.data.description : err),
383
+ })
384
+ "
385
+ :customer =" customer"
386
+ :payment-methods =" paymentMethods"
387
+ :return-url =" `${config.public.siteUrl}/servers/manage`"
388
+ :server-name =" `${auth?.user?.username}'s server`"
389
+ />
345
390
<NewModal ref =" addPaymentMethodModal" >
346
391
<template #title >
347
392
<span class =" text-lg font-extrabold text-contrast" >
359
404
<div id =" address-element" ></div >
360
405
<div id =" payment-element" class =" mt-4" ></div >
361
406
</div >
362
- <div v-show =" loadingPaymentMethodModal === 2" class =" input-group push-right mt-auto pt-4" >
363
- <button class =" btn" @click =" $refs.addPaymentMethodModal.hide()" >
364
- <XIcon />
365
- {{ formatMessage(commonMessages.cancelButton) }}
366
- </button >
367
- <button class =" btn btn-primary" :disabled =" loadingAddMethod" @click =" submit" >
368
- <PlusIcon />
369
- {{ formatMessage(messages.paymentMethodAdd) }}
370
- </button >
407
+ <div v-show =" loadingPaymentMethodModal === 2" class =" input-group mt-auto pt-4" >
408
+ <ButtonStyled color =" brand" >
409
+ <button :disabled =" loadingAddMethod" @click =" submit" >
410
+ <PlusIcon />
411
+ {{ formatMessage(messages.paymentMethodAdd) }}
412
+ </button >
413
+ </ButtonStyled >
414
+ <ButtonStyled >
415
+ <button @click =" $refs.addPaymentMethodModal.hide()" >
416
+ <XIcon />
417
+ {{ formatMessage(commonMessages.cancelButton) }}
418
+ </button >
419
+ </ButtonStyled >
371
420
</div >
372
421
</div >
373
422
</NewModal >
442
491
</div >
443
492
</div >
444
493
<OverflowMenu
494
+ :dropdown-id =" `${baseId}-payment-method-overflow-${index}`"
445
495
class =" btn icon-only transparent"
446
496
:options ="
447
497
[
@@ -493,6 +543,7 @@ import {
493
543
} from " @modrinth/ui" ;
494
544
import {
495
545
PlusIcon ,
546
+ ArrowBigUpDashIcon ,
496
547
XIcon ,
497
548
CardIcon ,
498
549
MoreVerticalIcon ,
@@ -515,6 +566,9 @@ definePageMeta({
515
566
middleware: " auth" ,
516
567
});
517
568
569
+ const auth = await useAuth ();
570
+ const baseId = useId ();
571
+
518
572
useHead ({
519
573
script: [
520
574
{
@@ -704,7 +758,7 @@ const pyroSubscriptions = computed(() => {
704
758
});
705
759
});
706
760
707
- const purchaseModal = ref ();
761
+ const midasPurchaseModal = ref ();
708
762
const country = useUserCountry ();
709
763
const price = computed (() =>
710
764
midasProduct .value ? .prices ? .find ((x ) => x .currency_code === getCurrency (country .value )),
@@ -896,6 +950,46 @@ const showPyroCancelModal = (subscriptionId) => {
896
950
}
897
951
};
898
952
953
+ const pyroPurchaseModal = ref ();
954
+ const currentSubscription = ref (null );
955
+ const currentProduct = ref (null );
956
+ const upgradeProducts = ref ([]);
957
+ upgradeProducts .value .metadata = { type: " pyro" };
958
+
959
+ const currentSubRenewalDate = ref ();
960
+
961
+ const showPyroUpgradeModal = async (subscription ) => {
962
+ currentSubscription .value = subscription;
963
+ currentSubRenewalDate .value = getPyroCharge (subscription).due ;
964
+ currentProduct .value = getPyroProduct (subscription);
965
+ upgradeProducts .value = products .filter (
966
+ (p ) =>
967
+ p .metadata .type === " pyro" &&
968
+ (! currentProduct .value || p .metadata .ram > currentProduct .value .metadata .ram ),
969
+ );
970
+ upgradeProducts .value .metadata = { type: " pyro" };
971
+
972
+ await nextTick ();
973
+
974
+ if (! currentProduct .value ) {
975
+ console .error (" Could not find product for current subscription" );
976
+ data .$notify ({
977
+ group: " main" ,
978
+ title: " An error occurred" ,
979
+ text: " Could not find product for current subscription" ,
980
+ type: " error" ,
981
+ });
982
+ return ;
983
+ }
984
+
985
+ if (! pyroPurchaseModal .value ) {
986
+ console .error (" pyroPurchaseModal ref is undefined" );
987
+ return ;
988
+ }
989
+
990
+ pyroPurchaseModal .value .show ();
991
+ };
992
+
899
993
const resubscribePyro = async (subscriptionId ) => {
900
994
try {
901
995
await useBaseFetch (` billing/subscription/${ subscriptionId} ` , {
0 commit comments