541 lines
16 KiB
Vue
541 lines
16 KiB
Vue
<template>
|
|
<v-container fluid>
|
|
<!-- Header -->
|
|
<v-row class="mb-6">
|
|
<v-col>
|
|
<h1 class="text-h3 font-weight-bold mb-2">System Settings</h1>
|
|
<p class="text-body-1 text-medium-emphasis">Configure system preferences and options</p>
|
|
</v-col>
|
|
</v-row>
|
|
|
|
<!-- Settings Tabs -->
|
|
<v-card elevation="2">
|
|
<v-tabs v-model="activeTab" color="primary">
|
|
<v-tab value="general">
|
|
<v-icon start>mdi-cog</v-icon>
|
|
General
|
|
</v-tab>
|
|
<v-tab value="email">
|
|
<v-icon start>mdi-email</v-icon>
|
|
Email
|
|
</v-tab>
|
|
</v-tabs>
|
|
|
|
<v-window v-model="activeTab">
|
|
<!-- General Settings -->
|
|
<v-window-item value="general">
|
|
<v-card-text>
|
|
<!-- Edit Mode Toggle -->
|
|
<v-row class="mb-4">
|
|
<v-col>
|
|
<v-alert
|
|
v-if="!generalEditMode"
|
|
type="info"
|
|
variant="tonal"
|
|
density="compact"
|
|
>
|
|
<template v-slot:text>
|
|
Click "Edit Settings" to modify these values
|
|
</template>
|
|
</v-alert>
|
|
</v-col>
|
|
<v-col cols="auto">
|
|
<v-btn
|
|
v-if="!generalEditMode"
|
|
color="primary"
|
|
variant="outlined"
|
|
@click="generalEditMode = true"
|
|
>
|
|
<v-icon start>mdi-pencil</v-icon>
|
|
Edit Settings
|
|
</v-btn>
|
|
<v-btn-group v-else>
|
|
<v-btn
|
|
color="success"
|
|
variant="flat"
|
|
@click="saveGeneralSettings"
|
|
>
|
|
<v-icon start>mdi-check</v-icon>
|
|
Save
|
|
</v-btn>
|
|
<v-btn
|
|
color="error"
|
|
variant="outlined"
|
|
@click="cancelGeneralEdit"
|
|
>
|
|
<v-icon start>mdi-close</v-icon>
|
|
Cancel
|
|
</v-btn>
|
|
</v-btn-group>
|
|
</v-col>
|
|
</v-row>
|
|
|
|
<v-row>
|
|
<v-col cols="12">
|
|
<h3 class="text-h6 mb-4">Organization Information</h3>
|
|
</v-col>
|
|
<v-col cols="12" md="6">
|
|
<v-text-field
|
|
v-model="settings.general.orgName"
|
|
label="Organization Name"
|
|
variant="outlined"
|
|
:readonly="!generalEditMode"
|
|
:disabled="!generalEditMode"
|
|
autocomplete="off"
|
|
:class="{ 'readonly-field': !generalEditMode }"
|
|
/>
|
|
</v-col>
|
|
<v-col cols="12" md="6">
|
|
<v-text-field
|
|
v-model="settings.general.orgEmail"
|
|
label="Contact Email"
|
|
variant="outlined"
|
|
type="email"
|
|
:readonly="!generalEditMode"
|
|
:disabled="!generalEditMode"
|
|
autocomplete="off"
|
|
:class="{ 'readonly-field': !generalEditMode }"
|
|
/>
|
|
</v-col>
|
|
<v-col cols="12">
|
|
<v-textarea
|
|
v-model="settings.general.orgDescription"
|
|
label="Description"
|
|
variant="outlined"
|
|
rows="3"
|
|
:readonly="!generalEditMode"
|
|
:disabled="!generalEditMode"
|
|
autocomplete="off"
|
|
:class="{ 'readonly-field': !generalEditMode }"
|
|
/>
|
|
</v-col>
|
|
<v-col cols="12">
|
|
<v-divider class="my-4" />
|
|
</v-col>
|
|
<v-col cols="12">
|
|
<h3 class="text-h6 mb-4">Regional Settings</h3>
|
|
</v-col>
|
|
<v-col cols="12" md="4">
|
|
<v-select
|
|
v-model="settings.general.timezone"
|
|
label="Timezone"
|
|
:items="timezones"
|
|
variant="outlined"
|
|
:readonly="!generalEditMode"
|
|
:disabled="!generalEditMode"
|
|
:class="{ 'readonly-field': !generalEditMode }"
|
|
/>
|
|
</v-col>
|
|
<v-col cols="12" md="4">
|
|
<v-select
|
|
v-model="settings.general.dateFormat"
|
|
label="Date Format"
|
|
:items="dateFormats"
|
|
variant="outlined"
|
|
:readonly="!generalEditMode"
|
|
:disabled="!generalEditMode"
|
|
:class="{ 'readonly-field': !generalEditMode }"
|
|
/>
|
|
</v-col>
|
|
<v-col cols="12" md="4">
|
|
<v-select
|
|
v-model="settings.general.currency"
|
|
label="Currency"
|
|
:items="currencies"
|
|
variant="outlined"
|
|
:readonly="!generalEditMode"
|
|
:disabled="!generalEditMode"
|
|
:class="{ 'readonly-field': !generalEditMode }"
|
|
/>
|
|
</v-col>
|
|
</v-row>
|
|
</v-card-text>
|
|
</v-window-item>
|
|
|
|
<!-- Email Settings -->
|
|
<v-window-item value="email">
|
|
<v-card-text>
|
|
<!-- Edit Mode Toggle -->
|
|
<v-row class="mb-4">
|
|
<v-col>
|
|
<v-alert
|
|
v-if="!emailEditMode"
|
|
type="info"
|
|
variant="tonal"
|
|
density="compact"
|
|
>
|
|
<template v-slot:text>
|
|
Click "Edit Email Configuration" to modify SMTP settings
|
|
</template>
|
|
</v-alert>
|
|
<v-alert
|
|
v-if="emailEditMode"
|
|
type="warning"
|
|
variant="tonal"
|
|
density="compact"
|
|
>
|
|
<template v-slot:text>
|
|
Be careful when editing email settings. Incorrect values may prevent emails from being sent.
|
|
</template>
|
|
</v-alert>
|
|
</v-col>
|
|
<v-col cols="auto">
|
|
<v-btn
|
|
v-if="!emailEditMode"
|
|
color="primary"
|
|
variant="outlined"
|
|
@click="emailEditMode = true"
|
|
>
|
|
<v-icon start>mdi-pencil</v-icon>
|
|
Edit Email Configuration
|
|
</v-btn>
|
|
<v-btn-group v-else>
|
|
<v-btn
|
|
color="success"
|
|
variant="flat"
|
|
@click="saveEmailSettings"
|
|
>
|
|
<v-icon start>mdi-check</v-icon>
|
|
Save
|
|
</v-btn>
|
|
<v-btn
|
|
color="warning"
|
|
variant="outlined"
|
|
@click="testEmailSettings"
|
|
:loading="testingEmail"
|
|
>
|
|
<v-icon start>mdi-email-check</v-icon>
|
|
Test
|
|
</v-btn>
|
|
<v-btn
|
|
color="error"
|
|
variant="outlined"
|
|
@click="cancelEmailEdit"
|
|
>
|
|
<v-icon start>mdi-close</v-icon>
|
|
Cancel
|
|
</v-btn>
|
|
</v-btn-group>
|
|
</v-col>
|
|
</v-row>
|
|
|
|
<v-row>
|
|
<v-col cols="12">
|
|
<h3 class="text-h6 mb-4">SMTP Configuration</h3>
|
|
</v-col>
|
|
<v-col cols="12" md="6">
|
|
<v-text-field
|
|
v-model="settings.email.smtpHost"
|
|
label="SMTP Host"
|
|
variant="outlined"
|
|
:readonly="!emailEditMode"
|
|
:disabled="!emailEditMode"
|
|
autocomplete="new-password"
|
|
:type="emailEditMode ? 'text' : 'password'"
|
|
:class="{ 'readonly-field': !emailEditMode }"
|
|
/>
|
|
</v-col>
|
|
<v-col cols="12" md="6">
|
|
<v-text-field
|
|
v-model="settings.email.smtpPort"
|
|
label="SMTP Port"
|
|
variant="outlined"
|
|
type="number"
|
|
:readonly="!emailEditMode"
|
|
:disabled="!emailEditMode"
|
|
autocomplete="off"
|
|
:class="{ 'readonly-field': !emailEditMode }"
|
|
/>
|
|
</v-col>
|
|
<v-col cols="12" md="6">
|
|
<v-text-field
|
|
v-model="settings.email.smtpUsername"
|
|
label="SMTP Username"
|
|
variant="outlined"
|
|
:readonly="!emailEditMode"
|
|
:disabled="!emailEditMode"
|
|
autocomplete="new-password"
|
|
:type="emailEditMode ? 'text' : 'password'"
|
|
:class="{ 'readonly-field': !emailEditMode }"
|
|
/>
|
|
</v-col>
|
|
<v-col cols="12" md="6">
|
|
<v-text-field
|
|
v-model="settings.email.smtpPassword"
|
|
label="SMTP Password"
|
|
variant="outlined"
|
|
:type="showPassword ? 'text' : 'password'"
|
|
:readonly="!emailEditMode"
|
|
:disabled="!emailEditMode"
|
|
autocomplete="new-password"
|
|
:class="{ 'readonly-field': !emailEditMode }"
|
|
>
|
|
<template v-slot:append-inner>
|
|
<v-icon
|
|
v-if="emailEditMode"
|
|
@click="showPassword = !showPassword"
|
|
:icon="showPassword ? 'mdi-eye-off' : 'mdi-eye'"
|
|
class="cursor-pointer"
|
|
/>
|
|
</template>
|
|
</v-text-field>
|
|
</v-col>
|
|
<v-col cols="12">
|
|
<v-switch
|
|
v-model="settings.email.useTLS"
|
|
label="Use TLS/SSL"
|
|
color="primary"
|
|
:readonly="!emailEditMode"
|
|
:disabled="!emailEditMode"
|
|
/>
|
|
</v-col>
|
|
<v-col cols="12">
|
|
<v-divider class="my-4" />
|
|
</v-col>
|
|
<v-col cols="12">
|
|
<h3 class="text-h6 mb-4">Email Templates</h3>
|
|
</v-col>
|
|
<v-col cols="12" md="6">
|
|
<v-text-field
|
|
v-model="settings.email.fromName"
|
|
label="From Name"
|
|
variant="outlined"
|
|
:readonly="!emailEditMode"
|
|
:disabled="!emailEditMode"
|
|
autocomplete="off"
|
|
:class="{ 'readonly-field': !emailEditMode }"
|
|
/>
|
|
</v-col>
|
|
<v-col cols="12" md="6">
|
|
<v-text-field
|
|
v-model="settings.email.fromEmail"
|
|
label="From Email"
|
|
variant="outlined"
|
|
type="email"
|
|
:readonly="!emailEditMode"
|
|
:disabled="!emailEditMode"
|
|
autocomplete="off"
|
|
:class="{ 'readonly-field': !emailEditMode }"
|
|
/>
|
|
</v-col>
|
|
<v-col cols="12">
|
|
<v-btn variant="outlined" color="primary">
|
|
<v-icon start>mdi-email-edit</v-icon>
|
|
Manage Email Templates
|
|
</v-btn>
|
|
</v-col>
|
|
</v-row>
|
|
</v-card-text>
|
|
</v-window-item>
|
|
</v-window>
|
|
</v-card>
|
|
|
|
<!-- Snackbar for notifications -->
|
|
<v-snackbar
|
|
v-model="snackbar"
|
|
:color="snackbarColor"
|
|
:timeout="3000"
|
|
>
|
|
{{ snackbarText }}
|
|
<template v-slot:actions>
|
|
<v-btn
|
|
variant="text"
|
|
@click="snackbar = false"
|
|
>
|
|
Close
|
|
</v-btn>
|
|
</template>
|
|
</v-snackbar>
|
|
</v-container>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
definePageMeta({
|
|
layout: 'admin',
|
|
middleware: 'admin'
|
|
});
|
|
|
|
// State
|
|
const activeTab = ref('general');
|
|
const generalEditMode = ref(false);
|
|
const emailEditMode = ref(false);
|
|
const showPassword = ref(false);
|
|
const testingEmail = ref(false);
|
|
const snackbar = ref(false);
|
|
const snackbarText = ref('');
|
|
const snackbarColor = ref('success');
|
|
|
|
// Original settings backup for cancel functionality
|
|
const originalSettings = ref<any>(null);
|
|
|
|
// Settings data
|
|
const settings = ref({
|
|
general: {
|
|
orgName: 'MonacoUSA',
|
|
orgEmail: 'info@monacousa.org',
|
|
orgDescription: 'Monaco USA Association - Connecting Monaco and USA',
|
|
timezone: 'America/New_York',
|
|
dateFormat: 'MM/DD/YYYY',
|
|
currency: 'EUR'
|
|
},
|
|
email: {
|
|
smtpHost: 'smtp.gmail.com',
|
|
smtpPort: 587,
|
|
smtpUsername: '',
|
|
smtpPassword: '',
|
|
useTLS: true,
|
|
fromName: 'MonacoUSA',
|
|
fromEmail: 'noreply@monacousa.org'
|
|
}
|
|
});
|
|
|
|
// Options
|
|
const timezones = [
|
|
'America/New_York',
|
|
'America/Chicago',
|
|
'America/Denver',
|
|
'America/Los_Angeles',
|
|
'Europe/Monaco'
|
|
];
|
|
|
|
const dateFormats = [
|
|
'MM/DD/YYYY',
|
|
'DD/MM/YYYY',
|
|
'YYYY-MM-DD'
|
|
];
|
|
|
|
const currencies = [
|
|
'EUR',
|
|
'USD',
|
|
'GBP'
|
|
];
|
|
|
|
// Load settings on mount
|
|
onMounted(async () => {
|
|
await loadSettings();
|
|
});
|
|
|
|
// Methods
|
|
const loadSettings = async () => {
|
|
try {
|
|
// Load settings from API
|
|
// For now, we'll keep the defaults
|
|
console.log('Loading settings...');
|
|
} catch (error) {
|
|
console.error('Error loading settings:', error);
|
|
showNotification('Failed to load settings', 'error');
|
|
}
|
|
};
|
|
|
|
const saveGeneralSettings = async () => {
|
|
try {
|
|
console.log('Saving general settings:', settings.value.general);
|
|
// TODO: Save to API
|
|
generalEditMode.value = false;
|
|
showNotification('General settings saved successfully', 'success');
|
|
} catch (error) {
|
|
console.error('Error saving general settings:', error);
|
|
showNotification('Failed to save general settings', 'error');
|
|
}
|
|
};
|
|
|
|
const cancelGeneralEdit = () => {
|
|
if (originalSettings.value) {
|
|
settings.value.general = { ...originalSettings.value.general };
|
|
}
|
|
generalEditMode.value = false;
|
|
};
|
|
|
|
const saveEmailSettings = async () => {
|
|
try {
|
|
console.log('Saving email settings:', settings.value.email);
|
|
// TODO: Save to API
|
|
emailEditMode.value = false;
|
|
showPassword.value = false;
|
|
showNotification('Email settings saved successfully', 'success');
|
|
} catch (error) {
|
|
console.error('Error saving email settings:', error);
|
|
showNotification('Failed to save email settings', 'error');
|
|
}
|
|
};
|
|
|
|
const testEmailSettings = async () => {
|
|
testingEmail.value = true;
|
|
try {
|
|
console.log('Testing email settings...');
|
|
// TODO: Test email configuration via API
|
|
await new Promise(resolve => setTimeout(resolve, 2000)); // Simulate API call
|
|
showNotification('Test email sent successfully', 'success');
|
|
} catch (error) {
|
|
console.error('Error testing email:', error);
|
|
showNotification('Failed to send test email', 'error');
|
|
} finally {
|
|
testingEmail.value = false;
|
|
}
|
|
};
|
|
|
|
const cancelEmailEdit = () => {
|
|
if (originalSettings.value) {
|
|
settings.value.email = { ...originalSettings.value.email };
|
|
}
|
|
emailEditMode.value = false;
|
|
showPassword.value = false;
|
|
};
|
|
|
|
const showNotification = (text: string, color: string = 'success') => {
|
|
snackbarText.value = text;
|
|
snackbarColor.value = color;
|
|
snackbar.value = true;
|
|
};
|
|
|
|
// Watch for edit mode changes to backup original settings
|
|
watch(generalEditMode, (newVal) => {
|
|
if (newVal) {
|
|
originalSettings.value = {
|
|
general: { ...settings.value.general }
|
|
};
|
|
}
|
|
});
|
|
|
|
watch(emailEditMode, (newVal) => {
|
|
if (newVal) {
|
|
originalSettings.value = {
|
|
email: { ...settings.value.email }
|
|
};
|
|
}
|
|
});
|
|
|
|
// Prevent browser autofill on mount
|
|
onMounted(() => {
|
|
// Disable autofill for all inputs initially
|
|
const inputs = document.querySelectorAll('input');
|
|
inputs.forEach(input => {
|
|
input.setAttribute('autocomplete', 'off');
|
|
input.setAttribute('data-lpignore', 'true'); // LastPass
|
|
input.setAttribute('data-form-type', 'other'); // Dashlane
|
|
});
|
|
});
|
|
</script>
|
|
|
|
<style scoped>
|
|
.readonly-field :deep(.v-field) {
|
|
background-color: rgba(0, 0, 0, 0.02);
|
|
}
|
|
|
|
.readonly-field :deep(.v-field__input) {
|
|
cursor: default !important;
|
|
}
|
|
|
|
.cursor-pointer {
|
|
cursor: pointer;
|
|
}
|
|
|
|
/* Prevent browser autofill styling */
|
|
:deep(input:-webkit-autofill),
|
|
:deep(input:-webkit-autofill:hover),
|
|
:deep(input:-webkit-autofill:focus),
|
|
:deep(input:-webkit-autofill:active) {
|
|
-webkit-box-shadow: 0 0 0 30px white inset !important;
|
|
box-shadow: 0 0 0 30px white inset !important;
|
|
}
|
|
</style> |