shopflo-appbrew 0.1.1 → 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shopflo-appbrew",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "main": "./src/index.ts",
5
5
  "types": "./src/index.ts",
6
6
  "exports": {
@@ -24,7 +24,6 @@ import { useIsFocused } from '@react-navigation/native'
24
24
  import {
25
25
  isShopifyCartUrl,
26
26
  lastSegment,
27
- toCartSignature,
28
27
  toShopfloCartUrl,
29
28
  } from '../utils/shopflo'
30
29
  import { toUpiAppUrl } from '../utils/payment-intents'
@@ -49,9 +48,6 @@ export function ShopfloWebview(props: ShopfloWebviewProps) {
49
48
  { checkoutUrl: string; tokenId: string; loadId: number } | undefined
50
49
  >()
51
50
  const isFocused = useIsFocused()
52
- const cartSignature = useAppStore((s) => toCartSignature(s.cart.data.lineItems))
53
- // Signature of the cart Shopflo currently shows; null until the first load
54
- const loadedSignature = React.useRef<string | null>(null)
55
51
  // Id of the newest token request; an older one resolving later is dropped
56
52
  const latestRequest = React.useRef(0)
57
53
  const block = useBlock(props.screenId, props.componentId, props.instanceId)
@@ -123,15 +119,12 @@ export function ShopfloWebview(props: ShopfloWebviewProps) {
123
119
  }
124
120
 
125
121
  // Get the URL from the provider
126
- loadedSignature.current = toCartSignature(
127
- useAppStore.getState().cart.data.lineItems
128
- )
129
122
  const request = ++latestRequest.current
130
123
  const result =
131
124
  page === 'checkout'
132
125
  ? await checkoutProvider.fetchCheckoutUrl()
133
126
  : await checkoutProvider.fetchCartUrl()
134
- // The cart changed while this was in flight; the newer request decides
127
+ // A newer visit started another request while this was in flight
135
128
  if (request !== latestRequest.current) return
136
129
  if (!result?.checkoutUrl || !result?.tokenId) {
137
130
  console.error('Failed to get checkout URL')
@@ -160,16 +153,20 @@ export function ShopfloWebview(props: ShopfloWebviewProps) {
160
153
  capturedCheckout.current = false
161
154
  }, [page, settings, gotoLink, setOverrideBack, onUnavailable])
162
155
 
163
- // On every visit, reload only if the app's cart changed since Shopflo got it.
156
+ // Kept in a ref so only a new visit, not a re-created callback, reloads
157
+ const initializeRef = React.useRef(initializeWebView)
158
+ initializeRef.current = initializeWebView
159
+
160
+ // Every visit mints a fresh token from the app's cart; edits made inside
161
+ // Shopflo while it is open are only synced to the app cart, never reloaded.
164
162
  // An empty cart (after purchase) keeps the thank-you page up
165
163
  React.useEffect(() => {
166
- if (!isFocused || !cartSignature) return
167
- if (cartSignature === loadedSignature.current) return
168
- initializeWebView()
169
- }, [isFocused, cartSignature, initializeWebView])
164
+ if (!isFocused) return
165
+ if (!useAppStore.getState().cart.data.lineItems.length) return
166
+ initializeRef.current()
167
+ }, [isFocused])
170
168
 
171
- // Shopflo already shows edits made inside it; record them as loaded so they
172
- // don't trigger a reload of the cart the user is looking at
169
+ // Shopflo already shows edits made inside it; only the app cart needs them
173
170
  const syncFromShopflo = React.useCallback(
174
171
  async (apply: () => Promise<unknown>) => {
175
172
  try {
@@ -177,9 +174,6 @@ export function ShopfloWebview(props: ShopfloWebviewProps) {
177
174
  } catch (error) {
178
175
  console.warn('Syncing Shopflo cart change failed:', error)
179
176
  }
180
- loadedSignature.current = toCartSignature(
181
- useAppStore.getState().cart.data.lineItems
182
- )
183
177
  },
184
178
  []
185
179
  )
@@ -271,14 +265,6 @@ export function ShopfloWebview(props: ShopfloWebviewProps) {
271
265
  // The cart view's close (X) posts CLOSE_CART_IFRAME, not FLO_EXIT_CHECKOUT
272
266
  case 'CLOSE_CART_IFRAME':
273
267
  case 'FLO_EXIT_CHECKOUT':
274
- // On the cart screen Shopflo moved to checkout inside this WebView
275
- // (is_cart_redirect); put it back on the cart so the next visit
276
- // to the cart screen opens there
277
- if (type === 'FLO_EXIT_CHECKOUT' && page === 'cart') {
278
- setCheckoutData(
279
- (prev) => prev && { ...prev, loadId: prev.loadId + 1 }
280
- )
281
- }
282
268
  if (settings?.source?.closeModalId) {
283
269
  openModal(settings.source.closeModalId)
284
270
  } else {
@@ -292,7 +278,7 @@ export function ShopfloWebview(props: ShopfloWebviewProps) {
292
278
  console.error('Error parsing message from WebView:', error)
293
279
  }
294
280
  },
295
- [page, settings, back, openModal, syncFromShopflo]
281
+ [settings, back, openModal, syncFromShopflo]
296
282
  )
297
283
 
298
284
  if (!checkoutData) return null
@@ -27,12 +27,6 @@ export const isShopifyCartUrl = (url: string, domain: string) =>
27
27
  .replace(/^https?:\/\//, '')
28
28
  .replace(/\/$/, '') === `${domain}/cart`
29
29
 
30
- // What Shopflo was last given; a different value means the token call must
31
- // run again so Shopflo's cart matches the app's
32
- export const toCartSignature = (
33
- lineItems: Array<{ variantId: string; quantity: number }>
34
- ) => lineItems.map((li) => `${li.variantId}:${li.quantity}`).join(',')
35
-
36
30
  // The token's checkout_url already opens Shopflo's cart view (page=cart);
37
31
  // is_cart_redirect=true makes its Checkout button move to checkout inside the
38
32
  // same WebView. String-based: RN's URL lacks full searchParams