UNPKG

@bzbs/react-providers

Version:

A collection of React Context Provider for Buzzebees apps

1 lines 221 kB
{"version":3,"sources":["../src/stores/address.store.ts","../src/stores/buzzebeess-app.store.ts","../src/stores/alert.store.ts","../src/stores/analytics.store.ts","../src/stores/auth.store.ts","../src/stores/locale.store.ts","../src/utils/locale.ts","../src/utils/analytics.ts","../src/providers/analytics_provider.tsx","../src/utils/string_utils.ts","../src/constant.tsx","../src/utils/purchase_utils.tsx","../src/stores/user.store.ts","../src/service/bzbs_service.ts","../src/stores/campaign-detail.store.ts","../src/stores/campaigns.store.ts","../src/stores/cart.store.ts","../src/stores/categories.store.ts","../src/stores/confirm.store.ts","../src/stores/consent.store.ts","../src/stores/coupon.store.ts","../src/stores/dashboard.store.ts","../src/stores/loading-indicator.store.ts","../src/stores/maintenance.store.ts","../src/stores/notification.store.ts","../src/stores/point-log.store.ts","../src/stores/popup.store.ts","../src/stores/purchase.store.ts","../src/stores/registration.store.ts","../src/stores/zipcode.store.ts"],"sourcesContent":["import { Address, ServiceResponse } from '@bzbs/react-api-client';\nimport { create } from 'zustand';\nimport { useBuzzebeesAppStore } from './buzzebeess-app.store';\n\nexport type AddressState = {\n data: Address[];\n selectedAddress: Address | null;\n isLoading: boolean;\n error: ServiceResponse<unknown> | null;\n};\n\nexport type AddressActions = {\n setSelectedAddress: (address: Address | null) => void;\n fetchData: () => Promise<ServiceResponse<Address[]>>;\n createAddress: (address: AddressUpdateParams) => Promise<ServiceResponse<Address>>;\n updateAddress: (address: AddressUpdateParams) => Promise<ServiceResponse<Address>>;\n deleteAddress: (rowKey: string) => Promise<ServiceResponse<unknown>>;\n clear: () => void;\n};\n\nexport type AddressStore = AddressState & AddressActions;\n\nexport type AddressUpdateParams = {\n name?: string;\n addressName?: string;\n firstName?: string;\n lastName?: string;\n address?: string;\n zipcode?: string;\n provinceCode?: string;\n provinceName?: string;\n districtCode?: string;\n districtName?: string;\n subDistrictCode?: string;\n subDistrictName?: string;\n contactNumber?: string;\n countryCode?: string;\n countryName?: string;\n isDefault?: boolean;\n rowKey?: string;\n};\n\nexport const useAddressStore = create<AddressStore>((set, get) => ({\n // Initial state\n data: [],\n selectedAddress: null,\n isLoading: false,\n error: null,\n\n setSelectedAddress: (address: Address | null) => set({ selectedAddress: address }),\n\n fetchData: async () => {\n const bzbsService = useBuzzebeesAppStore.getState().bzbsService;\n\n if (!bzbsService) {\n return { type: 'client-error', message: 'Service not configured' };\n }\n\n set({ isLoading: true });\n const response = await bzbsService.addressApi.userAddresses();\n set({ isLoading: false });\n\n if (response.type === 'success') {\n set({\n data: response.model,\n error: null,\n });\n } else {\n set({ error: response });\n }\n\n return response;\n },\n\n createAddress: async (address: AddressUpdateParams) => {\n const bzbsService = useBuzzebeesAppStore.getState().bzbsService;\n\n if (!bzbsService) {\n return { type: 'client-error', message: 'Service not configured' };\n }\n\n set({ isLoading: true });\n const response = await bzbsService.addressApi.updateAddress({\n ...address,\n rowKey: '',\n });\n set({ isLoading: false });\n\n if (response.type === 'success') {\n // Refresh address list\n get().fetchData();\n set({ error: null });\n } else {\n set({ error: response });\n }\n\n return response;\n },\n\n updateAddress: async (address: AddressUpdateParams) => {\n const bzbsService = useBuzzebeesAppStore.getState().bzbsService;\n\n if (!bzbsService) {\n return { type: 'client-error', message: 'Service not configured' };\n }\n\n set({ isLoading: true });\n const response = await bzbsService.addressApi.updateAddress({\n ...address,\n rowKey: address.rowKey || '',\n });\n set({ isLoading: false });\n\n if (response.type === 'success') {\n // Refresh address list\n get().fetchData();\n set({ error: null });\n } else {\n set({ error: response });\n }\n\n return response;\n },\n\n deleteAddress: async (rowKey: string) => {\n const bzbsService = useBuzzebeesAppStore.getState().bzbsService;\n\n if (!bzbsService) {\n return { type: 'client-error', message: 'Service not configured' };\n }\n\n set({ isLoading: true });\n const response = await bzbsService.addressApi.deleteAddress({ rowKey });\n set({ isLoading: false });\n\n if (response.type === 'success') {\n // Refresh address list\n get().fetchData();\n set({ error: null });\n } else {\n set({ error: response });\n }\n\n return response;\n },\n\n clear: () => {\n set({\n data: [],\n selectedAddress: null,\n isLoading: false,\n error: null,\n });\n },\n}));\n","import { BzbsService } from '@bzbs/react-api-client';\nimport { create } from 'zustand';\n\nexport type AuthTokenType = 'jwt' | 'auth_token';\n\ntype getTokenFunction = () => Promise<string | null>;\ntype setTokenFunction = (token: string) => void;\ntype removeTokenFunction = () => void;\n\nexport type TokenFunctions = {\n getToken: getTokenFunction;\n setToken: setTokenFunction;\n removeToken: removeTokenFunction;\n};\n\nexport type BuzzebeesAppState = {\n appId: string;\n appName: string;\n bzbsService: BzbsService | null;\n uuid: string;\n macAddress: string;\n clientVersion: string;\n os: string;\n platform: string;\n fcmToken: string;\n deviceNotificationEnabled: boolean;\n urls: {\n webCallback: string;\n cart: string;\n };\n tokenFunctions: TokenFunctions | null;\n tokenType: AuthTokenType;\n config: {\n defaultDashboardConfig: string;\n defaultDashboardMode: 'main' | 'sub';\n defaultMenuConfig: string;\n defaultCampaignConfig: string;\n };\n};\n\nexport type BuzzebeesAppActions = {\n setAppId: (appId: string) => void;\n setAppName: (appName: string) => void;\n setBzbsService: (service: BzbsService) => void;\n setUuid: (uuid: string) => void;\n setMacAddress: (macAddress: string) => void;\n setClientVersion: (clientVersion: string) => void;\n setOs: (os: string) => void;\n setPlatform: (platform: string) => void;\n setFcmToken: (fcmToken: string) => void;\n setDeviceNotificationEnabled: (deviceNotificationEnabled: boolean) => void;\n setUrls: (urls: { webCallback: string; cart: string }) => void;\n setTokenType: (tokenType: AuthTokenType) => void;\n setTokenFunctions: (tokenFunctions: TokenFunctions) => void;\n configure: (config: {\n appId: string;\n appName: string;\n bzbsService: BzbsService;\n uuid: string;\n clientVersion: string;\n os: string;\n platform: string;\n fcmToken: string;\n deviceNotificationEnabled: boolean;\n urls: { webCallback: string; cart: string };\n tokenFunctions: TokenFunctions;\n tokenType: AuthTokenType;\n defaultDashboardConfig: string;\n defaultDashboardMode: 'main' | 'sub';\n defaultMenuConfig: string;\n defaultCampaignConfig: string;\n }) => void;\n};\n\nexport type BuzzebeesAppStore = BuzzebeesAppState & BuzzebeesAppActions;\n\nexport const useBuzzebeesAppStore = create<BuzzebeesAppStore>((set) => ({\n appId: '',\n appName: '',\n bzbsService: null,\n uuid: '',\n macAddress: '',\n clientVersion: '',\n os: '',\n platform: '',\n fcmToken: '',\n deviceNotificationEnabled: false,\n urls: {\n webCallback: '',\n cart: '',\n },\n tokenFunctions: null,\n tokenType: 'auth_token',\n config: {\n defaultDashboardConfig: '',\n defaultDashboardMode: 'main',\n defaultMenuConfig: '',\n defaultCampaignConfig: '',\n },\n setAppId: (appId: string) => set({ appId }),\n setAppName: (appName: string) => set({ appName }),\n setBzbsService: (service: BzbsService) => set({ bzbsService: service }),\n setUuid: (uuid: string) => set({ uuid }),\n setMacAddress: (macAddress: string) => set({ macAddress }),\n setClientVersion: (clientVersion: string) => set({ clientVersion }),\n setOs: (os: string) => set({ os }),\n setPlatform: (platform: string) => set({ platform }),\n setFcmToken: (fcmToken: string) => set({ fcmToken }),\n setDeviceNotificationEnabled: (deviceNotificationEnabled: boolean) => set({ deviceNotificationEnabled }),\n setUrls: (urls: { webCallback: string; cart: string }) => set({ urls }),\n setTokenFunctions: (tokenFunctions: TokenFunctions) => set({ tokenFunctions }),\n setTokenType: (tokenType: AuthTokenType) => set({ tokenType }),\n configure: (config: {\n appId: string;\n appName: string;\n bzbsService: BzbsService;\n uuid: string;\n clientVersion: string;\n os: string;\n platform: string;\n fcmToken: string;\n deviceNotificationEnabled: boolean;\n urls: { webCallback: string; cart: string };\n tokenFunctions: TokenFunctions;\n tokenType: AuthTokenType;\n defaultDashboardConfig: string;\n defaultDashboardMode: 'main' | 'sub';\n defaultMenuConfig: string;\n defaultCampaignConfig: string;\n }) => {\n set({\n appId: config.appId,\n appName: config.appName,\n bzbsService: config.bzbsService,\n uuid: config.uuid,\n clientVersion: config.clientVersion,\n os: config.os,\n platform: config.platform,\n fcmToken: config.fcmToken,\n deviceNotificationEnabled: config.deviceNotificationEnabled,\n urls: config.urls,\n tokenFunctions: config.tokenFunctions,\n tokenType: config.tokenType,\n config: {\n defaultDashboardConfig: config.defaultDashboardConfig,\n defaultDashboardMode: config.defaultDashboardMode,\n defaultMenuConfig: config.defaultMenuConfig,\n defaultCampaignConfig: config.defaultCampaignConfig,\n },\n });\n },\n}));\n","import { create } from 'zustand';\n\nexport type AlertRequest = {\n title: string;\n content: string;\n closeText?: string;\n onClose: () => void;\n};\n\nexport type AlertState = {\n isOpen: boolean;\n alertRequest: AlertRequest;\n};\n\nexport type AlertActions = {\n openAlert: (request: AlertRequest) => void;\n closeAlert: () => void;\n};\n\nexport type AlertStore = AlertState & AlertActions;\n\nexport const useAlertStore = create<AlertStore>((set, get) => ({\n isOpen: false,\n alertRequest: {\n title: '',\n content: '',\n onClose: () => {},\n },\n\n openAlert: (request: AlertRequest) => {\n set({ alertRequest: request, isOpen: true });\n },\n\n closeAlert: () => {\n const { alertRequest } = get();\n alertRequest.onClose();\n set({ isOpen: false });\n },\n}));\n","import type { UserInfo } from 'matomo-tracker-react-native';\nimport MatomoTracker from 'matomo-tracker-react-native';\nimport { create } from 'zustand';\n\nexport type AnalyticsEventParams = {\n action: string;\n name?: string;\n category?: string;\n value?: number;\n campaign?: string;\n userInfo?: UserInfo;\n};\n\nexport type AnalyticsPageViewParams = {\n name: string;\n url?: string;\n userInfo?: UserInfo;\n};\n\nexport type AnalyticsState = {\n isInitialized: boolean;\n isEnabled: boolean;\n siteId?: number;\n urlBase?: string;\n trackerUrl?: string;\n userId?: string;\n disabled?: boolean;\n log?: boolean;\n matomoInstance?: MatomoTracker;\n presetUserInfo?: UserInfo;\n};\n\nexport type AnalyticsActions = {\n initialize: (config: {\n siteId: number;\n urlBase: string;\n trackerUrl?: string;\n userId?: string;\n disabled?: boolean;\n log?: boolean;\n }) => void;\n setEnabled: (enabled: boolean) => void;\n setPresetUserInfo: (userInfo: UserInfo) => void;\n clearPresetUserInfo: () => void;\n trackAppStart: (userInfo?: UserInfo) => Promise<void>;\n trackEvent: (params: AnalyticsEventParams) => Promise<void>;\n trackScreenView: (params: AnalyticsPageViewParams) => Promise<void>;\n trackAction: (params: AnalyticsPageViewParams) => Promise<void>;\n trackSiteSearch: (params: {\n keyword: string;\n category?: string;\n count?: number;\n userInfo?: UserInfo;\n }) => Promise<void>;\n trackLink: (params: { link: string; userInfo?: UserInfo }) => Promise<void>;\n trackDownload: (params: { download: string; userInfo?: UserInfo }) => Promise<void>;\n setUserId: (userId: string | null) => void;\n setCustomDimension: (id: number, value: string) => void;\n reset: () => void;\n};\n\nexport type AnalyticsStore = AnalyticsState & AnalyticsActions;\n\nexport const useAnalyticsStore = create<AnalyticsStore>((set, get) => ({\n isInitialized: false,\n isEnabled: true,\n siteId: undefined,\n urlBase: undefined,\n trackerUrl: undefined,\n userId: undefined,\n disabled: false,\n log: false,\n matomoInstance: undefined,\n presetUserInfo: undefined,\n\n initialize: (config) => {\n try {\n // Create Matomo tracker instance\n const matomoInstance = new MatomoTracker({\n urlBase: config.urlBase,\n siteId: config.siteId,\n trackerUrl: config.trackerUrl,\n userId: config.userId,\n disabled: config.disabled || false,\n log: config.log || false,\n });\n\n set({\n siteId: config.siteId,\n urlBase: config.urlBase,\n trackerUrl: config.trackerUrl,\n userId: config.userId,\n disabled: config.disabled || false,\n log: config.log || false,\n matomoInstance,\n isInitialized: true,\n });\n\n console.log('Analytics: Matomo tracker initialized', config);\n } catch (error) {\n console.error('Analytics: Failed to initialize Matomo tracker', error);\n set({\n siteId: config.siteId,\n urlBase: config.urlBase,\n trackerUrl: config.trackerUrl,\n userId: config.userId,\n disabled: config.disabled || false,\n log: config.log || false,\n isInitialized: false,\n });\n }\n },\n\n setEnabled: (enabled: boolean) => {\n set({ isEnabled: enabled });\n },\n\n setPresetUserInfo: (userInfo: UserInfo) => {\n set({ presetUserInfo: userInfo });\n },\n\n clearPresetUserInfo: () => {\n set({ presetUserInfo: undefined });\n },\n\n trackAppStart: async (userInfo?: UserInfo) => {\n const state = get();\n if (!state.isInitialized || !state.isEnabled || !state.matomoInstance || state.disabled) {\n console.debug('Analytics: Track App Start skipped - not initialized, disabled, or tracking disabled');\n return;\n }\n\n try {\n // Merge preset userInfo with provided userInfo\n const mergedUserInfo = { ...state.presetUserInfo, ...userInfo };\n\n await state.matomoInstance.trackAppStart({\n userInfo: Object.keys(mergedUserInfo).length > 0 ? mergedUserInfo : undefined,\n });\n\n if (state.log) {\n console.debug('Analytics: App start tracked successfully', { userInfo: mergedUserInfo });\n }\n } catch (error) {\n console.error('Analytics: Failed to track app start', error);\n }\n },\n\n trackEvent: async (params: AnalyticsEventParams) => {\n const state = get();\n if (!state.isInitialized || !state.isEnabled || !state.matomoInstance || state.disabled) {\n console.debug('Analytics: Track Event skipped - not initialized, disabled, or tracking disabled', params);\n return;\n }\n\n try {\n // Merge preset userInfo with provided userInfo\n const mergedUserInfo = { ...state.presetUserInfo, ...params.userInfo };\n\n await state.matomoInstance.trackEvent({\n category: params.category || 'User Action',\n action: params.action,\n name: params.name,\n value: params.value,\n campaign: params.campaign,\n userInfo: Object.keys(mergedUserInfo).length > 0 ? mergedUserInfo : undefined,\n });\n\n if (state.log) {\n console.debug('Analytics: Event tracked successfully', params);\n }\n } catch (error) {\n console.error('Analytics: Failed to track event', error, params);\n }\n },\n\n trackScreenView: async (params: AnalyticsPageViewParams) => {\n const state = get();\n if (!state.isInitialized || !state.isEnabled || !state.matomoInstance || state.disabled) {\n console.debug('Analytics: Track Screen View skipped - not initialized, disabled, or tracking disabled', params);\n return;\n }\n\n try {\n // Merge preset userInfo with provided userInfo\n const mergedUserInfo = { ...state.presetUserInfo, ...params.userInfo };\n\n await state.matomoInstance.trackScreenView({\n name: params.name,\n userInfo: Object.keys(mergedUserInfo).length > 0 ? mergedUserInfo : undefined,\n });\n\n if (state.log) {\n console.debug('Analytics: Screen view tracked successfully', params);\n }\n } catch (error) {\n console.error('Analytics: Failed to track screen view', error, params);\n }\n },\n\n trackAction: async (params: AnalyticsPageViewParams) => {\n const state = get();\n if (!state.isInitialized || !state.isEnabled || !state.matomoInstance || state.disabled) {\n console.debug('Analytics: Track Action skipped - not initialized, disabled, or tracking disabled', params);\n return;\n }\n\n try {\n // Merge preset userInfo with provided userInfo\n const mergedUserInfo = { ...state.presetUserInfo, ...params.userInfo };\n\n await state.matomoInstance.trackAction({\n name: params.name,\n userInfo: Object.keys(mergedUserInfo).length > 0 ? mergedUserInfo : undefined,\n });\n\n if (state.log) {\n console.debug('Analytics: Action tracked successfully', params);\n }\n } catch (error) {\n console.error('Analytics: Failed to track action', error, params);\n }\n },\n\n trackSiteSearch: async (params: { keyword: string; category?: string; count?: number; userInfo?: UserInfo }) => {\n const state = get();\n if (!state.isInitialized || !state.isEnabled || !state.matomoInstance || state.disabled) {\n console.debug('Analytics: Track Site Search skipped - not initialized, disabled, or tracking disabled', params);\n return;\n }\n\n try {\n // Merge preset userInfo with provided userInfo\n const mergedUserInfo = { ...state.presetUserInfo, ...params.userInfo };\n\n await state.matomoInstance.trackSiteSearch({\n keyword: params.keyword,\n category: params.category,\n count: params.count,\n userInfo: Object.keys(mergedUserInfo).length > 0 ? mergedUserInfo : undefined,\n });\n\n if (state.log) {\n console.debug('Analytics: Site search tracked successfully', params);\n }\n } catch (error) {\n console.error('Analytics: Failed to track site search', error, params);\n }\n },\n\n trackLink: async (params: { link: string; userInfo?: UserInfo }) => {\n const state = get();\n if (!state.isInitialized || !state.isEnabled || !state.matomoInstance || state.disabled) {\n console.debug('Analytics: Track Link skipped - not initialized, disabled, or tracking disabled', params);\n return;\n }\n\n try {\n // Merge preset userInfo with provided userInfo\n const mergedUserInfo = { ...state.presetUserInfo, ...params.userInfo };\n\n await state.matomoInstance.trackLink({\n link: params.link,\n userInfo: Object.keys(mergedUserInfo).length > 0 ? mergedUserInfo : undefined,\n });\n\n if (state.log) {\n console.debug('Analytics: Link tracked successfully', params);\n }\n } catch (error) {\n console.error('Analytics: Failed to track link', error, params);\n }\n },\n\n trackDownload: async (params: { download: string; userInfo?: UserInfo }) => {\n const state = get();\n if (!state.isInitialized || !state.isEnabled || !state.matomoInstance || state.disabled) {\n console.debug('Analytics: Track Download skipped - not initialized, disabled, or tracking disabled', params);\n return;\n }\n\n try {\n // Merge preset userInfo with provided userInfo\n const mergedUserInfo = { ...state.presetUserInfo, ...params.userInfo };\n\n await state.matomoInstance.trackDownload({\n download: params.download,\n userInfo: Object.keys(mergedUserInfo).length > 0 ? mergedUserInfo : undefined,\n });\n\n if (state.log) {\n console.debug('Analytics: Download tracked successfully', params);\n }\n } catch (error) {\n console.error('Analytics: Failed to track download', error, params);\n }\n },\n\n setUserId: (userId: string | null) => {\n const state = get();\n\n // Update both the userId state and the preset userInfo\n if (userId) {\n const updatedUserInfo = {\n ...state.presetUserInfo,\n uid: userId,\n };\n set({\n userId: userId,\n presetUserInfo: updatedUserInfo,\n });\n } else {\n // Remove uid from preset userInfo if userId is null\n const currentUserInfo = state.presetUserInfo || {};\n if (currentUserInfo.uid) {\n const updatedUserInfo = { ...currentUserInfo };\n delete updatedUserInfo.uid;\n\n set({\n userId: undefined,\n presetUserInfo: Object.keys(updatedUserInfo).length > 0 ? updatedUserInfo : undefined,\n });\n } else {\n set({ userId: undefined });\n }\n }\n\n if (state.log) {\n console.debug('Analytics: User ID updated in preset userInfo', userId);\n }\n },\n\n setCustomDimension: (id: number, value: string) => {\n const state = get();\n if (!state.presetUserInfo) {\n set({ presetUserInfo: { [`dimension${id}`]: value } });\n } else {\n set({\n presetUserInfo: {\n ...state.presetUserInfo,\n [`dimension${id}`]: value,\n },\n });\n }\n\n if (state.log) {\n console.debug('Analytics: Custom dimension set in preset userInfo', { id, value });\n }\n },\n\n reset: () => {\n set({\n isInitialized: false,\n isEnabled: true,\n siteId: undefined,\n urlBase: undefined,\n trackerUrl: undefined,\n userId: undefined,\n disabled: false,\n log: false,\n matomoInstance: undefined,\n presetUserInfo: undefined,\n });\n\n console.debug('Analytics: Store reset successfully');\n },\n}));\n","import {\n ConfirmOtpResponse,\n ErrorResponse,\n ForgetPasswordResponse,\n LoginResponse,\n OtpResponse,\n ResumeResponse,\n ServiceResponse,\n StatusResponse,\n ValidateOtpResponse,\n Version,\n} from '@bzbs/react-api-client';\nimport { create } from 'zustand';\nimport { useBuzzebeesAppStore } from './buzzebeess-app.store';\nimport { useLocaleStore } from './locale.store';\nimport { trackCommonEvents } from '../utils';\nimport { useAnalyticsStore } from './analytics.store';\nimport { useUserStore } from './user.store';\n\nexport type AuthState = {\n isInitialized: boolean;\n versionData: Version | null;\n rawVersionData: unknown | null;\n data: LoginResponse | ResumeResponse | null;\n isLoading: boolean;\n isLoadingToken: boolean;\n error: ErrorResponse | null;\n token: string | null;\n isLoggedIn: boolean;\n};\n\nexport type AuthActions = {\n setIsLoading: (isLoading: boolean) => void;\n setIsLoadingToken: (isLoadingToken: boolean) => void;\n setError: (error: ErrorResponse | null) => void;\n checkLoggedIn: () => Promise<void>;\n loginWithUsernamePassword: (username: string, password: string) => Promise<ServiceResponse<LoginResponse>>;\n loginWithGoogle: (token: string) => Promise<ServiceResponse<LoginResponse>>;\n loginWithFacebook: (token: string) => Promise<ServiceResponse<LoginResponse>>;\n loginWithApple: (token: string, refreshToken: string) => Promise<ServiceResponse<LoginResponse>>;\n loginWithUUID: () => Promise<ServiceResponse<LoginResponse>>;\n logout: () => Promise<ServiceResponse<unknown>>;\n forgetPassword: (\n contact: string,\n type: 'email' | 'contact_number'\n ) => Promise<ServiceResponse<ForgetPasswordResponse>>;\n resetPassword: (\n contact: string,\n otp: string,\n refCode: string,\n password: string\n ) => Promise<ServiceResponse<StatusResponse>>;\n sendOtp: (contact: string, channel: string) => Promise<ServiceResponse<OtpResponse>>;\n validateOtp: (\n otp: string,\n refCode: string,\n contact: string,\n channel: string\n ) => Promise<ServiceResponse<ValidateOtpResponse>>;\n confirmOtp: (otp: string, refCode: string, contact: string) => Promise<ServiceResponse<ConfirmOtpResponse>>;\n resume: (clientVersion: string) => Promise<ServiceResponse<ResumeResponse>>;\n version: (clientVersion: string) => Promise<ServiceResponse<Version>>;\n clear: () => void;\n};\n\nexport type AuthStore = AuthState & AuthActions;\n\ntype LoginHandlerParams = {\n loginFn: () => Promise<ServiceResponse<LoginResponse>>;\n};\n\nexport const useAuthStore = create<AuthStore>((set) => {\n // Private helper function to handle common login logic\n const handleLogin = async ({ loginFn }: LoginHandlerParams): Promise<ServiceResponse<LoginResponse>> => {\n const { bzbsService, tokenFunctions, tokenType } = useBuzzebeesAppStore.getState();\n\n if (!bzbsService || !tokenFunctions) {\n return { type: 'client-error', message: 'Service or auth persistence not configured' };\n }\n\n set({ isLoading: true, error: null });\n const response = await loginFn();\n set({ isLoading: false });\n\n if (response.type === 'success') {\n const token = tokenType === 'jwt' ? response.model.jwt : response.model.token;\n tokenFunctions.setToken(token);\n\n set({\n data: response.model,\n token: response.model.token,\n isLoggedIn: true,\n error: null,\n });\n useAnalyticsStore.getState().setUserId(response.model.userId);\n useAnalyticsStore.getState().setCustomDimension(1, useBuzzebeesAppStore.getState().clientVersion);\n useAnalyticsStore.getState().setCustomDimension(2, useBuzzebeesAppStore.getState().appId);\n\n const userResponse = await useUserStore.getState().fetchUser();\n if (userResponse.type === 'success') {\n useAnalyticsStore.getState().setCustomDimension(3, userResponse.model.Contact_Number ?? '');\n useAnalyticsStore.getState().setCustomDimension(4, userResponse.model.Email ?? '');\n }\n\n trackCommonEvents.loginSuccess();\n } else {\n set({ error: response });\n }\n\n return response;\n };\n\n return {\n isInitialized: false,\n versionData: null,\n rawVersionData: null,\n data: null,\n isLoading: false,\n isLoadingToken: false,\n error: null,\n token: null,\n isLoggedIn: false,\n\n setIsLoading: (isLoading: boolean) => set({ isLoading }),\n setIsLoadingToken: (isLoadingToken: boolean) => set({ isLoadingToken }),\n setError: (error: ErrorResponse | null) => set({ error }),\n\n checkLoggedIn: async () => {\n const { tokenFunctions } = useBuzzebeesAppStore.getState();\n if (!tokenFunctions) {\n set({ isLoggedIn: false, isInitialized: true });\n return;\n }\n\n try {\n set({ isLoadingToken: true });\n const token = await tokenFunctions.getToken();\n if (token) {\n set({ isLoggedIn: true, token });\n } else {\n set({ isLoggedIn: false, token: null });\n }\n } catch (error) {\n set({ isLoggedIn: false, token: null });\n } finally {\n set({ isLoadingToken: false, isInitialized: true });\n }\n },\n\n loginWithUsernamePassword: async (username: string, password: string) => {\n const { appId, uuid, os, platform, deviceNotificationEnabled, clientVersion, fcmToken } =\n useBuzzebeesAppStore.getState();\n const localeId = useLocaleStore.getState().localeId;\n const bzbsService = useBuzzebeesAppStore.getState().bzbsService;\n\n if (!bzbsService) {\n return { type: 'client-error', message: 'Service not configured' };\n }\n\n return handleLogin({\n loginFn: () =>\n bzbsService.authApi.usernamePasswordLogin({\n username,\n password,\n appId,\n uuid,\n deviceToken: fcmToken,\n clientVersion,\n os,\n platform,\n deviceLocale: localeId.toString(),\n deviceNotificationEnabled,\n }),\n });\n },\n\n loginWithGoogle: async (token: string) => {\n const { appId, uuid, os, platform, deviceNotificationEnabled, clientVersion, fcmToken } =\n useBuzzebeesAppStore.getState();\n const localeId = useLocaleStore.getState().localeId;\n const bzbsService = useBuzzebeesAppStore.getState().bzbsService;\n\n if (!bzbsService) {\n return { type: 'client-error', message: 'Service not configured' };\n }\n\n return handleLogin({\n loginFn: () =>\n bzbsService.authApi.googleLogin({\n idToken: token,\n appId,\n uuid,\n deviceToken: fcmToken,\n clientVersion,\n os,\n platform,\n deviceLocale: localeId.toString(),\n deviceNotificationEnabled,\n }),\n });\n },\n\n loginWithFacebook: async (token: string) => {\n const { appId, uuid, os, platform, deviceNotificationEnabled, clientVersion, fcmToken } =\n useBuzzebeesAppStore.getState();\n const localeId = useLocaleStore.getState().localeId;\n const bzbsService = useBuzzebeesAppStore.getState().bzbsService;\n\n if (!bzbsService) {\n return { type: 'client-error', message: 'Service not configured' };\n }\n\n return handleLogin({\n loginFn: () =>\n bzbsService.authApi.facebookLogin({\n accessToken: token,\n appId,\n uuid,\n deviceToken: fcmToken,\n clientVersion,\n os,\n platform,\n deviceLocale: localeId.toString(),\n deviceNotificationEnabled,\n }),\n });\n },\n\n loginWithApple: async (token: string, refreshToken: string) => {\n const { appId, uuid, os, platform, deviceNotificationEnabled, clientVersion, fcmToken } =\n useBuzzebeesAppStore.getState();\n const localeId = useLocaleStore.getState().localeId;\n const bzbsService = useBuzzebeesAppStore.getState().bzbsService;\n\n if (!bzbsService) {\n return { type: 'client-error', message: 'Service not configured' };\n }\n\n return handleLogin({\n loginFn: () =>\n bzbsService.authApi.appleLogin({\n idToken: token,\n refreshToken,\n appId,\n uuid,\n deviceToken: fcmToken,\n clientVersion,\n os,\n platform,\n deviceLocale: localeId.toString(),\n deviceNotificationEnabled,\n }),\n });\n },\n\n loginWithUUID: async () => {\n const { appId, uuid, os, platform, deviceNotificationEnabled, clientVersion, fcmToken } =\n useBuzzebeesAppStore.getState();\n const localeId = useLocaleStore.getState().localeId;\n const bzbsService = useBuzzebeesAppStore.getState().bzbsService;\n\n if (!bzbsService) {\n return { type: 'client-error', message: 'Service not configured' };\n }\n\n return handleLogin({\n loginFn: () =>\n bzbsService.authApi.deviceLogin({\n appId,\n uuid,\n deviceToken: fcmToken,\n clientVersion,\n os,\n platform,\n deviceLocale: localeId.toString(),\n deviceNotificationEnabled,\n }),\n });\n },\n\n logout: async () => {\n const { tokenFunctions } = useBuzzebeesAppStore.getState();\n const uuid = useBuzzebeesAppStore.getState().uuid;\n const bzbsService = useBuzzebeesAppStore.getState().bzbsService;\n\n if (!bzbsService || !tokenFunctions) {\n return { type: 'client-error', message: 'Service or auth persistence not configured' };\n }\n\n set({ isLoading: true });\n const response = await bzbsService.authApi.logout({ uuid });\n set({ isLoading: false });\n\n tokenFunctions.removeToken();\n set({\n data: null,\n token: null,\n isLoggedIn: false,\n error: null,\n });\n\n return response;\n },\n\n forgetPassword: async (contact: string, type: 'email' | 'contact_number') => {\n const bzbsService = useBuzzebeesAppStore.getState().bzbsService;\n\n if (!bzbsService) {\n return { type: 'client-error', message: 'Service not configured' };\n }\n\n set({ isLoading: true });\n const response = await bzbsService.authApi.forgetPassword({ contact, type });\n set({ isLoading: false });\n return response;\n },\n\n resetPassword: async (contact: string, otp: string, refCode: string, password: string) => {\n const bzbsService = useBuzzebeesAppStore.getState().bzbsService;\n\n if (!bzbsService) {\n return { type: 'client-error', message: 'Service not configured' };\n }\n\n set({ isLoading: true });\n const response = await bzbsService.authApi.resetPassword({\n contact,\n otp,\n refCode,\n newPassword: password,\n });\n set({ isLoading: false });\n return response;\n },\n\n sendOtp: async (contact: string, channel: string) => {\n const uuid = useBuzzebeesAppStore.getState().uuid;\n const appId = useBuzzebeesAppStore.getState().appId;\n const bzbsService = useBuzzebeesAppStore.getState().bzbsService;\n\n if (!bzbsService) {\n return { type: 'client-error', message: 'Service not configured' };\n }\n\n set({ isLoading: true });\n const response = await bzbsService.authApi.otp({\n uuid,\n appId,\n contactNumber: contact,\n channel,\n });\n set({ isLoading: false });\n return response;\n },\n\n validateOtp: async (otp: string, refCode: string, contact: string, channel: string) => {\n const appId = useBuzzebeesAppStore.getState().appId;\n const bzbsService = useBuzzebeesAppStore.getState().bzbsService;\n\n if (!bzbsService) {\n return { type: 'client-error', message: 'Service not configured' };\n }\n\n set({ isLoading: true });\n const response = await bzbsService.authApi.validateOtp({\n appId,\n otp,\n refCode,\n contactNumber: contact,\n use: false,\n channel,\n });\n set({ isLoading: false });\n return response;\n },\n\n confirmOtp: async (otp: string, refCode: string, contact: string) => {\n const bzbsService = useBuzzebeesAppStore.getState().bzbsService;\n\n if (!bzbsService) {\n return { type: 'client-error', message: 'Service not configured' };\n }\n\n set({ isLoading: true });\n const response = await bzbsService.authApi.confirmOtp({\n otp,\n refCode,\n contactNumber: contact,\n });\n set({ isLoading: false });\n return response;\n },\n\n resume: async (clientVersion: string) => {\n const { uuid, appId, fcmToken } = useBuzzebeesAppStore.getState();\n const { tokenFunctions, tokenType } = useBuzzebeesAppStore.getState();\n const bzbsService = useBuzzebeesAppStore.getState().bzbsService;\n\n if (!bzbsService || !tokenFunctions) {\n return { type: 'client-error', message: 'Service or auth persistence not configured' };\n }\n\n set({ isLoading: true });\n const response = await bzbsService.authApi.resume({\n uuid,\n appId,\n clientVersion,\n deviceToken: fcmToken,\n });\n set({ isLoading: false });\n\n if (response.type === 'success') {\n const token = tokenType === 'jwt' ? response.model.jwt! : response.model.token!;\n tokenFunctions.setToken(token);\n set({\n data: response.model,\n error: null,\n });\n } else {\n set({ error: response });\n }\n\n return response;\n },\n\n version: async (clientVersion: string) => {\n const bzbsService = useBuzzebeesAppStore.getState().bzbsService;\n\n if (!bzbsService) {\n return { type: 'client-error', message: 'Service not configured' };\n }\n\n set({ isLoading: true });\n const response = await bzbsService.authApi.versionRaw(clientVersion);\n set({ isLoading: false });\n\n if (response.type === 'success') {\n set({ versionData: response.model, rawVersionData: response.model });\n }\n\n return response;\n },\n\n clear: () => {\n set({\n data: null,\n versionData: null,\n isLoading: false,\n error: null,\n token: null,\n isLoggedIn: false,\n });\n },\n };\n});\n","import { create } from 'zustand';\nimport { findBestLocaleFromString } from '../utils/locale';\n\nexport type AppLocale = {\n locale: string;\n localeId: number;\n};\n\nexport const EN = { locale: 'en', localeId: 1033 };\nexport const TH = { locale: 'th', localeId: 1054 };\n\nexport type LocaleState = {\n appLocale: AppLocale;\n locale: string;\n localeId: number;\n};\n\nexport type LocaleActions = {\n setAppLocale: (locale: AppLocale | string) => void;\n};\n\nexport type LocaleStore = LocaleState & LocaleActions;\n\nexport const useLocaleStore = create<LocaleStore>((set) => ({\n appLocale: EN,\n locale: 'en',\n localeId: 1033,\n\n setAppLocale: (locale: AppLocale | string) => {\n const newLocale = typeof locale === 'string' ? findBestLocaleFromString(locale) : locale;\n set({\n appLocale: newLocale,\n locale: newLocale.locale,\n localeId: newLocale.localeId,\n });\n },\n}));\n","export const localeToLCIDMap: { [key: string]: number } = {\n 'ar-SA': 1025,\n 'bg-BG': 1026,\n 'ca-ES': 1027,\n 'zh-TW': 1028,\n 'cs-CZ': 1029,\n 'da-DK': 1030,\n 'de-DE': 1031,\n 'el-GR': 1032,\n 'en-US': 1033,\n 'es-ES': 1034,\n 'fi-FI': 1035,\n 'fr-FR': 1036,\n 'he-IL': 1037,\n 'hu-HU': 1038,\n 'is-IS': 1039,\n 'it-IT': 1040,\n 'ja-JP': 1041,\n 'ko-KR': 1042,\n 'nl-NL': 1043,\n 'nb-NO': 1044,\n 'pl-PL': 1045,\n 'pt-BR': 1046,\n 'rm-CH': 1047,\n 'ro-RO': 1048,\n 'ru-RU': 1049,\n 'hr-HR': 1050,\n 'sk-SK': 1051,\n 'sq-AL': 1052,\n 'sv-SE': 1053,\n 'th-TH': 1054,\n 'tr-TR': 1055,\n 'ur-PK': 1056,\n 'id-ID': 1057,\n 'uk-UA': 1058,\n 'be-BY': 1059,\n 'sl-SI': 1060,\n 'et-EE': 1061,\n 'lv-LV': 1062,\n 'lt-LT': 1063,\n 'tg-Cyrl-TJ': 1064,\n 'fa-IR': 1065,\n 'vi-VN': 1066,\n 'hy-AM': 1067,\n 'az-Latn-AZ': 1068,\n 'eu-ES': 1069,\n 'wen-DE': 1070,\n 'mk-MK': 1071,\n 'st-ZA': 1072,\n 'ts-ZA': 1073,\n 'tn-ZA': 1074,\n 'ven-ZA': 1075,\n 'xh-ZA': 1076,\n 'zu-ZA': 1077,\n 'af-ZA': 1078,\n 'ka-GE': 1079,\n 'fo-FO': 1080,\n 'hi-IN': 1081,\n 'mt-MT': 1082,\n 'se-NO': 1083,\n 'gd-GB': 1084,\n yi: 1085,\n 'ms-MY': 1086,\n 'kk-KZ': 1087,\n 'ky-KG': 1088,\n 'sw-KE': 1089,\n 'tk-TM': 1090,\n 'uz-Latn-UZ': 1091,\n 'tt-RU': 1092,\n 'bn-IN': 1093,\n 'pa-IN': 1094,\n 'gu-IN': 1095,\n 'or-IN': 1096,\n 'ta-IN': 1097,\n 'te-IN': 1098,\n 'kn-IN': 1099,\n 'ml-IN': 1100,\n 'as-IN': 1101,\n 'mr-IN': 1102,\n 'sa-IN': 1103,\n 'mn-MN': 1104,\n 'bo-CN': 1105,\n 'cy-GB': 1106,\n 'km-KH': 1107,\n 'lo-LA': 1108,\n 'my-MM': 1109,\n 'gl-ES': 1110,\n 'kok-IN': 1111,\n mni: 1112,\n 'sd-IN': 1113,\n 'syr-SY': 1114,\n 'si-LK': 1115,\n 'chr-US': 1116,\n 'iu-Cans-CA': 1117,\n 'am-ET': 1118,\n tmz: 1119,\n 'ks-Arab-IN': 1120,\n 'ne-NP': 1121,\n 'fy-NL': 1122,\n 'ps-AF': 1123,\n 'fil-PH': 1124,\n 'dv-MV': 1125,\n 'bin-NG': 1126,\n 'fuv-NG': 1127,\n 'ha-Latn-NG': 1128,\n 'ibb-NG': 1129,\n 'yo-NG': 1130,\n 'quz-BO': 1131,\n 'nso-ZA': 1132,\n 'ig-NG': 1136,\n 'kr-NG': 1137,\n 'gaz-ET': 1138,\n 'ti-ER': 1139,\n 'gn-PY': 1140,\n 'haw-US': 1141,\n la: 1142,\n 'so-SO': 1143,\n 'ii-CN': 1144,\n 'pap-AN': 1145,\n 'ug-Arab-CN': 1152,\n 'mi-NZ': 1153,\n 'ar-IQ': 2049,\n 'zh-CN': 2052,\n 'de-CH': 2055,\n 'en-GB': 2057,\n 'es-MX': 2058,\n 'fr-BE': 2060,\n 'it-CH': 2064,\n 'nl-BE': 2067,\n 'nn-NO': 2068,\n 'pt-PT': 2070,\n 'ro-MD': 2072,\n 'ru-MD': 2073,\n 'sr-Latn-CS': 2074,\n 'sv-FI': 2077,\n 'ur-IN': 2080,\n 'az-Cyrl-AZ': 2092,\n 'ga-IE': 2108,\n 'ms-BN': 2110,\n 'uz-Cyrl-UZ': 2115,\n 'bn-BD': 2117,\n 'pa-PK': 2118,\n 'mn-Mong-CN': 2128,\n 'bo-BT': 2129,\n 'sd-PK': 2137,\n 'tzm-Latn-DZ': 2143,\n 'ks-Deva-IN': 2144,\n 'ne-IN': 2145,\n 'quz-EC': 2155,\n 'ti-ET': 2163,\n 'ar-EG': 3073,\n 'zh-HK': 3076,\n 'de-AT': 3079,\n 'en-AU': 3081,\n 'fr-CA': 3084,\n 'sr-Cyrl-CS': 3098,\n 'ar-LY': 4097,\n 'zh-SG': 4100,\n 'de-LU': 4103,\n 'en-CA': 4105,\n 'fr-CH': 4108,\n 'hr-BA': 4122,\n 'ar-DZ': 5121,\n 'zh-MO': 5124,\n 'de-LI': 5127,\n 'en-NZ': 5129,\n 'fr-LU': 5132,\n 'bs-Latn-BA': 5146,\n 'ar-MO': 6145,\n 'fr-MC': 6156,\n 'ar-TN': 7169,\n 'ar-OM': 8193,\n 'ar-YE': 9217,\n 'en-BZ': 10249,\n 'es-PE': 10250,\n 'fr-SN': 10252,\n 'ar-JO': 11265,\n 'fr-CM': 11276,\n 'en-ID': 14345,\n 'es-CL': 13322,\n 'en-HK': 15369,\n 'fr-MA': 14348,\n 'en-MY': 17417,\n 'es-SV': 17418,\n 'es-NI': 19466,\n 'es-PR': 20490,\n 'es-US': 21514,\n 'fr-015': 58380,\n};\n\nexport function findBestLocaleFromString(value: string): { locale: string; localeId: number } {\n // Attempt to find an exact match in the map\n if (localeToLCIDMap[value]) {\n return {\n locale: value,\n localeId: localeToLCIDMap[value],\n };\n }\n\n // Fallback: Check for a partial match (e.g., \"en\" in \"en-US\")\n const partialMatch = Object.keys(localeToLCIDMap).find((key) => key.startsWith(value.split('-')[0]));\n\n if (partialMatch) {\n return {\n locale: partialMatch,\n localeId: localeToLCIDMap[partialMatch],\n };\n }\n\n // Default result if no match is found\n throw new Error(`Locale '${value}' is not supported.`);\n}\n","import type { UserInfo } from 'matomo-tracker-react-native';\nimport React, { useEffect } from 'react';\nimport { useAnalyticsContext } from '../providers/analytics_provider';\nimport { useAnalyticsStore } from '../stores/analytics.store';\n\n/**\n * Hook to automatically track page views when component mounts or dependencies change\n */\nexport const usePageTracking = (pageName?: string, dependencies: unknown[] = [], customUserInfo?: UserInfo) => {\n const { actions, isInitialized, isEnabled } = useAnalyticsContext();\n\n useEffect(() => {\n if (isInitialized && isEnabled) {\n actions.trackScreenView({\n name: pageName || (typeof window !== 'undefined' ? window.location.pathname : '/'),\n userInfo: customUserInfo,\n });\n }\n }, [isInitialized, isEnabled, pageName, customUserInfo, ...dependencies]);\n};\n\n/**\n * Hook that returns analytics tracking functions\n */\nexport const useAnalytics = () => {\n const { actions, isInitialized, isEnabled } = useAnalyticsContext();\n\n return {\n isInitialized,\n isEnabled,\n trackEvent: actions.trackEvent,\n trackScreenView: actions.trackScreenView,\n trackAction: actions.trackAction,\n trackAppStart: actions.trackAppStart,\n trackSiteSearch: actions.trackSiteSearch,\n trackLink: actions.trackLink,\n trackDownload: actions.trackDownload,\n setUserId: actions.setUserId,\n setCustomDimension: actions.setCustomDimension,\n setEnabled: actions.setEnabled,\n setPresetUserInfo: actions.setPresetUserInfo,\n clearPresetUserInfo: actions.clearPresetUserInfo,\n };\n};\n\n/**\n * Hook that provides access to the Zustand analytics store\n */\nexport const useAnalyticsState = () => {\n return useAnalyticsStore();\n};\n\n/**\n * Utility function to track common events with immediate execution\n */\nexport const trackCommonEvents = {\n /**\n * Track register success event\n * Screen: register, Category: register, Event: register_success\n */\n registerSuccess: async (userInfo?: UserInfo) => {\n const store = useAnalyticsStore.getState();\n if (store.isInitialized && store.isEnabled) {\n await store.trackEvent({\n action: 'on click',\n category: 'register',\n name: 'register_success',\n userInfo,\n });\n }\n },\n\n /**\n * Track login success event\n * Screen: login, Category: login, Event: login_success\n */\n loginSuccess: async (userInfo?: UserInfo) => {\n const store = useAnalyticsStore.getState();\n if (store.isInitialized && store.isEnabled) {\n await store.trackEvent({\n action: 'on click',\n category: 'login',\n name: 'login_success',\n userInfo,\n });\n }\n },\n\n /**\n * Track view campaign event\n * Screen: campaign, Category: campaign_list, Event: view_campaign\n */\n viewCampaign: async (userInfo?: UserInfo) => {\n const store = useAnalyticsStore.getState();\n if (store.isInitialized && store.isEnabled) {\n await store.trackEvent({\n action: 'on click',\n category: 'campaign_list',\n name: 'view_campaign',\n userInfo,\n });\n }\n },\n\n /**\n * Track redeem success event\n * Screen: campaign, Category: campaign_redeem, Event: redeem_success\n */\n redeemSuccess: async (campaignId: string, userInfo?: UserInfo) => {\n const store = useAnalyticsStore.getState();\n if (store.isInitialized && store.isEnabled) {\n await store.trackEvent({\n action: 'on click',\n category: 'campaign_redeem',\n name: 'redeem_success',\n // Use campaign_id as label - can be passed in userInfo or as a separate dimension\n userInfo: {\n ...userInfo,\n dimension3: campaignId, // Store campaign_id in dimension3\n },\n });\n }\n },\n\n /**\n * Track unconsent success event\n * Screen: marketing, Category: marketing_unconsent, Event: unconsent_success\n */\n unconsentSuccess: async (userInfo?: UserInfo) => {\n const store = useAnalyticsStore.getState();\n if (store.isInitialized && store.isEnabled) {\n await store.trackEvent({\n action: 'on click',\n category: 'marketing_unconsent',\n name: 'unconsent_success',\n userInfo,\n });\n }\n },\n\n /**\n * Track button click event\n */\n buttonClick: async (buttonName: string, category: string = 'UI', userInfo?: UserInfo) => {\n const store = useAnalyticsStore.getState();\n if (store.isInitialized && store.isEnabled) {\n await store.trackEvent({\n action: 'on click',\n category,\n name: buttonName,\n userInfo,\n });\n }\n },\n\n /**\n * Track form submit event\n */\n formSubmit: async (formName: string, success: boolean = true, userInfo?: UserInfo) => {\n const store = useAnalyticsStore.getState();\n if (store.isInitialized && store.isEnabled) {\n await store.trackEvent({\n action: 'submit',\n category: 'Form',\n name: formName,\n userInfo: {\n ...userInfo,\n dimension1: success ? 'success' : 'failure',\n },\n });\n }\n },\n\n /**\n * Track search event\n */\n search: async (keyword: string, resultCount?: number, category: string = 'Search', userInfo?: UserInfo) => {\n const store = useAnalyticsStore.getState();\n if (store.isInitialized && store.isEnabled) {\n await store.trackSiteSearch({\n keyword,\n category,\n count: resultCount,\n userInfo,\n });\n }\n },\n\n /**\n * Track purchase event\n */\n purchase: async (amount: number, currency: string = 'THB', productName?: string, userInfo?: UserInfo) => {\n const store = useAnalyticsStore.getState();\n if (store.isInitialized && store.isEnabled) {\n await store.trackEvent({\n action: 'purchase',\n category: 'Commerce',\n name: productName || 'Purchase',\n value: amount,\n userInfo: {\n ...userInfo,\n dimension1: currency,\n },\n });\n }\n },\n\n /**\n * Track user registration event\n */\n userRegistration: async (method: string = 'email', userInfo?: UserInfo) => {\n const store = useAnalyticsStore.getState();\n if (store.isInitialized && store.isEnabled) {\n await store.trackEvent({\n action: 'register',\n category: 'User',\n name: `registration_${method}`,\n userInfo,\n });\n }\n },\n\n /**\n * Track user login event\n */\n userLogin: async (method: string = 'email', userInfo?: UserInfo) => {\n const store = useAnalyticsStore.getState();\n if (store.isInitialized && store.isEnabled) {\n await store.trackEvent({\n action: 'login',\n category: 'User',\n name: `login_${method}`,\n userInfo,\n });\n }\n },\n\n /**\n * Track error event\n */\n error: async (errorType: string, errorMessage?: string, userInfo?: UserInfo) => {\n const store = useAnalyticsStore.getState();\n if (store.isInitialized && store.isEnabled) {\n await store.trackEvent({\n action: 'error',\n category: 'Error',\n name: errorType,\n userInfo: {\n ...userInfo,\n dimension2: errorMessage,\n },\n });\n }\n },\n\n /**\n * Track custom event\n */\n custom: async (name: string, category: string, label?: string, value?: number, userInfo?: UserInfo) => {\n const store = useAnalyticsStore.getState();\n if (store.isInitialized && store.isEnabled)