@shopify/shop-minis-react 0.2.1 → 0.2.3

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.
@@ -8,6 +8,7 @@ import React, {
8
8
  } from 'react'
9
9
 
10
10
  import {useRequestPermissions} from '../hooks/util/useRequestPermissions'
11
+ import {useReportInteraction} from '../internal/useReportInteraction'
11
12
 
12
13
  export type CameraFacing = 'front' | 'back'
13
14
 
@@ -42,8 +43,10 @@ export function ImagePickerProvider({children}: ImagePickerProviderProps) {
42
43
  input: HTMLInputElement
43
44
  handler: () => void
44
45
  } | null>(null)
46
+ const activeOperationRef = useRef<'gallery' | 'camera' | null>(null)
45
47
 
46
48
  const {requestPermission} = useRequestPermissions()
49
+ const {reportInteraction} = useReportInteraction()
47
50
 
48
51
  const cleanupCancelHandler = useCallback(() => {
49
52
  if (activeCancelHandlerRef.current) {
@@ -55,30 +58,56 @@ export function ImagePickerProvider({children}: ImagePickerProviderProps) {
55
58
 
56
59
  const rejectPendingPromise = useCallback(() => {
57
60
  if (rejectRef.current) {
58
- rejectRef.current(
59
- new Error('New file picker opened before previous completed')
61
+ const error = new Error(
62
+ 'New file picker opened before previous completed'
60
63
  )
64
+ if (activeOperationRef.current === 'gallery') {
65
+ reportInteraction({
66
+ interactionType: 'image_picker_error',
67
+ interactionValue: error.message,
68
+ })
69
+ } else if (activeOperationRef.current === 'camera') {
70
+ reportInteraction({
71
+ interactionType: 'camera_error',
72
+ interactionValue: error.message,
73
+ })
74
+ }
75
+
76
+ rejectRef.current(error)
61
77
  resolveRef.current = null
62
78
  rejectRef.current = null
79
+ activeOperationRef.current = null
63
80
  }
64
- }, [])
81
+ }, [reportInteraction])
65
82
 
66
83
  const handleFileChange = useCallback(
67
84
  (event: React.ChangeEvent<HTMLInputElement>) => {
68
85
  const file = event.target.files?.[0]
69
86
 
70
87
  if (file && resolveRef.current) {
88
+ // Report success based on the active operation
89
+ if (activeOperationRef.current === 'gallery') {
90
+ reportInteraction({
91
+ interactionType: 'image_picker_success',
92
+ })
93
+ } else if (activeOperationRef.current === 'camera') {
94
+ reportInteraction({
95
+ interactionType: 'camera_success',
96
+ })
97
+ }
98
+
71
99
  resolveRef.current(file)
72
100
 
73
101
  resolveRef.current = null
74
102
  rejectRef.current = null
103
+ activeOperationRef.current = null
75
104
 
76
105
  cleanupCancelHandler()
77
106
  }
78
107
 
79
108
  event.target.value = ''
80
109
  },
81
- [cleanupCancelHandler]
110
+ [cleanupCancelHandler, reportInteraction]
82
111
  )
83
112
 
84
113
  const openGallery = useCallback(() => {
@@ -88,21 +117,34 @@ export function ImagePickerProvider({children}: ImagePickerProviderProps) {
88
117
 
89
118
  resolveRef.current = resolve
90
119
  rejectRef.current = reject
120
+ activeOperationRef.current = 'gallery'
91
121
 
92
122
  const input = galleryInputRef.current
93
123
 
94
124
  if (!input) {
95
- reject(new Error('Gallery input not found'))
125
+ const error = new Error('Gallery input not found')
126
+ reportInteraction({
127
+ interactionType: 'image_picker_error',
128
+ interactionValue: error.message,
129
+ })
130
+ reject(error)
96
131
  resolveRef.current = null
97
132
  rejectRef.current = null
133
+ activeOperationRef.current = null
98
134
  return
99
135
  }
100
136
 
101
137
  const handleCancel = () => {
102
138
  if (rejectRef.current) {
103
- rejectRef.current(new Error('User cancelled file selection'))
139
+ const error = new Error('User cancelled file selection')
140
+ reportInteraction({
141
+ interactionType: 'image_picker_error',
142
+ interactionValue: error.message,
143
+ })
144
+ rejectRef.current(error)
104
145
  resolveRef.current = null
105
146
  rejectRef.current = null
147
+ activeOperationRef.current = null
106
148
  }
107
149
  cleanupCancelHandler()
108
150
  }
@@ -110,6 +152,10 @@ export function ImagePickerProvider({children}: ImagePickerProviderProps) {
110
152
  input.addEventListener('cancel', handleCancel)
111
153
  activeCancelHandlerRef.current = {input, handler: handleCancel}
112
154
 
155
+ reportInteraction({
156
+ interactionType: 'image_picker_open',
157
+ })
158
+
113
159
  requestPermission({permission: 'CAMERA'})
114
160
  .then(() => {
115
161
  // This will show both Camera and Gallery
@@ -120,7 +166,12 @@ export function ImagePickerProvider({children}: ImagePickerProviderProps) {
120
166
  input.click()
121
167
  })
122
168
  })
123
- }, [rejectPendingPromise, cleanupCancelHandler, requestPermission])
169
+ }, [
170
+ rejectPendingPromise,
171
+ cleanupCancelHandler,
172
+ requestPermission,
173
+ reportInteraction,
174
+ ])
124
175
 
125
176
  const openCamera = useCallback(
126
177
  (cameraFacing: CameraFacing = 'back') => {
@@ -130,6 +181,7 @@ export function ImagePickerProvider({children}: ImagePickerProviderProps) {
130
181
 
131
182
  resolveRef.current = resolve
132
183
  rejectRef.current = reject
184
+ activeOperationRef.current = 'camera'
133
185
 
134
186
  const input =
135
187
  cameraFacing === 'front'
@@ -137,17 +189,29 @@ export function ImagePickerProvider({children}: ImagePickerProviderProps) {
137
189
  : backCameraInputRef.current
138
190
 
139
191
  if (!input) {
140
- reject(new Error('Camera input not found'))
192
+ const error = new Error('Camera input not found')
193
+ reportInteraction({
194
+ interactionType: 'camera_error',
195
+ interactionValue: error.message,
196
+ })
197
+ reject(error)
141
198
  resolveRef.current = null
142
199
  rejectRef.current = null
200
+ activeOperationRef.current = null
143
201
  return
144
202
  }
145
203
 
146
204
  const handleCancel = () => {
147
205
  if (rejectRef.current) {
148
- rejectRef.current(new Error('User cancelled camera'))
206
+ const error = new Error('User cancelled camera')
207
+ reportInteraction({
208
+ interactionType: 'camera_error',
209
+ interactionValue: error.message,
210
+ })
211
+ rejectRef.current(error)
149
212
  resolveRef.current = null
150
213
  rejectRef.current = null
214
+ activeOperationRef.current = null
151
215
  }
152
216
  cleanupCancelHandler()
153
217
  }
@@ -155,24 +219,41 @@ export function ImagePickerProvider({children}: ImagePickerProviderProps) {
155
219
  input.addEventListener('cancel', handleCancel)
156
220
  activeCancelHandlerRef.current = {input, handler: handleCancel}
157
221
 
222
+ reportInteraction({
223
+ interactionType: 'camera_open',
224
+ })
225
+
158
226
  requestPermission({permission: 'CAMERA'})
159
227
  .then(({granted}) => {
160
228
  if (granted) {
161
229
  input.click()
162
230
  } else {
163
- reject(new Error('Camera permission not granted'))
231
+ const error = new Error('Camera permission not granted')
232
+ reportInteraction({
233
+ interactionType: 'camera_error',
234
+ interactionValue: error.message,
235
+ })
236
+ reject(error)
164
237
  resolveRef.current = null
165
238
  rejectRef.current = null
239
+ activeOperationRef.current = null
166
240
  }
167
241
  })
168
242
  .catch(() => {
169
- reject(new Error('Camera permission not granted'))
243
+ const error = new Error('Camera permission not granted')
244
+ reject(error)
170
245
  resolveRef.current = null
171
246
  rejectRef.current = null
247
+ activeOperationRef.current = null
172
248
  })
173
249
  })
174
250
  },
175
- [rejectPendingPromise, cleanupCancelHandler, requestPermission]
251
+ [
252
+ rejectPendingPromise,
253
+ cleanupCancelHandler,
254
+ requestPermission,
255
+ reportInteraction,
256
+ ]
176
257
  )
177
258
 
178
259
  useEffect(() => {