akhaliq HF Staff commited on
Commit
27c7a45
Β·
1 Parent(s): 4b29926

update landing to show login

Browse files
frontend/src/app/page.tsx CHANGED
@@ -504,6 +504,7 @@ export default function Home() {
504
  isAuthenticated={isAuthenticated}
505
  initialLanguage={selectedLanguage}
506
  initialModel={selectedModel}
 
507
  />
508
  </div>
509
  );
 
504
  isAuthenticated={isAuthenticated}
505
  initialLanguage={selectedLanguage}
506
  initialModel={selectedModel}
507
+ onAuthChange={checkAuth}
508
  />
509
  </div>
510
  );
frontend/src/components/LandingPage.tsx CHANGED
@@ -2,20 +2,32 @@
2
 
3
  import { useState, useEffect, useRef } from 'react';
4
  import { apiClient } from '@/lib/api';
 
 
 
 
 
 
 
 
 
5
  import type { Model, Language } from '@/types';
 
6
 
7
  interface LandingPageProps {
8
  onStart: (prompt: string, language: Language, modelId: string) => void;
9
  isAuthenticated: boolean;
10
  initialLanguage?: Language;
11
  initialModel?: string;
 
12
  }
13
 
14
  export default function LandingPage({
15
  onStart,
16
  isAuthenticated,
17
  initialLanguage = 'html',
18
- initialModel = 'gemini-3.0-pro'
 
19
  }: LandingPageProps) {
20
  const [prompt, setPrompt] = useState('');
21
  const [selectedLanguage, setSelectedLanguage] = useState<Language>(initialLanguage);
@@ -24,6 +36,13 @@ export default function LandingPage({
24
  const [languages, setLanguages] = useState<Language[]>([]);
25
  const [isLoading, setIsLoading] = useState(true);
26
 
 
 
 
 
 
 
 
27
  // Dropdown states
28
  const [showLanguageDropdown, setShowLanguageDropdown] = useState(false);
29
  const [showModelDropdown, setShowModelDropdown] = useState(false);
@@ -32,8 +51,75 @@ export default function LandingPage({
32
 
33
  useEffect(() => {
34
  loadData();
 
 
 
 
 
 
 
 
 
35
  }, []);
36
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
  // Close dropdowns when clicking outside
38
  useEffect(() => {
39
  const handleClickOutside = (event: MouseEvent) => {
@@ -93,10 +179,94 @@ export default function LandingPage({
93
  return (
94
  <div className="min-h-screen flex flex-col bg-[#1e1e1e] overflow-y-auto">
95
  {/* Header - Minimal Apple style */}
96
- <header className="flex items-center px-8 py-4 border-b border-[#3e3e42]/30 flex-shrink-0">
97
  <h1 className="text-base font-semibold text-[#cccccc] tracking-tight">
98
  AnyCoder
99
  </h1>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
  </header>
101
 
102
  {/* Main Content - Centered with generous Apple spacing */}
 
2
 
3
  import { useState, useEffect, useRef } from 'react';
4
  import { apiClient } from '@/lib/api';
5
+ import {
6
+ initializeOAuth,
7
+ loginWithHuggingFace,
8
+ loginDevMode,
9
+ logout,
10
+ getStoredUserInfo,
11
+ isAuthenticated as checkIsAuthenticated,
12
+ isDevelopmentMode
13
+ } from '@/lib/auth';
14
  import type { Model, Language } from '@/types';
15
+ import type { OAuthUserInfo } from '@/lib/auth';
16
 
17
  interface LandingPageProps {
18
  onStart: (prompt: string, language: Language, modelId: string) => void;
19
  isAuthenticated: boolean;
20
  initialLanguage?: Language;
21
  initialModel?: string;
22
+ onAuthChange?: () => void;
23
  }
24
 
25
  export default function LandingPage({
26
  onStart,
27
  isAuthenticated,
28
  initialLanguage = 'html',
29
+ initialModel = 'gemini-3.0-pro',
30
+ onAuthChange
31
  }: LandingPageProps) {
32
  const [prompt, setPrompt] = useState('');
33
  const [selectedLanguage, setSelectedLanguage] = useState<Language>(initialLanguage);
 
36
  const [languages, setLanguages] = useState<Language[]>([]);
37
  const [isLoading, setIsLoading] = useState(true);
38
 
39
+ // Auth states
40
+ const [userInfo, setUserInfo] = useState<OAuthUserInfo | null>(null);
41
+ const [isAuthLoading, setIsAuthLoading] = useState(true);
42
+ const [showDevLogin, setShowDevLogin] = useState(false);
43
+ const [devUsername, setDevUsername] = useState('');
44
+ const isDevMode = isDevelopmentMode();
45
+
46
  // Dropdown states
47
  const [showLanguageDropdown, setShowLanguageDropdown] = useState(false);
48
  const [showModelDropdown, setShowModelDropdown] = useState(false);
 
51
 
52
  useEffect(() => {
53
  loadData();
54
+ handleOAuthInit();
55
+ // Check auth status periodically to catch OAuth redirects
56
+ const interval = setInterval(() => {
57
+ const authenticated = checkIsAuthenticated();
58
+ if (authenticated && !userInfo) {
59
+ handleOAuthInit();
60
+ }
61
+ }, 1000);
62
+ return () => clearInterval(interval);
63
  }, []);
64
 
65
+ const handleOAuthInit = async () => {
66
+ setIsAuthLoading(true);
67
+ try {
68
+ const oauthResult = await initializeOAuth();
69
+
70
+ if (oauthResult) {
71
+ setUserInfo(oauthResult.userInfo);
72
+ apiClient.setToken(oauthResult.accessToken);
73
+ if (onAuthChange) onAuthChange();
74
+ } else {
75
+ const storedUserInfo = getStoredUserInfo();
76
+ if (storedUserInfo) {
77
+ setUserInfo(storedUserInfo);
78
+ }
79
+ }
80
+ } catch (error) {
81
+ console.error('OAuth initialization error:', error);
82
+ } finally {
83
+ setIsAuthLoading(false);
84
+ }
85
+ };
86
+
87
+ const handleLogin = async () => {
88
+ try {
89
+ await loginWithHuggingFace();
90
+ } catch (error) {
91
+ console.error('Login failed:', error);
92
+ alert('Failed to start login process. Please try again.');
93
+ }
94
+ };
95
+
96
+ const handleLogout = () => {
97
+ logout();
98
+ apiClient.logout();
99
+ setUserInfo(null);
100
+ if (onAuthChange) onAuthChange();
101
+ window.location.reload();
102
+ };
103
+
104
+ const handleDevLogin = () => {
105
+ if (!devUsername.trim()) {
106
+ alert('Please enter a username');
107
+ return;
108
+ }
109
+
110
+ try {
111
+ const result = loginDevMode(devUsername);
112
+ setUserInfo(result.userInfo);
113
+ apiClient.setToken(result.accessToken);
114
+ setShowDevLogin(false);
115
+ setDevUsername('');
116
+ if (onAuthChange) onAuthChange();
117
+ } catch (error) {
118
+ console.error('Dev login failed:', error);
119
+ alert('Failed to login in dev mode');
120
+ }
121
+ };
122
+
123
  // Close dropdowns when clicking outside
124
  useEffect(() => {
125
  const handleClickOutside = (event: MouseEvent) => {
 
179
  return (
180
  <div className="min-h-screen flex flex-col bg-[#1e1e1e] overflow-y-auto">
181
  {/* Header - Minimal Apple style */}
182
+ <header className="flex items-center justify-between px-8 py-4 border-b border-[#3e3e42]/30 flex-shrink-0">
183
  <h1 className="text-base font-semibold text-[#cccccc] tracking-tight">
184
  AnyCoder
185
  </h1>
186
+
187
+ {/* Auth Section */}
188
+ <div className="flex items-center space-x-3">
189
+ {isAuthLoading ? (
190
+ <div className="px-4 py-2">
191
+ <span className="text-xs text-[#858585] font-medium">Loading...</span>
192
+ </div>
193
+ ) : userInfo ? (
194
+ <div className="flex items-center space-x-3">
195
+ {userInfo.avatarUrl && (
196
+ <img
197
+ src={userInfo.avatarUrl}
198
+ alt={userInfo.name}
199
+ className="w-7 h-7 rounded-full ring-2 ring-[#3e3e42]"
200
+ />
201
+ )}
202
+ <span className="hidden sm:inline text-sm text-[#cccccc] font-medium truncate max-w-[120px]">
203
+ {userInfo.preferredUsername || userInfo.name}
204
+ </span>
205
+ <button
206
+ onClick={handleLogout}
207
+ className="px-4 py-2 bg-[#2d2d30] text-[#cccccc] text-xs rounded-lg hover:bg-[#3a3a3c] transition-all border border-[#3e3e42] font-semibold active:scale-95"
208
+ >
209
+ Logout
210
+ </button>
211
+ </div>
212
+ ) : (
213
+ <div className="flex items-center space-x-3">
214
+ {/* Dev Mode Login (only on localhost) */}
215
+ {isDevMode && (
216
+ <>
217
+ {showDevLogin ? (
218
+ <div className="flex items-center space-x-2 bg-[#2d2d30] px-3 py-2 rounded-lg border border-[#ff9f0a]">
219
+ <span className="hidden sm:inline text-xs text-[#ff9f0a] font-semibold">DEV</span>
220
+ <input
221
+ type="text"
222
+ value={devUsername}
223
+ onChange={(e) => setDevUsername(e.target.value)}
224
+ onKeyPress={(e) => e.key === 'Enter' && handleDevLogin()}
225
+ placeholder="username"
226
+ className="px-3 py-1.5 rounded-lg text-xs bg-[#1e1e1e] text-[#cccccc] border border-[#3e3e42] focus:outline-none focus:ring-2 focus:ring-[#ff9f0a] focus:border-transparent w-28 font-medium"
227
+ autoFocus
228
+ />
229
+ <button
230
+ onClick={handleDevLogin}
231
+ className="px-3 py-1.5 bg-[#ff9f0a] text-white rounded-lg hover:bg-[#ff8800] text-xs font-semibold active:scale-95"
232
+ >
233
+ OK
234
+ </button>
235
+ <button
236
+ onClick={() => {
237
+ setShowDevLogin(false);
238
+ setDevUsername('');
239
+ }}
240
+ className="text-[#858585] hover:text-[#cccccc] text-sm transition-colors"
241
+ >
242
+ βœ•
243
+ </button>
244
+ </div>
245
+ ) : (
246
+ <button
247
+ onClick={() => setShowDevLogin(true)}
248
+ className="px-4 py-2 bg-[#ff9f0a] text-white rounded-lg hover:bg-[#ff8800] transition-all text-xs flex items-center space-x-2 font-semibold active:scale-95"
249
+ title="Dev Mode (localhost)"
250
+ >
251
+ <span>πŸ”§</span>
252
+ <span>Dev Login</span>
253
+ </button>
254
+ )}
255
+ <span className="text-[#858585] text-xs font-medium">or</span>
256
+ </>
257
+ )}
258
+
259
+ {/* OAuth Login */}
260
+ <button
261
+ onClick={handleLogin}
262
+ className="px-4 py-2 bg-[#007acc] text-white rounded-lg hover:bg-[#0066b3] transition-all text-xs flex items-center space-x-2 font-semibold active:scale-95"
263
+ >
264
+ <span>πŸ€—</span>
265
+ <span>Sign in</span>
266
+ </button>
267
+ </div>
268
+ )}
269
+ </div>
270
  </header>
271
 
272
  {/* Main Content - Centered with generous Apple spacing */}