From 467b1510f46fc199e65f187bc2cd88dfa8db03c8 Mon Sep 17 00:00:00 2001 From: Samir Boulahtit Date: Sun, 22 Feb 2026 22:53:05 +0100 Subject: [PATCH] fix: use apiClient instead of httponly cookie in merchant stores/profile pages The merchant_token cookie is httponly, so JS cannot read it via document.cookie. This caused getToken() to return null, redirecting users to login, which then bounced back to dashboard. Co-Authored-By: Claude Opus 4.6 --- .../templates/tenancy/merchant/profile.html | 36 ++----------------- .../templates/tenancy/merchant/stores.html | 21 +---------- 2 files changed, 3 insertions(+), 54 deletions(-) diff --git a/app/modules/tenancy/templates/tenancy/merchant/profile.html b/app/modules/tenancy/templates/tenancy/merchant/profile.html index 10ecb218..c8e29bbf 100644 --- a/app/modules/tenancy/templates/tenancy/merchant/profile.html +++ b/app/modules/tenancy/templates/tenancy/merchant/profile.html @@ -151,28 +151,9 @@ function merchantProfile() { this.loadProfile(); }, - getToken() { - const match = document.cookie.match(/(?:^|;\s*)merchant_token=([^;]*)/); - return match ? decodeURIComponent(match[1]) : null; - }, - async loadProfile() { - const token = this.getToken(); - if (!token) { - window.location.href = '/merchants/login'; - return; - } - try { - const resp = await fetch('/api/v1/merchants/account/profile', { - headers: { 'Authorization': `Bearer ${token}` } - }); - if (resp.status === 401) { - window.location.href = '/merchants/login'; - return; - } - if (!resp.ok) throw new Error('Failed to load profile'); - const data = await resp.json(); + const data = await apiClient.get('/merchants/account/profile'); this.form.name = data.name || ''; this.form.contact_email = data.contact_email || data.email || ''; @@ -193,22 +174,9 @@ function merchantProfile() { this.error = null; this.successMessage = null; - const token = this.getToken(); try { - const resp = await fetch('/api/v1/merchants/account/profile', { - method: 'PUT', - headers: { - 'Authorization': `Bearer ${token}`, - 'Content-Type': 'application/json' - }, - body: JSON.stringify(this.form) - }); - if (!resp.ok) { - const data = await resp.json(); - throw new Error(data.detail || 'Failed to save profile'); - } + await apiClient.put('/merchants/account/profile', this.form); this.successMessage = 'Profile updated successfully.'; - // Auto-hide success message after 3 seconds setTimeout(() => { this.successMessage = null; }, 3000); } catch (err) { this.error = err.message; diff --git a/app/modules/tenancy/templates/tenancy/merchant/stores.html b/app/modules/tenancy/templates/tenancy/merchant/stores.html index e911fc6f..af0b9fd2 100644 --- a/app/modules/tenancy/templates/tenancy/merchant/stores.html +++ b/app/modules/tenancy/templates/tenancy/merchant/stores.html @@ -92,28 +92,9 @@ function merchantStores() { this.loadStores(); }, - getToken() { - const match = document.cookie.match(/(?:^|;\s*)merchant_token=([^;]*)/); - return match ? decodeURIComponent(match[1]) : null; - }, - async loadStores() { - const token = this.getToken(); - if (!token) { - window.location.href = '/merchants/login'; - return; - } - try { - const resp = await fetch('/api/v1/merchants/account/stores', { - headers: { 'Authorization': `Bearer ${token}` } - }); - if (resp.status === 401) { - window.location.href = '/merchants/login'; - return; - } - if (!resp.ok) throw new Error('Failed to load stores'); - const data = await resp.json(); + const data = await apiClient.get('/merchants/account/stores'); this.stores = data.stores || data.items || []; } catch (err) { console.error('Error loading stores:', err);