diff --git a/__tests__/CreateAnnouncement.test.tsx b/__tests__/CreateAnnouncement.test.tsx
new file mode 100644
index 0000000..5c8d6dd
--- /dev/null
+++ b/__tests__/CreateAnnouncement.test.tsx
@@ -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();
+
+ 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();
+
+ 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();
+
+ 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();
+
+ 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();
+ });
+});
diff --git a/__tests__/TreeEntryForm.test.tsx b/__tests__/TreeEntryForm.test.tsx
index e25280a..2461a1d 100644
--- a/__tests__/TreeEntryForm.test.tsx
+++ b/__tests__/TreeEntryForm.test.tsx
@@ -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 }) =>
{children}
,
diff --git a/package-lock.json b/package-lock.json
index a299513..c2d7177 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,6 +9,7 @@
"version": "0.1.0",
"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",
@@ -650,6 +651,16 @@
"react": ">=18"
}
},
+ "node_modules/@chakra-ui/icons": {
+ "version": "2.2.4",
+ "resolved": "https://registry.npmjs.org/@chakra-ui/icons/-/icons-2.2.4.tgz",
+ "integrity": "sha512-l5QdBgwrAg3Sc2BRqtNkJpfuLw/pWRDwwT58J6c4PqQT6wzXxyNa8Q0PForu1ltB5qEiFb1kxr/F/HO1EwNa6g==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@chakra-ui/react": ">=2.0.0",
+ "react": ">=18"
+ }
+ },
"node_modules/@chakra-ui/react": {
"version": "2.10.5",
"resolved": "https://registry.npmjs.org/@chakra-ui/react/-/react-2.10.5.tgz",
diff --git a/package.json b/package.json
index dd4b21c..068080e 100644
--- a/package.json
+++ b/package.json
@@ -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",
diff --git a/src/app/createAnnouncement/page.tsx b/src/app/createAnnouncement/page.tsx
new file mode 100644
index 0000000..f9f734b
--- /dev/null
+++ b/src/app/createAnnouncement/page.tsx
@@ -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({
+ recipients: "",
+ subject: "",
+ message: "",
+ attachment: null, // Make sure this is 'attachment'
+ });
+
+ const handleChange = (e: React.ChangeEvent) => {
+ const { name, value } = e.target;
+ setFormData((prev) => ({
+ ...prev,
+ [name]: value,
+ }));
+ };
+
+ const handleFileChange = (e: React.ChangeEvent) => {
+ if (e.target.files && e.target.files[0]) {
+ setFormData((prev) => ({
+ ...prev,
+ attachment: e.target.files![0],
+ }));
+ }
+ };
+
+ const handleSubmit = () => {
+ console.log("Submitted Data: ", formData);
+ };
+
+ return (
+
+
+
+ New Message
+
+
+ Send to
+
+
+
+ Subject
+
+
+
+ Message
+
+
+
+
+
+
+
+
+
+
+
+
+ //
+ );
+};
+
+export default CreateAnnouncement;
diff --git a/src/database/announcementSchema.ts b/src/database/announcementSchema.ts
new file mode 100644
index 0000000..a4e3471
--- /dev/null
+++ b/src/database/announcementSchema.ts
@@ -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({
+ 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("Announcement", AnnouncementSchema);