feat: add email sending via Mail API
This commit is contained in:
parent
0141657e14
commit
6cd1f7d620
10
package-lock.json
generated
10
package-lock.json
generated
@ -12,6 +12,7 @@
|
|||||||
"vue": "^3.4.21",
|
"vue": "^3.4.21",
|
||||||
"vue-loading-overlay": "^6.0.6",
|
"vue-loading-overlay": "^6.0.6",
|
||||||
"vue-preloader": "^1.1.4",
|
"vue-preloader": "^1.1.4",
|
||||||
|
"vue-toastification": "^2.0.0-rc.5",
|
||||||
"vue-typer": "^1.2.0",
|
"vue-typer": "^1.2.0",
|
||||||
"vue3-typer": "^1.0.0"
|
"vue3-typer": "^1.0.0"
|
||||||
},
|
},
|
||||||
@ -2963,6 +2964,15 @@
|
|||||||
"node": ">=14"
|
"node": ">=14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/vue-toastification": {
|
||||||
|
"version": "2.0.0-rc.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/vue-toastification/-/vue-toastification-2.0.0-rc.5.tgz",
|
||||||
|
"integrity": "sha512-q73e5jy6gucEO/U+P48hqX+/qyXDozAGmaGgLFm5tXX4wJBcVsnGp4e/iJqlm9xzHETYOilUuwOUje2Qg1JdwA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"vue": "^3.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/vue-typer": {
|
"node_modules/vue-typer": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/vue-typer/-/vue-typer-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/vue-typer/-/vue-typer-1.2.0.tgz",
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
"vue": "^3.4.21",
|
"vue": "^3.4.21",
|
||||||
"vue-loading-overlay": "^6.0.6",
|
"vue-loading-overlay": "^6.0.6",
|
||||||
"vue-preloader": "^1.1.4",
|
"vue-preloader": "^1.1.4",
|
||||||
|
"vue-toastification": "^2.0.0-rc.5",
|
||||||
"vue-typer": "^1.2.0",
|
"vue-typer": "^1.2.0",
|
||||||
"vue3-typer": "^1.0.0"
|
"vue3-typer": "^1.0.0"
|
||||||
},
|
},
|
||||||
|
@ -2,7 +2,8 @@
|
|||||||
import {ref} from 'vue'
|
import {ref} from 'vue'
|
||||||
import {Github, Globe, Linkedin, Mail, MapPin, Phone} from 'lucide-vue-next'
|
import {Github, Globe, Linkedin, Mail, MapPin, Phone} from 'lucide-vue-next'
|
||||||
import type {Profile} from '@/domain/models/Profile'
|
import type {Profile} from '@/domain/models/Profile'
|
||||||
|
import { useToast } from "vue-toastification";
|
||||||
|
const toast = useToast();
|
||||||
defineProps<{
|
defineProps<{
|
||||||
profile: Profile
|
profile: Profile
|
||||||
}>()
|
}>()
|
||||||
@ -27,23 +28,37 @@ function getSocialIcon(platform) {
|
|||||||
async function handleSubmit() {
|
async function handleSubmit() {
|
||||||
isSubmitting.value = true
|
isSubmitting.value = true
|
||||||
|
|
||||||
// Simulate form submission
|
try {
|
||||||
await new Promise(resolve => setTimeout(resolve, 1000))
|
const payload = {
|
||||||
|
from: form.value.email,
|
||||||
|
subject: form.value.name,
|
||||||
|
body: form.value.message
|
||||||
|
}
|
||||||
|
|
||||||
// Here you would typically send the form data to your backend
|
const response = await fetch(`${import.meta.env.VITE_MAIL_API_URL}/mail`, {
|
||||||
console.log('Form submitted:', form.value)
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify(payload)
|
||||||
|
})
|
||||||
|
|
||||||
// Reset form
|
if (!response.ok) {
|
||||||
form.value = {
|
throw new Error(`Error en el envío: ${response.status}`)
|
||||||
name: '',
|
}
|
||||||
email: '',
|
|
||||||
message: ''
|
form.value = {
|
||||||
|
name: '',
|
||||||
|
email: '',
|
||||||
|
message: ''
|
||||||
|
}
|
||||||
|
|
||||||
|
toast.success("✅ ¡Mensaje enviado correctamente! Te responderé pronto.")
|
||||||
|
} catch (error) {
|
||||||
|
toast.error("❌ Hubo un error al enviar el mensaje. Inténtalo de nuevo.")
|
||||||
|
} finally {
|
||||||
|
isSubmitting.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
isSubmitting.value = false
|
|
||||||
|
|
||||||
// Show success message (you could use a toast notification)
|
|
||||||
alert('¡Mensaje enviado correctamente! Te responderé pronto.')
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -117,15 +132,12 @@ async function handleSubmit() {
|
|||||||
|
|
||||||
<!-- Contact Form -->
|
<!-- Contact Form -->
|
||||||
<div class="bg-gray-50 dark:bg-gray-700 rounded-xl p-8">
|
<div class="bg-gray-50 dark:bg-gray-700 rounded-xl p-8">
|
||||||
<p class="m-5">¡Hola! Por el momento mi servidor SMTP está de vacaciones 😅.</p>
|
|
||||||
<p class="m-5">Si quieres contactarme, envíame un correo electrónico directamente y prometo responderte
|
|
||||||
rápido.</p>
|
|
||||||
<form @submit.prevent="handleSubmit" class="space-y-6">
|
<form @submit.prevent="handleSubmit" class="space-y-6">
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||||
Nombre
|
Nombre
|
||||||
</label>
|
</label>
|
||||||
<input disabled
|
<input
|
||||||
v-model="form.name"
|
v-model="form.name"
|
||||||
type="text"
|
type="text"
|
||||||
required
|
required
|
||||||
@ -137,7 +149,7 @@ async function handleSubmit() {
|
|||||||
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||||
Email
|
Email
|
||||||
</label>
|
</label>
|
||||||
<input disabled
|
<input
|
||||||
v-model="form.email"
|
v-model="form.email"
|
||||||
type="email"
|
type="email"
|
||||||
required
|
required
|
||||||
@ -149,7 +161,7 @@ async function handleSubmit() {
|
|||||||
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||||
Mensaje
|
Mensaje
|
||||||
</label>
|
</label>
|
||||||
<textarea disabled
|
<textarea
|
||||||
v-model="form.message"
|
v-model="form.message"
|
||||||
rows="4"
|
rows="4"
|
||||||
required
|
required
|
||||||
@ -159,7 +171,7 @@ async function handleSubmit() {
|
|||||||
|
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
:disabled="isSubmitting || 1===1"
|
:disabled="isSubmitting"
|
||||||
class="w-full px-6 py-3 bg-purple-600 hover:bg-purple-700 disabled:opacity-50 text-white rounded-lg font-semibold transition-colors"
|
class="w-full px-6 py-3 bg-purple-600 hover:bg-purple-700 disabled:opacity-50 text-white rounded-lg font-semibold transition-colors"
|
||||||
>
|
>
|
||||||
{{ isSubmitting ? 'Enviando...' : 'Enviar Mensaje' }}
|
{{ isSubmitting ? 'Enviando...' : 'Enviar Mensaje' }}
|
||||||
|
@ -3,10 +3,14 @@ import "./style.css"
|
|||||||
import VueTyper from 'vue3-typer'
|
import VueTyper from 'vue3-typer'
|
||||||
import "vue3-typer/dist/vue-typer.css"
|
import "vue3-typer/dist/vue-typer.css"
|
||||||
import App from "./App.vue";
|
import App from "./App.vue";
|
||||||
|
import Toast from "vue-toastification";
|
||||||
|
import "vue-toastification/dist/index.css";
|
||||||
|
|
||||||
const app = createApp(App)
|
const app = createApp(App)
|
||||||
app.component('VueTyper', VueTyper)
|
app.component('VueTyper', VueTyper)
|
||||||
|
|
||||||
|
app.use(Toast, {});
|
||||||
|
|
||||||
// Global error handler
|
// Global error handler
|
||||||
app.config.errorHandler = (err, vm, info) => {
|
app.config.errorHandler = (err, vm, info) => {
|
||||||
console.error("Global error:", err, info)
|
console.error("Global error:", err, info)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user