@dotted-labs/ngx-supabase-stripe 0.1.13 → 0.2.0
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/fesm2022/dotted-labs-ngx-supabase-stripe.mjs +382 -82
- package/fesm2022/dotted-labs-ngx-supabase-stripe.mjs.map +1 -1
- package/lib/components/customer/payment-intents/payment-intents-dialog/payment-intents-dialog.component.d.ts +10 -0
- package/lib/components/customer/payment-intents/payment-intents-table/payment-intents-table.component.d.ts +2 -1
- package/lib/components/customer/payment-method/payment-method.component.d.ts +18 -0
- package/lib/components/customer/subscriptions/subscriptions-list/subscription-item/subscription-item.component.d.ts +7 -3
- package/lib/components/customer/subscriptions/subscriptions.component.d.ts +18 -2
- package/lib/components/embedded-checkout/embedded-checkout.component.d.ts +16 -0
- package/lib/components/embedded-subscription/embedded-subscription.component.d.ts +16 -0
- package/lib/components/product-list/product-item/product-item.component.d.ts +10 -2
- package/lib/components/product-list/product-list.component.d.ts +13 -7
- package/lib/directives/brand-icon.directive.d.ts +11 -0
- package/lib/directives/brand-name.directive.d.ts +11 -0
- package/lib/directives/payment-method-type.directive.d.ts +11 -0
- package/lib/models/currency.model.d.ts +9 -0
- package/lib/pages/customer/customer.component.d.ts +16 -0
- package/lib/services/stripe-client.service.d.ts +8 -0
- package/lib/store/customer.store.d.ts +22 -1
- package/lib/store/products.store.d.ts +11 -6
- package/package.json +1 -1
- package/public-api.d.ts +2 -0
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { InjectionToken, inject, Injectable, computed, Component, input, output, signal } from '@angular/core';
|
|
2
|
+
import { InjectionToken, inject, Injectable, computed, Component, input, output, effect, Directive, signal } from '@angular/core';
|
|
3
3
|
import { signalStore, withState, withComputed, withMethods, patchState, withHooks } from '@ngrx/signals';
|
|
4
4
|
import { loadStripe } from '@stripe/stripe-js';
|
|
5
5
|
import { createClient } from '@supabase/supabase-js';
|
|
6
|
+
import { withEntities, upsertEntity, setAllEntities } from '@ngrx/signals/entities';
|
|
6
7
|
import * as i1 from '@angular/common';
|
|
7
8
|
import { CommonModule } from '@angular/common';
|
|
8
9
|
import { ActivatedRoute, Router } from '@angular/router';
|
|
10
|
+
import { DomSanitizer } from '@angular/platform-browser';
|
|
9
11
|
|
|
10
12
|
const STRIPE_CONFIG = new InjectionToken('STRIPE_CONFIG');
|
|
11
13
|
/**
|
|
@@ -575,6 +577,36 @@ class StripeClientService {
|
|
|
575
577
|
return { customer: null, error: error };
|
|
576
578
|
}
|
|
577
579
|
}
|
|
580
|
+
async getCustomerPaymentMethods(customerId) {
|
|
581
|
+
try {
|
|
582
|
+
const { data, error } = await this.supabase.getClient()
|
|
583
|
+
.functions.invoke('customer_payment_methods', {
|
|
584
|
+
body: { customerId }
|
|
585
|
+
});
|
|
586
|
+
if (error) {
|
|
587
|
+
throw error;
|
|
588
|
+
}
|
|
589
|
+
return { paymentMethods: data, error: null };
|
|
590
|
+
}
|
|
591
|
+
catch (error) {
|
|
592
|
+
return { paymentMethods: null, error: error };
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
async getCustomerPaymentMethod(customerId, paymentMethodId) {
|
|
596
|
+
try {
|
|
597
|
+
const { data, error } = await this.supabase.getClient()
|
|
598
|
+
.functions.invoke('customer_payment_method', {
|
|
599
|
+
body: { customerId, paymentMethodId }
|
|
600
|
+
});
|
|
601
|
+
if (error) {
|
|
602
|
+
throw error;
|
|
603
|
+
}
|
|
604
|
+
return { paymentMethod: data, error: null };
|
|
605
|
+
}
|
|
606
|
+
catch (error) {
|
|
607
|
+
return { paymentMethod: null, error: error };
|
|
608
|
+
}
|
|
609
|
+
}
|
|
578
610
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: StripeClientService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
579
611
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: StripeClientService, providedIn: 'root' });
|
|
580
612
|
}
|
|
@@ -585,19 +617,32 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImpor
|
|
|
585
617
|
}]
|
|
586
618
|
}], ctorParameters: () => [] });
|
|
587
619
|
|
|
620
|
+
var Currency;
|
|
621
|
+
(function (Currency) {
|
|
622
|
+
Currency["EUR"] = "eur";
|
|
623
|
+
Currency["USD"] = "usd";
|
|
624
|
+
Currency["GBP"] = "gbp";
|
|
625
|
+
Currency["JPY"] = "jpy";
|
|
626
|
+
Currency["KRW"] = "krw";
|
|
627
|
+
Currency["CNY"] = "cny";
|
|
628
|
+
Currency["INR"] = "inr";
|
|
629
|
+
})(Currency || (Currency = {}));
|
|
630
|
+
|
|
588
631
|
const initialProductsState = {
|
|
589
|
-
products:
|
|
590
|
-
prices:
|
|
632
|
+
products: [],
|
|
633
|
+
prices: [],
|
|
591
634
|
status: 'idle',
|
|
592
635
|
error: null,
|
|
636
|
+
currency: Currency.EUR,
|
|
593
637
|
};
|
|
594
638
|
const ProductsStore = signalStore({ providedIn: 'root' }, withState(initialProductsState), withComputed((state) => ({
|
|
595
639
|
isStatusLoading: computed(() => state.status() === 'loading'),
|
|
596
640
|
isStatusSuccess: computed(() => state.status() === 'success'),
|
|
597
641
|
isStatusError: computed(() => state.status() === 'error'),
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
642
|
+
oneTimeproductsByCurrency: computed(() => state.products().filter(product => product.prices.some(price => (price.details.type === 'one_time' && price.details.currency === state.currency()))) || []),
|
|
643
|
+
recurringProductsByCurrency: computed(() => state.products().filter(product => product.prices.some(price => (price.details.type === 'recurring' && price.details.currency === state.currency()))) || []),
|
|
644
|
+
productsByCurrency: computed(() => state.products().filter(product => product.prices.some(price => (price.details.currency === state.currency()))) || []),
|
|
645
|
+
hasProducts: computed(() => state.products().length > 0),
|
|
601
646
|
isError: computed(() => state.error())
|
|
602
647
|
})), withMethods((store, supabaseService = inject(SupabaseClientService)) => ({
|
|
603
648
|
/**
|
|
@@ -607,6 +652,12 @@ const ProductsStore = signalStore({ providedIn: 'root' }, withState(initialProdu
|
|
|
607
652
|
console.log('🎮 [ProductsStore] Loading products by ids: ', ids);
|
|
608
653
|
return store.products()?.filter(product => product.id && ids.includes(product.id)) || [];
|
|
609
654
|
},
|
|
655
|
+
/**
|
|
656
|
+
* Set the currency filter for products
|
|
657
|
+
*/
|
|
658
|
+
setCurrency(currency) {
|
|
659
|
+
patchState(store, { currency });
|
|
660
|
+
},
|
|
610
661
|
/**
|
|
611
662
|
* Load product by id
|
|
612
663
|
*/
|
|
@@ -635,6 +686,12 @@ const ProductsStore = signalStore({ providedIn: 'root' }, withState(initialProdu
|
|
|
635
686
|
async loadProducts() {
|
|
636
687
|
patchState(store, { status: 'loading', error: null });
|
|
637
688
|
try {
|
|
689
|
+
const { data: prices, error: pricesError } = await supabaseService.selectStripePrices();
|
|
690
|
+
if (pricesError) {
|
|
691
|
+
console.error('🎮 [ProductsStore]: Error loading prices', pricesError);
|
|
692
|
+
patchState(store, { status: 'error', error: pricesError.message });
|
|
693
|
+
}
|
|
694
|
+
patchState(store, { prices: prices || [] });
|
|
638
695
|
const { data: stripeProducts, error: productsError } = await supabaseService.selectStripeProducts();
|
|
639
696
|
if (productsError) {
|
|
640
697
|
console.error('🎮 [ProductsStore]: Error loading products', productsError);
|
|
@@ -670,15 +727,9 @@ const ProductsStore = signalStore({ providedIn: 'root' }, withState(initialProdu
|
|
|
670
727
|
reset() {
|
|
671
728
|
patchState(store, initialProductsState);
|
|
672
729
|
}
|
|
673
|
-
})), withHooks((store
|
|
730
|
+
})), withHooks((store) => ({
|
|
674
731
|
async onInit() {
|
|
675
732
|
console.log('🎮 [ProductsStore] onInit');
|
|
676
|
-
const { data: prices, error: pricesError } = await supabaseService.selectStripePrices();
|
|
677
|
-
if (pricesError) {
|
|
678
|
-
console.error('🎮 [ProductsStore]: Error loading prices', pricesError);
|
|
679
|
-
patchState(store, { status: 'error', error: pricesError.message });
|
|
680
|
-
}
|
|
681
|
-
patchState(store, { prices });
|
|
682
733
|
const products = store.products();
|
|
683
734
|
console.log('🎮 [ProductsStore] products: ', products);
|
|
684
735
|
if (!products) {
|
|
@@ -918,8 +969,10 @@ const initialCustomerState = {
|
|
|
918
969
|
status: 'idle',
|
|
919
970
|
error: null,
|
|
920
971
|
},
|
|
972
|
+
paymentMethodsStatus: 'idle',
|
|
973
|
+
paymentMethodsError: null,
|
|
921
974
|
};
|
|
922
|
-
const CustomerStore = signalStore({ providedIn: 'root' }, withState(initialCustomerState), withComputed((state) => ({
|
|
975
|
+
const CustomerStore = signalStore({ providedIn: 'root' }, withState(initialCustomerState), withEntities(), withComputed((state) => ({
|
|
923
976
|
isPaymentIntentsStatusLoading: computed(() => state.paymentIntents.status() === 'loading'),
|
|
924
977
|
isPaymentIntentsStatusSuccess: computed(() => state.paymentIntents.status() === 'success'),
|
|
925
978
|
isPaymentIntentsStatusError: computed(() => state.paymentIntents.status() === 'error'),
|
|
@@ -931,6 +984,11 @@ const CustomerStore = signalStore({ providedIn: 'root' }, withState(initialCusto
|
|
|
931
984
|
firstSubscription: computed(() => state.subscriptions.data()?.[0]),
|
|
932
985
|
restSubscriptions: computed(() => state.subscriptions.data()?.slice(1)),
|
|
933
986
|
isError: computed(() => state.paymentIntents.error()),
|
|
987
|
+
isPaymentMethodsStatusLoading: computed(() => state.paymentMethodsStatus() === 'loading'),
|
|
988
|
+
isPaymentMethodsStatusSuccess: computed(() => state.paymentMethodsStatus() === 'success'),
|
|
989
|
+
isPaymentMethodsStatusError: computed(() => state.paymentMethodsStatus() === 'error'),
|
|
990
|
+
hasPaymentMethods: computed(() => state.entities().length > 0),
|
|
991
|
+
paymentMethods: computed(() => state.entities()),
|
|
934
992
|
})), withMethods((state, supabaseService = inject(SupabaseClientService), stripeService = inject(StripeClientService), productsStore = inject(ProductsStore)) => ({
|
|
935
993
|
/**
|
|
936
994
|
* Load customer
|
|
@@ -947,6 +1005,7 @@ const CustomerStore = signalStore({ providedIn: 'root' }, withState(initialCusto
|
|
|
947
1005
|
if (customer) {
|
|
948
1006
|
this.loadPaymentIntents(customer.id);
|
|
949
1007
|
this.loadSubscriptions(customer.id);
|
|
1008
|
+
this.loadPaymentMethods(customer.id);
|
|
950
1009
|
patchState(state, { customer: { data: customer, status: 'success', error: null } });
|
|
951
1010
|
}
|
|
952
1011
|
else {
|
|
@@ -974,7 +1033,7 @@ const CustomerStore = signalStore({ providedIn: 'root' }, withState(initialCusto
|
|
|
974
1033
|
async loadPaymentIntents(customerId) {
|
|
975
1034
|
patchState(state, { paymentIntents: { status: 'loading', data: [], error: null } });
|
|
976
1035
|
const { data, error } = await supabaseService.getCustomerPaymentIntents(customerId);
|
|
977
|
-
const paymentIntents = data?.map((paymentIntent) => parsePaymentIntent(paymentIntent));
|
|
1036
|
+
const paymentIntents = data?.map((paymentIntent) => parsePaymentIntent(paymentIntent, state.entityMap()));
|
|
978
1037
|
if (error) {
|
|
979
1038
|
patchState(state, { paymentIntents: { error: error.message, status: 'error', data: [] } });
|
|
980
1039
|
}
|
|
@@ -1009,6 +1068,61 @@ const CustomerStore = signalStore({ providedIn: 'root' }, withState(initialCusto
|
|
|
1009
1068
|
patchState(state, { subscriptions: { data: subscriptions ?? [], status: 'success', error: null } });
|
|
1010
1069
|
}
|
|
1011
1070
|
},
|
|
1071
|
+
/**
|
|
1072
|
+
* Load payment methods for a customer
|
|
1073
|
+
* @param customerId The customer ID
|
|
1074
|
+
*/
|
|
1075
|
+
async loadPaymentMethods(customerId) {
|
|
1076
|
+
patchState(state, {
|
|
1077
|
+
paymentMethodsStatus: 'loading',
|
|
1078
|
+
paymentMethodsError: null
|
|
1079
|
+
});
|
|
1080
|
+
const { paymentMethods, error } = await stripeService.getCustomerPaymentMethods(customerId);
|
|
1081
|
+
if (error) {
|
|
1082
|
+
patchState(state, {
|
|
1083
|
+
paymentMethodsStatus: 'error',
|
|
1084
|
+
paymentMethodsError: error.message
|
|
1085
|
+
});
|
|
1086
|
+
}
|
|
1087
|
+
else {
|
|
1088
|
+
patchState(state, setAllEntities(paymentMethods ?? []), {
|
|
1089
|
+
paymentMethodsStatus: 'success',
|
|
1090
|
+
paymentMethodsError: null
|
|
1091
|
+
});
|
|
1092
|
+
}
|
|
1093
|
+
},
|
|
1094
|
+
/**
|
|
1095
|
+
* Load a single payment method and add/update it in the entity collection
|
|
1096
|
+
* @param customerId The customer ID
|
|
1097
|
+
* @param paymentMethodId The payment method ID
|
|
1098
|
+
*/
|
|
1099
|
+
async loadPaymentMethod(customerId, paymentMethodId) {
|
|
1100
|
+
patchState(state, {
|
|
1101
|
+
paymentMethodsStatus: 'loading',
|
|
1102
|
+
paymentMethodsError: null
|
|
1103
|
+
});
|
|
1104
|
+
const { paymentMethod, error } = await stripeService.getCustomerPaymentMethod(customerId, paymentMethodId);
|
|
1105
|
+
if (error) {
|
|
1106
|
+
patchState(state, {
|
|
1107
|
+
paymentMethodsStatus: 'error',
|
|
1108
|
+
paymentMethodsError: error.message
|
|
1109
|
+
});
|
|
1110
|
+
}
|
|
1111
|
+
else if (paymentMethod) {
|
|
1112
|
+
}
|
|
1113
|
+
if (paymentMethod) {
|
|
1114
|
+
patchState(state, upsertEntity(paymentMethod), {
|
|
1115
|
+
paymentMethodsStatus: 'success',
|
|
1116
|
+
paymentMethodsError: null
|
|
1117
|
+
});
|
|
1118
|
+
}
|
|
1119
|
+
else {
|
|
1120
|
+
patchState(state, {
|
|
1121
|
+
paymentMethodsStatus: 'error',
|
|
1122
|
+
paymentMethodsError: 'Payment method not found'
|
|
1123
|
+
});
|
|
1124
|
+
}
|
|
1125
|
+
},
|
|
1012
1126
|
})), withHooks(() => {
|
|
1013
1127
|
return {
|
|
1014
1128
|
onInit() {
|
|
@@ -1024,15 +1138,18 @@ const CustomerStore = signalStore({ providedIn: 'root' }, withState(initialCusto
|
|
|
1024
1138
|
}
|
|
1025
1139
|
};
|
|
1026
1140
|
}));
|
|
1027
|
-
function parsePaymentIntent(paymentIntent) {
|
|
1141
|
+
function parsePaymentIntent(paymentIntent, paymentMethodsMap = {}) {
|
|
1142
|
+
console.log('🔍 [CustomerStore] paymentIntent: ', paymentIntent);
|
|
1028
1143
|
const paymentIntentAttrs = paymentIntent.attrs;
|
|
1144
|
+
const paymentMethodId = paymentIntentAttrs.payment_method;
|
|
1029
1145
|
return {
|
|
1030
1146
|
...paymentIntent,
|
|
1031
1147
|
status: paymentIntentAttrs.status,
|
|
1032
1148
|
invoiceId: paymentIntentAttrs.invoice,
|
|
1033
1149
|
liveMode: paymentIntentAttrs.livemode,
|
|
1034
1150
|
confirmationMethod: paymentIntentAttrs.confirmation_method,
|
|
1035
|
-
paymentMethodId
|
|
1151
|
+
paymentMethodId,
|
|
1152
|
+
paymentMethod: paymentMethodId ? paymentMethodsMap[paymentMethodId] : undefined,
|
|
1036
1153
|
};
|
|
1037
1154
|
}
|
|
1038
1155
|
|
|
@@ -1135,6 +1252,55 @@ const CheckoutStore = signalStore({ providedIn: 'root' }, withState(initialCheck
|
|
|
1135
1252
|
}
|
|
1136
1253
|
}));
|
|
1137
1254
|
|
|
1255
|
+
const initialPortalState = {
|
|
1256
|
+
status: 'idle',
|
|
1257
|
+
error: null,
|
|
1258
|
+
portalUrl: null
|
|
1259
|
+
};
|
|
1260
|
+
const PortalAccountStore = signalStore({ providedIn: 'root' }, withState(initialPortalState), withComputed((state) => ({
|
|
1261
|
+
isStatusIdle: computed(() => state.status() === 'idle'),
|
|
1262
|
+
isStatusLoading: computed(() => state.status() === 'loading'),
|
|
1263
|
+
isStatusSuccess: computed(() => state.status() === 'success'),
|
|
1264
|
+
isStatusError: computed(() => state.status() === 'error'),
|
|
1265
|
+
})), withMethods((store, stripeService = inject(StripeClientService)) => ({
|
|
1266
|
+
/**
|
|
1267
|
+
* Creates a customer portal session and redirects to the URL
|
|
1268
|
+
* @param customerId Stripe customer ID
|
|
1269
|
+
* @param returnUrl URL to redirect to after the portal session
|
|
1270
|
+
*/
|
|
1271
|
+
async createPortalSession(customerId, returnUrl) {
|
|
1272
|
+
patchState(store, { status: 'loading', error: null, portalUrl: null });
|
|
1273
|
+
try {
|
|
1274
|
+
const { url, error } = await stripeService.createPortalSession(customerId, returnUrl);
|
|
1275
|
+
if (error) {
|
|
1276
|
+
throw new Error(error.message);
|
|
1277
|
+
}
|
|
1278
|
+
if (!url) {
|
|
1279
|
+
throw new Error('No se pudo crear la sesión del portal');
|
|
1280
|
+
}
|
|
1281
|
+
patchState(store, {
|
|
1282
|
+
status: 'success',
|
|
1283
|
+
portalUrl: url
|
|
1284
|
+
});
|
|
1285
|
+
window.location.href = url;
|
|
1286
|
+
}
|
|
1287
|
+
catch (error) {
|
|
1288
|
+
console.error('🚨 [PortalAccountStore]', error);
|
|
1289
|
+
const errorMessage = error instanceof Error ? error.message : 'Error desconocido';
|
|
1290
|
+
patchState(store, {
|
|
1291
|
+
status: 'error',
|
|
1292
|
+
error: errorMessage
|
|
1293
|
+
});
|
|
1294
|
+
}
|
|
1295
|
+
},
|
|
1296
|
+
/**
|
|
1297
|
+
* Resets the store to initial state
|
|
1298
|
+
*/
|
|
1299
|
+
reset() {
|
|
1300
|
+
patchState(store, initialPortalState);
|
|
1301
|
+
}
|
|
1302
|
+
})));
|
|
1303
|
+
|
|
1138
1304
|
class EmbeddedSkeletonComponent {
|
|
1139
1305
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: EmbeddedSkeletonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1140
1306
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.5", type: EmbeddedSkeletonComponent, isStandalone: true, selector: "lib-embedded-skeleton", ngImport: i0, template: "<div class=\"w-full max-w-md mx-auto p-4\">\n <!-- Header skeleton -->\n <div class=\"flex items-center gap-4 mb-6\">\n <div class=\"skeleton w-16 h-16 rounded-lg\"></div>\n <div class=\"skeleton h-6 w-48\"></div>\n </div>\n\n <!-- Price skeleton -->\n <div class=\"mb-8\">\n <div class=\"skeleton h-10 w-32 mb-2\"></div>\n <div class=\"skeleton h-4 w-24\"></div>\n </div>\n\n <!-- Payment form skeleton -->\n <div class=\"space-y-4\">\n <!-- Email field -->\n <div class=\"skeleton h-12 w-full\"></div>\n \n <!-- Card info field -->\n <div class=\"skeleton h-12 w-full\"></div>\n \n <!-- Name field -->\n <div class=\"skeleton h-12 w-full\"></div>\n \n <!-- Country selector -->\n <div class=\"skeleton h-12 w-full\"></div>\n \n <!-- Submit button -->\n <div class=\"skeleton h-12 w-full mt-6\"></div>\n </div>\n</div> " });
|
|
@@ -1217,7 +1383,6 @@ class UtilsService {
|
|
|
1217
1383
|
formatAmount(amount, currency = 'EUR') {
|
|
1218
1384
|
if (!amount)
|
|
1219
1385
|
return 'N/A';
|
|
1220
|
-
console.log('[🛠️ UtilsService - formatAmount] currency: ', currency.toLocaleUpperCase());
|
|
1221
1386
|
const formatter = new Intl.NumberFormat(currency.toLocaleUpperCase() === 'EUR' ? 'es-ES' : 'en-US', {
|
|
1222
1387
|
style: 'currency',
|
|
1223
1388
|
currency: currency || 'USD',
|
|
@@ -1266,24 +1431,32 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImpor
|
|
|
1266
1431
|
|
|
1267
1432
|
class ProductItemComponent {
|
|
1268
1433
|
product = input.required();
|
|
1434
|
+
currency = input(Currency.EUR);
|
|
1269
1435
|
productSelected = output();
|
|
1270
1436
|
priceSelected = output();
|
|
1271
1437
|
utils = inject(UtilsService);
|
|
1272
|
-
|
|
1438
|
+
sanitizer = inject(DomSanitizer);
|
|
1439
|
+
price = computed(() => this.product().prices.find(price => price.details.currency === this.currency()));
|
|
1440
|
+
sanitizedImage = computed(() => {
|
|
1441
|
+
const imageUrl = this.product().images?.[0];
|
|
1442
|
+
return imageUrl ? this.sanitizer.bypassSecurityTrustUrl(imageUrl) : null;
|
|
1443
|
+
});
|
|
1444
|
+
onSelect() {
|
|
1273
1445
|
this.productSelected.emit(this.product());
|
|
1274
|
-
this.priceSelected.emit(price);
|
|
1446
|
+
this.priceSelected.emit(this.price()?.details);
|
|
1275
1447
|
}
|
|
1276
1448
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: ProductItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1277
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.5", type: ProductItemComponent, isStandalone: true, selector: "lib-product-item", inputs: { product: { classPropertyName: "product", publicName: "product", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { productSelected: "productSelected", priceSelected: "priceSelected" }, ngImport: i0, template: "<div class=\"card bg-base-100 shadow-xl\">\n @if (
|
|
1449
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.5", type: ProductItemComponent, isStandalone: true, selector: "lib-product-item", inputs: { product: { classPropertyName: "product", publicName: "product", isSignal: true, isRequired: true, transformFunction: null }, currency: { classPropertyName: "currency", publicName: "currency", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { productSelected: "productSelected", priceSelected: "priceSelected" }, ngImport: i0, template: "<div class=\"card bg-base-100 shadow-xl max-w-sm mx-auto rounded-3xl overflow-hidden\">\n <!-- Header with image and favorite icon -->\n <div class=\"relative\">\n @if (sanitizedImage()) {\n <figure class=\"bg-gradient-to-br from-base-200 to-base-300\">\n <img \n [src]=\"sanitizedImage()\" \n alt=\"{{ product().name }}\" \n class=\"h-64 w-full object-cover p-8 rounded-t-3xl\" />\n </figure>\n } @else {\n <div class=\"h-64 bg-gradient-to-br from-base-200 to-base-300 flex items-center justify-center\">\n <div class=\"text-base-content/50 text-6xl\">\uD83D\uDCE6</div>\n </div>\n }\n </div>\n\n <div class=\"card-body p-6 flex flex-col h-full\">\n <!-- Product title -->\n <h2 class=\"card-title text-xl font-bold text-base-content\">\n {{ product().name }}\n </h2>\n\n <!-- Description (moved under title) -->\n @if (product().description) {\n <p class=\"text-base-content/70 text-sm mb-4 line-clamp-3\">\n {{ product().description }}\n </p>\n }\n\n <!-- Price options as text -->\n <div class=\"flex justify-between gap-2\">\n <span class=\"text-xl font-bold text-base-content\">\n @if (price()?.details?.type === 'recurring') {\n {{ utils.formatAmount(price()?.details?.unit_amount ?? 0, price()?.details?.currency ?? 'EUR') }}/{{ price()?.recurringInterval === 'month' ? 'mo' : 'yr' }}\n } @else {\n {{ utils.formatAmount(price()?.details?.unit_amount ?? 0, price()?.details?.currency ?? 'EUR') }}\n }\n </span>\n\n <!-- Status badge (only show if inactive) -->\n @if (!product().active) {\n <div class=\"mt-4\">\n <div class=\"badge badge-warning badge-sm\">Inactive</div>\n </div>\n } @else {\n <button \n class=\"btn btn-primary\"\n (click)=\"onSelect()\">\n Buy now\n </button>\n }\n </div>\n </div>\n</div> ", dependencies: [{ kind: "ngmodule", type: CommonModule }] });
|
|
1278
1450
|
}
|
|
1279
1451
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: ProductItemComponent, decorators: [{
|
|
1280
1452
|
type: Component,
|
|
1281
|
-
args: [{ selector: 'lib-product-item', standalone: true, imports: [CommonModule], template: "<div class=\"card bg-base-100 shadow-xl\">\n @if (
|
|
1453
|
+
args: [{ selector: 'lib-product-item', standalone: true, imports: [CommonModule], template: "<div class=\"card bg-base-100 shadow-xl max-w-sm mx-auto rounded-3xl overflow-hidden\">\n <!-- Header with image and favorite icon -->\n <div class=\"relative\">\n @if (sanitizedImage()) {\n <figure class=\"bg-gradient-to-br from-base-200 to-base-300\">\n <img \n [src]=\"sanitizedImage()\" \n alt=\"{{ product().name }}\" \n class=\"h-64 w-full object-cover p-8 rounded-t-3xl\" />\n </figure>\n } @else {\n <div class=\"h-64 bg-gradient-to-br from-base-200 to-base-300 flex items-center justify-center\">\n <div class=\"text-base-content/50 text-6xl\">\uD83D\uDCE6</div>\n </div>\n }\n </div>\n\n <div class=\"card-body p-6 flex flex-col h-full\">\n <!-- Product title -->\n <h2 class=\"card-title text-xl font-bold text-base-content\">\n {{ product().name }}\n </h2>\n\n <!-- Description (moved under title) -->\n @if (product().description) {\n <p class=\"text-base-content/70 text-sm mb-4 line-clamp-3\">\n {{ product().description }}\n </p>\n }\n\n <!-- Price options as text -->\n <div class=\"flex justify-between gap-2\">\n <span class=\"text-xl font-bold text-base-content\">\n @if (price()?.details?.type === 'recurring') {\n {{ utils.formatAmount(price()?.details?.unit_amount ?? 0, price()?.details?.currency ?? 'EUR') }}/{{ price()?.recurringInterval === 'month' ? 'mo' : 'yr' }}\n } @else {\n {{ utils.formatAmount(price()?.details?.unit_amount ?? 0, price()?.details?.currency ?? 'EUR') }}\n }\n </span>\n\n <!-- Status badge (only show if inactive) -->\n @if (!product().active) {\n <div class=\"mt-4\">\n <div class=\"badge badge-warning badge-sm\">Inactive</div>\n </div>\n } @else {\n <button \n class=\"btn btn-primary\"\n (click)=\"onSelect()\">\n Buy now\n </button>\n }\n </div>\n </div>\n</div> " }]
|
|
1282
1454
|
}] });
|
|
1283
1455
|
|
|
1284
1456
|
class ProductListComponent {
|
|
1285
1457
|
productsStore = inject(ProductsStore);
|
|
1286
1458
|
products = input([]);
|
|
1459
|
+
currency = input(Currency.EUR);
|
|
1287
1460
|
productSelected = output();
|
|
1288
1461
|
priceSelected = output();
|
|
1289
1462
|
onProductSelect(product) {
|
|
@@ -1293,11 +1466,11 @@ class ProductListComponent {
|
|
|
1293
1466
|
this.priceSelected.emit(price);
|
|
1294
1467
|
}
|
|
1295
1468
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: ProductListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1296
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.5", type: ProductListComponent, isStandalone: true, selector: "stripe-product-list", inputs: { products: { classPropertyName: "products", publicName: "products", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { productSelected: "productSelected", priceSelected: "priceSelected" }, ngImport: i0, template: "@if (productsStore.isStatusLoading()) {\n <div class=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6\">\n @for (item of [1,2,3]; track item) {\n <lib-product-item-skeleton></lib-product-item-skeleton>\n }\n </div>\n}
|
|
1469
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.5", type: ProductListComponent, isStandalone: true, selector: "stripe-product-list", inputs: { products: { classPropertyName: "products", publicName: "products", isSignal: true, isRequired: false, transformFunction: null }, currency: { classPropertyName: "currency", publicName: "currency", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { productSelected: "productSelected", priceSelected: "priceSelected" }, ngImport: i0, template: "@if (productsStore.isStatusLoading()) {\n <div class=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6\">\n @for (item of [1,2,3]; track item) {\n <lib-product-item-skeleton></lib-product-item-skeleton>\n }\n </div>\n}\n\n@if (productsStore.isStatusError() && !productsStore.isStatusLoading()) {\n <div class=\"alert alert-error\">\n <span>{{ productsStore.error() }}</span>\n </div>\n}\n\n@if (!productsStore.hasProducts()) {\n <div class=\"alert alert-info\">\n <span>No products available</span>\n </div>\n}\n\n@if (productsStore.hasProducts()) {\n <div class=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6\">\n @for (product of products(); track product.id) {\n <lib-product-item\n [product]=\"product\"\n [currency]=\"currency()\"\n (productSelected)=\"onProductSelect($event)\"\n (priceSelected)=\"onPriceSelect($event)\">\n </lib-product-item>\n }\n </div>\n} \n\n\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: ProductItemComponent, selector: "lib-product-item", inputs: ["product", "currency"], outputs: ["productSelected", "priceSelected"] }, { kind: "component", type: ProductItemSkeletonComponent, selector: "lib-product-item-skeleton" }] });
|
|
1297
1470
|
}
|
|
1298
1471
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: ProductListComponent, decorators: [{
|
|
1299
1472
|
type: Component,
|
|
1300
|
-
args: [{ selector: 'stripe-product-list', standalone: true, imports: [CommonModule, ProductItemComponent, ProductItemSkeletonComponent], template: "@if (productsStore.isStatusLoading()) {\n <div class=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6\">\n @for (item of [1,2,3]; track item) {\n <lib-product-item-skeleton></lib-product-item-skeleton>\n }\n </div>\n}
|
|
1473
|
+
args: [{ selector: 'stripe-product-list', standalone: true, imports: [CommonModule, ProductItemComponent, ProductItemSkeletonComponent], template: "@if (productsStore.isStatusLoading()) {\n <div class=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6\">\n @for (item of [1,2,3]; track item) {\n <lib-product-item-skeleton></lib-product-item-skeleton>\n }\n </div>\n}\n\n@if (productsStore.isStatusError() && !productsStore.isStatusLoading()) {\n <div class=\"alert alert-error\">\n <span>{{ productsStore.error() }}</span>\n </div>\n}\n\n@if (!productsStore.hasProducts()) {\n <div class=\"alert alert-info\">\n <span>No products available</span>\n </div>\n}\n\n@if (productsStore.hasProducts()) {\n <div class=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6\">\n @for (product of products(); track product.id) {\n <lib-product-item\n [product]=\"product\"\n [currency]=\"currency()\"\n (productSelected)=\"onProductSelect($event)\"\n (priceSelected)=\"onPriceSelect($event)\">\n </lib-product-item>\n }\n </div>\n} \n\n\n" }]
|
|
1301
1474
|
}] });
|
|
1302
1475
|
|
|
1303
1476
|
class EmbeddedSubscriptionComponent {
|
|
@@ -1357,6 +1530,173 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImpor
|
|
|
1357
1530
|
args: [{ selector: 'lib-subscription-return-page', standalone: true, imports: [CommonModule], template: "<div class=\"flex justify-center min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100 p-4\">\n <div class=\"hero-content text-center max-w-md\">\n <div class=\"card w-full bg-base-100 shadow-2xl\">\n <div class=\"card-body items-center text-center\">\n <!-- Success Icon -->\n <div class=\"mb-6\">\n <div class=\"avatar\">\n <div class=\"w-24 h-24 rounded-full bg-success/10 flex items-center justify-center\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"h-full w-full text-success\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z\"\n />\n </svg>\n </div>\n </div>\n </div>\n\n <!-- Status Content -->\n @if (checkoutStore.isStatusLoading()) {\n <div class=\"flex flex-col items-center gap-4 mb-6\">\n <span class=\"loading loading-spinner loading-lg text-primary\"></span>\n <div class=\"alert alert-info\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" class=\"stroke-current shrink-0 w-6 h-6\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z\"></path>\n </svg>\n <span>Cargando detalles de la suscripci\u00F3n...</span>\n </div>\n </div>\n } @else if (checkoutStore.isStatusError()) {\n <div class=\"alert alert-error mb-6\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"stroke-current shrink-0 h-6 w-6\" fill=\"none\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z\" />\n </svg>\n <span>{{ subscriptionsStore.error() }}</span>\n </div>\n } @else if (checkoutStore.isPaymentComplete()) {\n\n <!-- Title and Description -->\n <h2 class=\"card-title text-3xl font-bold text-base-content mb-2\">{{ sessionStatus()?.amount_total }}</h2>\n\n <div class=\"alert alert-success mb-6\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"stroke-current shrink-0 h-6 w-6\" fill=\"none\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z\" />\n </svg>\n <span class=\"font-medium\">Tu suscripci\u00F3n est\u00E1 activa y lista para usar.</span>\n </div>\n\n <div class=\"bg-base-200 rounded-lg p-4 mb-6 w-full\">\n <h3 class=\"font-semibold text-sm text-base-content/80 mb-3\">Beneficios incluidos:</h3>\n <ul class=\"space-y-2\">\n <li class=\"flex items-center text-sm\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-4 w-4 text-success mr-2\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 13l4 4L19 7\" />\n </svg>\n Acceso completo a todas las funciones\n </li>\n <li class=\"flex items-center text-sm\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-4 w-4 text-success mr-2\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 13l4 4L19 7\" />\n </svg>\n Soporte prioritario 24/7\n </li>\n <li class=\"flex items-center text-sm\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-4 w-4 text-success mr-2\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 13l4 4L19 7\" />\n </svg>\n Actualizaciones autom\u00E1ticas\n </li>\n </ul>\n </div>\n }\n\n <!-- Action Buttons -->\n <div class=\"card-actions justify-center w-full\">\n <button class=\"btn btn-primary btn-wide\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-5 w-5 mr-2\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6\"\n />\n </svg>\n Ir al Panel Principal\n </button>\n </div>\n\n <!-- Additional Help -->\n <div class=\"text-center mt-4\">\n <p class=\"text-xs text-base-content/50\">\n \u00BFNecesitas ayuda?\n <a href=\"#\" class=\"link link-primary\">Contacta soporte</a>\n </p>\n </div>\n </div>\n </div>\n </div>\n</div>" }]
|
|
1358
1531
|
}] });
|
|
1359
1532
|
|
|
1533
|
+
class BrandIconDirective {
|
|
1534
|
+
el;
|
|
1535
|
+
paymentMethod = input.required({ alias: 'ngxBrandIcon' });
|
|
1536
|
+
constructor(el) {
|
|
1537
|
+
this.el = el;
|
|
1538
|
+
effect(() => {
|
|
1539
|
+
const icon = this.getBrandIcon();
|
|
1540
|
+
this.el.nativeElement.textContent = icon;
|
|
1541
|
+
});
|
|
1542
|
+
}
|
|
1543
|
+
getBrandIcon() {
|
|
1544
|
+
const brand = this.paymentMethod().card?.brand;
|
|
1545
|
+
const brandIcons = {
|
|
1546
|
+
'visa': '💳',
|
|
1547
|
+
'mastercard': '💳',
|
|
1548
|
+
'amex': '💳',
|
|
1549
|
+
'discover': '💳',
|
|
1550
|
+
'diners': '💳',
|
|
1551
|
+
'jcb': '💳',
|
|
1552
|
+
'unionpay': '💳',
|
|
1553
|
+
'unknown': '💳'
|
|
1554
|
+
};
|
|
1555
|
+
return brandIcons[brand || 'unknown'] || '💳';
|
|
1556
|
+
}
|
|
1557
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: BrandIconDirective, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive });
|
|
1558
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.5", type: BrandIconDirective, isStandalone: true, selector: "[ngxBrandIcon]", inputs: { paymentMethod: { classPropertyName: "paymentMethod", publicName: "ngxBrandIcon", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 });
|
|
1559
|
+
}
|
|
1560
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: BrandIconDirective, decorators: [{
|
|
1561
|
+
type: Directive,
|
|
1562
|
+
args: [{
|
|
1563
|
+
selector: '[ngxBrandIcon]',
|
|
1564
|
+
standalone: true
|
|
1565
|
+
}]
|
|
1566
|
+
}], ctorParameters: () => [{ type: i0.ElementRef }] });
|
|
1567
|
+
|
|
1568
|
+
class BrandNameDirective {
|
|
1569
|
+
el;
|
|
1570
|
+
paymentMethod = input.required({ alias: 'ngxBrandName' });
|
|
1571
|
+
constructor(el) {
|
|
1572
|
+
this.el = el;
|
|
1573
|
+
effect(() => {
|
|
1574
|
+
const name = this.getBrandName();
|
|
1575
|
+
this.el.nativeElement.textContent = name;
|
|
1576
|
+
});
|
|
1577
|
+
}
|
|
1578
|
+
getBrandName() {
|
|
1579
|
+
const brand = this.paymentMethod().card?.brand;
|
|
1580
|
+
const brandNames = {
|
|
1581
|
+
'visa': 'Visa',
|
|
1582
|
+
'mastercard': 'Mastercard',
|
|
1583
|
+
'amex': 'American Express',
|
|
1584
|
+
'discover': 'Discover',
|
|
1585
|
+
'diners': 'Diners Club',
|
|
1586
|
+
'jcb': 'JCB',
|
|
1587
|
+
'unionpay': 'UnionPay',
|
|
1588
|
+
'unknown': 'Tarjeta'
|
|
1589
|
+
};
|
|
1590
|
+
return brandNames[brand || 'unknown'] || 'Tarjeta';
|
|
1591
|
+
}
|
|
1592
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: BrandNameDirective, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive });
|
|
1593
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.5", type: BrandNameDirective, isStandalone: true, selector: "[ngxBrandName]", inputs: { paymentMethod: { classPropertyName: "paymentMethod", publicName: "ngxBrandName", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 });
|
|
1594
|
+
}
|
|
1595
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: BrandNameDirective, decorators: [{
|
|
1596
|
+
type: Directive,
|
|
1597
|
+
args: [{
|
|
1598
|
+
selector: '[ngxBrandName]',
|
|
1599
|
+
standalone: true
|
|
1600
|
+
}]
|
|
1601
|
+
}], ctorParameters: () => [{ type: i0.ElementRef }] });
|
|
1602
|
+
|
|
1603
|
+
class PaymentMethodTypeDirective {
|
|
1604
|
+
el;
|
|
1605
|
+
paymentMethod = input.required({ alias: 'ngxPaymentMethodType' });
|
|
1606
|
+
constructor(el) {
|
|
1607
|
+
this.el = el;
|
|
1608
|
+
effect(() => {
|
|
1609
|
+
const type = this.getPaymentMethodType();
|
|
1610
|
+
this.el.nativeElement.textContent = type;
|
|
1611
|
+
});
|
|
1612
|
+
}
|
|
1613
|
+
getPaymentMethodType() {
|
|
1614
|
+
const typeNames = {
|
|
1615
|
+
'card': 'Tarjeta',
|
|
1616
|
+
'paypal': 'PayPal',
|
|
1617
|
+
'klarna': 'Klarna',
|
|
1618
|
+
'afterpay_clearpay': 'Afterpay',
|
|
1619
|
+
'alipay': 'Alipay',
|
|
1620
|
+
'bancontact': 'Bancontact',
|
|
1621
|
+
'eps': 'EPS',
|
|
1622
|
+
'giropay': 'Giropay',
|
|
1623
|
+
'ideal': 'iDEAL',
|
|
1624
|
+
'p24': 'Przelewy24',
|
|
1625
|
+
'sepa_debit': 'SEPA Direct Debit',
|
|
1626
|
+
'sofort': 'Sofort',
|
|
1627
|
+
'wechat_pay': 'WeChat Pay'
|
|
1628
|
+
};
|
|
1629
|
+
return typeNames[this.paymentMethod().type] || 'Método de pago';
|
|
1630
|
+
}
|
|
1631
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: PaymentMethodTypeDirective, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive });
|
|
1632
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.5", type: PaymentMethodTypeDirective, isStandalone: true, selector: "[ngxPaymentMethodType]", inputs: { paymentMethod: { classPropertyName: "paymentMethod", publicName: "ngxPaymentMethodType", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 });
|
|
1633
|
+
}
|
|
1634
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: PaymentMethodTypeDirective, decorators: [{
|
|
1635
|
+
type: Directive,
|
|
1636
|
+
args: [{
|
|
1637
|
+
selector: '[ngxPaymentMethodType]',
|
|
1638
|
+
standalone: true
|
|
1639
|
+
}]
|
|
1640
|
+
}], ctorParameters: () => [{ type: i0.ElementRef }] });
|
|
1641
|
+
|
|
1642
|
+
class PaymentMethodComponent {
|
|
1643
|
+
paymentMethod = input.required();
|
|
1644
|
+
mode = input('detailed');
|
|
1645
|
+
get last4() {
|
|
1646
|
+
return this.paymentMethod().card?.last4 || '****';
|
|
1647
|
+
}
|
|
1648
|
+
get expirationDate() {
|
|
1649
|
+
const card = this.paymentMethod().card;
|
|
1650
|
+
if (!card?.exp_month || !card?.exp_year)
|
|
1651
|
+
return '';
|
|
1652
|
+
return `${card.exp_month.toString().padStart(2, '0')}/${card.exp_year.toString().slice(-2)}`;
|
|
1653
|
+
}
|
|
1654
|
+
get holderName() {
|
|
1655
|
+
return this.paymentMethod().billing_details?.name || 'N/A';
|
|
1656
|
+
}
|
|
1657
|
+
get isExpired() {
|
|
1658
|
+
const card = this.paymentMethod().card;
|
|
1659
|
+
if (!card?.exp_month || !card?.exp_year)
|
|
1660
|
+
return false;
|
|
1661
|
+
const now = new Date();
|
|
1662
|
+
const expDate = new Date(card.exp_year, card.exp_month - 1);
|
|
1663
|
+
return expDate < now;
|
|
1664
|
+
}
|
|
1665
|
+
get cardFunding() {
|
|
1666
|
+
return this.paymentMethod().card?.funding;
|
|
1667
|
+
}
|
|
1668
|
+
get cardCountry() {
|
|
1669
|
+
return this.paymentMethod().card?.country || undefined;
|
|
1670
|
+
}
|
|
1671
|
+
get billingEmail() {
|
|
1672
|
+
return this.paymentMethod().billing_details?.email || undefined;
|
|
1673
|
+
}
|
|
1674
|
+
get billingPhone() {
|
|
1675
|
+
return this.paymentMethod().billing_details?.phone || undefined;
|
|
1676
|
+
}
|
|
1677
|
+
get billingAddress() {
|
|
1678
|
+
return this.paymentMethod().billing_details?.address;
|
|
1679
|
+
}
|
|
1680
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: PaymentMethodComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1681
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.5", type: PaymentMethodComponent, isStandalone: true, selector: "ngx-payment-method", inputs: { paymentMethod: { classPropertyName: "paymentMethod", publicName: "paymentMethod", isSignal: true, isRequired: true, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<!-- Detailed Version -->\n@if (mode() === 'detailed') {\n <div class=\"w-full max-w-md mx-auto\">\n <!-- Stack of Credit Cards -->\n <div class=\"stack w-full h-56\">\n <div class=\"bg-gradient-to-br from-primary to-accent text-neutral-content relative place-content-center rounded-box\">\n <div class=\"card-body p-6 relative z-10\">\n <!-- Card Header -->\n <div class=\"flex justify-between items-start mb-6\">\n <div class=\"flex items-center gap-2\">\n <!--<span class=\"text-3xl filter drop-shadow-lg\" [ngxBrandIcon]=\"paymentMethod()\"></span>-->\n <div class=\"font-bold text-lg text-primary-content\" [ngxBrandName]=\"paymentMethod()\"></div>\n @if (cardCountry) {\n <div class=\"text-xs text-primary-content/60 uppercase\">{{ cardCountry }}</div>\n }\n @if (isExpired) {\n <div class=\"badge badge-error badge-sm animate-pulse\">Expirada</div>\n }\n </div>\n </div>\n\n <!-- Card Number -->\n <div class=\"mb-6\">\n <div class=\"font-mono text-xl tracking-wider text-primary-content\">\n **** **** **** {{ last4 }}\n </div>\n </div>\n\n <!-- Card Bottom Info -->\n <div class=\"flex justify-start items-end\">\n <div class=\"flex-1\">\n <div class=\"text-xs text-primary-content/60 mb-1\">TITULAR</div>\n <div class=\"font-medium text-sm text-primary-content truncate max-w-32\">{{ holderName }}</div>\n </div>\n \n @if (expirationDate) {\n <div class=\"flex-1\">\n <div class=\"text-xs text-primary-content/60 mb-1\">V\u00C1LIDA HASTA</div>\n <div class=\"font-mono text-sm text-primary-content\">{{ expirationDate }}</div>\n </div>\n }\n </div>\n </div>\n\n <!-- Card Background Pattern -->\n <div class=\"absolute inset-0 opacity-20\">\n <div class=\"absolute top-4 right-4 w-20 h-20 rounded-full bg-primary-content/30\"></div>\n <div class=\"absolute bottom-4 left-4 w-16 h-16 rounded-full bg-primary-content/20\"></div>\n <div class=\"absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-32 h-32 rounded-full bg-primary-content/10\"></div>\n </div>\n </div>\n <div class=\"bg-secondary grid place-content-center rounded-box\"></div>\n <div class=\"bg-accent grid place-content-center rounded-box\"></div>\n </div>\n\n <!-- Additional Information Below Cards -->\n <div class=\"mt-6 space-y-4\">\n <!-- Billing Information -->\n @if (billingEmail || billingPhone) {\n <div class=\"card bg-base-100 shadow-sm border border-base-200\">\n <div class=\"card-body p-4\">\n <h4 class=\"card-title text-sm mb-3 flex items-center gap-2\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z\" />\n </svg>\n Informaci\u00F3n de Contacto\n </h4>\n \n <div class=\"space-y-2\">\n @if (billingEmail) {\n <div class=\"flex items-center gap-2 text-sm\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-4 w-4 text-base-content/60\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M16 12a4 4 0 10-8 0 4 4 0 008 0zm0 0v1.5a2.5 2.5 0 005 0V12a9 9 0 10-9 9m4.5-1.206a8.959 8.959 0 01-4.5 1.207\" />\n </svg>\n <span class=\"text-base-content/70\">{{ billingEmail }}</span>\n </div>\n }\n \n @if (billingPhone) {\n <div class=\"flex items-center gap-2 text-sm\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-4 w-4 text-base-content/60\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z\" />\n </svg>\n <span class=\"text-base-content/70\">{{ billingPhone }}</span>\n </div>\n }\n </div>\n </div>\n </div>\n }\n\n <!-- Billing Address -->\n @if (billingAddress && (billingAddress.line1 || billingAddress.city)) {\n <div class=\"card bg-base-100 shadow-sm border border-base-200\">\n <div class=\"card-body p-4\">\n <h4 class=\"card-title text-sm mb-3 flex items-center gap-2\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z\" />\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M15 11a3 3 0 11-6 0 3 3 0 016 0z\" />\n </svg>\n Direcci\u00F3n de Facturaci\u00F3n\n </h4>\n \n <div class=\"text-sm text-base-content/70 space-y-1\">\n @if (billingAddress.line1) {\n <div>{{ billingAddress.line1 }}</div>\n @if (billingAddress.line2) {\n <div>{{ billingAddress.line2 }}</div>\n }\n }\n \n <div class=\"flex gap-2 flex-wrap\">\n @if (billingAddress.city) {\n <span>{{ billingAddress.city }}</span>\n }\n @if (billingAddress.postal_code) {\n <span>{{ billingAddress.postal_code }}</span>\n }\n @if (billingAddress.country) {\n <span class=\"uppercase\">{{ billingAddress.country }}</span>\n }\n </div>\n </div>\n </div>\n </div>\n }\n\n <!-- Card Creation Date -->\n <div class=\"flex items-center justify-between text-sm text-base-content/60 px-2\">\n <span>M\u00E9todo agregado:</span>\n <span>{{ paymentMethod().created * 1000 | date:'short' }}</span>\n </div>\n </div>\n </div>\n}\n\n<!-- Compact Version -->\n@if (mode() === 'compact') {\n <div class=\"flex items-center gap-2\">\n <!--<span class=\"text-xl filter drop-shadow-sm\" [ngxBrandIcon]=\"paymentMethod()\"></span>-->\n \n <div class=\"flex-1 min-w-0\">\n <div class=\"flex items-center gap-2\">\n <span class=\"font-medium\" [ngxBrandName]=\"paymentMethod()\"></span>\n <span class=\"text-base-content/70\">\u2022\u2022\u2022\u2022 {{ last4 }}</span>\n @if (paymentMethod().type === 'card' && expirationDate) {\n <span class=\"text-base-content/70 text-sm\">{{ expirationDate }}</span>\n }\n </div>\n </div>\n\n @if (isExpired) {\n <div class=\"badge badge-error badge-sm animate-pulse\">Expirada</div>\n } @else {\n <div class=\"badge badge-success badge-sm\">Activa</div>\n }\n </div>\n}\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i1.DatePipe, name: "date" }, { kind: "directive", type: BrandNameDirective, selector: "[ngxBrandName]", inputs: ["ngxBrandName"] }] });
|
|
1682
|
+
}
|
|
1683
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: PaymentMethodComponent, decorators: [{
|
|
1684
|
+
type: Component,
|
|
1685
|
+
args: [{ selector: 'ngx-payment-method', standalone: true, imports: [CommonModule, BrandIconDirective, BrandNameDirective, PaymentMethodTypeDirective], template: "<!-- Detailed Version -->\n@if (mode() === 'detailed') {\n <div class=\"w-full max-w-md mx-auto\">\n <!-- Stack of Credit Cards -->\n <div class=\"stack w-full h-56\">\n <div class=\"bg-gradient-to-br from-primary to-accent text-neutral-content relative place-content-center rounded-box\">\n <div class=\"card-body p-6 relative z-10\">\n <!-- Card Header -->\n <div class=\"flex justify-between items-start mb-6\">\n <div class=\"flex items-center gap-2\">\n <!--<span class=\"text-3xl filter drop-shadow-lg\" [ngxBrandIcon]=\"paymentMethod()\"></span>-->\n <div class=\"font-bold text-lg text-primary-content\" [ngxBrandName]=\"paymentMethod()\"></div>\n @if (cardCountry) {\n <div class=\"text-xs text-primary-content/60 uppercase\">{{ cardCountry }}</div>\n }\n @if (isExpired) {\n <div class=\"badge badge-error badge-sm animate-pulse\">Expirada</div>\n }\n </div>\n </div>\n\n <!-- Card Number -->\n <div class=\"mb-6\">\n <div class=\"font-mono text-xl tracking-wider text-primary-content\">\n **** **** **** {{ last4 }}\n </div>\n </div>\n\n <!-- Card Bottom Info -->\n <div class=\"flex justify-start items-end\">\n <div class=\"flex-1\">\n <div class=\"text-xs text-primary-content/60 mb-1\">TITULAR</div>\n <div class=\"font-medium text-sm text-primary-content truncate max-w-32\">{{ holderName }}</div>\n </div>\n \n @if (expirationDate) {\n <div class=\"flex-1\">\n <div class=\"text-xs text-primary-content/60 mb-1\">V\u00C1LIDA HASTA</div>\n <div class=\"font-mono text-sm text-primary-content\">{{ expirationDate }}</div>\n </div>\n }\n </div>\n </div>\n\n <!-- Card Background Pattern -->\n <div class=\"absolute inset-0 opacity-20\">\n <div class=\"absolute top-4 right-4 w-20 h-20 rounded-full bg-primary-content/30\"></div>\n <div class=\"absolute bottom-4 left-4 w-16 h-16 rounded-full bg-primary-content/20\"></div>\n <div class=\"absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-32 h-32 rounded-full bg-primary-content/10\"></div>\n </div>\n </div>\n <div class=\"bg-secondary grid place-content-center rounded-box\"></div>\n <div class=\"bg-accent grid place-content-center rounded-box\"></div>\n </div>\n\n <!-- Additional Information Below Cards -->\n <div class=\"mt-6 space-y-4\">\n <!-- Billing Information -->\n @if (billingEmail || billingPhone) {\n <div class=\"card bg-base-100 shadow-sm border border-base-200\">\n <div class=\"card-body p-4\">\n <h4 class=\"card-title text-sm mb-3 flex items-center gap-2\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z\" />\n </svg>\n Informaci\u00F3n de Contacto\n </h4>\n \n <div class=\"space-y-2\">\n @if (billingEmail) {\n <div class=\"flex items-center gap-2 text-sm\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-4 w-4 text-base-content/60\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M16 12a4 4 0 10-8 0 4 4 0 008 0zm0 0v1.5a2.5 2.5 0 005 0V12a9 9 0 10-9 9m4.5-1.206a8.959 8.959 0 01-4.5 1.207\" />\n </svg>\n <span class=\"text-base-content/70\">{{ billingEmail }}</span>\n </div>\n }\n \n @if (billingPhone) {\n <div class=\"flex items-center gap-2 text-sm\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-4 w-4 text-base-content/60\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z\" />\n </svg>\n <span class=\"text-base-content/70\">{{ billingPhone }}</span>\n </div>\n }\n </div>\n </div>\n </div>\n }\n\n <!-- Billing Address -->\n @if (billingAddress && (billingAddress.line1 || billingAddress.city)) {\n <div class=\"card bg-base-100 shadow-sm border border-base-200\">\n <div class=\"card-body p-4\">\n <h4 class=\"card-title text-sm mb-3 flex items-center gap-2\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z\" />\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M15 11a3 3 0 11-6 0 3 3 0 016 0z\" />\n </svg>\n Direcci\u00F3n de Facturaci\u00F3n\n </h4>\n \n <div class=\"text-sm text-base-content/70 space-y-1\">\n @if (billingAddress.line1) {\n <div>{{ billingAddress.line1 }}</div>\n @if (billingAddress.line2) {\n <div>{{ billingAddress.line2 }}</div>\n }\n }\n \n <div class=\"flex gap-2 flex-wrap\">\n @if (billingAddress.city) {\n <span>{{ billingAddress.city }}</span>\n }\n @if (billingAddress.postal_code) {\n <span>{{ billingAddress.postal_code }}</span>\n }\n @if (billingAddress.country) {\n <span class=\"uppercase\">{{ billingAddress.country }}</span>\n }\n </div>\n </div>\n </div>\n </div>\n }\n\n <!-- Card Creation Date -->\n <div class=\"flex items-center justify-between text-sm text-base-content/60 px-2\">\n <span>M\u00E9todo agregado:</span>\n <span>{{ paymentMethod().created * 1000 | date:'short' }}</span>\n </div>\n </div>\n </div>\n}\n\n<!-- Compact Version -->\n@if (mode() === 'compact') {\n <div class=\"flex items-center gap-2\">\n <!--<span class=\"text-xl filter drop-shadow-sm\" [ngxBrandIcon]=\"paymentMethod()\"></span>-->\n \n <div class=\"flex-1 min-w-0\">\n <div class=\"flex items-center gap-2\">\n <span class=\"font-medium\" [ngxBrandName]=\"paymentMethod()\"></span>\n <span class=\"text-base-content/70\">\u2022\u2022\u2022\u2022 {{ last4 }}</span>\n @if (paymentMethod().type === 'card' && expirationDate) {\n <span class=\"text-base-content/70 text-sm\">{{ expirationDate }}</span>\n }\n </div>\n </div>\n\n @if (isExpired) {\n <div class=\"badge badge-error badge-sm animate-pulse\">Expirada</div>\n } @else {\n <div class=\"badge badge-success badge-sm\">Activa</div>\n }\n </div>\n}\n" }]
|
|
1686
|
+
}] });
|
|
1687
|
+
|
|
1688
|
+
class PaymentIntentsDialogComponent {
|
|
1689
|
+
paymentIntent = input.required();
|
|
1690
|
+
dialogId = input.required();
|
|
1691
|
+
utils = new UtilsService();
|
|
1692
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: PaymentIntentsDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1693
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.5", type: PaymentIntentsDialogComponent, isStandalone: true, selector: "lib-payment-intents-dialog", inputs: { paymentIntent: { classPropertyName: "paymentIntent", publicName: "paymentIntent", isSignal: true, isRequired: true, transformFunction: null }, dialogId: { classPropertyName: "dialogId", publicName: "dialogId", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<dialog [id]=\"dialogId()\" class=\"modal\">\n <div class=\"modal-box max-w-2xl\">\n <h3 class=\"font-bold text-lg mb-4\">Detalles del Payment Intent</h3>\n \n <!-- Header with Amount and Status -->\n <div class=\"flex items-center gap-3 mb-6 p-4 bg-base-200 rounded-lg\">\n <div class=\"flex-1\">\n <div class=\"text-3xl font-bold text-primary\">\n {{ utils.formatAmount(paymentIntent().amount ?? 0, paymentIntent().currency ?? 'EUR') }}\n </div>\n <div class=\"text-sm text-base-content/70\">\n {{ (paymentIntent().currency ?? 'EUR').toUpperCase() }}\n </div>\n </div>\n <div class=\"flex gap-2\">\n <div class=\"badge {{ utils.getStatusBadgeClass(paymentIntent().status) }}\">\n {{ paymentIntent().status }}\n </div>\n @if (!paymentIntent().liveMode) {\n <div class=\"badge badge-warning\">TEST</div>\n }\n </div>\n </div>\n\n <div class=\"space-y-6\">\n <!-- Transaction Details -->\n <div>\n <h4 class=\"text-sm font-semibold text-base-content/80 mb-3 flex items-center gap-2\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z\" />\n </svg>\n Detalles de la Transacci\u00F3n\n </h4>\n \n <div class=\"grid grid-cols-1 sm:grid-cols-2 gap-3\">\n <div class=\"stat bg-base-200 rounded-lg p-3\">\n <div class=\"stat-title text-xs\">Estado</div>\n <div class=\"stat-value text-sm capitalize\">{{ paymentIntent().status }}</div>\n <div class=\"stat-desc\">{{ paymentIntent().liveMode ? 'Producci\u00F3n' : 'Pruebas' }}</div>\n </div>\n \n <div class=\"stat bg-base-200 rounded-lg p-3\">\n <div class=\"stat-title text-xs\">Monto</div>\n <div class=\"stat-value text-sm\">{{ utils.formatAmount(paymentIntent().amount ?? 0, paymentIntent().currency ?? 'EUR') }}</div>\n <div class=\"stat-desc\">{{ (paymentIntent().currency ?? 'EUR').toUpperCase() }}</div>\n </div>\n </div>\n\n <!-- Confirmation Method -->\n <div class=\"mt-3 flex items-center gap-2 text-sm p-2 bg-base-200 rounded\">\n <div class=\"w-2 h-2 bg-success rounded-full\"></div>\n <span class=\"text-base-content/70\">Confirmaci\u00F3n:</span>\n <span class=\"capitalize font-medium\">{{ paymentIntent().confirmationMethod.replace('_', ' ') }}</span>\n </div>\n </div>\n\n <!-- Payment Information -->\n @if (paymentIntent().paymentMethod) {\n <div>\n <h4 class=\"text-sm font-semibold text-base-content/80 mb-3 flex items-center gap-2\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z\" />\n </svg>\n Informaci\u00F3n del Pago\n </h4>\n \n <ngx-payment-method \n [paymentMethod]=\"paymentIntent().paymentMethod!\" \n mode=\"detailed\">\n </ngx-payment-method>\n </div>\n }\n\n <!-- Additional Information -->\n <div>\n <h4 class=\"text-sm font-semibold text-base-content/80 mb-3 flex items-center gap-2\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z\" />\n </svg>\n Informaci\u00F3n Adicional\n </h4>\n \n <div class=\"space-y-2\">\n @if (paymentIntent().invoiceId) {\n <div class=\"flex items-center justify-between p-2 bg-base-200 rounded\">\n <span class=\"text-sm text-base-content/70\">Factura</span>\n <span class=\"text-sm font-mono\">{{ paymentIntent().invoiceId.slice(-8) }}</span>\n </div>\n }\n \n <div class=\"flex items-center justify-between p-2 bg-base-200 rounded\">\n <span class=\"text-sm text-base-content/70\">Entorno</span>\n <span class=\"text-sm\">\n @if (paymentIntent().liveMode) {\n <span class=\"text-success\">Producci\u00F3n</span>\n } @else {\n <span class=\"text-warning\">Pruebas</span>\n }\n </span>\n </div>\n \n <div class=\"flex items-center justify-between p-2 bg-base-200 rounded\">\n <span class=\"text-sm text-base-content/70\">Referencia</span>\n <span class=\"text-sm font-mono\">\u2022\u2022\u2022{{ paymentIntent().id?.slice(-6) || 'N/A' }}</span>\n </div>\n </div>\n </div>\n </div>\n\n <div class=\"modal-action\">\n <form method=\"dialog\">\n <button class=\"btn btn-primary\">Cerrar</button>\n </form>\n </div>\n </div>\n</dialog>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: PaymentMethodComponent, selector: "ngx-payment-method", inputs: ["paymentMethod", "mode"] }] });
|
|
1694
|
+
}
|
|
1695
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: PaymentIntentsDialogComponent, decorators: [{
|
|
1696
|
+
type: Component,
|
|
1697
|
+
args: [{ selector: 'lib-payment-intents-dialog', standalone: true, imports: [CommonModule, PaymentMethodComponent], template: "<dialog [id]=\"dialogId()\" class=\"modal\">\n <div class=\"modal-box max-w-2xl\">\n <h3 class=\"font-bold text-lg mb-4\">Detalles del Payment Intent</h3>\n \n <!-- Header with Amount and Status -->\n <div class=\"flex items-center gap-3 mb-6 p-4 bg-base-200 rounded-lg\">\n <div class=\"flex-1\">\n <div class=\"text-3xl font-bold text-primary\">\n {{ utils.formatAmount(paymentIntent().amount ?? 0, paymentIntent().currency ?? 'EUR') }}\n </div>\n <div class=\"text-sm text-base-content/70\">\n {{ (paymentIntent().currency ?? 'EUR').toUpperCase() }}\n </div>\n </div>\n <div class=\"flex gap-2\">\n <div class=\"badge {{ utils.getStatusBadgeClass(paymentIntent().status) }}\">\n {{ paymentIntent().status }}\n </div>\n @if (!paymentIntent().liveMode) {\n <div class=\"badge badge-warning\">TEST</div>\n }\n </div>\n </div>\n\n <div class=\"space-y-6\">\n <!-- Transaction Details -->\n <div>\n <h4 class=\"text-sm font-semibold text-base-content/80 mb-3 flex items-center gap-2\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z\" />\n </svg>\n Detalles de la Transacci\u00F3n\n </h4>\n \n <div class=\"grid grid-cols-1 sm:grid-cols-2 gap-3\">\n <div class=\"stat bg-base-200 rounded-lg p-3\">\n <div class=\"stat-title text-xs\">Estado</div>\n <div class=\"stat-value text-sm capitalize\">{{ paymentIntent().status }}</div>\n <div class=\"stat-desc\">{{ paymentIntent().liveMode ? 'Producci\u00F3n' : 'Pruebas' }}</div>\n </div>\n \n <div class=\"stat bg-base-200 rounded-lg p-3\">\n <div class=\"stat-title text-xs\">Monto</div>\n <div class=\"stat-value text-sm\">{{ utils.formatAmount(paymentIntent().amount ?? 0, paymentIntent().currency ?? 'EUR') }}</div>\n <div class=\"stat-desc\">{{ (paymentIntent().currency ?? 'EUR').toUpperCase() }}</div>\n </div>\n </div>\n\n <!-- Confirmation Method -->\n <div class=\"mt-3 flex items-center gap-2 text-sm p-2 bg-base-200 rounded\">\n <div class=\"w-2 h-2 bg-success rounded-full\"></div>\n <span class=\"text-base-content/70\">Confirmaci\u00F3n:</span>\n <span class=\"capitalize font-medium\">{{ paymentIntent().confirmationMethod.replace('_', ' ') }}</span>\n </div>\n </div>\n\n <!-- Payment Information -->\n @if (paymentIntent().paymentMethod) {\n <div>\n <h4 class=\"text-sm font-semibold text-base-content/80 mb-3 flex items-center gap-2\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z\" />\n </svg>\n Informaci\u00F3n del Pago\n </h4>\n \n <ngx-payment-method \n [paymentMethod]=\"paymentIntent().paymentMethod!\" \n mode=\"detailed\">\n </ngx-payment-method>\n </div>\n }\n\n <!-- Additional Information -->\n <div>\n <h4 class=\"text-sm font-semibold text-base-content/80 mb-3 flex items-center gap-2\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z\" />\n </svg>\n Informaci\u00F3n Adicional\n </h4>\n \n <div class=\"space-y-2\">\n @if (paymentIntent().invoiceId) {\n <div class=\"flex items-center justify-between p-2 bg-base-200 rounded\">\n <span class=\"text-sm text-base-content/70\">Factura</span>\n <span class=\"text-sm font-mono\">{{ paymentIntent().invoiceId.slice(-8) }}</span>\n </div>\n }\n \n <div class=\"flex items-center justify-between p-2 bg-base-200 rounded\">\n <span class=\"text-sm text-base-content/70\">Entorno</span>\n <span class=\"text-sm\">\n @if (paymentIntent().liveMode) {\n <span class=\"text-success\">Producci\u00F3n</span>\n } @else {\n <span class=\"text-warning\">Pruebas</span>\n }\n </span>\n </div>\n \n <div class=\"flex items-center justify-between p-2 bg-base-200 rounded\">\n <span class=\"text-sm text-base-content/70\">Referencia</span>\n <span class=\"text-sm font-mono\">\u2022\u2022\u2022{{ paymentIntent().id?.slice(-6) || 'N/A' }}</span>\n </div>\n </div>\n </div>\n </div>\n\n <div class=\"modal-action\">\n <form method=\"dialog\">\n <button class=\"btn btn-primary\">Cerrar</button>\n </form>\n </div>\n </div>\n</dialog>\n" }]
|
|
1698
|
+
}] });
|
|
1699
|
+
|
|
1360
1700
|
class PaymentIntentsTableComponent {
|
|
1361
1701
|
paymentIntents = input.required();
|
|
1362
1702
|
paymentIntentsTable = computed(() => {
|
|
@@ -1407,13 +1747,15 @@ class PaymentIntentsTableComponent {
|
|
|
1407
1747
|
this.exportSelected.emit(this.paymentIntentsTable().filter(paymentIntent => paymentIntent.selected));
|
|
1408
1748
|
}
|
|
1409
1749
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: PaymentIntentsTableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1410
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.5", type: PaymentIntentsTableComponent, isStandalone: true, selector: "lib-payment-intents-table", inputs: { paymentIntents: { classPropertyName: "paymentIntents", publicName: "paymentIntents", isSignal: true, isRequired: true, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, withControls: { classPropertyName: "withControls", publicName: "withControls", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { exportSelected: "exportSelected", onRefresh: "onRefresh" }, ngImport: i0, template: "<div class=\"payment-intents-container\">\n @if (withControls()) {\n <div class=\"controls mb-4 flex justify-between items-center\">\n <div class=\"stats\">\n @if (hasPaymentIntents()) {\n <span class=\"badge badge-soft badge-info\">{{ paymentIntentsTable().length }} payment intents</span>\n }\n </div>\n <div class=\"flex justify-end items-center gap-2\">\n <button class=\"btn btn-sm btn-outline\" (click)=\"refreshPaymentIntents()\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-4 w-4 mr-1\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15\" />\n </svg>\n Actualizar\n </button>\n <button class=\"btn btn-sm btn-primary\" [disabled]=\"!somePaymentIntentsSelected()\" (click)=\"exportSelectedPaymentIntents()\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"1em\" height=\"1em\" viewBox=\"0 0 24 24\"><path fill=\"currentColor\" d=\"M8.71 7.71L11 5.41V15a1 1 0 0 0 2 0V5.41l2.29 2.3a1 1 0 0 0 1.42 0a1 1 0 0 0 0-1.42l-4-4a1 1 0 0 0-.33-.21a1 1 0 0 0-.76 0a1 1 0 0 0-.33.21l-4 4a1 1 0 1 0 1.42 1.42M21 14a1 1 0 0 0-1 1v4a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-4a1 1 0 0 0-2 0v4a3 3 0 0 0 3 3h14a3 3 0 0 0 3-3v-4a1 1 0 0 0-1-1\"/></svg>\n Export Selected\n </button>\n </div>\n </div>\n }\n\n @if (loading()) {\n <div class=\"overflow-x-auto\">\n <div class=\"skeleton h-32 w-full\"></div>\n </div>\n } @else if (error()) {\n <div class=\"error-container\">\n <div class=\"alert alert-error\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"stroke-current shrink-0 h-6 w-6\" fill=\"none\" viewBox=\"0 0 24 24\"><path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z\" /></svg>\n <span>{{ error() }}</span>\n </div>\n </div>\n } @else if (hasPaymentIntents()) {\n <div class=\"overflow-x-auto rounded-box bg-base-100\">\n <table class=\"table table-zebra\">\n <!-- head -->\n <thead>\n <tr>\n <th>\n <label>\n <input type=\"checkbox\" class=\"checkbox\" (change)=\"toggleAllPaymentIntents($event)\" [checked]=\"allPaymentIntentsSelected()\" />\n </label>\n </th>\n <th>Amount</th>\n <th>Payment Method</th>\n <th>Status</th>\n <th>Mode</th>\n <th></th>\n </tr>\n </thead>\n <tbody>\n @for (paymentIntent of paymentIntentsTable(); track trackByPaymentIntentId(0, paymentIntent)) {\n <tr>\n <th>\n <label>\n <input type=\"checkbox\" class=\"checkbox\" (change)=\"togglePaymentIntent($event, paymentIntent.id ?? '')\" [checked]=\"paymentIntent.selected\" />\n </label>\n </th>\n <td>{{ utils.formatAmount(paymentIntent.amount ?? 0, paymentIntent.currency ?? 'EUR') }}</td>\n <td>\n <span class=\"badge badge-outline\">\n
|
|
1750
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.5", type: PaymentIntentsTableComponent, isStandalone: true, selector: "lib-payment-intents-table", inputs: { paymentIntents: { classPropertyName: "paymentIntents", publicName: "paymentIntents", isSignal: true, isRequired: true, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, withControls: { classPropertyName: "withControls", publicName: "withControls", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { exportSelected: "exportSelected", onRefresh: "onRefresh" }, ngImport: i0, template: "<div class=\"payment-intents-container\">\n @if (withControls()) {\n <div class=\"controls mb-4 flex justify-between items-center\">\n <div class=\"stats\">\n @if (hasPaymentIntents()) {\n <span class=\"badge badge-soft badge-info\">{{ paymentIntentsTable().length }} payment intents</span>\n }\n </div>\n <div class=\"flex justify-end items-center gap-2\">\n <button class=\"btn btn-sm btn-outline\" (click)=\"refreshPaymentIntents()\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-4 w-4 mr-1\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15\" />\n </svg>\n Actualizar\n </button>\n <button class=\"btn btn-sm btn-primary\" [disabled]=\"!somePaymentIntentsSelected()\" (click)=\"exportSelectedPaymentIntents()\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"1em\" height=\"1em\" viewBox=\"0 0 24 24\"><path fill=\"currentColor\" d=\"M8.71 7.71L11 5.41V15a1 1 0 0 0 2 0V5.41l2.29 2.3a1 1 0 0 0 1.42 0a1 1 0 0 0 0-1.42l-4-4a1 1 0 0 0-.33-.21a1 1 0 0 0-.76 0a1 1 0 0 0-.33.21l-4 4a1 1 0 1 0 1.42 1.42M21 14a1 1 0 0 0-1 1v4a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-4a1 1 0 0 0-2 0v4a3 3 0 0 0 3 3h14a3 3 0 0 0 3-3v-4a1 1 0 0 0-1-1\"/></svg>\n Export Selected\n </button>\n </div>\n </div>\n }\n\n @if (loading()) {\n <div class=\"overflow-x-auto\">\n <div class=\"skeleton h-32 w-full\"></div>\n </div>\n } @else if (error()) {\n <div class=\"error-container\">\n <div class=\"alert alert-error\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"stroke-current shrink-0 h-6 w-6\" fill=\"none\" viewBox=\"0 0 24 24\"><path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z\" /></svg>\n <span>{{ error() }}</span>\n </div>\n </div>\n } @else if (hasPaymentIntents()) {\n <div class=\"overflow-x-auto rounded-box bg-base-100\">\n <table class=\"table table-zebra\">\n <!-- head -->\n <thead>\n <tr>\n <th>\n <label>\n <input type=\"checkbox\" class=\"checkbox\" (change)=\"toggleAllPaymentIntents($event)\" [checked]=\"allPaymentIntentsSelected()\" />\n </label>\n </th>\n <th>Amount</th>\n <th>Payment Method</th>\n <th>Status</th>\n <th>Mode</th>\n <th></th>\n </tr>\n </thead>\n <tbody>\n @for (paymentIntent of paymentIntentsTable(); track trackByPaymentIntentId(0, paymentIntent)) {\n <tr>\n <th>\n <label>\n <input type=\"checkbox\" class=\"checkbox\" (change)=\"togglePaymentIntent($event, paymentIntent.id ?? '')\" [checked]=\"paymentIntent.selected\" />\n </label>\n </th>\n <td>{{ utils.formatAmount(paymentIntent.amount ?? 0, paymentIntent.currency ?? 'EUR') }}</td>\n <td>\n @if (paymentIntent.paymentMethod) {\n <ngx-payment-method \n [paymentMethod]=\"paymentIntent.paymentMethod!\" \n mode=\"compact\">\n </ngx-payment-method>\n } @else {\n <span class=\"badge badge-outline\">\n {{ paymentIntent.paymentMethodId }}\n </span>\n }\n </td>\n <td>\n <span class=\"badge badge-soft {{ utils.getStatusBadgeClass(paymentIntent.status) }}\">\n {{ paymentIntent.status}}\n </span>\n </td>\n <td>{{ paymentIntent.liveMode ? 'Live' : 'Test' }}</td>\n <td>\n <button class=\"btn btn-xs btn-ghost\" (click)=\"showDetails(paymentIntent.id ?? '')\">\n Details\n </button>\n <lib-payment-intents-dialog \n [paymentIntent]=\"paymentIntent\" \n [dialogId]=\"'modal-' + paymentIntent.id\">\n </lib-payment-intents-dialog>\n </td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n } @else {\n <div class=\"empty-state\">\n <div class=\"card bg-base-100 shadow-sm\">\n <div class=\"card-body items-center text-center\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-12 w-12 text-gray-400 mb-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z\" />\n </svg>\n <h2 class=\"card-title text-xl\">No recent payment intents</h2>\n <p class=\"text-gray-600\">No payment intents found in your history.</p>\n </div>\n </div>\n </div>\n }\n</div> ", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: PaymentMethodComponent, selector: "ngx-payment-method", inputs: ["paymentMethod", "mode"] }, { kind: "component", type: PaymentIntentsDialogComponent, selector: "lib-payment-intents-dialog", inputs: ["paymentIntent", "dialogId"] }] });
|
|
1411
1751
|
}
|
|
1412
1752
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: PaymentIntentsTableComponent, decorators: [{
|
|
1413
1753
|
type: Component,
|
|
1414
1754
|
args: [{ selector: 'lib-payment-intents-table', standalone: true, imports: [
|
|
1415
|
-
CommonModule
|
|
1416
|
-
|
|
1755
|
+
CommonModule,
|
|
1756
|
+
PaymentMethodComponent,
|
|
1757
|
+
PaymentIntentsDialogComponent
|
|
1758
|
+
], template: "<div class=\"payment-intents-container\">\n @if (withControls()) {\n <div class=\"controls mb-4 flex justify-between items-center\">\n <div class=\"stats\">\n @if (hasPaymentIntents()) {\n <span class=\"badge badge-soft badge-info\">{{ paymentIntentsTable().length }} payment intents</span>\n }\n </div>\n <div class=\"flex justify-end items-center gap-2\">\n <button class=\"btn btn-sm btn-outline\" (click)=\"refreshPaymentIntents()\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-4 w-4 mr-1\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15\" />\n </svg>\n Actualizar\n </button>\n <button class=\"btn btn-sm btn-primary\" [disabled]=\"!somePaymentIntentsSelected()\" (click)=\"exportSelectedPaymentIntents()\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"1em\" height=\"1em\" viewBox=\"0 0 24 24\"><path fill=\"currentColor\" d=\"M8.71 7.71L11 5.41V15a1 1 0 0 0 2 0V5.41l2.29 2.3a1 1 0 0 0 1.42 0a1 1 0 0 0 0-1.42l-4-4a1 1 0 0 0-.33-.21a1 1 0 0 0-.76 0a1 1 0 0 0-.33.21l-4 4a1 1 0 1 0 1.42 1.42M21 14a1 1 0 0 0-1 1v4a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-4a1 1 0 0 0-2 0v4a3 3 0 0 0 3 3h14a3 3 0 0 0 3-3v-4a1 1 0 0 0-1-1\"/></svg>\n Export Selected\n </button>\n </div>\n </div>\n }\n\n @if (loading()) {\n <div class=\"overflow-x-auto\">\n <div class=\"skeleton h-32 w-full\"></div>\n </div>\n } @else if (error()) {\n <div class=\"error-container\">\n <div class=\"alert alert-error\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"stroke-current shrink-0 h-6 w-6\" fill=\"none\" viewBox=\"0 0 24 24\"><path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z\" /></svg>\n <span>{{ error() }}</span>\n </div>\n </div>\n } @else if (hasPaymentIntents()) {\n <div class=\"overflow-x-auto rounded-box bg-base-100\">\n <table class=\"table table-zebra\">\n <!-- head -->\n <thead>\n <tr>\n <th>\n <label>\n <input type=\"checkbox\" class=\"checkbox\" (change)=\"toggleAllPaymentIntents($event)\" [checked]=\"allPaymentIntentsSelected()\" />\n </label>\n </th>\n <th>Amount</th>\n <th>Payment Method</th>\n <th>Status</th>\n <th>Mode</th>\n <th></th>\n </tr>\n </thead>\n <tbody>\n @for (paymentIntent of paymentIntentsTable(); track trackByPaymentIntentId(0, paymentIntent)) {\n <tr>\n <th>\n <label>\n <input type=\"checkbox\" class=\"checkbox\" (change)=\"togglePaymentIntent($event, paymentIntent.id ?? '')\" [checked]=\"paymentIntent.selected\" />\n </label>\n </th>\n <td>{{ utils.formatAmount(paymentIntent.amount ?? 0, paymentIntent.currency ?? 'EUR') }}</td>\n <td>\n @if (paymentIntent.paymentMethod) {\n <ngx-payment-method \n [paymentMethod]=\"paymentIntent.paymentMethod!\" \n mode=\"compact\">\n </ngx-payment-method>\n } @else {\n <span class=\"badge badge-outline\">\n {{ paymentIntent.paymentMethodId }}\n </span>\n }\n </td>\n <td>\n <span class=\"badge badge-soft {{ utils.getStatusBadgeClass(paymentIntent.status) }}\">\n {{ paymentIntent.status}}\n </span>\n </td>\n <td>{{ paymentIntent.liveMode ? 'Live' : 'Test' }}</td>\n <td>\n <button class=\"btn btn-xs btn-ghost\" (click)=\"showDetails(paymentIntent.id ?? '')\">\n Details\n </button>\n <lib-payment-intents-dialog \n [paymentIntent]=\"paymentIntent\" \n [dialogId]=\"'modal-' + paymentIntent.id\">\n </lib-payment-intents-dialog>\n </td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n } @else {\n <div class=\"empty-state\">\n <div class=\"card bg-base-100 shadow-sm\">\n <div class=\"card-body items-center text-center\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-12 w-12 text-gray-400 mb-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z\" />\n </svg>\n <h2 class=\"card-title text-xl\">No recent payment intents</h2>\n <p class=\"text-gray-600\">No payment intents found in your history.</p>\n </div>\n </div>\n </div>\n }\n</div> " }]
|
|
1417
1759
|
}] });
|
|
1418
1760
|
|
|
1419
1761
|
class SubscriptionItemSkeletonComponent {
|
|
@@ -1425,75 +1767,33 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImpor
|
|
|
1425
1767
|
args: [{ selector: 'lib-subscription-item-skeleton', standalone: true, imports: [CommonModule], template: "<div class=\"card bg-base-100 shadow-sm\">\n <div class=\"card-body p-4\">\n <div class=\"flex justify-between\">\n <div>\n <div class=\"flex items-center gap-2\">\n <div class=\"skeleton h-6 w-32\"></div>\n <div class=\"skeleton h-5 w-20\"></div>\n </div>\n <div class=\"skeleton h-4 w-48 mt-2\"></div>\n </div>\n \n <div class=\"flex gap-2\">\n <div class=\"skeleton h-8 w-20\"></div>\n </div>\n </div>\n\n <div class=\"mt-2\">\n <div class=\"flex justify-between text-sm\">\n <div class=\"skeleton h-4 w-32\"></div>\n <div class=\"skeleton h-4 w-32\"></div>\n </div>\n </div>\n\n <!--<div class=\"mt-4 border-t pt-4\">\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <div>\n <div class=\"skeleton h-5 w-24 mb-2\"></div>\n <div class=\"space-y-1\">\n <div class=\"skeleton h-4 w-full\"></div>\n <div class=\"skeleton h-4 w-full\"></div>\n <div class=\"skeleton h-4 w-3/4\"></div>\n </div>\n </div>\n \n <div>\n <div class=\"skeleton h-5 w-24 mb-2\"></div>\n <div class=\"space-y-1\">\n <div class=\"skeleton h-4 w-full\"></div>\n <div class=\"skeleton h-4 w-3/4\"></div>\n </div>\n </div>\n </div>\n \n <div class=\"card-actions mt-4 justify-end\">\n <div class=\"skeleton h-8 w-32\"></div>\n </div>\n </div>-->\n </div>\n</div>" }]
|
|
1426
1768
|
}] });
|
|
1427
1769
|
|
|
1428
|
-
const initialPortalState = {
|
|
1429
|
-
status: 'idle',
|
|
1430
|
-
error: null,
|
|
1431
|
-
portalUrl: null
|
|
1432
|
-
};
|
|
1433
|
-
const PortalAccountStore = signalStore({ providedIn: 'root' }, withState(initialPortalState), withComputed((state) => ({
|
|
1434
|
-
isStatusIdle: computed(() => state.status() === 'idle'),
|
|
1435
|
-
isStatusLoading: computed(() => state.status() === 'loading'),
|
|
1436
|
-
isStatusSuccess: computed(() => state.status() === 'success'),
|
|
1437
|
-
isStatusError: computed(() => state.status() === 'error'),
|
|
1438
|
-
})), withMethods((store, stripeService = inject(StripeClientService)) => ({
|
|
1439
|
-
/**
|
|
1440
|
-
* Creates a customer portal session and redirects to the URL
|
|
1441
|
-
* @param customerId Stripe customer ID
|
|
1442
|
-
* @param returnUrl URL to redirect to after the portal session
|
|
1443
|
-
*/
|
|
1444
|
-
async createPortalSession(customerId, returnUrl) {
|
|
1445
|
-
patchState(store, { status: 'loading', error: null, portalUrl: null });
|
|
1446
|
-
try {
|
|
1447
|
-
const { url, error } = await stripeService.createPortalSession(customerId, returnUrl);
|
|
1448
|
-
if (error) {
|
|
1449
|
-
throw new Error(error.message);
|
|
1450
|
-
}
|
|
1451
|
-
if (!url) {
|
|
1452
|
-
throw new Error('No se pudo crear la sesión del portal');
|
|
1453
|
-
}
|
|
1454
|
-
patchState(store, {
|
|
1455
|
-
status: 'success',
|
|
1456
|
-
portalUrl: url
|
|
1457
|
-
});
|
|
1458
|
-
window.location.href = url;
|
|
1459
|
-
}
|
|
1460
|
-
catch (error) {
|
|
1461
|
-
console.error('🚨 [PortalAccountStore]', error);
|
|
1462
|
-
const errorMessage = error instanceof Error ? error.message : 'Error desconocido';
|
|
1463
|
-
patchState(store, {
|
|
1464
|
-
status: 'error',
|
|
1465
|
-
error: errorMessage
|
|
1466
|
-
});
|
|
1467
|
-
}
|
|
1468
|
-
},
|
|
1469
|
-
/**
|
|
1470
|
-
* Resets the store to initial state
|
|
1471
|
-
*/
|
|
1472
|
-
reset() {
|
|
1473
|
-
patchState(store, initialPortalState);
|
|
1474
|
-
}
|
|
1475
|
-
})));
|
|
1476
|
-
|
|
1477
1770
|
class SubscriptionItemComponent {
|
|
1478
1771
|
subscriptionsStore = inject(SubscriptionsStore);
|
|
1479
1772
|
portalAccountStore = inject(PortalAccountStore);
|
|
1480
1773
|
utils = inject(UtilsService);
|
|
1774
|
+
sanitizer = inject(DomSanitizer);
|
|
1481
1775
|
subscription = input.required();
|
|
1482
1776
|
onManageSubscription = output();
|
|
1483
1777
|
isStatusLoading = computed(() => this.portalAccountStore.isStatusLoading());
|
|
1778
|
+
productImage = computed(() => {
|
|
1779
|
+
return this.subscription().product?.images?.[0] || 'https://img.daisyui.com/images/profile/demo/yellingcat@192.webp';
|
|
1780
|
+
});
|
|
1484
1781
|
isExpanded = false;
|
|
1485
1782
|
toggleExpand() {
|
|
1486
1783
|
this.isExpanded = !this.isExpanded;
|
|
1487
1784
|
}
|
|
1488
|
-
|
|
1785
|
+
manageSubscription() {
|
|
1489
1786
|
this.onManageSubscription.emit(this.subscription().customer ?? '');
|
|
1490
1787
|
}
|
|
1788
|
+
sanitizeImageUrl(imageUrl) {
|
|
1789
|
+
return this.sanitizer.bypassSecurityTrustUrl(imageUrl);
|
|
1790
|
+
}
|
|
1491
1791
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: SubscriptionItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1492
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.5", type: SubscriptionItemComponent, isStandalone: true, selector: "lib-subscription-item", inputs: { subscription: { classPropertyName: "subscription", publicName: "subscription", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { onManageSubscription: "onManageSubscription" }, ngImport: i0, template: "<div class=\"card bg-
|
|
1792
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.5", type: SubscriptionItemComponent, isStandalone: true, selector: "lib-subscription-item", inputs: { subscription: { classPropertyName: "subscription", publicName: "subscription", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { onManageSubscription: "onManageSubscription" }, ngImport: i0, template: "<div class=\"card bg-gradient-to-br from-primary/10 to-secondary/10 shadow-lg hover:shadow-xl transition-all duration-300 border border-base-300\">\n <div class=\"card-body p-6\">\n <!-- Header con t\u00EDtulo y precio -->\n <div class=\"flex justify-between items-start mb-4\">\n <div class=\"flex items-center gap-3\">\n <!-- Imagen de la suscripci\u00F3n -->\n <div class=\"avatar\">\n <div class=\"w-24 rounded\">\n <img [src]=\"sanitizeImageUrl(productImage())\" \n [alt]=\"subscription().product?.name || 'Subscription product'\"\n class=\"w-full h-full object-cover rounded-lg\" />\n </div>\n </div> \n \n <div>\n <h3 class=\"text-2xl font-bold text-base-content\">\n {{ subscription().product?.name || 'Subscription Plan' }}\n </h3>\n <div class=\"flex items-center gap-2 mt-1\">\n <span class=\"badge {{ utils.getStatusBadgeClass(subscription().status) }} badge-lg\">\n {{ subscription().status }}\n </span>\n @if (subscription().cancel.cancel_at_period_end) {\n <span class=\"badge badge-warning badge-lg\">Cancelada</span>\n }\n </div>\n </div>\n </div>\n \n <!-- Precio principal -->\n <div class=\"text-right\">\n <div class=\"text-4xl font-bold text-primary\">\n {{ utils.formatAmount(subscription().plan.amount, subscription().currency ?? 'EUR') }}\n </div>\n <div class=\"text-base-content/70 text-lg capitalize\">\n {{ subscription().plan.interval }}ly\n </div>\n </div>\n </div>\n\n <!-- Fechas de per\u00EDodo -->\n <div class=\"flex justify-between items-center py-4 border-t border-base-300\">\n <div class=\"text-left\">\n <div class=\"text-base-content/70 text-sm font-medium\">Start:</div>\n <div class=\"text-base-content font-semibold\">\n {{ utils.formatDate(subscription().current_period_start ?? '') }}\n </div>\n </div>\n \n <div class=\"text-right\">\n <div class=\"text-base-content/70 text-sm font-medium\">End:</div>\n <div class=\"text-base-content font-semibold\">\n {{ utils.formatDate(subscription().current_period_end ?? '') }}\n </div>\n </div>\n </div>\n <div class=\"flex justify-end w-full\">\n <button class=\"btn btn-primary\" [disabled]=\"isStatusLoading()\" (click)=\"manageSubscription()\">\n @if (isStatusLoading()) {\n <span class=\"loading loading-spinner loading-sm\"></span>\n Cargando...\n } @else {\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-5 w-5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z\" />\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M15 12a3 3 0 11-6 0 3 3 0 016 0z\" />\n </svg>\n Gestionar Suscripci\u00F3n\n }\n </button>\n </div>\n </div>\n</div> ", dependencies: [{ kind: "ngmodule", type: CommonModule }] });
|
|
1493
1793
|
}
|
|
1494
1794
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: SubscriptionItemComponent, decorators: [{
|
|
1495
1795
|
type: Component,
|
|
1496
|
-
args: [{ selector: 'lib-subscription-item', standalone: true, imports: [CommonModule], template: "<div class=\"card bg-
|
|
1796
|
+
args: [{ selector: 'lib-subscription-item', standalone: true, imports: [CommonModule], template: "<div class=\"card bg-gradient-to-br from-primary/10 to-secondary/10 shadow-lg hover:shadow-xl transition-all duration-300 border border-base-300\">\n <div class=\"card-body p-6\">\n <!-- Header con t\u00EDtulo y precio -->\n <div class=\"flex justify-between items-start mb-4\">\n <div class=\"flex items-center gap-3\">\n <!-- Imagen de la suscripci\u00F3n -->\n <div class=\"avatar\">\n <div class=\"w-24 rounded\">\n <img [src]=\"sanitizeImageUrl(productImage())\" \n [alt]=\"subscription().product?.name || 'Subscription product'\"\n class=\"w-full h-full object-cover rounded-lg\" />\n </div>\n </div> \n \n <div>\n <h3 class=\"text-2xl font-bold text-base-content\">\n {{ subscription().product?.name || 'Subscription Plan' }}\n </h3>\n <div class=\"flex items-center gap-2 mt-1\">\n <span class=\"badge {{ utils.getStatusBadgeClass(subscription().status) }} badge-lg\">\n {{ subscription().status }}\n </span>\n @if (subscription().cancel.cancel_at_period_end) {\n <span class=\"badge badge-warning badge-lg\">Cancelada</span>\n }\n </div>\n </div>\n </div>\n \n <!-- Precio principal -->\n <div class=\"text-right\">\n <div class=\"text-4xl font-bold text-primary\">\n {{ utils.formatAmount(subscription().plan.amount, subscription().currency ?? 'EUR') }}\n </div>\n <div class=\"text-base-content/70 text-lg capitalize\">\n {{ subscription().plan.interval }}ly\n </div>\n </div>\n </div>\n\n <!-- Fechas de per\u00EDodo -->\n <div class=\"flex justify-between items-center py-4 border-t border-base-300\">\n <div class=\"text-left\">\n <div class=\"text-base-content/70 text-sm font-medium\">Start:</div>\n <div class=\"text-base-content font-semibold\">\n {{ utils.formatDate(subscription().current_period_start ?? '') }}\n </div>\n </div>\n \n <div class=\"text-right\">\n <div class=\"text-base-content/70 text-sm font-medium\">End:</div>\n <div class=\"text-base-content font-semibold\">\n {{ utils.formatDate(subscription().current_period_end ?? '') }}\n </div>\n </div>\n </div>\n <div class=\"flex justify-end w-full\">\n <button class=\"btn btn-primary\" [disabled]=\"isStatusLoading()\" (click)=\"manageSubscription()\">\n @if (isStatusLoading()) {\n <span class=\"loading loading-spinner loading-sm\"></span>\n Cargando...\n } @else {\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-5 w-5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z\" />\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M15 12a3 3 0 11-6 0 3 3 0 016 0z\" />\n </svg>\n Gestionar Suscripci\u00F3n\n }\n </button>\n </div>\n </div>\n</div> " }]
|
|
1497
1797
|
}] });
|
|
1498
1798
|
|
|
1499
1799
|
class SubscriptionsListComponent {
|
|
@@ -1569,11 +1869,11 @@ class PaymentIntentItemComponent {
|
|
|
1569
1869
|
this.isExpanded.update(value => !value);
|
|
1570
1870
|
}
|
|
1571
1871
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: PaymentIntentItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1572
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.5", type: PaymentIntentItemComponent, isStandalone: true, selector: "lib-payment-intent-item", inputs: { paymentIntent: { classPropertyName: "paymentIntent", publicName: "paymentIntent", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div class=\"card bg-base-100 shadow-sm hover:shadow-md transition-
|
|
1872
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.5", type: PaymentIntentItemComponent, isStandalone: true, selector: "lib-payment-intent-item", inputs: { paymentIntent: { classPropertyName: "paymentIntent", publicName: "paymentIntent", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div class=\"card bg-base-100 shadow-sm hover:shadow-md transition-all duration-200 border border-base-200\">\n <div class=\"card-body p-4\">\n \n <!-- Header Section -->\n <div class=\"flex justify-between items-start mb-3\">\n <div class=\"flex-1\">\n <div class=\"flex items-center gap-2 mb-1\">\n <div class=\"text-2xl font-bold text-primary\">\n {{ utils.formatAmount(paymentIntent().amount ?? 0, paymentIntent().currency ?? 'EUR') }}\n </div>\n <div class=\"badge {{ utils.getStatusBadgeClass(paymentIntent().status) }} badge-sm\">\n {{ paymentIntent().status }}\n </div>\n @if (!paymentIntent().liveMode) {\n <div class=\"badge badge-warning badge-sm\">TEST</div>\n }\n </div>\n </div>\n \n <button \n class=\"btn btn-sm btn-ghost btn-circle\" \n (click)=\"toggleExpand()\"\n [class.rotate-180]=\"isExpanded()\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-4 w-4 transition-transform duration-200\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M19 9l-7 7-7-7\" />\n </svg>\n </button>\n </div>\n\n <!-- Main Info Section -->\n <div class=\"space-y-2\">\n <!-- Payment Method -->\n @if (paymentIntent().paymentMethod) {\n <ngx-payment-method \n [paymentMethod]=\"paymentIntent().paymentMethod!\" \n mode=\"compact\">\n </ngx-payment-method>\n } @else {\n <div class=\"flex items-center gap-2 p-2 bg-base-200 rounded-lg\">\n <div class=\"w-8 h-8 bg-base-300 rounded-full flex items-center justify-center\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z\" />\n </svg>\n </div>\n <div>\n <div class=\"font-medium text-sm\">M\u00E9todo de pago</div>\n <div class=\"text-xs text-base-content/70\">\u2022\u2022\u2022\u2022 {{ paymentIntent().paymentMethodId.slice(-4) }}</div>\n </div>\n </div>\n }\n\n <!-- Confirmation Method -->\n <div class=\"flex items-center gap-2 text-sm\">\n <div class=\"w-2 h-2 bg-success rounded-full\"></div>\n <span class=\"text-base-content/70\">Confirmaci\u00F3n:</span>\n <span class=\"capitalize font-medium\">{{ paymentIntent().confirmationMethod.replace('_', ' ') }}</span>\n </div>\n </div>\n\n <!-- Expanded Details -->\n @if (isExpanded()) {\n <div class=\"divider my-4\"></div>\n \n <div class=\"space-y-4\">\n <!-- Transaction Details -->\n <div>\n <h4 class=\"text-sm font-semibold text-base-content/80 mb-3 flex items-center gap-2\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z\" />\n </svg>\n Detalles de la Transacci\u00F3n\n </h4>\n \n <div class=\"grid grid-cols-1 sm:grid-cols-2 gap-3\">\n <div class=\"stat bg-base-200 rounded-lg p-3\">\n <div class=\"stat-title text-xs\">Estado</div>\n <div class=\"stat-value text-sm capitalize\">{{ paymentIntent().status }}</div>\n <div class=\"stat-desc\">{{ paymentIntent().liveMode ? 'Producci\u00F3n' : 'Pruebas' }}</div>\n </div>\n \n <div class=\"stat bg-base-200 rounded-lg p-3\">\n <div class=\"stat-title text-xs\">Monto</div>\n <div class=\"stat-value text-sm\">{{ utils.formatAmount(paymentIntent().amount ?? 0, paymentIntent().currency ?? 'EUR') }}</div>\n <div class=\"stat-desc\">{{ (paymentIntent().currency ?? 'EUR').toUpperCase() }}</div>\n </div>\n </div>\n </div>\n\n <!-- Payment Information -->\n @if (paymentIntent().paymentMethod) {\n <div>\n <h4 class=\"text-sm font-semibold text-base-content/80 mb-3 flex items-center gap-2\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z\" />\n </svg>\n Informaci\u00F3n del Pago\n </h4>\n \n <ngx-payment-method \n [paymentMethod]=\"paymentIntent().paymentMethod!\" \n mode=\"detailed\">\n </ngx-payment-method>\n </div>\n }\n\n <!-- Additional Information -->\n <div>\n <h4 class=\"text-sm font-semibold text-base-content/80 mb-3 flex items-center gap-2\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z\" />\n </svg>\n Informaci\u00F3n Adicional\n </h4>\n \n <div class=\"space-y-2\">\n @if (paymentIntent().invoiceId) {\n <div class=\"flex items-center justify-between p-2 bg-base-200 rounded\">\n <span class=\"text-sm text-base-content/70\">Factura</span>\n <span class=\"text-sm font-mono\">{{ paymentIntent().invoiceId.slice(-8) }}</span>\n </div>\n }\n \n <div class=\"flex items-center justify-between p-2 bg-base-200 rounded\">\n <span class=\"text-sm text-base-content/70\">Entorno</span>\n <span class=\"text-sm\">\n @if (paymentIntent().liveMode) {\n <span class=\"text-success\">Producci\u00F3n</span>\n } @else {\n <span class=\"text-warning\">Pruebas</span>\n }\n </span>\n </div>\n \n <div class=\"flex items-center justify-between p-2 bg-base-200 rounded\">\n <span class=\"text-sm text-base-content/70\">Referencia</span>\n <span class=\"text-sm font-mono\">\u2022\u2022\u2022{{ paymentIntent().id?.slice(-6) || 'N/A' }}</span>\n </div>\n </div>\n </div>\n </div>\n }\n </div>\n</div> ", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: PaymentMethodComponent, selector: "ngx-payment-method", inputs: ["paymentMethod", "mode"] }] });
|
|
1573
1873
|
}
|
|
1574
1874
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: PaymentIntentItemComponent, decorators: [{
|
|
1575
1875
|
type: Component,
|
|
1576
|
-
args: [{ selector: 'lib-payment-intent-item', standalone: true, imports: [CommonModule], template: "<div class=\"card bg-base-100 shadow-sm hover:shadow-md transition-
|
|
1876
|
+
args: [{ selector: 'lib-payment-intent-item', standalone: true, imports: [CommonModule, PaymentMethodComponent], template: "<div class=\"card bg-base-100 shadow-sm hover:shadow-md transition-all duration-200 border border-base-200\">\n <div class=\"card-body p-4\">\n \n <!-- Header Section -->\n <div class=\"flex justify-between items-start mb-3\">\n <div class=\"flex-1\">\n <div class=\"flex items-center gap-2 mb-1\">\n <div class=\"text-2xl font-bold text-primary\">\n {{ utils.formatAmount(paymentIntent().amount ?? 0, paymentIntent().currency ?? 'EUR') }}\n </div>\n <div class=\"badge {{ utils.getStatusBadgeClass(paymentIntent().status) }} badge-sm\">\n {{ paymentIntent().status }}\n </div>\n @if (!paymentIntent().liveMode) {\n <div class=\"badge badge-warning badge-sm\">TEST</div>\n }\n </div>\n </div>\n \n <button \n class=\"btn btn-sm btn-ghost btn-circle\" \n (click)=\"toggleExpand()\"\n [class.rotate-180]=\"isExpanded()\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-4 w-4 transition-transform duration-200\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M19 9l-7 7-7-7\" />\n </svg>\n </button>\n </div>\n\n <!-- Main Info Section -->\n <div class=\"space-y-2\">\n <!-- Payment Method -->\n @if (paymentIntent().paymentMethod) {\n <ngx-payment-method \n [paymentMethod]=\"paymentIntent().paymentMethod!\" \n mode=\"compact\">\n </ngx-payment-method>\n } @else {\n <div class=\"flex items-center gap-2 p-2 bg-base-200 rounded-lg\">\n <div class=\"w-8 h-8 bg-base-300 rounded-full flex items-center justify-center\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z\" />\n </svg>\n </div>\n <div>\n <div class=\"font-medium text-sm\">M\u00E9todo de pago</div>\n <div class=\"text-xs text-base-content/70\">\u2022\u2022\u2022\u2022 {{ paymentIntent().paymentMethodId.slice(-4) }}</div>\n </div>\n </div>\n }\n\n <!-- Confirmation Method -->\n <div class=\"flex items-center gap-2 text-sm\">\n <div class=\"w-2 h-2 bg-success rounded-full\"></div>\n <span class=\"text-base-content/70\">Confirmaci\u00F3n:</span>\n <span class=\"capitalize font-medium\">{{ paymentIntent().confirmationMethod.replace('_', ' ') }}</span>\n </div>\n </div>\n\n <!-- Expanded Details -->\n @if (isExpanded()) {\n <div class=\"divider my-4\"></div>\n \n <div class=\"space-y-4\">\n <!-- Transaction Details -->\n <div>\n <h4 class=\"text-sm font-semibold text-base-content/80 mb-3 flex items-center gap-2\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z\" />\n </svg>\n Detalles de la Transacci\u00F3n\n </h4>\n \n <div class=\"grid grid-cols-1 sm:grid-cols-2 gap-3\">\n <div class=\"stat bg-base-200 rounded-lg p-3\">\n <div class=\"stat-title text-xs\">Estado</div>\n <div class=\"stat-value text-sm capitalize\">{{ paymentIntent().status }}</div>\n <div class=\"stat-desc\">{{ paymentIntent().liveMode ? 'Producci\u00F3n' : 'Pruebas' }}</div>\n </div>\n \n <div class=\"stat bg-base-200 rounded-lg p-3\">\n <div class=\"stat-title text-xs\">Monto</div>\n <div class=\"stat-value text-sm\">{{ utils.formatAmount(paymentIntent().amount ?? 0, paymentIntent().currency ?? 'EUR') }}</div>\n <div class=\"stat-desc\">{{ (paymentIntent().currency ?? 'EUR').toUpperCase() }}</div>\n </div>\n </div>\n </div>\n\n <!-- Payment Information -->\n @if (paymentIntent().paymentMethod) {\n <div>\n <h4 class=\"text-sm font-semibold text-base-content/80 mb-3 flex items-center gap-2\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z\" />\n </svg>\n Informaci\u00F3n del Pago\n </h4>\n \n <ngx-payment-method \n [paymentMethod]=\"paymentIntent().paymentMethod!\" \n mode=\"detailed\">\n </ngx-payment-method>\n </div>\n }\n\n <!-- Additional Information -->\n <div>\n <h4 class=\"text-sm font-semibold text-base-content/80 mb-3 flex items-center gap-2\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z\" />\n </svg>\n Informaci\u00F3n Adicional\n </h4>\n \n <div class=\"space-y-2\">\n @if (paymentIntent().invoiceId) {\n <div class=\"flex items-center justify-between p-2 bg-base-200 rounded\">\n <span class=\"text-sm text-base-content/70\">Factura</span>\n <span class=\"text-sm font-mono\">{{ paymentIntent().invoiceId.slice(-8) }}</span>\n </div>\n }\n \n <div class=\"flex items-center justify-between p-2 bg-base-200 rounded\">\n <span class=\"text-sm text-base-content/70\">Entorno</span>\n <span class=\"text-sm\">\n @if (paymentIntent().liveMode) {\n <span class=\"text-success\">Producci\u00F3n</span>\n } @else {\n <span class=\"text-warning\">Pruebas</span>\n }\n </span>\n </div>\n \n <div class=\"flex items-center justify-between p-2 bg-base-200 rounded\">\n <span class=\"text-sm text-base-content/70\">Referencia</span>\n <span class=\"text-sm font-mono\">\u2022\u2022\u2022{{ paymentIntent().id?.slice(-6) || 'N/A' }}</span>\n </div>\n </div>\n </div>\n </div>\n }\n </div>\n</div> " }]
|
|
1577
1877
|
}] });
|
|
1578
1878
|
|
|
1579
1879
|
class PaymentIntentsListComponent {
|
|
@@ -1654,5 +1954,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImpor
|
|
|
1654
1954
|
* Generated bundle index. Do not edit.
|
|
1655
1955
|
*/
|
|
1656
1956
|
|
|
1657
|
-
export { CheckoutStore, CustomerDashboardComponent, CustomerStore, EmbeddedCheckoutComponent, EmbeddedSubscriptionComponent, PaymentIntentsListComponent, PaymentIntentsTableComponent, ProductListComponent, ProductsStore, ReturnPageComponent, STRIPE_CONFIG, SUPABASE_CONFIG, StripeClientService, SubscriptionCardComponent, SubscriptionReturnPageComponent, SubscriptionsListComponent, SubscriptionsStore, SupabaseClientService, parsePaymentIntent, parseProduct, parseSubscription, provideNgxSupabaseStripeConfig, provideStripeConfig, provideSupabaseConfig };
|
|
1957
|
+
export { CheckoutStore, Currency, CustomerDashboardComponent, CustomerStore, EmbeddedCheckoutComponent, EmbeddedSubscriptionComponent, PaymentIntentsListComponent, PaymentIntentsTableComponent, PortalAccountStore, ProductListComponent, ProductsStore, ReturnPageComponent, STRIPE_CONFIG, SUPABASE_CONFIG, StripeClientService, SubscriptionCardComponent, SubscriptionReturnPageComponent, SubscriptionsListComponent, SubscriptionsStore, SupabaseClientService, parsePaymentIntent, parseProduct, parseSubscription, provideNgxSupabaseStripeConfig, provideStripeConfig, provideSupabaseConfig };
|
|
1658
1958
|
//# sourceMappingURL=dotted-labs-ngx-supabase-stripe.mjs.map
|