Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,4 @@ deno.lock

/static/open-letter/portraits/original
CLAUDE.md
.claude/
408 changes: 204 additions & 204 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion src/lib/redirects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ const REDIRECTS: Record<string, string> = {
'/polls': '/polls-and-surveys',
'/surveys': '/polls-and-surveys',
'/stipends': '/volunteer-stipends',
'/volunteer-vacancies': '/join#volunteer-vacancies'
'/volunteer-vacancies': '/join#volunteer-vacancies',
'/contact': '/contact-us'
}

/** Temporary redirects (302) - for time-limited campaigns, A/B tests, etc. */
Expand Down
4 changes: 1 addition & 3 deletions src/posts/partnerships.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,4 @@ PauseAI offers unique benefits to a variety of organizations and individuals, en
- **Grassroots Feedback:** Gather ground-level feedback on AI safety programs.
- **Cross-border Collaboration:** Connect local activists with global initiatives.

## Interested in exploring partnership opportunities?

Send an email to [joep@pauseai.info](mailto:joep@pauseai.info).
Interested in exploring partnership opportunities? Check out our [Contact form](/contact-us?tab=partnerships).
4 changes: 1 addition & 3 deletions src/posts/press.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@
title: PauseAI Press materials & media coverage
---

## Contact

Maxime Fournes ([press@pauseai.info](mailto:press@pauseai.info))
If you want to contact us, use our [Contact form](/contact-us?tab=media)

## Logo, materials

Expand Down
219 changes: 219 additions & 0 deletions src/routes/contact-us/+page.server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
import { fail } from '@sveltejs/kit'
import type { Actions } from './$types'
import { env } from '$env/dynamic/private'

export const prerender = false

// Configure recipient email addresses for each contact form type
const CONTACT_RECIPIENTS = {
Standard: 'info@pauseai.info',
Media: 'press@pauseai.info',
Partnerships: 'info@pauseai.info',
Feedback: 'info@pauseai.info'
} as const

async function sendContactEmail(data: {
name: string
email: string
subject: string
message: string
type: 'Standard' | 'Media' | 'Partnerships' | 'Feedback'
organization?: string
}) {
if (!env.MAILERSEND_API_KEY) {
console.error('MAILERSEND_API_KEY is not configured')
return {
success: false,
message: 'Email service is not configured. Please contact the administrator.'
}
}

const recipientEmail = CONTACT_RECIPIENTS[data.type]

let htmlContent = `
<p><strong>Name:</strong> ${data.name}</p>
<p><strong>Email:</strong> ${data.email}</p>
<p><strong>Subject:</strong> ${data.subject}</p>
`

if (data.organization) {
htmlContent += `<p><strong>Organization:</strong> ${data.organization}</p>`
}

htmlContent += `<p><strong>Message:</strong></p><p>${data.message.replace(/\n/g, '<br>')}</p>`

const textContent = `Name: ${data.name}\nEmail: ${data.email}\nSubject: ${data.subject}${data.organization ? `\nOrganization: ${data.organization}` : ''}\n\nMessage:\n${data.message}`

// Build the request body for MailerSend API
const emailBody: {
from: { email: string; name: string }
to: { email: string; name: string }[]
subject: string
html: string
text: string
reply_to?: { email: string; name: string }
} = {
from: {
email: 'info@pauseai.info',
name: 'PauseAI Contact Form'
},
to: [
{
email: recipientEmail,
name: 'PauseAI Team'
}
],
subject: `[Contact Form] ${data.subject}`,
html: htmlContent,
text: textContent
}

if (data.email) {
emailBody.reply_to = {
email: data.email,
name: data.name
}
}

try {
const response = await fetch('https://api.mailersend.com/v1/email', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${env.MAILERSEND_API_KEY}`
},
body: JSON.stringify(emailBody)
})

if (!response.ok) {
const errorData = await response.json().catch(() => ({}))
console.error('MailerSend Error:', response.status, JSON.stringify(errorData, null, 2))

let errorMessage = 'Failed to send email. Please try again later.'
if (errorData.message) {
errorMessage = errorData.message.replace('reply to.email', 'email')
}

return { success: false, message: errorMessage }
}

return { success: true }
} catch (error: unknown) {
console.error('MailerSend Error:', error)

let errorMessage = 'Failed to send email. Please try again later.'
const err = error as { message?: string }
if (err.message) {
errorMessage = err.message
}

return { success: false, message: errorMessage }
}
}

export const actions: Actions = {
standard: async ({ request }) => {
const data = await request.formData()
const name = data.get('name')?.toString()
const email = data.get('email')?.toString()
const subject = data.get('subject')?.toString()
const message = data.get('message')?.toString()

if (!name || !email || !subject || !message) {
return fail(400, { message: 'Missing required fields' })
}

const result = await sendContactEmail({
name,
email,
subject,
message,
type: 'Standard'
})

if (!result.success) {
return fail(500, { message: result.message })
}

return { success: true }
},
media: async ({ request }) => {
const data = await request.formData()
const name = data.get('name')?.toString()
const email = data.get('email')?.toString()
const subject = data.get('subject')?.toString()
const organization = data.get('organization')?.toString()
const details = data.get('details')?.toString()

if (!name || !email || !subject || !organization || !details) {
return fail(400, { message: 'Missing required fields' })
}

const result = await sendContactEmail({
name,
email,
subject,
message: details,
organization,
type: 'Media'
})

if (!result.success) {
return fail(500, { message: result.message })
}

return { success: true }
},
partnerships: async ({ request }) => {
const data = await request.formData()
const name = data.get('name')?.toString()
const email = data.get('email')?.toString()
const organization = data.get('organization')?.toString()
const subject = data.get('subject')?.toString()
const message = data.get('message')?.toString()

if (!name || !email || !organization || !subject || !message) {
return fail(400, { message: 'Missing required fields' })
}

const result = await sendContactEmail({
name,
email,
organization,
subject,
message,
type: 'Partnerships'
})

if (!result.success) {
return fail(500, { message: result.message })
}

return { success: true }
},
feedback: async ({ request }) => {
const data = await request.formData()
const name = data.get('name')?.toString() || 'Anonymous'
const email = data.get('email')?.toString() || ''
const subject = data.get('subject')?.toString()
const message = data.get('message')?.toString()

if (!subject || !message) {
return fail(400, { message: 'Missing required fields' })
}

const result = await sendContactEmail({
name,
email,
subject,
message,
type: 'Feedback'
})

if (!result.success) {
return fail(500, { message: result.message })
}

return { success: true }
}
}
Loading
Loading