switch to discord hook for contact
This commit is contained in:
parent
68c5fc73f4
commit
832ef7f411
5 changed files with 53 additions and 62 deletions
6
bun.lock
6
bun.lock
|
|
@ -10,7 +10,6 @@
|
||||||
"@sveltejs/adapter-netlify": "^5.2.4",
|
"@sveltejs/adapter-netlify": "^5.2.4",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.13",
|
||||||
"nodemailer": "^6.10.1",
|
|
||||||
"pino": "^9.6.0",
|
"pino": "^9.6.0",
|
||||||
"tailwind-merge": "^3.4.0",
|
"tailwind-merge": "^3.4.0",
|
||||||
},
|
},
|
||||||
|
|
@ -21,7 +20,6 @@
|
||||||
"@sveltejs/kit": "^2.20.7",
|
"@sveltejs/kit": "^2.20.7",
|
||||||
"@sveltejs/vite-plugin-svelte": "^5.0.3",
|
"@sveltejs/vite-plugin-svelte": "^5.0.3",
|
||||||
"@tailwindcss/vite": "^4.1.4",
|
"@tailwindcss/vite": "^4.1.4",
|
||||||
"@types/nodemailer": "^6.4.17",
|
|
||||||
"autoprefixer": "^10.4.21",
|
"autoprefixer": "^10.4.21",
|
||||||
"daisyui": "^5.5.14",
|
"daisyui": "^5.5.14",
|
||||||
"eslint": "^9.25.1",
|
"eslint": "^9.25.1",
|
||||||
|
|
@ -252,8 +250,6 @@
|
||||||
|
|
||||||
"@types/node": ["@types/node@22.15.3", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-lX7HFZeHf4QG/J7tBZqrCAXwz9J5RD56Y6MpP0eJkka8p+K0RY/yBTW7CYFJ4VGCclxqOLKmiGP5juQc6MKgcw=="],
|
"@types/node": ["@types/node@22.15.3", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-lX7HFZeHf4QG/J7tBZqrCAXwz9J5RD56Y6MpP0eJkka8p+K0RY/yBTW7CYFJ4VGCclxqOLKmiGP5juQc6MKgcw=="],
|
||||||
|
|
||||||
"@types/nodemailer": ["@types/nodemailer@6.4.17", "", { "dependencies": { "@types/node": "*" } }, "sha512-I9CCaIp6DTldEg7vyUTZi8+9Vo0hi1/T8gv3C89yk1rSAAzoKQ8H8ki/jBYJSFoH/BisgLP8tkZMlQ91CIquww=="],
|
|
||||||
|
|
||||||
"@types/resolve": ["@types/resolve@1.20.2", "", {}, "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q=="],
|
"@types/resolve": ["@types/resolve@1.20.2", "", {}, "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q=="],
|
||||||
|
|
||||||
"@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="],
|
"@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="],
|
||||||
|
|
@ -574,8 +570,6 @@
|
||||||
|
|
||||||
"node-releases": ["node-releases@2.0.19", "", {}, "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw=="],
|
"node-releases": ["node-releases@2.0.19", "", {}, "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw=="],
|
||||||
|
|
||||||
"nodemailer": ["nodemailer@6.10.1", "", {}, "sha512-Z+iLaBGVaSjbIzQ4pX6XV41HrooLsQ10ZWPUehGmuantvzWoDVBnmsdUcOIDM1t+yPor5pDhVlDESgOMEGxhHA=="],
|
|
||||||
|
|
||||||
"normalize-range": ["normalize-range@0.1.2", "", {}, "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA=="],
|
"normalize-range": ["normalize-range@0.1.2", "", {}, "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA=="],
|
||||||
|
|
||||||
"on-exit-leak-free": ["on-exit-leak-free@2.1.2", "", {}, "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA=="],
|
"on-exit-leak-free": ["on-exit-leak-free@2.1.2", "", {}, "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA=="],
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@
|
||||||
"@sveltejs/kit": "^2.20.7",
|
"@sveltejs/kit": "^2.20.7",
|
||||||
"@sveltejs/vite-plugin-svelte": "^5.0.3",
|
"@sveltejs/vite-plugin-svelte": "^5.0.3",
|
||||||
"@tailwindcss/vite": "^4.1.4",
|
"@tailwindcss/vite": "^4.1.4",
|
||||||
"@types/nodemailer": "^6.4.17",
|
|
||||||
"autoprefixer": "^10.4.21",
|
"autoprefixer": "^10.4.21",
|
||||||
"daisyui": "^5.5.14",
|
"daisyui": "^5.5.14",
|
||||||
"eslint": "^9.25.1",
|
"eslint": "^9.25.1",
|
||||||
|
|
@ -47,7 +46,6 @@
|
||||||
"@sveltejs/adapter-netlify": "^5.2.4",
|
"@sveltejs/adapter-netlify": "^5.2.4",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.13",
|
||||||
"nodemailer": "^6.10.1",
|
|
||||||
"pino": "^9.6.0",
|
"pino": "^9.6.0",
|
||||||
"tailwind-merge": "^3.4.0"
|
"tailwind-merge": "^3.4.0"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
26
src/lib/server/discord.ts
Normal file
26
src/lib/server/discord.ts
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
import { DISCORD_CONTACT_WEBHOOK } from '$env/static/private';
|
||||||
|
|
||||||
|
export async function sendContactMessage(
|
||||||
|
name: string,
|
||||||
|
email: string,
|
||||||
|
subject: string,
|
||||||
|
message: string
|
||||||
|
) {
|
||||||
|
const form = new FormData();
|
||||||
|
|
||||||
|
// We need a better way than this to format a string to markdown
|
||||||
|
const content = `
|
||||||
|
# Someone is reaching out!
|
||||||
|
|
||||||
|
From: ${name} - [${email}](mailto:${email})
|
||||||
|
> **Subject: ${subject}**
|
||||||
|
> ${message}
|
||||||
|
`
|
||||||
|
.split('\n')
|
||||||
|
.map((str) => str.trim())
|
||||||
|
.join('\n');
|
||||||
|
|
||||||
|
form.append('content', content);
|
||||||
|
|
||||||
|
return await fetch(DISCORD_CONTACT_WEBHOOK, { method: 'POST', body: form });
|
||||||
|
}
|
||||||
|
|
@ -1,84 +1,59 @@
|
||||||
import { env } from "$env/dynamic/private";
|
import { sendContactMessage } from '$lib/server/discord';
|
||||||
import { fail } from "@sveltejs/kit";
|
import { logger } from '$lib/server/logger';
|
||||||
import { createTransport } from "nodemailer";
|
import { fail } from '@sveltejs/kit';
|
||||||
import type { Actions } from "./$types";
|
import type { Actions } from './$types';
|
||||||
import { logger } from "$lib/server/logger";
|
|
||||||
|
|
||||||
export const actions = {
|
export const actions = {
|
||||||
default: async ({ request }) => {
|
default: async ({ request }) => {
|
||||||
const form = await request.formData();
|
const form = await request.formData();
|
||||||
|
|
||||||
if (!form.has("name")) {
|
if (!form.has('name')) {
|
||||||
return fail(400, { name: null, missing: true });
|
return fail(400, { name: null, missing: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!form.has("email")) {
|
if (!form.has('email')) {
|
||||||
return fail(400, { email: null, missing: true });
|
return fail(400, { email: null, missing: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!form.has("subject")) {
|
if (!form.has('subject')) {
|
||||||
return fail(400, { subject: null, missing: true });
|
return fail(400, { subject: null, missing: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!form.has("message")) {
|
if (!form.has('message')) {
|
||||||
return fail(400, { message: null, missing: true });
|
return fail(400, { message: null, missing: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
const name = form.get("name");
|
const name = form.get('name');
|
||||||
if (typeof name !== "string") {
|
if (typeof name !== 'string') {
|
||||||
return fail(400, { name, incorrect: true });
|
return fail(400, { name, incorrect: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
const email = form.get("email");
|
const email = form.get('email');
|
||||||
if (typeof email !== "string") {
|
if (typeof email !== 'string') {
|
||||||
return fail(400, { email, incorrect: true });
|
return fail(400, { email, incorrect: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
const subject = form.get("subject");
|
const subject = form.get('subject');
|
||||||
if (typeof subject !== "string") {
|
if (typeof subject !== 'string') {
|
||||||
return fail(400, { subject, incorrect: true });
|
return fail(400, { subject, incorrect: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
const message = form.get("message");
|
const message = form.get('message');
|
||||||
if (typeof message !== "string") {
|
if (typeof message !== 'string') {
|
||||||
return fail(400, { message, incorrect: true });
|
return fail(400, { message, incorrect: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
const transport = createTransport({
|
|
||||||
host: env.MAIL_TRANSPORT_HOST,
|
|
||||||
port: isNaN(Number(env.MAIL_TRANSPORT_PORT))
|
|
||||||
? 587
|
|
||||||
: Number(env.MAIL_TRANSPORT_PORT),
|
|
||||||
auth: {
|
|
||||||
user: env.MAIL_TRANSPORT_USER,
|
|
||||||
pass: env.MAIL_TRANSPORT_PASS,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const info1 = await transport.sendMail({
|
const response = await sendContactMessage(name, email, subject, message);
|
||||||
from: "no-reply@benjaminpalko.ca",
|
|
||||||
to: email,
|
|
||||||
subject: `Thank you for reaching out`,
|
|
||||||
text: `Hello ${name}!\n\nThank you for reaching out! I will be sure to get back to you ASAP.\n\nCheers,\nBenjamin`,
|
|
||||||
});
|
|
||||||
|
|
||||||
const info2 = await transport.sendMail({
|
|
||||||
from: email,
|
|
||||||
to: "contact@benjaminpalko.ca",
|
|
||||||
subject: subject,
|
|
||||||
text: message,
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
response: {
|
response: {
|
||||||
accepted: [...info1.accepted, ...info2.accepted],
|
ok: response.ok
|
||||||
rejected: [...info1.rejected, ...info2.rejected],
|
}
|
||||||
},
|
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(error);
|
logger.error(error);
|
||||||
fail(400, { incorrect: true });
|
fail(400, { incorrect: true });
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
} satisfies Actions;
|
} satisfies Actions;
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,6 @@
|
||||||
let loading = $state(false);
|
let loading = $state(false);
|
||||||
|
|
||||||
let { form }: PageProps = $props();
|
let { form }: PageProps = $props();
|
||||||
|
|
||||||
$inspect(form);
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<form
|
<form
|
||||||
|
|
@ -33,19 +31,19 @@
|
||||||
<h2 class="col-span-full text-center text-4xl font-light">Reach out! 🤝</h2>
|
<h2 class="col-span-full text-center text-4xl font-light">Reach out! 🤝</h2>
|
||||||
|
|
||||||
<div class="col-span-full">
|
<div class="col-span-full">
|
||||||
{#if form?.response?.rejected.length ?? 0 > 0}
|
{#if form?.incorrect}
|
||||||
<div role="alert" class="alert alert-error w-full">
|
<div role="alert" class="alert alert-warning w-full">
|
||||||
<CircleX />
|
<TriangleAlert />
|
||||||
<span>Ruh roh raggy!</span>
|
<span>Ruh roh raggy!</span>
|
||||||
</div>
|
</div>
|
||||||
{:else if form?.response?.accepted.length ?? 0 > 0}
|
{:else if form?.response?.ok}
|
||||||
<div role="alert" class="alert alert-success w-full">
|
<div role="alert" class="alert alert-success w-full">
|
||||||
<CircleCheck />
|
<CircleCheck />
|
||||||
<span>Your message has been sent successfully!</span>
|
<span>Your message has been sent successfully!</span>
|
||||||
</div>
|
</div>
|
||||||
{:else if form?.incorrect}
|
{:else if form?.response?.ok === false}
|
||||||
<div role="alert" class="alert alert-warning w-full">
|
<div role="alert" class="alert alert-error w-full">
|
||||||
<TriangleAlert />
|
<CircleX />
|
||||||
<span>Ruh roh raggy!</span>
|
<span>Ruh roh raggy!</span>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue