Skip to content

Commit 9ffc2c2

Browse files
Merge pull request #334 from stripe/lm-payment-updates
feat(firestore-stripe-web-sdk): Added onCurrentUserPaymentUpdate() API
2 parents 8eac766 + 6780653 commit 9ffc2c2

File tree

5 files changed

+474
-27
lines changed

5 files changed

+474
-27
lines changed

firestore-stripe-web-sdk/etc/firestore-stripe-payments.api.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,9 @@ export interface LineItemSessionCreateParams extends CommonSessionCreateParams {
110110
line_items: LineItemParams[];
111111
}
112112

113+
// @public
114+
export function onCurrentUserPaymentUpdate(payments: StripePayments, onUpdate: (snapshot: PaymentSnapshot) => void, onError?: (error: StripePaymentsError) => void): () => void;
115+
113116
// @public
114117
export function onCurrentUserSubscriptionUpdate(payments: StripePayments, onUpdate: (snapshot: SubscriptionSnapshot) => void, onError?: (error: StripePaymentsError) => void): () => void;
115118

@@ -138,9 +141,23 @@ export interface Payment {
138141
readonly uid: string;
139142
}
140143

144+
// @public
145+
export type PaymentChangeType = "added" | "modified" | "removed";
146+
141147
// @public
142148
export type PaymentMethodType = "card" | "acss_debit" | "afterpay_clearpay" | "alipay" | "bacs_debit" | "bancontact" | "boleto" | "eps" | "fpx" | "giropay" | "grabpay" | "ideal" | "klarna" | "oxxo" | "p24" | "sepa_debit" | "sofort" | "wechat_pay";
143149

150+
// @public
151+
export interface PaymentSnapshot {
152+
changes: Array<{
153+
type: PaymentChangeType;
154+
payment: Payment;
155+
}>;
156+
empty: boolean;
157+
payments: Payment[];
158+
size: number;
159+
}
160+
144161
// @public
145162
export type PaymentStatus = "requires_payment_method" | "requires_confirmation" | "requires_action" | "processing" | "requires_capture" | "cancelled" | "succeeded";
146163

firestore-stripe-web-sdk/src/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,12 @@ export {
4141
export {
4242
GetPaymentsOptions,
4343
Payment,
44+
PaymentChangeType,
45+
PaymentSnapshot,
4446
PaymentStatus,
4547
getCurrentUserPayment,
4648
getCurrentUserPayments,
49+
onCurrentUserPaymentUpdate,
4750
} from "./payment";
4851

4952
export {

firestore-stripe-web-sdk/src/payment.ts

Lines changed: 117 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,27 @@
1717
import { FirebaseApp } from "@firebase/app";
1818
import {
1919
collection,
20+
CollectionReference,
2021
doc,
22+
DocumentChange,
2123
DocumentData,
2224
DocumentReference,
2325
DocumentSnapshot,
2426
Firestore,
2527
FirestoreDataConverter,
28+
FirestoreError,
2629
getDoc,
2730
getDocs,
2831
getFirestore,
32+
onSnapshot,
2933
query,
3034
Query,
3135
QueryDocumentSnapshot,
3236
QuerySnapshot,
3337
where,
3438
} from "@firebase/firestore";
3539
import { StripePayments, StripePaymentsError } from "./init";
36-
import { getCurrentUser } from "./user";
40+
import { getCurrentUser, getCurrentUserSync } from "./user";
3741
import { checkNonEmptyArray, checkNonEmptyString } from "./utils";
3842

3943
/**
@@ -176,6 +180,68 @@ export function getCurrentUserPayments(
176180
});
177181
}
178182

183+
/**
184+
* Different types of changes that may occur on a payment object.
185+
*/
186+
export type PaymentChangeType = "added" | "modified" | "removed";
187+
188+
/**
189+
* Represents the current state of a set of payments owned by a user.
190+
*/
191+
export interface PaymentSnapshot {
192+
/**
193+
* A list of all currently available payments ordered by the payment ID. Empty
194+
* if no payments are available.
195+
*/
196+
payments: Payment[];
197+
198+
/**
199+
* The list of changes in the payments since the last snapshot.
200+
*/
201+
changes: Array<{
202+
type: PaymentChangeType;
203+
payment: Payment;
204+
}>;
205+
206+
/**
207+
* Number of currently available payments. This is same as the length of the
208+
* `payments` array in the snapshot.
209+
*/
210+
size: number;
211+
212+
/**
213+
* True if there are no payments available. False whenever at least one payment is
214+
* present. When True, the `payments` array is empty, and the `size` is 0.
215+
*/
216+
empty: boolean;
217+
}
218+
219+
/**
220+
* Registers a listener to receive payment update events for the currently signed in
221+
* user. If the user is not signed in throws an `unauthenticated` error, and no listener is
222+
* registered.
223+
*
224+
* Upon successful registration, the `onUpdate` callback will fire once with
225+
* the current state of all the payments. From then onwards, each update to a payment
226+
* will fire the `onUpdate` callback with the latest state of the payments.
227+
*
228+
* @param payments - A valid {@link StripePayments} object.
229+
* @param onUpdate - A callback that will fire whenever the current user's payments
230+
* are updated.
231+
* @param onError - A callback that will fire whenever an error occurs while listening to
232+
* payment updates.
233+
* @returns A function that can be called to cancel and unregister the listener.
234+
*/
235+
export function onCurrentUserPaymentUpdate(
236+
payments: StripePayments,
237+
onUpdate: (snapshot: PaymentSnapshot) => void,
238+
onError?: (error: StripePaymentsError) => void
239+
): () => void {
240+
const uid: string = getCurrentUserSync(payments);
241+
const dao: PaymentDAO = getOrInitPaymentDAO(payments);
242+
return dao.onPaymentUpdate(uid, onUpdate, onError);
243+
}
244+
179245
function getStatusAsArray(
180246
status: PaymentStatus | PaymentStatus[]
181247
): PaymentStatus[] {
@@ -199,6 +265,11 @@ export interface PaymentDAO {
199265
uid: string,
200266
options?: { status?: PaymentStatus[] }
201267
): Promise<Payment[]>;
268+
onPaymentUpdate(
269+
uid: string,
270+
onUpdate: (snapshot: PaymentSnapshot) => void,
271+
onError?: (error: StripePaymentsError) => void
272+
): () => void;
202273
}
203274

204275
const PAYMENT_CONVERTER: FirestoreDataConverter<Payment> = {
@@ -272,6 +343,51 @@ class FirestorePaymentDAO implements PaymentDAO {
272343
return payments;
273344
}
274345

346+
public onPaymentUpdate(
347+
uid: string,
348+
onUpdate: (snapshot: PaymentSnapshot) => void,
349+
onError?: (error: StripePaymentsError) => void
350+
): () => void {
351+
const payments: CollectionReference<Payment> = collection(
352+
this.firestore,
353+
this.customersCollection,
354+
uid,
355+
PAYMENTS_COLLECTION
356+
).withConverter(PAYMENT_CONVERTER);
357+
return onSnapshot(
358+
payments,
359+
(querySnap: QuerySnapshot<Payment>) => {
360+
const snapshot: PaymentSnapshot = {
361+
payments: [],
362+
changes: [],
363+
size: querySnap.size,
364+
empty: querySnap.empty,
365+
};
366+
querySnap.forEach((snap: QueryDocumentSnapshot<Payment>) => {
367+
snapshot.payments.push(snap.data());
368+
});
369+
querySnap.docChanges().forEach((change: DocumentChange<Payment>) => {
370+
snapshot.changes.push({
371+
type: change.type,
372+
payment: change.doc.data(),
373+
});
374+
});
375+
376+
onUpdate(snapshot);
377+
},
378+
(err: FirestoreError) => {
379+
if (onError) {
380+
const arg: StripePaymentsError = new StripePaymentsError(
381+
"internal",
382+
`Error while listening to database updates: ${err.message}`,
383+
err
384+
);
385+
onError(arg);
386+
}
387+
}
388+
);
389+
}
390+
275391
private async getPaymentSnapshotIfExists(
276392
uid: string,
277393
paymentId: string

0 commit comments

Comments
 (0)