diff --git a/components/profile/ProfileButtonAction.tsx b/components/profile/ProfileButtonAction.tsx index 4bed896..9805832 100644 --- a/components/profile/ProfileButtonAction.tsx +++ b/components/profile/ProfileButtonAction.tsx @@ -1,17 +1,21 @@ "use client"; -import React, { useState } from "react"; +import convertJsonProcess from "@/hook/convertJsonProcess"; +import { ProfileAtomDetails } from "@/type"; +import { FormEvent, useCallback, useEffect, useState } from "react"; import { AiOutlineDownload, AiOutlineEye, AiOutlineFileDone, } from "react-icons/ai"; import { BiArrowBack, BiCopy } from "react-icons/bi"; +import { BsFiletypeJson } from "react-icons/bs"; import { toast } from "react-toastify"; type Props = { setIsShow: (value: boolean) => void; setIsMdPreview: (value: boolean) => void; + profileDetails: ProfileAtomDetails; isMdPreview: boolean; }; @@ -19,10 +23,15 @@ function ProfileButtonAction({ setIsShow, setIsMdPreview, isMdPreview, + profileDetails, }: Props) { const [isCopy, setIsCopy] = useState(false); + const [isDownLoad, setIsDownload] = useState(false); - const handleDownloadMarkdown = (event: React.FormEvent) => { + const { processJsonDownloaded, skillLabel, currentPostState } = + convertJsonProcess(); + + const handleDownloadMarkdown = (event: FormEvent) => { event.preventDefault(); if (isMdPreview) { @@ -44,7 +53,7 @@ function ProfileButtonAction({ } }; - const handleCopyToClipboard = (event: React.FormEvent) => { + const handleCopyToClipboard = (event: FormEvent) => { event.preventDefault(); if (isMdPreview) { @@ -65,6 +74,38 @@ function ProfileButtonAction({ } }; + const handleStartProcess = useCallback(() => { + processJsonDownloaded(); + setIsDownload(true); + }, [isDownLoad]); + + const handleDownloadJson = (value: ProfileAtomDetails) => { + if (!value) return; + + const tempElement = document.createElement("a"); + tempElement.setAttribute( + "href", + `data:text/json;charset=utf-8,${encodeURIComponent( + JSON.stringify(value) + )}` + ); + tempElement.setAttribute("download", "data.json"); + tempElement.style.display = "none"; + document.body.appendChild(tempElement); + tempElement.click(); + document.body.removeChild(tempElement); + }; + + useEffect(() => { + if (isDownLoad) { + if (skillLabel.length > 0) { + handleDownloadJson(currentPostState); + } else { + handleDownloadJson(profileDetails); + } + } + }, [currentPostState.skills]); + return (
- {/* */} +
+ )} @@ -110,6 +112,7 @@ function ProfileContent({}: Props) { setIsShow={setIsShow} setIsMdPreview={setIsMdPreview} isMdPreview={isMdPreview} + profileDetails={profileDetails} /> {isMdPreview ? ( - {/* - */} diff --git a/components/profile/process/ConfigOptions.tsx b/components/profile/process/ConfigOptions.tsx new file mode 100644 index 0000000..c07539a --- /dev/null +++ b/components/profile/process/ConfigOptions.tsx @@ -0,0 +1,78 @@ +"use client"; + +import { profileAtomDetail } from "@/atom/profileDetailsAtom"; +import readJson from "@/hook/readJson"; +import updateProfileValue from "@/hook/updateProfileValue"; +import { ProfileAtomDetails } from "@/type"; +import { FormEvent, useCallback, useEffect, useState } from "react"; +import { toast } from "react-toastify"; +import { useRecoilState } from "recoil"; + +import Options from "./components/Options"; + +type Props = {}; + +function ConfigOptions({}: Props) { + const [files, setFiles] = useState(null); + const [fileName, setFileName] = useState(""); + const [updateCurrentState, setUpdateCurrentState] = + useRecoilState(profileAtomDetail); + + const { updateStateValue, currentValue } = readJson(files!); + const { updateProfileStore } = updateProfileValue(); + + const handleChange = (event: React.ChangeEvent) => { + const fileReader = new FileReader(); + + const fileType = event.target.files && event.target.files[0]; + + if (!fileType) return; + + if (fileType.type === "application/json") { + setFileName(fileType.name); + fileReader.readAsText(fileType, "UTF-8"); + fileReader.onload = (event) => { + const jasonData = JSON.parse(event.target?.result as string); + setFiles(jasonData); + }; + } else { + toast.error("This File Type Not Supported"); + setFileName(fileType.name); + } + }; + + const handleProcess = useCallback( + (e: FormEvent) => { + e.preventDefault(); + + if (!files) return; + + if (files.skills.length > 0) { + updateStateValue(); + } else { + updateProfileStore(files, setUpdateCurrentState); + } + }, + [files] + ); + + useEffect(() => { + if (!currentValue) return; + updateProfileStore(currentValue, setUpdateCurrentState); + }, [currentValue]); + + return ( +
+ +
+ ); +} + +export default ConfigOptions; diff --git a/components/profile/process/components/Options.tsx b/components/profile/process/components/Options.tsx new file mode 100644 index 0000000..1564bfd --- /dev/null +++ b/components/profile/process/components/Options.tsx @@ -0,0 +1,127 @@ +"use client"; + +import { ProfileAtomDetails } from "@/type"; +import { motion } from "framer-motion"; +import { FormEvent } from "react"; + +type Props = { + files: ProfileAtomDetails | null; + fileName: string; + setFiles: (value: ProfileAtomDetails | null) => void; + setFileName: (value: string) => void; + handleProcess: (event: FormEvent) => void; + handleChange: (event: React.ChangeEvent) => void; +}; + +function Options({ + files, + fileName, + setFiles, + setFileName, + handleProcess, + handleChange, +}: Props) { + return ( +
+
+

+ Config options +

+

+ Enter the downloaded JSON text to restore +

+
+
+
+ +
+ {files || fileName ? ( +
+
{ + setFiles(null); + setFileName(""); + }} + > + {fileName.includes("json") ? ( + + ) : ( + + )} +

{fileName}

+
+
+ ) : ( + + )} +
+
+

+ File type: json +

+
+ +
+
+
+ ); +} + +export default Options; diff --git a/hook/convertJsonProcess.ts b/hook/convertJsonProcess.ts new file mode 100644 index 0000000..eeaddd6 --- /dev/null +++ b/hook/convertJsonProcess.ts @@ -0,0 +1,44 @@ +import { profileAtomDetail } from "@/atom/profileDetailsAtom"; +import { ProfileAtomDetails } from "@/type"; +import { useCallback, useEffect, useState } from "react"; +import { useRecoilState } from "recoil"; + +interface ElementType { + label: string; + image: string; +} + +function convertJsonProcess() { + const [skillLabel, setSkillLabel] = useState([]); + const [currentState] = useRecoilState(profileAtomDetail); + const [currentPostState, setCurrentPostState] = + useState(currentState); + + const processJsonDownloaded = useCallback(() => { + const labelArr: string[] = []; + + for (let index = 0; index < currentState.skills.length; index++) { + const element: ElementType | any = currentState.skills[index]; + labelArr.push(element.label); + } + + setSkillLabel(labelArr); + }, [currentState.skills]); + + useEffect(() => { + if (!skillLabel) return; + + setCurrentPostState((prev) => ({ + ...prev, + skills: skillLabel, + })); + }, [skillLabel]); + + return { + skillLabel, + currentPostState, + processJsonDownloaded, + }; +} + +export default convertJsonProcess; diff --git a/hook/readJson.ts b/hook/readJson.ts new file mode 100644 index 0000000..b3e70b6 --- /dev/null +++ b/hook/readJson.ts @@ -0,0 +1,48 @@ +import Request from "@/lib/request"; +import { topic } from "@/lib/themesStore"; +import { ProfileAtomDetails, Technologies } from "@/type"; +import { useCallback, useState } from "react"; + +const readJson = (currentStateValue: ProfileAtomDetails) => { + const { skills } = Request(); + const [currentValue, setCurrentValue] = useState( + null + ); + + const skillCustomArr: string[] = []; + const finalData: any[] = []; + + const precessMakDown = () => { + for (let index = 0; index < topic.length; index++) { + const element = topic[index]; + // @ts-ignore + const sortedOneArr = skills[element]; + skillCustomArr.push(sortedOneArr); + } + }; + + const updateStateValue = useCallback(() => { + precessMakDown(); + + setCurrentValue(currentStateValue); + + const flatArr: Technologies[] | any[] = skillCustomArr.flat(); + + if (flatArr.length < 0) return; + + for (let index = 0; index < currentStateValue.skills.length; index++) { + const elements = currentStateValue.skills[index]; + + const filter = flatArr.filter((element) => element.label === elements); + finalData.push(filter); + } + setCurrentValue((prev: any) => ({ + ...prev, + skills: finalData.flat(), + })); + }, [skillCustomArr]); + + return { updateStateValue, currentValue }; +}; + +export default readJson; diff --git a/lib/bin/defaultPostState.ts b/lib/bin/defaultPostState.ts new file mode 100644 index 0000000..1109e98 --- /dev/null +++ b/lib/bin/defaultPostState.ts @@ -0,0 +1,80 @@ +export const defaultPostState = { + profileTitle: "Hi šŸ‘‹, I'm", + profileName: "", + profileSubTitle: "", + working: "šŸ”­ Iā€™m currently working on", + workingName: "", + workingLink: "", + collaborate: "šŸ‘Æ Iā€™m looking to collaborate on", + collaborateName: "", + collaborateLink: "", + learning: "šŸŒ± Iā€™m currently learning", + learningName: "", + about: "šŸ’¬ Ask me about", + aboutName: "", + reach: "šŸ“« How to reach me", + reachName: "", + myProjects: "šŸ‘Øā€šŸ’» All of my projects are available at", + myProjectsName: "", + articles: "šŸ“ I regularly write articles on", + articlesName: "", + experiences: "šŸ“„ Know about my experiences", + experiencesName: "", + fact: "āš” Fun fact", + factName: "", + help: "šŸ¤ Iā€™m looking for help with", + helpName: "", + helpLink: "", + skills: [], + github: "", + dev: "", + codeSandbox: "", + linkedin: "", + facebook: "", + dribbble: "", + hashnode: "", + youtube: "", + hackerrank: "", + leetCode: "", + hackerearth: "", + discord: "", + twitter: "", + codePen: "", + stackoverflow: "", + kaggle: "", + instagram: "", + behance: "", + medium: "", + codeChef: "", + codeforces: "", + topCoder: "", + GFG: "", + RSS: "", + visitors: false, + trophy: false, + stats: false, + skillsCard: false, + streak: false, + buymeacoffee: "", + koFi: "", + trophyTheme: "", + starsTheme: "", + skillCardTheme: "", + skillCardLayout: "compact", + streakTheme: "", + rightHandSideImage: "", + statisticsStars: false, + statisticsTheme: "2077", + summaryCard: false, + summaryCardTheme: "2077", + mostCommit: false, + mostCommitTheme: "2077", + productiveTime: false, + productiveTimeTheme: "2077", + profileDetailsCard: false, + profileDetailsCardTheme: "2077", + activityGraph: false, + activityGraphTheme: "default", + startWelcomeSection: false, + endWelcomeSection: false, +}; diff --git a/hook/bin/languageArr.ts b/lib/bin/languageArr.ts similarity index 100% rename from hook/bin/languageArr.ts rename to lib/bin/languageArr.ts diff --git a/hook/bin/updateState.ts b/lib/bin/updateState.ts similarity index 94% rename from hook/bin/updateState.ts rename to lib/bin/updateState.ts index 2c1eb85..2b93768 100644 --- a/hook/bin/updateState.ts +++ b/lib/bin/updateState.ts @@ -1,4 +1,4 @@ -import { gitImages } from "@/atom/images"; +/* import { gitImages } from "@/atom/images"; import { useEffect } from "react"; import { useRecoilState } from "recoil"; import languageArr from "./languageArr"; @@ -41,10 +41,10 @@ const updateState = () => { } }; - /* useEffect(() => { + useEffect(() => { filterOneByOne(); }, [technology]); - */ + return { updatedLanguageArray, unique, @@ -53,3 +53,4 @@ const updateState = () => { }; export default updateState; + */ diff --git a/lib/request.ts b/lib/request.ts index b86256a..17471a7 100644 --- a/lib/request.ts +++ b/lib/request.ts @@ -26,7 +26,8 @@ const Request = () => { const fetchData = async () => { try { const skills: SkillsType = await fetch( - process.env.NEXT_PUBLIC_SKILL_API_KEY! + "https://globalmusicbeats.github.io/skill/Skills.json" + /* process.env.NEXT_PUBLIC_SKILL_API_KEY! */ ).then((res) => res.json()); setSkills(skills); diff --git a/lib/themesStore.ts b/lib/themesStore.ts index c53982c..fb2e9d0 100644 --- a/lib/themesStore.ts +++ b/lib/themesStore.ts @@ -1094,3 +1094,22 @@ export const activityGraphTheme = [ label: "Arctic", }, ]; + +export const topic = [ + "automation", + "backend", + "backendService", + "database", + "devops", + "engines", + "framework", + "frontend", + "languages", + "mL", + "mobile", + "other", + "software", + "static", + "testing", + "visualization", +];