Skip to content

Commit

Permalink
✨ feat(profile): add memory cahce search by tag
Browse files Browse the repository at this point in the history
  • Loading branch information
lwinmoepaing committed Oct 23, 2023
1 parent 4112f6e commit 642b9da
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 53 deletions.
20 changes: 9 additions & 11 deletions src/components/Common/Tag/Tag.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,33 @@
import { cn } from "@/utils";
import TitleText from "../TitleText/TitleText";
import { IoClose } from "react-icons/io5";
import { useRouter, useSearchParams } from "next/navigation";
import { checkIsFoundTag } from "@/utils/profileHelper";
import { MouseEvent, useCallback } from "react";
import { IoClose } from "react-icons/io5";
import TitleText from "../TitleText/TitleText";

const Tag = ({
tag,
searchTag,
bgColor,
isShowClose = false,
onClick,
}: {
tag: string;
searchTag: string;
bgColor: string;
isShowClose?: boolean;
onClick?: (tag: string) => void;
}) => {
const searchParams = useSearchParams();
const router = useRouter();
const isTagActive = checkIsFoundTag(tag, searchTag);

const onClickTag = useCallback(
(e: MouseEvent) => {
e.preventDefault();
const tmpSearchParam = new URLSearchParams(searchParams.toString());

tmpSearchParam.set("tag", !isTagActive ? tag : "");

router.push(`/profile?${tmpSearchParam.toString()}`);
onClick?.(tag);
// const tmpSearchParam = new URLSearchParams(searchParams.toString());
// tmpSearchParam.set("tag", !isTagActive ? tag : "");
// router.push(`/profile?${tmpSearchParam.toString()}`);
},
[isTagActive, router, searchParams, tag]
[onClick, tag]
);

return (
Expand Down
82 changes: 41 additions & 41 deletions src/components/Profile/ProfileCardList/ProfileCardList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,41 +4,33 @@ import SpacingDivider from "@/components/Common/SpacingDivider/SpacingDivider";
import Tag from "@/components/Common/Tag/Tag";
import TitleText from "@/components/Common/TitleText/TitleText";
import ProfileCardItem from "@/components/Profile/ProfileCardItem/ProfileCardItem";
import { opacityAnimation } from "@/data/animationVariants";
import { titleFont } from "@/fonts/fonts";
import useProfileHook from "@/hooks/profile/useProfileHook";
import { cn, generateColorArray } from "@/utils/index";
import { profileHelperService } from "@/utils/profileHelper";
import { Profile } from "contentlayer/generated";
import { motion } from "framer-motion";
import { useSearchParams } from "next/navigation";
import { useMemo, useState } from "react";
import { useState } from "react";
import { IoPeople } from "react-icons/io5";
import { motion } from "framer-motion";
import { opacityAnimation } from "@/data/animationVariants";

type TPropsProfileCardList = {
profiles: Profile[];
};

const ProfileCardList = ({ profiles }: TPropsProfileCardList) => {
const searchParams = useSearchParams();
const searchTag = searchParams.get("tag") ?? "";
const { uniqueTags, foundProfiles, searchedTags } = profileHelperService(
profiles,
searchTag
);

const [searchByName, setSearchByName] = useState<string>("");
const [uniqueTagColors] = useState<string[]>(() => {
return generateColorArray(uniqueTags.length);
});

const filteredProfiles = useMemo(() => {
if (!!searchByName.trim().length) {
return foundProfiles.filter((profile) =>
profile.name.toLowerCase().includes(searchByName.toLowerCase())
);
}
return foundProfiles;
}, [foundProfiles, searchByName]);
const initSearchTag = searchParams.get("tag") ?? "";
const {
searchTag,
uniqueTagColors,
uniqueTags,
searchedTags,
filteredProfiles,
searchByName,
handleSearchByName,
handleSearchTag,
} = useProfileHook(profiles, initSearchTag);

return (
<>
Expand All @@ -48,15 +40,21 @@ const ProfileCardList = ({ profiles }: TPropsProfileCardList) => {
transition={{ staggerChildren: 0.005 }}
className="relative"
>
{uniqueTags.map((tag, i) => (
<motion.span
key={tag}
variants={opacityAnimation}
className="inline-block"
>
<Tag tag={tag} searchTag={searchTag} bgColor={uniqueTagColors[i]} />
</motion.span>
))}
{uniqueTagColors?.length &&
uniqueTags.map((tag, i) => (
<motion.span
key={tag}
variants={opacityAnimation}
className="inline-block"
>
<Tag
tag={tag}
searchTag={searchTag}
bgColor={uniqueTagColors[i]}
onClick={handleSearchTag}
/>
</motion.span>
))}
</motion.div>

<div className="flex flex-col gap-3 md:flex-row mt-2 md:items-center">
Expand All @@ -67,21 +65,23 @@ const ProfileCardList = ({ profiles }: TPropsProfileCardList) => {
titleFont.className
)}
value={searchByName}
onChange={(e) => setSearchByName(e.target.value)}
onChange={handleSearchByName}
/>
<TitleText tag="h3" className="text-sm ">
<IoPeople className="inline-block -top-[2px] ml-1 mr-2 relative" />
Total Profiles :{filteredProfiles.length}
</TitleText>

{searchedTags.map((tag, i) => (
<Tag
key={`distincted_${tag}`}
tag={tag}
searchTag={searchTag}
bgColor={uniqueTagColors[i]}
/>
))}
{uniqueTagColors?.length &&
searchedTags.map((tag, i) => (
<Tag
key={`distincted_${tag}`}
tag={tag}
searchTag={searchTag}
bgColor={uniqueTagColors[i]}
onClick={handleSearchTag}
/>
))}
</div>

<SpacingDivider size="lg" />
Expand Down
1 change: 0 additions & 1 deletion src/fonts/fonts.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { PT_Mono, Work_Sans } from "next/font/google";
import localFont from "next/font/local";
// import {} from "next/font"

export const titleFont = PT_Mono({
weight: "400",
Expand Down
3 changes: 3 additions & 0 deletions src/hooks/blog/useBlogHook.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const useBlogHook = () => {
return {};
};
91 changes: 91 additions & 0 deletions src/hooks/profile/useProfileHook.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { generateColorArray } from "@/utils";
import { checkIsFoundTag, profileHelperService } from "@/utils/profileHelper";
import { Profile } from "contentlayer/generated";
import { ChangeEvent, useCallback, useMemo, useState } from "react";

const useProfileHook = (initProfiles: Profile[], initSearchTag: string) => {
const [uniqueTags, setUniqueTags] = useState<string[]>([]);
const [foundProfiles, setFoundProfiles] = useState<Profile[]>([]);
const [searchedTags, setSelectedTags] = useState<string[]>([]);
const [uniqueTagColors, setUniqueTagColors] = useState<string[]>();
const [searchTag, setSearchTag] = useState<string>(initSearchTag);

const [profiles] = useState<Profile[]>(() => {
const expensiveCalculation = profileHelperService(
initProfiles,
initSearchTag
);

setUniqueTags(expensiveCalculation.uniqueTags);

setFoundProfiles(expensiveCalculation.foundProfiles);

setSelectedTags(expensiveCalculation.searchedTags);

setUniqueTagColors(
generateColorArray(expensiveCalculation.uniqueTags.length)
);

return initProfiles;
});

const [searchByName, setSearchByName] = useState<string>("");

const handleSearchByName = useCallback((e: ChangeEvent<HTMLInputElement>) => {
setSearchByName(e.target.value);
}, []);

const handleSearchTag = useCallback(
(tagName: string) => {
const isAlreadySearched = searchedTags.some((tag) =>
checkIsFoundTag(tagName, tag)
);

console.log("isAlreadySearched", isAlreadySearched);
if (isAlreadySearched) {
setSearchTag("");
setSelectedTags((prev) => []);
setFoundProfiles((profile) => profiles);
return;
}

setFoundProfiles((prevFoundProfiles) => {
return profiles.filter((profile) => {
return profile.tags?.some((tag) => checkIsFoundTag(tag, tagName));
});
});

setSelectedTags(
uniqueTags.filter((tag) => checkIsFoundTag(tag, tagName))
);

setSearchTag(tagName);
},
[profiles, searchTag, uniqueTags]
);

const filteredProfiles = useMemo(() => {
const isSetSearchByName = !!searchByName.trim().length;

if (isSetSearchByName) {
return foundProfiles.filter((profile) =>
profile.name.toLowerCase().includes(searchByName.toLowerCase())
);
}
return foundProfiles;
}, [foundProfiles, searchByName]);

return {
searchTag,
uniqueTagColors,
profiles,
searchByName,
foundProfiles,
uniqueTags,
searchedTags,
filteredProfiles,
handleSearchByName,
handleSearchTag,
};
};
export default useProfileHook;

0 comments on commit 642b9da

Please sign in to comment.