Simplify login to sessionid-only method with clear instructions

This commit is contained in:
Khoa.vo 2025-12-19 15:14:33 +07:00
parent c92a6a6bf5
commit 19c2b4b410

View file

@ -4,71 +4,35 @@ import axios from 'axios';
import { API_BASE_URL } from '../config'; import { API_BASE_URL } from '../config';
export const Login: React.FC = () => { export const Login: React.FC = () => {
const [username, setUsername] = useState(''); const [sessionId, setSessionId] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState(''); const [error, setError] = useState('');
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const [showCookieMethod, setShowCookieMethod] = useState(false); const [showInstructions, setShowInstructions] = useState(true);
const [cookies, setCookies] = useState('');
const navigate = useNavigate(); const navigate = useNavigate();
const handleLogin = async (e: React.FormEvent) => { const handleLogin = async () => {
e.preventDefault(); if (!sessionId.trim()) return;
if (!username.trim() || !password.trim()) return;
setError(''); setError('');
setIsLoading(true); setIsLoading(true);
try { try {
const res = await axios.post(`${API_BASE_URL}/auth/login`, { // Send sessionid as credentials
username: username.trim(),
password: password.trim()
});
if (res.data.status === 'success') {
navigate('/');
} else {
setError(res.data.message || 'Login failed. Please check your credentials.');
}
} catch (err: any) {
const message = err.response?.data?.detail || err.response?.data?.message || 'Login failed. Please try again.';
setError(message);
} finally {
setIsLoading(false);
}
};
const handleCookieLogin = async () => {
if (!cookies.trim()) return;
setError('');
setIsLoading(true);
try {
// Try to parse as JSON
let jsonCreds;
try {
jsonCreds = JSON.parse(cookies);
} catch {
// If not JSON, wrap it as simple session format
jsonCreds = {
http: {
cookies: { sessionid: cookies.trim() }
}
};
}
const res = await axios.post(`${API_BASE_URL}/auth/credentials`, { const res = await axios.post(`${API_BASE_URL}/auth/credentials`, {
credentials: jsonCreds credentials: {
http: {
cookies: { sessionid: sessionId.trim() }
}
}
}); });
if (res.data.status === 'success') { if (res.data.status === 'success') {
navigate('/'); navigate('/');
} else { } else {
setError(res.data.message || 'Failed to save cookies.'); setError(res.data.message || 'Login failed.');
} }
} catch (err: any) { } catch (err: any) {
setError(err.response?.data?.detail || 'Invalid cookie format.'); setError(err.response?.data?.detail || 'Invalid session. Please try again.');
} finally { } finally {
setIsLoading(false); setIsLoading(false);
} }
@ -77,7 +41,7 @@ export const Login: React.FC = () => {
return ( return (
<div className="min-h-screen bg-gradient-to-br from-gray-950 via-black to-gray-950 flex flex-col"> <div className="min-h-screen bg-gradient-to-br from-gray-950 via-black to-gray-950 flex flex-col">
{/* Header */} {/* Header */}
<div className="flex-shrink-0 pt-10 pb-4 px-6 text-center"> <div className="flex-shrink-0 pt-8 pb-4 px-6 text-center">
<div className="relative inline-block mb-3"> <div className="relative inline-block mb-3">
<div className="w-14 h-14 bg-gradient-to-r from-cyan-400 to-pink-500 rounded-2xl rotate-12 absolute -inset-1 blur-lg opacity-50" /> <div className="w-14 h-14 bg-gradient-to-r from-cyan-400 to-pink-500 rounded-2xl rotate-12 absolute -inset-1 blur-lg opacity-50" />
<div className="relative w-14 h-14 bg-gradient-to-r from-cyan-400 to-pink-500 rounded-2xl flex items-center justify-center"> <div className="relative w-14 h-14 bg-gradient-to-r from-cyan-400 to-pink-500 rounded-2xl flex items-center justify-center">
@ -99,36 +63,62 @@ export const Login: React.FC = () => {
</div> </div>
)} )}
{/* Simple Login Form */} {/* Instructions Toggle */}
<form onSubmit={handleLogin} className="space-y-4"> <button
onClick={() => setShowInstructions(!showInstructions)}
className="w-full text-left mb-4 p-3 bg-cyan-500/10 border border-cyan-500/20 rounded-xl"
>
<div className="flex items-center justify-between">
<span className="text-cyan-400 text-sm font-medium">📱 How to get your Session ID</span>
<span className="text-cyan-400">{showInstructions ? '▲' : '▼'}</span>
</div>
</button>
{showInstructions && (
<div className="mb-5 space-y-3">
<div className="flex items-start gap-3 p-3 bg-white/5 rounded-xl">
<div className="w-6 h-6 bg-cyan-500 rounded-full flex items-center justify-center flex-shrink-0 text-white font-bold text-xs">1</div>
<div> <div>
<label className="block text-gray-400 text-xs mb-1.5 ml-1">Email or Username</label> <p className="text-white text-sm">Open TikTok app Login</p>
</div>
</div>
<div className="flex items-start gap-3 p-3 bg-white/5 rounded-xl">
<div className="w-6 h-6 bg-pink-500 rounded-full flex items-center justify-center flex-shrink-0 text-white font-bold text-xs">2</div>
<div>
<p className="text-white text-sm">On desktop: Open TikTok in Chrome</p>
<p className="text-gray-500 text-xs mt-0.5">F12 Application Cookies tiktok.com</p>
</div>
</div>
<div className="flex items-start gap-3 p-3 bg-white/5 rounded-xl">
<div className="w-6 h-6 bg-purple-500 rounded-full flex items-center justify-center flex-shrink-0 text-white font-bold text-xs">3</div>
<div>
<p className="text-white text-sm">Copy the <code className="bg-white/10 px-1 rounded text-cyan-400">sessionid</code> value</p>
<p className="text-gray-500 text-xs mt-0.5">Long string starting with numbers</p>
</div>
</div>
</div>
)}
{/* Session ID Input */}
<div className="mb-4">
<label className="block text-gray-400 text-xs mb-1.5 ml-1">Session ID</label>
<input <input
type="text" type="text"
value={username} value={sessionId}
onChange={(e) => setUsername(e.target.value)} onChange={(e) => setSessionId(e.target.value)}
placeholder="Enter your TikTok email" placeholder="Paste your sessionid here..."
className="w-full bg-black/60 border-2 border-white/10 rounded-xl p-3.5 text-white text-sm focus:outline-none focus:border-cyan-500/50 placeholder:text-gray-600" className="w-full bg-black/60 border-2 border-white/10 rounded-xl p-4 text-white text-sm font-mono focus:outline-none focus:border-cyan-500/50 placeholder:text-gray-600"
disabled={isLoading}
/>
</div>
<div>
<label className="block text-gray-400 text-xs mb-1.5 ml-1">Password</label>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="Enter your password"
className="w-full bg-black/60 border-2 border-white/10 rounded-xl p-3.5 text-white text-sm focus:outline-none focus:border-cyan-500/50 placeholder:text-gray-600"
disabled={isLoading} disabled={isLoading}
/> />
</div> </div>
{/* Connect Button */}
<button <button
type="submit" onClick={handleLogin}
disabled={!username.trim() || !password.trim() || isLoading} disabled={!sessionId.trim() || isLoading}
className={`w-full py-4 text-white font-semibold rounded-xl transition-all transform active:scale-[0.98] text-base mt-2 ${username.trim() && password.trim() && !isLoading className={`w-full py-4 text-white font-semibold rounded-xl transition-all transform active:scale-[0.98] text-base ${sessionId.trim() && !isLoading
? 'bg-gradient-to-r from-cyan-500 to-pink-500 shadow-lg shadow-pink-500/20' ? 'bg-gradient-to-r from-cyan-500 to-pink-500 shadow-lg shadow-pink-500/20'
: 'bg-gray-700 cursor-not-allowed' : 'bg-gray-700 cursor-not-allowed'
}`} }`}
@ -136,54 +126,29 @@ export const Login: React.FC = () => {
{isLoading ? ( {isLoading ? (
<span className="flex items-center justify-center gap-2"> <span className="flex items-center justify-center gap-2">
<div className="w-4 h-4 border-2 border-white/30 border-t-white rounded-full animate-spin" /> <div className="w-4 h-4 border-2 border-white/30 border-t-white rounded-full animate-spin" />
Logging in... Connecting...
</span> </span>
) : ( ) : (
'Log In' 'Connect'
)} )}
</button> </button>
</form>
{/* Info */} {/* Video Tutorial Link */}
<div className="mt-6 text-center">
<a
href="https://www.youtube.com/results?search_query=how+to+get+tiktok+sessionid+cookie"
target="_blank"
rel="noopener noreferrer"
className="text-cyan-400 text-sm underline"
>
Watch tutorial on YouTube
</a>
</div>
{/* Note */}
<p className="text-gray-600 text-xs text-center mt-4"> <p className="text-gray-600 text-xs text-center mt-4">
Your credentials are used only to log into TikTok on the server. They are not stored. Your session ID connects you to your TikTok account. It's stored locally on the server.
</p> </p>
{/* Cookie Method - Alternative */}
<div className="mt-8 pt-6 border-t border-white/10">
<button
onClick={() => setShowCookieMethod(!showCookieMethod)}
className="w-full text-gray-500 hover:text-gray-400 text-sm py-2 flex items-center justify-center gap-2"
>
<span>{showCookieMethod ? '▲' : '▼'}</span>
<span>Alternative: Cookie Method</span>
</button>
{showCookieMethod && (
<div className="mt-3 p-4 bg-white/5 rounded-xl space-y-3">
<p className="text-gray-400 text-xs text-center">
If login doesn't work, you can paste TikTok cookies directly.
</p>
<textarea
value={cookies}
onChange={(e) => setCookies(e.target.value)}
placeholder='Paste sessionid or full cookie JSON...'
className="w-full h-24 bg-black/60 border border-white/10 rounded-xl p-3 text-white text-xs font-mono resize-none focus:outline-none focus:border-cyan-500/50 placeholder:text-gray-600"
disabled={isLoading}
/>
<button
onClick={handleCookieLogin}
disabled={!cookies.trim() || isLoading}
className={`w-full py-3 rounded-xl text-sm transition-all ${cookies.trim() && !isLoading
? 'bg-white/10 hover:bg-white/20 text-white'
: 'bg-gray-800 text-gray-500 cursor-not-allowed'
}`}
>
Connect with Cookies
</button>
</div>
)}
</div>
</div> </div>
</div> </div>
</div> </div>