Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Make Contact Us Form Functional #245

Merged
merged 10 commits into from
Feb 25, 2025
Merged
1 change: 1 addition & 0 deletions .env.local.example
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,4 @@ SMTP_HOST=
SMTP_USER=
SMTP_PASS=
SMTP_EMAIL_ADDRESS=
CONTACT_EMAIL_ADDRESS=
26 changes: 26 additions & 0 deletions src/app/api/contact/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { sendContactEmail } from '@/server/send-contact-email';
import { z } from 'zod';

export async function POST(request: Request) {
try {
const req = await request.json();

const schema = z.object({
fullName: z.string().min(1),
email: z.string().email().min(1),
message: z.string().min(1),
});

const reqBody = schema.safeParse(req);

if (!reqBody.success) {
return new Response(JSON.stringify(reqBody.error.format()), { status: 400 });
}

await sendContactEmail(reqBody.data.fullName, reqBody.data.email, reqBody.data.message);

return new Response(JSON.stringify({ success: true }), { status: 200 });
} catch {
return new Response(JSON.stringify({ error: 'Internal Server Error' }), { status: 500 });
}
}
29 changes: 25 additions & 4 deletions src/app/contact/Form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,28 @@
import Button from '@/components/Button';
import Duck from '@/components/Duck';
import { createSubmit } from 'just-submit';
import ky from 'ky';
import { useState } from 'react';

export default function Form({ className }: { className?: string }) {
const [submitInfo, setSubmitInfo] = useState('');
const [isSuccess, setIsSuccess] = useState(false);
const submit = createSubmit({ fullName: 'string', email: 'string', message: 'string' });
const handleSubmit = submit((data) => {
// TODO(#31): Email integration
console.log(data);
const handleSubmit = submit(async (data) => {
const response = await ky.post('/api/contact', {
json: data,
});
if (response.ok) {
setSubmitInfo('Message sent successfully!');
setIsSuccess(true);
} else {
setSubmitInfo('Failed to send message. Please try again.');
setIsSuccess(false);
}
setTimeout(() => {
setSubmitInfo('');
}, 5000);
});

return (
<div className={`${className} relative`}>
<div className="absolute right-[25px] top-[-48px] hidden gap-6 md:flex">
Expand Down Expand Up @@ -49,6 +63,13 @@ export default function Form({ className }: { className?: string }) {
Submit
</Button>
</div>
{submitInfo && (
<div
className={`col-span-2 text-center ${isSuccess ? 'text-green-500' : 'text-red-500'}`}
>
{submitInfo}
</div>
)}
</form>
</div>
);
Expand Down
43 changes: 22 additions & 21 deletions src/emails/body.tsx → src/emails/Body.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Img } from '@react-email/components';
import { Img, Container } from '@react-email/components';
import * as React from 'react';

export interface BodyProps {
Expand All @@ -7,7 +7,7 @@ export interface BodyProps {

export default function EmailBody({ firstName }: BodyProps) {
return (
<div>
<Container>
<picture>
<source
srcSet="https://csclub.org.au/images/email/light/welcome.png"
Expand All @@ -30,7 +30,7 @@ export default function EmailBody({ firstName }: BodyProps) {
<h2>{'>'}</h2>
</td>
<td>
<h2>Welcome, {firstName}!</h2>
<h2>{`Welcome, ${firstName}!`}</h2>
<div className="border-t-0.5 dynamicBorder h-0.5 w-full border-x-0 border-b-0 border-solid"></div>
</td>
</tr>
Expand All @@ -46,19 +46,19 @@ export default function EmailBody({ firstName }: BodyProps) {
</p>
<p>
The best way to keep up to date on what’s happening in our club is through our
Discord server, social media accounts, and our{' '}
Discord server, social media accounts, and our&nbsp;
<a href="https://csclub.org.au" className="font-bold text-orange underline">
website
</a>
! If you haven’t seen a{' '}
! If you haven’t seen a&nbsp;
<a
href="https://csclub.org.au/about#committee"
className="font-bold text-purple underline"
>
committee member
</a>{' '}
about your sign-up yet, please pop in to the Duck Lounge (Engineering and Maths
EM110) to get your cool ducky sticker for your uni ID card & verify your
</a>
&nbsp;about your sign-up yet, please pop in to the Duck Lounge (Engineering and
Maths EM110) to get your cool ducky sticker for your uni ID card & verify your
membership payment!.
</p>
<p>And of course, we hope to see you at our events and meet you very soon!</p>
Expand Down Expand Up @@ -89,10 +89,10 @@ export default function EmailBody({ firstName }: BodyProps) {
<p>
There’s socialising, gaming, and of course if you have any
questions with CS-related subjects, you’re bound to find someone
who can help you!{' '}
who can help you!&nbsp;
</p>
<p>
If you’re having trouble finding the room,{' '}
If you’re having trouble finding the room,&nbsp;
<a
href="https://studentvip.com.au/adelaide-uni/north-terrace/maps/127019"
className="font-bold text-orange underline"
Expand Down Expand Up @@ -175,7 +175,7 @@ export default function EmailBody({ firstName }: BodyProps) {
</tr>
<tr>
<p className="mx-6 pb-2">
We hold <strong>Weekly Games Nights</strong> every{' '}
We hold <strong>Weekly Games Nights</strong> every&nbsp;
<strong>Friday</strong> in the Duck lounge! Our other events are
always posted on our social media and in our Discord server, so
be sure to be on a lookout for those announcements!
Expand All @@ -192,14 +192,14 @@ export default function EmailBody({ firstName }: BodyProps) {
<p className="mx-6 pb-2">
Our Club OneDrive consists of past exams, notes and other
materials with Computer Science related subjects to help you fly
through exams! Log into our{' '}
through exams! Log into our&nbsp;
<a
href="https://csclub.org.au"
className="font-bold text-orange underline"
>
website
</a>{' '}
to access or{' '}
</a>
&nbsp;to access or&nbsp;
<a
href={process.env.NEXT_PUBLIC_DRIVE_LINK}
className="font-bold text-purple underline"
Expand All @@ -221,14 +221,14 @@ export default function EmailBody({ firstName }: BodyProps) {
<p className="mx-6 pb-2">
Our Club OneDrive consists of past exams, notes and other
materials with Computer Science related subjects to help you fly
through exams! Log into our{' '}
through exams! Log into our&nbsp;
<a
href="https://csclub.org.au"
className="font-bold text-orange underline"
>
website
</a>{' '}
to access or{' '}
</a>
&nbsp;to access or&nbsp;
<a
href="https://csclub.org.au"
className="font-bold text-purple underline"
Expand All @@ -241,25 +241,26 @@ export default function EmailBody({ firstName }: BodyProps) {
</td>
</tr>
</table>

<div className="mb-4 text-center text-grey dark:text-white">
<h2>Contacts</h2>
<div className="border-t-0.5 dynamicBorder mx-auto mb-6 h-0.5 w-1/3 border-x-0 border-b-0 border-solid"></div>
<p>
If you need any help, hop on Discord and DM any of the{' '}
If you need any help, hop on Discord and DM any of the&nbsp;
<a
href="https://csclub.org.au/about#committee"
className="font-bold text-purple underline"
>
committee
</a>{' '}
members, or...
</a>
&nbsp;members, or...
</p>
<a href="mailto:[email protected]">
<button className="border-t-0.5 dynamicBorder mt-2 rounded-2xl border-[3px] border-solid bg-yellow px-10 py-2 text-base font-bold text-grey">
Send an email!
</button>
</a>
</div>
</div>
</Container>
);
}
Loading