feat: Complete Mode2Svelte with file viewer and token management
- Implemented Graph token lifecycle management with 60s safety buffer - Added automatic token refresh scheduled 5min before expiry - Fixed token expiration handling with env variable fallback - Resolved SharePoint link parsing for both URL formats (RootFolder param and direct pathname) - Handled URL-encoded spaces in file paths with proper decoding - Implemented internal file viewer modal staying within app context - Added file categorization system (Manager Info, Contracts, Plans, Submittals, Other) - Integrated SVG icons for file types (PDF, Word, Excel, Presentation, Images) - Added search/filter capability for files in folder view - Enhanced auth module with improved button click debugging - Fixed mobile responsiveness for file listing Changes: - Mode2Svelte/src/routes/+page.svelte: Complete component rewrite with token management - Mode2Svelte/src/lib/auth/frontend.ts: Added comprehensive logging for auth flow - Mode2Svelte/src/routes/api/job-files/+server.ts: Created file access endpoint - Mode2Svelte/src/routes/api/jobs/list/+server.ts: Added jobs list endpoint Status: Files now load and display in grouped categories with internal viewer Next: Fix mobile app authentication issue and further refinements
This commit is contained in:
@@ -55,45 +55,77 @@ export class PocketBaseAuth {
|
||||
* Setup login button click handler
|
||||
*/
|
||||
private setupLoginButton(): void {
|
||||
const loginBtn = document.getElementById(this.config.loginBtnId);
|
||||
if (!loginBtn) {
|
||||
console.warn(`Login button with id "${this.config.loginBtnId}" not found`);
|
||||
return;
|
||||
}
|
||||
|
||||
loginBtn.addEventListener('click', async (e) => {
|
||||
e.preventDefault();
|
||||
await this.handleLogin();
|
||||
});
|
||||
console.log('[Auth] Setting up login button with id:', this.config.loginBtnId);
|
||||
|
||||
// Retry finding button in case component hasn't rendered yet
|
||||
let attempts = 0;
|
||||
const setupInterval = setInterval(() => {
|
||||
const loginBtn = document.getElementById(this.config.loginBtnId);
|
||||
console.log(`[Auth] Attempt ${attempts + 1}: Looking for button, found:`, !!loginBtn);
|
||||
|
||||
if (loginBtn) {
|
||||
clearInterval(setupInterval);
|
||||
// Remove any existing listeners to avoid duplicates
|
||||
const newBtn = loginBtn.cloneNode(true) as HTMLElement;
|
||||
loginBtn.parentNode?.replaceChild(newBtn, loginBtn);
|
||||
|
||||
newBtn.addEventListener('click', async (e) => {
|
||||
console.log('[Auth] Login button clicked!');
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
await this.handleLogin();
|
||||
}, false);
|
||||
console.log(`✓ Login button listener attached (attempt ${attempts + 1})`);
|
||||
} else if (attempts++ > 100) {
|
||||
// Give up after 10 seconds (100 * 100ms)
|
||||
clearInterval(setupInterval);
|
||||
console.error(`Login button with id "${this.config.loginBtnId}" not found after 10 seconds. All elements:`,
|
||||
Array.from(document.querySelectorAll('[id*="login"]')).map(e => e.id));
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle login button click
|
||||
*/
|
||||
private async handleLogin(): Promise<void> {
|
||||
console.log('[Auth] handleLogin called');
|
||||
const loginBtn = document.getElementById(this.config.loginBtnId) as HTMLButtonElement;
|
||||
const loginError = document.getElementById(this.config.loginErrorId) as HTMLElement;
|
||||
|
||||
if (!loginBtn || !loginError) return;
|
||||
if (!loginBtn) {
|
||||
console.error('[Auth] Login button not found in handleLogin!');
|
||||
return;
|
||||
}
|
||||
if (!loginError) {
|
||||
console.error('[Auth] Login error element not found!');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('[Auth] Starting login flow...');
|
||||
loginBtn.disabled = true;
|
||||
loginBtn.textContent = 'Checking session...';
|
||||
loginError.classList.add('hidden');
|
||||
|
||||
try {
|
||||
// Try to use existing token first
|
||||
console.log('[Auth] Checking for existing token...');
|
||||
const hadToken = await this.ensureUserLogged();
|
||||
if (hadToken) {
|
||||
console.log('[Auth] Found valid existing token, using it');
|
||||
this.resetLoginButton();
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise perform OAuth
|
||||
console.log('[Auth] No valid token, starting OAuth flow...');
|
||||
loginBtn.textContent = 'Logging in...';
|
||||
console.log('[Auth] Calling authWithOAuth2 with provider:', this.config.provider);
|
||||
const authData = await this.pb.collection(this.config.collection).authWithOAuth2({
|
||||
provider: this.config.provider,
|
||||
});
|
||||
|
||||
console.log('[Auth] OAuth successful, updating state');
|
||||
this.updateState(authData);
|
||||
this.updateAuthUI();
|
||||
this.callbacks.onAuthSuccess?.(this.state);
|
||||
@@ -101,7 +133,7 @@ export class PocketBaseAuth {
|
||||
console.log('✓ Logged in with', this.config.provider);
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : 'Unknown error';
|
||||
console.error('Login failed:', message);
|
||||
console.error('[Auth] Login failed:', message, error);
|
||||
loginError.textContent = `Login failed: ${message}`;
|
||||
loginError.classList.remove('hidden');
|
||||
this.callbacks.onAuthFailure?.(error);
|
||||
|
||||
Reference in New Issue
Block a user