Skip to content

Commit

Permalink
Merge pull request #1357 from near/newsletter
Browse files Browse the repository at this point in the history
Newsletter
  • Loading branch information
gagdiez authored Jan 5, 2025
2 parents d0dd277 + d94ef78 commit 3752de4
Show file tree
Hide file tree
Showing 19 changed files with 6,617 additions and 5,428 deletions.
4 changes: 4 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,7 @@ NEXT_PUBLIC_LUMA_NEAR_HZN_CALENDAR_ID="cal-BOILOqC74o135WB"
NEXT_PUBLIC_DEVHUB_COMMUNITY_CALENDAR_ID="c_f54ed37fd92327acdc7e4343fe40722ae5797b6c82929ba93e9f3a89c69657ab@group.calendar.google.com"
NEXT_PUBLIC_LUMA_DEVHUB_HACKS_CALENDAR_ID="cal-O0HiPZ7GwczF4x0"
NEXT_PUBLIC_NEAR_TOWN_HALL_CALENDAR_ID="cal-F5SO498BSXZ6BNK"
# Mailchimp
NEXT_PUBLIC_MAILCHIMP_API_KEY=""
NEXT_PUBLIC_MAILCHIMP_REGION=""
NEXT_PUBLIC_NEWSLETTER_AUDIENCE_ID=""
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,16 +78,19 @@
"react-singleton-hook": "^3.4.0",
"rudder-sdk-js": "^2.48.6",
"styled-components": "^5.3.11",
"swr": "^2.2.5",
"typescript": "^5.4.5",
"wagmi": "^2.12.17",
"zustand": "^4.5.2"
},
"devDependencies": {
"@commitlint/cli": "^19.3.0",
"@commitlint/config-conventional": "^19.2.2",
"@mailchimp/mailchimp_marketing": "^3.0.80",
"@types/big.js": "^6.2.2",
"@types/dompurify": "^3.0.5",
"@types/lodash": "^4.17.0",
"@types/mailchimp__mailchimp_marketing": "^3.0.20",
"@types/node": "^18.19.31",
"@types/react": "^18.2.79",
"@types/react-dom": "^18.2.25",
Expand Down
11,490 changes: 6,245 additions & 5,245 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

Binary file added public/newsletter/00f47a7eee.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/newsletter/138d590a7b.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed public/newsletter/32.jpg
Binary file not shown.
Binary file removed public/newsletter/33.jpg
Binary file not shown.
Binary file removed public/newsletter/34.jpg
Binary file not shown.
Binary file removed public/newsletter/35.jpg
Binary file not shown.
Binary file removed public/newsletter/36.png
Binary file not shown.
Binary file added public/newsletter/379eb76f0f.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/newsletter/4824296aee.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/newsletter/d1bd3e0fc0.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
46 changes: 46 additions & 0 deletions src/components/scrollToTop.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { Button } from '@near-pagoda/ui';
import { useEffect, useState } from 'react';
import styled, { keyframes } from 'styled-components';

const fadeIn = keyframes`
0% {
opacity: 0;
}
100% {
opacity: 1;
}
`;

const ScrollToTopButton = styled(Button)<{ isVisible: boolean }>`
position: fixed;
bottom: 15px;
right: 30px;
cursor: pointer;
z-index: 1000;
animation: ${fadeIn} 0.5s;
`;

export default function ScrollToTop() {
const [isVisible, setIsVisible] = useState(false);

const toggleVisibility = () => {
if (window.scrollY > 300) {
setIsVisible(true);
} else {
setIsVisible(false);
}
};

const scrollToTop = () => {
window.scrollTo({
top: 0,
behavior: 'smooth',
});
};

useEffect(() => {
window.addEventListener('scroll', toggleVisibility);
}, []);

return <>{isVisible && <ScrollToTopButton label="back to top" isVisible={isVisible} onClick={scrollToTop} />}</>;
}
3 changes: 3 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ export const lumaDevHubHacksCalendarId = process.env.NEXT_PUBLIC_LUMA_DEVHUB_HAC
export const nearTownHallCalendarId = process.env.NEXT_PUBLIC_NEAR_TOWN_HALL_CALENDAR_ID ?? '';
export const googleCalendarApiKey = process.env.NEXT_PUBLIC_GOOGLE_CALENDAR_API_KEY ?? '';
export const devhubCommunityCalendarId = process.env.NEXT_PUBLIC_DEVHUB_COMMUNITY_CALENDAR_ID ?? '';
export const mailchimpApiKey = process.env.NEXT_PUBLIC_MAILCHIMP_API_KEY ?? '';
export const mailchimpRegion = process.env.NEXT_PUBLIC_MAILCHIMP_REGION ?? '';
export const mailchimpAudienceId = process.env.NEXT_PUBLIC_MAILCHIMP_AUDIENCE_ID ?? '';
export const EVMWalletChain = evmWalletChains[networkId];

export const commitModalBypassAuthorIds = (process.env.NEXT_PUBLIC_COMMIT_MODAL_BYPASS_AUTHOR_IDS ?? '')
Expand Down
29 changes: 29 additions & 0 deletions src/pages/api/newsletter/[id].ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import mailchimp from '@mailchimp/mailchimp_marketing';
import type { NextApiRequest, NextApiResponse } from 'next';

import { mailchimpApiKey, mailchimpRegion } from '../../../config';

mailchimp.setConfig({
apiKey: mailchimpApiKey,
server: mailchimpRegion,
});

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const { id } = req.query;

if (!id) {
res.status(400).json({ error: 'Missing id parameter' });
return;
}

try {
const response = await mailchimp.campaigns.getContent(id.toString());
if ('html' in response) {
res.status(200).json(response.html);
} else {
res.status(500).json({ error: 'Invalid response from Mailchimp' });
}
} catch (error) {
res.status(500).json({ error: 'error' });
}
}
29 changes: 29 additions & 0 deletions src/pages/api/newsletter/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import mailchimp from '@mailchimp/mailchimp_marketing';
import type { NextApiRequest, NextApiResponse } from 'next';

import { mailchimpApiKey, mailchimpRegion } from '../../../config';

mailchimp.setConfig({
apiKey: mailchimpApiKey,
server: mailchimpRegion,
});

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try {
const response = await mailchimp.campaigns.list({
fields: ['campaigns.settings.subject_line', 'campaigns.send_time', 'campaigns.id'],
count: 5,
status: 'sent',
sortField: 'send_time',
sortDir: 'DESC',
});

if ('campaigns' in response) {
res.status(200).json(response.campaigns);
} else {
res.status(500).json({ error: 'Failed to fetch campaigns' });
}
} catch (error) {
res.status(500).json({ error: 'error' });
}
}
37 changes: 37 additions & 0 deletions src/pages/api/newsletter/subscribe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import mailchimp from '@mailchimp/mailchimp_marketing';
import type { NextApiRequest, NextApiResponse } from 'next';

import { mailchimpApiKey, mailchimpAudienceId, mailchimpRegion } from '../../../config';

mailchimp.setConfig({
apiKey: mailchimpApiKey,
server: mailchimpRegion,
});

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method === 'POST') {
const { email } = req.body;

try {
const response = await mailchimp.lists.addListMember(mailchimpAudienceId, {
email_address: email,
status: 'pending',
});

console.log(`response: ${response}`);

// Respond to the client
res.status(200).json({
success: true,
message: 'Form submitted successfully! Please confirm your email',
});
} catch (error) {
console.error('Error adding to list:', error);

res.status(500).json({
success: false,
message: 'An error occurred while processing your request.',
});
}
}
}
Loading

0 comments on commit 3752de4

Please sign in to comment.