@bzbs/react-providers
v3.0.0
Published
A collection of React Context Provider for Buzzebees apps
Downloads
520
Readme
@bzbs/react-providers
Version: 2.7.8 | License: ISC | Author: Buzzebees Co., Ltd. Repository: Azure DevOps
A collection of React state management providers and Zustand stores for Buzzebees loyalty/reward apps. This package is the implementation layer on top of @bzbs/react-api-client, wrapping API calls with React-friendly state, actions, and side-effects (analytics, token management, event broadcasting).
⚠️ Important: The Context API layer (
/providers,./contextexport) is deprecated. All new development must use the Zustand stores (@bzbs/react-providers/zustand). The Context API docs are retained for migration reference only.
Table of Contents
- Installation
- Architecture Overview
- Quick Start (Zustand)
- Package Exports
- Zustand Stores Reference
- useBuzzebeesAppStore
- useAuthStore
- useUserStore
- useCartStore
- useLocaleStore
- useAnalyticsStore
- useAlertStore
- useConfirmStore
- usePopupStore
- useLoadingIndicatorStore
- useNotificationStore
- useMaintenanceStore
- useConsentStore
- useRegistrationStore
- useAddressStore
- useZipCodeStore
- createCampaignsStore
- createCampaignDetailStore
- createCategoriesStore
- createDashboardStore
- createPointLogStore
- createPurchaseStore
- useCouponStore
- createFavoriteCampaignsStore
- TokenFunctions Interface
- Service Utilities
- Analytics Utilities
- Locale Utilities
- Constants
- Types Reference
- Deprecated: Context API
- Relationship to @bzbs/react-api-client
- Development Commands
Installation
npm install @bzbs/react-providersPeer dependencies:
npm install react react-dom axiosAlso required (provides BzbsService):
npm install @bzbs/react-api-clientArchitecture Overview
@bzbs/react-providers
├── Zustand Stores ← Recommended: import from '@bzbs/react-providers/zustand'
├── Context Providers ← DEPRECATED: import from '@bzbs/react-providers/context'
├── Service Utilities ← HTTP interceptors, URL helpers, event emitter
├── Analytics Utils ← Matomo tracking wrappers
├── Locale Utils ← Locale → LCID mapping
└── Constants ← Campaign types, point typesDependencies flow:
@bzbs/react-api-client (BzbsService)
↓
useBuzzebeesAppStore ← Central config store
↓
useAuthStore, useUserStore, useCartStore, ... ← Feature storesAll feature stores read bzbsService from useBuzzebeesAppStore to make API calls. You must call useBuzzebeesAppStore.getState().configure(...) (or use individual setters) before using any other store.
Quick Start (Zustand)
import axios from 'axios';
import { BzbsService } from '@bzbs/react-api-client';
import {
useBuzzebeesAppStore,
addDefaultHeaderInterceptor,
useAuthStore,
} from '@bzbs/react-providers/zustand';
// 1. Create an Axios instance
const axiosClient = axios.create({
headers: {
'Content-Type': 'application/json',
'App-Id': 'YOUR_APP_ID',
'Ocp-Apim-Subscription-Key': 'YOUR_SUBSCRIPTION_KEY',
},
});
// 2. Create the BzbsService instance
const bzbsService = new BzbsService(axiosClient, 'https://api.buzzebees.com');
// 3. Define token persistence functions
const tokenFunctions = {
getToken: async () => localStorage.getItem('bzbs_token'),
setToken: (token: string) => localStorage.setItem('bzbs_token', token),
removeToken: () => localStorage.removeItem('bzbs_token'),
};
// 4. Attach auth/header interceptors
addDefaultHeaderInterceptor(
axiosClient,
'YOUR_APP_ID',
'YOUR_SUBSCRIPTION_KEY',
tokenFunctions,
'1.0'
);
// 5. Configure the central app store (call this once at app startup)
useBuzzebeesAppStore.getState().configure({
appId: 'YOUR_APP_ID',
appName: 'your-app',
bzbsService,
tokenFunctions,
tokenType: 'jwt',
urls: {
webCallback: 'https://yourapp.com/callback',
cart: 'https://cart.buzzebees.com',
},
config: {
defaultDashboardConfig: 'main',
defaultDashboardMode: 'main',
defaultMenuConfig: 'default',
defaultCampaignConfig: 'default',
},
});
// 6. Use stores in components
function LoginScreen() {
const { isLoading, isLoggedIn, actions } = useAuthStore();
const handleLogin = async () => {
const result = await actions.loginWithUsernamePassword('[email protected]', 'password');
if (result.type === 'success') {
console.log('Logged in!');
}
};
return <button onClick={handleLogin} disabled={isLoading}>Login</button>;
}Package Exports
| Import Path | Contents |
|---|---|
| @bzbs/react-providers | Everything: all providers, stores, utils, constants, services |
| @bzbs/react-providers/zustand | Zustand stores + utils + constants + services (recommended) |
| @bzbs/react-providers/context | Context providers + utils + constants + services (deprecated) |
Zustand Stores Reference
All stores are available from @bzbs/react-providers/zustand.
useBuzzebeesAppStore
Central configuration store. Must be configured before any other store is used.
import { useBuzzebeesAppStore } from '@bzbs/react-providers/zustand';State:
type BuzzebeesAppState = {
appId: string;
appName: string;
bzbsService: BzbsService | null;
uuid: string;
macAddress: string;
clientVersion: string;
os: string;
platform: string;
fcmToken: string;
deviceNotificationEnabled: boolean;
urls: { webCallback: string; cart: string };
tokenFunctions: TokenFunctions | null;
tokenType: AuthTokenType; // 'jwt' | 'auth_token'
config: {
defaultDashboardConfig: string;
defaultDashboardMode: 'main' | 'sub';
defaultMenuConfig: string;
defaultCampaignConfig: string;
};
};Actions:
type BuzzebeesAppActions = {
// Bulk configure — call this once at app startup
configure(config: {
appId: string;
appName: string;
bzbsService: BzbsService;
tokenFunctions: TokenFunctions;
tokenType?: AuthTokenType;
uuid?: string;
macAddress?: string;
clientVersion?: string;
os?: string;
platform?: string;
fcmToken?: string;
deviceNotificationEnabled?: boolean;
urls: { webCallback: string; cart: string };
config?: {
defaultDashboardConfig?: string;
defaultDashboardMode?: 'main' | 'sub';
defaultMenuConfig?: string;
defaultCampaignConfig?: string;
};
}): void;
// Individual setters
setAppId(appId: string): void;
setAppName(appName: string): void;
setBzbsService(service: BzbsService): void;
setUuid(uuid: string): void;
setMacAddress(macAddress: string): void;
setClientVersion(clientVersion: string): void;
setOs(os: string): void;
setPlatform(platform: string): void;
setFcmToken(fcmToken: string): void;
setDeviceNotificationEnabled(enabled: boolean): void;
setUrls(urls: { webCallback: string; cart: string }): void;
setTokenType(tokenType: AuthTokenType): void;
setTokenFunctions(tokenFunctions: TokenFunctions): void;
};Usage:
// Access state in a component
const { appId, bzbsService } = useBuzzebeesAppStore();
// Access state outside React (e.g., service files)
const state = useBuzzebeesAppStore.getState();useAuthStore
Manages the full authentication lifecycle: login, logout, OTP, token validation.
import { useAuthStore } from '@bzbs/react-providers/zustand';State:
type AuthState = {
isInitialized: boolean;
versionData: Version | null;
rawVersionData: unknown | null;
data: LoginResponse | ResumeResponse | null;
isLoading: boolean;
isLoadingToken: boolean;
error: ErrorResponse | null;
token: string | null;
isLoggedIn: boolean;
};Actions:
type AuthActions = {
// State setters
setIsLoading(value: boolean): void;
setIsLoadingToken(value: boolean): void;
setError(value: unknown): void;
// Check persisted token and restore session
checkLoggedIn(): Promise<void>;
// Login methods — all return ServiceResponse<LoginResponse>
loginWithUsernamePassword(username: string, password: string): Promise<ServiceResponse<LoginResponse>>;
loginWithGoogle(token: string): Promise<ServiceResponse<LoginResponse>>;
loginWithFacebook(token: string): Promise<ServiceResponse<LoginResponse>>;
loginWithApple(token: string, refreshToken: string): Promise<ServiceResponse<LoginResponse>>;
loginWithUUID(): Promise<ServiceResponse<LoginResponse>>;
loginWithOtp(otp: string, refCode: string, contact: string): Promise<ServiceResponse<LoginResponse>>;
// Password management
forgetPassword(contact: string, type: 'email' | 'contact_number'): Promise<ServiceResponse<ForgetPasswordResponse>>;
resetPassword(contact: string, otp: string, refCode: string, password: string): Promise<ServiceResponse<StatusResponse>>;
// OTP
sendOtp(contact: string, channel: string): Promise<ServiceResponse<OtpResponse>>;
validateOtp(otp: string, refCode: string, contact: string, channel: string, type: 'email' | 'contact_number'): Promise<ServiceResponse<ValidateOtpResponse>>;
confirmOtp(otp: string, refCode: string, contact: string): Promise<ServiceResponse<ConfirmOtpResponse>>;
// Apple Sign-In
appleToken(authorizationCode: string, idToken: string): Promise<ServiceResponse<AppleToken>>;
// Session management
logout(): Promise<ServiceResponse<unknown>>;
resume(clientVersion: string): Promise<ServiceResponse<ResumeResponse>>;
version(clientVersion: string): Promise<ServiceResponse<Version>>;
clear(): void;
};Example:
const { isLoggedIn, isLoading, token, actions } = useAuthStore();
// Login
const res = await actions.loginWithUsernamePassword('[email protected]', 'secret');
if (res.type === 'success') { /* navigate to home */ }
// Check token on app start
useEffect(() => {
actions.checkLoggedIn();
}, []);
// Logout
await actions.logout();Note: After a successful login,
useAuthStoreautomatically callsuseUserStore.getState().fetchUser()and fires analytics events.
useUserStore
Manages the authenticated user's profile, points, badges, cart count, and traces.
import { useUserStore } from '@bzbs/react-providers/zustand';State:
type UserState = {
user: ProfileResponse | null;
points: number;
recentPoints: UpdatedPoints | null;
expiringPoints: UpdatedPoints[];
recentBadge: unknown | null;
recentTrace: unknown | null;
cartCount: number;
isLoading: boolean;
error: ErrorResponse | null;
badgeList: unknown[];
traceList: unknown[];
};Actions:
type UserActions = {
fetchUser(): Promise<ServiceResponse<ProfileResponse>>;
fetchPoint(): Promise<void>;
fetchExpiringPoints(): Promise<void>;
fetchCartCount(): Promise<void>;
editUser(params: UpdateProfileParams): Promise<ServiceResponse<ProfileResponse>>;
changePassword(oldPassword: string, newPassword: string): Promise<ServiceResponse<unknown>>;
changeContactNumber(contactNumber: string, otp: string, refCode: string): Promise<ServiceResponse<unknown>>;
changeAvatar(file: File | Blob): Promise<ServiceResponse<unknown>>;
deleteUser(): Promise<ServiceResponse<unknown>>;
consumeRecentPoints(): void;
consumeRecentBadge(): void;
consumeRecentTrace(): void;
setupEventListeners(): void;
cleanupEventListeners(): void;
setError(value: unknown): void;
clear(): void;
};
type UpdateProfileParams = {
firstName?: string;
lastName?: string;
email?: string;
birthDate?: string;
gender?: string;
// ... additional profile fields from @bzbs/react-api-client
};useCartStore
Fetches and tracks the number of items in the user's cart.
import { useCartStore } from '@bzbs/react-providers/zustand';State:
type CartState = {
count: number;
isLoading: boolean;
error: ErrorResponse | null;
};Actions:
type CartActions = {
fetchCount(): Promise<ServiceResponse<CartCountResponse>>;
clear(): void;
};useLocaleStore
Manages the app locale used for API requests.
import { useLocaleStore, EN, TH } from '@bzbs/react-providers/zustand';State:
type LocaleState = {
appLocale: AppLocale;
locale: string; // e.g. 'en', 'th'
localeId: number; // LCID e.g. 1033, 1054
};
type AppLocale = {
locale: string;
localeId: number;
};Constants:
const EN: AppLocale = { locale: 'en', localeId: 1033 };
const TH: AppLocale = { locale: 'th', localeId: 1054 };Actions:
type LocaleActions = {
// Accepts an AppLocale object or a locale string like 'en', 'th-TH', 'en-US'
setAppLocale(locale: AppLocale | string): void;
};Example:
const { locale, localeId } = useLocaleStore();
// Set by locale string (resolves via findBestLocaleFromString)
useLocaleStore.getState().setAppLocale('th');
// Set by full AppLocale object
useLocaleStore.getState().setAppLocale(TH);useAnalyticsStore
Manages Matomo analytics tracking.
import { useAnalyticsStore } from '@bzbs/react-providers/zustand';State:
type AnalyticsState = {
isInitialized: boolean;
isEnabled: boolean;
siteId: number;
urlBase: string;
trackerUrl: string | undefined;
userId: string | undefined;
disabled: boolean;
log: boolean;
matomoInstance: MatomoTracker | null;
presetUserInfo: UserInfo | undefined;
};Actions:
type AnalyticsActions = {
initialize(config: {
siteId: number;
urlBase: string;
trackerUrl?: string;
userId?: string;
disabled?: boolean;
log?: boolean;
}): void;
setEnabled(enabled: boolean): void;
setPresetUserInfo(userInfo: UserInfo): void;
clearPresetUserInfo(): void;
trackAppStart(userInfo?: UserInfo): Promise<void>;
trackEvent(params: {
action: string;
name?: string;
category?: string;
value?: number;
campaign?: string;
userInfo?: UserInfo;
}): Promise<void>;
trackScreenView(params: { name: string; userInfo?: UserInfo }): Promise<void>;
trackAction(params: { name: string; userInfo?: UserInfo }): Promise<void>;
trackSiteSearch(params: {
keyword: string;
category?: string;
count?: number;
userInfo?: UserInfo;
}): Promise<void>;
trackLink(params: { link: string; userInfo?: UserInfo }): Promise<void>;
trackDownload(params: { download: string; userInfo?: UserInfo }): Promise<void>;
setUserId(userId: string | null): void;
setCustomDimension(id: number, value: string): void;
reset(): void;
};useAlertStore
Manages alert/dialog display state.
import { useAlertStore } from '@bzbs/react-providers/zustand';State:
type AlertState = {
isOpen: boolean;
request: AlertRequest | null;
};
type AlertRequest = {
title?: string;
message: string;
confirmLabel?: string;
onConfirm?: () => void;
};Actions:
type AlertActions = {
show(request: AlertRequest): void;
hide(): void;
};useConfirmStore
Manages confirmation dialog state.
import { useConfirmStore } from '@bzbs/react-providers/zustand';State:
type ConfirmState = {
isOpen: boolean;
request: ConfirmRequest | null;
};
type ConfirmRequest = {
title?: string;
message: string;
confirmLabel?: string;
cancelLabel?: string;
onConfirm?: () => void;
onCancel?: () => void;
};Actions:
type ConfirmActions = {
show(request: ConfirmRequest): void;
hide(): void;
};usePopupStore
Manages popup/modal display state.
import { usePopupStore } from '@bzbs/react-providers/zustand';State:
type PopupState = {
isOpen: boolean;
request: PopupRequest | null;
};
type PopupRequest = {
content: React.ReactNode;
onClose?: () => void;
};Actions:
type PopupActions = {
show(request: PopupRequest): void;
hide(): void;
};useLoadingIndicatorStore
Manages a global loading indicator with named loading keys.
import { useLoadingIndicatorStore, useLoading } from '@bzbs/react-providers/zustand';State:
type LoadingIndicatorState = {
loadingKeys: string[];
isLoading: boolean;
};Actions:
type LoadingIndicatorActions = {
show(key?: string): void;
hide(key?: string): void;
clear(): void;
};useLoading hook: A convenience hook for reading the current loading state.
useNotificationStore
Manages user notification list and unread count.
import { useNotificationStore } from '@bzbs/react-providers/zustand';Wraps notificationApi from @bzbs/react-api-client. Actions include fetching notifications, marking as read, and clearing state.
useMaintenanceStore
Manages app maintenance mode state.
import { useMaintenanceStore } from '@bzbs/react-providers/zustand';Fetches maintenance configuration from the API and exposes isMaintenance: boolean and maintenanceData.
useConsentStore
Manages user consent preferences (marketing, data sharing, etc.).
import { useConsentStore } from '@bzbs/react-providers/zustand';Wraps consentApi from @bzbs/react-api-client. Exposes consent state and update actions.
useRegistrationStore
Manages user registration flow state.
import { useRegistrationStore } from '@bzbs/react-providers/zustand';Wraps registrationApi. Handles multi-step registration: form data, OTP verification, and account creation.
useAddressStore
Manages user address book.
import { useAddressStore } from '@bzbs/react-providers/zustand';Wraps addressApi. CRUD operations for user addresses.
useZipCodeStore
Fetches postal/zip code data for address forms.
import { useZipCodeStore } from '@bzbs/react-providers/zustand';createCampaignsStore
Factory that creates a scoped campaigns list store. Use when you need multiple independent campaign list instances.
import { createCampaignsStore } from '@bzbs/react-providers/zustand';
const useMyCampaignsStore = createCampaignsStore();Wraps campaignApi.getCampaigns(). Supports pagination, filtering, and config-based loading.
createCampaignDetailStore
Factory that creates a scoped campaign detail store.
import { createCampaignDetailStore } from '@bzbs/react-providers/zustand';
const useCampaignDetailStore = createCampaignDetailStore();Wraps campaignApi.getCampaignDetail().
createCategoriesStore
Factory that creates a scoped categories/menu store.
import { createCategoriesStore } from '@bzbs/react-providers/zustand';
const useCategoriesStore = createCategoriesStore();createDashboardStore
Factory that creates a scoped dashboard configuration store.
import { createDashboardStore } from '@bzbs/react-providers/zustand';
const useDashboardStore = createDashboardStore();createPointLogStore
Factory that creates a scoped point history store.
import { createPointLogStore } from '@bzbs/react-providers/zustand';
const usePointLogStore = createPointLogStore();Wraps pointLogApi. Supports pagination.
createPurchaseStore
Factory that creates a scoped purchase history store.
import { createPurchaseStore } from '@bzbs/react-providers/zustand';
const usePurchaseStore = createPurchaseStore();useCouponStore
Manages user coupon list and coupon operations.
import { useCouponStore } from '@bzbs/react-providers/zustand';createFavoriteCampaignsStore
Factory that creates a scoped favorites store.
import { createFavoriteCampaignsStore } from '@bzbs/react-providers/zustand';
const useFavoriteCampaignsStore = createFavoriteCampaignsStore();TokenFunctions Interface
A required interface for token persistence. You provide your own implementation based on your storage mechanism.
type TokenFunctions = {
getToken: () => Promise<string | null>;
setToken: (token: string) => void;
removeToken: () => void;
};Example implementations:
// Web (localStorage)
const tokenFunctions: TokenFunctions = {
getToken: async () => localStorage.getItem('auth_token'),
setToken: (token) => localStorage.setItem('auth_token', token),
removeToken: () => localStorage.removeItem('auth_token'),
};
// React Native (AsyncStorage)
import AsyncStorage from '@react-native-async-storage/async-storage';
const tokenFunctions: TokenFunctions = {
getToken: () => AsyncStorage.getItem('auth_token'),
setToken: (token) => AsyncStorage.setItem('auth_token', token),
removeToken: () => AsyncStorage.removeItem('auth_token'),
};
// In-memory (testing / SSR)
let _token: string | null = null;
const tokenFunctions: TokenFunctions = {
getToken: async () => _token,
setToken: (token) => { _token = token; },
removeToken: () => { _token = null; },
};Service Utilities
Exported from @bzbs/react-providers/zustand (and the default export).
addDefaultHeaderInterceptor
Attaches request and response interceptors to an Axios instance. Call this once after creating your Axios instance and before passing it to BzbsService.
import { addDefaultHeaderInterceptor } from '@bzbs/react-providers/zustand';
addDefaultHeaderInterceptor(
axiosInstance: AxiosInstance,
appId: string,
subscriptionKey: string,
tokenFunctions: TokenFunctions,
apiVersion: string,
corelationIdGenerator?: () => string // optional, defaults to uuidv7()
): voidWhat it does:
| Direction | Action |
|---|---|
| Request | Adds App-Id, Ocp-Apim-Subscription-Key, api-version, X-Corelation-Id headers |
| Request | Adds Authorization: Bearer <token> (JWT) or Authorization: token <token> |
| Response | Normalises both new-style ({ Success, Data }) and old-style ({ error, ... }) responses |
| Response | Emits get_points event if response contains buzzebees.points |
| Response | Emits get_badges event if response contains buzzebees.badges |
| Response | Emits session_expired event on error code 1905 or 2076 |
addBlake2OtpSignatureInterceptor
Adds BLAKE2b OTP signature headers to requests matching specified URL paths.
import { addBlake2OtpSignatureInterceptor } from '@bzbs/react-providers/zustand';
addBlake2OtpSignatureInterceptor(
axiosInstance: AxiosInstance,
paths: string[], // URL path substrings to match (e.g. ['/otp/send'])
encoder: TextEncoder,
getCurrentDateTime?: () => Date // optional, defaults to () => new Date()
): voidWhen a matching request includes app_id, contact_number, and channel params, the interceptor adds:
OTP-Signature: BLAKE2b hex ofappId|contactNumber|channel|datetimeTimestamp: Unix timestamp (seconds)
Utility Functions
import {
avatarUrl,
largeImage,
fetchImage,
interfaceWebsite,
createInterfaceToken,
createCartUrl,
generateBlake2bSignatureHex,
generateShortLivedId,
getOtpSignatureHeaders,
} from '@bzbs/react-providers/zustand';| Function | Signature | Description |
|---|---|---|
| avatarUrl | (baseUrl, appId, userId, token) => string | Builds a profile picture URL with cache-busting timestamp |
| largeImage | (url) => string | Transforms a standard image URL to its large variant |
| fetchImage | (axiosClient, imageUrl) => Promise<Blob \| undefined> | Downloads an image as a Blob |
| interfaceWebsite | (url, token?, returnUrl?, params?) => string | Builds an interface website URL with obfuscated token |
| createInterfaceToken | (token) => string | Obfuscates a token by rearranging first/last characters |
| createCartUrl | (cartUrl, appName, accessKey, params?) => string | Builds a cart landing URL with access key |
| generateBlake2bSignatureHex | (data, key, encoder) => string | Generates a BLAKE2b hex signature |
| generateShortLivedId | () => string | Generates a random short-lived ID string |
| getOtpSignatureHeaders | ({ appId, contactNumber, channel, encoder, now? }) => object | Returns { 'OTP-Signature': string, Timestamp: number } |
eventEmitter
A global Emittery instance for cross-component communication. The addDefaultHeaderInterceptor automatically fires events on it.
import { eventEmitter } from '@bzbs/react-providers/zustand';
// Listen for points update (response contains buzzebees.points)
eventEmitter.on('get_points', (data) => {
console.log('New points:', data.points);
});
// Listen for badges update
eventEmitter.on('get_badges', (badges) => {
console.log('New badges:', badges);
});
// Listen for session expiry (error code 1905 or 2076)
eventEmitter.on('session_expired', (error) => {
// Redirect to login, clear token, etc.
useAuthStore.getState().clear();
});
useUserStoreinternally callssetupEventListeners()to subscribe toget_pointsandget_badgesand update its state. CallcleanupEventListeners()on unmount.
Analytics Utilities
import {
analytics,
trackCommonEvents,
useAnalytics,
usePageTracking,
useAnalyticsState,
initializeAnalytics,
withPageTracking,
} from '@bzbs/react-providers/zustand';trackCommonEvents
Pre-built Matomo event calls for common Buzzebees actions. All functions are async and no-op if analytics is not initialized.
await trackCommonEvents.loginSuccess(userInfo?)
await trackCommonEvents.registerSuccess(userInfo?)
await trackCommonEvents.viewCampaign(userInfo?)
await trackCommonEvents.redeemSuccess(campaignId: string, userInfo?)
await trackCommonEvents.unconsentSuccess(userInfo?)
await trackCommonEvents.buttonClick(buttonName: string, category?: string, userInfo?)
await trackCommonEvents.formSubmit(formName: string, success?: boolean, userInfo?)
await trackCommonEvents.search(keyword: string, resultCount?: number, category?: string, userInfo?)
await trackCommonEvents.purchase(amount: number, currency?: string, productName?: string, userInfo?)
await trackCommonEvents.userRegistration(method?: string, userInfo?)
await trackCommonEvents.userLogin(method?: string, userInfo?)
await trackCommonEvents.error(errorType: string, errorMessage?: string, userInfo?)
await trackCommonEvents.custom(name: string, category: string, label?: string, value?: number, userInfo?)analytics (global object)
For use outside React components (service files, event handlers, etc.).
analytics.init({ siteId: 1, urlBase: 'https://matomo.example.com' })
analytics.trackEvent({ action, name?, category?, value?, campaign?, userInfo? })
analytics.trackScreenView(name: string, userInfo?)
analytics.trackAppStart(userInfo?)
analytics.trackSiteSearch(keyword: string, category?, count?, userInfo?)
analytics.trackLink(link: string, userInfo?)
analytics.trackDownload(download: string, userInfo?)
analytics.setUserId(userId: string | null)
analytics.setCustomDimension(id: number, value: string)
analytics.setPresetUserInfo(userInfo: UserInfo)
analytics.clearPresetUserInfo()
analytics.setEnabled(enabled: boolean)
analytics.reset()useAnalytics Hook
React hook that returns analytics functions from the current context.
const {
isInitialized,
isEnabled,
trackEvent,
trackScreenView,
trackAction,
trackAppStart,
trackSiteSearch,
trackLink,
trackDownload,
setUserId,
setCustomDimension,
setEnabled,
setPresetUserInfo,
clearPresetUserInfo,
} = useAnalytics();usePageTracking hook — automatically tracks screen view on mount:
usePageTracking(
pageName?: string,
dependencies?: unknown[],
customUserInfo?: UserInfo
): voidwithPageTracking HOC:
const TrackedComponent = withPageTracking(MyComponent, 'Home Screen');Locale Utilities
import { findBestLocaleFromString, localeToLCIDMap } from '@bzbs/react-providers/zustand';findBestLocaleFromString(value: string): { locale: string; localeId: number }
Resolves a locale string to an AppLocale object with LCID. Supports:
- Exact match:
'th-TH'→{ locale: 'th-TH', localeId: 1054 } - Partial match:
'th'→ finds first key starting with'th' - Throws
Errorif no match found
localeToLCIDMap — Object mapping 200+ locale strings (BCP 47) to Windows LCID numbers.
Common mappings:
| Locale | LCID |
|---|---|
| en-US | 1033 |
| th-TH | 1054 |
| zh-CN | 2052 |
| zh-TW | 1028 |
| ja-JP | 1041 |
| ko-KR | 1042 |
| ms-MY | 1086 |
| id-ID | 1057 |
| vi-VN | 1066 |
Constants
import { campaignType, campaignPointType, campaignInterfaceType } from '@bzbs/react-providers/zustand';campaignType
Maps campaign type names to numeric IDs used by the Buzzebees API.
const campaignType = {
draw: 0,
free: 1,
deal: 2,
buy: 3,
bid: 4,
ads: 5,
install: 6,
booking: 7,
interface: 8,
event: 9,
media: 10,
ewalletTopUp: 11,
ewalletRedeem: 12,
ewalletTransfer: 13,
ewalletBanking: 14,
autofeed: 15,
news: 16,
reservation: 17,
ewalletBuy: 18,
pointRedemption: 19,
donate: 20,
pointFree: 21,
voucher: 22,
encrypt: 23,
encryptRedeem: 24,
giftCard: 25,
verifyCode: 26,
subscription: 27,
fillCode: 28,
subscriptionFood: 29,
buyEVoucher: 30,
uploadReceipt: 31,
payWithPoints: 32,
marketPlacePrivilege: 33,
topup2C2P: 34,
directTopup2C2P: 35,
};Usage:
if (campaign.campaign_type === campaignType.voucher) {
// Handle voucher campaign
}campaignPointType
const campaignPointType = {
use: 'use', // campaign costs points
get: 'get', // campaign rewards points
};campaignInterfaceType
const campaignInterfaceType = {
web: 'web',
survey: 'survey',
surveyApprove: 'surveyapprove',
};Types Reference
import type {
TokenFunctions,
AuthTokenType,
AppLocale,
MatomoConfig,
LoginResponseHandler,
ErrorResponseHandler,
// Store types
BuzzebeesAppState,
BuzzebeesAppActions,
BuzzebeesAppStore,
AuthState,
AuthActions,
AuthStore,
UserState,
UserActions,
UserStore,
CartState,
CartActions,
CartStore,
LocaleState,
LocaleActions,
LocaleStore,
AlertState,
AlertActions,
AlertStore,
AlertRequest,
ConfirmState,
ConfirmActions,
ConfirmStore,
ConfirmRequest,
PopupState,
PopupActions,
PopupStore,
PopupRequest,
LoadingIndicatorState,
LoadingIndicatorActions,
LoadingIndicatorStore,
UpdateProfileParams,
} from '@bzbs/react-providers/zustand';| Type | Description |
|---|---|
| TokenFunctions | Token persistence interface (getToken/setToken/removeToken) |
| AuthTokenType | 'jwt' \| 'auth_token' — token format stored after login |
| AppLocale | { locale: string; localeId: number } |
| MatomoConfig | Matomo tracker configuration (siteId, urlBase, trackerUrl?, userId?, disabled?, log?) |
| LoginResponseHandler | (response: LoginResponse) => void |
| ErrorResponseHandler | (error: ErrorResponse) => void |
| UpdateProfileParams | Parameters for useUserStore().editUser() |
All API response types (LoginResponse, ProfileResponse, ErrorResponse, etc.) are re-exported from @bzbs/react-api-client. See react-api-client.md for the full models reference.
Deprecated: Context API
⚠️ The Context API layer is deprecated. Do not use it in new code. Use Zustand stores instead.
DefaultMainAppProvider
(Deprecated) A composite provider that wraps the entire app with all context providers nested in order.
// DEPRECATED — use useBuzzebeesAppStore.getState().configure() instead
import { DefaultMainAppProvider } from '@bzbs/react-providers/context';Props:
type DefaultMainAppProviderProps = {
appId: string;
appName: string;
bzbsService: BzbsService;
urls: { webCallback: string; cart: string };
tokenFunctions: TokenFunctions;
defaultDashboardConfig: string;
defaultDashboardMode: 'main' | 'sub';
defaultMenuConfig: string;
defaultCampaignConfig: string;
language: string;
matomoConfig?: MatomoConfig;
children: React.ReactNode;
};Provider nesting order (outer → inner):
BuzzebeesServiceProviderAnalyticsProviderAppLocaleProviderLoadingProviderPopupProviderMaintenanceProviderAuthProviderRegisterProviderUserProviderPointLogProviderConsentProviderNotificationProviderAddressProviderZipCodeProviderCartProviderDashboardProviderCategoriesProviderCampaignProvider
Context Providers Table
(Deprecated) All context providers and their Zustand equivalents.
| Provider | Hook | Zustand Equivalent |
|---|---|---|
| BuzzebeesServiceProvider | useBuzzebeesServiceContext() | useBuzzebeesAppStore |
| AuthProvider | useAuthContext() | useAuthStore |
| UserProvider | useUserContext() | useUserStore |
| CartProvider | useCartContext() | useCartStore |
| CampaignsProvider | useCampaignsContext() | createCampaignsStore() |
| CampaignDetailProvider | useCampaignDetailContext() | createCampaignDetailStore() |
| CategoriesProvider | useCategoriesContext() | createCategoriesStore() |
| CouponProvider | useCouponContext() | useCouponStore |
| AlertProvider | useAlertContext() | useAlertStore |
| ConfirmProvider | useConfirmContext() | useConfirmStore |
| PopupProvider | usePopupContext() | usePopupStore |
| LoadingProvider | useLoadingContext() / useLoading() | useLoadingIndicatorStore / useLoading |
| NotificationProvider | useNotificationContext() | useNotificationStore |
| AnalyticsProvider | useAnalyticsContext() | useAnalyticsStore |
| AppLocaleProvider | useAppLocaleContext() | useLocaleStore |
| ConsentProvider | useConsentContext() | useConsentStore |
| MaintenanceProvider | useMaintenanceContext() | useMaintenanceStore |
| RegistrationProvider | useRegistrationContext() | useRegistrationStore |
| AddressProvider | useAddressContext() | useAddressStore |
| ZipCodeProvider | useZipCodeContext() | useZipCodeStore |
| DashboardProvider | useDashboardContext() | createDashboardStore() |
| PointLogProvider | usePointLogContext() | createPointLogStore() |
| PurchaseProvider | usePurchaseContext() | createPurchaseStore() |
Relationship to @bzbs/react-api-client
@bzbs/react-providers is the stateful wrapper around @bzbs/react-api-client. The relationship:
@bzbs/react-api-client @bzbs/react-providers
──────────────────────── ──────────────────────────────
BzbsService → Passed into useBuzzebeesAppStore
authenticateApi → useAuthStore
profileApi → useUserStore
cartApi → useCartStore
campaignApi → createCampaignsStore / createCampaignDetailStore
categoryApi → createCategoriesStore
couponApi → useCouponStore
notificationApi → useNotificationStore
historyApi → createPurchaseStore
registrationApi → useRegistrationStore
addressApi → useAddressStore
badgeApi → useUserStore (badges)
consentApi → useConsentStore
dashboardApi → createDashboardStore
pointLogApi → createPointLogStoreTo create a BzbsService instance, refer to react-api-client.md.
Development Commands
# Build all entry points (dist/)
npm run build
# Run tests with coverage
npm test
# Format source files
npm run format
# Upgrade @bzbs/react-api-client to latest
npm run update:client
# Publish — patch version bump
npm run patch
# Publish — minor version bump
npm run minor
# Publish — major version bump
npm run majorBuild output (three entry points, each with CJS + ESM + types):
| Entry point | CJS | ESM | Types |
|---|---|---|---|
| src/index.ts | dist/index.js | dist/index.mjs | dist/index.d.ts |
| context.ts | dist/context.js | dist/context.mjs | dist/context.d.ts |
| zustand.ts | dist/zustand.js | dist/zustand.mjs | dist/zustand.d.ts |
