feat(loyalty): fix Google Wallet integration and improve enrollment flow
- Fix Google Wallet class creation: add required issuerName field (merchant name), programLogo with default logo fallback, hexBackgroundColor default - Add default loyalty logo assets (200px + 512px) for programs without custom logos - Smart retry: skip retries on 400/401/403/404 client errors (not transient) - Fix enrollment success page: use sessionStorage for wallet URLs instead of authenticated API call (self-enrolled customers have no session) - Hide wallet section on success page when no wallet URLs available - Wire up T&C modal on enrollment page with program.terms_text - Add startup validation for Google/Apple Wallet configs in lifespan - Add admin wallet status dashboard endpoint and UI (moved to service layer) - Fix Apple Wallet push notifications with real APNs HTTP/2 implementation - Fix docs: correct enrollment URLs (port, path segments, /v1 prefix) - Fix test assertion: !loyalty-enroll! → !enrollment! Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -33,6 +33,10 @@ function adminLoyaltyAnalytics() {
|
||||
showMerchantDropdown: false,
|
||||
searchingMerchants: false,
|
||||
|
||||
// Wallet integration status
|
||||
walletStatus: null,
|
||||
walletStatusLoading: false,
|
||||
|
||||
loading: false,
|
||||
error: null,
|
||||
|
||||
@@ -59,6 +63,7 @@ function adminLoyaltyAnalytics() {
|
||||
window._loyaltyAnalyticsInitialized = true;
|
||||
|
||||
await this.loadStats();
|
||||
await this.loadWalletStatus();
|
||||
loyaltyAnalyticsLog.info('=== LOYALTY ANALYTICS PAGE INITIALIZATION COMPLETE ===');
|
||||
},
|
||||
|
||||
@@ -166,6 +171,21 @@ function adminLoyaltyAnalytics() {
|
||||
await this.loadStats();
|
||||
},
|
||||
|
||||
async loadWalletStatus() {
|
||||
this.walletStatusLoading = true;
|
||||
try {
|
||||
const response = await apiClient.get('/admin/loyalty/wallet-status');
|
||||
if (response) {
|
||||
this.walletStatus = response;
|
||||
loyaltyAnalyticsLog.info('Wallet status loaded');
|
||||
}
|
||||
} catch (error) {
|
||||
loyaltyAnalyticsLog.error('Failed to load wallet status:', error);
|
||||
} finally {
|
||||
this.walletStatusLoading = false;
|
||||
}
|
||||
},
|
||||
|
||||
formatNumber(num) {
|
||||
if (num === null || num === undefined) return '0';
|
||||
return new Intl.NumberFormat('en-US').format(num);
|
||||
|
||||
BIN
app/modules/loyalty/static/shared/img/default-logo-200.png
Normal file
BIN
app/modules/loyalty/static/shared/img/default-logo-200.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
BIN
app/modules/loyalty/static/shared/img/default-logo-512.png
Normal file
BIN
app/modules/loyalty/static/shared/img/default-logo-512.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
@@ -25,6 +25,7 @@ function customerLoyaltyEnroll() {
|
||||
enrolled: false,
|
||||
enrolledCard: null,
|
||||
error: null,
|
||||
showTerms: false,
|
||||
|
||||
async init() {
|
||||
console.log('Customer loyalty enroll initializing...');
|
||||
@@ -73,8 +74,13 @@ function customerLoyaltyEnroll() {
|
||||
if (response) {
|
||||
const cardNumber = response.card?.card_number || response.card_number;
|
||||
console.log('Enrollment successful:', cardNumber);
|
||||
// Redirect to success page - extract base path from current URL
|
||||
// Current page is at /storefront/loyalty/join, redirect to /storefront/loyalty/join/success
|
||||
|
||||
// Store wallet URLs for the success page (no auth needed)
|
||||
if (response.wallet_urls) {
|
||||
sessionStorage.setItem('loyalty_wallet_urls', JSON.stringify(response.wallet_urls));
|
||||
}
|
||||
|
||||
// Redirect to success page
|
||||
const currentPath = window.location.pathname;
|
||||
const successUrl = currentPath.replace(/\/join\/?$/, '/join/success') +
|
||||
'?card=' + encodeURIComponent(cardNumber);
|
||||
|
||||
Reference in New Issue
Block a user