1- import { useEffect , useState , useRef } from "react" ;
1+ import { useEffect , useState } from "react" ;
22import { signInWithPopup , onAuthStateChanged , signOut } from "firebase/auth" ;
33import { auth , googleProvider } from "../../firebase" ;
44import { useNavigate } from "react-router-dom" ;
@@ -7,63 +7,85 @@ export default function Login() {
77 const [ loggedIn , setLoggedIn ] = useState ( false ) ;
88 const [ userInfo , setUserInfo ] = useState ( { name : "" , email : "" } ) ;
99 const navigate = useNavigate ( ) ;
10+
1011 const ACTIVITY_LIMIT = 20 * 60 * 1000 ;
11- const inactivityTimer = useRef ( null ) ;
12+ const LAST_ACTIVE_KEY = "lastActiveTime" ;
1213
13- const resetTimer = ( ) => {
14- if ( ! loggedIn ) return ;
15- clearTimeout ( inactivityTimer . current ) ;
16- inactivityTimer . current = setTimeout (
17- ( ) => handleLogout ( true ) ,
18- ACTIVITY_LIMIT
19- ) ;
14+ const updateLastActive = ( ) => {
15+ if ( loggedIn ) {
16+ localStorage . setItem ( LAST_ACTIVE_KEY , Date . now ( ) . toString ( ) ) ;
17+ }
2018 } ;
2119
22- useEffect ( ( ) => {
23- const events = [ "mousemove" , "keydown" , "click" , "touchstart" ] ;
24- events . forEach ( ( e ) => window . addEventListener ( e , resetTimer ) ) ;
25- return ( ) =>
26- events . forEach ( ( e ) => window . removeEventListener ( e , resetTimer ) ) ;
27- } , [ loggedIn ] ) ;
20+ const handleLogout = async ( auto ) => {
21+ await signOut ( auth ) ;
22+ localStorage . removeItem ( LAST_ACTIVE_KEY ) ;
23+ setLoggedIn ( false ) ;
24+ if ( auto ) alert ( "You were logged out dude." ) ;
25+ navigate ( "/" ) ;
26+ } ;
27+
28+ const checkInactivity = async ( ) => {
29+ const lastActive = localStorage . getItem ( LAST_ACTIVE_KEY ) ;
30+ if ( ! lastActive ) return ;
31+
32+ if ( Date . now ( ) - Number ( lastActive ) >= ACTIVITY_LIMIT ) {
33+ await handleLogout ( true ) ;
34+ }
35+ } ;
2836
2937 useEffect ( ( ) => {
30- const unsub = onAuthStateChanged ( auth , ( user ) => {
38+ const unsub = onAuthStateChanged ( auth , async ( user ) => {
3139 if ( user ) {
40+ const lastActive = localStorage . getItem ( LAST_ACTIVE_KEY ) ;
41+ if (
42+ lastActive &&
43+ Date . now ( ) - Number ( lastActive ) >= ACTIVITY_LIMIT
44+ ) {
45+ await signOut ( auth ) ;
46+ localStorage . removeItem ( LAST_ACTIVE_KEY ) ;
47+ return ;
48+ }
49+
3250 setUserInfo ( {
3351 name : user . displayName || "" ,
3452 email : user . email || ""
3553 } ) ;
3654 setLoggedIn ( true ) ;
37- resetTimer ( ) ;
55+ updateLastActive ( ) ;
3856 } else {
3957 setLoggedIn ( false ) ;
4058 setUserInfo ( { name : "" , email : "" } ) ;
59+ localStorage . removeItem ( LAST_ACTIVE_KEY ) ;
4160 }
4261 } ) ;
62+
4363 return ( ) => unsub ( ) ;
4464 } , [ ] ) ;
4565
66+ useEffect ( ( ) => {
67+ if ( ! loggedIn ) return ;
68+ const interval = setInterval ( checkInactivity , 60000 ) ;
69+ return ( ) => clearInterval ( interval ) ;
70+ } , [ loggedIn ] ) ;
71+
72+ useEffect ( ( ) => {
73+ const events = [ "mousemove" , "keydown" , "click" , "touchstart" ] ;
74+ events . forEach ( ( e ) => window . addEventListener ( e , updateLastActive ) ) ;
75+ return ( ) =>
76+ events . forEach ( ( e ) =>
77+ window . removeEventListener ( e , updateLastActive )
78+ ) ;
79+ } , [ loggedIn ] ) ;
4680
4781 const loginWithGoogle = async ( ) => {
48- try {
49- const result = await signInWithPopup ( auth , googleProvider ) ;
50- setUserInfo ( {
51- name : result . user . displayName ,
52- email : result . user . email
53- } ) ;
54- setLoggedIn ( true ) ;
55- resetTimer ( ) ;
56- } catch ( error ) {
57- console . error ( error ) ;
58- }
59- } ;
60-
61- const handleLogout = async ( auto ) => {
62- await signOut ( auth ) ;
63- setLoggedIn ( false ) ;
64- clearTimeout ( inactivityTimer . current ) ;
65- if ( auto ) alert ( "You were logged out dude." ) ;
66- navigate ( "/" ) ;
82+ const result = await signInWithPopup ( auth , googleProvider ) ;
83+ setUserInfo ( {
84+ name : result . user . displayName ,
85+ email : result . user . email
86+ } ) ;
87+ setLoggedIn ( true ) ;
88+ updateLastActive ( ) ;
6789 } ;
6890
6991 const goToDashboard = ( ) => navigate ( "/dashboard" ) ;
@@ -109,67 +131,46 @@ export default function Login() {
109131 height = "28"
110132 viewBox = "0 0 48 48"
111133 >
112- < path
113- fill = "#FFC107"
114- d = "M43.611,20.083H42V20H24v8h11.303c-1.649,4.657-6.08,8-11.303,8c-6.627,0-12-5.373-12-12c0-6.627,5.373-12,12-12c3.059,0,5.842,1.154,7.961,3.039l5.657-5.657C34.046,6.053,29.268,4,24,4C12.955,4,4,12.955,4,24c0,11.045,8.955,20,20,20c11.045,0,20-8.955,20-20C44,22.659,43.862,21.35,43.611,20.083z"
115- />
116- < path
117- fill = "#FF3D00"
118- d = "M6.306,14.691l6.571,4.819C14.655,15.108,18.961,12,24,12c3.059,0,5.842,1.154,7.961,3.039l5.657-5.657C34.046,6.053,29.268,4,24,4C16.318,4,9.656,8.337,6.306,14.691z"
119- />
120- < path
121- fill = "#4CAF50"
122- d = "M24,44c5.166,0,9.86-1.977,13.409-5.192l-6.19-5.238C29.211,35.091,26.715,36,24,36c-5.202,0-9.619-3.317-11.283-7.946l-6.522,5.025C9.505,39.556,16.227,44,24,44z"
123- />
124- < path
125- fill = "#1976D2"
126- d = "M43.611,20.083H42V20H24v8h11.303c-0.792,2.237-2.231,4.166-4.087,5.571l6.19,5.238C36.971,39.205,44,34,44,24C44,22.659,43.862,21.35,43.611,20.083z"
127- />
134+ < path fill = "#FFC107" d = "M43.611,20.083H24v8h11.303c-1.649,4.657-6.08,8-11.303,8c-6.627,0-12-5.373-12-12c0-6.627,5.373-12,12-12c3.059,0,5.842,1.154,7.961,3.039l5.657-5.657C34.046,6.053,29.268,4,24,4C12.955,4,4,12.955,4,24c0,11.045,8.955,20,20,20c11.045,0,20-8.955,20-20c0-1.341-0.138-2.65-0.389-3.917z" />
135+ < path fill = "#FF3D00" d = "M6.306,14.691l6.571,4.819C14.655,15.108,18.961,12,24,12c3.059,0,5.842,1.154,7.961,3.039l5.657-5.657C34.046,6.053,29.268,4,24,4c-7.682,0-14.344,4.337-17.694,10.691z" />
136+ < path fill = "#4CAF50" d = "M24,44c5.166,0,9.86-1.977,13.409-5.192l-6.19-5.238C29.211,35.091,26.715,36,24,36c-5.202,0-9.619-3.317-11.283-7.946l-6.522,5.025C9.505,39.556,16.227,44,24,44z" />
137+ < path fill = "#1976D2" d = "M43.611,20.083H24v8h11.303c-0.792,2.237-2.231,4.166-4.087,5.571l6.19,5.238C36.971,39.205,44,34,44,24c0-1.341-0.138-2.65-0.389-3.917z" />
128138 </ svg >
129- < span className = "text-base sm:text-lg" >
130- Continue with Google
131- </ span >
139+ < span className = "text-base sm:text-lg" > Continue with Google</ span >
132140 </ div >
133141 </ button >
134142 ) }
135143
136144 { loggedIn && (
137- < div className = "mt-7 bg-black/60 border border-yellow-700/30 p-4 rounded-2xl flex items-center gap-4" >
138- < div className = "flex-shrink-0 w-10 h-10 sm:w-12 sm:h-12 rounded-full bg-yellow-400 flex items-center justify-center text-black font-bold" >
139- { userInfo . name
140- ? userInfo . name . charAt ( 0 ) . toUpperCase ( )
141- : "U" }
142- </ div >
143- < div className = "text-left" >
144- < div className = "text-white font-semibold" >
145- { userInfo . name }
145+ < >
146+ < div className = "mt-7 bg-black/60 border border-yellow-700/30 p-4 rounded-2xl flex items-center gap-4" >
147+ < div className = "flex-shrink-0 w-10 h-10 sm:w-12 sm:h-12 rounded-full bg-yellow-400 flex items-center justify-center text-black font-bold" >
148+ { userInfo . name
149+ ? userInfo . name . charAt ( 0 ) . toUpperCase ( )
150+ : "U" }
146151 </ div >
147- < div className = "text-xs sm:text-sm text-yellow-100/70 break-all" >
148- { userInfo . email }
152+ < div className = "text-left" >
153+ < div className = "text-white font-semibold" > { userInfo . name } </ div >
154+ < div className = "text-xs sm:text-sm text-yellow-100/70 break-all" >
155+ { userInfo . email }
156+ </ div >
149157 </ div >
150158 </ div >
151- </ div >
152- ) }
153159
154- < button
155- onClick = { goToDashboard }
156- disabled = { ! loggedIn }
157- className = { `mt-6 w-full py-3 rounded-xl text-base sm:text-lg font-semibold transition shadow-lg ${
158- loggedIn
159- ? "bg-black/80 border border-yellow-400 text-white hover:bg-black/70"
160- : "bg-neutral-800 text-neutral-400 cursor-not-allowed"
161- } `}
162- >
163- Go to Dashboard
164- </ button >
160+ < button
161+ onClick = { goToDashboard }
162+ className = "mt-6 w-full py-3 rounded-xl text-base sm:text-lg font-semibold bg-black/80 border border-yellow-400 text-white hover:bg-black/70 transition shadow-lg"
163+ >
164+ Go to Dashboard
165+ </ button >
165166
166- { loggedIn && (
167- < button
168- onClick = { ( ) => handleLogout ( false ) }
169- className = "mt-4 w-full py-3 rounded-xl bg-red-600 hover:bg-red-700 text-white font-semibold text-base sm:text-lg shadow-md transition"
170- >
171- Logout
172- </ button >
167+ < button
168+ onClick = { ( ) => handleLogout ( false ) }
169+ className = "mt-4 w-full py-3 rounded-xl bg-red-600 hover:bg-red-700 text-white font-semibold text-base sm:text-lg shadow-md transition"
170+ >
171+ Logout
172+ </ button >
173+ </ >
173174 ) }
174175
175176 < div className = "mt-6 text-xs sm:text-sm text-yellow-100/60" >
0 commit comments