template-monorepo/frontend/src/pages/user/OAuthCallbackPage.tsx

91 lines
2.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useEffect, useState } from 'react';
import { Link, useNavigate, useSearchParams } from 'react-router-dom';
import * as authApi from '../../api/auth';
import { ApiError } from '../../api/http';
import { DEFAULT_TENANT } from '../../config';
import { useAuth } from '../../context/AuthContext';
import * as permApi from '../../api/permission';
type OAuthMode = 'login' | 'register';
export function OAuthCallbackPage({ mode }: { mode: OAuthMode }) {
const navigate = useNavigate();
const [search] = useSearchParams();
const { syncSession, refreshRoles } = useAuth();
const [error, setError] = useState('');
useEffect(() => {
const code = search.get('code');
const state = search.get('state');
const oauthError = search.get('error');
const tenant =
localStorage.getItem('tenant_slug') ?? DEFAULT_TENANT;
if (oauthError) {
setError(search.get('error_description') ?? oauthError);
return;
}
if (!code || !state) {
setError('缺少 OAuth 參數code / state');
return;
}
let cancelled = false;
(async () => {
try {
if (mode === 'login') {
const result = await authApi.loginSocialCallback(code, state);
if (result.mfa_required && result.mfa_challenge_id) {
navigate('/login', {
replace: true,
state: {
message: '請完成雙因素驗證以完成登入',
mfa_challenge_id: result.mfa_challenge_id,
tenant,
},
});
return;
}
} else {
await authApi.registerSocialCallback(code, state);
}
if (cancelled) return;
syncSession();
await refreshRoles();
const me = await permApi.getMyPermissions();
const admin = permApi.isAdminRole(me.roles ?? []);
navigate(admin ? '/admin' : '/app', { replace: true });
} catch (err) {
if (cancelled) return;
if (err instanceof ApiError && err.code === 29301000 && mode === 'login') {
setError('尚無帳號,請先註冊或聯絡管理員開通 LDAP 帳號。');
} else {
setError(err instanceof ApiError ? err.message : '登入失敗');
}
}
})();
return () => {
cancelled = true;
};
}, [mode, navigate, refreshRoles, search, syncSession]);
return (
<div className="auth-card">
<h1>{mode === 'login' ? '登入處理中' : '註冊處理中'}</h1>
{error ? (
<>
<p className="form-error">{error}</p>
<p className="auth-footer">
<Link to={mode === 'login' ? '/login' : '/register'}></Link>
</p>
</>
) : (
<p className="auth-hint"></p>
)}
</div>
);
}