@dotted-labs/ngx-supabase-stripe 0.6.3 → 0.6.5
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.
|
@@ -157,6 +157,12 @@ class SupabaseClientService {
|
|
|
157
157
|
.rpc('get_stripe_products')
|
|
158
158
|
.select('*');
|
|
159
159
|
}
|
|
160
|
+
async selectStripeProductsByIds(ids) {
|
|
161
|
+
return this.client
|
|
162
|
+
.schema(this.config.supabaseSchema)
|
|
163
|
+
.rpc('get_stripe_products_by_ids', { product_ids: ids })
|
|
164
|
+
.select('*');
|
|
165
|
+
}
|
|
160
166
|
/**
|
|
161
167
|
* Select a Stripe product
|
|
162
168
|
* @param productId The product ID
|
|
@@ -699,6 +705,102 @@ var Currency;
|
|
|
699
705
|
Currency["INR"] = "inr";
|
|
700
706
|
})(Currency || (Currency = {}));
|
|
701
707
|
|
|
708
|
+
class ProductsService {
|
|
709
|
+
supabaseService = inject(SupabaseClientService);
|
|
710
|
+
/**
|
|
711
|
+
* Map a Stripe product row plus price rows to the public shape used by the UI.
|
|
712
|
+
*/
|
|
713
|
+
toStripeProductPublic(product, prices = []) {
|
|
714
|
+
return this.parseProduct(product, prices);
|
|
715
|
+
}
|
|
716
|
+
/**
|
|
717
|
+
* Load all Stripe prices and products, returning parsed public products.
|
|
718
|
+
*/
|
|
719
|
+
async fetchFullCatalog() {
|
|
720
|
+
const [pricesResult, productsResult] = await Promise.all([
|
|
721
|
+
this.supabaseService.selectStripePrices(),
|
|
722
|
+
this.supabaseService.selectStripeProducts(),
|
|
723
|
+
]);
|
|
724
|
+
const pricesError = pricesResult.error;
|
|
725
|
+
const productsError = productsResult.error;
|
|
726
|
+
if (pricesError) {
|
|
727
|
+
return { data: null, error: pricesError };
|
|
728
|
+
}
|
|
729
|
+
if (productsError) {
|
|
730
|
+
return { data: null, error: productsError };
|
|
731
|
+
}
|
|
732
|
+
const prices = (pricesResult.data ?? []);
|
|
733
|
+
const stripeProducts = (productsResult.data ?? []);
|
|
734
|
+
const products = stripeProducts.map((product) => this.parseProduct(product, prices));
|
|
735
|
+
return { data: { prices, products }, error: null };
|
|
736
|
+
}
|
|
737
|
+
/**
|
|
738
|
+
* Load prices and a single product by id, returning parsed public product(s).
|
|
739
|
+
*/
|
|
740
|
+
async fetchProductById(id) {
|
|
741
|
+
const [pricesResult, productResult] = await Promise.all([
|
|
742
|
+
this.supabaseService.selectStripePrices(),
|
|
743
|
+
this.supabaseService.selectStripeProduct(id),
|
|
744
|
+
]);
|
|
745
|
+
const pricesError = pricesResult.error;
|
|
746
|
+
const productError = productResult.error;
|
|
747
|
+
if (pricesError) {
|
|
748
|
+
return { data: [], error: pricesError };
|
|
749
|
+
}
|
|
750
|
+
if (productError) {
|
|
751
|
+
return { data: [], error: productError };
|
|
752
|
+
}
|
|
753
|
+
const prices = (pricesResult.data ?? []);
|
|
754
|
+
const rows = productResult.data;
|
|
755
|
+
if (!rows?.length) {
|
|
756
|
+
return { data: [], error: null };
|
|
757
|
+
}
|
|
758
|
+
return { data: [this.parseProduct(rows[0], prices)], error: null };
|
|
759
|
+
}
|
|
760
|
+
/**
|
|
761
|
+
* Load prices and products for the given Stripe product ids.
|
|
762
|
+
*/
|
|
763
|
+
async fetchProductsByIds(ids) {
|
|
764
|
+
const [pricesResult, productsResult] = await Promise.all([
|
|
765
|
+
this.supabaseService.selectStripePrices(),
|
|
766
|
+
this.supabaseService.selectStripeProductsByIds(ids),
|
|
767
|
+
]);
|
|
768
|
+
const pricesError = pricesResult.error;
|
|
769
|
+
const productsError = productsResult.error;
|
|
770
|
+
if (pricesError) {
|
|
771
|
+
return { data: [], error: pricesError };
|
|
772
|
+
}
|
|
773
|
+
if (productsError) {
|
|
774
|
+
return { data: [], error: productsError };
|
|
775
|
+
}
|
|
776
|
+
const prices = (pricesResult.data ?? []);
|
|
777
|
+
const stripeProducts = (productsResult.data ?? []);
|
|
778
|
+
const products = stripeProducts.map((product) => this.parseProduct(product, prices));
|
|
779
|
+
return { data: products, error: null };
|
|
780
|
+
}
|
|
781
|
+
parseProduct(product, prices = []) {
|
|
782
|
+
const { attrs, ...mainProperties } = product;
|
|
783
|
+
return {
|
|
784
|
+
...mainProperties,
|
|
785
|
+
images: attrs?.images ?? [],
|
|
786
|
+
prices: prices
|
|
787
|
+
.filter((price) => price.product === product.id)
|
|
788
|
+
.map((price) => ({
|
|
789
|
+
details: price,
|
|
790
|
+
recurringInterval: price?.attrs?.recurring?.interval ?? 'no-recurring',
|
|
791
|
+
})),
|
|
792
|
+
};
|
|
793
|
+
}
|
|
794
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: ProductsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
795
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: ProductsService, providedIn: 'root' });
|
|
796
|
+
}
|
|
797
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: ProductsService, decorators: [{
|
|
798
|
+
type: Injectable,
|
|
799
|
+
args: [{
|
|
800
|
+
providedIn: 'root',
|
|
801
|
+
}]
|
|
802
|
+
}] });
|
|
803
|
+
|
|
702
804
|
const initialProductsState = {
|
|
703
805
|
products: null,
|
|
704
806
|
prices: null,
|
|
@@ -710,18 +812,23 @@ const ProductsStore = signalStore({ providedIn: 'root' }, withState(initialProdu
|
|
|
710
812
|
isStatusLoading: computed(() => state.status() === 'loading'),
|
|
711
813
|
isStatusSuccess: computed(() => state.status() === 'success'),
|
|
712
814
|
isStatusError: computed(() => state.status() === 'error'),
|
|
713
|
-
oneTimeproductsByCurrency: computed(() => state
|
|
714
|
-
|
|
715
|
-
|
|
815
|
+
oneTimeproductsByCurrency: computed(() => state
|
|
816
|
+
.products()
|
|
817
|
+
?.filter((product) => product.prices.some((price) => price.details.type === 'one_time' && price.details.currency === state.currency())) || []),
|
|
818
|
+
recurringProductsByCurrency: computed(() => state
|
|
819
|
+
.products()
|
|
820
|
+
?.filter((product) => product.prices.some((price) => price.details.type === 'recurring' && price.details.currency === state.currency())) || []),
|
|
821
|
+
productsByCurrency: computed(() => state
|
|
822
|
+
.products()
|
|
823
|
+
?.filter((product) => product.prices.some((price) => price.details.currency === state.currency())) || []),
|
|
716
824
|
hasProducts: computed(() => state.products() !== null && state.products().length > 0),
|
|
717
|
-
isError: computed(() => state.error())
|
|
718
|
-
})), withMethods((store,
|
|
825
|
+
isError: computed(() => state.error()),
|
|
826
|
+
})), withMethods((store, productsService = inject(ProductsService)) => ({
|
|
719
827
|
/**
|
|
720
828
|
* Get products by IDs from the current loaded products
|
|
721
829
|
*/
|
|
722
830
|
getProductsByIds(ids) {
|
|
723
|
-
|
|
724
|
-
return store.products()?.filter(product => product.id && ids.includes(product.id)) || [];
|
|
831
|
+
return store.products()?.filter((product) => product.id && ids.includes(product.id)) || [];
|
|
725
832
|
},
|
|
726
833
|
/**
|
|
727
834
|
* Set the currency filter for products
|
|
@@ -735,15 +842,11 @@ const ProductsStore = signalStore({ providedIn: 'root' }, withState(initialProdu
|
|
|
735
842
|
async loadProductById(id) {
|
|
736
843
|
patchState(store, { status: 'loading', error: null });
|
|
737
844
|
try {
|
|
738
|
-
const { data:
|
|
845
|
+
const { data: products, error: productError } = await productsService.fetchProductById(id);
|
|
739
846
|
if (productError) {
|
|
740
847
|
console.error('🎮 [ProductsStore]: Error loading product', productError);
|
|
741
848
|
patchState(store, { status: 'error', error: productError.message });
|
|
742
|
-
|
|
743
|
-
const products = [];
|
|
744
|
-
if (product && product.length > 0) {
|
|
745
|
-
const productParsed = parseProduct(product[0], store.prices());
|
|
746
|
-
products.push(productParsed);
|
|
849
|
+
return;
|
|
747
850
|
}
|
|
748
851
|
patchState(store, { status: 'success', products });
|
|
749
852
|
}
|
|
@@ -757,33 +860,25 @@ const ProductsStore = signalStore({ providedIn: 'root' }, withState(initialProdu
|
|
|
757
860
|
async loadProducts() {
|
|
758
861
|
patchState(store, { status: 'loading', error: null });
|
|
759
862
|
try {
|
|
760
|
-
const { data
|
|
761
|
-
if (
|
|
762
|
-
console.error('🎮 [ProductsStore]: Error loading
|
|
763
|
-
patchState(store, { status: 'error', error: pricesError.message });
|
|
764
|
-
}
|
|
765
|
-
patchState(store, { prices: prices || [] });
|
|
766
|
-
const { data: stripeProducts, error: productsError } = await supabaseService.selectStripeProducts();
|
|
767
|
-
if (productsError) {
|
|
768
|
-
console.error('🎮 [ProductsStore]: Error loading products', productsError);
|
|
863
|
+
const { data, error } = await productsService.fetchFullCatalog();
|
|
864
|
+
if (error) {
|
|
865
|
+
console.error('🎮 [ProductsStore]: Error loading catalog', error);
|
|
769
866
|
patchState(store, {
|
|
770
867
|
status: 'error',
|
|
771
|
-
error:
|
|
868
|
+
error: error.message,
|
|
772
869
|
});
|
|
870
|
+
return;
|
|
773
871
|
}
|
|
774
|
-
if (
|
|
775
|
-
{
|
|
776
|
-
|
|
777
|
-
stripeProducts.forEach(product => {
|
|
778
|
-
products.push(parseProduct(product, store.prices()));
|
|
779
|
-
});
|
|
780
|
-
console.log('🎮 [ProductsStore] products: ', products);
|
|
781
|
-
patchState(store, {
|
|
782
|
-
status: 'success',
|
|
783
|
-
products: products
|
|
784
|
-
});
|
|
785
|
-
}
|
|
872
|
+
if (!data) {
|
|
873
|
+
patchState(store, { status: 'success', prices: [], products: [] });
|
|
874
|
+
return;
|
|
786
875
|
}
|
|
876
|
+
console.log('🎮 [ProductsStore] products: ', data.products);
|
|
877
|
+
patchState(store, {
|
|
878
|
+
status: 'success',
|
|
879
|
+
prices: data.prices,
|
|
880
|
+
products: data.products,
|
|
881
|
+
});
|
|
787
882
|
}
|
|
788
883
|
catch (error) {
|
|
789
884
|
patchState(store, {
|
|
@@ -792,12 +887,31 @@ const ProductsStore = signalStore({ providedIn: 'root' }, withState(initialProdu
|
|
|
792
887
|
});
|
|
793
888
|
}
|
|
794
889
|
},
|
|
890
|
+
async loadProductsByIds(ids) {
|
|
891
|
+
patchState(store, { status: 'loading', error: null });
|
|
892
|
+
try {
|
|
893
|
+
const { data: products, error: productsError } = await productsService.fetchProductsByIds(ids);
|
|
894
|
+
if (productsError) {
|
|
895
|
+
console.error('🎮 [ProductsStore]: Error loading products', productsError);
|
|
896
|
+
patchState(store, { status: 'error', error: productsError.message });
|
|
897
|
+
return;
|
|
898
|
+
}
|
|
899
|
+
console.log('🎮 [ProductsStore] products: ', products);
|
|
900
|
+
patchState(store, {
|
|
901
|
+
status: 'success',
|
|
902
|
+
products,
|
|
903
|
+
});
|
|
904
|
+
}
|
|
905
|
+
catch (error) {
|
|
906
|
+
patchState(store, { status: 'error', error: error.message });
|
|
907
|
+
}
|
|
908
|
+
},
|
|
795
909
|
/**
|
|
796
910
|
* Reset the store to initial state
|
|
797
911
|
*/
|
|
798
912
|
reset() {
|
|
799
913
|
patchState(store, initialProductsState);
|
|
800
|
-
}
|
|
914
|
+
},
|
|
801
915
|
})), withHooks((store) => ({
|
|
802
916
|
async onInit() {
|
|
803
917
|
console.log('🎮 [ProductsStore] onInit');
|
|
@@ -807,19 +921,8 @@ const ProductsStore = signalStore({ providedIn: 'root' }, withState(initialProdu
|
|
|
807
921
|
console.log('🎮 [ProductsStore] loading products...');
|
|
808
922
|
await store.loadProducts();
|
|
809
923
|
}
|
|
810
|
-
}
|
|
924
|
+
},
|
|
811
925
|
})));
|
|
812
|
-
function parseProduct(product, prices = []) {
|
|
813
|
-
const { attrs, ...mainProperties } = product;
|
|
814
|
-
return {
|
|
815
|
-
...mainProperties,
|
|
816
|
-
images: attrs?.images || [],
|
|
817
|
-
prices: prices.filter(price => price.product === product.id).map(price => ({
|
|
818
|
-
details: price,
|
|
819
|
-
recurringInterval: price?.attrs?.recurring?.interval || 'no-recurring'
|
|
820
|
-
}))
|
|
821
|
-
};
|
|
822
|
-
}
|
|
823
926
|
|
|
824
927
|
const initialSubscriptionState = {
|
|
825
928
|
subscriptions: null,
|
|
@@ -834,7 +937,7 @@ const SubscriptionsStore = signalStore({ providedIn: 'root' }, withState(initial
|
|
|
834
937
|
isStatusError: computed(() => state.status() === 'error'),
|
|
835
938
|
hasSubscriptions: computed(() => state.subscriptions() !== null && state.subscriptions().length > 0),
|
|
836
939
|
isError: computed(() => state.error()),
|
|
837
|
-
})), withMethods((store, stripeService = inject(StripeClientService), supabaseService = inject(SupabaseClientService), productsStore = inject(ProductsStore), customerStore = inject(CustomerStore)) => ({
|
|
940
|
+
})), withMethods((store, stripeService = inject(StripeClientService), supabaseService = inject(SupabaseClientService), productsStore = inject(ProductsStore), productsService = inject(ProductsService), customerStore = inject(CustomerStore)) => ({
|
|
838
941
|
/**
|
|
839
942
|
* Create a subscription
|
|
840
943
|
* @param priceId The price ID for the subscription
|
|
@@ -892,7 +995,7 @@ const SubscriptionsStore = signalStore({ providedIn: 'root' }, withState(initial
|
|
|
892
995
|
const prices = (productsStore.prices() ?? []);
|
|
893
996
|
const userProductsById = new Map((userStripeProducts ?? []).map((p) => [
|
|
894
997
|
p.id,
|
|
895
|
-
|
|
998
|
+
productsService.toStripeProductPublic(p, prices),
|
|
896
999
|
]));
|
|
897
1000
|
console.log('🔍 [SubscriptionsStore] loaded subscriptions', subscriptions);
|
|
898
1001
|
const parsedSubscriptions = subscriptions?.map((subscription) => {
|
|
@@ -2091,5 +2194,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
|
|
|
2091
2194
|
* Generated bundle index. Do not edit.
|
|
2092
2195
|
*/
|
|
2093
2196
|
|
|
2094
|
-
export { CheckoutStore, Currency, CustomerDashboardComponent, CustomerStore, EmbeddedCheckoutComponent, EmbeddedSubscriptionComponent, PaymentIntentsListComponent, PaymentIntentsTableComponent, PortalAccountStore, ProductItemButtonComponent, ProductListComponent, ProductsStore, ReturnPageComponent, STRIPE_CONFIG, SUPABASE_BROWSER_CLIENT, SUPABASE_CONFIG, StripeClientService, SubscriptionCardComponent, SubscriptionReturnPageComponent, SubscriptionsListComponent, SubscriptionsStore, SupabaseClientService, parsePaymentIntent,
|
|
2197
|
+
export { CheckoutStore, Currency, CustomerDashboardComponent, CustomerStore, EmbeddedCheckoutComponent, EmbeddedSubscriptionComponent, PaymentIntentsListComponent, PaymentIntentsTableComponent, PortalAccountStore, ProductItemButtonComponent, ProductListComponent, ProductsService, ProductsStore, ReturnPageComponent, STRIPE_CONFIG, SUPABASE_BROWSER_CLIENT, SUPABASE_CONFIG, StripeClientService, SubscriptionCardComponent, SubscriptionReturnPageComponent, SubscriptionsListComponent, SubscriptionsStore, SupabaseClientService, parsePaymentIntent, parseSubscription, provideNgxSupabaseStripeConfig, provideStripeConfig, provideSupabaseConfig };
|
|
2095
2198
|
//# sourceMappingURL=dotted-labs-ngx-supabase-stripe.mjs.map
|