add postgres integration to save progress across devices
This commit is contained in:
@@ -23,12 +23,15 @@
|
||||
|
||||
let tokenClient: any;
|
||||
let accessToken = '';
|
||||
let gapiLoaded = false;
|
||||
let googleLoaded = false;
|
||||
|
||||
let readerFolderId = '';
|
||||
let volumeDataId = '';
|
||||
let profilesId = '';
|
||||
|
||||
let loadingMessage = '';
|
||||
let errorMessage = '';
|
||||
|
||||
let completed = 0;
|
||||
let totalSize = 0;
|
||||
@@ -36,6 +39,11 @@
|
||||
|
||||
function xhrDownloadFileId(fileId: string) {
|
||||
return new Promise<Blob>((resolve, reject) => {
|
||||
if (!gapiLoaded || !gapi.auth.getToken()) {
|
||||
reject(new Error('Not authenticated'));
|
||||
return;
|
||||
}
|
||||
|
||||
const { access_token } = gapi.auth.getToken();
|
||||
const xhr = new XMLHttpRequest();
|
||||
|
||||
@@ -88,50 +96,61 @@
|
||||
accessToken = resp?.access_token;
|
||||
loadingMessage = 'Connecting to drive';
|
||||
|
||||
const { result: readerFolderRes } = await gapi.client.drive.files.list({
|
||||
q: `mimeType='application/vnd.google-apps.folder' and name='${READER_FOLDER}'`,
|
||||
fields: 'files(id)'
|
||||
});
|
||||
|
||||
if (readerFolderRes.files?.length === 0) {
|
||||
const { result: createReaderFolderRes } = await gapi.client.drive.files.create({
|
||||
resource: { mimeType: FOLDER_MIME_TYPE, name: READER_FOLDER },
|
||||
fields: 'id'
|
||||
try {
|
||||
const { result: readerFolderRes } = await gapi.client.drive.files.list({
|
||||
q: `mimeType='application/vnd.google-apps.folder' and name='${READER_FOLDER}'`,
|
||||
fields: 'files(id)'
|
||||
});
|
||||
|
||||
readerFolderId = createReaderFolderRes.id || '';
|
||||
} else {
|
||||
const id = readerFolderRes.files?.[0]?.id || '';
|
||||
if (readerFolderRes.files?.length === 0) {
|
||||
const { result: createReaderFolderRes } = await gapi.client.drive.files.create({
|
||||
resource: { mimeType: FOLDER_MIME_TYPE, name: READER_FOLDER },
|
||||
fields: 'id'
|
||||
});
|
||||
|
||||
readerFolderId = id || '';
|
||||
}
|
||||
readerFolderId = createReaderFolderRes.id || '';
|
||||
} else {
|
||||
const id = readerFolderRes.files?.[0]?.id || '';
|
||||
readerFolderId = id || '';
|
||||
}
|
||||
|
||||
const { result: volumeDataRes } = await gapi.client.drive.files.list({
|
||||
q: `'${readerFolderId}' in parents and name='${VOLUME_DATA_FILE}'`,
|
||||
fields: 'files(id, name)'
|
||||
});
|
||||
const { result: volumeDataRes } = await gapi.client.drive.files.list({
|
||||
q: `'${readerFolderId}' in parents and name='${VOLUME_DATA_FILE}'`,
|
||||
fields: 'files(id, name)'
|
||||
});
|
||||
|
||||
if (volumeDataRes.files?.length !== 0) {
|
||||
volumeDataId = volumeDataRes.files?.[0].id || '';
|
||||
}
|
||||
if (volumeDataRes.files?.length !== 0) {
|
||||
volumeDataId = volumeDataRes.files?.[0].id || '';
|
||||
}
|
||||
|
||||
const { result: profilesRes } = await gapi.client.drive.files.list({
|
||||
q: `'${readerFolderId}' in parents and name='${PROFILES_FILE}'`,
|
||||
fields: 'files(id, name)'
|
||||
});
|
||||
const { result: profilesRes } = await gapi.client.drive.files.list({
|
||||
q: `'${readerFolderId}' in parents and name='${PROFILES_FILE}'`,
|
||||
fields: 'files(id, name)'
|
||||
});
|
||||
|
||||
if (profilesRes.files?.length !== 0) {
|
||||
profilesId = profilesRes.files?.[0].id || '';
|
||||
}
|
||||
if (profilesRes.files?.length !== 0) {
|
||||
profilesId = profilesRes.files?.[0].id || '';
|
||||
}
|
||||
|
||||
loadingMessage = '';
|
||||
loadingMessage = '';
|
||||
errorMessage = '';
|
||||
|
||||
if (accessToken) {
|
||||
showSnackbar('Connected to Google Drive');
|
||||
if (accessToken) {
|
||||
showSnackbar('Connected to Google Drive');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error connecting to Drive:', error);
|
||||
errorMessage = 'Failed to connect to Google Drive. Please check your credentials.';
|
||||
loadingMessage = '';
|
||||
}
|
||||
}
|
||||
|
||||
function signIn() {
|
||||
if (!gapiLoaded || !googleLoaded) {
|
||||
errorMessage = 'Google APIs not loaded yet. Please wait and try again.';
|
||||
return;
|
||||
}
|
||||
|
||||
if (gapi.client.getToken() === null) {
|
||||
tokenClient.requestAccessToken({ prompt: 'consent' });
|
||||
} else {
|
||||
@@ -140,23 +159,50 @@
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
gapi.load('client', async () => {
|
||||
await gapi.client.init({
|
||||
apiKey: API_KEY,
|
||||
discoveryDocs: [DISCOVERY_DOC]
|
||||
// Check if environment variables are set
|
||||
if (!CLIENT_ID || !API_KEY) {
|
||||
errorMessage = 'Google Drive integration not configured. Please set VITE_GDRIVE_CLIENT_ID and VITE_GDRIVE_API_KEY environment variables.';
|
||||
return;
|
||||
}
|
||||
|
||||
// Load Google APIs
|
||||
if (typeof gapi !== 'undefined') {
|
||||
gapiLoaded = true;
|
||||
gapi.load('client', async () => {
|
||||
try {
|
||||
await gapi.client.init({
|
||||
apiKey: API_KEY,
|
||||
discoveryDocs: [DISCOVERY_DOC]
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error initializing gapi client:', error);
|
||||
errorMessage = 'Failed to initialize Google Drive client.';
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
gapi.load('picker', () => {});
|
||||
gapi.load('picker', () => {});
|
||||
} else {
|
||||
errorMessage = 'Google APIs not loaded. Please check your internet connection.';
|
||||
}
|
||||
|
||||
tokenClient = google.accounts.oauth2.initTokenClient({
|
||||
client_id: CLIENT_ID,
|
||||
scope: SCOPES,
|
||||
callback: connectDrive
|
||||
});
|
||||
if (typeof google !== 'undefined') {
|
||||
googleLoaded = true;
|
||||
tokenClient = google.accounts.oauth2.initTokenClient({
|
||||
client_id: CLIENT_ID,
|
||||
scope: SCOPES,
|
||||
callback: connectDrive
|
||||
});
|
||||
} else {
|
||||
errorMessage = 'Google OAuth not loaded. Please check your internet connection.';
|
||||
}
|
||||
});
|
||||
|
||||
function createPicker() {
|
||||
if (!googleLoaded || !accessToken) {
|
||||
showSnackbar('Not connected to Google Drive');
|
||||
return;
|
||||
}
|
||||
|
||||
const docsView = new google.picker.DocsView(google.picker.ViewId.DOCS)
|
||||
.setMimeTypes('application/zip,application/x-zip-compressed')
|
||||
.setMode(google.picker.DocsViewMode.LIST)
|
||||
@@ -293,6 +339,12 @@
|
||||
</svelte:head>
|
||||
|
||||
<div class="p-2 h-[90svh]">
|
||||
{#if errorMessage}
|
||||
<div class="bg-red-900/20 border border-red-700 rounded-lg p-4 mb-4">
|
||||
<p class="text-red-400">{errorMessage}</p>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if loadingMessage || completed > 0}
|
||||
<Loader>
|
||||
{#if completed > 0}
|
||||
@@ -352,12 +404,16 @@
|
||||
<button
|
||||
class="w-full border rounded-lg border-slate-600 p-10 border-opacity-50 hover:bg-slate-800 max-w-3xl"
|
||||
on:click={signIn}
|
||||
disabled={!gapiLoaded || !googleLoaded}
|
||||
>
|
||||
<div class="flex sm:flex-row flex-col gap-2 items-center justify-center">
|
||||
<GoogleSolid size="lg" />
|
||||
<h2 class="text-lg">Connect to Google Drive</h2>
|
||||
</div>
|
||||
</button>
|
||||
{#if !gapiLoaded || !googleLoaded}
|
||||
<p class="text-sm text-gray-400 mt-2">Loading Google APIs...</p>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user