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 () => {
|
const handleConnectGoogle = async () => {
|
||||||
try {
|
try {
|
||||||
const res = await googleWorkspaceSignIn();
|
const res = await googleWorkspaceSignIn();
|
||||||
@@ -107,26 +110,35 @@ export const GoogleWorkspaceHub: React.FC<GoogleWorkspaceHubProps> = ({
|
|||||||
setIsConnected(true);
|
setIsConnected(true);
|
||||||
setAccessToken(res.accessToken);
|
setAccessToken(res.accessToken);
|
||||||
setConnectedUser({
|
setConnectedUser({
|
||||||
email: res.user.email || 'connected@gmail.com',
|
email: res.user.email || 'dkifer19@gmail.com',
|
||||||
name: res.user.displayName || 'Connected User'
|
name: res.user.displayName || 'David Kifer'
|
||||||
});
|
});
|
||||||
showToast('✓ Google Workspace connected successfully (Sheets, Drive, Docs & Keep permissions granted)!');
|
showToast('✓ Google Workspace connected successfully (Sheets, Drive, Docs & Keep permissions granted)!');
|
||||||
loadDriveFiles(res.accessToken);
|
loadDriveFiles(res.accessToken);
|
||||||
}
|
}
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
console.error("Google Sign-In Error Details:", err);
|
console.error("Google Sign-In Error Details:", err);
|
||||||
// Display actual error message to the user
|
|
||||||
const msg = err?.message || String(err);
|
const msg = err?.message || String(err);
|
||||||
if (msg.includes('popup-closed-by-user')) {
|
setShowTokenInputModal(true);
|
||||||
showToast('Sign-in window closed before completing.');
|
showToast(`Notice: Popup closed. You can paste a Google Access Token directly or activate Workspace Sandbox mode.`);
|
||||||
} 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}`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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 () => {
|
const handleDisconnectGoogle = async () => {
|
||||||
await googleSignOut();
|
await googleSignOut();
|
||||||
setIsConnected(false);
|
setIsConnected(false);
|
||||||
@@ -695,8 +707,51 @@ export const GoogleWorkspaceHub: React.FC<GoogleWorkspaceHubProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</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>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -51,8 +51,14 @@ export const googleWorkspaceSignIn = async (): Promise<{ user: User; accessToken
|
|||||||
}
|
}
|
||||||
cachedAccessToken = credential.accessToken;
|
cachedAccessToken = credential.accessToken;
|
||||||
return { user: result.user, accessToken: cachedAccessToken };
|
return { user: result.user, accessToken: cachedAccessToken };
|
||||||
} catch (error) {
|
} catch (error: any) {
|
||||||
console.error('Google Workspace Sign-in Error:', error);
|
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;
|
throw error;
|
||||||
} finally {
|
} finally {
|
||||||
isSigningIn = false;
|
isSigningIn = false;
|
||||||
|
|||||||
Reference in New Issue
Block a user