TheK3R1M commited on
Commit
77d0015
·
verified ·
1 Parent(s): 2b3a0b1

Add API Key Onboarding Modal and Firebase Local Mode

Browse files
Files changed (3) hide show
  1. App.tsx +51 -0
  2. firebase.ts +9 -3
  3. services/geminiService.ts +3 -3
App.tsx CHANGED
@@ -1845,6 +1845,57 @@ const App: React.FC = () => {
1845
  return (
1846
  <div className="flex h-screen bg-[#0B0F19] text-slate-100 overflow-hidden font-sans selection:bg-indigo-500/30">
1847
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1848
  {/* Mobile Sidebar Overlay */}
1849
  {isMobileMenuOpen && (
1850
  <div
 
1845
  return (
1846
  <div className="flex h-screen bg-[#0B0F19] text-slate-100 overflow-hidden font-sans selection:bg-indigo-500/30">
1847
 
1848
+ {/* API Key Gateway Modal */}
1849
+ {!userGeminiKey && (
1850
+ <div className="fixed inset-0 bg-[#0B0F19] z-[100] flex flex-col items-center justify-center p-4">
1851
+ <div className="max-w-md w-full bg-slate-800 border border-indigo-500/30 rounded-2xl p-8 shadow-2xl shadow-indigo-500/10 text-center">
1852
+ <div className="w-16 h-16 bg-indigo-500/20 rounded-full flex items-center justify-center mx-auto mb-6">
1853
+ <Key className="w-8 h-8 text-indigo-400" />
1854
+ </div>
1855
+ <h2 className="text-2xl font-black text-white mb-2 tracking-tight">Welcome to MindSpark</h2>
1856
+ <p className="text-slate-400 text-sm mb-6 leading-relaxed">
1857
+ To use this AI Workspace, you need your own Google Gemini API Key.
1858
+ Your key is stored securely in your browser's local storage and is never sent to our servers.
1859
+ </p>
1860
+ <a href="https://aistudio.google.com/app/apikey" target="_blank" rel="noreferrer" className="text-indigo-400 hover:text-indigo-300 text-sm font-medium mb-6 inline-block transition-colors">
1861
+ Get your free API key here &rarr;
1862
+ </a>
1863
+ <div className="space-y-4 text-left">
1864
+ <label className="block text-xs font-bold text-slate-400 uppercase tracking-wider">Gemini API Key</label>
1865
+ <input
1866
+ type="password"
1867
+ id="gateway-api-key"
1868
+ placeholder="AIzaSy..."
1869
+ className="w-full bg-black/40 border border-white/10 rounded-xl px-4 py-3 text-white focus:border-indigo-500 outline-none transition-all"
1870
+ onKeyDown={(e) => {
1871
+ if (e.key === 'Enter') {
1872
+ const val = e.currentTarget.value.trim();
1873
+ if (val) {
1874
+ localStorage.setItem('user_gemini_api_key', val);
1875
+ setUserGeminiKey(val);
1876
+ window.location.reload();
1877
+ }
1878
+ }
1879
+ }}
1880
+ />
1881
+ <button
1882
+ onClick={() => {
1883
+ const val = (document.getElementById('gateway-api-key') as HTMLInputElement).value.trim();
1884
+ if (val) {
1885
+ localStorage.setItem('user_gemini_api_key', val);
1886
+ setUserGeminiKey(val);
1887
+ window.location.reload();
1888
+ }
1889
+ }}
1890
+ className="w-full bg-indigo-600 hover:bg-indigo-500 text-white font-black py-3 rounded-xl transition-all shadow-lg shadow-indigo-600/20"
1891
+ >
1892
+ Save & Continue
1893
+ </button>
1894
+ </div>
1895
+ </div>
1896
+ </div>
1897
+ )}
1898
+
1899
  {/* Mobile Sidebar Overlay */}
1900
  {isMobileMenuOpen && (
1901
  <div
firebase.ts CHANGED
@@ -13,8 +13,9 @@ const firebaseConfig = {
13
  };
14
 
15
  // Check if Firebase config is complete to avoid "invalid-api-key" error
16
- if (!firebaseConfig.apiKey) {
17
- console.warn("Firebase API Key is missing. Please check your .env file or environment variables.");
 
18
  }
19
 
20
  const app = initializeApp(firebaseConfig);
@@ -23,6 +24,9 @@ export const db = getFirestore(app, import.meta.env.VITE_FIREBASE_FIRESTORE_DATA
23
  export const googleProvider = new GoogleAuthProvider();
24
 
25
  export const signInWithGoogle = async () => {
 
 
 
26
  try {
27
  const result = await signInWithPopup(auth, googleProvider);
28
  return result.user;
@@ -33,6 +37,7 @@ export const signInWithGoogle = async () => {
33
  };
34
 
35
  export const logOut = async () => {
 
36
  try {
37
  await signOut(auth);
38
  } catch (error) {
@@ -43,11 +48,12 @@ export const logOut = async () => {
43
 
44
  // Test connection
45
  async function testConnection() {
 
46
  try {
47
  await getDocFromServer(doc(db, 'test', 'connection'));
48
  } catch (error) {
49
  if(error instanceof Error && error.message.includes('the client is offline')) {
50
- console.error("Please check your Firebase configuration. ");
51
  }
52
  }
53
  }
 
13
  };
14
 
15
  // Check if Firebase config is complete to avoid "invalid-api-key" error
16
+ const isDummy = firebaseConfig.apiKey === "dummy-api-key" || !firebaseConfig.apiKey;
17
+ if (isDummy) {
18
+ console.log("Firebase is running in Local Workspace Mode (No API keys provided). Data will be saved locally.");
19
  }
20
 
21
  const app = initializeApp(firebaseConfig);
 
24
  export const googleProvider = new GoogleAuthProvider();
25
 
26
  export const signInWithGoogle = async () => {
27
+ if (isDummy) {
28
+ throw new Error("LocalMode");
29
+ }
30
  try {
31
  const result = await signInWithPopup(auth, googleProvider);
32
  return result.user;
 
37
  };
38
 
39
  export const logOut = async () => {
40
+ if (isDummy) return;
41
  try {
42
  await signOut(auth);
43
  } catch (error) {
 
48
 
49
  // Test connection
50
  async function testConnection() {
51
+ if (isDummy) return;
52
  try {
53
  await getDocFromServer(doc(db, 'test', 'connection'));
54
  } catch (error) {
55
  if(error instanceof Error && error.message.includes('the client is offline')) {
56
+ console.warn("Firebase client is offline. Defaulting to local mode.");
57
  }
58
  }
59
  }
services/geminiService.ts CHANGED
@@ -4,10 +4,10 @@ import { ProjectPlan, NoteType, StyleMemory } from "../types";
4
  const getAI = () => {
5
  const userKey = localStorage.getItem('user_gemini_api_key');
6
  const apiKey = userKey || process.env.GEMINI_API_KEY;
7
- if (!apiKey) {
8
- console.warn("Gemini API Key is missing. Please set it in Settings.");
9
  }
10
- return new GoogleGenAI({ apiKey: apiKey || 'dummy-key' });
11
  };
12
 
13
  // Helper to compress base64 images to avoid Firestore 1MB limit
 
4
  const getAI = () => {
5
  const userKey = localStorage.getItem('user_gemini_api_key');
6
  const apiKey = userKey || process.env.GEMINI_API_KEY;
7
+ if (!apiKey || apiKey === 'dummy-key') {
8
+ throw new Error("API_KEY_MISSING");
9
  }
10
+ return new GoogleGenAI({ apiKey: apiKey });
11
  };
12
 
13
  // Helper to compress base64 images to avoid Firestore 1MB limit