254 lines
7.8 KiB
Vue
254 lines
7.8 KiB
Vue
<template>
|
|
<v-card>
|
|
<v-card-title class="text-h6 d-flex align-center">
|
|
<v-icon class="mr-2">mdi-email-lock</v-icon>
|
|
Email Account Setup
|
|
</v-card-title>
|
|
<v-card-text>
|
|
<v-alert type="info" variant="tonal" class="mb-4">
|
|
Enter your email credentials to send and receive emails. Your password is encrypted and stored only for this session.
|
|
</v-alert>
|
|
|
|
<v-form @submit.prevent="testConnection" ref="form">
|
|
<v-text-field
|
|
v-model="credentials.email"
|
|
label="Email Address"
|
|
type="email"
|
|
variant="outlined"
|
|
density="comfortable"
|
|
prepend-inner-icon="mdi-email"
|
|
:rules="[rules.required, rules.email]"
|
|
:disabled="testing"
|
|
/>
|
|
|
|
<v-text-field
|
|
v-model="credentials.password"
|
|
label="Password"
|
|
:type="showPassword ? 'text' : 'password'"
|
|
variant="outlined"
|
|
density="comfortable"
|
|
prepend-inner-icon="mdi-lock"
|
|
:append-inner-icon="showPassword ? 'mdi-eye' : 'mdi-eye-off'"
|
|
@click:append-inner="showPassword = !showPassword"
|
|
:rules="[rules.required]"
|
|
:disabled="testing"
|
|
/>
|
|
|
|
<v-expansion-panels variant="accordion" class="mb-4">
|
|
<v-expansion-panel>
|
|
<v-expansion-panel-title>
|
|
<v-icon class="mr-2">mdi-cog</v-icon>
|
|
Advanced Settings
|
|
</v-expansion-panel-title>
|
|
<v-expansion-panel-text>
|
|
<v-text-field
|
|
v-model="credentials.imapHost"
|
|
label="IMAP Host"
|
|
variant="outlined"
|
|
density="comfortable"
|
|
placeholder="mail.portnimara.com"
|
|
:disabled="testing"
|
|
/>
|
|
<v-text-field
|
|
v-model="credentials.smtpHost"
|
|
label="SMTP Host"
|
|
variant="outlined"
|
|
density="comfortable"
|
|
placeholder="mail.portnimara.com"
|
|
:disabled="testing"
|
|
/>
|
|
</v-expansion-panel-text>
|
|
</v-expansion-panel>
|
|
|
|
<v-expansion-panel>
|
|
<v-expansion-panel-title>
|
|
<v-icon class="mr-2">mdi-card-account-details</v-icon>
|
|
Email Signature
|
|
</v-expansion-panel-title>
|
|
<v-expansion-panel-text>
|
|
<v-text-field
|
|
v-model="signature.name"
|
|
label="Your Name"
|
|
variant="outlined"
|
|
density="comfortable"
|
|
placeholder="John Doe"
|
|
class="mb-3"
|
|
/>
|
|
<v-text-field
|
|
v-model="signature.title"
|
|
label="Job Title"
|
|
variant="outlined"
|
|
density="comfortable"
|
|
placeholder="Sales & Marketing Director"
|
|
class="mb-3"
|
|
/>
|
|
<v-text-field
|
|
v-model="signature.company"
|
|
label="Company"
|
|
variant="outlined"
|
|
density="comfortable"
|
|
placeholder="Port Nimara"
|
|
class="mb-3"
|
|
/>
|
|
<v-textarea
|
|
v-model="signature.contactInfo"
|
|
label="Additional Contact Info"
|
|
variant="outlined"
|
|
density="comfortable"
|
|
rows="3"
|
|
placeholder="Phone: +1234567890 Mobile: +0987654321"
|
|
/>
|
|
</v-expansion-panel-text>
|
|
</v-expansion-panel>
|
|
</v-expansion-panels>
|
|
|
|
<v-btn
|
|
type="submit"
|
|
color="primary"
|
|
block
|
|
size="large"
|
|
:loading="testing"
|
|
:disabled="testing"
|
|
>
|
|
<v-icon start>mdi-connection</v-icon>
|
|
Test Connection & Continue
|
|
</v-btn>
|
|
</v-form>
|
|
</v-card-text>
|
|
</v-card>
|
|
</template>
|
|
|
|
<script lang="ts" setup>
|
|
import { ref, onMounted } from 'vue';
|
|
|
|
interface Emits {
|
|
(e: 'connected', email: string): void;
|
|
(e: 'credentials-saved', data: { sessionId: string }): void;
|
|
}
|
|
|
|
const emit = defineEmits<Emits>();
|
|
|
|
const user = useDirectusUser();
|
|
const toast = useToast();
|
|
|
|
const form = ref();
|
|
const testing = ref(false);
|
|
const showPassword = ref(false);
|
|
|
|
const credentials = ref({
|
|
email: '',
|
|
password: '',
|
|
imapHost: '',
|
|
smtpHost: ''
|
|
});
|
|
|
|
const signature = ref({
|
|
name: '',
|
|
title: 'Sales & Marketing Director',
|
|
company: 'Port Nimara',
|
|
contactInfo: ''
|
|
});
|
|
|
|
const rules = {
|
|
required: (v: string) => !!v || 'Required',
|
|
email: (v: string) => /.+@.+\..+/.test(v) || 'Invalid email'
|
|
};
|
|
|
|
// Generate or get session ID
|
|
const getSessionId = () => {
|
|
let sessionId = localStorage.getItem('emailSessionId');
|
|
if (!sessionId) {
|
|
sessionId = `session-${Date.now()}-${Math.random().toString(36).substring(2)}`;
|
|
localStorage.setItem('emailSessionId', sessionId);
|
|
}
|
|
return sessionId;
|
|
};
|
|
|
|
const testConnection = async () => {
|
|
// Prevent multiple simultaneous connection attempts
|
|
if (testing.value) {
|
|
console.log('[EmailCredentialsSetup] Connection test already in progress, ignoring');
|
|
return;
|
|
}
|
|
|
|
const { valid } = await form.value.validate();
|
|
if (!valid) return;
|
|
|
|
testing.value = true;
|
|
|
|
try {
|
|
const response = await $fetch<{ success: boolean; message: string; email: string }>('/api/email/test-connection', {
|
|
method: 'POST',
|
|
headers: {
|
|
'x-tag': user.value?.email ? '094ut234' : 'pjnvü1230',
|
|
},
|
|
body: {
|
|
email: credentials.value.email,
|
|
password: credentials.value.password,
|
|
imapHost: credentials.value.imapHost || undefined,
|
|
smtpHost: credentials.value.smtpHost || undefined,
|
|
sessionId: getSessionId()
|
|
},
|
|
timeout: 15000 // 15 second timeout
|
|
});
|
|
|
|
if (response.success) {
|
|
toast.success('Email connection successful!');
|
|
// Store email and signature config
|
|
localStorage.setItem('connectedEmail', credentials.value.email);
|
|
localStorage.setItem('emailSignature', JSON.stringify(signature.value));
|
|
|
|
// Emit both events for compatibility
|
|
emit('connected', credentials.value.email);
|
|
emit('credentials-saved', { sessionId: getSessionId() });
|
|
}
|
|
} catch (error: any) {
|
|
console.error('Connection test failed:', error);
|
|
|
|
// If it's a timeout error, offer to proceed anyway
|
|
if (error.message?.includes('timeout') || error.statusCode === 504) {
|
|
const proceed = confirm('Connection test timed out, but the email system might still work. Would you like to proceed anyway?');
|
|
if (proceed) {
|
|
// Store credentials anyway
|
|
toast.info('Proceeding with email setup...');
|
|
localStorage.setItem('connectedEmail', credentials.value.email);
|
|
localStorage.setItem('emailSignature', JSON.stringify(signature.value));
|
|
|
|
// Manually store encrypted credentials
|
|
try {
|
|
// Generate a session ID if not already present
|
|
const sessionId = getSessionId();
|
|
|
|
// We'll trust that the credentials are correct and proceed
|
|
emit('connected', credentials.value.email);
|
|
emit('credentials-saved', { sessionId: sessionId });
|
|
} catch (e) {
|
|
console.error('Failed to store credentials:', e);
|
|
}
|
|
}
|
|
} else {
|
|
toast.error(error.data?.statusMessage || 'Failed to connect to email server');
|
|
}
|
|
} finally {
|
|
testing.value = false;
|
|
}
|
|
};
|
|
|
|
// Pre-fill email from user if available
|
|
onMounted(() => {
|
|
if (user.value?.email) {
|
|
credentials.value.email = user.value.email;
|
|
}
|
|
|
|
// Load saved signature
|
|
const savedSignature = localStorage.getItem('emailSignature');
|
|
if (savedSignature) {
|
|
try {
|
|
signature.value = JSON.parse(savedSignature);
|
|
} catch (e) {
|
|
console.error('Failed to load saved signature:', e);
|
|
}
|
|
}
|
|
});
|
|
</script>
|