Skip to content

Commit

Permalink
fixed google auth, added auth provider, fixed logout, added tabs comp…
Browse files Browse the repository at this point in the history
…onent, added dependencies for typing gapi auth/oauth2/drive
  • Loading branch information
k1tbyte committed Jun 5, 2024
1 parent 6d8f032 commit 589c36b
Show file tree
Hide file tree
Showing 9 changed files with 211 additions and 118 deletions.
4 changes: 4 additions & 0 deletions SteamOrganizer.Web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"@fingerprintjs/fingerprintjs": "^4.2.2",
"clsx": "^2.1.0",
"framer-motion": "^11.2.9",
"gapi-script": "^1.2.0",
"overlayscrollbars": "^2.7.3",
"react": "^18.2.0",
"react-cool-virtual": "^0.7.0",
Expand All @@ -22,6 +23,9 @@
"tailwind-merge": "^2.3.0"
},
"devDependencies": {
"@types/gapi": "^0.0.47",
"@types/gapi.auth2": "^0.0.60",
"@types/gapi.client.drive-v3": "^0.0.4",
"@types/react": "^18.2.66",
"@types/react-dom": "^18.2.22",
"@typescript-eslint/eslint-plugin": "^7.2.0",
Expand Down
7 changes: 5 additions & 2 deletions SteamOrganizer.Web/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import Authentication from "@/pages/Modals/Authentication.tsx";
import { Defs } from "./assets"
import {modal, ModalsHost} from "./components/elements/Modal.tsx";
import {Profile} from "@/pages/Profile/Profile.tsx";
import {AuthProvider} from "@/providers/authProvider.tsx";

const router = createBrowserRouter([
{
Expand Down Expand Up @@ -81,8 +82,10 @@ export default function App() {

return (
<>
<RouterProvider router={router}/>
<ModalsHost/>
<AuthProvider>
<RouterProvider router={router}/>
<ModalsHost/>
</AuthProvider>
<Defs/>
</>
)
Expand Down
1 change: 1 addition & 0 deletions SteamOrganizer.Web/src/components/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ export const Sidebar: FC<ISidebarProps> = ({children}) => {
{/* <span className="text-foreground-muted text-xs">kit8.com</span>*/}
{/* <div className="absolute w-1/3 h-full right-0 bg-gradient-to-r from-transparent to-primary"/>*/}
{/*</div>*/}
<GoogleLogin></GoogleLogin>


</div>
Expand Down
142 changes: 27 additions & 115 deletions SteamOrganizer.Web/src/components/elements/GoogleLogin.tsx
Original file line number Diff line number Diff line change
@@ -1,119 +1,31 @@
import React, {useState, useEffect, useRef} from 'react';
import { gapi } from 'gapi-script';
import {saveFile} from "@/services/gdrive.ts";

interface User {
name: string;
profileImg: string;
email:string;
}


interface GoogleLoginProps {
apiKey:string;
clientId: string;
discoveryDocs?:string[];
scope?: string;
}

export const GoogleLogin: React.FC<GoogleLoginProps> = ({
clientId, apiKey,
scope = 'https://www.googleapis.com/auth/drive.file',
discoveryDocs=['https://www.googleapis.com/discovery/v1/apis/drive/v3/rest'],
}) => {
let gay=true;
const [user, setUser] = useState<User|null>(null

/*
{email: "[email protected]",
profileImg: "https://ui-avatars.com/api/?background=c7d2fe&color=3730a3&bold=true",
name:"John doe"}*/)
const signIn = () => {

if(gay){
console.log(JSON.stringify(user));
gapi.auth2.getAuthInstance().signIn();
}

};

/**
* Called when the signed in status changes, to update the UI
* appropriately. After a sign-in, the API is called.
*/
const updateUser = (isSignedIn: boolean) => {
if (isSignedIn) {
let currentUser= gapi.auth2.getAuthInstance().currentUser.get().getBasicProfile();
const name = currentUser.getName();
const profileImg = currentUser.getImageUrl();
const email =currentUser.getEmail();
setUser({
name,
profileImg,
email,
});
saveFile();
} else {
signIn();
}
};

const initClient = () => {
gapi.client
.init({
apiKey: apiKey,
clientId: clientId,
discoveryDocs: discoveryDocs,
scope: scope,
})
.then(
function () {
// Listen for sign-in state changes.
gapi.auth2.getAuthInstance().isSignedIn.listen(updateUser);
// Handle the initial sign-in state.
updateUser(gapi.auth2.getAuthInstance().isSignedIn.get());
}
);
};

const HandleSignIn = () => {
//After the platform library loads, load the auth2 library:
gapi.load('client:auth2', initClient);
};

const HandleSignOut = () => {
gay=false;
const auth2 = gapi.auth2.getAuthInstance();
auth2.signOut().then(() => {
setUser(null);
//console.log('User signed out.');
});
};
if(user) {
return (
<div>
<img
src={user.profileImg}
alt=""
className="w-10 h-10 rounded-md"
/>
<div className="pl-2 flex-col flex justify-center text-nowrap w-full truncate relative">
<h4 className="text-fg-3 text-sm">{user.name}</h4>
<span className="text-fg-1 text-xs">{user.email}</span>
<div className="absolute w-1/3 h-full right-0 bg-gradient-to-r from-transparent to-pr-2"/>
import React from 'react';
import {useAuth} from "@/providers/authProvider.tsx";

export const GoogleLogin: React.FC = () => {
const { user, signIn, signOut } = useAuth();

return (user.isLoggedIn ? (
<div>
<img
src={user.profileImg}
alt=""
className="w-10 h-10 rounded-md"
/>
<div className="pl-2 flex-col flex justify-center text-nowrap w-full truncate relative">
<h4 className="text-fg-3 text-sm">{user.name}</h4>
<span className="text-fg-1 text-xs">{user.email}</span>
<div className="absolute w-1/3 h-full right-0 bg-gradient-to-r from-transparent to-pr-2"/>
</div>
<div className="btn" onClick={signOut}>
Logout
</div>
</div>
<div className="btn" onClick={HandleSignOut}>
Logout
) : (
<div>
<div className="btn" onClick={signIn}>
<p>{user.isLoggedIn === undefined ? "loading..." : "Sign in"} </p>
</div>
</div>
</div>
);
}

return (
<div>
<div className="btn" onClick={HandleSignIn}>
Login
</div>
</div>
)
);
}
61 changes: 61 additions & 0 deletions SteamOrganizer.Web/src/components/elements/Tabs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import {AnimatePresence, motion} from "framer-motion";
import React, {FC, Key, ReactNode, useState} from "react";
import clsx from "clsx";

interface ITabProps {
children: ReactNode,
title: ReactNode,
}

interface ITabPanelProps {
children: React.ReactElement<ITabProps> | React.ReactElement<ITabProps>[];
activeKey: Key
}

export const TabPanel: FC<ITabPanelProps> = ({ children, activeKey }) => {
const [active, setActive] = useState(activeKey)
let renderContent: ReactNode;

return (
<div className="flex items-center flex-col">
<div className="flex gap-3 mb-10 bg-primary p-2 rounded-lg ">
{
React.Children.map(children, (child) => {
let isActive: boolean = false;
if (child.key == active) {
renderContent = child
isActive = true
}
return (
<button key={child.key} onClick={() => setActive(child.key!)}
className={clsx("relative px-3 py-1.5 text-sm font-medium text-black transition-colors",
isActive ? "text-background" : "text-foreground")}>
{isActive &&
(<motion.div layoutId="active-pill" style={{borderRadius: 8}}
transition={{type: "spring", duration: 0.6}}
className="absolute inset-0 bg-secondary"/>)
}
<span className="relative z-10">{child.props.title}</span>
</button>
)
})
}
</div>

<div>
<AnimatePresence>
<motion.div initial={{opacity: 0, marginTop: 20}} key={active}
animate={{opacity: 1, marginTop: 0}}>
{renderContent}
</motion.div>
</AnimatePresence>
</div>
</div>
)
}

export const Tab: FC<ITabProps> = ({ children}) => (
<>
{children}
</>
)
18 changes: 18 additions & 0 deletions SteamOrganizer.Web/src/lib/eventEmitter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export class EventEmitter<T> {
private listeners: Array<(data: T) => void> = new Array<(data: T) => void>();

subscribe(listener: (data: T) => void): void {
this.listeners.push(listener);
}

unsubscribe(listener: (data: T) => void): void {
const index = this.listeners.indexOf(listener);
if (index > -1) {
this.listeners.splice(index, 1);
}
}

emit(data: T): void {
this.listeners.forEach(listener => listener(data));
}
}
51 changes: 51 additions & 0 deletions SteamOrganizer.Web/src/providers/authProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React, {createContext, useContext, useState, ReactNode, useEffect} from 'react';
import {getUserProfile, initGapi, signIn, signOut, subscribe, unsubscribe} from "@/services/gAuthService.ts";

interface IAuthUser {
isLoggedIn?: boolean | undefined;
name?: string;
profileImg?: string;
email?:string;
}

interface AuthContextType {
signIn: () => void;
signOut: () => void;
user: IAuthUser;
}

const AuthContext = createContext<AuthContextType>(undefined!);

export const AuthProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
const [user, setUser] = useState<IAuthUser>({});

useEffect(() => {
const stateCallback = (state: boolean) => {
let info;
if(state) {
const profile = getUserProfile()
info ={
isLoggedIn: state,
email: profile.getEmail(),
name: profile.getName(),
profileImg: profile.getImageUrl()
}
}
setUser(info ?? { isLoggedIn: state })
}

subscribe(stateCallback)
initGapi()

return () => unsubscribe(stateCallback)
},[])


return (
<AuthContext.Provider value={{ user, signIn, signOut }}>
{children}
</AuthContext.Provider>
);
};

export const useAuth = () => useContext(AuthContext);
42 changes: 42 additions & 0 deletions SteamOrganizer.Web/src/services/gAuthService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { gapi } from 'gapi-script';
import {EventEmitter} from "@/lib/eventEmitter.ts";

export let isAuthorized : boolean;
const authSubscribers: EventEmitter<boolean> = new EventEmitter<boolean>()

const setAuthState = (state: boolean) => {
isAuthorized = state;
authSubscribers.emit(state)
}

const onClientInitializing = async () => {
await gapi.client.init({
apiKey: "AIzaSyCWCk7kXhV2kmsPs8Bv6Abe8hAx4RDa_z0",
clientId: "1051364021046-9rkovhkatqt70kmubg8fv7ukbalobj8q.apps.googleusercontent.com",
discoveryDocs: [ "https://www.googleapis.com/discovery/v1/apis/drive/v3/rest" ],
scope: "https://www.googleapis.com/auth/drive.file",
})

const instance = gapi.auth2.getAuthInstance();
setAuthState(instance.isSignedIn.get())
instance.isSignedIn.listen(setAuthState)
}

export const signIn = () =>
gapi.auth2.getAuthInstance().signIn( { ux_mode: "popup" } );

export const signOut = () =>
gapi.auth2.getAuthInstance().disconnect();

export const subscribe = (callback: (data: boolean) => void ) =>
authSubscribers.subscribe(callback)

export const unsubscribe = (callback: (data: boolean) => void ) =>
authSubscribers.unsubscribe(callback);

export const getUserProfile = () =>
gapi.auth2.getAuthInstance().currentUser.get().getBasicProfile();

export const initGapi = () =>
gapi.load('client:auth2', onClientInitializing);

3 changes: 2 additions & 1 deletion SteamOrganizer.Web/src/services/gdrive.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@

import {gapi} from "gapi-script";
import {isAuthorized} from "@/services/gAuthService.ts";


export const saveFile = async () => {
if (!gapi.auth2.getAuthInstance()) {
if (!isAuthorized) {
console.log('User not signed in');
return;
}
Expand Down

0 comments on commit 589c36b

Please sign in to comment.