111 lines
3.8 KiB
Svelte
111 lines
3.8 KiB
Svelte
<script lang="ts">
|
|
import { onMount } from 'svelte';
|
|
import { goto } from '$app/navigation';
|
|
|
|
let to = '';
|
|
let subject = '';
|
|
let body = '';
|
|
let qrcode_b64 = '';
|
|
let loading = false;
|
|
let error = '';
|
|
let success = '';
|
|
let authorized = false;
|
|
let refreshToken = '';
|
|
|
|
async function validateToken(token: string): Promise<boolean> {
|
|
if (!token) return false;
|
|
const res = await fetch('/private/api/gmail', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ action: 'validate', refreshToken: token })
|
|
});
|
|
if (!res.ok) return false;
|
|
const data = await res.json();
|
|
return !!data.valid;
|
|
}
|
|
|
|
onMount(async () => {
|
|
refreshToken = localStorage.getItem('gmail_refresh_token') ?? '';
|
|
authorized = await validateToken(refreshToken);
|
|
});
|
|
|
|
const connect = () => goto('/private/api/gmail?action=auth');
|
|
|
|
async function sendTestEmail(event: Event) {
|
|
event.preventDefault();
|
|
error = '';
|
|
success = '';
|
|
loading = true;
|
|
try {
|
|
const r = await fetch('/private/api/gmail', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({
|
|
action: 'send',
|
|
to,
|
|
subject,
|
|
text: body,
|
|
qr_code: qrcode_b64,
|
|
refreshToken
|
|
})
|
|
});
|
|
if (r.ok) {
|
|
success = 'Email sent!';
|
|
to = subject = body = qrcode_b64 = '';
|
|
} else {
|
|
error = await r.text();
|
|
}
|
|
} catch (e) {
|
|
error = e.message || 'Unknown error';
|
|
}
|
|
loading = false;
|
|
}
|
|
</script>
|
|
|
|
<div class="max-w-lg mx-auto bg-white border border-gray-300 rounded p-8 mt-8 shadow">
|
|
<h2 class="text-2xl font-semibold mb-6 text-center">Test Email Sender</h2>
|
|
{#if !authorized}
|
|
<div class="mb-4 flex items-center justify-between">
|
|
<p class="text-gray-700">Google not connected.</p>
|
|
<button class="btn bg-blue-600 hover:bg-blue-700 text-white font-semibold py-2 px-4 rounded ml-auto" onclick={connect}>
|
|
Connect Google
|
|
</button>
|
|
</div>
|
|
<form onsubmit={sendTestEmail} class="space-y-4">
|
|
<label class="block">
|
|
<span class="text-gray-700">To</span>
|
|
<input type="email" class="mt-1 block w-full border border-gray-300 rounded px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-200" bind:value={to} required />
|
|
</label>
|
|
<label class="block">
|
|
<span class="text-gray-700">Subject</span>
|
|
<input type="text" class="mt-1 block w-full border border-gray-300 rounded px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-200" bind:value={subject} required />
|
|
</label>
|
|
<label class="block">
|
|
<span class="text-gray-700">Body</span>
|
|
<textarea class="mt-1 block w-full border border-gray-300 rounded px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-200 resize-none" rows="6" bind:value={body} required></textarea>
|
|
</label>
|
|
<label class="block">
|
|
<span class="text-gray-700">QR Code (base64, data:image/png;base64,...)</span>
|
|
<input type="text" class="mt-1 block w-full border border-gray-300 rounded px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-200 font-mono text-xs" bind:value={qrcode_b64} placeholder="Paste base64 image string here" required />
|
|
</label>
|
|
<button type="submit" class="w-full py-2 bg-blue-600 text-white rounded hover:bg-blue-700 transition" disabled={loading}>
|
|
{#if loading}
|
|
<svg class="animate-spin h-5 w-5 mr-2 inline-block text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
|
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
|
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8v8z"></path>
|
|
</svg>
|
|
Sending...
|
|
{:else}
|
|
Send Test Email
|
|
{/if}
|
|
</button>
|
|
</form>
|
|
{/if}
|
|
{#if error}
|
|
<div class="rounded border-l-4 border-red-500 bg-red-100 p-4 text-red-700 mt-4">{error}</div>
|
|
{/if}
|
|
{#if success}
|
|
<div class="rounded border-l-4 border-green-500 bg-green-100 p-4 text-green-700 mt-4">{success}</div>
|
|
{/if}
|
|
</div>
|