UNPKG

@bzbs/react-providers

Version:

A collection of React Context Provider for Buzzebees apps

1 lines 237 kB
{"version":3,"sources":["../../src/providers/address_provider.tsx","../../src/providers/buzzebees_service_provider.tsx","../../src/providers/alert_provider.tsx","../../src/providers/analytics_provider.tsx","../../src/providers/auth_provider.tsx","../../src/providers/locale_provider.tsx","../../src/utils/locale.ts","../../src/providers/campaign_detail_provider.tsx","../../src/constant.tsx","../../src/providers/user_provider.tsx","../../src/service/bzbs_service.ts","../../src/providers/campaigns_provider.tsx","../../src/providers/cart_provider.tsx","../../src/providers/categories_provider.tsx","../../src/providers/confirm_provider.tsx","../../src/providers/consent_provider.tsx","../../src/providers/coupon_provider.tsx","../../src/providers/dashboard_provider.tsx","../../src/providers/default_main_app_provider.tsx","../../src/utils/analytics.ts","../../src/stores/analytics.store.ts","../../src/utils/string_utils.ts","../../src/utils/purchase_utils.tsx","../../src/providers/loading_indicator_provider.tsx","../../src/providers/maintenance_provider.tsx","../../src/providers/notification_provider.tsx","../../src/providers/point_log_provider.tsx","../../src/providers/popup_provider.tsx","../../src/providers/registration_provider.tsx","../../src/providers/zipcode_provider.tsx","../../src/providers/purchase_provider.tsx"],"sourcesContent":["import { Address, ErrorResponse, ServiceResponse } from '@bzbs/react-api-client';\nimport React, { createContext, useContext, useState } from 'react';\nimport { useBuzzebeesServiceContext } from './buzzebees_service_provider';\n\nexport type AddressContextType = {\n addresses: Address[];\n taxAddresses: Address[];\n isLoading: boolean;\n error: ErrorResponse | null;\n actions: {\n fetchAddresses: () => Promise<ServiceResponse<Address[]>>;\n addAddress: (address: AddressFormData) => Promise<ServiceResponse<Address>>;\n editAddress: (address: AddressFormData) => Promise<ServiceResponse<Address>>;\n deleteAddress: (rowKey: string) => Promise<ServiceResponse<any>>;\n fetchTaxAddresses: () => Promise<ServiceResponse<Address[]>>;\n addTaxAddress: (address: AddressFormData) => Promise<ServiceResponse<Address>>;\n editTaxAddress: (address: AddressFormData) => Promise<ServiceResponse<Address>>;\n deleteTaxAddress: (rowKey: string) => Promise<ServiceResponse<any>>;\n };\n};\n\nexport type AddressFormData = {\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\nconst AddressContext = createContext<AddressContextType>({\n addresses: [],\n taxAddresses: [],\n isLoading: false,\n error: null,\n actions: {\n fetchAddresses: async () => ({ type: 'client-error', message: 'Not implemented' }),\n addAddress: async () => ({ type: 'client-error', message: 'Not implemented' }),\n editAddress: async () => ({ type: 'client-error', message: 'Not implemented' }),\n deleteAddress: async () => ({ type: 'client-error', message: 'Not implemented' }),\n fetchTaxAddresses: async () => ({ type: 'client-error', message: 'Not implemented' }),\n addTaxAddress: async () => ({ type: 'client-error', message: 'Not implemented' }),\n editTaxAddress: async () => ({ type: 'client-error', message: 'Not implemented' }),\n deleteTaxAddress: async () => ({ type: 'client-error', message: 'Not implemented' }),\n },\n});\n\nexport function useAddressContext() {\n return useContext(AddressContext);\n}\n\nexport function AddressProvider({ children }: { children: React.ReactNode }) {\n const [addresses, setAddresses] = useState<Address[]>([]);\n const [taxAddresses, setTaxAddresses] = useState<Address[]>([]);\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<ErrorResponse | null>(null);\n\n const { bzbsService } = useBuzzebeesServiceContext();\n\n const fetchAddresses = async (): Promise<ServiceResponse<Address[]>> => {\n setIsLoading(true);\n const response = await bzbsService.addressApi.userAddresses();\n setIsLoading(false);\n\n if (response.type === 'success') {\n setAddresses(response.model);\n setError(null);\n } else {\n setError(response);\n }\n\n return response;\n };\n\n const addAddress = async (addressForm: AddressFormData): Promise<ServiceResponse<Address>> => {\n setIsLoading(true);\n const response = await bzbsService.addressApi.updateAddress({\n ...addressForm,\n rowKey: '',\n });\n setIsLoading(false);\n\n if (response.type === 'success') {\n fetchAddresses();\n setError(null);\n } else {\n setError(response);\n }\n\n return response;\n };\n\n const editAddress = async (addressForm: AddressFormData): Promise<ServiceResponse<Address>> => {\n setIsLoading(true);\n const response = await bzbsService.addressApi.updateAddress({\n ...addressForm,\n });\n setIsLoading(false);\n\n if (response.type === 'success') {\n fetchAddresses();\n setError(null);\n } else {\n setError(response);\n }\n\n return response;\n };\n\n const deleteAddress = async (rowKey: string): Promise<ServiceResponse<any>> => {\n setIsLoading(true);\n const response = await bzbsService.addressApi.deleteAddress({ rowKey });\n setIsLoading(false);\n\n if (response.type === 'success') {\n fetchAddresses();\n setError(null);\n } else {\n setError(response);\n }\n\n return response;\n };\n\n const fetchTaxAddresses = async (): Promise<ServiceResponse<Address[]>> => {\n setIsLoading(true);\n const response = await bzbsService.addressApi.userTaxAddresses();\n setIsLoading(false);\n\n if (response.type === 'success') {\n setTaxAddresses(response.model);\n setError(null);\n } else {\n setError(response);\n }\n\n return response;\n };\n\n const addTaxAddress = async (addressForm: AddressFormData): Promise<ServiceResponse<Address>> => {\n setIsLoading(true);\n const response = await bzbsService.addressApi.updateTaxAddress({\n ...addressForm,\n rowKey: '',\n });\n setIsLoading(false);\n\n if (response.type === 'success') {\n fetchTaxAddresses();\n setError(null);\n } else {\n setError(response);\n }\n\n return response;\n };\n\n const editTaxAddress = async (addressForm: AddressFormData): Promise<ServiceResponse<Address>> => {\n setIsLoading(true);\n const response = await bzbsService.addressApi.updateTaxAddress({\n ...addressForm,\n rowKey: addressForm.rowKey || '',\n });\n setIsLoading(false);\n\n if (response.type === 'success') {\n fetchTaxAddresses();\n setError(null);\n } else {\n setError(response);\n }\n\n return response;\n };\n\n const deleteTaxAddress = async (rowKey: string): Promise<ServiceResponse<any>> => {\n setIsLoading(true);\n const response = await bzbsService.addressApi.deleteTaxAddress({ rowKey });\n setIsLoading(false);\n\n if (response.type === 'success') {\n fetchTaxAddresses();\n setError(null);\n } else {\n setError(response);\n }\n\n return response;\n };\n\n return (\n <AddressContext.Provider\n value={{\n addresses,\n taxAddresses,\n isLoading,\n error,\n actions: {\n fetchAddresses,\n addAddress,\n editAddress,\n deleteAddress,\n fetchTaxAddresses,\n addTaxAddress,\n editTaxAddress,\n deleteTaxAddress,\n },\n }}\n >\n {children}\n </AddressContext.Provider>\n );\n}\n","import { BzbsService } from '@bzbs/react-api-client';\nimport React, { createContext, useContext } from 'react';\n\nexport type BuzzebeesServiceContextType = {\n appId: string;\n appName: string;\n bzbsService: BzbsService;\n urls: {\n webCallback: string;\n cart: string;\n };\n};\n\nexport const BuzzebeesServiceContext = createContext<BuzzebeesServiceContextType>({\n appId: '',\n appName: '',\n bzbsService: {} as BzbsService,\n urls: {\n webCallback: '',\n cart: '',\n },\n});\n\nexport function useBuzzebeesServiceContext() {\n return useContext(BuzzebeesServiceContext);\n}\n\nexport type BuzzebeesServiceProviderProps = {\n appId: string;\n appName: string;\n bzbsService: BzbsService;\n urls: {\n webCallback: string;\n cart: string;\n };\n children: React.ReactNode;\n};\n\nexport function BuzzebeesServiceProvider({\n appId,\n appName,\n bzbsService,\n urls,\n children,\n}: BuzzebeesServiceProviderProps) {\n return (\n <BuzzebeesServiceContext.Provider\n value={{\n appId,\n appName,\n urls,\n bzbsService,\n }}\n >\n {children}\n </BuzzebeesServiceContext.Provider>\n );\n}\n","import React, { ReactNode, createContext, useContext, useState } from 'react';\n\nexport type AlertRequest = {\n title: string;\n content: string;\n closeText?: string;\n onClose: () => void;\n};\n\nexport type AlertContextType = {\n isOpen: boolean;\n alertRequest: AlertRequest;\n openAlert: (request: AlertRequest) => void;\n closeAlert: () => void;\n};\n\nexport const AlertContext = createContext({\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n openAlert: (request: AlertRequest) => {},\n closeAlert: () => {},\n} as AlertContextType);\n\nexport const useAlertContext = () => {\n return useContext(AlertContext);\n};\n\nexport const AlertProvider = ({ children }: { children: ReactNode }) => {\n const [isAlertOpen, setIsAlertOpen] = useState(false);\n\n const [alertRequest, setAlertRequest] = useState<AlertRequest>({\n title: '',\n content: '',\n onClose: () => {},\n });\n\n const openAlert = (request: AlertRequest) => {\n setAlertRequest(request);\n setIsAlertOpen(true);\n };\n\n const closeAlert = () => {\n alertRequest.onClose();\n setIsAlertOpen(false);\n };\n\n return (\n <AlertContext.Provider\n value={{\n isOpen: isAlertOpen,\n alertRequest: alertRequest,\n openAlert: openAlert,\n closeAlert: closeAlert,\n }}\n >\n {children}\n </AlertContext.Provider>\n );\n};\n","import type { UserInfo } from 'matomo-tracker-react-native';\nimport MatomoTracker, { MatomoProvider, useMatomo } from 'matomo-tracker-react-native';\nimport React, { createContext, useContext, useState } from 'react';\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 AnalyticsContextType = {\n isInitialized: boolean;\n isEnabled: boolean;\n userId?: string;\n presetUserInfo?: UserInfo;\n actions: {\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};\n\nexport const AnalyticsContext = createContext<AnalyticsContextType>({\n isInitialized: false,\n isEnabled: true,\n actions: {\n setEnabled: () => {},\n setPresetUserInfo: () => {},\n clearPresetUserInfo: () => {},\n trackAppStart: async () => {},\n trackEvent: async () => {},\n trackScreenView: async () => {},\n trackAction: async () => {},\n trackSiteSearch: async () => {},\n trackLink: async () => {},\n trackDownload: async () => {},\n setUserId: () => {},\n setCustomDimension: () => {},\n reset: () => {},\n },\n});\n\nexport function useAnalyticsContext() {\n return useContext(AnalyticsContext);\n}\n\n// Inner component that has access to Matomo\nfunction AnalyticsInner({\n children,\n userId,\n enableLogging,\n}: {\n children: React.ReactNode;\n userId?: string;\n enableLogging?: boolean;\n}) {\n const { trackEvent, trackScreenView, trackAppStart, trackAction, trackSiteSearch, trackLink, trackDownload } =\n useMatomo();\n const [isEnabled, setIsEnabled] = useState(true);\n const [userIdState, setUserIdState] = useState<string | undefined>(userId);\n const [presetUserInfo, setPresetUserInfoState] = useState<UserInfo | undefined>(undefined);\n const [log] = useState(enableLogging || false);\n\n const handleSetEnabled = (enabled: boolean) => {\n setIsEnabled(enabled);\n };\n\n const handleSetPresetUserInfo = (userInfo: UserInfo) => {\n setPresetUserInfoState(userInfo);\n };\n\n const handleClearPresetUserInfo = () => {\n setPresetUserInfoState(undefined);\n };\n\n const handleTrackAppStart = async (userInfo?: UserInfo) => {\n if (!userIdState || !isEnabled) {\n if (log) {\n console.debug('Analytics: Track App Start skipped - not initialized or disabled');\n }\n return;\n }\n\n try {\n // Merge preset userInfo with provided userInfo\n const mergedUserInfo = { ...presetUserInfo, ...userInfo };\n\n await trackAppStart({\n userInfo: Object.keys(mergedUserInfo).length > 0 ? mergedUserInfo : undefined,\n });\n\n if (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 const handleTrackEvent = async (params: AnalyticsEventParams) => {\n if (!userIdState || !isEnabled) {\n if (log) {\n console.debug('Analytics: Track Event skipped - not initialized or disabled', params);\n }\n return;\n }\n\n try {\n // Merge preset userInfo with provided userInfo\n const mergedUserInfo = { ...presetUserInfo, ...params.userInfo };\n\n await 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 (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 const handleTrackScreenView = async (params: AnalyticsPageViewParams) => {\n if (!userIdState || !isEnabled) {\n if (log) {\n console.debug('Analytics: Track Screen View skipped - not initialized or disabled', params);\n }\n return;\n }\n\n try {\n // Merge preset userInfo with provided userInfo\n const mergedUserInfo = { ...presetUserInfo, ...params.userInfo };\n\n await trackScreenView({\n name: params.name,\n userInfo: Object.keys(mergedUserInfo).length > 0 ? mergedUserInfo : undefined,\n });\n\n if (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 const handleTrackAction = async (params: AnalyticsPageViewParams) => {\n if (!userIdState || !isEnabled) {\n if (log) {\n console.debug('Analytics: Track Action skipped - not initialized or disabled', params);\n }\n return;\n }\n\n try {\n // Merge preset userInfo with provided userInfo\n const mergedUserInfo = { ...presetUserInfo, ...params.userInfo };\n\n await trackAction({\n name: params.name,\n userInfo: Object.keys(mergedUserInfo).length > 0 ? mergedUserInfo : undefined,\n });\n\n if (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 const handleTrackSiteSearch = async (params: {\n keyword: string;\n category?: string;\n count?: number;\n userInfo?: UserInfo;\n }) => {\n if (!userIdState || !isEnabled) {\n if (log) {\n console.debug('Analytics: Track Site Search skipped - not initialized or disabled', params);\n }\n return;\n }\n\n try {\n // Merge preset userInfo with provided userInfo\n const mergedUserInfo = { ...presetUserInfo, ...params.userInfo };\n\n await 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 (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 const handleTrackLink = async (params: { link: string; userInfo?: UserInfo }) => {\n if (!userIdState || !isEnabled) {\n if (log) {\n console.debug('Analytics: Track Link skipped - not initialized or disabled', params);\n }\n return;\n }\n\n try {\n // Merge preset userInfo with provided userInfo\n const mergedUserInfo = { ...presetUserInfo, ...params.userInfo };\n\n await trackLink({\n link: params.link,\n userInfo: Object.keys(mergedUserInfo).length > 0 ? mergedUserInfo : undefined,\n });\n\n if (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 const handleTrackDownload = async (params: { download: string; userInfo?: UserInfo }) => {\n if (!userIdState || !isEnabled) {\n if (log) {\n console.debug('Analytics: Track Download skipped - not initialized or disabled', params);\n }\n return;\n }\n\n try {\n // Merge preset userInfo with provided userInfo\n const mergedUserInfo = { ...presetUserInfo, ...params.userInfo };\n\n await trackDownload({\n download: params.download,\n userInfo: Object.keys(mergedUserInfo).length > 0 ? mergedUserInfo : undefined,\n });\n\n if (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 const handleSetUserId = (userId: string | null) => {\n setUserIdState(userId || undefined);\n\n // Update preset userInfo with the new userId\n if (userId) {\n setPresetUserInfoState((prev) => ({\n ...prev,\n uid: userId,\n }));\n } else {\n // Remove uid from preset userInfo if userId is null\n setPresetUserInfoState((prev) => {\n if (prev?.uid) {\n const updatedUserInfo = { ...prev };\n delete updatedUserInfo.uid;\n return Object.keys(updatedUserInfo).length > 0 ? updatedUserInfo : undefined;\n }\n return prev;\n });\n }\n\n if (log) {\n console.debug('Analytics: User ID updated in preset userInfo', userId);\n }\n };\n\n const handleSetCustomDimension = (id: number, value: string) => {\n if (!presetUserInfo) {\n setPresetUserInfoState({ [`dimension${id}`]: value });\n } else {\n setPresetUserInfoState({\n ...presetUserInfo,\n [`dimension${id}`]: value,\n });\n }\n\n if (log) {\n console.debug('Analytics: Custom dimension set in preset userInfo', { id, value });\n }\n };\n\n const reset = () => {\n setUserIdState(undefined);\n setPresetUserInfoState(undefined);\n setIsEnabled(true);\n\n console.debug('Analytics: Provider reset successfully');\n };\n\n const contextValue: AnalyticsContextType = {\n isInitialized: true, // Always true since initialization is handled by MatomoProvider\n isEnabled,\n userId: userIdState,\n presetUserInfo,\n actions: {\n setEnabled: handleSetEnabled,\n setPresetUserInfo: handleSetPresetUserInfo,\n clearPresetUserInfo: handleClearPresetUserInfo,\n trackAppStart: handleTrackAppStart,\n trackEvent: handleTrackEvent,\n trackScreenView: handleTrackScreenView,\n trackAction: handleTrackAction,\n trackSiteSearch: handleTrackSiteSearch,\n trackLink: handleTrackLink,\n trackDownload: handleTrackDownload,\n setUserId: handleSetUserId,\n setCustomDimension: handleSetCustomDimension,\n reset,\n },\n };\n\n return <AnalyticsContext.Provider value={contextValue}>{children}</AnalyticsContext.Provider>;\n}\n\nexport type AnalyticsProviderProps = {\n children: React.ReactNode;\n disabled?: boolean;\n instance?: MatomoTracker;\n userId?: string;\n enableLogging?: boolean;\n};\n\nexport function AnalyticsProvider({\n children,\n disabled = false,\n instance,\n userId,\n enableLogging = false,\n}: AnalyticsProviderProps) {\n // If analytics is disabled, provide a no-op context\n if (disabled) {\n const noOpContextValue: AnalyticsContextType = {\n isInitialized: false,\n isEnabled: false,\n actions: {\n setEnabled: () => {},\n setPresetUserInfo: () => {},\n clearPresetUserInfo: () => {},\n trackAppStart: async () => {},\n trackEvent: async () => {},\n trackScreenView: async () => {},\n trackAction: async () => {},\n trackSiteSearch: async () => {},\n trackLink: async () => {},\n trackDownload: async () => {},\n setUserId: () => {},\n setCustomDimension: () => {},\n reset: () => {},\n },\n };\n\n return <AnalyticsContext.Provider value={noOpContextValue}>{children}</AnalyticsContext.Provider>;\n }\n\n // Use provided instance or create a default placeholder\n const matomoInstance =\n instance ||\n new MatomoTracker({\n urlBase: 'https://placeholder.com',\n siteId: 1,\n disabled: true, // Disabled until properly initialized\n });\n\n return (\n <MatomoProvider instance={matomoInstance}>\n <AnalyticsInner userId={userId} enableLogging={enableLogging}>\n {children}\n </AnalyticsInner>\n </MatomoProvider>\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 React, { createContext, useContext, useRef, useState } from 'react';\nimport { LoginResponseHandler } from '../types';\nimport { useBuzzebeesServiceContext } from './buzzebees_service_provider';\nimport { useAppLocaleContext } from './locale_provider';\nimport { useAnalyticsContext } from './analytics_provider';\n\nexport type AuthContextType = {\n isInitialized: boolean;\n versionData?: Version | null;\n isLoading: boolean;\n token: string | null;\n isLoadingToken: boolean;\n isLoggedIn: boolean;\n error: ErrorResponse | null;\n actions: {\n init(uuid: string, appId: string, deviceToken: string): void;\n setUUID(value: string): void;\n setAppId(value: string): void;\n setDeviceToken(value: string): void;\n setClientVersion(value: string): void;\n setOs(value: string): void;\n setPlatform(value: string): void;\n setError(value: unknown): void;\n setLoginResponseHandler(fn: LoginResponseHandler): void;\n clearData: () => 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) => 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 };\n};\n\nexport const AuthContext = createContext({\n isInitialized: false,\n authData: null,\n versionData: null,\n isLoading: false,\n isLoggedIn: false,\n error: null,\n token: null,\n isLoadingToken: false,\n actions: {\n init: () => {},\n setUUID: () => {},\n setAppId: () => {},\n setDeviceToken: () => {},\n setClientVersion: () => {},\n setOs: () => {},\n setPlatform: () => {},\n setError: () => {},\n setLoginResponseHandler: () => {},\n clearData: () => {},\n loginWithUsernamePassword: async () => ({ type: 'client-error', message: 'Not implemented' }),\n loginWithGoogle: async () => ({ type: 'client-error', message: 'Not implemented' }),\n loginWithFacebook: async () => ({ type: 'client-error', message: 'Not implemented' }),\n loginWithApple: async () => ({ type: 'client-error', message: 'Not implemented' }),\n loginWithUUID: async () => ({ type: 'client-error', message: 'Not implemented' }),\n logout: async () => ({ type: 'client-error', message: 'Not implemented' }),\n forgetPassword: async () => ({ type: 'client-error', message: 'Not implemented' }),\n resetPassword: async () => ({ type: 'client-error', message: 'Not implemented' }),\n sendOtp: async () => ({ type: 'client-error', message: 'Not implemented' }),\n validateOtp: async () => ({ type: 'client-error', message: 'Not implemented' }),\n confirmOtp: async () => ({ type: 'client-error', message: 'Not implemented' }),\n resume: async () => ({ type: 'client-error', message: 'Not implemented' }),\n version: async () => ({ type: 'client-error', message: 'Not implemented' }),\n },\n} as AuthContextType);\n\nexport function useAuthContext() {\n return useContext(AuthContext);\n}\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 function AuthProvider({\n tokenFunctions,\n children,\n}: {\n tokenFunctions: TokenFunctions;\n children: React.ReactNode;\n}) {\n const [versionData, setVersionData] = useState<Version | null>(null);\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<ErrorResponse | null>(null);\n const [isLoggedIn, setIsLoggedIn] = useState(false);\n const [isLoadingToken, setIsLoadingToken] = useState(false);\n const [token, setToken] = useState<string | null>(null);\n const [isInitialized, setIsInitialized] = useState(false);\n\n const [loginResponseHandler, setLoginResponseHandler] = useState<LoginResponseHandler>(() => {});\n\n const { bzbsService } = useBuzzebeesServiceContext();\n const { localeId } = useAppLocaleContext();\n const { actions: analyticsActions } = useAnalyticsContext();\n const uuid = useRef<string>('');\n const appId = useRef<string>('');\n const deviceToken = useRef<string>('');\n const clientVersion = useRef<string>('');\n const os = useRef<string>('');\n const platform = useRef<string>('');\n\n const setUUID = (value: string) => {\n uuid.current = value;\n };\n\n const setAppId = (value: string) => {\n appId.current = value;\n };\n\n const setDeviceToken = (value: string) => {\n deviceToken.current = value;\n };\n\n const setClientVersion = (value: string) => {\n clientVersion.current = value;\n };\n\n const setOs = (value: string) => {\n os.current = value;\n };\n\n const setPlatform = (value: string) => {\n platform.current = value;\n };\n\n const init = (uuid: string, appId: string, deviceToken: string) => {\n setUUID(uuid);\n setAppId(appId);\n setDeviceToken(deviceToken);\n checkLoggedIn();\n };\n\n const checkLoggedIn = async () => {\n try {\n setIsLoadingToken(true);\n const savedToken = await tokenFunctions.getToken();\n setIsLoadingToken(false);\n if (savedToken) {\n setIsLoggedIn(true);\n } else {\n setIsLoggedIn(false);\n }\n setToken(savedToken);\n } catch (error) {\n setIsLoggedIn(false);\n }\n\n setIsInitialized(true);\n };\n\n const clearData = () => {\n setVersionData(null);\n setError(null);\n setIsLoading(false);\n setIsLoggedIn(false);\n setToken(null);\n };\n\n const login = async (\n loginFn: () => Promise<ServiceResponse<LoginResponse>>\n ): Promise<ServiceResponse<LoginResponse>> => {\n setIsLoading(true);\n const response = await loginFn();\n setIsLoading(false);\n\n if (response.type === 'success') {\n tokenFunctions.setToken(response.model.token);\n setToken(response.model.token);\n setIsLoggedIn(true);\n setError(null);\n loginResponseHandler(response.model);\n analyticsActions.trackEvent({\n action: 'on_click',\n name: 'login_success',\n category: 'login',\n });\n } else {\n setError(response);\n }\n\n return response;\n };\n\n const loginWithUsernamePassword = async (\n username: string,\n password: string\n ): Promise<ServiceResponse<LoginResponse>> => {\n const response = await login(() =>\n bzbsService.authApi.usernamePasswordLogin({\n username: username,\n password: password,\n appId: appId.current,\n uuid: uuid.current,\n deviceToken: deviceToken.current,\n clientVersion: clientVersion.current,\n os: os.current,\n platform: platform.current,\n deviceLocale: localeId.toString(),\n deviceNotificationEnabled: true,\n })\n );\n\n return response;\n };\n\n const loginWithGoogle = async (token: string): Promise<ServiceResponse<LoginResponse>> => {\n const response = await login(() =>\n bzbsService.authApi.googleLogin({\n idToken: token,\n appId: appId.current,\n uuid: uuid.current,\n deviceToken: deviceToken.current,\n clientVersion: clientVersion.current,\n os: os.current,\n platform: platform.current,\n deviceLocale: localeId.toString(),\n deviceNotificationEnabled: true,\n })\n );\n\n return response;\n };\n\n const loginWithFacebook = async (token: string): Promise<ServiceResponse<LoginResponse>> => {\n const response = await login(() =>\n bzbsService.authApi.facebookLogin({\n accessToken: token,\n appId: appId.current,\n uuid: uuid.current,\n deviceToken: deviceToken.current,\n clientVersion: clientVersion.current,\n os: os.current,\n platform: platform.current,\n deviceLocale: localeId.toString(),\n deviceNotificationEnabled: true,\n })\n );\n\n return response;\n };\n\n const loginWithApple = async (token: string, refreshToken: string): Promise<ServiceResponse<LoginResponse>> => {\n const response = await login(() =>\n bzbsService.authApi.appleLogin({\n idToken: token,\n refreshToken: refreshToken,\n appId: appId.current,\n uuid: uuid.current,\n deviceToken: deviceToken.current,\n clientVersion: clientVersion.current,\n os: os.current,\n platform: platform.current,\n deviceLocale: localeId.toString(),\n deviceNotificationEnabled: true,\n })\n );\n\n return response;\n };\n\n const loginWithUUID = async (): Promise<ServiceResponse<LoginResponse>> => {\n const response = await login(() =>\n bzbsService.authApi.deviceLogin({\n appId: appId.current,\n uuid: uuid.current,\n deviceToken: deviceToken.current,\n clientVersion: clientVersion.current,\n os: os.current,\n platform: platform.current,\n deviceLocale: localeId.toString(),\n deviceNotificationEnabled: true,\n })\n );\n\n return response;\n };\n\n const logout = async (): Promise<ServiceResponse<unknown>> => {\n setIsLoading(true);\n const response = await bzbsService.authApi.logout({ uuid: uuid.current });\n setIsLoading(false);\n tokenFunctions.removeToken();\n setToken(null);\n setIsLoggedIn(false);\n setError(null);\n return response;\n };\n\n const forgetPassword = async (\n contact: string,\n type: 'email' | 'contact_number'\n ): Promise<ServiceResponse<ForgetPasswordResponse>> => {\n setIsLoading(true);\n const response = await bzbsService.authApi.forgetPassword({ contact: contact, type: type });\n setIsLoading(false);\n return response;\n };\n\n const resetPassword = async (\n contact: string,\n otp: string,\n refCode: string,\n newPassword: string\n ): Promise<ServiceResponse<StatusResponse>> => {\n setIsLoading(true);\n const response = await bzbsService.authApi.resetPassword({\n contact: contact,\n refCode: refCode,\n otp: otp,\n newPassword: newPassword,\n });\n setIsLoading(false);\n return response;\n };\n\n const sendOtp = async (contact: string): Promise<ServiceResponse<OtpResponse>> => {\n setIsLoading(true);\n const response = await bzbsService.authApi.otp({\n uuid: uuid.current,\n appId: appId.current,\n contactNumber: contact,\n });\n setIsLoading(false);\n return response;\n };\n\n const validateOtp = async (\n contact: string,\n otp: string,\n refCode: string,\n channel: string\n ): Promise<ServiceResponse<ValidateOtpResponse>> => {\n setIsLoading(true);\n const response = await bzbsService.authApi.validateOtp({\n appId: appId.current,\n otp: otp,\n refCode: refCode,\n contactNumber: contact,\n use: false,\n channel: channel,\n });\n setIsLoading(false);\n return response;\n };\n\n const confirmOtp = async (\n contact: string,\n otp: string,\n refCode: string\n ): Promise<ServiceResponse<ConfirmOtpResponse>> => {\n setIsLoading(true);\n const response = await bzbsService.authApi.confirmOtp({ otp: otp, refCode: refCode, contactNumber: contact });\n setIsLoading(false);\n return response;\n };\n\n const resume = async (clientVersion: string): Promise<ServiceResponse<ResumeResponse>> => {\n setIsLoading(true);\n const response = await bzbsService.authApi.resume({\n uuid: uuid.current,\n appId: appId.current,\n clientVersion: clientVersion,\n deviceToken: deviceToken.current,\n });\n setIsLoading(false);\n return response;\n };\n\n const version = async (clientVersion: string): Promise<ServiceResponse<Version>> => {\n setIsLoading(true);\n const response = await bzbsService.authApi.version(clientVersion);\n if (response.type === 'success') {\n setVersionData(response.model);\n }\n setIsLoading(false);\n return response;\n };\n\n return (\n <AuthContext.Provider\n value={{\n isInitialized,\n versionData,\n isLoading,\n isLoggedIn,\n token,\n isLoadingToken,\n error,\n actions: {\n init,\n setUUID,\n setAppId,\n setDeviceToken,\n setClientVersion,\n setOs,\n setPlatform,\n setError,\n setLoginResponseHandler,\n clearData,\n loginWithUsernamePassword,\n loginWithGoogle,\n loginWithFacebook,\n loginWithApple,\n loginWithUUID,\n logout,\n forgetPassword,\n resetPassword,\n sendOtp,\n validateOtp,\n confirmOtp,\n resume,\n version,\n },\n }}\n >\n {children}\n </AuthContext.Provider>\n );\n}\n","import React, { createContext, ReactNode, useContext, useState } from 'react';\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 LocaleContextType = {\n appLocale: AppLocale;\n locale: string;\n localeId: number;\n setAppLocale: (locale: AppLocale | string) => void;\n};\n\nexport const LocaleContext = createContext({\n appLocale: EN,\n locale: 'en',\n localeId: 1033,\n setAppLocale: () => {},\n} as LocaleContextType);\n\nexport const useAppLocaleContext = () => {\n return useContext(LocaleContext);\n};\n\nexport const AppLocaleProvider = ({ initLocale, children }: { initLocale: AppLocale; children: ReactNode }) => {\n const [locale, setLocale] = useState<AppLocale>(initLocale);\n\n const setAppLocale = (locale: AppLocale | string) => {\n if (typeof locale === 'string') {\n setLocale(findBestLocaleFromString(locale));\n } else {\n setLocale(locale);\n }\n };\n\n return (\n <LocaleContext.Provider\n value={{\n appLocale: locale,\n locale: locale.locale,\n localeId: locale.localeId,\n setAppLocale: setAppLocale,\n }}\n >\n {children}\n </LocaleContext.Provider>\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 {\n Address,\n CampaignDetail,\n CartCountResponse,\n ErrorResponse,\n RedeemResponse,\n ServiceResponse,\n Style,\n UseCampaignResponse,\n} from '@bzbs/react-api-client';\nimport React, { createContext, useContext, useEffect, useRef, useState } from 'react';\nimport { campaignInterfaceType, campaignPointType, campaignType } from '../constant';\nimport { useBuzzebeesServiceContext } from './buzzebees_service_provider';\nimport { useAppLocaleContext } from './locale_provider';\nimport { useUserContext } from './user_provider';\nimport { useAnalyticsContext } from './analytics_provider';\n\nexport type CampaignButtonType =\n | 'redeem'\n | 'get_points'\n | 'add_to_cart'\n | 'survey'\n | 'website'\n | 'draw'\n | 'donate'\n | 'delivery';\n\nexport type CampaignDetailButtonState = {\n enabled: boolean;\n type: CampaignButtonType;\n display: boolean;\n};\n\nexport type CampaignState =\n | 'redeemable'\n | 'point_not_enough'\n | 'expired'\n | 'cool_down'\n | 'fail_in_condition'\n | 'sold_out'\n | 'redeemed';\n\nexport type AfterRedeemDestination = 'delivery' | 'draw' | 'code' | 'get_points';\n\nexport type AfterRedeem = {\n destination: AfterRedeemDestination;\n redeemData: RedeemResponse;\n clear: () => void;\n};\n\nexport type AfterUse = {\n useData: UseCampaignResponse;\n clear: () => void;\n};\n\nexport type CampaignDetailContextType = {\n data: CampaignDetail | null;\n style: Style | null;\n subStyle: Style | null;\n quantity: number;\n totalPrice: number;\n deliveryAddress: Address | null;\n afterRedeem: AfterRedeem | null;\n afterUse: AfterUse | null;\n buttonState: CampaignDetailButtonState;\n campaignState: CampaignState;\n interfaceWebsite: string | null;\n isLoading: boolean;\n error: ErrorResponse | null;\n actions: {\n setError: (error: ErrorResponse) => void;\n fetchData: (id: string) => Promise<ServiceResponse<CampaignDetail>>;\n redeem: (\n addressOverride?: Address,\n options?: { [key: string]: unknown }\n ) => Promise<ServiceResponse<RedeemResponse>>;\n use: () => Promise<ServiceResponse<UseCampaignResponse>>;\n addToFavorite(): Promise<ServiceResponse<unknown>>;\n removeFromFavorite(): Promise<ServiceResponse<unknown>>;\n setStyle: (style: Style) => void;\n setSubStyle: (style: Style) => void;\n setQuantity: (quantity: number) => void;\n setDeliveryAddress: (address: Address) => void;\n addToCart: () => Promise<ServiceResponse<CartCountResponse>>;\n clear: () => void;\n };\n};\n\nexport const CampaignDetailContext = createContext({\n data: null,\n style: null,\n subStyle: null,\n quantity: 1,\n totalPrice: 0,\n deliveryAddress: null,\n afterRedeem: null,\n afterUse: null,\n buttonState: { enabled: false, type: 'redeem', display: false },\n campaignState: 'redeemable',\n interfaceWebsite: null,\n isLoading: false,\n error: null,\n actions: {\n setError: () => {},\n fetchData: async () => ({ type: 'client-error', message: 'Not implemented' }),\n redeem: async () => ({ type: 'client-error', message: 'Not implemented' }),\n use: async () => ({ type: 'client-error', message: 'Not implemented' }),\n addToFavorite: async () => ({ type: 'client-error', message: 'Not implemented' }),\n removeFromFavorite: async () => ({ type: 'client-error', message: 'Not implemented' }),\n setStyle: () => {},\n setSubStyle: () => {},\n setQuantity: () => {},\n setDeliveryAddress: () => {},\n addToCart: async () => ({ type: 'client-error', message: 'Not implemented' }),\n clear: () => {},\n },\n} as CampaignDetailContextType);\n\nexport function useCampaignDetailContext() {\n return useContext(CampaignDetailContext);\n}\n\nexport function CampaignDetailProvider({ children }: { children: React.ReactNode }) {\n const campaignId = useRef<string | undefined>(undefined);\n const [data, setData] = useState<CampaignDetail | null>(null);\n const [afterRedeem, setAfterRedeem] = useState<AfterRedeem | null>(null);\n const [afterUse, setAfterUse] = useState<AfterUse | null>(null);\n const [campaignState, setCampaignState] = useState<CampaignState>('redeemable');\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<ErrorResponse | null>(null);\n\n const { localeId } = useAppLocaleContext();\n const { actions: analyticsActions } = useAnalyticsContext();\n\n const [style, setStyle] = useState<Style | null>(null);\n const [subStyle, setSubStyle] = useState<Style | null>(null);\n const [quantity, setQuantity] = useState(1);\n const [totalPrice, setTotalPrice] = useState(0);\n const [deliveryAddress, setDeliveryAddress] = useState<Address | null>(null);\n\n const interfaceWebsite = useRef<string | null>(null);\n\n const [buttonState, setButtonState] = useState<CampaignDetailButtonState>({\n enabled: false,\n type: 'redeem',\n display: false,\n });\n\n const { bzbsService } = useBuzzebeesServiceContext();\n const user = useUserContext();\n const userData = user.user;\n const userPoints = user.points;\n\n useEffect(() => {\n if (data && userData) {\n updateButtonState();\n }\n }, [data, userData, userPoints, style, subStyle, quantity]);\n\n useEffect(() => {\n if (data && userData) {\n checkCondition();\n }\n }, [data, userData, userPoints]);\n\n useEffect(() => {\n if (data && style && subStyle) {\n calculatePrice();\n } else if (data) {\n if (style === null) {\n setSubStyle(null);\n }\n } else {\n setTotalPrice(0);\n setStyle(null);\n setSubStyle(null);\n }\n }, [data, style, subStyle, quantity]);\n\n const fetchData = async (id: string): Promise<ServiceResponse<CampaignDetail>> => {\n campaignId.current = id;\n\n setIsLoading(true);\n\n await user.actions.fetchUser();\n await user.actions.fetchPoint();\n await user.actions.fetchCartCount();\n\n const response = await bzbsService.campaignApi.campaignDetails({ id, deviceLocale: localeId });\n setIsLoading(false);\n\n if (response.type === 'success') {\n setData(response.model);\n analyticsActions.trackEvent({\n action: 'on_click',\n name: 'view_campaign',\n category: 'campaign_list',\n });\n } else {\n setError(response);\n }\n\n return response;\n };\n\n const updateButtonState = () => {\n if (!data) {\n return;\n }\n\n const type = data.Type ?? 0;\n const pointType = data.PointType ?? campaignPointType.use;\n\n const pointPerUnit = data.PointPerUnit ?? 0;\n let pointEnough = true;\n\n if (pointType === campaignPointType.use && pointPerUnit > userPoints) {\n pointEnough = false;\n }\n\n let buttonType: CampaignButtonType = 'redeem';\n let display = true;\n let canAddToCart = true;\n\n const nonRedeemable = [campaignType.event, campaignType.media, campaignType.news];\n\n switch (type) {\n case campaignType.buy:\n