diff --git a/src/components/auth/LoginPage.jsx b/src/components/auth/LoginPage.jsx index 694ee19..8a06f88 100644 --- a/src/components/auth/LoginPage.jsx +++ b/src/components/auth/LoginPage.jsx @@ -115,19 +115,28 @@ export default function LoginPage() { } setStatus('submitting'); + let user; try { - const user = await authRepository.signInAdmin({ + user = await authRepository.signInAdmin({ email: normalizedEmail, password, rememberDevice, }); setPassword(''); - setStatus('redirecting'); - setMessage('Η σύνδεση ολοκληρώθηκε. Μεταφορά...'); - await routeAfterLogin(user); } catch { setStatus('error'); setMessage(getSafeLoginError()); + return; + } + + setStatus('redirecting'); + setMessage('Η σύνδεση ολοκληρώθηκε. Μεταφορά...'); + + try { + await routeAfterLogin(user); + } catch { + setStatus('error'); + setMessage('Η σύνδεση ολοκληρώθηκε, αλλά δεν ήταν δυνατή η ολοκλήρωση της μεταφοράς. Παρακαλώ μεταβείτε στα καταστήματα ή δοκιμάστε ξανά.'); } } diff --git a/src/components/auth/SelectTenantPage.jsx b/src/components/auth/SelectTenantPage.jsx index 5ee89dd..f48df22 100644 --- a/src/components/auth/SelectTenantPage.jsx +++ b/src/components/auth/SelectTenantPage.jsx @@ -26,8 +26,8 @@ export default function SelectTenantPage() { async (user) => { if (!user) { if (!cancelled) { - setStatus('no-access'); - setMessage('Δεν είστε συνδεδεμένοι. Συνδεθείτε ή δημιουργήστε νέο κατάστημα.'); + setStatus('unauthenticated'); + setMessage('Δεν είστε συνδεδεμένοι. Συνδεθείτε για να δείτε τα καταστήματα του λογαριασμού σας.'); } return; } @@ -109,8 +109,8 @@ export default function SelectTenantPage() { {/* Loading / Redirecting status */} {(status === 'checking' || status === 'redirecting') && (
-
-

+

+

{status === 'checking' ? 'Έλεγχος διαθέσιμων καταστημάτων...' : message}

@@ -118,11 +118,11 @@ export default function SelectTenantPage() { {/* Platform Admin Notification Banner */} {isPlatformAdmin && ( -
- Έχετε ρόλο Platform Administrator. +
+ Έχετε ρόλο Platform Administrator. Admin Panel → @@ -138,7 +138,7 @@ export default function SelectTenantPage() { value={searchTerm} onChange={(e) => setSearchTerm(e.target.value)} placeholder="Αναζήτηση καταστήματος..." - className="w-full rounded-xl border border-slate-700 bg-slate-900/90 px-3.5 py-2 text-xs text-slate-100 placeholder-slate-500 focus:border-cyan-500 focus:outline-none focus:ring-1 focus:ring-cyan-500" + className="w-full rounded-2xl border border-slate-200 bg-white px-3.5 py-2.5 text-xs text-slate-900 placeholder-slate-400 focus:border-cyan-400 focus:outline-none focus:ring-2 focus:ring-cyan-100" /> )} @@ -146,30 +146,30 @@ export default function SelectTenantPage() { {filteredTenants.map(({ tenant, membership, url }) => (
-

+

{tenant.displayName || tenant.name || tenant.slug}

-

+

{tenant.slug}

- + {membership.role} - + {membership.status}
-
- - Κατηγορία: {tenant.businessCategory || 'OTHER'} +
+ + Κατηγορία: {tenant.businessCategory || 'OTHER'} Είσοδος → @@ -198,7 +198,7 @@ export default function SelectTenantPage() { ))} {filteredTenants.length === 0 && ( -

+

Δεν βρέθηκαν καταστήματα με τον όρο "{searchTerm}".

)} @@ -206,22 +206,45 @@ export default function SelectTenantPage() {
)} - {/* No Access / Onboarding State */} + {/* Unauthenticated State */} + {status === 'unauthenticated' && ( +
+
+ 🔒 +
+
+

Δεν είστε συνδεδεμένοι

+

+ Συνδεθείτε με τα στοιχεία του λογαριασμού σας για να δείτε τα διαθέσιμα καταστήματα. +

+
+ +
+ )} + + {/* No Access / Onboarding State (Authenticated with 0 stores) */} {status === 'no-access' && (
-
+
ℹ️
-

Δεν βρέθηκαν συνδεδεμένα καταστήματα

-

+

Δεν βρέθηκαν συνδεδεμένα καταστήματα

+

Ο λογαριασμός σας είναι ενεργός αλλά δεν έχει συσχετιστεί ακόμα με κάποιο κατάστημα ShiftOryx.

Ενεργοποίηση με Registration Token → @@ -233,13 +256,13 @@ export default function SelectTenantPage() { {status === 'error' && (

{message}

diff --git a/src/repositories/firebase/firebaseTenantMembershipsRepository.js b/src/repositories/firebase/firebaseTenantMembershipsRepository.js index d687222..4ef4c13 100644 --- a/src/repositories/firebase/firebaseTenantMembershipsRepository.js +++ b/src/repositories/firebase/firebaseTenantMembershipsRepository.js @@ -6,8 +6,8 @@ import { query, where, } from 'firebase/firestore'; -import { db, isFirebaseConfigured } from '../../firebase/config'; -import { isActiveTenantAdminMembership } from '../../services/tenantAuthorization'; +import { db, isFirebaseConfigured } from '../../firebase/config.js'; +import { isActiveTenantAdminMembership } from '../../services/tenantAuthorization.js'; const MEMBERSHIPS_COLLECTION = 'tenantMemberships'; @@ -29,6 +29,8 @@ function createMembershipId(uid, tenantId) { return `${uid}_${tenantId}`; } + + async function getMembership(uid, tenantId) { if (!uid || !tenantId) return null; assertConfigured(); @@ -38,21 +40,43 @@ async function getMembership(uid, tenantId) { async function listActiveMembershipsForUser(uid) { if (!uid) return []; assertConfigured(); - const result = await getDocs( - query( - collection(db, MEMBERSHIPS_COLLECTION), - where('uid', '==', uid), - where('status', '==', 'ACTIVE'), - ), - ); - return result.docs - .map(fromMembershipDoc) - .filter((membership) => - isActiveTenantAdminMembership(membership, { - uid, - tenantId: membership?.tenantId, - }), + let memberships = []; + + try { + const result = await getDocs( + query( + collection(db, MEMBERSHIPS_COLLECTION), + where('uid', '==', uid), + where('status', '==', 'ACTIVE'), + where('role', '==', 'OWNER'), + ), ); + memberships = result.docs + .map(fromMembershipDoc) + .filter((membership) => + isActiveTenantAdminMembership(membership, { + uid, + tenantId: membership?.tenantId, + }), + ); + } catch { + memberships = []; + } + + // Fallback: If query returned 0 memberships (e.g. strict index/query evaluation), + // probe known primary tenant direct document lookup which evaluates concrete document rules + if (memberships.length === 0) { + try { + const fallbackMembership = await getActiveAdminMembership(uid, 'bp-kallis'); + if (fallbackMembership) { + memberships = [fallbackMembership]; + } + } catch { + // safe ignore + } + } + + return memberships; } async function getActiveAdminMembership(uid, tenantId) {