@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.
@@ -36,74 +36,177 @@
36
36
  <p class="center-text">{{ssoLang[appLanguage].billing_p }}</p>
37
37
 
38
38
  <div class="full-top">
39
- <!-- No subscriptions message -->
40
- <div v-if="subscriptions.length === 0" class="no-subscriptions center-text full-top">
41
- <p class="gray-text">There are no active subscriptions at this point.</p>
42
- </div>
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
- <!-- Subscriptions list -->
45
- <div v-else>
46
- <div v-for="sub in subscriptions" :key="sub.subscriptionId" class="subscription-card half-bottom">
47
- <div class="subscription-header">
48
- <div class="subscription-info">
49
- <h3 class="subscription-name">{{ sub.subscriptionName }}</h3>
50
- <span class="subscription-status" :class="getStatusClass(sub.status)">
51
- {{ getStatusText(sub.status) }}
52
- </span>
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
- <div class="subscription-details">
57
- <div class="detail-row">
58
- <span class="detail-label">Amount:</span>
59
- <span class="detail-value">{{ formatCurrency(sub.amount, sub.currency) }}</span>
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
- <div class="detail-row">
62
- <span class="detail-label">Billing:</span>
63
- <span class="detail-value">{{ formatInterval(sub.interval) }}</span>
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
- <div class="detail-row">
66
- <span class="detail-label">Licenses:</span>
67
- <span class="detail-value">{{ sub.licenses }}</span>
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
- <div v-if="sub.isTrial" class="detail-row">
70
- <span class="detail-label">Trial Ends:</span>
71
- <span class="detail-value">{{ formatDate(sub.trialEnd) }}</span>
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
- <div v-else-if="sub.endDate" class="detail-row">
74
- <span class="detail-label">Next Billing:</span>
75
- <span class="detail-value">{{ formatDate(sub.endDate) }}</span>
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
- <div class="subscription-actions">
80
- <button
81
- v-if="sub.status === 'canceled' || sub.status === 'expired'"
82
- @click="resubscribe(sub)"
83
- class="resubscribe-button"
84
- :disabled="loading"
85
- >
86
- {{ loading ? 'Processing...' : 'Re-Subscribe' }}
87
- </button>
88
- <button
89
- v-if="sub.status === 'past_due' || sub.status === 'unpaid'"
90
- @click="retryPayment(sub)"
91
- class="pay-now-button"
92
- :disabled="loading"
93
- >
94
- {{ loading ? 'Processing...' : 'Pay Now' }}
95
- </button>
96
- <button
97
- v-if="sub.status !== 'canceled' && sub.status !== 'expired' && sub.status !== 'past_due' && sub.status !== 'unpaid'"
98
- @click="openCancelModal(sub)"
99
- class="cancel-button"
100
- :disabled="loading"
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
- </div>
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.getAccountSettings();
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?.toFixed(2) || '0.00'}`;
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.getAccountSettings();
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.getAccountSettings();
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.getAccountSettings();
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>