Skip to content

Commit 80ad698

Browse files
authored
Merge pull request #41 from whysosaket/newsletter
Newsletter
2 parents 8e9b3ed + 5bbdef4 commit 80ad698

11 files changed

+1108
-155
lines changed

Diff for: my-app/package-lock.json

+867-91
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: my-app/package.json

+4-1
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,19 @@
1111
},
1212
"dependencies": {
1313
"@headlessui/react": "^2.1.8",
14+
"@wojtekmaj/react-hooks": "^1.21.0",
1415
"framer-motion": "^11.5.6",
1516
"react": "^18.3.1",
1617
"react-dom": "^18.3.1",
1718
"react-helmet": "^6.1.0",
1819
"react-icons": "^5.3.0",
20+
"react-pdf": "^9.1.1",
1921
"react-router-dom": "^6.26.2",
2022
"react-secure-storage": "^1.3.2",
2123
"react-slick": "^0.30.2",
2224
"slick-carousel": "^1.8.1",
23-
"toastify-js": "^1.12.0"
25+
"toastify-js": "^1.12.0",
26+
"vite-plugin-static-copy": "^1.0.6"
2427
},
2528
"devDependencies": {
2629
"@eslint/js": "^9.9.0",

Diff for: my-app/public/Newsletter.pdf

3.47 MB
Binary file not shown.

Diff for: my-app/src/App.jsx

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import Events from "./pages/Events";
88
import Base from "./layouts/Base";
99
import Subscribe from "./components/Subscribe";
1010
import { useState } from "react";
11+
import NewsletterPage from "./pages/NewsletterPage";
1112

1213
export default function App() {
1314
const [isVisible, setIsVisible] = useState(false);
@@ -27,6 +28,7 @@ export default function App() {
2728
<Route path="/community" element={<Community />} />
2829
<Route path="/events" element={<Events />} />
2930
<Route path="/contact-us" element={<ContactForm />} />
31+
<Route path="/newsletter" element={<NewsletterPage />} />
3032
<Route path="*" element={<NotFound />} />
3133
</Routes>
3234
</Base>

Diff for: my-app/src/data.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ const navigation = [
22
{ name: "Home", to: "/" },
33
{ name: "Community", to: "/community" },
44
{ name: "Events", to: "/events" },
5+
{ name: "Newsletter", to: "/newsletter" },
56
{ name: "About us", to: "about-us" },
6-
{ name: "Contact us", to: "/contact-us" },
77
];
88
export { navigation };

Diff for: my-app/src/pages/Community.jsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -288,8 +288,8 @@ export default function Community() {
288288
"w-full rounded-lg py-2.5 text-sm font-medium leading-5 text-blue-700",
289289
"ring-white ring-opacity-60 ring-offset-2 ring-offset-blue-400 focus:outline-none",
290290
selected
291-
? "bg-white shadow"
292-
: "text-blue-100 hover:bg-white/[0.12] hover:text-white"
291+
? "bg-white shadow "
292+
: "text-white hover:bg-white/[0.12] hover:text-blue-100"
293293
)
294294
}
295295
>

Diff for: my-app/src/pages/Events.jsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ export default function Events() {
170170
"ring-white ring-opacity-60 ring-offset-2 ring-offset-blue-400 focus:outline-none",
171171
selected
172172
? "bg-white shadow"
173-
: "text-blue-100 hover:bg-white/[0.12] hover:text-white"
173+
: " text-white hover:bg-white/[0.12] hover:text-blue-100"
174174
)
175175
}
176176
>

Diff for: my-app/src/pages/NewsletterPage.jsx

+180
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
import { pdfjs } from "react-pdf";
2+
import { useCallback, useEffect, useMemo, useState } from "react";
3+
import { Document, Page } from "react-pdf";
4+
import { useResizeObserver } from "@wojtekmaj/react-hooks";
5+
import "react-pdf/dist/esm/Page/AnnotationLayer.css";
6+
import "react-pdf/dist/esm/Page/TextLayer.css";
7+
import { IoChevronBack, IoChevronForward } from "react-icons/io5";
8+
import { API_URL } from "../lib/constants";
9+
10+
import "../styles/newsletter.css";
11+
import Newsletter from "../components/Newsletter";
12+
13+
pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.mjs`;
14+
const maxWidth = 800;
15+
const resizeObserverOptions = {};
16+
17+
const NewsletterPage = () => {
18+
const [file, setFile] = useState();
19+
const [editions, setEditions] = useState([]);
20+
const [numPages, setNumPages] = useState();
21+
const [pageNumber, setPageNumber] = useState(1);
22+
const [containerRef, setContainerRef] = useState(null);
23+
const [containerWidth, setContainerWidth] = useState();
24+
const [loading, setLoading] = useState(true);
25+
26+
// Memoize the options object to prevent unnecessary reloads
27+
const options = useMemo(
28+
() => ({
29+
cMapUrl: `https://unpkg.com/pdfjs-dist@${pdfjs.version}/cmaps/`,
30+
}),
31+
[]
32+
);
33+
34+
const onDocumentLoadSuccess = ({ numPages }) => {
35+
setNumPages(numPages);
36+
};
37+
38+
const onResize = useCallback((entries) => {
39+
const [entry] = entries;
40+
if (entry) {
41+
setContainerWidth(entry.contentRect.width);
42+
}
43+
}, []);
44+
45+
useResizeObserver(containerRef, resizeObserverOptions, onResize);
46+
47+
const getNewsletters = async () => {
48+
try {
49+
const response = await fetch(`${API_URL}/newsletter`, {
50+
method: "GET",
51+
headers: {
52+
"Content-Type": "application/json",
53+
},
54+
});
55+
56+
const data = await response.json();
57+
if(data.success){
58+
setEditions(data.newsletter);
59+
if(data.newsletter.length>0) getNewsletter(data.newsletter[0].id)
60+
}
61+
setLoading(false);
62+
} catch (error) {
63+
setLoading(false);
64+
}
65+
};
66+
67+
const getNewsletter = async (id) => {
68+
try {
69+
const response = await fetch(`${API_URL}/newsletter/${id}`, {
70+
method: "GET",
71+
headers: {
72+
"Content-Type": "application/json",
73+
},
74+
});
75+
76+
const data = await response.json();
77+
if(data.success){
78+
const pdfResponse = await fetch(data.newsletter.link);
79+
const blob = await pdfResponse.blob();
80+
const fileUrl = URL.createObjectURL(blob);
81+
setFile(fileUrl);
82+
}
83+
setLoading(false);
84+
} catch (error) {
85+
setLoading(false);
86+
}
87+
};
88+
89+
useEffect(()=>{
90+
getNewsletters();
91+
},[])
92+
93+
const forward = () => {
94+
if (pageNumber + 1 <= numPages) setPageNumber(pageNumber + 1);
95+
};
96+
97+
const backward = () => {
98+
if (pageNumber - 1 >= 1) setPageNumber(pageNumber - 1);
99+
};
100+
101+
const [selectedValue, setSelectedValue] = useState('Option 1');
102+
103+
// Handle change event
104+
const handleChange = (event) => {
105+
setLoading(true);
106+
setSelectedValue(event.target.value);
107+
getNewsletter(event.target.value);
108+
};
109+
110+
return (
111+
<div className="text-white flex flex-col justify-center">
112+
<h1 className="text-4xl tracking-tight my-2 font-extrabold text-pastel text-center sm:text-5xl md:text-6xl">
113+
Newsletters
114+
</h1>
115+
<div className="flex justify-center mt-4 mb-8">
116+
<div className="mx-auto">
117+
<label htmlFor="dropdown" className="mb-2 text-lg font-medium text-gray-300 text-center">
118+
Select an edition:
119+
</label>
120+
<select
121+
id="dropdown"
122+
value={selectedValue}
123+
onChange={handleChange}
124+
className="block w-64 px-3 py-2 border border-gray-300 bg-gray-700 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
125+
>
126+
{
127+
editions.map((item, index)=>{
128+
return <option key={index} value={item.id}>{item.edition}</option>
129+
})
130+
}
131+
</select>
132+
</div>
133+
</div>
134+
{
135+
loading&&
136+
<div className="h-24 w-4/6 rounded-xl bg-white/30 text-transparent mx-auto animate-pulse">
137+
asda
138+
</div>
139+
}
140+
{!loading&&file&&
141+
<div>
142+
<div className="flex justify-center">
143+
<div className="flex justify-center gap-12">
144+
<button onClick={backward}><IoChevronBack size={25} /></button>
145+
{pageNumber} of {numPages}
146+
<button onClick={forward}><IoChevronForward size={25} /></button>
147+
</div>
148+
</div>
149+
<div>
150+
<div className="Example__container__document mx-auto" ref={setContainerRef}>
151+
<Document
152+
file={file}
153+
onLoadSuccess={onDocumentLoadSuccess}
154+
options={options}
155+
>
156+
<Page
157+
pageNumber={pageNumber}
158+
width={
159+
containerWidth ? Math.min(containerWidth, maxWidth) : maxWidth
160+
}
161+
/>
162+
</Document>
163+
</div>
164+
</div>
165+
<div className="flex justify-center">
166+
<div className="flex justify-center gap-12">
167+
<button onClick={backward}><IoChevronBack size={25} /></button>
168+
{pageNumber} of {numPages}
169+
<button onClick={forward}><IoChevronForward size={25} /></button>
170+
</div>
171+
</div>
172+
</div>}
173+
<div className="my-6">
174+
<Newsletter />
175+
</div>
176+
</div>
177+
);
178+
};
179+
180+
export default NewsletterPage;

Diff for: my-app/src/styles/newsletter.css

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
.Example input,
2+
.Example button {
3+
font: inherit;
4+
}
5+
6+
.Example header {
7+
background-color: #323639;
8+
box-shadow: 0 0 8px rgba(0, 0, 0, 0.5);
9+
padding: 20px;
10+
color: white;
11+
}
12+
13+
.Example header h1 {
14+
font-size: inherit;
15+
margin: 0;
16+
}
17+
18+
.Example__container {
19+
display: flex;
20+
flex-direction: column;
21+
align-items: center;
22+
margin: 10px 0;
23+
padding: 10px;
24+
}
25+
26+
.Example__container__load {
27+
margin-top: 1em;
28+
color: white;
29+
}
30+
31+
.Example__container__document {
32+
width: 100%;
33+
max-width: calc(100% - 2em);
34+
margin: 1em 0;
35+
}
36+
37+
.Example__container__document .react-pdf__Document {
38+
display: flex;
39+
flex-direction: column;
40+
align-items: center;
41+
}
42+
43+
.Example__container__document .react-pdf__Page {
44+
margin: 1em 0;
45+
box-shadow: 0 0 8px rgba(0, 0, 0, 0.5);
46+
}
47+
48+
.Example__container__document .react-pdf__message {
49+
padding: 20px;
50+
color: white;
51+
}

Diff for: package-lock.json

-54
This file was deleted.

Diff for: package.json

-5
This file was deleted.

0 commit comments

Comments
 (0)