Add fallback Google OAuth Token input modal and explicit domain configuration dialog
This commit is contained in:
@@ -100,6 +100,9 @@ export const GoogleWorkspaceHub: React.FC<GoogleWorkspaceHubProps> = ({
|
||||
}
|
||||
}, []);
|
||||
|
||||
const [showTokenInputModal, setShowTokenInputModal] = useState(false);
|
||||
const [customTokenInput, setCustomTokenInput] = useState('');
|
||||
|
||||
const handleConnectGoogle = async () => {
|
||||
try {
|
||||
const res = await googleWorkspaceSignIn();
|
||||
@@ -107,26 +110,35 @@ export const GoogleWorkspaceHub: React.FC<GoogleWorkspaceHubProps> = ({
|
||||
setIsConnected(true);
|
||||
setAccessToken(res.accessToken);
|
||||
setConnectedUser({
|
||||
email: res.user.email || 'connected@gmail.com',
|
||||
name: res.user.displayName || 'Connected User'
|
||||
email: res.user.email || 'dkifer19@gmail.com',
|
||||
name: res.user.displayName || 'David Kifer'
|
||||
});
|
||||
showToast('✓ Google Workspace connected successfully (Sheets, Drive, Docs & Keep permissions granted)!');
|
||||
loadDriveFiles(res.accessToken);
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.error("Google Sign-In Error Details:", err);
|
||||
// Display actual error message to the user
|
||||
const msg = err?.message || String(err);
|
||||
if (msg.includes('popup-closed-by-user')) {
|
||||
showToast('Sign-in window closed before completing.');
|
||||
} else if (msg.includes('auth/unauthorized-domain')) {
|
||||
showToast('Error: http://localhost:3000 needs to be added to Authorized Domains in Firebase Auth Console.');
|
||||
} else {
|
||||
showToast(`Google Sign-In Notice: ${msg}`);
|
||||
}
|
||||
setShowTokenInputModal(true);
|
||||
showToast(`Notice: Popup closed. You can paste a Google Access Token directly or activate Workspace Sandbox mode.`);
|
||||
}
|
||||
};
|
||||
|
||||
const handleApplyCustomToken = () => {
|
||||
if (customTokenInput.trim()) {
|
||||
setAccessToken(customTokenInput.trim());
|
||||
setIsConnected(true);
|
||||
setConnectedUser({ email: 'dkifer19@gmail.com', name: 'David Kifer' });
|
||||
showToast('✓ Custom Google OAuth Access Token connected!');
|
||||
loadDriveFiles(customTokenInput.trim());
|
||||
} else {
|
||||
setIsConnected(true);
|
||||
setConnectedUser({ email: 'dkifer19@gmail.com', name: 'David Kifer (Sandbox Mode)' });
|
||||
showToast('Connected in Offline Workspace Sandbox Mode.');
|
||||
}
|
||||
setShowTokenInputModal(false);
|
||||
};
|
||||
|
||||
const handleDisconnectGoogle = async () => {
|
||||
await googleSignOut();
|
||||
setIsConnected(false);
|
||||
@@ -695,8 +707,51 @@ export const GoogleWorkspaceHub: React.FC<GoogleWorkspaceHubProps> = ({
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{/* Manual OAuth Token Modal */}
|
||||
{showTokenInputModal && (
|
||||
<div className="fixed inset-0 bg-slate-950/80 backdrop-blur-md flex items-center justify-center p-4 z-50 animate-fadeIn">
|
||||
<div className="bg-slate-900 border border-slate-800 rounded-2xl max-w-md w-full p-6 shadow-2xl space-y-4">
|
||||
<div className="flex items-center justify-between pb-3 border-b border-slate-800">
|
||||
<h3 className="text-sm font-bold text-white flex items-center gap-2">
|
||||
<Lock className="w-4 h-4 text-indigo-400" /> Google Workspace OAuth Setup
|
||||
</h3>
|
||||
<button onClick={() => setShowTokenInputModal(false)} className="text-slate-400 hover:text-white text-xs">✕</button>
|
||||
</div>
|
||||
|
||||
<p className="text-xs text-slate-300">
|
||||
Google Auth popups require <code className="text-indigo-300">http://localhost:3000</code> to be registered under <strong>Authorized Origins</strong> in your Firebase/Google Cloud console.
|
||||
</p>
|
||||
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-semibold text-slate-400 block">Option A: Paste Google OAuth Access Token</label>
|
||||
<input
|
||||
type="password"
|
||||
placeholder="ya29.a0... (Paste OAuth Token)"
|
||||
value={customTokenInput}
|
||||
onChange={(e) => setCustomTokenInput(e.target.value)}
|
||||
className="w-full bg-slate-950 border border-slate-800 rounded-xl px-3.5 py-2 text-xs text-slate-100 placeholder:text-slate-600 focus:outline-none focus:border-indigo-500"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-end gap-2 pt-2">
|
||||
<button
|
||||
onClick={() => handleApplyCustomToken()}
|
||||
className="px-4 py-2 rounded-xl bg-slate-800 hover:bg-slate-700 text-slate-300 text-xs font-semibold"
|
||||
>
|
||||
Use Offline Sandbox
|
||||
</button>
|
||||
<button
|
||||
onClick={() => handleApplyCustomToken()}
|
||||
className="px-4 py-2 rounded-xl bg-indigo-600 hover:bg-indigo-500 text-white text-xs font-bold shadow-lg shadow-indigo-600/30"
|
||||
>
|
||||
Connect Token
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -51,8 +51,14 @@ export const googleWorkspaceSignIn = async (): Promise<{ user: User; accessToken
|
||||
}
|
||||
cachedAccessToken = credential.accessToken;
|
||||
return { user: result.user, accessToken: cachedAccessToken };
|
||||
} catch (error) {
|
||||
} catch (error: any) {
|
||||
console.error('Google Workspace Sign-in Error:', error);
|
||||
|
||||
// Check if error is due to domain restriction or cross-origin popup block
|
||||
const errCode = error?.code || '';
|
||||
if (errCode.includes('unauthorized-domain') || errCode.includes('popup-closed') || errCode.includes('auth/invalid-api-key')) {
|
||||
throw new Error(`Google Auth Domain Restriction: Your local origin (localhost:3000) is not listed in the Firebase/Google Auth authorized domains. Error Code: ${errCode}`);
|
||||
}
|
||||
throw error;
|
||||
} finally {
|
||||
isSigningIn = false;
|
||||
|
||||
Reference in New Issue
Block a user