From d56556d6a01f46135cf219e65037e4ece93ad429 Mon Sep 17 00:00:00 2001 From: SySagar Date: Sun, 24 Sep 2023 14:30:18 +0530 Subject: [PATCH] feat:added blog tags --- src/App.css | 5 + src/app/blog/CreateBlog.tsx | 6 ++ src/app/blog/components/TagInput.tsx | 112 +++++++++++++++++++++ src/app/home/HeroPage.tsx | 76 +++++++++++++- src/app/home/components/Blog.tsx | 9 +- src/app/home/components/SearchedBlogs.tsx | 81 +++++++++++++++ src/layout/headeroptions/HeaderActions.tsx | 33 ++++++ src/lib/axios/api.ts | 1 + src/lib/constants/TAGS.ts | 30 ++++++ src/lib/store/useEditorContent.ts | 3 + src/lib/store/useSearchStore.tsx | 16 +++ 11 files changed, 366 insertions(+), 6 deletions(-) create mode 100644 src/app/blog/components/TagInput.tsx create mode 100644 src/app/home/components/SearchedBlogs.tsx create mode 100644 src/lib/constants/TAGS.ts create mode 100644 src/lib/store/useSearchStore.tsx diff --git a/src/App.css b/src/App.css index 9f872ce..7f7a114 100644 --- a/src/App.css +++ b/src/App.css @@ -10,6 +10,11 @@ src:local('Inconsolata'), url('./fonts/Inconsolata.ttf'); font-weight: 700; } +*{ + margin: 0; + padding: 0; +} + .hero-blog:hover{ position: relative; } diff --git a/src/app/blog/CreateBlog.tsx b/src/app/blog/CreateBlog.tsx index 61f39d8..3696284 100644 --- a/src/app/blog/CreateBlog.tsx +++ b/src/app/blog/CreateBlog.tsx @@ -2,6 +2,7 @@ import { IconButton, Stack, TextField, Typography } from "@mui/material"; import Tiptap from "./components/Tiptap"; import AddPhotoAlternateIcon from "@mui/icons-material/AddPhotoAlternate"; import useEditorContent from "../../lib/store/useEditorContent"; +import TagInput from "./components/TagInput"; interface BlogImageTypes { coverImage: File | null | Blob | MediaSource; @@ -78,12 +79,17 @@ const onTitleChange = (e: React.ChangeEvent) => { Add a cover image + + {blog.coverImage && ( )} + + + diff --git a/src/app/blog/components/TagInput.tsx b/src/app/blog/components/TagInput.tsx new file mode 100644 index 0000000..cf8ac53 --- /dev/null +++ b/src/app/blog/components/TagInput.tsx @@ -0,0 +1,112 @@ +// TagInput.tsx +import React, { useEffect, useState } from "react"; +import Autocomplete from "@mui/material/Autocomplete"; +import TextField from "@mui/material/TextField"; +import TAGS from "../../../lib/constants/TAGS"; +import { Button, Chip, Stack, Typography } from "@mui/material"; +import useEditorContent from "../../../lib/store/useEditorContent"; + +interface BlogTagTypes { + tags: string[]; +} + +const TagInput: React.FC = () => { + const [tags, setTags] = useState([]); + const [tagInput, setTagInput] = useState(""); + + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment + const [blog, setBlog] = useEditorContent((state: any) => [ state.blog as BlogTagTypes,state.setBlog,]); + // const onTagsChnage = (e: React.ChangeEvent) => { + + // } + + const handleTagInputChange = (event: React.ChangeEvent) => { + setTagInput(event.target.value); + }; + + console.log("tags", tags); + const handleAddTag = () => { + if (tagInput.trim() !== "" && !tags.includes(tagInput)) { + setTags([...tags, tagInput]); + setTagInput(""); + } + }; + + const handleAutocompleteChange = ( + event: React.SyntheticEvent, + value: string | null + ) => { + console.log("value", event); + if (value) { + setTags([...tags, value]); + } + }; + + useEffect(() => { + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + setBlog({ ...blog, tags: tags }); + }, [tags]); + + const handleDeleteTag = (tagToDelete: string) => { + setTags(tags.filter((tag) => tag !== tagToDelete)); + }; + + return ( + + Select category/categories + + ( + { + if (e.key === "Enter") { + e.preventDefault(); + handleAddTag(); + } + }} + /> + )} + onChange={handleAutocompleteChange} + /> + + + + {tags.map((tag, index) => ( + handleDeleteTag(tag)} + sx={{ + background: "#474747", + color: "white", + borderRadius: "14px", + padding: "5px 10px", + "& .MuiChip-deleteIcon": { + color: "white", // Change this to the desired color for the delete icon + }, + }} + /> + ))} + + + ); +}; + +export default TagInput; diff --git a/src/app/home/HeroPage.tsx b/src/app/home/HeroPage.tsx index 66813d1..cd671a5 100644 --- a/src/app/home/HeroPage.tsx +++ b/src/app/home/HeroPage.tsx @@ -6,6 +6,8 @@ import { useEffect, useState } from "react"; import APIMethods from '../../lib/axios/api' import { blogTypes } from "../blog/types/blogTypes"; import SentimentDissatisfiedIcon from '@mui/icons-material/SentimentDissatisfied'; +import useSearchStore from "../../lib/store/useSearchStore"; +import SearchedBlogs from "./components/SearchedBlogs"; // const blogs = [ // { @@ -73,6 +75,10 @@ import SentimentDissatisfiedIcon from '@mui/icons-material/SentimentDissatisfied export default function HeroPage() { const [loading,setLoading] = useState(true); + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + const [searchItem ] = useSearchStore(( + state: { searchItem: string; } + ) => [state.searchItem]); const [blogs,setBlogs] = useState([] as unknown as blogTypes[]); const fetchBLogs = async () => { @@ -102,7 +108,7 @@ export default function HeroPage() { className="main" minHeight={"100vh"} direction={"row"} - justifyContent={"space-evenly"} + justifyContent={( (searchItem.length==0))?"space-evenly":"space-between"} position={"relative"} alignItems={"flex-start"} > @@ -113,15 +119,27 @@ export default function HeroPage() { alignItems={"center"} gap={1} borderColor={"#A3A0B2"} + width={( (searchItem.length==0))?"80vw":"100%"} > + { + (searchItem.length!=0) ? + Results for {searchItem} + : + The best from the week The latest industry news, interviews, technologies, and resources. - + + } + + { + (searchItem.length!=0) ?
: + + } - { + {/* { loading ? @@ -157,6 +175,58 @@ export default function HeroPage() { }
+ } */} + + { + loading ? + + + :( + (searchItem.length!=0) ? + + + + : + + {blogs.length!=0 && blogs.map((blog, index) => ( + + ))} + { + (blogs.length==0) && + + No Blogs to show + + + } + + ) } ([]); + const {searchItem} = useSearchStore(); + + const fetchSearchedBlogs = async () => { + try { + setIsLoading(true); + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call + await APIMethods.blog.getBlogsByTag(searchItem).then((res:{data:{blogs:any}}) => { + const blogsRes = res.data.blogs as blogTypes[]; + setBlogs(blogsRes); + console.log("searched blogs",blogsRes); + }); + + } catch (error) { + console.log(error); + } + } + + + useEffect(() => { + fetchSearchedBlogs().then(() => { + console.log("fetching done"); + }).catch((err) => { + console.log(err); + }).finally(() => { + console.log("finally",blogs); + setIsLoading(false); + } + ); + }, [searchItem]) + + useEffect(() => { + if(!blogs || blogs.length === 0) { + return; + } + else + { + setIsLoading(false); + } + }, [blogs]) + + return ( + + { + isLoading ? + + + : + + {blogs.length!=0 && blogs.map((blog, index) => ( + + ))} + + } + { + !isLoading && blogs.length === 0 && No blogs found + } + + ) +} diff --git a/src/layout/headeroptions/HeaderActions.tsx b/src/layout/headeroptions/HeaderActions.tsx index e55c2cf..e2b84bd 100644 --- a/src/layout/headeroptions/HeaderActions.tsx +++ b/src/layout/headeroptions/HeaderActions.tsx @@ -5,8 +5,10 @@ import { Button, CircularProgress, IconButton, + InputAdornment, Popover, Stack, + TextField, } from "@mui/material"; import { Link, useLocation, useNavigate } from "react-router-dom"; import NotificationsIcon from "@mui/icons-material/Notifications"; @@ -23,6 +25,8 @@ import { v4 as uuidv4 } from "uuid"; import Notification from "../../app/notifications/Notification"; import React from "react"; import UserProfile from "../../app/user/UserProfile"; +import SearchIcon from '@mui/icons-material/Search'; +import useSearchStore from "../../lib/store/useSearchStore"; interface userTypes { _id: string; @@ -148,8 +152,37 @@ const AuthorizedActions = () => { setIsSidebarOpen(!isSidebarOpen); }; + const [ setSearch] = useSearchStore((state: any) => [state.setSearch]); + + const handleSearch = (e: any) => { + if (e.key === 'Enter') { + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + setSearch(e.target.value); + } + } + return ( + + + + + , + style: { height: '40px', fontSize: '14px' }, + }} + variant="outlined" + onKeyDown={handleSearch} + sx={{ + width: "350px", + background: "#FAF8FF", + marginRight: "20px", + }} + /> + + {isWriting && (