Skip to content

Commit 119f1d9

Browse files
committed
fix: handle new user auth race conditions and improve no-org UX
- Add retry logic to getUserProfile for trigger timing - Check pending_org_members directly if user has no org_id - Add retry logic to registerDeviceSession for foreign key errors - Add 'No Organization Found' screen with helpful guidance - Update invite email button to link directly to downloads
1 parent f034020 commit 119f1d9

File tree

6 files changed

+301
-59
lines changed

6 files changed

+301
-59
lines changed

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,19 @@
22

33
All notable changes to BluePLM will be documented in this file.
44

5+
## [2.16.10] - 2025-12-30
6+
7+
### Fixed
8+
- **New user auth race condition**: Added retry logic when fetching user profile (handles trigger timing)
9+
- **Invited users not linked to org**: Now checks `pending_org_members` directly if trigger didn't run
10+
- **Session registration fails for new users**: Added retry logic with helpful error message
11+
- **Stuck spinners**: Users now see proper "No Organization Found" screen with helpful guidance
12+
13+
### Changed
14+
- **Invite email button**: Links directly to blueplm.io/downloads instead of auth confirmation URL
15+
16+
---
17+
518
## [2.16.9] - 2025-12-30
619

720
### Added

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "blue-plm",
3-
"version": "2.16.9",
3+
"version": "2.16.10",
44
"description": "Product Lifecycle Management for everyone who builds",
55
"main": "dist-electron/main.js",
66
"scripts": {

src/App.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,8 @@ function App() {
469469
console.log('[Auth] No organization found:', orgError)
470470
if (connectingTimeout) clearTimeout(connectingTimeout)
471471
setIsConnecting(false)
472+
// Show a toast with helpful message
473+
addToast('warning', orgError?.message || 'No organization found. Please enter an organization code or contact your administrator.')
472474
}
473475
} catch (err) {
474476
console.error('[Auth] Error in auth state handler:', err)

src/components/TabBar.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,7 @@ export function TabBar() {
394394
{/* New tab button */}
395395
<button
396396
onClick={handleNewTabClick}
397-
className="h-7 w-7 mb-0.5 ml-1 flex items-center justify-center text-plm-fg-dim hover:text-plm-fg hover:bg-plm-bg-light rounded transition-colors flex-shrink-0"
397+
className="h-7 w-7 mb-1 ml-1 flex items-center justify-center text-plm-fg-dim hover:text-plm-fg hover:bg-plm-bg-light rounded transition-colors flex-shrink-0"
398398
title="New Tab"
399399
>
400400
<Plus size={16} />

src/components/WelcomeScreen.tsx

Lines changed: 110 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useState, useEffect, useRef } from 'react'
2-
import { FolderPlus, Loader2, HardDrive, WifiOff, LogIn, Check, Database, Link, User, Truck, Mail, Phone, ArrowLeft, Eye, EyeOff, RotateCw, X } from 'lucide-react'
2+
import { FolderPlus, Loader2, HardDrive, WifiOff, LogIn, Check, Database, Link, User, Truck, Mail, Phone, ArrowLeft, Eye, EyeOff, RotateCw, X, AlertTriangle, LogOut } from 'lucide-react'
33
import { usePDMStore, ConnectedVault } from '../stores/pdmStore'
44
import { signInWithGoogle, signInWithEmail, signUpWithEmail, signInWithPhone, verifyPhoneOTP, isSupabaseConfigured, supabase, getAccessibleVaults } from '../lib/supabase'
55
import { getInitials } from '../types/pdm'
@@ -1395,6 +1395,115 @@ export function WelcomeScreen({ onOpenRecentVault }: WelcomeScreenProps) {
13951395
)
13961396
}
13971397

1398+
// ============================================
1399+
// NO ORGANIZATION SCREEN (signed in but not linked to any org)
1400+
// ============================================
1401+
if (user && !organization && !isOfflineMode) {
1402+
const handleSignOutAndRetry = async () => {
1403+
uiLog('info', 'User signing out to retry with different account')
1404+
const { signOut: supabaseSignOut } = await import('../lib/supabase')
1405+
await supabaseSignOut()
1406+
}
1407+
1408+
return (
1409+
<div className="flex-1 flex items-center justify-center bg-plm-bg overflow-auto">
1410+
<div className="max-w-md w-full p-8">
1411+
{/* Logo and Title */}
1412+
<div className="text-center mb-8">
1413+
<div className="flex justify-center items-center gap-3 mb-4">
1414+
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" className="text-plm-warning">
1415+
<path
1416+
d="M12 2L2 7L12 12L22 7L12 2Z"
1417+
stroke="currentColor"
1418+
strokeWidth="2"
1419+
strokeLinecap="round"
1420+
strokeLinejoin="round"
1421+
/>
1422+
<path
1423+
d="M2 17L12 22L22 17"
1424+
stroke="currentColor"
1425+
strokeWidth="2"
1426+
strokeLinecap="round"
1427+
strokeLinejoin="round"
1428+
/>
1429+
<path
1430+
d="M2 12L12 17L22 12"
1431+
stroke="currentColor"
1432+
strokeWidth="2"
1433+
strokeLinecap="round"
1434+
strokeLinejoin="round"
1435+
/>
1436+
</svg>
1437+
<h1 className="text-2xl font-bold text-plm-fg">{t('welcome.title')}</h1>
1438+
</div>
1439+
</div>
1440+
1441+
{/* User Info */}
1442+
<div className="text-center mb-6">
1443+
<div className="inline-flex items-center gap-2 px-4 py-2 bg-plm-bg-light border border-plm-border rounded-full mb-4">
1444+
{user.avatar_url ? (
1445+
<img src={user.avatar_url} alt="" className="w-5 h-5 rounded-full" />
1446+
) : (
1447+
<div className="w-5 h-5 rounded-full bg-plm-accent flex items-center justify-center text-[10px] text-white font-semibold">
1448+
{getInitials(user.full_name || user.email)}
1449+
</div>
1450+
)}
1451+
<span className="text-sm text-plm-fg-dim">
1452+
{user.full_name || user.email}
1453+
</span>
1454+
</div>
1455+
</div>
1456+
1457+
{/* Warning Card */}
1458+
<div className="bg-plm-warning/10 border border-plm-warning/30 rounded-xl p-6 mb-6">
1459+
<div className="flex gap-4">
1460+
<div className="flex-shrink-0">
1461+
<AlertTriangle className="w-6 h-6 text-plm-warning" />
1462+
</div>
1463+
<div>
1464+
<h3 className="text-plm-fg font-semibold mb-2">{t('welcome.noOrgTitle', 'No Organization Found')}</h3>
1465+
<p className="text-sm text-plm-fg-muted">
1466+
{t('welcome.noOrgDesc', 'Your account isn\'t linked to any organization. This can happen if:')}
1467+
</p>
1468+
<ul className="text-sm text-plm-fg-muted mt-2 space-y-1 list-disc list-inside">
1469+
<li>{t('welcome.noOrgReason1', 'You haven\'t been invited yet')}</li>
1470+
<li>{t('welcome.noOrgReason2', 'You signed in with a different email than the invite')}</li>
1471+
<li>{t('welcome.noOrgReason3', 'The invite hasn\'t been processed yet')}</li>
1472+
</ul>
1473+
</div>
1474+
</div>
1475+
</div>
1476+
1477+
{/* Actions */}
1478+
<div className="space-y-3">
1479+
<button
1480+
onClick={handleSignOutAndRetry}
1481+
className="w-full py-3 bg-plm-accent hover:bg-plm-accent-hover text-white font-medium rounded-lg transition-colors flex items-center justify-center gap-2"
1482+
>
1483+
<LogOut size={18} />
1484+
{t('welcome.signOutAndRetry', 'Sign Out & Try Different Account')}
1485+
</button>
1486+
1487+
<button
1488+
onClick={handleOfflineMode}
1489+
className="w-full py-3 bg-plm-bg-light border border-plm-border hover:bg-plm-bg-light/80 text-plm-fg font-medium rounded-lg transition-colors flex items-center justify-center gap-2"
1490+
>
1491+
<WifiOff size={18} />
1492+
{t('welcome.workOffline')}
1493+
</button>
1494+
</div>
1495+
1496+
{/* Help Text */}
1497+
<div className="mt-6 p-4 bg-plm-bg-light border border-plm-border rounded-lg">
1498+
<p className="text-xs text-plm-fg-muted text-center">
1499+
{t('welcome.noOrgHelp', 'If you were invited, please check your email for the invite link and make sure to sign in with the same email address that received the invitation. Contact your administrator if you need help.')}
1500+
</p>
1501+
</div>
1502+
</div>
1503+
</div>
1504+
)
1505+
}
1506+
13981507
// ============================================
13991508
// VAULT CONNECTION SCREEN (shown when authenticated or offline)
14001509
// ============================================

0 commit comments

Comments
 (0)