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/forum tag modal #427

Merged
merged 7 commits into from
Apr 20, 2023
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
6 changes: 4 additions & 2 deletions apps/forum/src/components/App.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import React from "react";
import { useTranslation } from "react-i18next";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Header from "@app/components/common/Header";
import HeaderWithModal from "@app/components/common/HeaderWithModal";

import { ThemeContext } from "@app/utils/theme-context";
import Board from "./Board";
import BoardMenu from "@app/components/BoardMenu";
import Thread from "@app/components/Thread";
import FilterMenu from "./FilterMenu";
import SearchTags from "./SearchTags";

const App = () => {
const { t, i18n } = useTranslation();
Expand All @@ -17,7 +18,8 @@ const App = () => {
<div className="flex flex-col">
<BrowserRouter>
<div className="basis-[67px]">
<Header
<HeaderWithModal
modal={SearchTags}
title={t("navigation.forum")}
onInputChange={() => {}}
placeholder={t("search placeholder")}
Expand Down
8 changes: 8 additions & 0 deletions apps/forum/src/components/Atoms.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import * as React from "react";
import { atom } from "recoil";
import { useRecoilState } from "recoil";

export const TagState = atom<string[]>({
key: "tagState",
default: [],
});
163 changes: 163 additions & 0 deletions apps/forum/src/components/SearchTags.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
import React, { useState } from "react";
import { useRecoilState, useRecoilValue, useSetRecoilState } from "recoil";
import { atom } from "recoil";
import { TagState } from "./Atoms";

type Props = {
isShow: boolean;
closeModal: () => void;
}

const SearchTags: React.FC<Props> = ({ isShow, closeModal }) => {
const tagState = useRecoilValue(TagState);

const [selectedTags, setSelectedTags] = useState<[]>([]);
const setTagsSelected = useSetRecoilState(TagState);
{
/* Later, use useEffect hook to fetch tags from the server side. */
}
const tags: Array<string> = [
"alpha",
"apple",
"adios",
"amigo",
"amino",
"bravo",
"charlie",
"delta",
];
const academicTags: Array<string> = [
"Courses",
"Professors",
"Seminars/Labs",
"Research",
"School Applications",
];
const campusTags: Array<string> = [
"Facilities",
"Circles",
"Events",
"Scholarships",
];
const lifeTags: Array<string> = [
"Gourmet",
"Culture",
"Languages",
"Housing",
"Travels",
"Events",
];
const jobTags: Array<string> = ["Part-time", "Internships", "Job Hunting"];

const [query, setQuery] = useState("");

const handleClick = (item: string) => {
if (!selectedTags.includes(item)) {
setSelectedTags((selectedTags) => [...selectedTags, item]);
}
};

const handleCloseModal = () => {
// setSelectedTags([]);
closeModal();
};

const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
setTagsSelected(selectedTags);
setQuery("");
closeModal();
};

return (
<div className={(isShow) ? "" : "hidden"}>
<div
className="z-10 fixed flex flex-col top-1/4 left-1/3 w-1/3 min-h-1/3 bg-white border shadow-lg rounded-lg overflow-y-auto"
>
<div className="modal-header flex sticky top-0 bg-white items-center justify-between p-4 border-b border-gray-200 rounded-t-md">
<h5
className="text-xl font-medium leading-normal text-gray-800 font-sans"
id="exampleModalLabel"
>
Choose Your Tags
</h5>
</div>
{/* SEARCH COMPONENT PART */}
<div className="modal-body flex flex-col">
<div>
<input
type="text"
value={query}
onChange={(e) => setQuery(e.target.value)}
className="h-full w-full px-4 py-4 shadow-lg rounded-md"
placeholder="Search"
/>
</div>
<ul className="py-1 shadow-lg rounded-lg">
{tags
.filter((item) => {
const searchTerm = query.toLowerCase();
const existingTerm = item.toLocaleLowerCase();
return searchTerm && existingTerm.startsWith(searchTerm);
})
.map((item) => (
<li
className="px-4 py-2 hover:bg-gray-100 font-sans"
onClick={() => handleClick(item)}
>
{item}
</li>
))}
</ul>

<div className="grid grid-cols-3 gap-4 items-center justify-between relative p-4 border-b">
{tags.map((tag) => (
<button
key={tag}
className="inline-block bg-gray-200 w-20 hover:bg-gray-300 px-2 py-1 rounded-full mr-2 mb-2 font-sans"
onClick={() => handleClick(tag)}
>
{tag}
</button>
))}
</div>
{/* DISPLAY FOR CURRENT SELECTED TAGS */}
{selectedTags.length > 0 && (
<div className="my-2 w-full shadow-lg rounded-lg">
{selectedTags.map((tag) => (
<button
key={tag}
className="inline-block bg-gray-200 hover:bg-gray-300 px-2 py-1 rounded-full mr-2 mb-2 font-sans"
onClick={() =>
setSelectedTags(selectedTags.filter((item) => item !== tag))
}
>
{tag}
</button>
))}
</div>
)}
<div className="modal-footer flex flex-wrap sticky bottom-0 w-full h-18 bg-white items-center justify-end p-4 border-t border-gray-200 rounded-b-md">
<button
type="submit"
className="border bg-light-lighter hover:bg-light-main cursor-pointer text-white text-center rounded-xl px-4 py-2"
onClick={handleSubmit}
>
Apply
</button>
<button
type="button"
className="border bg-light-lighter hover:bg-light-main cursor-pointer text-white text-center rounded-xl px-4 py-2"
onClick={handleCloseModal}
>
Close
</button>
</div>
</div>
</div>
<div className="z-0 absolute w-screen h-screen opacity-50 bg-slate-300" onClick={closeModal}></div>
</div>
);
};

export default SearchTags;
73 changes: 0 additions & 73 deletions apps/forum/src/components/TagsModal.tsx

This file was deleted.

5 changes: 4 additions & 1 deletion apps/forum/src/components/common/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,10 @@ const Header = ({
onChange={
onInputChange ? (e) => onInputChange(e.target.value) : () => {}
}
onFocus={() => setIsInputExpanded(true)}
onFocus={() => {
setIsInputExpanded(true);
onSearchBarClick();
}}
onBlur={() => setIsInputExpanded(false)}
value={inputText || ""}
disabled={disabled}
Expand Down
35 changes: 35 additions & 0 deletions apps/forum/src/components/common/HeaderWithModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React, { ReactElement, useState } from "react";
import Header from "./Header";
import { THEME } from "@app/types/theme";

type Props = {
modal: React.FC<any>;
title: string;
onInputChange(x: string): void;
placeholder: string;
inputText: string | string[];
disabled?: boolean;
isBlur: boolean;
changeLang(x: string): void;
theme?: THEME;
setTheme?: (theme: THEME) => void;
onSearchBarClick?: () => void;
};

const HeaderWithModal = ({ modal, onSearchBarClick, ...others }: Props) => {
const [ isModalOpen, setModalOpen ] = useState(false);

const handleSearchBarClick = () => {
if (onSearchBarClick) onSearchBarClick();
setModalOpen(!isModalOpen);
}

return (
<>
<Header {...others} onSearchBarClick={handleSearchBarClick} />
{modal({ isShow: isModalOpen, closeModal: () => setModalOpen(false) })}
</>
)
}

export default HeaderWithModal;