@tapni/auth 1.0.73 → 1.0.74
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.vite/manifest.json +8 -8
- package/dist/{Apps-Dys7WVIh.js → Apps-Ca-YMuAn.js} +1 -1
- package/dist/{CustomApp-tARqhmAA.js → CustomApp-C6PBysID.js} +1 -1
- package/dist/{QR-NKmxwqC3.js → QR-DWC2Q2sk.js} +1 -1
- package/dist/TapniAuth.es.js +1 -1
- package/dist/TapniAuth.umd.js +25 -25
- package/dist/{install-BIhtHWTM.js → install-C1jLtDf_.js} +6444 -6220
- package/dist/style.css +1 -1
- package/package.json +2 -1
- package/src/services/AuthService.js +3 -0
- package/src/store/auth.js +13 -25
- package/src/views/Billing.vue +578 -67
package/src/views/Billing.vue
CHANGED
|
@@ -36,74 +36,177 @@
|
|
|
36
36
|
<p class="center-text">{{ssoLang[appLanguage].billing_p }}</p>
|
|
37
37
|
|
|
38
38
|
<div class="full-top">
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
<section class="billing-section">
|
|
40
|
+
<div class="section-heading">
|
|
41
|
+
<h3 class="section-title">Subscriptions</h3>
|
|
42
|
+
</div>
|
|
43
|
+
|
|
44
|
+
<div v-if="subscriptions.length === 0" class="no-subscriptions center-text full-top">
|
|
45
|
+
<p class="gray-text">There are no active subscriptions at this point.</p>
|
|
46
|
+
</div>
|
|
43
47
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
</
|
|
48
|
+
<div v-else>
|
|
49
|
+
<div v-for="sub in subscriptions" :key="sub.subscriptionId" class="subscription-card half-bottom">
|
|
50
|
+
<div class="subscription-header">
|
|
51
|
+
<div class="subscription-info">
|
|
52
|
+
<h3 class="subscription-name">{{ sub.subscriptionName }}</h3>
|
|
53
|
+
<span class="subscription-status" :class="getStatusClass(sub.status)">
|
|
54
|
+
{{ getStatusText(sub.status) }}
|
|
55
|
+
</span>
|
|
56
|
+
</div>
|
|
53
57
|
</div>
|
|
54
|
-
</div>
|
|
55
58
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
59
|
+
<div class="subscription-details">
|
|
60
|
+
<div class="detail-row">
|
|
61
|
+
<span class="detail-label">Amount:</span>
|
|
62
|
+
<span class="detail-value">{{ formatCurrency(sub.amount, sub.currency) }}</span>
|
|
63
|
+
</div>
|
|
64
|
+
<div class="detail-row">
|
|
65
|
+
<span class="detail-label">Billing:</span>
|
|
66
|
+
<span class="detail-value">{{ formatInterval(sub.interval) }}</span>
|
|
67
|
+
</div>
|
|
68
|
+
<div class="detail-row">
|
|
69
|
+
<span class="detail-label">Licenses:</span>
|
|
70
|
+
<span class="detail-value">{{ sub.licenses }}</span>
|
|
71
|
+
</div>
|
|
72
|
+
<div v-if="sub.isTrial" class="detail-row">
|
|
73
|
+
<span class="detail-label">Trial Ends:</span>
|
|
74
|
+
<span class="detail-value">{{ formatDate(sub.trialEnd) }}</span>
|
|
75
|
+
</div>
|
|
76
|
+
<div v-else-if="sub.endDate" class="detail-row">
|
|
77
|
+
<span class="detail-label">Next Billing:</span>
|
|
78
|
+
<span class="detail-value">{{ formatDate(sub.endDate) }}</span>
|
|
79
|
+
</div>
|
|
60
80
|
</div>
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
<
|
|
81
|
+
|
|
82
|
+
<div class="subscription-actions">
|
|
83
|
+
<button
|
|
84
|
+
v-if="sub.status === 'canceled' || sub.status === 'expired'"
|
|
85
|
+
@click="resubscribe(sub)"
|
|
86
|
+
class="resubscribe-button"
|
|
87
|
+
:disabled="loading"
|
|
88
|
+
>
|
|
89
|
+
{{ loading ? 'Processing...' : 'Re-Subscribe' }}
|
|
90
|
+
</button>
|
|
91
|
+
<button
|
|
92
|
+
v-if="sub.status === 'past_due' || sub.status === 'unpaid'"
|
|
93
|
+
@click="retryPayment(sub)"
|
|
94
|
+
class="pay-now-button"
|
|
95
|
+
:disabled="loading"
|
|
96
|
+
>
|
|
97
|
+
{{ loading ? 'Processing...' : 'Pay Now' }}
|
|
98
|
+
</button>
|
|
99
|
+
<button
|
|
100
|
+
v-if="sub.status !== 'canceled' && sub.status !== 'expired' && sub.status !== 'past_due' && sub.status !== 'unpaid'"
|
|
101
|
+
@click="openCancelModal(sub)"
|
|
102
|
+
class="cancel-button"
|
|
103
|
+
:disabled="loading"
|
|
104
|
+
>
|
|
105
|
+
{{ loading ? 'Processing...' : 'Cancel Subscription' }}
|
|
106
|
+
</button>
|
|
64
107
|
</div>
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
108
|
+
</div>
|
|
109
|
+
</div>
|
|
110
|
+
</section>
|
|
111
|
+
|
|
112
|
+
<section class="billing-section orders-section">
|
|
113
|
+
<div class="section-heading">
|
|
114
|
+
<h3 class="section-title">Orders</h3>
|
|
115
|
+
<span v-if="orders.length" class="section-caption">{{ orders.length }} found</span>
|
|
116
|
+
</div>
|
|
117
|
+
|
|
118
|
+
<div v-if="ordersLoading" class="no-subscriptions center-text full-top">
|
|
119
|
+
<p class="gray-text">Loading your orders...</p>
|
|
120
|
+
</div>
|
|
121
|
+
|
|
122
|
+
<div v-else-if="orders.length === 0" class="no-subscriptions center-text full-top">
|
|
123
|
+
<p class="gray-text">No orders found for this account yet.</p>
|
|
124
|
+
</div>
|
|
125
|
+
|
|
126
|
+
<div v-else>
|
|
127
|
+
<div v-for="order in orders" :key="order.id" class="subscription-card order-card half-bottom">
|
|
128
|
+
<div class="subscription-header order-header">
|
|
129
|
+
<div class="subscription-info">
|
|
130
|
+
<h3 class="subscription-name">{{ order.orderNumber || order.orderId }}</h3>
|
|
131
|
+
<div class="order-meta">
|
|
132
|
+
<span class="order-date">{{ formatDateValue(order.createdAt) }}</span>
|
|
133
|
+
<span class="order-source">{{ formatSource(order.source) }}</span>
|
|
134
|
+
</div>
|
|
135
|
+
</div>
|
|
136
|
+
|
|
137
|
+
<div class="order-badges">
|
|
138
|
+
<span class="subscription-status" :class="getOrderStateClass(order.status)">
|
|
139
|
+
{{ formatOrderState(order.status, order.isDraft, order.canceled) }}
|
|
140
|
+
</span>
|
|
141
|
+
<span v-if="order.paymentStatus" class="subscription-status" :class="getPaymentStatusClass(order.paymentStatus)">
|
|
142
|
+
{{ formatPaymentStatus(order.paymentStatus) }}
|
|
143
|
+
</span>
|
|
144
|
+
<span v-if="order.fulfillmentStatus" class="subscription-status" :class="getFulfillmentStatusClass(order.fulfillmentStatus)">
|
|
145
|
+
{{ formatFulfillmentStatus(order.fulfillmentStatus) }}
|
|
146
|
+
</span>
|
|
147
|
+
</div>
|
|
68
148
|
</div>
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
<
|
|
149
|
+
|
|
150
|
+
<div class="subscription-details order-grid">
|
|
151
|
+
<div class="detail-row">
|
|
152
|
+
<span class="detail-label">Total:</span>
|
|
153
|
+
<span class="detail-value">{{ formatCurrency(order.total, order.currency) }}</span>
|
|
154
|
+
</div>
|
|
155
|
+
<div class="detail-row">
|
|
156
|
+
<span class="detail-label">Subtotal:</span>
|
|
157
|
+
<span class="detail-value">{{ formatCurrency(order.subtotal, order.currency) }}</span>
|
|
158
|
+
</div>
|
|
159
|
+
<div class="detail-row">
|
|
160
|
+
<span class="detail-label">Discount:</span>
|
|
161
|
+
<span class="detail-value">{{ formatSignedCurrency(order.discountAmount, order.currency) }}</span>
|
|
162
|
+
</div>
|
|
163
|
+
<div class="detail-row">
|
|
164
|
+
<span class="detail-label">Tax:</span>
|
|
165
|
+
<span class="detail-value">{{ formatCurrency(order.taxAmount, order.currency) }}</span>
|
|
166
|
+
</div>
|
|
167
|
+
<div class="detail-row">
|
|
168
|
+
<span class="detail-label">Shipping:</span>
|
|
169
|
+
<span class="detail-value">{{ order.shippingMethod || 'Not specified' }}</span>
|
|
170
|
+
</div>
|
|
171
|
+
<div class="detail-row">
|
|
172
|
+
<span class="detail-label">Invoice:</span>
|
|
173
|
+
<span class="detail-value">{{ order.invoiceStatus || 'Not available' }}</span>
|
|
174
|
+
</div>
|
|
72
175
|
</div>
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
<
|
|
176
|
+
|
|
177
|
+
<div v-if="order.items?.length" class="order-items">
|
|
178
|
+
<h4 class="subsection-title">Items</h4>
|
|
179
|
+
<div v-for="(item, index) in order.items" :key="`${order.id}-${index}`" class="order-item-row">
|
|
180
|
+
<span class="detail-label">{{ item.name || item.sku || 'Item' }} x{{ item.quantity }}</span>
|
|
181
|
+
<span class="detail-value">{{ formatCurrency(item.price * item.quantity, order.currency) }}</span>
|
|
182
|
+
</div>
|
|
76
183
|
</div>
|
|
77
|
-
</div>
|
|
78
184
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
class="
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
v-if="
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
>
|
|
102
|
-
{{ loading ? 'Processing...' : 'Cancel Subscription' }}
|
|
103
|
-
</button>
|
|
185
|
+
<div class="order-addresses" v-if="order.billingAddress || order.shippingAddress">
|
|
186
|
+
<div v-if="order.billingAddress" class="address-card">
|
|
187
|
+
<h4 class="subsection-title">Billing Address</h4>
|
|
188
|
+
<p class="address-line">{{ formatAddress(order.billingAddress) }}</p>
|
|
189
|
+
</div>
|
|
190
|
+
<div v-if="order.shippingAddress" class="address-card">
|
|
191
|
+
<h4 class="subsection-title">Shipping Address</h4>
|
|
192
|
+
<p class="address-line">{{ formatAddress(order.shippingAddress) }}</p>
|
|
193
|
+
</div>
|
|
194
|
+
</div>
|
|
195
|
+
|
|
196
|
+
<div class="subscription-actions order-actions">
|
|
197
|
+
<a v-if="order.invoiceUrl" :href="order.invoiceUrl" target="_blank" rel="noopener noreferrer" class="resubscribe-button button-link">
|
|
198
|
+
View Invoice
|
|
199
|
+
</a>
|
|
200
|
+
<a v-if="order.designerUrl" :href="order.designerUrl" target="_blank" rel="noopener noreferrer" class="pay-now-button button-link">
|
|
201
|
+
Open Order
|
|
202
|
+
</a>
|
|
203
|
+
<a v-if="order.orderStatusUrl" :href="order.orderStatusUrl" target="_blank" rel="noopener noreferrer" class="cancel-button button-link">
|
|
204
|
+
Order Status
|
|
205
|
+
</a>
|
|
206
|
+
</div>
|
|
104
207
|
</div>
|
|
105
208
|
</div>
|
|
106
|
-
</
|
|
209
|
+
</section>
|
|
107
210
|
</div>
|
|
108
211
|
</div>
|
|
109
212
|
|
|
@@ -153,6 +256,7 @@
|
|
|
153
256
|
import AuthMixin from "../mixins/auth.mixin";
|
|
154
257
|
import {EventBus} from "@/store/event-bus.js";
|
|
155
258
|
import api from "@/services/Api.js";
|
|
259
|
+
import AuthService from "@/services/AuthService.js";
|
|
156
260
|
|
|
157
261
|
export default {
|
|
158
262
|
name: "AuthBilling",
|
|
@@ -167,6 +271,8 @@ export default {
|
|
|
167
271
|
return {
|
|
168
272
|
loading: false,
|
|
169
273
|
subscriptions: [],
|
|
274
|
+
orders: [],
|
|
275
|
+
ordersLoading: false,
|
|
170
276
|
showCancelModal: false,
|
|
171
277
|
selectedSubscription: null,
|
|
172
278
|
cancelFeedback: ''
|
|
@@ -174,13 +280,17 @@ export default {
|
|
|
174
280
|
},
|
|
175
281
|
async mounted() {
|
|
176
282
|
if (!this.isLoggedIn) this.$router.push('/login');
|
|
177
|
-
await this.
|
|
178
|
-
this.loadSubscriptions();
|
|
283
|
+
await this.refreshBillingData();
|
|
179
284
|
},
|
|
180
285
|
methods: {
|
|
181
286
|
close () {
|
|
182
287
|
EventBus.$emit('ssoEvent', {name: 'toggleAuthModal', data: true})
|
|
183
288
|
},
|
|
289
|
+
async refreshBillingData() {
|
|
290
|
+
await this.getAccountSettings();
|
|
291
|
+
this.loadSubscriptions();
|
|
292
|
+
await this.loadOrders();
|
|
293
|
+
},
|
|
184
294
|
loadSubscriptions() {
|
|
185
295
|
// Extract subscriptions from account.billing
|
|
186
296
|
if (this.account.billing) {
|
|
@@ -195,6 +305,26 @@ export default {
|
|
|
195
305
|
}
|
|
196
306
|
|
|
197
307
|
this.subscriptions = subs;
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
this.subscriptions = [];
|
|
312
|
+
},
|
|
313
|
+
async loadOrders() {
|
|
314
|
+
this.ordersLoading = true;
|
|
315
|
+
|
|
316
|
+
try {
|
|
317
|
+
const response = await AuthService.getAccountOrders({ limit: 25 });
|
|
318
|
+
this.orders = response?.data?.data || [];
|
|
319
|
+
} catch (error) {
|
|
320
|
+
console.error('Error loading account orders:', error);
|
|
321
|
+
this.orders = [];
|
|
322
|
+
EventBus.$emit('showToast', {
|
|
323
|
+
type: 'error',
|
|
324
|
+
message: error.response?.data?.error || 'Failed to load orders.'
|
|
325
|
+
});
|
|
326
|
+
} finally {
|
|
327
|
+
this.ordersLoading = false;
|
|
198
328
|
}
|
|
199
329
|
},
|
|
200
330
|
formatCurrency(amount, currency) {
|
|
@@ -204,7 +334,11 @@ export default {
|
|
|
204
334
|
'GBP': '£'
|
|
205
335
|
};
|
|
206
336
|
const symbol = currencySymbols[currency?.toUpperCase()] || currency || '';
|
|
207
|
-
return `${symbol}${amount
|
|
337
|
+
return `${symbol}${Number(amount || 0).toFixed(2)}`;
|
|
338
|
+
},
|
|
339
|
+
formatSignedCurrency(amount, currency) {
|
|
340
|
+
const numericAmount = Number(amount || 0);
|
|
341
|
+
return numericAmount > 0 ? `-${this.formatCurrency(numericAmount, currency)}` : this.formatCurrency(numericAmount, currency);
|
|
208
342
|
},
|
|
209
343
|
formatInterval(interval) {
|
|
210
344
|
return interval ? `per ${interval}` : '';
|
|
@@ -214,6 +348,18 @@ export default {
|
|
|
214
348
|
const date = new Date(timestamp * 1000);
|
|
215
349
|
return date.toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric' });
|
|
216
350
|
},
|
|
351
|
+
formatDateValue(value) {
|
|
352
|
+
if (!value) return '';
|
|
353
|
+
const date = new Date(value);
|
|
354
|
+
if (Number.isNaN(date.getTime())) return '';
|
|
355
|
+
return date.toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric' });
|
|
356
|
+
},
|
|
357
|
+
formatSource(source) {
|
|
358
|
+
if (!source) return 'Unknown source';
|
|
359
|
+
if (source.includes('myshopify.com')) return 'Shopify';
|
|
360
|
+
if (source === 'tapstack.erp') return 'Tapstack';
|
|
361
|
+
return source;
|
|
362
|
+
},
|
|
217
363
|
getStatusText(status) {
|
|
218
364
|
const statusMap = {
|
|
219
365
|
'trialing': 'Trial',
|
|
@@ -228,6 +374,45 @@ export default {
|
|
|
228
374
|
getStatusClass(status) {
|
|
229
375
|
return `status-${status}`;
|
|
230
376
|
},
|
|
377
|
+
getOrderStateClass(status) {
|
|
378
|
+
return `status-${String(status || 'created').toLowerCase().replace(/_/g, '-')}`;
|
|
379
|
+
},
|
|
380
|
+
getPaymentStatusClass(status) {
|
|
381
|
+
return `status-${String(status || '').toLowerCase().replace(/_/g, '-')}`;
|
|
382
|
+
},
|
|
383
|
+
getFulfillmentStatusClass(status) {
|
|
384
|
+
return `status-${String(status || '').toLowerCase().replace(/_/g, '-')}`;
|
|
385
|
+
},
|
|
386
|
+
formatOrderState(status, isDraft, canceled) {
|
|
387
|
+
if (canceled) return 'Canceled';
|
|
388
|
+
if (isDraft) return 'Draft';
|
|
389
|
+
return this.formatStatusLabel(status || 'created');
|
|
390
|
+
},
|
|
391
|
+
formatPaymentStatus(status) {
|
|
392
|
+
return this.formatStatusLabel(status);
|
|
393
|
+
},
|
|
394
|
+
formatFulfillmentStatus(status) {
|
|
395
|
+
return this.formatStatusLabel(status);
|
|
396
|
+
},
|
|
397
|
+
formatStatusLabel(status) {
|
|
398
|
+
return String(status || '')
|
|
399
|
+
.replace(/_/g, ' ')
|
|
400
|
+
.replace(/\b\w/g, (char) => char.toUpperCase());
|
|
401
|
+
},
|
|
402
|
+
formatAddress(address) {
|
|
403
|
+
if (!address) return '';
|
|
404
|
+
return [
|
|
405
|
+
address.name,
|
|
406
|
+
address.email,
|
|
407
|
+
address.company,
|
|
408
|
+
address.line1,
|
|
409
|
+
address.line2,
|
|
410
|
+
[address.postalCode, address.city].filter(Boolean).join(' '),
|
|
411
|
+
address.state,
|
|
412
|
+
address.country,
|
|
413
|
+
address.phone
|
|
414
|
+
].filter(Boolean).join(', ');
|
|
415
|
+
},
|
|
231
416
|
openCancelModal(subscription) {
|
|
232
417
|
this.selectedSubscription = subscription;
|
|
233
418
|
this.showCancelModal = true;
|
|
@@ -275,8 +460,7 @@ export default {
|
|
|
275
460
|
});
|
|
276
461
|
|
|
277
462
|
// Refresh account settings to get updated billing info
|
|
278
|
-
await this.
|
|
279
|
-
this.loadSubscriptions();
|
|
463
|
+
await this.refreshBillingData();
|
|
280
464
|
|
|
281
465
|
// Close modal
|
|
282
466
|
this.closeCancelModal();
|
|
@@ -307,8 +491,7 @@ export default {
|
|
|
307
491
|
const response = await api(false, 'v2').post('checkout/resubscribe/' + sub.subscriptionId);
|
|
308
492
|
if (response.data.success) {
|
|
309
493
|
EventBus.$emit('showToast', { type: 'success', message: response.data.message || 'Subscription reactivated successfully' });
|
|
310
|
-
await this.
|
|
311
|
-
this.loadSubscriptions();
|
|
494
|
+
await this.refreshBillingData();
|
|
312
495
|
if (response.data.clientSecret) {
|
|
313
496
|
EventBus.$emit('ssoEvent', { name: 'resubscribePaymentRequired', data: { clientSecret: response.data.clientSecret } });
|
|
314
497
|
}
|
|
@@ -332,8 +515,7 @@ export default {
|
|
|
332
515
|
const data = response.data;
|
|
333
516
|
if (data.paid) {
|
|
334
517
|
EventBus.$emit('showToast', { type: 'success', message: data.message || 'Payment successful' });
|
|
335
|
-
await this.
|
|
336
|
-
this.loadSubscriptions();
|
|
518
|
+
await this.refreshBillingData();
|
|
337
519
|
} else if (data.hostedInvoiceUrl) {
|
|
338
520
|
window.open(data.hostedInvoiceUrl, '_blank', 'noopener,noreferrer');
|
|
339
521
|
EventBus.$emit('showToast', { type: 'info', message: data.message || 'Please complete payment in the opened window.' });
|
|
@@ -353,6 +535,335 @@ export default {
|
|
|
353
535
|
};
|
|
354
536
|
</script>
|
|
355
537
|
|
|
356
|
-
<style>
|
|
538
|
+
<style scoped>
|
|
539
|
+
.billing-section {
|
|
540
|
+
margin-top: 24px;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
.section-heading {
|
|
544
|
+
display: flex;
|
|
545
|
+
align-items: center;
|
|
546
|
+
justify-content: space-between;
|
|
547
|
+
margin-bottom: 14px;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
.section-title {
|
|
551
|
+
margin: 0;
|
|
552
|
+
font-size: 18px;
|
|
553
|
+
font-weight: 600;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
.section-caption {
|
|
557
|
+
color: #7d7d7d;
|
|
558
|
+
font-size: 13px;
|
|
559
|
+
}
|
|
357
560
|
|
|
561
|
+
.subscription-card {
|
|
562
|
+
background: #ffffff;
|
|
563
|
+
border: 1px solid #ececec;
|
|
564
|
+
border-radius: 18px;
|
|
565
|
+
padding: 18px;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
.subscription-header {
|
|
569
|
+
display: flex;
|
|
570
|
+
justify-content: space-between;
|
|
571
|
+
gap: 16px;
|
|
572
|
+
align-items: flex-start;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
.subscription-info {
|
|
576
|
+
display: flex;
|
|
577
|
+
flex-direction: column;
|
|
578
|
+
gap: 8px;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
.subscription-name {
|
|
582
|
+
margin: 0;
|
|
583
|
+
font-size: 18px;
|
|
584
|
+
font-weight: 600;
|
|
585
|
+
color: #111111;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
.subscription-status {
|
|
589
|
+
display: inline-flex;
|
|
590
|
+
align-items: center;
|
|
591
|
+
width: fit-content;
|
|
592
|
+
padding: 6px 10px;
|
|
593
|
+
border-radius: 999px;
|
|
594
|
+
font-size: 12px;
|
|
595
|
+
font-weight: 600;
|
|
596
|
+
background: #f1f5f9;
|
|
597
|
+
color: #334155;
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
.subscription-details {
|
|
601
|
+
margin-top: 16px;
|
|
602
|
+
display: grid;
|
|
603
|
+
gap: 10px;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
.detail-row {
|
|
607
|
+
display: flex;
|
|
608
|
+
justify-content: space-between;
|
|
609
|
+
gap: 16px;
|
|
610
|
+
align-items: flex-start;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
.detail-label {
|
|
614
|
+
color: #6b7280;
|
|
615
|
+
font-size: 14px;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
.detail-value {
|
|
619
|
+
color: #111111;
|
|
620
|
+
font-size: 14px;
|
|
621
|
+
text-align: right;
|
|
622
|
+
word-break: break-word;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
.subscription-actions {
|
|
626
|
+
margin-top: 18px;
|
|
627
|
+
display: flex;
|
|
628
|
+
flex-wrap: wrap;
|
|
629
|
+
gap: 10px;
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
.cancel-button,
|
|
633
|
+
.resubscribe-button,
|
|
634
|
+
.pay-now-button,
|
|
635
|
+
.button-secondary,
|
|
636
|
+
.button-danger {
|
|
637
|
+
border: 0;
|
|
638
|
+
border-radius: 999px;
|
|
639
|
+
padding: 10px 16px;
|
|
640
|
+
font-size: 14px;
|
|
641
|
+
font-weight: 600;
|
|
642
|
+
cursor: pointer;
|
|
643
|
+
transition: opacity 0.2s ease;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
.cancel-button:disabled,
|
|
647
|
+
.resubscribe-button:disabled,
|
|
648
|
+
.pay-now-button:disabled,
|
|
649
|
+
.button-secondary:disabled,
|
|
650
|
+
.button-danger:disabled {
|
|
651
|
+
opacity: 0.6;
|
|
652
|
+
cursor: not-allowed;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
.cancel-button,
|
|
656
|
+
.button-secondary {
|
|
657
|
+
background: #111111;
|
|
658
|
+
color: #ffffff;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
.resubscribe-button {
|
|
662
|
+
background: #111111;
|
|
663
|
+
color: #ffffff;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
.pay-now-button,
|
|
667
|
+
.button-danger {
|
|
668
|
+
background: #0f766e;
|
|
669
|
+
color: #ffffff;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
.button-link {
|
|
673
|
+
text-decoration: none;
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
.order-card {
|
|
677
|
+
background: #fafafa;
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
.order-header {
|
|
681
|
+
align-items: center;
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
.order-meta {
|
|
685
|
+
display: flex;
|
|
686
|
+
flex-wrap: wrap;
|
|
687
|
+
gap: 8px;
|
|
688
|
+
color: #6b7280;
|
|
689
|
+
font-size: 13px;
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
.order-source {
|
|
693
|
+
text-transform: capitalize;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
.order-badges {
|
|
697
|
+
display: flex;
|
|
698
|
+
flex-wrap: wrap;
|
|
699
|
+
justify-content: flex-end;
|
|
700
|
+
gap: 8px;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
.order-grid {
|
|
704
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
.order-items,
|
|
708
|
+
.order-addresses {
|
|
709
|
+
margin-top: 18px;
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
.subsection-title {
|
|
713
|
+
margin: 0 0 10px 0;
|
|
714
|
+
font-size: 14px;
|
|
715
|
+
font-weight: 600;
|
|
716
|
+
color: #111111;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
.order-item-row {
|
|
720
|
+
display: flex;
|
|
721
|
+
justify-content: space-between;
|
|
722
|
+
gap: 16px;
|
|
723
|
+
padding: 8px 0;
|
|
724
|
+
border-top: 1px solid #ececec;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
.order-item-row:first-of-type {
|
|
728
|
+
border-top: 0;
|
|
729
|
+
padding-top: 0;
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
.order-addresses {
|
|
733
|
+
display: grid;
|
|
734
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
735
|
+
gap: 14px;
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
.address-card {
|
|
739
|
+
background: #ffffff;
|
|
740
|
+
border: 1px solid #ececec;
|
|
741
|
+
border-radius: 14px;
|
|
742
|
+
padding: 14px;
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
.address-line {
|
|
746
|
+
margin: 0;
|
|
747
|
+
color: #374151;
|
|
748
|
+
font-size: 14px;
|
|
749
|
+
line-height: 1.5;
|
|
750
|
+
word-break: break-word;
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
.modal-overlay {
|
|
754
|
+
position: fixed;
|
|
755
|
+
inset: 0;
|
|
756
|
+
background: rgba(17, 17, 17, 0.5);
|
|
757
|
+
display: flex;
|
|
758
|
+
align-items: center;
|
|
759
|
+
justify-content: center;
|
|
760
|
+
z-index: 20;
|
|
761
|
+
padding: 20px;
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
.modal-content {
|
|
765
|
+
width: min(100%, 520px);
|
|
766
|
+
background: #ffffff;
|
|
767
|
+
border-radius: 20px;
|
|
768
|
+
padding: 20px;
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
.modal-header,
|
|
772
|
+
.modal-footer {
|
|
773
|
+
display: flex;
|
|
774
|
+
align-items: center;
|
|
775
|
+
justify-content: space-between;
|
|
776
|
+
gap: 12px;
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
.modal-header {
|
|
780
|
+
margin-bottom: 16px;
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
.modal-body {
|
|
784
|
+
display: grid;
|
|
785
|
+
gap: 16px;
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
.modal-text,
|
|
789
|
+
.feedback-label {
|
|
790
|
+
color: #374151;
|
|
791
|
+
font-size: 14px;
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
.feedback-textarea {
|
|
795
|
+
width: 100%;
|
|
796
|
+
border: 1px solid #d1d5db;
|
|
797
|
+
border-radius: 14px;
|
|
798
|
+
padding: 12px;
|
|
799
|
+
font: inherit;
|
|
800
|
+
resize: vertical;
|
|
801
|
+
min-height: 110px;
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
.close-button {
|
|
805
|
+
background: transparent;
|
|
806
|
+
border: 0;
|
|
807
|
+
font-size: 26px;
|
|
808
|
+
line-height: 1;
|
|
809
|
+
cursor: pointer;
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
.status-active,
|
|
813
|
+
.status-paid,
|
|
814
|
+
.status-success,
|
|
815
|
+
.status-created,
|
|
816
|
+
.status-submitted,
|
|
817
|
+
.status-fulfilled {
|
|
818
|
+
background: #dcfce7;
|
|
819
|
+
color: #166534;
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
.status-trialing,
|
|
823
|
+
.status-open,
|
|
824
|
+
.status-unfulfilled,
|
|
825
|
+
.status-processing,
|
|
826
|
+
.status-draft {
|
|
827
|
+
background: #fef3c7;
|
|
828
|
+
color: #92400e;
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
.status-canceled,
|
|
832
|
+
.status-cancelled,
|
|
833
|
+
.status-expired,
|
|
834
|
+
.status-unpaid,
|
|
835
|
+
.status-past-due,
|
|
836
|
+
.status-void,
|
|
837
|
+
.status-failure,
|
|
838
|
+
.status-failed {
|
|
839
|
+
background: #fee2e2;
|
|
840
|
+
color: #991b1b;
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
@media (max-width: 720px) {
|
|
844
|
+
.subscription-header,
|
|
845
|
+
.modal-header,
|
|
846
|
+
.modal-footer {
|
|
847
|
+
flex-direction: column;
|
|
848
|
+
align-items: stretch;
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
.order-badges {
|
|
852
|
+
justify-content: flex-start;
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
.order-grid,
|
|
856
|
+
.order-addresses {
|
|
857
|
+
grid-template-columns: 1fr;
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
.detail-row,
|
|
861
|
+
.order-item-row {
|
|
862
|
+
flex-direction: column;
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
.detail-value {
|
|
866
|
+
text-align: left;
|
|
867
|
+
}
|
|
868
|
+
}
|
|
358
869
|
</style>
|