Make emails editable
This commit is contained in:
@@ -10,7 +10,6 @@
|
||||
import EmailSending from './components/EmailSending.svelte';
|
||||
import EmailResults from './components/EmailResults.svelte';
|
||||
import Statistics from './components/Statistics.svelte';
|
||||
import ToastContainer from '$lib/components/ToastContainer.svelte';
|
||||
import { toast } from '$lib/stores/toast.js';
|
||||
|
||||
let { data } = $props();
|
||||
@@ -48,6 +47,7 @@
|
||||
let participantsLoading = $state(true);
|
||||
let syncingParticipants = $state(false);
|
||||
let sendingEmails = $state(false);
|
||||
let updatingEmail = $state(false);
|
||||
let emailProgress = $state({ sent: 0, total: 0 });
|
||||
let emailResults = $state<{success: boolean, results: any[], summary: any} | null>(null);
|
||||
|
||||
@@ -268,6 +268,42 @@
|
||||
}
|
||||
}
|
||||
|
||||
// For Email Template updating
|
||||
async function handleEmailUpdate(eventId: string, subject: string, body: string) {
|
||||
updatingEmail = true;
|
||||
|
||||
try {
|
||||
// Call the email_modify RPC function
|
||||
const { error } = await data.supabase.rpc('email_modify', {
|
||||
p_event_id: eventId,
|
||||
p_email_subject: subject,
|
||||
p_email_body: body
|
||||
});
|
||||
|
||||
if (error) throw error;
|
||||
|
||||
// Update the local event data on success
|
||||
if (event) {
|
||||
event.email_subject = subject;
|
||||
event.email_body = body;
|
||||
}
|
||||
|
||||
toast.add({
|
||||
message: 'Email template updated successfully',
|
||||
type: 'success'
|
||||
});
|
||||
|
||||
} catch (err) {
|
||||
console.error('Error updating email template:', err);
|
||||
toast.add({
|
||||
message: 'Failed to update email template',
|
||||
type: 'error'
|
||||
});
|
||||
} finally {
|
||||
updatingEmail = false;
|
||||
}
|
||||
}
|
||||
|
||||
function handleGoogleAuthSuccess() {
|
||||
// Success handled by toast in the component
|
||||
}
|
||||
@@ -312,7 +348,12 @@ onSyncParticipants={syncParticipants}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<EmailTemplate {event} {loading} />
|
||||
<EmailTemplate
|
||||
{event}
|
||||
{loading}
|
||||
{updatingEmail}
|
||||
onUpdateEmail={handleEmailUpdate}
|
||||
/>
|
||||
|
||||
<EmailSending
|
||||
{loading}
|
||||
|
||||
@@ -1,18 +1,104 @@
|
||||
<script lang="ts">
|
||||
interface Event {
|
||||
id: string;
|
||||
email_subject: string;
|
||||
email_body: string;
|
||||
}
|
||||
|
||||
let { event, loading } = $props<{
|
||||
let {
|
||||
event,
|
||||
loading,
|
||||
updatingEmail,
|
||||
onUpdateEmail
|
||||
} = $props<{
|
||||
event: Event | null;
|
||||
loading: boolean;
|
||||
updatingEmail: boolean;
|
||||
onUpdateEmail: (eventId: string, subject: string, body: string) => void;
|
||||
}>();
|
||||
|
||||
// State for form
|
||||
let isEditing = $state(false);
|
||||
let emailSubject = $state('');
|
||||
let emailBody = $state('');
|
||||
|
||||
// Update form values when event changes
|
||||
$effect(() => {
|
||||
if (event) {
|
||||
emailSubject = event.email_subject;
|
||||
emailBody = event.email_body;
|
||||
}
|
||||
});
|
||||
|
||||
// Toggle editing mode
|
||||
function toggleEdit() {
|
||||
isEditing = !isEditing;
|
||||
// Reset form when exiting edit mode without saving
|
||||
if (!isEditing && event) {
|
||||
emailSubject = event.email_subject;
|
||||
emailBody = event.email_body;
|
||||
}
|
||||
}
|
||||
|
||||
// Track the previous updatingEmail state to detect changes
|
||||
let wasUpdating = $state(false);
|
||||
|
||||
// Save email template
|
||||
function handleSave() {
|
||||
if (!event) return;
|
||||
onUpdateEmail(event.id, emailSubject, emailBody);
|
||||
}
|
||||
|
||||
// Watch for updatingEmail changes to detect when operation completes
|
||||
$effect(() => {
|
||||
// Detect the transition from updating to not updating (operation completed)
|
||||
if (wasUpdating && !updatingEmail) {
|
||||
// If event data matches our form data, the update was successful
|
||||
// Turn off editing mode after successful update
|
||||
if (event && event.email_subject === emailSubject && event.email_body === emailBody) {
|
||||
isEditing = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Store current state for next comparison
|
||||
wasUpdating = updatingEmail;
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="rounded-lg border border-gray-300 bg-white p-6 mb-4">
|
||||
<div class="mb-4">
|
||||
<div class="mb-4 flex justify-between items-center">
|
||||
<h2 class="text-xl font-semibold text-gray-900">Email Template</h2>
|
||||
{#if !loading && event}
|
||||
<div class="flex gap-3">
|
||||
{#if isEditing}
|
||||
<button
|
||||
onclick={handleSave}
|
||||
disabled={updatingEmail}
|
||||
class="rounded bg-blue-600 px-4 py-2 text-white transition hover:bg-blue-700 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
aria-label="Save email template"
|
||||
>
|
||||
{updatingEmail ? 'Saving...' : 'Save'}
|
||||
</button>
|
||||
<button
|
||||
onclick={toggleEdit}
|
||||
class="rounded bg-gray-300 px-4 py-2 text-gray-700 transition hover:bg-gray-400 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
disabled={updatingEmail}
|
||||
aria-label="Cancel editing"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
{:else}
|
||||
<button
|
||||
onclick={toggleEdit}
|
||||
class="rounded bg-blue-600 px-4 py-2 text-white transition hover:bg-blue-700 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
disabled={updatingEmail}
|
||||
aria-label="Edit email template"
|
||||
>
|
||||
Edit Email
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
{#if loading}
|
||||
@@ -31,17 +117,34 @@
|
||||
{:else if event}
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<span class="block mb-1 text-sm font-medium text-gray-700">Subject:</span>
|
||||
<div class="bg-gray-50 p-3 rounded-lg border border-gray-200">
|
||||
<p class="text-sm text-gray-900">{event.email_subject}</p>
|
||||
</div>
|
||||
<label for="emailSubject" class="block mb-1 text-sm font-medium text-gray-700">Subject:</label>
|
||||
<input
|
||||
id="emailSubject"
|
||||
type="text"
|
||||
bind:value={emailSubject}
|
||||
disabled={!isEditing || updatingEmail}
|
||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg {!isEditing ? 'bg-gray-50 cursor-default' : ''} focus:ring-blue-500 focus:border-blue-500 disabled:bg-gray-50"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<span class="block mb-1 text-sm font-medium text-gray-700">Body:</span>
|
||||
<div class="bg-gray-50 p-3 rounded-lg border border-gray-200 max-h-48 overflow-y-auto">
|
||||
<p class="text-sm whitespace-pre-wrap text-gray-900">{event.email_body}</p>
|
||||
</div>
|
||||
<label for="emailBody" class="block mb-1 text-sm font-medium text-gray-700">Body:</label>
|
||||
<textarea
|
||||
id="emailBody"
|
||||
bind:value={emailBody}
|
||||
rows="6"
|
||||
disabled={!isEditing || updatingEmail}
|
||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg {!isEditing ? 'bg-gray-50 cursor-default' : ''} focus:ring-blue-500 focus:border-blue-500 disabled:bg-gray-50"
|
||||
></textarea>
|
||||
{#if isEditing}
|
||||
<div class="mt-2 text-xs text-gray-500">
|
||||
Template variables: <span class="font-mono bg-gray-100 px-1 rounded">{name}</span>,
|
||||
<span class="font-mono bg-gray-100 px-1 rounded">{surname}</span>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<!-- Save button moved to the header -->
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user