Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
c3df639
Judge invites!
ReehalS Feb 26, 2026
302ee39
Linty lint
ReehalS Feb 26, 2026
f4d2371
Fix image URL and error handling for sending emails
ReehalS Feb 26, 2026
2ee04c4
Document browser preview csv parser
ReehalS Feb 26, 2026
47aef86
Throw error for missing email ENV vars
ReehalS Feb 26, 2026
3e88930
Single mentor invite
ReehalS Feb 26, 2026
b8ae04b
Bulk mentor invites and modify invites page
ReehalS Feb 26, 2026
e08f6fa
New format bulk mentor invites
ReehalS Feb 26, 2026
9b2ef1d
Lint fixes
ReehalS Feb 27, 2026
fd07861
Single mentor invite
ReehalS Feb 26, 2026
4e25ab9
Bulk mentor invites and modify invites page
ReehalS Feb 26, 2026
e0aaf45
New format bulk mentor invites
ReehalS Feb 26, 2026
fd85880
Lint fixes
ReehalS Feb 27, 2026
458d2db
Merge branch '376-mentor-email-invites' of https://github.com/HackDav…
ReehalS Mar 3, 2026
a4fc269
Revert "Merge branch '376-mentor-email-invites' of https://github.com…
ReehalS Mar 3, 2026
40ce0dd
Move mentor invites to new folder and add vars
ReehalS Mar 3, 2026
2000a1a
Create InviteCSV parsing test
ReehalS Mar 3, 2026
8862474
Update email subject
ReehalS Mar 3, 2026
6306c93
Update sendSingleMentorInvite.ts
ReehalS Mar 3, 2026
7b63f33
Update sendBulkMentorInvites.ts
ReehalS Mar 3, 2026
013f33a
Move EMAIL_SUBJECT to be common rather than redefined for each file
ReehalS Mar 3, 2026
9162ee5
Move Judge+Mentor bulk invite creation to new processing pipeline
ReehalS Mar 3, 2026
c68ffdd
Add tests for Limiter and processBulkInvites
ReehalS Mar 3, 2026
4ab3a49
Merge branch 'main' of https://github.com/HackDavis/hackdavis-hub int…
michelleyeoh Mar 8, 2026
2471768
fixed mentor template
michelleyeoh Mar 8, 2026
6e0edb7
redo mentor and judge email design
michelleyeoh Mar 14, 2026
f173ff6
extract consts
michelleyeoh Mar 14, 2026
28a286b
cleaned console
michelleyeoh Mar 14, 2026
8a15887
update workflow env vars
michelleyeoh Mar 14, 2026
e973aca
added comment to new file
michelleyeoh Mar 14, 2026
0fa1cee
Merge branch 'main' into 376-mentor-email-invites
michelleyeoh Mar 14, 2026
02745ac
Merge branch 'main' of https://github.com/HackDavis/hackdavis-hub int…
michelleyeoh Mar 14, 2026
89258df
update error msg
michelleyeoh Mar 14, 2026
e706ad6
Merge branch '376-mentor-email-invites' of https://github.com/HackDav…
michelleyeoh Mar 14, 2026
419bfc9
fix extra bracket
michelleyeoh Mar 14, 2026
1aae2a4
added error message for safe handling
michelleyeoh Mar 14, 2026
f7b7649
Merge branch '376-mentor-email-invites' of https://github.com/HackDav…
michelleyeoh Mar 14, 2026
23f6f95
small mentor email template fix
michelleyeoh Mar 14, 2026
c33516d
Merge branch '449-create-individual-judge-hacker-hub-invite' of https…
michelleyeoh Mar 14, 2026
684dbc8
added emergency invite
michelleyeoh Mar 14, 2026
4ca8019
template html fix
michelleyeoh Mar 14, 2026
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
50 changes: 50 additions & 0 deletions app/(api)/_actions/emails/emailTemplates/forgotPasswordTemplate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
export default function forgotPasswordTemplate(link: string) {
const HEADER_IMAGE_URL = `${process.env.BASE_URL}/email/2025_email_header.png`;
return `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Reset your HackDavis Hub Password</title>
<style>
body { margin: 0; padding: 0; font-family: 'DM Mono', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; background-color: #ffffff; }
.container { max-width: 600px; margin: 0 auto; background-color: #ffffff; }
.header-image { width: 100%; height: auto; display: block; }
.title { text-align: center; font-size: 28px; font-weight: bold; margin: 30px 0; color: #000000; }
.content-box { background-color: #ffffff; margin: 20px 0; }
.content-box p { font-size: 16px; line-height: 1.5; color: #222222; margin: 0 0 16px 0; }
.content-box a { color: #0061FE; text-decoration: none; }
.content-box a:hover { text-decoration: underline; }
.content-box ul { margin: 16px 0; padding-left: 20px; }
.content-box li { font-size: 16px; line-height: 1.6; color: #222222; margin-bottom: 12px; }
.content-box ul ul { margin-top: 8px; }
.content-box p.special-note { font-size: 14px; color: #8d9ca2; }
.bordered-section { border-width: 2px; border-style: solid; border-color: #e5e5e5; border-radius: 5px; padding: 12px 24px; margin: 16px 0; }
.bold { font-weight: bold; }
.divider { height: 2px; background-color: #F2F2F2; margin: 40px 0; }
.footer-image { width: 100%; height: auto; display: block; margin-top: 20px; }
@media only screen and (max-width: 600px) {
.content-box { padding: 24px; margin: 10px; }
.title { font-size: 24px; margin: 20px 0; }
}
</style>
</head>
<body>
<div class="container">
<img src="${HEADER_IMAGE_URL}" alt="HackDavis 2025 header" class="header-image">
<h1 class="title">
<span style="color: #173a52;">Reset your HackDavis Hub Password</span>
</h1>
<div class="divider"></div>
<div class="content-box">
<p>Click the link below to reset your password for the HackDavis Hub. This link expires in 24 hours. Do <span class="bold">NOT</span> share this link with anyone.</p>
<p ><a href="${link}" style="font-size: 14px;">${link}</a></p>
<p class="special-note">If you didn't request to reset your password, you can safely ignore this email.</p>
</div>
</div>
</body>
</html>
`;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
export default function hubEmergencyInviteTemplate(link: string) {
const HEADER_IMAGE_URL = `${process.env.BASE_URL}/email/2025_email_header.png`;
return `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>HackDavis Hub Invite Link</title>
<style>
body { margin: 0; padding: 0; font-family: 'DM Mono', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; background-color: #ffffff; }
.container { max-width: 600px; margin: 0 auto; background-color: #ffffff; }
.header-image { width: 100%; height: auto; display: block; }
.title { text-align: center; font-size: 28px; font-weight: bold; margin: 30px 0; color: #000000; }
.content-box { background-color: #ffffff; margin: 20px 0; }
.content-box p { font-size: 16px; line-height: 1.5; color: #222222; margin: 0 0 16px 0; }
.content-box a { color: #0061FE; text-decoration: none; }
.content-box a:hover { text-decoration: underline; }
.content-box ul { margin: 16px 0; padding-left: 20px; }
.content-box li { font-size: 16px; line-height: 1.6; color: #222222; margin-bottom: 12px; }
.content-box ul ul { margin-top: 8px; }
.content-box p.special-note { font-size: 14px; color: #8d9ca2; }
.bordered-section { border-width: 2px; border-style: solid; border-color: #e5e5e5; border-radius: 5px; padding: 12px 24px; margin: 16px 0; }
.bold { font-weight: bold; }
.divider { height: 2px; background-color: #F2F2F2; margin: 40px 0; }
.footer-image { width: 100%; height: auto; display: block; margin-top: 20px; }
@media only screen and (max-width: 600px) {
.content-box { padding: 24px; margin: 10px; }
.title { font-size: 24px; margin: 20px 0; }
}
</style>
</head>
<body>
<div class="container">
<img src="${HEADER_IMAGE_URL}" alt="HackDavis 2025 header" class="header-image">
<h1 class="title">
<span style="color: #173a52;">Invitation to the </span>
<span style="color: #57dade;">HackDavis Hub</span>
</h1>
<div class="divider"></div>
<div class="content-box">
<p>Click the link below to create your account on the HackDavis Hub. Do <span class="bold">NOT</span> share this unique invite link with anyone.</p>
<p><a href="${link}" style="font-size: 14px;">${link}</a></p>
</div>
</div>
</body>
</html>
`;
}
166 changes: 6 additions & 160 deletions app/(api)/_actions/invite/emailMessage.ts
Original file line number Diff line number Diff line change
@@ -1,162 +1,8 @@
export default function emailMessage(type: string, link: string) {
const inviteMsg = `
<!DOCTYPE html>
<html>
<head>
<title>HackDavis Hub Invite Link</title>
<style>
* {
box-sizing: border-box;
text-decoration: none;
}

.container {
background-color: #E5EEF1;
width: 100%;
padding: 48px;
}

.welcome-text {
color: black;
font-size: 1.5rem;
font-weight: 700;
font-family: 'Helvetica';
}

.make-account {
color: black;
font-family: 'Helvetica';
margin-bottom: 30px;
}

span {
font-weight: 700;
}

.button {
border: none;
border-radius: 4px;
padding: 12px;
background-color: #FFC53D;
font-weight: 500;
font-size: 1.25rem;
cursor: pointer;
text-align: center;
text-decoration: none;
font-family: 'Helvetica';
}

.sub-container {
margin-top: 30px;
}

.bottom-text {
font-family: 'Helvetica';
}

.link {
color: blue;
font-family: 'Helvetica';
text-decoration: underline;
}

</style>
</head>
<body>
<div class="container">
<h3 class="welcome-text">Invitation to the HackDavis Hub</h3>
<p class="make-account">
Click the button below to create your account on the HackDavis Hub. This link expires in 14 days. Do <span>NOT</span> share this unique invite link with anyone.
</p>
<a class="button" href="${link}">Register</a>
<div class="sub-container">
<p class="bottom-text">If you're having trouble with the above button, copy and paste the following link into your browser:</p>
<p class="link">${link}</p>
</div>
</div>
</body>
</html>
`;

const resetMsg = `
<!DOCTYPE html>
<html>
<head>
<title>HackDavis Hub Reset Password Link</title>
<style>
* {
box-sizing: border-box;
text-decoration: none;
}

.container {
background-color: #E5EEF1;
width: 100%;
padding: 48px;
}

.welcome-text {
color: black;
font-size: 1.5rem;
font-weight: 700;
font-family: 'Helvetica';
}
import forgotPasswordTemplate from '../emails/emailTemplates/forgotPasswordTemplate';
import hubEmergencyInviteTemplate from '../emails/emailTemplates/hubEmergencyInviteTemplate';

.make-account {
color: black;
font-family: 'Helvetica';
margin-bottom: 30px;
}

span {
font-weight: 700;
}

.button {
border: none;
border-radius: 4px;
padding: 12px;
background-color: #FFC53D;
font-weight: 500;
font-size: 1.25rem;
color: #173a52;
cursor: pointer;
text-align: center;
text-decoration: none;
font-family: 'Helvetica';
}

.sub-container {
margin-top: 30px;
}

.bottom-text {
font-family: 'Helvetica';
}

.link {
color: blue;
font-family: 'Helvetica';
text-decoration: underline;
}

</style>
</head>
<body>
<div class="container">
<h3 class="welcome-text">Reset Password Link for the HackDavis Hub</h3>
<p class="make-account">
Click the button below to reset your password for the HackDavis Hub. This link expires in 24 hours. Do <span>NOT</span> share this link with anyone. If you didn't request a password reset, you can safely ignore this email.
</p>
<a class="button" href="${link}">Reset Password</a>
<div class="sub-container">
<p class="bottom-text">If you're having trouble with the above button, copy and paste the following link into your browser:</p>
<p class="link">${link}</p>
</div>
</div>
</body>
</html>
`;

return type === 'invite' ? inviteMsg : resetMsg;
export default function emailMessage(type: string, link: string) {
return type === 'invite'
? hubEmergencyInviteTemplate(link)
: forgotPasswordTemplate(link);
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export default function InviteLinkForm() {
return (
<>
<form onSubmit={handleInvite} className={styles.form}>
<h3>Invite a User [to be deprecated & replaced]</h3>
<h3>Invite a User</h3>
<div className={styles.fields}>
<p className={styles.error_msg}>{error}</p>
<div>
Expand Down
4 changes: 2 additions & 2 deletions app/(pages)/admin/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ const action_links = [
body: 'Invites',
},
{
href: '/admin/invite-hackers',
body: 'Invite Hackers',
href: '/admin/emergency-invites',
body: 'Emergency Invites (hackers & judges)',
},
{
href: '/admin/randomize-projects',
Expand Down
Loading