Skip to content

Commit 34b8c75

Browse files
committed
added google auth provider
1 parent 668e4ae commit 34b8c75

19 files changed

Lines changed: 384 additions & 27 deletions

File tree

package-lock.json

Lines changed: 105 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"@fontsource/geist-mono": "^5.2.7",
1616
"@mantine/core": "^8.3.10",
1717
"@mantine/hooks": "^8.3.10",
18+
"@supabase/supabase-js": "^2.89.0",
1819
"@tanstack/react-router": "^1.143.3",
1920
"@tanstack/react-router-devtools": "^1.143.3",
2021
"react": "^19.2.3",

src/app/providers/auth-context.tsx

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import {
2+
createContext,
3+
useContext,
4+
useEffect,
5+
useState,
6+
ReactNode,
7+
} from 'react';
8+
import { authAdapter } from '@/shared/api/auth';
9+
10+
interface AuthContextType {
11+
user: any | null;
12+
isLoading: boolean;
13+
setIsLoading: (loading: boolean) => void;
14+
}
15+
16+
export const AuthContext = createContext<AuthContextType | undefined>(
17+
undefined
18+
);
19+
20+
export const AuthProvider = ({ children }: { children: ReactNode }) => {
21+
const [user, setUser] = useState<any | null>(null);
22+
const [isLoading, setIsLoading] = useState(true);
23+
useEffect(() => {
24+
const unsubscribe = authAdapter.onAuthStateChange((currentUser) => {
25+
setUser(currentUser);
26+
setIsLoading(false);
27+
if (window.location.href.endsWith('#')) {
28+
window.history.replaceState(null, '', window.location.pathname);
29+
}
30+
});
31+
return () => unsubscribe();
32+
}, []);
33+
34+
return (
35+
<AuthContext.Provider value={{ user, isLoading, setIsLoading }}>
36+
{children}
37+
</AuthContext.Provider>
38+
);
39+
};
40+
41+
export const useAuth = () => {
42+
const context = useContext(AuthContext);
43+
if (context === undefined)
44+
throw new Error('useAuth must be used within an AuthProvider');
45+
return context;
46+
};

src/app/providers/index.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import { ComponentType } from 'react';
33
import { withMantine } from './with-mantine';
44
import { withRouter } from './with-router';
5+
import { withAuth } from './with-auth';
56

67
type HOC = (component: ComponentType<any>) => ComponentType<any>;
78

@@ -11,4 +12,4 @@ const compose = (...hocs: HOC[]) => {
1112
};
1213
};
1314

14-
export const withProviders = compose(withMantine, withRouter);
15+
export const withProviders = compose(withMantine, withAuth, withRouter);

src/app/providers/with-auth.tsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { ComponentType } from 'react';
2+
import { AuthProvider } from './auth-context';
3+
4+
export const withAuth = (Component: ComponentType) => {
5+
const WrappedComponent = (props: any) => (
6+
<AuthProvider>
7+
<Component {...props} />
8+
</AuthProvider>
9+
);
10+
WrappedComponent.displayName = `withAuth(${Component.displayName || Component.name || 'Component'})`;
11+
return WrappedComponent;
12+
};

src/app/providers/with-router.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,14 @@
22
import { RouterProvider, createRouter } from '@tanstack/react-router';
33
import { routeTree } from '../../routeTree.gen';
44
import { ComponentType } from 'react';
5+
import { NotFoundPage } from '@/pages/not-found';
56

6-
const router = createRouter({ routeTree });
7+
const router = createRouter({
8+
routeTree,
9+
defaultNotFoundComponent: () => {
10+
return <NotFoundPage />;
11+
},
12+
});
713

814
export const withRouter = (_Component: ComponentType) => {
915
return () => <RouterProvider router={router} />;

src/entities/UserCard.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1+
import { useAuth } from '@/app/providers/auth-context';
12
import { Box, Group, MantineTheme, UnstyledButton, Text } from '@mantine/core';
23

34
export function UserCard() {
5+
const { user, isLoading } = useAuth();
6+
47
return (
58
<UnstyledButton
69
p="md"
@@ -13,10 +16,10 @@ export function UserCard() {
1316
<Group>
1417
<Box style={{ flex: 1 }}>
1518
<Text size="sm" fw={500}>
16-
Rohit Handique
19+
{!isLoading && user ? user.user_metadata.name : ''}
1720
</Text>
1821
<Text c="dimmed" size="xs">
19-
rohit.handique@gmail.com
22+
{!isLoading && user ? user.email : ''}
2023
</Text>
2124
</Box>
2225
</Group>

src/features/SignInModal.tsx

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,58 @@ import {
1313
Button,
1414
Flex,
1515
Group,
16+
Loader,
1617
} from '@mantine/core';
17-
import { useNavigate } from '@tanstack/react-router';
18+
import { useLocation, useNavigate } from '@tanstack/react-router';
19+
import { useAuth } from '@/app/providers/auth-context';
20+
import { authAdapter } from '@/shared/api/auth';
1821

1922
export function SignInModal() {
2023
const [opened, { open, close }] = useDisclosure(false);
2124
const navigate = useNavigate();
25+
const location = useLocation();
2226

27+
const { user, isLoading, setIsLoading } = useAuth();
2328
const modalContentHeight = rem(550);
2429

25-
const mockLogin = () => {
26-
close();
27-
navigate({ to: '/dashboard' });
30+
const handleGoogleLogin = async () => {
31+
try {
32+
setIsLoading(true);
33+
await authAdapter.loginWithGoogle();
34+
close();
35+
} catch (err) {
36+
console.error('Google Login failed', err);
37+
}
2838
};
2939

40+
const handleLogout = async () => {
41+
try {
42+
setIsLoading(true);
43+
navigate({ to: '/', replace: false });
44+
await authAdapter.logout();
45+
} catch (err) {
46+
console.error('Logout failed', err);
47+
}
48+
};
49+
50+
if (user) {
51+
if (location.pathname === '/') {
52+
return (
53+
<Button
54+
variant="filled"
55+
onClick={() => navigate({ to: '/dashboard', replace: false })}
56+
>
57+
{isLoading ? <Loader size={'xs'} /> : 'Go to Dashboard'}
58+
</Button>
59+
);
60+
}
61+
return (
62+
<Button variant="outline" onClick={() => handleLogout()}>
63+
Logout
64+
</Button>
65+
);
66+
}
67+
3068
return (
3169
<>
3270
<Modal
@@ -115,9 +153,10 @@ export function SignInModal() {
115153
mt="xl"
116154
size="md"
117155
radius="md"
118-
onClick={() => mockLogin()}
156+
loading={isLoading} // Show loading state if auth is initializing
157+
onClick={handleGoogleLogin} // Call t
119158
>
120-
Login
159+
Continue with Google{' '}
121160
</Button>
122161

123162
<Text ta="center" mt="md" size="sm">
@@ -147,7 +186,7 @@ export function SignInModal() {
147186
</Modal>
148187

149188
<Button variant="default" onClick={open}>
150-
Sign In
189+
{isLoading ? <Loader size={'xs'} /> : 'Sign In'}
151190
</Button>
152191
</>
153192
);

src/pages/landing/ui/features/index.tsx

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,6 @@ export function Features() {
7171
style={{
7272
fontSize: rem(34),
7373
fontWeight: 500,
74-
// Responsive font size using standard CSS logic
75-
'@media (max-width: 48em)': {
76-
fontSize: rem(24),
77-
},
7874
}}
7975
>
8076
Integrate effortlessly with any technology stack

src/pages/not-found/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { NotFoundPage as NotFoundPage } from './ui/NotFoundPage';

0 commit comments

Comments
 (0)