diff --git a/frontend/__tests__/Bookmark/NewBookmarkCard.test.tsx b/frontend/__tests__/Bookmark/NewBookmarkCard.test.tsx
index 0800df8c..050e4e07 100644
--- a/frontend/__tests__/Bookmark/NewBookmarkCard.test.tsx
+++ b/frontend/__tests__/Bookmark/NewBookmarkCard.test.tsx
@@ -57,7 +57,7 @@ describe("Fields logic", () => {
await user.click(toggle);
expect(submit).not.toBeDisabled();
- // fields should be populated
+ // Fields should be populated
expect(url).toHaveValue("https://foodnetwork.com");
const axiosMock = new MockAdapter(instance);
@@ -103,7 +103,7 @@ describe("Fields logic", () => {
await user.click(submit);
- // if everything submitted correctly then it should be empty input field.
+ // If submitted correctly, the fields should be reset.
expect(url).toHaveValue("");
expect(tags).toHaveValue("");
expect(submit).toBeDisabled();
@@ -171,7 +171,7 @@ describe("Fields logic", () => {
await user.type(tags, "food");
expect(submit).not.toBeDisabled();
- // fields should be populated
+ // Fields should be populated
expect(url).toHaveValue("https://foodnetwork.com");
const axiosMock = new MockAdapter(instance);
@@ -226,7 +226,7 @@ describe("Fields logic", () => {
await user.click(submit);
- // if everything submitted correctly then it should be empty input field.
+ // If submitted correctly, the fields should be reset.
expect(url).toHaveValue("");
expect(tags).toHaveValue("");
expect(submit).toBeDisabled();
@@ -276,3 +276,77 @@ describe("Tags Operations", () => {
expect(screen.queryByTestId("Tag2")).toEqual(null);
});
});
+
+describe("Success Toast", () => {
+ it("displays a green success toast when bookmark is added successfully", async () => {
+ render(
+
,
+ );
+
+ const submit = screen.getByText("Submit");
+ const tagsInput = screen.getByPlaceholderText("Enter a tag");
+ const urlInput = screen.getByPlaceholderText(/discover/i);
+
+ // Type in the URL (it will be prefixed with "https://")
+ await user.type(urlInput, "example.com");
+ expect(urlInput).toHaveValue("https://example.com");
+
+ // Type a tag and add it
+ await user.type(tagsInput, "testtag");
+ await user.type(tagsInput, "{enter}");
+
+ // Setup axios mocks for API calls
+ const axiosMock = new MockAdapter(instance);
+ const SERVER_URL = process.env.NEXT_PUBLIC_SERVER_URL;
+ const tagsAPI = SERVER_URL + "/api/tags";
+ const bookmarkAPI = SERVER_URL + "/api/bookmark";
+
+ const expectedResult = [
+ {
+ id: 1,
+ title: "testtag",
+ bookmarks: [],
+ },
+ ];
+
+ const expectedBookmark: Bookmark = {
+ id: 1,
+ title: "example.com",
+ url: "https://example.com",
+ tags: [
+ {
+ id: 1,
+ title: "testtag",
+ },
+ ],
+ screenshotUrl: "",
+ scrapable: true,
+ };
+
+ axiosMock.onPost(tagsAPI, ["testtag"]).reply(() => {
+ return [200, expectedResult];
+ });
+
+ axiosMock
+ .onPost(bookmarkAPI, {
+ title: "https://example.com",
+ url: "https://example.com",
+ tagIds: [1],
+ scrapable: true,
+ })
+ .reply(() => {
+ return [200, expectedBookmark];
+ });
+
+ await user.click(submit);
+
+ // Wait for the success toast to appear
+ expect(
+ await screen.findByText("Bookmark added successfully!")
+ ).toBeInTheDocument();
+ });
+});
diff --git a/frontend/components/Bookmark/NewBookmarkCard.tsx b/frontend/components/Bookmark/NewBookmarkCard.tsx
index 585c96fa..50c201ed 100644
--- a/frontend/components/Bookmark/NewBookmarkCard.tsx
+++ b/frontend/components/Bookmark/NewBookmarkCard.tsx
@@ -20,17 +20,14 @@ import { AxiosError, AxiosResponse } from "axios";
import { ScrapableNewBookmarkToggle } from "./ScrapableToggle";
async function makeNewBookmark(createBmk: Bookmark): Promise {
- let newBkmkRequest: NewBookmarkRequest;
- newBkmkRequest = {
+ let newBkmkRequest: NewBookmarkRequest = {
title: createBmk.title,
url: createBmk.url,
tagIds: [],
scrapable: createBmk.scrapable,
};
console.log(createBmk.scrapable);
- let tagTitles: string[] = createBmk.tags.map((t) => {
- return t.title;
- });
+ let tagTitles: string[] = createBmk.tags.map((t) => t.title);
await api.addAllTag(tagTitles).then((response) => {
let respTags: Tag[] = response.data;
@@ -55,16 +52,27 @@ async function makeNewBookmark(createBmk: Bookmark): Promise {
theme: "colored",
});
}
-
return;
}
if (!(response instanceof AxiosError)) {
- console.log(response.data.scrapable);
+ // Update the bookmark with the response data
createBmk.id = response.data.id;
createBmk.tags = response.data.tags;
createBmk.screenshotUrl = response.data.screenshotUrl;
createBmk.scrapable = response.data.scrapable;
createBmk.title = response.data.title;
+
+ // Show a green success toast for a successful add
+ toast.success("Bookmark added successfully!", {
+ position: "bottom-right",
+ autoClose: 3000,
+ hideProgressBar: false,
+ closeOnClick: true,
+ pauseOnHover: true,
+ draggable: true,
+ progress: undefined,
+ theme: "colored",
+ });
}
});
return createBmk;
@@ -95,10 +103,8 @@ export default function NewBookmarkCard() {
submittedBmk: NewBookmarkForm,
actions: any,
) => {
- // get the the last inputed string and all the tags already entered.
- let tags: Tag[] = strTags.map((t) => {
- return { title: t, id: -1 };
- });
+ // Get the last inputted string and all the tags already entered.
+ let tags: Tag[] = strTags.map((t) => ({ title: t, id: -1 }));
if (tagInput) {
tags.push({ title: tagInput, id: -1 });
}
@@ -112,10 +118,12 @@ export default function NewBookmarkCard() {
scrapable: isScrapable,
};
- actions.resetForm({ newcard }, setStrTags([]), setTagInput(""));
+ actions.resetForm({ newcard });
+ setStrTags([]);
+ setTagInput("");
let retBkmk = await makeNewBookmark(newBkmk);
- // if adding the bookmark was successful.
- if (retBkmk.id != -1) {
+ // If adding the bookmark was successful, dispatch actions.
+ if (retBkmk.id !== -1) {
retBkmk.tags.forEach((t) => {
let tAct: TagAction = {
type: "add",
@@ -146,7 +154,7 @@ export default function NewBookmarkCard() {
const { key } = e;
const trimmedInput = tagInput.trim();
if (
- // add tag via space bar or enter
+ // Add tag via space bar or enter
(key === "Enter" || key === "Space" || key === " ") &&
trimmedInput.length &&
!strTags.includes(trimmedInput)
@@ -156,8 +164,7 @@ export default function NewBookmarkCard() {
values.tagTitles = strTags.concat(trimmedInput);
setTagInput("");
}
- // user hits backspace and the user has input field of 0
- // then pop the last tag only if there is one.
+ // If backspace is pressed on an empty input field, remove the last tag.
if (key === "Backspace" && !tagInput.length && strTags.length) {
e.preventDefault();
const tagsCopy = [...strTags];