@bzbs/react-api-client 1.4.12 → 1.4.13

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/README.md CHANGED
@@ -1,82 +1,1035 @@
1
- # Installing
1
+ # @bzbs/react-api-client
2
2
 
3
- Using npm :
3
+ A TypeScript API client library for integrating with Buzzebees services. Provides strongly-typed methods for authentication, campaigns, profiles, shopping carts, notifications, and more.
4
+
5
+ **Version:** 1.4.12 | **License:** ISC | **Author:** Buzzebees Co., Ltd.
6
+
7
+ ## Table of Contents
8
+
9
+ - [Installation](#installation)
10
+ - [Quick Start](#quick-start)
11
+ - [Configuration](#configuration)
12
+ - [Architecture](#architecture)
13
+ - [API Reference](#api-reference)
14
+ - [AuthenticateApi](#authenticateapi)
15
+ - [CampaignApi](#campaignapi)
16
+ - [ProfileApi](#profileapi)
17
+ - [CartApi](#cartapi)
18
+ - [CategoryApi](#categoryapi)
19
+ - [CouponApi](#couponapi)
20
+ - [NotificationApi](#notificationapi)
21
+ - [HistoryApi](#historyapi)
22
+ - [RegistrationApi](#registrationapi)
23
+ - [AddressApi](#addressapi)
24
+ - [BadgeApi](#badgeapi)
25
+ - [ConsentApi](#consentapi)
26
+ - [DashboardApi](#dashboardapi)
27
+ - [LineApi](#lineapi)
28
+ - [PlaceApi](#placeapi)
29
+ - [PointLogApi](#pointlogapi)
30
+ - [StampApi](#stampapi)
31
+ - [RequestHelpApi (Forum)](#requesthelpapi-forum)
32
+ - [SettingApi](#settingapi)
33
+ - [Blob](#blob)
34
+ - [Response Handling](#response-handling)
35
+ - [Error Handling](#error-handling)
36
+ - [Models](#models)
37
+ - [Development](#development)
38
+ - [Build Output](#build-output)
39
+
40
+ ---
41
+
42
+ ## Installation
4
43
 
5
44
  ```bash
6
- npm i @bzbs/react-api-client
45
+ npm install @bzbs/react-api-client
7
46
  ```
8
47
 
9
- Once the package is installed, you can import the library using import or require approach:
48
+ ## Quick Start
10
49
 
11
- ```js
50
+ ```typescript
51
+ import axios from 'axios';
12
52
  import { BzbsService } from '@bzbs/react-api-client';
53
+
54
+ // 1. Create an Axios instance with default headers
55
+ const axiosClient = axios.create({
56
+ headers: {
57
+ 'Content-Type': 'application/json',
58
+ 'App-Id': '<your-app-id>',
59
+ 'Ocp-Apim-Subscription-Key': '<your-subscription-key>',
60
+ },
61
+ });
62
+
63
+ // 2. Define base URLs
64
+ const baseUrl = 'https://apigateway.buzzebees.com/api/';
65
+ const lineUrl = 'https://api.line.me/'; // Optional, pass "" to skip
66
+ const blobUrl = 'https://blob.buzzebees.com/'; // Blob storage URL
67
+
68
+ // 3. Create the service
69
+ const bzbsService = new BzbsService(axiosClient, baseUrl, lineUrl, blobUrl);
70
+
71
+ // 4. Use any API
72
+ const result = await bzbsService.campaignApi.campaigns({
73
+ config: 'campaign_buzzebeesdemo',
74
+ byConfig: true,
75
+ skip: 0,
76
+ top: 10,
77
+ });
78
+
79
+ if (result.type === 'success') {
80
+ console.log(result.model); // Campaign[]
81
+ }
82
+ ```
83
+
84
+ ## Configuration
85
+
86
+ ### Constructor
87
+
88
+ ```typescript
89
+ new BzbsService(client: AxiosInstance, baseUrl: string, baseLineUrl: string, baseBlobUrl: string)
13
90
  ```
14
91
 
15
- You must to have AxiosInstance, Base URL and Line URL for library require:
92
+ | Parameter | Type | Description |
93
+ |---|---|---|
94
+ | `client` | `AxiosInstance` | Pre-configured Axios instance with headers/interceptors |
95
+ | `baseUrl` | `string` | Buzzebees API base URL |
96
+ | `baseLineUrl` | `string` | LINE API base URL (pass `""` to skip LINE API initialization) |
97
+ | `baseBlobUrl` | `string` | Blob storage base URL |
98
+
99
+ ### Setting Headers
100
+
101
+ Configure your Axios instance with required headers before creating `BzbsService`:
16
102
 
17
- ```js
103
+ ```typescript
18
104
  const axiosClient = axios.create({});
19
- const baseUrl = 'https://www.xxx-api.com/api/';
20
- const lineUrl = 'https://api.line.me/v2/bot/';
105
+
106
+ // Set default headers
107
+ axiosClient.defaults.headers.common = {
108
+ 'Content-Type': 'application/json, multipart/form-data',
109
+ 'App-Id': '<your-app-id>',
110
+ 'Ocp-Apim-Subscription-Key': '<your-subscription-key>',
111
+ };
112
+
113
+ // Add auth token via interceptor
114
+ axiosClient.interceptors.request.use((config) => {
115
+ const token = getStoredToken(); // your token retrieval logic
116
+ if (token) {
117
+ config.headers.Authorization = token;
118
+ }
119
+ return config;
120
+ });
21
121
  ```
22
122
 
23
- And defind const and export libraty to using:
123
+ ### Dynamic URL Updates
124
+
125
+ You can update base URLs at runtime:
24
126
 
25
- ```js
26
- export const bzbsService = new BzbsService(axiosClient, baseUrl, lineUrl);
127
+ ```typescript
128
+ bzbsService.setBaseUrl('https://new-api.buzzebees.com/api/');
129
+ bzbsService.setBlobUrl('https://new-blob.buzzebees.com/');
130
+ bzbsService.setLineUrl('https://api.line.me/');
27
131
  ```
28
132
 
29
- If you have default header you can add to AxiosInstance brfore:
133
+ ---
30
134
 
31
- ```js
32
- const defaultOptions = {
33
- headers: {
34
- 'Content-Type': 'application/json, multipart/form-data',
35
- 'App-Id': 2952697274802274,
36
- 'Ocp-Apim-Subscription-Key': '89c1d9bafb65486aa02606f63cb86b5c',
37
- },
38
- };
135
+ ## Architecture
136
+
137
+ The library follows a layered service architecture:
39
138
 
40
- axiosClient.defaults.headers.common = defaultOptions.headers;
139
+ ```
140
+ BzbsService (entry point)
141
+ ├── AuthenticateApi → auth/
142
+ ├── BadgeApi → profile/me/badges
143
+ ├── CampaignApi → campaign/
144
+ ├── CartApi → cart/
145
+ ├── CategoryApi → campaigncat/
146
+ ├── ConsentApi → consent/
147
+ ├── CouponApi → coupon/
148
+ ├── DashboardApi → dashboard/
149
+ ├── HistoryApi → redeem/
150
+ ├── LineApi → LINE OAuth (optional)
151
+ ├── NotificationApi → noti/
152
+ ├── PlaceApi → place/
153
+ ├── PointLogApi → log/points
154
+ ├── ProfileApi → profile/me
155
+ ├── RegistrationApi → auth/register
156
+ ├── AddressApi → profile/me/address, main/
157
+ ├── StampApi → stamp/
158
+ ├── RequestHelpApi → buzz/, profile/me/help
159
+ ├── SettingApi → setting/
160
+ └── Blob → blob storage
41
161
  ```
42
162
 
43
- ## Example
163
+ All API classes extend `BaseService`, which provides:
164
+ - HTTP methods: `get`, `post`, `put`, `delete`, `patch`
165
+ - Automatic response normalization
166
+ - Error handling with typed responses
167
+ - URL construction utilities
168
+ - FormData creation utility
44
169
 
45
- Create service-config.tsx file:
170
+ ### Directory Structure
46
171
 
47
- ```tsx
48
- import { BzbsService } from '@bzbs/react-api-client';
49
- import axios from 'axios';
172
+ ```
173
+ src/
174
+ ├── api/
175
+ │ ├── base-service.ts # Abstract base with HTTP methods
176
+ │ ├── bzbs-service.ts # Main service aggregator
177
+ │ ├── address/address-api.ts
178
+ │ ├── auth/auth-api.ts
179
+ │ ├── badge/badge-api.ts
180
+ │ ├── blob/blob.ts
181
+ │ ├── campaign/campaign-api.ts
182
+ │ ├── cart/cart-api.ts
183
+ │ ├── category/category-api.ts
184
+ │ ├── consent/consent-api.ts
185
+ │ ├── coupon/coupon-api.ts
186
+ │ ├── dashboard/dashboard-api.ts
187
+ │ ├── history/history-api.ts
188
+ │ ├── line/line-api.ts
189
+ │ ├── notification/notification-api.ts
190
+ │ ├── place/place-api.ts
191
+ │ ├── point-log/point-log-api.ts
192
+ │ ├── profile/profile-api.ts
193
+ │ ├── registration/registration-api.ts
194
+ │ ├── request-help/request-help-api.ts
195
+ │ ├── setting/setting-api.ts
196
+ │ └── stamp/stamp-api.ts
197
+ ├── models/ # TypeScript interfaces
198
+ └── index.ts # Re-exports everything
199
+ ```
50
200
 
51
- const defaultOptions = {
52
- headers: {
53
- 'Content-Type': 'application/json, multipart/form-data',
54
- 'App-Id': 2952697274802274,
55
- 'Ocp-Apim-Subscription-Key': '89c1d9bafb65486aa02606f63cb86b5c',
56
- },
201
+ ---
202
+
203
+ ## API Reference
204
+
205
+ Every API method returns `Promise<ServiceResponse<T>>`. All methods accept an optional `requestOptions` parameter as the last argument for custom headers or query params.
206
+
207
+ ### RequestOptions
208
+
209
+ ```typescript
210
+ type RequestOptions = {
211
+ headers?: { [key: string]: string };
212
+ params?: { [key: string]: string };
213
+ data?: any;
214
+ baseUrl?: string;
57
215
  };
216
+ ```
217
+
218
+ ---
219
+
220
+ ### AuthenticateApi
221
+
222
+ Accessed via `bzbsService.authApi`.
223
+
224
+ | Method | Description | Returns |
225
+ |---|---|---|
226
+ | `deviceLogin(params)` | Login with device UUID | `LoginResponse` |
227
+ | `facebookLogin(params)` | Login with Facebook access token | `LoginResponse` |
228
+ | `googleLogin(params)` | Login with Google ID token | `LoginResponse` |
229
+ | `lineLogin(params)` | Login with LINE credentials | `LoginResponse` |
230
+ | `appleLogin(params)` | Login with Apple ID token + refresh token | `LoginResponse` |
231
+ | `appleToken(params)` | Request Apple refresh token | `AppleToken` |
232
+ | `usernamePasswordLogin(params)` | Login with username/password | `LoginResponse` |
233
+ | `connectLine(params)` | Connect/login with LINE | `LoginResponse` |
234
+ | `connectFacebook(params)` | Connect/login with Facebook | `LoginResponse` |
235
+ | `connectGoogle(params)` | Connect/login with Google | `LoginResponse` |
236
+ | `connectApple(params)` | Connect/login with Apple | `LoginResponse` |
237
+ | `logout(params)` | Logout user | `unknown` |
238
+ | `forgetPassword(params)` | Send forget password request | `ForgetPasswordResponse` |
239
+ | `resetPassword(params)` | Reset user password | `StatusResponse` |
240
+ | `otp(params)` | Request OTP via GET | `OtpResponse` |
241
+ | `otpV2(params)` | Request OTP via POST | `OtpResponse` |
242
+ | `otpEmail(params)` | Request OTP via email | `OtpResponse` |
243
+ | `confirmOtp(params)` | Confirm OTP | `ConfirmOtpResponse` |
244
+ | `validateOtp(params)` | Validate OTP | `ValidateOtpResponse` |
245
+ | `resume(params)` | Refresh token (session resume) | `ResumeResponse` |
246
+ | `updateDevice(params)` | Update device token for push notifications | `ResumeResponse` |
247
+ | `version(clientVersion)` | Get app version info | `Version` |
248
+ | `versionRaw(clientVersion)` | Get raw version info | `any` |
249
+
250
+ #### Login Example
251
+
252
+ ```typescript
253
+ const result = await bzbsService.authApi.deviceLogin({
254
+ appId: 'your-app-id',
255
+ uuid: 'device-uuid',
256
+ deviceLocale: 'en',
257
+ os: 'ios 17.0',
258
+ platform: 'iPhone',
259
+ deviceNotificationEnabled: true,
260
+ clientVersion: 'ios_myapp1.0.0',
261
+ deviceToken: 'fcm-token',
262
+ macAddress: 'device-mac-address',
263
+ });
264
+
265
+ if (result.type === 'success') {
266
+ const { token, userId, jwt } = result.model;
267
+ // Store token for subsequent requests
268
+ }
269
+ ```
270
+
271
+ #### OTP Flow Example
272
+
273
+ ```typescript
274
+ // 1. Request OTP
275
+ const otpResult = await bzbsService.authApi.otp({
276
+ uuid: 'device-uuid',
277
+ appId: 'your-app-id',
278
+ contactNumber: '0812345678',
279
+ });
280
+
281
+ // 2. Validate OTP
282
+ if (otpResult.type === 'success') {
283
+ const validateResult = await bzbsService.authApi.validateOtp({
284
+ appId: 'your-app-id',
285
+ otp: '123456',
286
+ refCode: otpResult.model.refcode,
287
+ type: 'contact_number',
288
+ contactNumber: '0812345678',
289
+ });
290
+ }
291
+ ```
292
+
293
+ ---
294
+
295
+ ### CampaignApi
296
+
297
+ Accessed via `bzbsService.campaignApi`.
298
+
299
+ | Method | Description | Returns |
300
+ |---|---|---|
301
+ | `campaigns(params)` | List campaigns with filtering/sorting | `Campaign[]` |
302
+ | `favoriteCampaigns(params)` | List user's favorite campaigns | `Campaign[]` |
303
+ | `campaignDetails(params)` | Get campaign details by ID | `CampaignDetail` |
304
+ | `addToFavorite(id)` | Add campaign to favorites | `FavoriteResponse` |
305
+ | `removeFromFavorite(params)` | Remove campaign from favorites | `FavoriteResponse` |
306
+ | `redeem(params)` | Redeem a campaign | `RedeemResponse` |
307
+ | `bulkRedeem(params)` | Redeem a campaign in bulk | `RedeemResponse` |
308
+
309
+ #### Campaign List Parameters
310
+
311
+ | Param | Type | Required | Description |
312
+ |---|---|---|---|
313
+ | `config` | `string` | Yes | Campaign list configuration name |
314
+ | `cat` | `string` | No | Category filter |
315
+ | `byConfig` | `boolean` | No | Filter by configuration |
316
+ | `skip` | `number` | No | Pagination offset |
317
+ | `top` | `number` | No | Number of items to retrieve |
318
+ | `keyword` | `string` | No | Search keyword |
319
+ | `sortBy` | `string` | No | Sort order |
320
+ | `center` | `string` | No | Geo coordinates for location-based search |
321
+ | `hashTags` | `string` | No | Filter by hashtags |
322
+ | `sponsorId` | `string` | No | Sponsor filter |
323
+ | `minPoints` | `string` | No | Minimum points filter |
324
+ | `maxPoints` | `string` | No | Maximum points filter |
325
+
326
+ #### Example
327
+
328
+ ```typescript
329
+ // List campaigns
330
+ const campaigns = await bzbsService.campaignApi.campaigns({
331
+ config: 'campaign_buzzebeesdemo',
332
+ byConfig: true,
333
+ skip: 0,
334
+ top: 20,
335
+ keyword: 'coffee',
336
+ sortBy: 'popular',
337
+ });
338
+
339
+ // Redeem a campaign
340
+ const redeem = await bzbsService.campaignApi.redeem({
341
+ id: '12345',
342
+ contactNumber: '0812345678',
343
+ });
344
+ ```
345
+
346
+ ---
347
+
348
+ ### ProfileApi
349
+
350
+ Accessed via `bzbsService.profileApi`.
351
+
352
+ | Method | Description | Returns |
353
+ |---|---|---|
354
+ | `profile()` | Get current user profile | `ProfileResponse` |
355
+ | `updateProfile(params)` | Update user profile (supports image upload) | `ProfileResponse` |
356
+ | `changePassword(params)` | Change user password | `StatusResponse` |
357
+ | `updateShipping(params)` | Update shipping information | `unknown` |
358
+ | `changeContactNumber(params)` | Change contact number (v1) | `ConfirmOtpResponse` |
359
+ | `changeContactNumberV2(params)` | Change contact number (v2) | `any` |
360
+ | `changeContactNumberV3(params)` | Change contact number by user ID (v3) | `any` |
361
+ | `points()` | Get user's current points | `UpdatedPoints` |
362
+ | `expiringPoints()` | Get user's expiring points | `ExpiringPoints` |
363
+ | `deactivate()` | Deactivate user profile | `unknown` |
364
+
365
+ #### Profile Update Example
366
+
367
+ ```typescript
368
+ // Update profile with image
369
+ const result = await bzbsService.profileApi.updateProfile({
370
+ firstName: 'John',
371
+ lastName: 'Doe',
372
+ email: 'john@example.com',
373
+ contactNumber: '0812345678',
374
+ gender: 'male',
375
+ birthDate: 946684800, // Unix timestamp in seconds
376
+ profileImage: fileObject, // File, { uri, name, type }, or object
377
+ });
378
+ ```
379
+
380
+ ---
381
+
382
+ ### CartApi
383
+
384
+ Accessed via `bzbsService.cartApi`.
385
+
386
+ | Method | Description | Returns |
387
+ |---|---|---|
388
+ | `addCart(params)` | Add item to cart | `CartCountResponse` |
389
+ | `cartCount()` | Get cart item count | `CartCountResponse` |
390
+ | `cartAccess(params)` | Get cart access token for web landing | `CartAccessResponse` |
391
+
392
+ ```typescript
393
+ await bzbsService.cartApi.addCart({ id: 'campaign-123', qty: 2 });
394
+ const count = await bzbsService.cartApi.cartCount();
395
+ ```
396
+
397
+ ---
398
+
399
+ ### CategoryApi
400
+
401
+ Accessed via `bzbsService.categoryApi`.
402
+
403
+ | Method | Description | Returns |
404
+ |---|---|---|
405
+ | `categories(params)` | Get campaign categories | `Category[]` |
406
+
407
+ ```typescript
408
+ const categories = await bzbsService.categoryApi.categories({
409
+ config: 'campaign_buzzebeesdemo',
410
+ byConfig: true,
411
+ });
412
+ ```
413
+
414
+ ---
415
+
416
+ ### CouponApi
417
+
418
+ Accessed via `bzbsService.couponApi`.
419
+
420
+ | Method | Description | Returns |
421
+ |---|---|---|
422
+ | `processCodes(params)` | Process coupon codes | `CouponResponse` |
423
+
424
+ ```typescript
425
+ const result = await bzbsService.couponApi.processCodes({
426
+ codes: 'ABCD-1234-EFGH',
427
+ });
428
+ ```
429
+
430
+ ---
431
+
432
+ ### NotificationApi
433
+
434
+ Accessed via `bzbsService.notificationApi`.
435
+
436
+ | Method | Description | Returns |
437
+ |---|---|---|
438
+ | `notifications(params)` | Get notifications list | `Notification[]` |
439
+ | `read(params)` | Mark notifications as read | `unknown` |
440
+
441
+ ```typescript
442
+ const notifs = await bzbsService.notificationApi.notifications({
443
+ mode: 'new', // 'new' | 'all'
444
+ sortBy: 'createdate_desc',
445
+ top: 20,
446
+ skip: 0,
447
+ });
448
+
449
+ // Mark as read
450
+ await bzbsService.notificationApi.read({
451
+ ids: 'rowKey1,rowKey2',
452
+ });
453
+ ```
454
+
455
+ ---
456
+
457
+ ### HistoryApi
458
+
459
+ Accessed via `bzbsService.historyApi`.
460
+
461
+ | Method | Description | Returns |
462
+ |---|---|---|
463
+ | `redeemHistories(params)` | Get redeem history | `Purchase[]` |
464
+ | `use(params)` | Mark a redeemed item as used | `UseCampaignResponse` |
465
+
466
+ ```typescript
467
+ const history = await bzbsService.historyApi.redeemHistories({
468
+ byConfig: true,
469
+ config: 'campaign_buzzebeesdemo',
470
+ skip: 0,
471
+ top: 20,
472
+ });
473
+
474
+ // Use a coupon
475
+ await bzbsService.historyApi.use({ redeemKey: 'ABC123_1' });
476
+ ```
477
+
478
+ ---
479
+
480
+ ### RegistrationApi
481
+
482
+ Accessed via `bzbsService.registerApi`.
483
+
484
+ | Method | Description | Returns |
485
+ |---|---|---|
486
+ | `validateRegister(params)` | Validate registration (triggers OTP) | `OtpResponse` |
487
+ | `register(params)` | Register a new user | `RegistrationResponse` |
488
+
489
+ **Validation Error Codes:**
490
+ - `2078` - Duplicate contact number
491
+ - `2089` - Duplicate email
492
+ - `401` - Duplicate username
493
+
494
+ ```typescript
495
+ // Step 1: Validate
496
+ const validation = await bzbsService.registerApi.validateRegister({
497
+ appId: 'your-app-id',
498
+ username: 'johndoe',
499
+ email: 'john@example.com',
500
+ contactNumber: '0812345678',
501
+ });
502
+
503
+ // Step 2: Register (after OTP verification)
504
+ const registration = await bzbsService.registerApi.register({
505
+ appId: 'your-app-id',
506
+ uuid: 'device-uuid',
507
+ macAddress: 'mac-address',
508
+ os: 'ios 17.0',
509
+ platform: 'iPhone',
510
+ clientVersion: 'ios_myapp1.0.0',
511
+ deviceNotificationEnable: true,
512
+ username: 'johndoe',
513
+ password: 'securepass',
514
+ confirmPassword: 'securepass',
515
+ firstName: 'John',
516
+ lastName: 'Doe',
517
+ contactNumber: '0812345678',
518
+ otp: '123456',
519
+ refCode: 'ABC123',
520
+ options: {},
521
+ });
522
+ ```
523
+
524
+ ---
525
+
526
+ ### AddressApi
527
+
528
+ Accessed via `bzbsService.addressApi`.
529
+
530
+ | Method | Description | Returns |
531
+ |---|---|---|
532
+ | `zipCodes(params)` | Look up zip code information | `ZipCode[]` |
533
+ | `provinces()` | Get Thailand provinces | `Province[]` |
534
+ | `districts(params)` | Get districts by province | `District[]` |
535
+ | `subDistricts(params)` | Get sub-districts by province/district | `SubDistrict[]` |
536
+ | `userAddresses()` | Get user's saved addresses | `Address[]` |
537
+ | `updateAddress(params)` | Create or update an address | `Address` |
538
+ | `deleteAddress(params)` | Delete an address | `unknown` |
539
+ | `userTaxAddresses()` | Get user's tax addresses | `Address[]` |
540
+ | `updateTaxAddress(params)` | Create or update a tax address | `Address` |
541
+ | `deleteTaxAddress(params)` | Delete a tax address | `unknown` |
542
+
543
+ ```typescript
544
+ // Get provinces
545
+ const provinces = await bzbsService.addressApi.provinces();
546
+
547
+ // Get districts for a province
548
+ const districts = await bzbsService.addressApi.districts({
549
+ provinceCode: '10',
550
+ });
551
+
552
+ // Save an address
553
+ await bzbsService.addressApi.updateAddress({
554
+ firstName: 'John',
555
+ lastName: 'Doe',
556
+ address: '123 Main St',
557
+ provinceCode: '10',
558
+ provinceName: 'Bangkok',
559
+ districtCode: '1001',
560
+ districtName: 'Phra Nakhon',
561
+ zipcode: '10200',
562
+ contactNumber: '0812345678',
563
+ isDefault: true,
564
+ });
565
+ ```
566
+
567
+ ---
568
+
569
+ ### BadgeApi
58
570
 
59
- var axiosClient = axios.create({});
60
- axiosClient.defaults.headers.common = defaultOptions.headers;
571
+ Accessed via `bzbsService.badgeApi`.
61
572
 
62
- const baseUrl = 'https://apigateway.buzzebees-uat.com/api/';
63
- const lineUrl = 'https://api.line.me/v2/bot/';
573
+ | Method | Description | Returns |
574
+ |---|---|---|
575
+ | `badges(params)` | Get user badges | `Badge[]` |
64
576
 
65
- export const bzbsService = new BzbsService(axiosClient, baseUrl, lineUrl);
577
+ ```typescript
578
+ const badges = await bzbsService.badgeApi.badges({});
579
+ // Or filter by badge ID
580
+ const badge = await bzbsService.badgeApi.badges({ badgeId: '123' });
66
581
  ```
67
582
 
68
- Using service API in another files:
583
+ ---
69
584
 
70
- ```tsx
71
- import { bzbsService } from './src/service-config';
585
+ ### ConsentApi
72
586
 
73
- const campaigList = async () => {
74
- await bzbsService.campaignApi?.campaign({
75
- config: 'campaign_buzzebeesdemo',
76
- byConfig: true,
77
- skip: 0,
78
- top: 10,
79
- deviceLocale: 1054,
587
+ Accessed via `bzbsService.consentApi`.
588
+
589
+ | Method | Description | Returns |
590
+ |---|---|---|
591
+ | `consent()` | Get user's consent status | `Consent` |
592
+ | `updateConsent(params)` | Update consent preferences | `Consent` |
593
+ | `unconsent()` | Withdraw all consent | `unknown` |
594
+
595
+ ```typescript
596
+ // Get consent
597
+ const consent = await bzbsService.consentApi.consent();
598
+
599
+ // Update consent
600
+ await bzbsService.consentApi.updateConsent({
601
+ termsAndConditions: '1.0',
602
+ dataPrivacy: '1.0',
603
+ marketingOption: '1.0',
604
+ email: '1', // '0' or '1'
605
+ sms: '1',
606
+ notification: '1',
607
+ line: '0',
608
+ });
609
+ ```
610
+
611
+ ---
612
+
613
+ ### DashboardApi
614
+
615
+ Accessed via `bzbsService.dashboardApi`.
616
+
617
+ | Method | Description | Returns |
618
+ |---|---|---|
619
+ | `mainDashboard(params)` | Get main dashboard data | `Dashboard[]` |
620
+ | `subDashboard(params)` | Get sub-dashboard data | `Dashboard[]` |
621
+
622
+ ```typescript
623
+ const dashboard = await bzbsService.dashboardApi.mainDashboard({
624
+ appName: 'buzzebeesdemo',
625
+ locale: 1054, // Thai locale
626
+ });
627
+
628
+ const subDashboard = await bzbsService.dashboardApi.subDashboard({
629
+ dashboardName: 'featured',
630
+ locale: 1054,
631
+ });
632
+ ```
633
+
634
+ ---
635
+
636
+ ### LineApi
637
+
638
+ Accessed via `bzbsService.lineApi` (only initialized if `baseLineUrl` is provided).
639
+
640
+ | Method | Description | Returns |
641
+ |---|---|---|
642
+ | `lineAuth(params)` | Authenticate with LINE OAuth | `LineAuthResponse` |
643
+
644
+ ```typescript
645
+ if (bzbsService.lineApi) {
646
+ const lineAuth = await bzbsService.lineApi.lineAuth({
647
+ grantType: 'authorization_code',
648
+ code: 'auth-code-from-line',
649
+ clientId: 'line-channel-id',
650
+ clientSecret: 'line-channel-secret',
651
+ redirectUrl: 'https://myapp.com/callback',
80
652
  });
653
+ }
654
+ ```
655
+
656
+ ---
657
+
658
+ ### PlaceApi
659
+
660
+ Accessed via `bzbsService.placeApi`.
661
+
662
+ | Method | Description | Returns |
663
+ |---|---|---|
664
+ | `placeList(params)` | List places with location search | `Place[]` |
665
+ | `place(params)` | Get place details | `Place` |
666
+ | `addToFavourite(params)` | Add place to favorites | `unknown` |
667
+ | `removeFromFavourite(params)` | Remove place from favorites | `unknown` |
668
+
669
+ ```typescript
670
+ const places = await bzbsService.placeApi.placeList({
671
+ agencyId: '123',
672
+ center: '13.7563,100.5018', // lat,lng
673
+ distance: 5000,
674
+ top: 20,
675
+ keyword: 'cafe',
676
+ });
677
+ ```
678
+
679
+ ---
680
+
681
+ ### PointLogApi
682
+
683
+ Accessed via `bzbsService.pointLogApi`.
684
+
685
+ | Method | Description | Returns |
686
+ |---|---|---|
687
+ | `getPointLog(params)` | Get point transaction log | `PointLog[]` |
688
+
689
+ ```typescript
690
+ const logs = await bzbsService.pointLogApi.getPointLog({
691
+ month: '2025-01',
692
+ type: 'earn', // 'earn' | 'burn' | etc.
693
+ top: 50,
694
+ });
695
+ ```
696
+
697
+ ---
698
+
699
+ ### StampApi
700
+
701
+ Accessed via `bzbsService.stampApi`.
702
+
703
+ | Method | Description | Returns |
704
+ |---|---|---|
705
+ | `createStamp(params)` | Create a new stamp | `CreateStampResponse` |
706
+ | `stamps(options)` | List all stamps | `Stamp[]` |
707
+ | `stampProfile(params)` | Get stamp card profile/details | `StampProfileResponse` |
708
+
709
+ ```typescript
710
+ const stamps = await bzbsService.stampApi.stamps({});
711
+
712
+ const profile = await bzbsService.stampApi.stampProfile({
713
+ id: 'stamp-123',
714
+ cardId: 'card-456',
715
+ });
716
+ ```
717
+
718
+ ---
719
+
720
+ ### RequestHelpApi (Forum)
721
+
722
+ Accessed via `bzbsService.forumApi`.
723
+
724
+ | Method | Description | Returns |
725
+ |---|---|---|
726
+ | `helpCode(params)` | Get help request code | `RequestHelpCode` |
727
+ | `requestHelpList(params)` | List help request messages | `ChatMessage[]` |
728
+ | `requestDetail(params)` | Get help request detail | `ChatMessage` |
729
+ | `postRequestHelp(params)` | Post a help request (supports image) | `ChatMessage` |
730
+ | `comments(params)` | Get comments on a post | `ChatMessage[]` |
731
+ | `postComment(params)` | Post a comment (supports image) | `ChatMessage` |
732
+ | `like(params)` | Like a post | `LikeForumResponse` |
733
+ | `unlike(params)` | Unlike a post | `LikeForumResponse` |
734
+
735
+ ```typescript
736
+ // Create a help request
737
+ const helpCode = await bzbsService.forumApi.helpCode({
738
+ os: 'ios 17.0',
739
+ platform: 'iPhone',
740
+ clientVersion: 'ios_myapp1.0.0',
741
+ });
742
+
743
+ // Post a message
744
+ await bzbsService.forumApi.postRequestHelp({
745
+ requestId: 'req-123',
746
+ message: 'I need help with my order',
747
+ image: imageFile, // optional File
748
+ });
749
+ ```
750
+
751
+ ---
752
+
753
+ ### SettingApi
754
+
755
+ Accessed via `bzbsService.settingApi`.
756
+
757
+ | Method | Description | Returns |
758
+ |---|---|---|
759
+ | `accessKey(params)` | Get access key for web landing pages | `AccessTokenResponse` |
760
+
761
+ ```typescript
762
+ const accessKey = await bzbsService.settingApi.accessKey({
763
+ data: JSON.stringify({
764
+ app_id: 'your-app-id',
765
+ campaign_id: 12345,
766
+ locale: 1054,
767
+ return_url: 'myapp://callback',
768
+ version: '2',
769
+ }),
770
+ });
771
+ ```
772
+
773
+ ---
774
+
775
+ ### Blob
776
+
777
+ Accessed via `bzbsService.blob`.
778
+
779
+ | Method | Description | Returns |
780
+ |---|---|---|
781
+ | `consentVersion(appId)` | Get PDPA consent version | `ConsentVersion` |
782
+ | `maintenance(appId)` | Get maintenance configuration | `Maintenance` |
783
+ | `blob(path)` | Fetch any blob storage path | `unknown` |
784
+
785
+ ```typescript
786
+ const consentVersion = await bzbsService.blob.consentVersion('your-app-id');
787
+ const maintenance = await bzbsService.blob.maintenance('your-app-id');
788
+ ```
789
+
790
+ ---
791
+
792
+ ## Response Handling
793
+
794
+ All API methods return `ServiceResponse<T>`, a discriminated union type:
795
+
796
+ ```typescript
797
+ type ServiceResponse<T> = SuccessResponse<T> | ErrorResponse;
798
+ ```
799
+
800
+ ### Success Response
801
+
802
+ ```typescript
803
+ type SuccessResponse<T> = {
804
+ type: 'success';
805
+ model: T; // The typed response data
806
+ response: AxiosResponse; // Raw Axios response
807
+ };
808
+ ```
809
+
810
+ ### Error Response
811
+
812
+ ```typescript
813
+ type ErrorResponse = ClientError | ServerError;
814
+
815
+ type ServerError = {
816
+ type: 'server-error';
817
+ error: BzbsErrorResponse; // { requestId, error: { id, message, code, type } }
818
+ statusCode: number;
819
+ response: AxiosResponse;
81
820
  };
821
+
822
+ type ClientError = {
823
+ type: 'client-error';
824
+ message: string;
825
+ details?: any;
826
+ };
827
+ ```
828
+
829
+ ### Usage Pattern
830
+
831
+ ```typescript
832
+ const result = await bzbsService.campaignApi.campaigns({
833
+ config: 'campaign_list',
834
+ });
835
+
836
+ switch (result.type) {
837
+ case 'success':
838
+ // result.model is Campaign[]
839
+ console.log(result.model);
840
+ break;
841
+
842
+ case 'server-error':
843
+ // Server returned an error
844
+ console.error(result.error.error?.message);
845
+ console.error('Status:', result.statusCode);
846
+ break;
847
+
848
+ case 'client-error':
849
+ // Network error or client-side issue
850
+ console.error(result.message);
851
+ break;
852
+ }
82
853
  ```
854
+
855
+ ### Response Normalization
856
+
857
+ The library automatically handles both uppercase and lowercase API response formats:
858
+ - `{ Success: true, Data: ... }` and `{ success: true, data: ... }` are both supported
859
+ - HTTP 204 responses return an empty object as the model
860
+ - Non-standard responses (without success flags) are treated as raw data
861
+
862
+ ---
863
+
864
+ ## Error Handling
865
+
866
+ ### BzbsErrorResponse
867
+
868
+ ```typescript
869
+ interface BzbsErrorResponse {
870
+ requestId?: string;
871
+ error?: {
872
+ id?: number;
873
+ message?: string;
874
+ code?: number;
875
+ type?: string;
876
+ };
877
+ }
878
+ ```
879
+
880
+ ### Common Error Codes
881
+
882
+ | Code | Description |
883
+ |---|---|
884
+ | `401` | Unauthorized / Duplicate username |
885
+ | `2078` | Duplicate contact number |
886
+ | `2089` | Duplicate email |
887
+
888
+ ---
889
+
890
+ ## Models
891
+
892
+ All TypeScript interfaces are exported from `@bzbs/react-api-client` and can be imported directly:
893
+
894
+ ```typescript
895
+ import {
896
+ Campaign,
897
+ CampaignDetail,
898
+ ProfileResponse,
899
+ LoginResponse,
900
+ Purchase,
901
+ // ... etc
902
+ } from '@bzbs/react-api-client';
903
+ ```
904
+
905
+ ### Key Models
906
+
907
+ | Model | Description |
908
+ |---|---|
909
+ | `LoginResponse` | Token, userId, jwt, consent status, points |
910
+ | `Campaign` | Campaign list item (ID, name, points, dates, images) |
911
+ | `CampaignDetail` | Full campaign details with pictures, subcampaigns, conditions |
912
+ | `ProfileResponse` | User profile with personal info, address, shipping, marketing preferences |
913
+ | `Purchase` | Redeem history item with usage status, voucher info, delivery status |
914
+ | `Address` | User address with full Thailand address structure, tax fields |
915
+ | `Notification` | Push notification with object type, category, read status |
916
+ | `Place` | Store/place with location, services, working hours |
917
+ | `Dashboard` | Dashboard configuration item with images and metadata |
918
+ | `Consent` | User consent status for terms, privacy, marketing channels, cookies |
919
+ | `ConsentVersion` | PDPA consent version from blob storage |
920
+ | `Maintenance` | App maintenance configuration |
921
+ | `Badge` | User badge information |
922
+ | `Category` | Campaign category |
923
+ | `PointLog` | Point transaction record |
924
+ | `Stamp` | Stamp card information |
925
+ | `StampProfileResponse` | Stamp card profile details |
926
+ | `OtpResponse` | OTP request response with reference code |
927
+ | `ConfirmOtpResponse` | OTP confirmation result |
928
+ | `ValidateOtpResponse` | OTP validation result |
929
+ | `RedeemResponse` | Campaign redemption result |
930
+ | `FavoriteResponse` | Favorite toggle response |
931
+ | `UseCampaignResponse` | Coupon usage result |
932
+ | `CartCountResponse` | Cart item count |
933
+ | `CartAccessResponse` | Cart web landing access token |
934
+ | `AccessTokenResponse` | Web landing access token |
935
+ | `LineAuthResponse` | LINE OAuth token response |
936
+ | `AppleToken` | Apple refresh token response |
937
+ | `ResumeResponse` | Session resume/token refresh response |
938
+ | `Version` | App version info |
939
+ | `RegistrationResponse` | Registration result |
940
+ | `ForgetPasswordResponse` | Password reset request result |
941
+ | `StatusResponse` | Generic status response |
942
+ | `RequestHelpCode` | Help request code |
943
+ | `ChatMessage` | Forum/help chat message |
944
+ | `LikeForumResponse` | Forum like/unlike result |
945
+ | `Province` | Thailand province |
946
+ | `District` | Thailand district |
947
+ | `SubDistrict` | Thailand sub-district |
948
+ | `ZipCode` | Zip code information |
949
+ | `UpdatedPoints` | User points with timestamp |
950
+ | `ExpiringPoints` | User expiring points info |
951
+ | `PointUnit` | Point service unit configuration |
952
+
953
+ ---
954
+
955
+ ## Development
956
+
957
+ ### Prerequisites
958
+
959
+ - Node.js
960
+ - npm
961
+
962
+ ### Commands
963
+
964
+ ```bash
965
+ # Install dependencies
966
+ npm install
967
+
968
+ # Build the library (CJS + ESM + type declarations)
969
+ npm run build
970
+
971
+ # Run tests in watch mode with coverage
972
+ npm test
973
+
974
+ # Lint source files
975
+ npm run lint
976
+
977
+ # Auto-fix lint issues
978
+ npm run lint:fix
979
+
980
+ # Format code with Prettier
981
+ npm run format
982
+ ```
983
+
984
+ ### Publishing
985
+
986
+ ```bash
987
+ npm run patch # Build, bump patch version, publish
988
+ npm run minor # Build, bump minor version, publish
989
+ npm run major # Build, bump major version, publish
990
+ ```
991
+
992
+ ### Adding a New API
993
+
994
+ 1. Create a new directory under `src/api/` (e.g., `src/api/my-feature/`)
995
+ 2. Create an API class that extends `BaseService`:
996
+
997
+ ```typescript
998
+ import { AxiosInstance } from 'axios';
999
+ import { BaseService, RequestOptions, ServiceResponse } from '../base-service';
1000
+ import { MyModel } from '../../models/my-model';
1001
+
1002
+ export class MyFeatureApi extends BaseService {
1003
+ constructor(client: AxiosInstance, baseUrl: string) {
1004
+ super(client, baseUrl);
1005
+ }
1006
+
1007
+ public async getItems(
1008
+ params: { id: string; options?: { [key: string]: unknown } },
1009
+ requestOptions?: RequestOptions
1010
+ ): Promise<ServiceResponse<MyModel[]>> {
1011
+ return await this.get<MyModel[]>(
1012
+ `my-feature/${params.id}`,
1013
+ { ...params.options },
1014
+ requestOptions
1015
+ );
1016
+ }
1017
+ }
1018
+ ```
1019
+
1020
+ 3. Create model interfaces in `src/models/`
1021
+ 4. Export from `src/models/index.ts` and `src/api/index.ts`
1022
+ 5. Add the API to `BzbsService` class and its `setBaseUrl()` method
1023
+
1024
+ ---
1025
+
1026
+ ## Build Output
1027
+
1028
+ The build process (tsup) generates:
1029
+
1030
+ | File | Format | Description |
1031
+ |---|---|---|
1032
+ | `dist/index.js` | CommonJS | For `require()` usage |
1033
+ | `dist/index.mjs` | ES Module | For `import` usage |
1034
+ | `dist/index.d.ts` | TypeScript | Type declarations |
1035
+ | `dist/*.map` | Source Maps | For debugging |