@@ -9,21 +9,36 @@ import {
99 clearTokens ,
1010 hasValidSpreadsheet ,
1111 hasValidSession ,
12- getSavedSession
12+ getSavedSession ,
13+ setTokenRefreshCallback
1314} from './utils/googleAuth' ;
15+ import { setupGlobalErrorHandlers } from './utils/errorReporter' ;
16+ import { slackUserCache } from './utils/slackUserCache' ;
17+ import { Alert , Button } from './components/ui' ;
1418
1519export default function App ( ) {
1620 const [ user , setUser ] = useState ( null ) ;
1721 const [ loading , setLoading ] = useState ( true ) ;
1822 const [ needsSpreadsheetSelection , setNeedsSpreadsheetSelection ] = useState ( false ) ;
23+ const [ tokenExpired , setTokenExpired ] = useState ( false ) ;
24+ const [ ignoreTokenExpiry , setIgnoreTokenExpiry ] = useState ( false ) ;
1925
2026 useEffect ( ( ) => {
27+ // Setup global error handlers
28+ setupGlobalErrorHandlers ( ) ;
29+
2130 const initializeApp = async ( ) => {
2231 // Initialize Google Auth
2332 await new Promise ( resolve => {
2433 initializeGoogleAuth ( ( ) => resolve ( ) ) ;
2534 } ) ;
2635
36+ // Set token refresh callback
37+ setTokenRefreshCallback ( ( error ) => {
38+ console . error ( 'Token refresh failed:' , error ) ;
39+ setTokenExpired ( true ) ;
40+ } ) ;
41+
2742 // Check if we have a valid saved session
2843 if ( hasValidSession ( ) ) {
2944 try {
@@ -35,6 +50,11 @@ export default function App() {
3550 if ( ! hasValidSpreadsheet ( ) ) {
3651 setNeedsSpreadsheetSelection ( true ) ;
3752 }
53+
54+ // Load Slack users in background
55+ slackUserCache . loadUsers ( ) . catch ( err => {
56+ console . error ( 'Failed to load Slack users:' , err ) ;
57+ } ) ;
3858 }
3959 } catch ( err ) {
4060 console . error ( 'Failed to restore session:' , err ) ;
@@ -51,11 +71,18 @@ export default function App() {
5171
5272 const handleSignIn = ( userData ) => {
5373 setUser ( userData ) ;
74+ setTokenExpired ( false ) ;
75+ setIgnoreTokenExpiry ( false ) ;
5476
5577 // Check if spreadsheet is already selected
5678 if ( ! hasValidSpreadsheet ( ) ) {
5779 setNeedsSpreadsheetSelection ( true ) ;
5880 }
81+
82+ // Load Slack users in background
83+ slackUserCache . loadUsers ( ) . catch ( err => {
84+ console . error ( 'Failed to load Slack users:' , err ) ;
85+ } ) ;
5986 } ;
6087
6188 const handleSpreadsheetSelected = ( ) => {
@@ -69,8 +96,20 @@ export default function App() {
6996
7097 const handleSignOut = ( ) => {
7198 clearTokens ( ) ;
99+ slackUserCache . clearCache ( ) ;
72100 setUser ( null ) ;
73101 setNeedsSpreadsheetSelection ( false ) ;
102+ setTokenExpired ( false ) ;
103+ setIgnoreTokenExpiry ( false ) ;
104+ } ;
105+
106+ const handleRelogin = ( ) => {
107+ handleSignOut ( ) ;
108+ } ;
109+
110+ const handleIgnoreExpiry = ( ) => {
111+ setIgnoreTokenExpiry ( true ) ;
112+ setTokenExpired ( false ) ;
74113 } ;
75114
76115 if ( loading ) {
@@ -79,6 +118,41 @@ export default function App() {
79118
80119 return (
81120 < AlertProvider >
121+ { /* Token Expiry Warning */ }
122+ { tokenExpired && ! ignoreTokenExpiry && user && (
123+ < div className = "fixed top-0 left-0 right-0 z-[100] p-4 bg-red-600" >
124+ < div className = "max-w-4xl mx-auto" >
125+ < Alert type = "error" className = "mb-0" >
126+ < div className = "flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3" >
127+ < div className = "flex-1" >
128+ < p className = "font-semibold text-white mb-1" > Authentication Expired</ p >
129+ < p className = "text-sm text-red-100" >
130+ Your session has expired. Please sign in again to continue making changes.
131+ You can still view data, but operations may fail.
132+ </ p >
133+ </ div >
134+ < div className = "flex gap-2 flex-shrink-0" >
135+ < Button
136+ variant = "secondary"
137+ size = "sm"
138+ onClick = { handleIgnoreExpiry }
139+ >
140+ Ignore (risky)
141+ </ Button >
142+ < Button
143+ variant = "primary"
144+ size = "sm"
145+ onClick = { handleRelogin }
146+ >
147+ Sign In Again
148+ </ Button >
149+ </ div >
150+ </ div >
151+ </ Alert >
152+ </ div >
153+ </ div >
154+ ) }
155+
82156 { ! user ? (
83157 < LoginPage onSignIn = { handleSignIn } />
84158 ) : needsSpreadsheetSelection ? (
0 commit comments