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

feat: added announcement schema and create announcement page #47

Merged
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
80 changes: 80 additions & 0 deletions __tests__/CreateAnnouncement.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/**
* @jest-environment jsdom
*/

import React from "react";
import "@testing-library/jest-dom";
import { render, screen, fireEvent, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import CreateAnnouncement from "@/app/createAnnouncement/page";

describe("CreateAnnouncement", () => {
it("renders the form correctly", () => {
render(<CreateAnnouncement />);

expect(screen.getByText("New Message")).toBeInTheDocument();
expect(screen.getByLabelText("Send to")).toBeInTheDocument();
expect(screen.getByLabelText("Subject")).toBeInTheDocument();
expect(screen.getByLabelText("Message")).toBeInTheDocument();
expect(screen.getByRole("button", { name: /Send/i })).toBeInTheDocument();
expect(screen.getByRole("button", { name: /Cancel/i })).toBeInTheDocument();
});

it("updates form fields when user types", async () => {
render(<CreateAnnouncement />);

const recipientsInput = screen.getByPlaceholderText("Find recipients") as HTMLInputElement;
const subjectInput = screen.getByPlaceholderText("Subject line here") as HTMLInputElement;
const messageInput = screen.getByPlaceholderText("Type your message here...") as HTMLTextAreaElement;

await userEvent.type(recipientsInput, "testUser");
await userEvent.type(subjectInput, "Meeting Update");
await userEvent.type(messageInput, "Hello everyone, please note the meeting time change.");

expect(recipientsInput.value).toBe("testUser");
expect(subjectInput.value).toBe("Meeting Update");
expect(messageInput.value).toBe("Hello everyone, please note the meeting time change.");
});

it("handles file selection correctly", () => {
render(<CreateAnnouncement />);

const fileInput = screen.getByLabelText(/Add attachment/i);
const file = new File(["sample content"], "sample.txt", { type: "text/plain" });

fireEvent.change(fileInput, { target: { files: [file] } });

// Check if the file name appears correctly
const attachmentText = screen.getByText("sample.txt");
expect(attachmentText).toBeInTheDocument();
});

it("handles form submission correctly", () => {
const logSpy = jest.spyOn(console, "log").mockImplementation();

// Render the component
render(<CreateAnnouncement />);

const recipientsInput = screen.getByPlaceholderText(/Find recipients/i);
const subjectInput = screen.getByPlaceholderText(/Subject line here/i);
const messageTextarea = screen.getByPlaceholderText(/Type your message here/i);

fireEvent.change(recipientsInput, { target: { value: "Test User" } });
fireEvent.change(subjectInput, { target: { value: "Test Subject" } });
fireEvent.change(messageTextarea, { target: { value: "Test Message" } });

// Simulate form submission
const submitButton = screen.getByRole("button", { name: /Send/i });
fireEvent.click(submitButton);

// Check if console.log was called with the correct form data
expect(logSpy).toHaveBeenCalledWith("Submitted Data: ", {
recipients: "Test User",
subject: "Test Subject",
message: "Test Message",
attachment: null,
});

logSpy.mockRestore();
});
});
2 changes: 0 additions & 2 deletions __tests__/TreeEntryForm.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ import { render, screen, fireEvent, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { treeIssues } from "@/app/newTreeForm/tree-form-data";
import TreeEntryForm from "@/app/newTreeForm/page";
import { ClerkProvider } from "@clerk/nextjs";
import mockRouter from "next-router-mock";

jest.mock("@clerk/nextjs", () => ({
ClerkProvider: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
Expand Down
11 changes: 11 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
},
"dependencies": {
"@auth0/nextjs-auth0": "^4.0.2",
"@chakra-ui/icons": "^2.2.4",
"@chakra-ui/react": "^2.10.5",
"@clerk/clerk-react": "^5.24.0",
"@clerk/nextjs": "^5.0.9",
Expand Down
153 changes: 153 additions & 0 deletions src/app/createAnnouncement/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
"use client";

import { useState } from "react";
import {
Box,
Button,
FormControl,
FormLabel,
Input,
Textarea,
VStack,
IconButton,
HStack,
useToast,
Flex,
Text,
} from "@chakra-ui/react";
import { AttachmentIcon } from "@chakra-ui/icons";

const CreateAnnouncement = () => {
type AnnouncementData = {
recipients: string;
subject: string;
message: string;
attachment: File | null;
};

const [formData, setFormData] = useState<AnnouncementData>({
recipients: "",
subject: "",
message: "",
attachment: null, // Make sure this is 'attachment'
});

const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>) => {
const { name, value } = e.target;
setFormData((prev) => ({
...prev,
[name]: value,
}));
};

const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
if (e.target.files && e.target.files[0]) {
setFormData((prev) => ({
...prev,
attachment: e.target.files![0],
}));
}
};

const handleSubmit = () => {
console.log("Submitted Data: ", formData);
};

return (
<Box
position="absolute"
width="100vw"
minHeight="100vh"
bg="#F4F1E8"
transform="translateX(-15rem)"
pl="15rem"
display="flex"
alignItems="center"
>
<VStack spacing={7} align="start" p="50px" py="50px" width="100%" maxW="900px" mx="auto">
<Box fontSize="3xl" fontWeight="bold">
New Message
</Box>
<FormControl>
<FormLabel fontWeight="bold">Send to</FormLabel>
<Input
name="recipients"
placeholder="Find recipients"
_placeholder={{ color: "#596435" }}
value={formData.recipients}
onChange={handleChange}
bg="white"
color="#596435"
borderRadius="xl"
py="23px"
/>
</FormControl>
<FormControl>
<FormLabel fontWeight="bold">Subject</FormLabel>
<Input
name="subject"
placeholder="Subject line here"
_placeholder={{ color: "#596435" }}
value={formData.subject}
onChange={handleChange}
bg="white"
borderRadius="xl"
py="23px"
/>
</FormControl>
<FormControl position="relative">
<FormLabel fontWeight="bold">Message</FormLabel>
<Textarea
name="message"
placeholder="Type your message here..."
_placeholder={{ color: "#596435" }}
value={formData.message}
onChange={handleChange}
bg="#white"
h="250px"
pr="40px" // Space for icon
color="#596435"
borderRadius="xl"
/>
<Box position="absolute" top="35px" right="15px" display="flex" alignItems="center">
<label htmlFor="file-upload" style={{ display: "flex", alignItems: "center", cursor: "pointer" }}>
<IconButton
icon={<AttachmentIcon />}
bg="transparent"
color="black"
aria-label="Upload file"
_hover={{ color: "black" }}
as="label"
htmlFor="file-upload"
mr="-6px"
/>
<Text fontSize="sm" color="black">
{formData.attachment ? formData.attachment.name : "Add attachment"}
</Text>
</label>
</Box>
<Input type="file" id="file-upload" display="none" onChange={handleFileChange} />
</FormControl>
<HStack spacing={5}>
<Button px="30px" fontWeight="normal" rounded="full" bg="#596435" color="white" onClick={handleSubmit}>
Send
</Button>
<Button
borderWidth="1.5px"
fontWeight="normal"
rounded="full"
variant="outline"
bg="white"
borderColor="#596435"
color="#596435"
>
Cancel
</Button>
</HStack>
</VStack>
</Box>
// </Box>
);
};

export default CreateAnnouncement;
18 changes: 18 additions & 0 deletions src/database/announcementSchema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import mongoose, { Schema } from "mongoose";

export type IAnnouncement = {
_id: string;
volunteers: string[];
sender: string;
dateSent: Date;
message: string;
};

const AnnouncementSchema = new Schema<IAnnouncement>({
volunteers: { type: [String], required: true },
sender: { type: String, required: true },
dateSent: { type: Date, required: true },
message: { type: String, required: true },
});

export default mongoose.models.Announcement || mongoose.model<IAnnouncement>("Announcement", AnnouncementSchema);