Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/kevinsophia/newsletter creator #42

Merged
merged 7 commits into from
May 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
21 changes: 19 additions & 2 deletions backend/src/controllers/newsletter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,22 +36,23 @@ export const getNewsletter: RequestHandler = async (req, res, next) => {

export const createNewsletter: RequestHandler = async (req, res, next) => {
const errors = validationResult(req);
const { _id, image, title, description, date, content } = req.body;
const { image, title, description, date, content } = req.body;

try {
validationErrorParser(errors);

const newsletter = await Newsletter.create({
_id,
image,
title,
description,
date,
content,
});

console.log("newsletter: ", newsletter);
res.status(201).json(newsletter);
} catch (error) {
console.error("Error creating newsletter:", error);
next(error);
}
};
Expand Down Expand Up @@ -83,3 +84,19 @@ export const updateNewsletter: RequestHandler = async (req, res, next) => {
next(error);
}
};

export const deleteNewsletter: RequestHandler = async (req, res, next) => {
const { id } = req.params;

try {
const newsletter = await Newsletter.findByIdAndDelete(id);

if (!newsletter) {
throw createHttpError(404, "Newsletter not found.");
}

res.status(200).json(newsletter);
} catch (error) {
next(error);
}
};
3 changes: 1 addition & 2 deletions backend/src/models/newsletter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ const newsletterSchema = new Schema({
title: { type: String, required: true },
description: { type: String, required: true },
date: { type: String, required: true },
content: { type: [String], required: true },
archive: { type: Boolean, required: true },
content: { type: String, required: true },
});

type Newsletters = InferSchemaType<typeof newsletterSchema>;
Expand Down
1 change: 1 addition & 0 deletions backend/src/routes/newsletter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ router.put(
NewsletterController.updateNewsletter,
);
router.post("/", NewsletterValidator.createNewsletter, NewsletterController.createNewsletter);
router.delete("/:id", NewsletterValidator.deleteNewsletter, NewsletterController.deleteNewsletter);

export default router;
14 changes: 12 additions & 2 deletions backend/src/validators/newsletter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,18 @@ const makeContentValidator = () =>
.exists()
.withMessage("content is required")
.bail()
.isArray()
.withMessage("content must be an array of strings");
.isString()
.withMessage("content must be a string");

export const createNewsletter = [
makeImageValidator(),
makeTitleValidator(),
makeDescriptionValidator(),
makeDateValidator(),
makeContentValidator(),
];

export const updateNewsletter = [
makeIDValidator(),
makeImageValidator(),
makeTitleValidator(),
Expand All @@ -53,3 +61,5 @@ export const createNewsletter = [
];

export const getNewsletter = [makeIDValidator()];

export const deleteNewsletter = [makeIDValidator()];
5 changes: 5 additions & 0 deletions frontend/public/ic_add.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
6 changes: 6 additions & 0 deletions frontend/public/ic_close2.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions frontend/public/ic_doublecaretright.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions frontend/public/ic_edit.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
27 changes: 23 additions & 4 deletions frontend/src/api/newsletter.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { get, handleAPIError, post, put } from "./requests";
import { del, get, handleAPIError, post, put } from "./requests";

import type { APIResult } from "./requests";

Expand All @@ -8,8 +8,15 @@ export type Newsletter = {
title: string;
description: string;
date: string;
content: string[];
archive: boolean;
content: string;
};

export type CreateNewsletterRequest = {
image: string;
title: string;
description: string;
date: string;
content: string;
};

export async function getNewsletter(id: string): Promise<APIResult<Newsletter>> {
Expand All @@ -36,7 +43,9 @@ export async function getAllNewsletters(): Promise<APIResult<Newsletter[]>> {
}
}

export async function createNewsletter(newsletter: Newsletter): Promise<APIResult<Newsletter>> {
export async function createNewsletter(
newsletter: CreateNewsletterRequest,
): Promise<APIResult<Newsletter>> {
try {
const response = await post("/api/newsletter", newsletter);
const json = (await response.json()) as Newsletter;
Expand All @@ -58,3 +67,13 @@ export async function updateNewsletter(newsletter: Newsletter): Promise<APIResul
return handleAPIError(error);
}
}

export async function deleteNewsletter(id: string): Promise<APIResult<Newsletter>> {
try {
const response = await del(`/api/newsletter/${id}`);
const json = (await response.json()) as Newsletter;
return { success: true, data: json };
} catch (error) {
return handleAPIError(error);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,24 @@
z-index: 1002;
}

/* .text {
.text {
font-weight: 16px;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
gap: 47px;
} */
/* gap: 47px; */
}

.content {
width: 100%;
white-space: pre-wrap;
font: var(--font-body);
font-size: 16px;
font-style: normal;
font-weight: 400;
line-height: 24px;
}

.description {
text-align: left;
Expand Down
29 changes: 2 additions & 27 deletions frontend/src/app/(web app)/newsletter/[newsletterID]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
"use client";
// import html2canvas from "html2canvas";
// import { jsPDF } from "jspdf";
import React, { useEffect, useState } from "react";

import { Newsletter, getNewsletter } from "../../../../api/newsletter";
Expand Down Expand Up @@ -38,16 +36,6 @@
setPopup(true);
};

const printDocument = () => {
window.scrollTo(0, 0);
// html2canvas(document.body, { scale: 0.32 }).then((canvas) => {
// const imgData = canvas.toDataURL("image/png");
// const pdf = new jsPDF();
// pdf.addImage(imgData, "PNG", 0, 0);
// pdf.save("download.pdf");
// });
};

useEffect(() => {
getNewsletter(params.newsletterID)
.then((response) => {
Expand Down Expand Up @@ -81,7 +69,7 @@
<NewsletterPopup open={popupOpen} setOpen={setPopup} />
</div>

<img

Check warning on line 72 in frontend/src/app/(web app)/newsletter/[newsletterID]/page.tsx

View workflow job for this annotation

GitHub Actions / Frontend check

Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` to automatically optimize images. This may incur additional usage or cost from your provider. See: https://nextjs.org/docs/messages/no-img-element
src={newsletter?.image ?? "image not found"}
alt="Description of the image"
style={{
Expand All @@ -93,29 +81,16 @@
flexShrink: 0,
}}
/>
<div
className={styles.subtitleSmaller}
style={{ display: "flex", alignItems: "center" }}
onClick={printDocument}
>
<div className={styles.subtitleSmaller} style={{ display: "flex", alignItems: "center" }}>
Here’s Our Story
<img
src="/ic_download.svg"
alt="Download Icon"
style={{ marginLeft: "10px", width: "27px", height: "27px" }}
/>
</div>

{newsletter?.content.map((paragraph, index) => (
<p key={index} className={styles.description}>
{paragraph}
</p>
))}
<pre className={styles.content}>{newsletter?.content}</pre>

<div className={styles.subtitleSharePost} style={{ display: "flex", alignItems: "center" }}>
Share This Post
<a href="https://www.facebook.com/4FLOT.team/" target="_blank" rel="noopener noreferrer">
<img

Check warning on line 93 in frontend/src/app/(web app)/newsletter/[newsletterID]/page.tsx

View workflow job for this annotation

GitHub Actions / Frontend check

Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` to automatically optimize images. This may incur additional usage or cost from your provider. See: https://nextjs.org/docs/messages/no-img-element
src="/facebook.svg"
alt="facebook Icon"
style={{ marginLeft: "20px", width: "30px", height: "30px", marginRight: "10px" }}
Expand All @@ -126,7 +101,7 @@
target="_blank"
rel="noopener noreferrer"
>
<img

Check warning on line 104 in frontend/src/app/(web app)/newsletter/[newsletterID]/page.tsx

View workflow job for this annotation

GitHub Actions / Frontend check

Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` to automatically optimize images. This may incur additional usage or cost from your provider. See: https://nextjs.org/docs/messages/no-img-element
src="/twitter.svg"
alt="twitter Icon"
style={{ marginLeft: "10px", width: "40px", height: "40px", marginRight: "10px" }}
Expand Down
14 changes: 11 additions & 3 deletions frontend/src/app/(web app)/newsletter/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { Newsletter, getAllNewsletters } from "@/api/newsletter";
import BackgroundHeader from "@/components/BackgroundHeader";
import Button from "@/components/Button";

export default function Newsletter() {
export default function NewsletterPage() {
const [popupOpen, setPopup] = useState(false);
const [images, setImages] = useState<BackgroundImage[]>([]);
const [curNewsletters, setCurNewsletters] = useState<Newsletter[]>([]);
Expand All @@ -35,10 +35,18 @@ export default function Newsletter() {
getAllNewsletters()
.then((response) => {
if (response.success) {
const curLetters = response.data.filter((item) => !item.archive);
const currentYear = new Date().getFullYear();

const curLetters = response.data.filter((item) => {
const itemDate = new Date(item.date);
return itemDate.getFullYear() === currentYear;
});
setCurNewsletters(curLetters);

const archiveLetters = response.data.filter((item) => item.archive);
const archiveLetters = response.data.filter((item) => {
const itemDate = new Date(item.date);
return itemDate.getFullYear() < currentYear;
});
const newslettersByYear: Record<string, Newsletter[]> = {};

archiveLetters.forEach((newsletter) => {
Expand Down
68 changes: 68 additions & 0 deletions frontend/src/app/admin/newsletter-creator/page.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
@import url("https://fonts.googleapis.com/css2?family=Open+Sans:ital,wdth,wght@0,75..100,300..800;1,75..100,300..800&family=Roboto+Slab:[email protected]&display=swap");

.page {
display: flex;
justify-content: flex-start;
padding-left: 282px;
padding-top: 22px;
padding-bottom: 50px;
}

.Headings {
text-align: left;
font: var(--font-body);
font-size: 16px;
font-style: normal;
font-weight: 700;
line-height: 24px; /* 133.333% */
color: white;
}

.cellentry {
text-align: left;
font: var(--font-body);
font-size: 16px;
font-style: normal;
font-weight: 400;
line-height: 24px; /* 133.333% */
color: black;
}

.headingBackground {
background-color: #694c97; /* Replace with your desired color */
}

.cellBorderStyle {
border-right: 1px solid #c9c9c9; /* Adjust the border style as needed */
}

.selectedRow {
border-radius: 5px;
box-shadow: inset 0 0 0 2px #bda7e0;
box-shadow: inset 0 0.5px 0 2px #bda7e0;
}
.selectedCol {
background: rgba(105, 76, 151, 0.05);
}

.evenRow {
background-color: #ffffff; /* White color for even rows */
}

.oddRow {
background-color: #f8f5fb; /* #F8F5FB color for odd rows */
}

.sidebar-container {
position: fixed;
top: 0;
right: 0;
bottom: 0;
width: 400px; /* Adjust width as needed */
transition: transform 0.3s ease-out;
transform: translateX(100%);
}

.sidebar-container.open {
transform: translateX(0%);
}
Loading
Loading