@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.products()?.filter(product => product.prices.some(price => (price.details.type === 'one_time' && price.details.currency === state.currency()))) || []),
714
- recurringProductsByCurrency: computed(() => state.products()?.filter(product => product.prices.some(price => (price.details.type === 'recurring' && price.details.currency === state.currency()))) || []),
715
- productsByCurrency: computed(() => state.products()?.filter(product => product.prices.some(price => (price.details.currency === state.currency()))) || []),
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, supabaseService = inject(SupabaseClientService)) => ({
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
- console.log('🎮 [ProductsStore] Loading products by ids: ', ids);
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: product, error: productError } = await supabaseService.selectStripeProduct(id);
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: prices, error: pricesError } = await supabaseService.selectStripePrices();
761
- if (pricesError) {
762
- console.error('🎮 [ProductsStore]: Error loading prices', pricesError);
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: productsError.message,
868
+ error: error.message,
772
869
  });
870
+ return;
773
871
  }
774
- if (stripeProducts) {
775
- {
776
- const products = [];
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
- parseProduct(p, prices),
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, parseProduct, parseSubscription, provideNgxSupabaseStripeConfig, provideStripeConfig, provideSupabaseConfig };
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