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

⚙️ Added Config options (#82) #82

Merged
merged 1 commit into from
May 17, 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
59 changes: 50 additions & 9 deletions components/profile/ProfileButtonAction.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,37 @@
"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;
};

function ProfileButtonAction({
setIsShow,
setIsMdPreview,
isMdPreview,
profileDetails,
}: Props) {
const [isCopy, setIsCopy] = useState(false);
const [isDownLoad, setIsDownload] = useState(false);

const handleDownloadMarkdown = (event: React.FormEvent<HTMLFormElement>) => {
const { processJsonDownloaded, skillLabel, currentPostState } =
convertJsonProcess();

const handleDownloadMarkdown = (event: FormEvent) => {
event.preventDefault();

if (isMdPreview) {
Expand All @@ -44,7 +53,7 @@ function ProfileButtonAction({
}
};

const handleCopyToClipboard = (event: React.FormEvent<HTMLFormElement>) => {
const handleCopyToClipboard = (event: FormEvent) => {
event.preventDefault();

if (isMdPreview) {
Expand All @@ -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 (
<div className="flex justify-between items-center py-2.5">
<button
Expand All @@ -75,7 +116,7 @@ function ProfileButtonAction({
<span>Back To Edit</span>
</button>
<button
onClick={(e: any) => handleCopyToClipboard(e)}
onClick={handleCopyToClipboard}
className="bg-gray-700 text-gray-300 hover:bg-slate-600 dark:bg-gray-300 dark:hover:bg-gray-400 dark:text-gray-800 font-bold py-2 px-4 rounded inline-flex items-center gap-2"
>
{isCopy ? (
Expand All @@ -91,19 +132,19 @@ function ProfileButtonAction({
)}
</button>
<button
onClick={(e: any) => handleDownloadMarkdown(e)}
onClick={handleDownloadMarkdown}
className="bg-gray-700 text-gray-300 hover:bg-slate-600 dark:bg-gray-300 dark:hover:bg-gray-400 dark:text-gray-800 font-bold py-2 px-4 rounded inline-flex items-center gap-2"
>
<AiOutlineDownload size={20} />
<span>Download Markdown</span>
</button>
{/* <button
onClick={() => toast.info("This feature will be coming soon")}
<button
onClick={handleStartProcess}
className="bg-gray-700 text-gray-300 hover:bg-slate-600 dark:bg-gray-300 dark:hover:bg-gray-400 dark:text-gray-800 font-bold py-2 px-4 rounded inline-flex items-center gap-2"
>
<AiOutlineSave size={20} />
<BsFiletypeJson size={20} />
<span>Save Markdown</span>
</button> */}
</button>
<button
onClick={() =>
isMdPreview ? setIsMdPreview(false) : setIsMdPreview(true)
Expand Down
5 changes: 4 additions & 1 deletion components/profile/ProfileContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import ProfileFormContainer from "./ProfileFormContainer";
import ProfileHeader from "./ProfileHeader";
import ProfileMarkdown from "./markdown/ProfileMarkdown";
import ProfileMarkdownPreview from "./markdown/ProfileMarkdownPreview";
import ConfigOptions from "./process/ConfigOptions";

type Props = {};

Expand Down Expand Up @@ -95,12 +96,13 @@ function ProfileContent({}: Props) {
<button
disabled={action}
onClick={OnChangeAction}
className="flex justify-center gap-4 bg-gradient-to-r from-green-400 to-blue-500 hover:from-pink-500 hover:to-yellow-500 w-auto rounded-xl text-xl font-bold px-6 py-6 animate-bounce"
className="flex justify-center gap-4 bg-gradient-to-r from-green-400 to-blue-500 hover:from-pink-500 hover:to-yellow-500 w-auto rounded-xl text-xl font-bold px-6 py-6 animate-pulse"
>
Generate File
<AiOutlineDownload size={25} />
</button>
</div>
<ConfigOptions />
</>
)}
</>
Expand All @@ -110,6 +112,7 @@ function ProfileContent({}: Props) {
setIsShow={setIsShow}
setIsMdPreview={setIsMdPreview}
isMdPreview={isMdPreview}
profileDetails={profileDetails}
/>
{isMdPreview ? (
<motion.div
Expand Down
2 changes: 0 additions & 2 deletions components/profile/ProfileFormContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,6 @@ function ProfileFormContainer({ updateCurrentValue, updateAtom }: Props) {
<DividerLine />
<StartAndEnd />
<DividerLine />
{/* <SideBarImage />
<DividerLine /> */}
<AddOns />
<DividerLine />
<Statistics />
Expand Down
78 changes: 78 additions & 0 deletions components/profile/process/ConfigOptions.tsx
Original file line number Diff line number Diff line change
@@ -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<ProfileAtomDetails | null>(null);
const [fileName, setFileName] = useState("");
const [updateCurrentState, setUpdateCurrentState] =
useRecoilState(profileAtomDetail);

const { updateStateValue, currentValue } = readJson(files!);
const { updateProfileStore } = updateProfileValue();

const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
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 (
<div className="w-full">
<Options
files={files}
fileName={fileName}
setFiles={setFiles}
setFileName={setFileName}
handleProcess={handleProcess}
handleChange={handleChange}
/>
</div>
);
}

export default ConfigOptions;
127 changes: 127 additions & 0 deletions components/profile/process/components/Options.tsx
Original file line number Diff line number Diff line change
@@ -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<HTMLInputElement>) => void;
};

function Options({
files,
fileName,
setFiles,
setFileName,
handleProcess,
handleChange,
}: Props) {
return (
<div className="w-full p-10 bg-gradient-to-r from-gray-100 via-gray-200 to-gray-100 dark:bg-gradient-to-r dark:from-[#191a47] dark:via-[#0d0d37] dark:to-[#06375f] rounded-xl z-10">
<div className="text-center">
<h2 className="mt-5 text-3xl font-bold text-gray-900 dark:text-gray-100">
Config options
</h2>
<p className="mt-2 text-sm text-gray-400">
Enter the downloaded JSON text to restore
</p>
</div>
<form className="mt-8 space-y-3" action="#" method="POST">
<div className="grid grid-cols-1 space-y-2">
<label className="text-sm font-bold text-gray-500 tracking-wide">
Attach Json Document
</label>
<div className="flex items-center justify-center w-full">
{files || fileName ? (
<div className="flex flex-col rounded-lg border-4 border-dashed w-full h-60 p-10 group text-center cursor-pointer overflow-hidden items-center">
<div
onClick={() => {
setFiles(null);
setFileName("");
}}
>
{fileName.includes("json") ? (
<motion.img
initial={{ opacity: 0, scale: 0.5 }}
animate={{ opacity: 1, scale: 1 }}
transition={{
duration: 0.8,
delay: 0.5,
ease: [0, 0.71, 0.2, 1.01],
}}
src="https://cdn2.iconfinder.com/data/icons/document-file-fill-outline-1/64/File_Document_Doc_Folder_JSON-512.png"
alt="img"
className="w-36 items-center"
/>
) : (
<motion.img
initial={{ opacity: 0, scale: 0.5 }}
animate={{ opacity: 1, scale: 1 }}
transition={{
duration: 0.8,
delay: 0.5,
ease: [0, 0.71, 0.2, 1.01],
}}
src="https://cdn3.iconfinder.com/data/icons/file-management/32/5_forbidden_ban_no_file_document-512.png"
alt="img"
className="w-36 items-center"
/>
)}
<p>{fileName}</p>
</div>
</div>
) : (
<label className="flex flex-col rounded-lg border-4 border-dashed w-full h-60 p-10 group text-center cursor-pointer">
<motion.div
initial={{ opacity: 0, scale: 0.5 }}
animate={{ opacity: 1, scale: 1 }}
transition={{
duration: 0.8,
delay: 0.5,
ease: [0, 0.71, 0.2, 1.01],
}}
className="h-full w-full text-center flex flex-col justify-center items-center"
>
<div className="flex flex-auto max-h-48 w-2/5 -mt-10 justify-center">
<img
className="has-mask h-36 object-center"
src="https://cosmoindia.in/wp-content/uploads/2020/08/businessgrowth.png"
alt="freepik image"
/>
</div>
<p className="pointer-none text-gray-500 ">
<span className="text-sm">Drag and drop</span> files here{" "}
<br /> or{" "}
<span id="" className="text-blue-600 hover:underline">
select a file
</span>{" "}
from your computer
</p>
</motion.div>
<input type="file" className="hidden" onChange={handleChange} />
</label>
)}
</div>
</div>
<p className="text-sm text-gray-700 dark:text-gray-300">
<span>File type: json</span>
</p>
<div>
<button
onClick={handleProcess}
className="my-5 w-full flex justify-center bg-blue-500 text-gray-100 p-4 rounded-full tracking-wide font-semibold focus:outline-none focus:shadow-outline hover:bg-blue-600 shadow-lg cursor-pointer transition ease-in duration-300"
>
Upload
</button>
</div>
</form>
</div>
);
}

export default Options;
Loading