Skip to content

Commit 1014650

Browse files
author
Alexia Michelle
committed
newsletter implementation
1 parent b859fcd commit 1014650

4 files changed

Lines changed: 266 additions & 0 deletions

File tree

i18n/es/docusaurus-plugin-content-pages/community.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
¡Únete a la comunidad!
44

5+
import NewsletterForm from '@site/src/components/NewsletterForm';
6+
7+
<NewsletterForm />
8+
59
## Canales
610
* **IRC**: irc.libera.chat #goldendog (puenteado con Discord)
711
* **Discord**: [Únete](https://goldendoglinux.org/discord)
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
import React, { useState } from 'react';
2+
import styles from './styles.module.css';
3+
import Translate from '@docusaurus/Translate';
4+
5+
export default function NewsletterForm() {
6+
const [email, setEmail] = useState('');
7+
const [selectedLists, setSelectedLists] = useState({
8+
news: true,
9+
security: false,
10+
});
11+
const [status, setStatus] = useState('idle'); // idle, loading, success, error
12+
const [message, setMessage] = useState('');
13+
14+
const lists = {
15+
news: {
16+
uuid: '90163d3c-64bb-4910-aa3e-dd71e0944cf6',
17+
label: <Translate id="newsletter.list.news">General News</Translate>,
18+
},
19+
security: {
20+
uuid: '57977cb6-60a6-465b-98f0-0b626847ed0d',
21+
label: <Translate id="newsletter.list.security">Security Updates</Translate>,
22+
},
23+
};
24+
25+
const handleCheckboxChange = (listKey) => {
26+
setSelectedLists((prev) => ({
27+
...prev,
28+
[listKey]: !prev[listKey],
29+
}));
30+
};
31+
32+
const handleSubmit = async (e) => {
33+
e.preventDefault();
34+
35+
const uuids = Object.keys(selectedLists)
36+
.filter((key) => selectedLists[key])
37+
.map((key) => lists[key].uuid);
38+
39+
if (uuids.length === 0) {
40+
setStatus('error');
41+
setMessage('Please select at least one list.');
42+
return;
43+
}
44+
45+
setStatus('loading');
46+
47+
try {
48+
const response = await fetch('https://lists.goldendoglinux.org/api/public/subscription', {
49+
method: 'POST',
50+
headers: {
51+
'Content-Type': 'application/json',
52+
},
53+
body: JSON.stringify({
54+
email: email,
55+
name: '',
56+
list_uuids: uuids,
57+
confirm: true,
58+
}),
59+
});
60+
61+
if (response.ok) {
62+
setStatus('success');
63+
setEmail('');
64+
setMessage('Thanks for subscribing! Please check your email to confirm.');
65+
} else {
66+
const data = await response.json();
67+
setStatus('error');
68+
setMessage(data.message || 'Something went wrong. Please try again.');
69+
}
70+
} catch (err) {
71+
setStatus('error');
72+
setMessage('Failed to connect to the subscription service. Please check your connection or CORS settings.');
73+
}
74+
};
75+
76+
return (
77+
<div className={styles.newsletterContainer}>
78+
<div className={styles.newsletterCard}>
79+
<h3>
80+
<Translate id="newsletter.title">Join our Newsletter</Translate>
81+
</h3>
82+
<p>
83+
<Translate id="newsletter.description">
84+
Stay updated with the latest releases, security updates, and community news.
85+
</Translate>
86+
</p>
87+
<form onSubmit={handleSubmit} className={styles.form}>
88+
<div className={styles.inputGroup}>
89+
<input
90+
type="email"
91+
placeholder="your@email.com"
92+
value={email}
93+
onChange={(e) => setEmail(e.target.value)}
94+
required
95+
className={styles.input}
96+
disabled={status === 'loading' || status === 'success'}
97+
/>
98+
<button
99+
type="submit"
100+
className={styles.button}
101+
disabled={status === 'loading' || status === 'success'}
102+
>
103+
{status === 'loading' ? (
104+
<Translate id="newsletter.loading">Subscribing...</Translate>
105+
) : status === 'success' ? (
106+
<Translate id="newsletter.success">Done!</Translate>
107+
) : (
108+
<Translate id="newsletter.button">Subscribe</Translate>
109+
)}
110+
</button>
111+
</div>
112+
<div className={styles.checkboxGroup}>
113+
{Object.keys(lists).map((key) => (
114+
<label key={key} className={styles.checkboxLabel}>
115+
<input
116+
type="checkbox"
117+
checked={selectedLists[key]}
118+
onChange={() => handleCheckboxChange(key)}
119+
disabled={status === 'loading' || status === 'success'}
120+
/>
121+
<span className={styles.checkboxText}>{lists[key].label}</span>
122+
</label>
123+
))}
124+
</div>
125+
</form>
126+
{message && (
127+
<p className={status === 'error' ? styles.errorMessage : styles.successMessage}>
128+
{message}
129+
</p>
130+
)}
131+
</div>
132+
</div>
133+
);
134+
}
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
.newsletterContainer {
2+
margin: 2rem 0;
3+
display: flex;
4+
justify-content: center;
5+
}
6+
7+
.newsletterCard {
8+
background: rgba(255, 255, 255, 0.05);
9+
backdrop-filter: blur(10px);
10+
border: 1px solid rgba(255, 255, 255, 0.1);
11+
border-radius: 12px;
12+
padding: 2rem;
13+
width: 100%;
14+
max-width: 500px;
15+
text-align: center;
16+
box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.37);
17+
}
18+
19+
.newsletterCard h3 {
20+
margin-top: 0;
21+
color: var(--ifm-color-primary);
22+
font-size: 1.5rem;
23+
}
24+
25+
.newsletterCard p {
26+
color: var(--ifm-font-color-base);
27+
opacity: 0.8;
28+
margin-bottom: 1.5rem;
29+
}
30+
31+
.form {
32+
display: flex;
33+
flex-direction: column;
34+
gap: 1rem;
35+
}
36+
37+
.inputGroup {
38+
display: flex;
39+
gap: 0.5rem;
40+
}
41+
42+
.input {
43+
flex: 1;
44+
padding: 0.75rem 1rem;
45+
border-radius: 8px;
46+
border: 1px solid rgba(255, 255, 255, 0.2);
47+
background: rgba(0, 0, 0, 0.2);
48+
color: white;
49+
font-size: 1rem;
50+
outline: none;
51+
transition: border-color 0.2s;
52+
}
53+
54+
.input:focus {
55+
border-color: var(--ifm-color-primary);
56+
}
57+
58+
.button {
59+
padding: 0.75rem 1.5rem;
60+
border-radius: 8px;
61+
border: none;
62+
background: var(--ifm-color-primary);
63+
color: white;
64+
font-weight: bold;
65+
cursor: pointer;
66+
transition: filter 0.2s, transform 0.1s;
67+
}
68+
69+
.button:hover:not(:disabled) {
70+
filter: brightness(1.1);
71+
}
72+
73+
.button:active:not(:disabled) {
74+
transform: scale(0.98);
75+
}
76+
77+
.button:disabled {
78+
opacity: 0.6;
79+
cursor: not-allowed;
80+
}
81+
82+
.checkboxGroup {
83+
display: flex;
84+
justify-content: center;
85+
gap: 1.5rem;
86+
flex-wrap: wrap;
87+
}
88+
89+
.checkboxLabel {
90+
display: flex;
91+
align-items: center;
92+
gap: 0.5rem;
93+
cursor: pointer;
94+
font-size: 0.9rem;
95+
opacity: 0.9;
96+
transition: opacity 0.2s;
97+
}
98+
99+
.checkboxLabel:hover {
100+
opacity: 1;
101+
}
102+
103+
.checkboxLabel input {
104+
cursor: pointer;
105+
accent-color: var(--ifm-color-primary);
106+
}
107+
108+
.successMessage {
109+
margin-top: 1rem;
110+
color: #4caf50;
111+
font-weight: 500;
112+
}
113+
114+
.errorMessage {
115+
margin-top: 1rem;
116+
color: #f44336;
117+
font-weight: 500;
118+
}
119+
120+
@media (max-width: 600px) {
121+
.inputGroup {
122+
flex-direction: column;
123+
}
124+
}

src/pages/community.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
Join the community!
44

5+
import NewsletterForm from '@site/src/components/NewsletterForm';
6+
7+
<NewsletterForm />
8+
59
## Channels
610
* **IRC**: irc.libera.chat #goldendoglinux (bridged to Discord)
711
* **Discord**: [Join us](https://goldendoglinux.org/discord)

0 commit comments

Comments
 (0)