import CryptoJS from 'crypto-js'; import { encryptedStorage } from '@/utils/storage'; export const ACTIVE_QR_URL_CACHE_KEY = 'cashier:property:active-url'; export const ACTIVE_QR_HASH_CACHE_KEY = 'cashier:property:active-url-hash'; const decodeOption = (value?: string) => { if (!value) return ''; try { return decodeURIComponent(value); } catch (error) { return value; } }; export const resolveMerchantUrlFromOptions = (options: Record) => { return decodeOption(options.url || options.qr_url || ''); }; const readQueryParam = (raw: string, key: string) => { const match = raw.match(new RegExp(`[?&]${key}=([^&]+)`)); return match ? decodeOption(match[1]) : ''; }; export const resolveMerchantUrlFromScanResult = (raw: string) => { const text = (raw || '').trim(); if (!text) return ''; if (/^https?:\/\//i.test(text)) { return text; } const fromUrl = readQueryParam(text, 'url') || readQueryParam(text, 'qr_url'); if (fromUrl) return fromUrl; const fromQ = readQueryParam(text, 'q'); if (fromQ) return resolveMerchantUrlFromScanResult(fromQ); return ''; }; export const getMerchantUrlHash = (merchantUrl: string) => { return CryptoJS.SHA256(merchantUrl).toString(); }; export const getPropertyBindingCacheKeyByHash = (hash: string) => { // Hash key keeps cache key short/stable and avoids raw URL special characters. return `cashier:property:binding:${hash}`; }; export const getSupplierCacheKeyByHash = (hash: string) => { return `cashier:supplier:detail:${hash}`; }; export const getPropertyBindingCacheKey = (merchantUrl: string) => { return getPropertyBindingCacheKeyByHash(getMerchantUrlHash(merchantUrl)); }; export const getSupplierCacheKey = (merchantUrl: string) => { return getSupplierCacheKeyByHash(getMerchantUrlHash(merchantUrl)); }; export const syncActiveMerchantContext = (merchantUrl: string) => { const currentHash = getMerchantUrlHash(merchantUrl); const previousHash = encryptedStorage.get(ACTIVE_QR_HASH_CACHE_KEY) || ''; encryptedStorage.set(ACTIVE_QR_URL_CACHE_KEY, merchantUrl); encryptedStorage.set(ACTIVE_QR_HASH_CACHE_KEY, currentHash); return { currentHash, previousHash, switched: Boolean(previousHash && previousHash !== currentHash) }; };