sbcwallet 0.0.1

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.
Files changed (67) hide show
  1. package/.env.example +10 -0
  2. package/.github/workflows/build.yml +66 -0
  3. package/.github/workflows/release.yml +57 -0
  4. package/APPLE_WALLET_SETUP.md +318 -0
  5. package/GOOGLE_WALLET_SETUP.md +473 -0
  6. package/LICENSE +201 -0
  7. package/README.md +187 -0
  8. package/dist/adapters/apple.d.ts +10 -0
  9. package/dist/adapters/apple.js +153 -0
  10. package/dist/adapters/google.d.ts +26 -0
  11. package/dist/adapters/google.js +431 -0
  12. package/dist/api/unified.d.ts +67 -0
  13. package/dist/api/unified.js +375 -0
  14. package/dist/index.d.ts +8 -0
  15. package/dist/index.js +11 -0
  16. package/dist/profiles/healthcare/index.d.ts +91 -0
  17. package/dist/profiles/healthcare/index.js +151 -0
  18. package/dist/profiles/logistics/index.d.ts +91 -0
  19. package/dist/profiles/logistics/index.js +152 -0
  20. package/dist/profiles/loyalty/index.d.ts +91 -0
  21. package/dist/profiles/loyalty/index.js +81 -0
  22. package/dist/templates/apple/child.json +59 -0
  23. package/dist/templates/apple/parent.json +54 -0
  24. package/dist/templates/google/child_object.json +38 -0
  25. package/dist/templates/google/loyalty_class.json +7 -0
  26. package/dist/templates/google/loyalty_object.json +29 -0
  27. package/dist/templates/google/parent_class.json +10 -0
  28. package/dist/templates/google/parent_object.json +33 -0
  29. package/dist/types.d.ts +422 -0
  30. package/dist/types.js +80 -0
  31. package/dist/utils/progress-image.d.ts +23 -0
  32. package/dist/utils/progress-image.js +94 -0
  33. package/examples/.loyalty-fixed-state.json +10 -0
  34. package/examples/claim-flow.ts +163 -0
  35. package/examples/loyalty-admin-server.js +207 -0
  36. package/examples/loyalty-admin.html +260 -0
  37. package/examples/loyalty-fixed-card-server.js +288 -0
  38. package/examples/loyalty-flow.ts +78 -0
  39. package/examples/loyalty-google-issue.js +115 -0
  40. package/package.json +51 -0
  41. package/scripts/copy-assets.js +35 -0
  42. package/scripts/smoke-dist-import.js +39 -0
  43. package/setup-google-class.js +97 -0
  44. package/setup-google-class.ts +105 -0
  45. package/src/adapters/apple.ts +193 -0
  46. package/src/adapters/google.ts +521 -0
  47. package/src/api/unified.ts +487 -0
  48. package/src/index.ts +74 -0
  49. package/src/profiles/healthcare/index.ts +157 -0
  50. package/src/profiles/logistics/index.ts +158 -0
  51. package/src/profiles/loyalty/index.ts +87 -0
  52. package/src/templates/apple/child.json +59 -0
  53. package/src/templates/apple/parent.json +54 -0
  54. package/src/templates/google/child_object.json +38 -0
  55. package/src/templates/google/loyalty_class.json +7 -0
  56. package/src/templates/google/loyalty_object.json +29 -0
  57. package/src/templates/google/parent_class.json +10 -0
  58. package/src/templates/google/parent_object.json +33 -0
  59. package/src/types.ts +324 -0
  60. package/src/utils/progress-image.ts +130 -0
  61. package/test-google-wallet.js +78 -0
  62. package/test-google-wallet.ts +94 -0
  63. package/tests/adapters.test.ts +244 -0
  64. package/tests/loyalty.test.ts +39 -0
  65. package/tests/unified.test.ts +388 -0
  66. package/tsconfig.json +19 -0
  67. package/vitest.config.ts +12 -0
@@ -0,0 +1,487 @@
1
+ import type {
2
+ CreateParentInput,
3
+ CreateChildInput,
4
+ CreateBusinessInput,
5
+ CreateCustomerAccountInput,
6
+ CreateLoyaltyProgramInput,
7
+ IssueLoyaltyCardInput,
8
+ UpdateLoyaltyPointsInput,
9
+ LoyaltyBusiness,
10
+ LoyaltyCustomerAccount,
11
+ ParentPassData,
12
+ ChildPassData,
13
+ PassData,
14
+ PassStatus,
15
+ ProfileType,
16
+ ProfileConfig,
17
+ PassGenerationResult
18
+ } from '../types.js'
19
+ import {
20
+ CreateParentInputSchema,
21
+ CreateChildInputSchema,
22
+ CreateBusinessInputSchema,
23
+ CreateCustomerAccountInputSchema,
24
+ CreateLoyaltyProgramInputSchema,
25
+ IssueLoyaltyCardInputSchema,
26
+ UpdateLoyaltyPointsInputSchema
27
+ } from '../types.js'
28
+ import { AppleWalletAdapter } from '../adapters/apple.js'
29
+ import { GoogleWalletAdapter } from '../adapters/google.js'
30
+ import logisticsProfile from '../profiles/logistics/index.js'
31
+ import healthcareProfile from '../profiles/healthcare/index.js'
32
+ import loyaltyProfile from '../profiles/loyalty/index.js'
33
+
34
+ const hashEvent = (data: any): string => {
35
+ // Include timestamp and random value to ensure unique hashes
36
+ const str = JSON.stringify({ ...data, _timestamp: Date.now(), _random: Math.random() })
37
+ return `hash_${Buffer.from(str).toString('base64').slice(0, 32)}`
38
+ }
39
+
40
+ const signCredential = (hash: string): string => {
41
+ return `sig_${hash.slice(5, 37)}`
42
+ }
43
+
44
+ // In-memory storage (replace with actual database in production)
45
+ const passStore = new Map<string, PassData>()
46
+ const businessStore = new Map<string, LoyaltyBusiness>()
47
+ const customerStore = new Map<string, LoyaltyCustomerAccount>()
48
+
49
+ // Profile registry
50
+ const profiles: Record<ProfileType, ProfileConfig> = {
51
+ logistics: logisticsProfile,
52
+ healthcare: healthcareProfile,
53
+ loyalty: loyaltyProfile
54
+ }
55
+
56
+ /**
57
+ * Get a profile by name
58
+ */
59
+ export function getProfile(profileType: ProfileType): ProfileConfig {
60
+ return profiles[profileType]
61
+ }
62
+
63
+ /**
64
+ * List all available profiles
65
+ */
66
+ export function listProfiles(): ProfileType[] {
67
+ return Object.keys(profiles) as ProfileType[]
68
+ }
69
+
70
+ /**
71
+ * Generate a unique ID for a pass
72
+ */
73
+ function generatePassId(profile: ProfileType, type: 'parent' | 'child', parentId?: string): string {
74
+ const date = new Date().toISOString().split('T')[0]
75
+ const random = Math.random().toString(36).substring(2, 6).toUpperCase()
76
+
77
+ if (type === 'parent') {
78
+ const prefix = profile === 'logistics' ? 'PES' : profile === 'healthcare' ? 'APB' : 'LPR'
79
+ return `${prefix}-${date}-${random}`
80
+ } else {
81
+ const prefix = profile === 'logistics' ? 'TO' : profile === 'healthcare' ? 'PV' : 'LCR'
82
+ const parentSuffix = parentId ? parentId.split('-').pop() : random
83
+ return `${prefix}-${date}-${parentSuffix}-${random}`
84
+ }
85
+ }
86
+
87
+ function generateBusinessId(): string {
88
+ const date = new Date().toISOString().split('T')[0]
89
+ const random = Math.random().toString(36).substring(2, 8).toUpperCase()
90
+ return `BIZ-${date}-${random}`
91
+ }
92
+
93
+ function generateCustomerId(): string {
94
+ const date = new Date().toISOString().split('T')[0]
95
+ const random = Math.random().toString(36).substring(2, 8).toUpperCase()
96
+ return `CUS-${date}-${random}`
97
+ }
98
+
99
+ function generateMemberId(businessId: string): string {
100
+ const bizSuffix = businessId.split('-').pop() || 'BIZ'
101
+ const random = Math.random().toString(36).substring(2, 10).toUpperCase()
102
+ // This is the value we encode into the QR code / barcode.
103
+ return `SBC-${bizSuffix}-${random}`
104
+ }
105
+
106
+ /**
107
+ * Create a business (tenant) that owns a loyalty program.
108
+ */
109
+ export function createBusiness(input: CreateBusinessInput): LoyaltyBusiness {
110
+ const validated = CreateBusinessInputSchema.parse(input)
111
+
112
+ const id = (validated as any).id || generateBusinessId()
113
+ const now = new Date().toISOString()
114
+
115
+ const business: LoyaltyBusiness = {
116
+ id,
117
+ name: validated.name,
118
+ programName: validated.programName || `${validated.name} Loyalty`,
119
+ pointsLabel: validated.pointsLabel || 'Points',
120
+ createdAt: now,
121
+ updatedAt: now
122
+ }
123
+
124
+ businessStore.set(id, business)
125
+ return business
126
+ }
127
+
128
+ export function getBusiness(businessId: string): LoyaltyBusiness | undefined {
129
+ return businessStore.get(businessId)
130
+ }
131
+
132
+ /**
133
+ * Create a customer account under a business.
134
+ */
135
+ export function createCustomerAccount(input: CreateCustomerAccountInput): LoyaltyCustomerAccount {
136
+ const validated = CreateCustomerAccountInputSchema.parse(input)
137
+
138
+ const business = businessStore.get(validated.businessId)
139
+ if (!business) {
140
+ throw new Error(`Business not found: ${validated.businessId}`)
141
+ }
142
+
143
+ const id = (validated as any).id || generateCustomerId()
144
+ const now = new Date().toISOString()
145
+
146
+ const customer: LoyaltyCustomerAccount = {
147
+ id,
148
+ businessId: validated.businessId,
149
+ fullName: validated.fullName,
150
+ memberId: (validated as any).memberId || generateMemberId(validated.businessId),
151
+ createdAt: now,
152
+ updatedAt: now
153
+ }
154
+
155
+ customerStore.set(id, customer)
156
+ return customer
157
+ }
158
+
159
+ export function getCustomerAccount(customerId: string): LoyaltyCustomerAccount | undefined {
160
+ return customerStore.get(customerId)
161
+ }
162
+
163
+ /**
164
+ * Define (or update) the loyalty program pass for a business.
165
+ * This creates a parent pass with profile=loyalty.
166
+ */
167
+ export async function createLoyaltyProgram(input: CreateLoyaltyProgramInput): Promise<ParentPassData> {
168
+ const validated = CreateLoyaltyProgramInputSchema.parse(input)
169
+
170
+ const business = businessStore.get(validated.businessId)
171
+ if (!business) {
172
+ throw new Error(`Business not found: ${validated.businessId}`)
173
+ }
174
+
175
+ const program = await createParentSchedule({
176
+ id: (validated as any).programId,
177
+ profile: 'loyalty',
178
+ programName: validated.programName || business.programName,
179
+ site: validated.site,
180
+ metadata: {
181
+ ...validated.metadata,
182
+ businessId: business.id,
183
+ businessName: business.name,
184
+ pointsLabel: business.pointsLabel,
185
+ googleWallet: {
186
+ ...(validated.metadata as any)?.googleWallet,
187
+ locations: validated.locations,
188
+ countryCode: validated.countryCode,
189
+ homepageUrl: validated.homepageUrl
190
+ }
191
+ }
192
+ })
193
+
194
+ business.loyaltyProgramId = program.id
195
+ business.updatedAt = new Date().toISOString()
196
+ businessStore.set(business.id, business)
197
+
198
+ return program
199
+ }
200
+
201
+ /**
202
+ * Issue a loyalty card (child pass) for a customer.
203
+ * QR/barcode value uses memberId.
204
+ */
205
+ export async function issueLoyaltyCard(input: IssueLoyaltyCardInput): Promise<ChildPassData> {
206
+ const validated = IssueLoyaltyCardInputSchema.parse(input)
207
+
208
+ const business = businessStore.get(validated.businessId)
209
+ if (!business) {
210
+ throw new Error(`Business not found: ${validated.businessId}`)
211
+ }
212
+ if (!business.loyaltyProgramId) {
213
+ throw new Error(`Business has no loyalty program yet: ${validated.businessId}`)
214
+ }
215
+
216
+ const customer = customerStore.get(validated.customerId)
217
+ if (!customer || customer.businessId !== validated.businessId) {
218
+ throw new Error(`Customer not found for business: ${validated.customerId}`)
219
+ }
220
+
221
+ const program = passStore.get(business.loyaltyProgramId)
222
+ const programGoogleWallet = program && program.type === 'parent' ? (program.metadata as any)?.googleWallet : undefined
223
+
224
+ const card = await createChildTicket({
225
+ id: (validated as any).cardId,
226
+ profile: 'loyalty',
227
+ parentId: business.loyaltyProgramId,
228
+ businessId: business.id,
229
+ customerId: customer.id,
230
+ customerName: customer.fullName,
231
+ memberId: customer.memberId,
232
+ points: validated.initialPoints,
233
+ metadata: {
234
+ ...validated.metadata,
235
+ businessName: business.name,
236
+ pointsLabel: business.pointsLabel,
237
+ googleWallet: {
238
+ ...(programGoogleWallet || {}),
239
+ ...((validated.metadata as any)?.googleWallet || {})
240
+ }
241
+ }
242
+ })
243
+
244
+ // Loyalty cards start as ACTIVE unless explicitly overridden
245
+ card.status = 'ACTIVE' as PassStatus
246
+ card.updatedAt = new Date().toISOString()
247
+ card.hash = hashEvent(card)
248
+ card.signature = signCredential(card.hash)
249
+ passStore.set(card.id, card)
250
+
251
+ return card
252
+ }
253
+
254
+ /**
255
+ * Update points on a loyalty card.
256
+ */
257
+ export async function updateLoyaltyPoints(input: UpdateLoyaltyPointsInput): Promise<PassData> {
258
+ const validated = UpdateLoyaltyPointsInputSchema.parse(input)
259
+ const pass = passStore.get(validated.cardId)
260
+
261
+ if (!pass) {
262
+ throw new Error(`Pass not found: ${validated.cardId}`)
263
+ }
264
+ if (pass.type !== 'child' || pass.profile !== 'loyalty') {
265
+ throw new Error(`Not a loyalty card: ${validated.cardId}`)
266
+ }
267
+
268
+ const currentPoints = typeof pass.points === 'number' ? pass.points : 0
269
+ const nextPoints = validated.setPoints !== undefined
270
+ ? validated.setPoints
271
+ : Math.max(0, currentPoints + (validated.delta || 0))
272
+
273
+ pass.points = nextPoints
274
+ pass.updatedAt = new Date().toISOString()
275
+
276
+ pass.hash = hashEvent(pass)
277
+ pass.signature = signCredential(pass.hash)
278
+
279
+ passStore.set(pass.id, pass)
280
+ return pass
281
+ }
282
+
283
+ /**
284
+ * Create a parent schedule (PES or AppointmentBatch)
285
+ */
286
+ export async function createParentSchedule(input: CreateParentInput): Promise<ParentPassData> {
287
+ // Validate input
288
+ const validated = CreateParentInputSchema.parse(input)
289
+
290
+ // Get profile
291
+ const profile = getProfile(validated.profile)
292
+
293
+ // Generate ID (allow callers to provide a stable one)
294
+ const id = (validated as any).id || generatePassId(validated.profile, 'parent')
295
+
296
+ // Get initial status
297
+ const initialStatus = profile.statusFlow[0] as PassStatus
298
+
299
+ // Create pass data
300
+ const passData: ParentPassData = {
301
+ id,
302
+ type: 'parent',
303
+ profile: validated.profile,
304
+ programName: validated.programName,
305
+ site: validated.site,
306
+ window: validated.window,
307
+ capacity: validated.capacity,
308
+ metadata: validated.metadata,
309
+ createdAt: new Date().toISOString(),
310
+ updatedAt: new Date().toISOString(),
311
+ status: initialStatus
312
+ }
313
+
314
+ const hash = hashEvent(passData)
315
+ const signature = signCredential(hash)
316
+
317
+ passData.hash = hash
318
+ passData.signature = signature
319
+
320
+ // Store pass
321
+ passStore.set(id, passData)
322
+
323
+ return passData
324
+ }
325
+
326
+ /**
327
+ * Create a child ticket (TO or PatientVisit)
328
+ */
329
+ export async function createChildTicket(input: CreateChildInput): Promise<ChildPassData> {
330
+ // Validate input
331
+ const validated = CreateChildInputSchema.parse(input)
332
+
333
+ // Verify parent exists
334
+ const parent = passStore.get(validated.parentId)
335
+ if (!parent || parent.type !== 'parent') {
336
+ throw new Error(`Parent pass not found: ${validated.parentId}`)
337
+ }
338
+
339
+ // Get profile
340
+ const profile = getProfile(validated.profile)
341
+
342
+ // Generate ID (allow callers to provide a stable one)
343
+ const id = (validated as any).id || generatePassId(validated.profile, 'child', validated.parentId)
344
+
345
+ // Get initial status
346
+ const initialStatus = profile.statusFlow[0] as PassStatus
347
+
348
+ // Create pass data
349
+ const passData: ChildPassData = {
350
+ id,
351
+ type: 'child',
352
+ profile: validated.profile,
353
+ parentId: validated.parentId,
354
+ plate: validated.plate,
355
+ carrier: validated.carrier,
356
+ client: validated.client,
357
+ patientName: validated.patientName,
358
+ procedure: validated.procedure,
359
+ doctor: validated.doctor,
360
+ businessId: validated.businessId,
361
+ customerId: validated.customerId,
362
+ customerName: validated.customerName,
363
+ memberId: validated.memberId,
364
+ points: validated.points,
365
+ metadata: validated.metadata,
366
+ createdAt: new Date().toISOString(),
367
+ updatedAt: new Date().toISOString(),
368
+ status: initialStatus
369
+ }
370
+
371
+ const hash = hashEvent(passData)
372
+ const signature = signCredential(hash)
373
+
374
+ passData.hash = hash
375
+ passData.signature = signature
376
+
377
+ // Store pass
378
+ passStore.set(id, passData)
379
+
380
+ return passData
381
+ }
382
+
383
+ /**
384
+ * Update the status of a pass
385
+ */
386
+ export async function updatePassStatus(passId: string, newStatus: PassStatus): Promise<PassData> {
387
+ // Get pass
388
+ const passData = passStore.get(passId)
389
+ if (!passData) {
390
+ throw new Error(`Pass not found: ${passId}`)
391
+ }
392
+
393
+ // Get profile
394
+ const profile = getProfile(passData.profile)
395
+
396
+ // Validate status transition
397
+ if (!profile.statusFlow.includes(newStatus)) {
398
+ throw new Error(`Invalid status '${newStatus}' for profile '${passData.profile}'`)
399
+ }
400
+
401
+ // Update status
402
+ passData.status = newStatus
403
+ passData.updatedAt = new Date().toISOString()
404
+
405
+ // Re-hash and sign
406
+ const hash = hashEvent(passData)
407
+ const signature = signCredential(hash)
408
+
409
+ passData.hash = hash
410
+ passData.signature = signature
411
+
412
+ // Update store
413
+ passStore.set(passId, passData)
414
+
415
+ return passData
416
+ }
417
+
418
+ /**
419
+ * Get a pass by ID
420
+ */
421
+ export function getPass(passId: string): PassData | undefined {
422
+ return passStore.get(passId)
423
+ }
424
+
425
+ /**
426
+ * Get Apple Wallet .pkpass buffer for a pass
427
+ */
428
+ export async function getPkpassBuffer(
429
+ passType: 'parent' | 'child',
430
+ passData: PassData
431
+ ): Promise<Buffer> {
432
+ const profile = getProfile(passData.profile)
433
+ const adapter = new AppleWalletAdapter()
434
+
435
+ return adapter.generatePkpass(passData, profile, passType)
436
+ }
437
+
438
+ /**
439
+ * Get Google Wallet object for a pass
440
+ */
441
+ export async function getGoogleObject(
442
+ passType: 'parent' | 'child',
443
+ passData: PassData
444
+ ): Promise<{ object: any; saveUrl: string }> {
445
+ const profile = getProfile(passData.profile)
446
+ const adapter = new GoogleWalletAdapter()
447
+
448
+ return adapter.generatePassObject(passData, profile, passType)
449
+ }
450
+
451
+ /**
452
+ * Generate a complete pass with both Apple and Google wallet data
453
+ */
454
+ export async function generatePass(
455
+ passData: PassData,
456
+ options: {
457
+ includeApple?: boolean
458
+ includeGoogle?: boolean
459
+ } = { includeApple: true, includeGoogle: true }
460
+ ): Promise<PassGenerationResult> {
461
+ const profile = getProfile(passData.profile)
462
+ const passType = passData.type
463
+
464
+ const result: PassGenerationResult = {
465
+ passData
466
+ }
467
+
468
+ if (options.includeApple) {
469
+ try {
470
+ result.applePkpass = await getPkpassBuffer(passType, passData)
471
+ } catch (error) {
472
+ console.warn('Failed to generate Apple Wallet pass:', error)
473
+ }
474
+ }
475
+
476
+ if (options.includeGoogle) {
477
+ try {
478
+ const googleResult = await getGoogleObject(passType, passData)
479
+ result.googleObject = googleResult.object
480
+ result.googleSaveUrl = googleResult.saveUrl
481
+ } catch (error) {
482
+ console.warn('Failed to generate Google Wallet object:', error)
483
+ }
484
+ }
485
+
486
+ return result
487
+ }
package/src/index.ts ADDED
@@ -0,0 +1,74 @@
1
+ // Main exports
2
+ export {
3
+ createParentSchedule,
4
+ createChildTicket,
5
+ updatePassStatus,
6
+ createBusiness,
7
+ getBusiness,
8
+ createCustomerAccount,
9
+ getCustomerAccount,
10
+ createLoyaltyProgram,
11
+ issueLoyaltyCard,
12
+ updateLoyaltyPoints,
13
+ getPkpassBuffer,
14
+ getGoogleObject,
15
+ listProfiles,
16
+ getProfile,
17
+ getPass,
18
+ generatePass
19
+ } from './api/unified.js'
20
+
21
+ // Adapter exports
22
+ export { AppleWalletAdapter } from './adapters/apple.js'
23
+ export { GoogleWalletAdapter } from './adapters/google.js'
24
+
25
+ // Profile exports
26
+ export { default as logisticsProfile } from './profiles/logistics/index.js'
27
+ export { default as healthcareProfile } from './profiles/healthcare/index.js'
28
+ export { default as loyaltyProfile } from './profiles/loyalty/index.js'
29
+
30
+ // Type exports
31
+ export type {
32
+ ProfileType,
33
+ PassStatus,
34
+ LogisticsStatus,
35
+ HealthcareStatus,
36
+ LoyaltyStatus,
37
+ GeoLocation,
38
+ TimeWindow,
39
+ BasePassData,
40
+ ParentPassData,
41
+ ChildPassData,
42
+ PassData,
43
+ CreateParentInput,
44
+ CreateChildInput,
45
+ LoyaltyBusiness,
46
+ LoyaltyCustomerAccount,
47
+ CreateBusinessInput,
48
+ CreateCustomerAccountInput,
49
+ CreateLoyaltyProgramInput,
50
+ IssueLoyaltyCardInput,
51
+ UpdateLoyaltyPointsInput,
52
+ ApplePassConfig,
53
+ ApplePassField,
54
+ ApplePassTemplate,
55
+ GooglePassConfig,
56
+ GoogleTextField,
57
+ GooglePassClass,
58
+ GooglePassObject,
59
+ ProfileFieldMap,
60
+ ProfileConfig,
61
+ PassGenerationResult
62
+ } from './types.js'
63
+
64
+ // Schema exports
65
+ export {
66
+ CreateParentInputSchema,
67
+ CreateChildInputSchema,
68
+ TimeWindowSchema,
69
+ CreateBusinessInputSchema,
70
+ CreateCustomerAccountInputSchema,
71
+ CreateLoyaltyProgramInputSchema,
72
+ IssueLoyaltyCardInputSchema,
73
+ UpdateLoyaltyPointsInputSchema
74
+ } from './types.js'
@@ -0,0 +1,157 @@
1
+ import type { ProfileConfig, ProfileFieldMap, HealthcareStatus } from '../../types.js'
2
+
3
+ export const statusFlow: HealthcareStatus[] = [
4
+ 'SCHEDULED',
5
+ 'CHECKIN',
6
+ 'PROCEDURE',
7
+ 'DISCHARGED'
8
+ ]
9
+
10
+ export const fieldMap: ProfileFieldMap = {
11
+ parent: {
12
+ programName: { label: 'Appointment Batch', key: 'programName' },
13
+ site: { label: 'Location', key: 'site' },
14
+ windowFrom: { label: 'Date Start', key: 'window.from' },
15
+ windowTo: { label: 'Date End', key: 'window.to' },
16
+ capacity: { label: 'Total Slots', key: 'capacity' }
17
+ },
18
+ child: {
19
+ patientName: { label: 'Patient', key: 'patientName' },
20
+ doctor: { label: 'Doctor', key: 'doctor' },
21
+ procedure: { label: 'Procedure', key: 'procedure' },
22
+ status: { label: 'Status', key: 'status' },
23
+ parentId: { label: 'Batch ID', key: 'parentId' }
24
+ }
25
+ }
26
+
27
+ export const defaultTemplates = {
28
+ apple: {
29
+ parent: {
30
+ formatVersion: 1,
31
+ organizationName: 'sbcwallet Healthcare',
32
+ description: 'Appointment Batch',
33
+ backgroundColor: 'rgb(100, 149, 237)',
34
+ foregroundColor: 'rgb(255, 255, 255)',
35
+ labelColor: 'rgb(220, 230, 255)',
36
+ logoText: 'Health',
37
+ generic: {
38
+ primaryFields: [
39
+ {
40
+ key: 'programName',
41
+ label: 'Appointment Batch',
42
+ value: ''
43
+ }
44
+ ],
45
+ secondaryFields: [
46
+ {
47
+ key: 'site',
48
+ label: 'Location',
49
+ value: ''
50
+ }
51
+ ],
52
+ auxiliaryFields: [
53
+ {
54
+ key: 'windowFrom',
55
+ label: 'Start Date',
56
+ value: ''
57
+ },
58
+ {
59
+ key: 'windowTo',
60
+ label: 'End Date',
61
+ value: ''
62
+ }
63
+ ],
64
+ backFields: [
65
+ {
66
+ key: 'batchId',
67
+ label: 'Batch ID',
68
+ value: ''
69
+ },
70
+ {
71
+ key: 'capacity',
72
+ label: 'Total Slots',
73
+ value: ''
74
+ }
75
+ ]
76
+ }
77
+ },
78
+ child: {
79
+ formatVersion: 1,
80
+ organizationName: 'sbcwallet Healthcare',
81
+ description: 'Patient Visit',
82
+ backgroundColor: 'rgb(72, 201, 176)',
83
+ foregroundColor: 'rgb(255, 255, 255)',
84
+ labelColor: 'rgb(200, 255, 240)',
85
+ logoText: 'Health',
86
+ generic: {
87
+ primaryFields: [
88
+ {
89
+ key: 'patientName',
90
+ label: 'Patient',
91
+ value: ''
92
+ }
93
+ ],
94
+ secondaryFields: [
95
+ {
96
+ key: 'doctor',
97
+ label: 'Doctor',
98
+ value: ''
99
+ },
100
+ {
101
+ key: 'status',
102
+ label: 'Status',
103
+ value: 'SCHEDULED'
104
+ }
105
+ ],
106
+ auxiliaryFields: [
107
+ {
108
+ key: 'procedure',
109
+ label: 'Procedure',
110
+ value: ''
111
+ }
112
+ ],
113
+ backFields: [
114
+ {
115
+ key: 'visitId',
116
+ label: 'Visit ID',
117
+ value: ''
118
+ },
119
+ {
120
+ key: 'parentId',
121
+ label: 'Batch ID',
122
+ value: ''
123
+ }
124
+ ]
125
+ }
126
+ }
127
+ },
128
+ google: {
129
+ parentClass: {
130
+ issuerName: 'sbcwallet Healthcare',
131
+ reviewStatus: 'UNDER_REVIEW'
132
+ },
133
+ parentObject: {
134
+ state: 'ACTIVE',
135
+ cardTitle: {
136
+ header: 'Appointment Batch',
137
+ body: ''
138
+ }
139
+ },
140
+ childObject: {
141
+ state: 'ACTIVE',
142
+ cardTitle: {
143
+ header: 'Patient Visit',
144
+ body: ''
145
+ }
146
+ }
147
+ }
148
+ }
149
+
150
+ export const healthcareProfile: ProfileConfig = {
151
+ name: 'healthcare',
152
+ fieldMap,
153
+ statusFlow,
154
+ defaultTemplates
155
+ }
156
+
157
+ export default healthcareProfile