Initial commit
This commit is contained in:
@@ -0,0 +1,168 @@
|
||||
import { initializeApp, getApps, getApp } from 'firebase/app';
|
||||
import {
|
||||
getAuth,
|
||||
signInWithPopup,
|
||||
GoogleAuthProvider,
|
||||
onAuthStateChanged,
|
||||
User,
|
||||
signOut
|
||||
} from 'firebase/auth';
|
||||
import firebaseConfig from '../../firebase-applet-config.json';
|
||||
import { JobApplication } from '../types';
|
||||
|
||||
const app = getApps().length === 0 ? initializeApp(firebaseConfig) : getApp();
|
||||
export const auth = getAuth(app);
|
||||
|
||||
const provider = new GoogleAuthProvider();
|
||||
// Workspace Scopes
|
||||
provider.addScope('https://www.googleapis.com/auth/spreadsheets');
|
||||
provider.addScope('https://www.googleapis.com/auth/drive');
|
||||
provider.addScope('https://www.googleapis.com/auth/documents');
|
||||
|
||||
let isSigningIn = false;
|
||||
let cachedAccessToken: string | null = null;
|
||||
|
||||
export const initAuthListener = (
|
||||
onSuccess: (user: User, token: string) => void,
|
||||
onFailure: () => void
|
||||
) => {
|
||||
return onAuthStateChanged(auth, async (user) => {
|
||||
if (user) {
|
||||
if (cachedAccessToken) {
|
||||
onSuccess(user, cachedAccessToken);
|
||||
} else if (!isSigningIn) {
|
||||
// If logged in without token in memory (e.g., page refresh), trigger quick re-auth if needed
|
||||
onFailure();
|
||||
}
|
||||
} else {
|
||||
cachedAccessToken = null;
|
||||
onFailure();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const googleWorkspaceSignIn = async (): Promise<{ user: User; accessToken: string } | null> => {
|
||||
try {
|
||||
isSigningIn = true;
|
||||
const result = await signInWithPopup(auth, provider);
|
||||
const credential = GoogleAuthProvider.credentialFromResult(result);
|
||||
if (!credential?.accessToken) {
|
||||
throw new Error('Failed to obtain Google access token');
|
||||
}
|
||||
cachedAccessToken = credential.accessToken;
|
||||
return { user: result.user, accessToken: cachedAccessToken };
|
||||
} catch (error) {
|
||||
console.error('Google Workspace Sign-in Error:', error);
|
||||
throw error;
|
||||
} finally {
|
||||
isSigningIn = false;
|
||||
}
|
||||
};
|
||||
|
||||
export const getCachedAccessToken = (): string | null => {
|
||||
return cachedAccessToken;
|
||||
};
|
||||
|
||||
export const googleSignOut = async (): Promise<void> => {
|
||||
await signOut(auth);
|
||||
cachedAccessToken = null;
|
||||
};
|
||||
|
||||
// Workspace Action Handlers
|
||||
|
||||
export async function exportApplicationsToGoogleSheets(
|
||||
applications: JobApplication[],
|
||||
accessToken?: string
|
||||
): Promise<{ spreadsheetId: string; spreadsheetUrl: string }> {
|
||||
const token = accessToken || cachedAccessToken;
|
||||
const res = await fetch('/api/workspace/sheets/export', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...(token ? { Authorization: `Bearer ${token}` } : {})
|
||||
},
|
||||
body: JSON.stringify({ applications, accessToken: token })
|
||||
});
|
||||
const data = await res.json();
|
||||
if (!data.success) {
|
||||
throw new Error(data.error || 'Failed to export applications to Google Sheets');
|
||||
}
|
||||
return { spreadsheetId: data.spreadsheetId, spreadsheetUrl: data.spreadsheetUrl };
|
||||
}
|
||||
|
||||
export async function createTailoredGoogleDoc(
|
||||
title: string,
|
||||
content: string,
|
||||
docType: 'resume' | 'coverLetter' | 'note',
|
||||
accessToken?: string
|
||||
): Promise<{ documentId: string; documentUrl: string }> {
|
||||
const token = accessToken || cachedAccessToken;
|
||||
const res = await fetch('/api/workspace/docs/create', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...(token ? { Authorization: `Bearer ${token}` } : {})
|
||||
},
|
||||
body: JSON.stringify({ title, content, docType, accessToken: token })
|
||||
});
|
||||
const data = await res.json();
|
||||
if (!data.success) {
|
||||
throw new Error(data.error || 'Failed to create Google Doc');
|
||||
}
|
||||
return { documentId: data.documentId, documentUrl: data.documentUrl };
|
||||
}
|
||||
|
||||
export async function uploadFileToGoogleDrive(
|
||||
fileName: string,
|
||||
fileContent: string,
|
||||
mimeType: string = 'text/plain',
|
||||
accessToken?: string
|
||||
): Promise<{ fileId: string; driveUrl: string }> {
|
||||
const token = accessToken || cachedAccessToken;
|
||||
const res = await fetch('/api/workspace/drive/upload', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...(token ? { Authorization: `Bearer ${token}` } : {})
|
||||
},
|
||||
body: JSON.stringify({ fileName, fileContent, mimeType, accessToken: token })
|
||||
});
|
||||
const data = await res.json();
|
||||
if (!data.success) {
|
||||
throw new Error(data.error || 'Failed to upload file to Google Drive');
|
||||
}
|
||||
return { fileId: data.fileId, driveUrl: data.driveUrl };
|
||||
}
|
||||
|
||||
export async function listGoogleDriveWorkspaceFiles(accessToken?: string): Promise<any[]> {
|
||||
const token = accessToken || cachedAccessToken;
|
||||
const res = await fetch('/api/workspace/drive/files', {
|
||||
headers: {
|
||||
...(token ? { Authorization: `Bearer ${token}` } : {})
|
||||
}
|
||||
});
|
||||
const data = await res.json();
|
||||
return data.files || [];
|
||||
}
|
||||
|
||||
export async function saveGoogleKeepNote(
|
||||
title: string,
|
||||
content: string,
|
||||
color: string = 'DEFAULT',
|
||||
accessToken?: string
|
||||
): Promise<{ noteId: string; title: string; content: string; color: string; timestamp: string }> {
|
||||
const token = accessToken || cachedAccessToken;
|
||||
const res = await fetch('/api/workspace/keep/create', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...(token ? { Authorization: `Bearer ${token}` } : {})
|
||||
},
|
||||
body: JSON.stringify({ title, content, color, accessToken: token })
|
||||
});
|
||||
const data = await res.json();
|
||||
if (!data.success) {
|
||||
throw new Error(data.error || 'Failed to create Keep note');
|
||||
}
|
||||
return data.note;
|
||||
}
|
||||
Reference in New Issue
Block a user