Skip to content

Commit 3c2ffb6

Browse files
authored
Merge pull request #3 from utmmcss/email-subscription-ui
Email subscription feature
2 parents 056e9cb + 8334fd4 commit 3c2ffb6

File tree

8 files changed

+147
-11
lines changed

8 files changed

+147
-11
lines changed

.vscode/settings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
// Fix all autofixable errors on file save
55
"editor.codeActionsOnSave": {
66
"source.fixAll": "explicit",
7-
"source.organizeImports": "never"
7+
"source.organizeImports": "always"
88
},
99
// Fix formatting issues on file save
1010
"editor.formatOnSave": true,
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
import { useState } from 'react'
2+
3+
import Alert from '@mui/material/Alert'
4+
import Box from '@mui/material/Box'
5+
import Button from '@mui/material/Button'
6+
import CircularProgress from '@mui/material/CircularProgress'
7+
import Container from '@mui/material/Container'
8+
import Snackbar from '@mui/material/Snackbar'
9+
import TextField from '@mui/material/TextField'
10+
import Typography from '@mui/material/Typography'
11+
12+
13+
const EmailSubscription = () => {
14+
const [email, setEmail] = useState('')
15+
const [loading, setLoading] = useState(false)
16+
const [success, setSuccess] = useState(false)
17+
const [error, setError] = useState('')
18+
19+
const handleSubmit = async (e: React.FormEvent) => {
20+
e.preventDefault()
21+
if (!email) return
22+
23+
setLoading(true)
24+
setError('')
25+
26+
try {
27+
const apiUrl = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8080'
28+
const response = await fetch(`${apiUrl}/api/subscribe`, {
29+
method: 'POST',
30+
headers: {
31+
'Content-Type': 'application/json',
32+
},
33+
body: JSON.stringify({ email }),
34+
})
35+
36+
if (!response.ok) {
37+
throw new Error('Subscription failed')
38+
}
39+
40+
setSuccess(true)
41+
setEmail('')
42+
} catch (err) {
43+
setError('Something went wrong. Please try again.')
44+
} finally {
45+
setLoading(false)
46+
}
47+
}
48+
49+
return (
50+
<Container id="subscription" sx={{ py: 8, textAlign: 'center' }}>
51+
<Box
52+
// @ts-ignore
53+
sx={{
54+
background: 'rgba(255, 255, 255, 0.05)',
55+
backdropFilter: 'blur(10px)',
56+
borderRadius: 4,
57+
p: { xs: 3, md: 6 },
58+
maxWidth: 'md',
59+
mx: 'auto',
60+
border: '1px solid rgba(255, 255, 255, 0.1)',
61+
}}
62+
data-aos="fade-up"
63+
>
64+
<Typography variant="h3" gutterBottom color="text.primary" sx={{ fontWeight: 'bold' }}>
65+
Stay in the Loop
66+
</Typography>
67+
<Typography variant="body1" color="text.secondary" sx={{ mb: 4 }}>
68+
Subscribe to our newsletter for the latest updates, announcements, and opportunities!
69+
</Typography>
70+
71+
<Box
72+
component="form"
73+
onSubmit={handleSubmit}
74+
sx={{
75+
display: 'flex',
76+
flexDirection: { xs: 'column', sm: 'row' },
77+
gap: 2,
78+
justifyContent: 'center',
79+
alignItems: 'center',
80+
}}
81+
>
82+
<TextField
83+
variant="outlined"
84+
placeholder="Enter your email"
85+
type="email"
86+
value={email}
87+
onChange={(e) => setEmail(e.target.value)}
88+
required
89+
fullWidth
90+
sx={{
91+
maxWidth: 400,
92+
'& .MuiOutlinedInput-root': {
93+
bgcolor: 'background.paper',
94+
borderRadius: 2,
95+
},
96+
}}
97+
/>
98+
<Button
99+
variant="contained"
100+
size="large"
101+
type="submit"
102+
disabled={loading}
103+
sx={{
104+
borderRadius: 2,
105+
px: 4,
106+
py: 1.8,
107+
background: 'linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)',
108+
color: 'white',
109+
fontWeight: 'bold',
110+
boxShadow: '0 3px 5px 2px rgba(255, 105, 135, .3)',
111+
'&:hover': {
112+
background: 'linear-gradient(45deg, #FE6B8B 60%, #FF8E53 90%)',
113+
},
114+
}}
115+
>
116+
{loading ? <CircularProgress size={24} color="inherit" /> : 'Subscribe'}
117+
</Button>
118+
</Box>
119+
</Box>
120+
121+
<Snackbar open={success} autoHideDuration={6000} onClose={() => setSuccess(false)}>
122+
<Alert onClose={() => setSuccess(false)} severity="success" sx={{ width: '100%' }}>
123+
Successfully subscribed! Check your inbox for a welcome email.
124+
</Alert>
125+
</Snackbar>
126+
<Snackbar open={!!error} autoHideDuration={6000} onClose={() => setError('')}>
127+
<Alert onClose={() => setError('')} severity="error" sx={{ width: '100%' }}>
128+
{error}
129+
</Alert>
130+
</Snackbar>
131+
</Container>
132+
)
133+
}
134+
135+
export default EmailSubscription

components/HomePage/Navbar/index.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,9 @@ const Menu = (props: MenuProps) => {
5555
{!toggles.dashboard && (
5656
<>
5757
<Box component="div" data-aos="fade" data-aos-delay="1000" data-aos-duration="1000">
58-
<Tooltip title="DeerHacks 2024">
59-
<Link rel="noopener" href="https://2024.deerhacks.ca">
60-
2024
58+
<Tooltip title="DeerHacks 2025">
59+
<Link rel="noopener" href="https://2025.deerhacks.ca">
60+
2025
6161
</Link>
6262
</Tooltip>
6363
</Box>

components/Shared/DeerHacksCollage/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ const DeerHacksCollage = () => {
33
<svg width="100%" viewBox="0 0 850 252" fill="none" xmlns="http://www.w3.org/2000/svg">
44
<desc>
55
Collage created by Anthony Tedja https://github.com/anthonytedja for the intended use of
6-
DeerHacks 2024
6+
DeerHacks 2025
77
</desc>
88
<g clipPath="url(#clip0_463_16292)">
99
<path

components/Shared/DeerHacksTitle/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ const DeerHacksTitle = () => {
33
<svg width="100%" viewBox="0 0 1248 126" fill="none" xmlns="http://www.w3.org/2000/svg">
44
<desc>
55
Collage created by Anthony Tedja https://github.com/anthonytedja for the intended use of
6-
DeerHacks 2024
6+
DeerHacks 2025
77
</desc>
88
<g clipPath="url(#clip0_425_65)">
99
<path

components/Shared/Footer/index.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@ const Footer = () => {
2323
alignItems="center"
2424
flexWrap="wrap"
2525
>
26-
<Typography color="text.primary">DeerHacks © 2025</Typography>
27-
<Tooltip title="DeerHacks 2024" placement="top">
28-
<Link rel="noopener" href="https://2024.deerhacks.ca">
29-
2024
26+
<Typography color="text.primary">DeerHacks © 2026</Typography>
27+
<Tooltip title="DeerHacks 2025" placement="top">
28+
<Link rel="noopener" href="https://2025.deerhacks.ca">
29+
2025
3030
</Link>
3131
</Tooltip>
3232
<Tooltip title="Instagram" placement="top">

pages/dashboard/index.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import Grid from '@mui/material/Grid'
88

99
import TileChecklist from '@/components/Dashboard/TileChecklist'
1010
import TileDevpost from '@/components/Dashboard/TileDevpost'
11-
import TileGallery from '@/components/Dashboard/TileGallery'
1211
import TileHackerPack from '@/components/Dashboard/TileHackerPack'
1312
import TileInstagram from '@/components/Dashboard/TileInstagram'
1413
import TileLinkedIn from '@/components/Dashboard/TileLinkedIn'

pages/index.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import Slide from '@mui/material/Slide'
77
import Typography from '@mui/material/Typography'
88

99
import About from '@/components/HomePage/About'
10+
import EmailSubscription from '@/components/HomePage/EmailSubscription'
1011
import FAQ from '@/components/HomePage/FAQ'
1112
import MNModel from '@/components/HomePage/MNModel'
1213
import Navbar from '@/components/HomePage/Navbar'
@@ -100,6 +101,7 @@ const HomePage = () => {
100101
<About />
101102
<Stats />
102103
<Sponsors />
104+
<EmailSubscription />
103105
{/* <Container>
104106
<TileGallery resize />
105107
</Container> */}

0 commit comments

Comments
 (0)