Skip to content

Commit b3aedd5

Browse files
committed
Remove check-env.js from tracking and add to .gitignore
1 parent 1a0f761 commit b3aedd5

8 files changed

Lines changed: 711 additions & 1056 deletions

File tree

client/src/App.tsx

Lines changed: 46 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1+
// client/src/App.tsx
2+
3+
import React, { useEffect } from "react";
14
import { Switch, Route } from "wouter";
2-
import { Toaster } from "@/components/ui/toaster";
35
import { TooltipProvider } from "@/components/ui/tooltip";
4-
import { QueryClientProvider } from "@tanstack/react-query";
5-
import { queryClient } from "@/lib/queryClient";
6-
import { SnippetProvider } from "@/contexts/SnippetContext";
7-
import { CollectionProvider } from "@/contexts/CollectionContext";
86
import { ThemeProvider } from "@/contexts/ThemeContext";
97
import { CodeThemeProvider } from "@/contexts/CodeThemeContext";
10-
import { AuthProvider } from "@/contexts/AuthContext";
8+
import { SnippetProvider } from "@/contexts/SnippetContext";
9+
import { CollectionProvider } from "@/contexts/CollectionContext";
10+
import { useAuthContext } from "@/contexts/AuthContext";
1111
import NotFound from "@/pages/not-found";
1212
import Home from "@/pages/Home";
1313
import Snippets from "@/pages/Snippets";
@@ -16,8 +16,7 @@ import CollectionDetail from "@/pages/CollectionDetail";
1616
import Tags from "@/pages/Tags";
1717
import Settings from "@/pages/Settings";
1818
import SharedSnippet from "@/pages/SharedSnippet";
19-
import { useEffect } from "react";
20-
import { DebugEnv } from './components/Debug';
19+
import { DebugEnv } from "./components/Debug";
2120

2221
function Router() {
2322
return (
@@ -34,40 +33,49 @@ function Router() {
3433
);
3534
}
3635

37-
function App() {
38-
// Get theme from document.documentElement class list
36+
export default function App() {
37+
const { user, loading, signIn } = useAuthContext();
38+
39+
// Apply your theme class once on mount
3940
useEffect(() => {
40-
// Check for system preference
4141
const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
42-
const savedTheme = localStorage.getItem("theme");
43-
const isDark = savedTheme === "dark" || (!savedTheme && prefersDark);
44-
45-
if (isDark) {
46-
document.documentElement.classList.add('dark');
47-
} else {
48-
document.documentElement.classList.remove('dark');
49-
}
42+
const saved = localStorage.getItem("theme");
43+
const isDark = saved === "dark" || (!saved && prefersDark);
44+
document.documentElement.classList.toggle("dark", isDark);
5045
}, []);
5146

47+
// 1) Still waiting for Firebase → show spinner or placeholder
48+
if (loading) {
49+
return <div className="h-screen flex items-center justify-center">Loading…</div>;
50+
}
51+
52+
// 2) Not signed in → show Google button
53+
if (!user) {
54+
return (
55+
<div className="h-screen flex items-center justify-center">
56+
<button
57+
onClick={signIn}
58+
className="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700"
59+
>
60+
Sign in with Google
61+
</button>
62+
</div>
63+
);
64+
}
65+
66+
// 3) Signed in → render the full app
5267
return (
53-
<QueryClientProvider client={queryClient}>
54-
<AuthProvider>
55-
<ThemeProvider>
56-
<CodeThemeProvider>
57-
<SnippetProvider>
58-
<CollectionProvider>
59-
<TooltipProvider>
60-
<Toaster />
61-
<Router />
62-
</TooltipProvider>
63-
</CollectionProvider>
64-
</SnippetProvider>
65-
</CodeThemeProvider>
66-
</ThemeProvider>
67-
</AuthProvider>
68-
<DebugEnv />
69-
</QueryClientProvider>
68+
<ThemeProvider>
69+
<CodeThemeProvider>
70+
<SnippetProvider>
71+
<CollectionProvider>
72+
<TooltipProvider>
73+
<Router />
74+
<DebugEnv />
75+
</TooltipProvider>
76+
</CollectionProvider>
77+
</SnippetProvider>
78+
</CodeThemeProvider>
79+
</ThemeProvider>
7080
);
7181
}
72-
73-
export default App;
Lines changed: 27 additions & 238 deletions
Original file line numberDiff line numberDiff line change
@@ -1,247 +1,36 @@
1-
import { createContext, useContext, useEffect, useState, ReactNode } from 'react';
2-
import {
3-
User,
4-
createUserWithEmailAndPassword,
5-
signInWithEmailAndPassword,
6-
signOut,
7-
onAuthStateChanged,
8-
sendPasswordResetEmail,
9-
signInWithPopup,
10-
updateProfile,
11-
GoogleAuthProvider,
12-
Auth
13-
} from 'firebase/auth';
14-
import { auth as firebaseAuth, googleProvider as firebaseGoogleProvider } from '@/lib/firebase';
15-
import { useToast } from '@/hooks/use-toast';
16-
import { apiRequest } from '@/lib/queryClient';
17-
18-
// Type assertions to ensure TypeScript understands our imports from firebase.ts
19-
const auth = firebaseAuth as Auth;
20-
const googleProvider = firebaseGoogleProvider as GoogleAuthProvider;
21-
22-
interface AuthContextProps {
23-
currentUser: User | null;
24-
isLoading: boolean;
25-
signUp: (email: string, password: string) => Promise<User>;
26-
login: (email: string, password: string) => Promise<User>;
27-
logout: () => Promise<void>;
28-
resetPassword: (email: string) => Promise<void>;
29-
signInWithGoogle: () => Promise<User>;
30-
updateUserProfile: (displayName: string) => Promise<void>;
31-
}
32-
33-
const AuthContext = createContext<AuthContextProps | null>(null);
34-
35-
export function useAuth() {
36-
const context = useContext(AuthContext);
37-
if (!context) {
38-
throw new Error('useAuth must be used within an AuthProvider');
39-
}
40-
return context;
1+
// client/src/contexts/AuthContext.tsx
2+
3+
import React, { createContext, ReactNode, useContext } from "react";
4+
import { useAuth } from "@/lib/useAuth";
5+
6+
interface AppUser {
7+
id: string;
8+
email: string | null;
9+
displayName: string | null;
10+
photoURL: string | null;
11+
createdAt: string;
12+
updatedAt: string;
4113
}
4214

43-
interface AuthProviderProps {
44-
children: ReactNode;
15+
interface AuthContextType {
16+
user: AppUser | null;
17+
loading: boolean;
18+
signIn: () => Promise<void>;
4519
}
4620

47-
export function AuthProvider({ children }: AuthProviderProps) {
48-
const [currentUser, setCurrentUser] = useState<User | null>(null);
49-
const [isLoading, setIsLoading] = useState<boolean>(true);
50-
const { toast } = useToast();
51-
52-
// Function to register user with our backend
53-
async function registerUserWithBackend(user: User) {
54-
try {
55-
if (user) {
56-
await fetch('/api/auth/user', {
57-
method: 'POST',
58-
headers: {
59-
'Content-Type': 'application/json',
60-
},
61-
body: JSON.stringify({
62-
uid: user.uid,
63-
email: user.email,
64-
displayName: user.displayName,
65-
photoURL: user.photoURL
66-
})
67-
});
68-
}
69-
} catch (error) {
70-
console.error("Error syncing user with backend:", error);
71-
}
72-
}
73-
74-
useEffect(() => {
75-
const unsubscribe = onAuthStateChanged(auth, (user) => {
76-
setCurrentUser(user);
77-
78-
// Register the user with our backend when they authenticate
79-
if (user) {
80-
registerUserWithBackend(user)
81-
.catch(error => console.error("Failed to register user with backend:", error));
82-
}
83-
84-
setIsLoading(false);
85-
});
86-
87-
return unsubscribe;
88-
}, []);
89-
90-
async function signUp(email: string, password: string): Promise<User> {
91-
try {
92-
const userCredential = await createUserWithEmailAndPassword(auth, email, password);
93-
// Register with our backend
94-
await registerUserWithBackend(userCredential.user);
95-
return userCredential.user;
96-
} catch (error: any) {
97-
const errorMessage = error.message || 'An error occurred during sign up';
98-
toast({
99-
title: 'Sign up failed',
100-
description: errorMessage,
101-
variant: 'destructive'
102-
});
103-
throw error;
104-
}
105-
}
106-
107-
async function login(email: string, password: string): Promise<User> {
108-
try {
109-
const userCredential = await signInWithEmailAndPassword(auth, email, password);
110-
// Register with our backend
111-
await registerUserWithBackend(userCredential.user);
112-
return userCredential.user;
113-
} catch (error: any) {
114-
const errorMessage = error.message || 'An error occurred during login';
115-
toast({
116-
title: 'Login failed',
117-
description: errorMessage,
118-
variant: 'destructive'
119-
});
120-
throw error;
121-
}
122-
}
123-
124-
async function logout(): Promise<void> {
125-
try {
126-
await signOut(auth);
127-
// No need to update backend as we're checking auth state in our API
128-
} catch (error: any) {
129-
const errorMessage = error.message || 'An error occurred during logout';
130-
toast({
131-
title: 'Logout failed',
132-
description: errorMessage,
133-
variant: 'destructive'
134-
});
135-
throw error;
136-
}
137-
}
138-
139-
async function resetPassword(email: string): Promise<void> {
140-
try {
141-
await sendPasswordResetEmail(auth, email);
142-
toast({
143-
title: 'Password reset email sent',
144-
description: 'Check your email for further instructions',
145-
});
146-
} catch (error: any) {
147-
const errorMessage = error.message || 'An error occurred during password reset';
148-
toast({
149-
title: 'Password reset failed',
150-
description: errorMessage,
151-
variant: 'destructive'
152-
});
153-
throw error;
154-
}
155-
}
156-
157-
async function signInWithGoogle(): Promise<User> {
158-
try {
159-
// Ensure Firebase auth is available
160-
if (!auth) {
161-
throw new Error("Firebase authentication is not available");
162-
}
163-
164-
// Create a new GoogleAuthProvider instance for this sign-in attempt
165-
// This ensures we have a fresh provider each time
166-
const provider = new GoogleAuthProvider();
167-
168-
// Add the scopes we need
169-
provider.addScope('email');
170-
provider.addScope('profile');
171-
172-
// Set custom parameters
173-
provider.setCustomParameters({
174-
prompt: 'select_account'
175-
});
176-
177-
// Use popup for mobile compatibility
178-
const result = await signInWithPopup(auth, provider);
179-
180-
// Register with our backend
181-
await registerUserWithBackend(result.user);
182-
return result.user;
183-
} catch (error: any) {
184-
// Provide a more user-friendly error message
185-
let errorMessage = 'An error occurred during Google sign in';
186-
187-
if (error.code === 'auth/popup-blocked') {
188-
errorMessage = 'The sign-in popup was blocked by your browser. Please allow popups for this site.';
189-
} else if (error.code === 'auth/popup-closed-by-user') {
190-
errorMessage = 'The sign-in popup was closed before completing the process.';
191-
} else if (error.code === 'auth/cancelled-popup-request') {
192-
errorMessage = 'The operation was cancelled.';
193-
} else if (error.code === 'auth/unauthorized-domain') {
194-
errorMessage = 'This domain is not authorized for Google sign-in. Please add this domain to your Firebase console under Authentication > Settings > Authorized domains.';
195-
} else if (error.code === 'auth/configuration-not-found') {
196-
errorMessage = 'Firebase configuration error. Please try email/password login or contact support.';
197-
} else if (error.message) {
198-
errorMessage = error.message;
199-
}
200-
201-
toast({
202-
title: 'Google sign in failed',
203-
description: errorMessage,
204-
variant: 'destructive'
205-
});
206-
throw error;
207-
}
208-
}
209-
210-
async function updateUserProfile(displayName: string): Promise<void> {
211-
try {
212-
if (currentUser) {
213-
await updateProfile(currentUser, { displayName });
214-
// Force refresh the user object
215-
setCurrentUser({ ...currentUser });
216-
217-
// Update user profile in our backend
218-
await registerUserWithBackend(currentUser);
219-
}
220-
} catch (error: any) {
221-
const errorMessage = error.message || 'An error occurred while updating profile';
222-
toast({
223-
title: 'Profile update failed',
224-
description: errorMessage,
225-
variant: 'destructive'
226-
});
227-
throw error;
228-
}
229-
}
230-
231-
const value = {
232-
currentUser,
233-
isLoading,
234-
signUp,
235-
login,
236-
logout,
237-
resetPassword,
238-
signInWithGoogle,
239-
updateUserProfile
240-
};
21+
const AuthContext = createContext<AuthContextType | undefined>(undefined);
24122

23+
export function AuthProvider({ children }: { children: ReactNode }) {
24+
const { user, loading, signIn } = useAuth();
24225
return (
243-
<AuthContext.Provider value={value}>
26+
<AuthContext.Provider value={{ user, loading, signIn }}>
24427
{children}
24528
</AuthContext.Provider>
24629
);
247-
}
30+
}
31+
32+
export function useAuthContext() {
33+
const ctx = useContext(AuthContext);
34+
if (!ctx) throw new Error("useAuthContext must be used within AuthProvider");
35+
return ctx;
36+
}

0 commit comments

Comments
 (0)