upload resume
This commit is contained in:
@@ -5,6 +5,8 @@ import { UserProfile } from "../models/user-profile";
|
|||||||
import { Button, Card, Divider, Input } from "@heroui/react";
|
import { Button, Card, Divider, Input } from "@heroui/react";
|
||||||
import Markdown from "react-markdown";
|
import Markdown from "react-markdown";
|
||||||
import remarkGfm from "remark-gfm";
|
import remarkGfm from "remark-gfm";
|
||||||
|
import { IconDownload, IconUpload } from "@tabler/icons-react";
|
||||||
|
import { toast } from "react-toastify";
|
||||||
|
|
||||||
export default function MemberPage() {
|
export default function MemberPage() {
|
||||||
const accessToken = getAccessToken();
|
const accessToken = getAccessToken();
|
||||||
@@ -12,18 +14,77 @@ export default function MemberPage() {
|
|||||||
|
|
||||||
const [userProfile, setUserProfile] = useState<UserProfile | null>(null);
|
const [userProfile, setUserProfile] = useState<UserProfile | null>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
const getProfile = () => {
|
||||||
if (!accessToken) {
|
|
||||||
window.location.reload();
|
|
||||||
}
|
|
||||||
http.get("/User/profile").then((response) => {
|
http.get("/User/profile").then((response) => {
|
||||||
if (response.status !== 200) {
|
if (response.status !== 200) {
|
||||||
navigate("/error");
|
navigate("/error");
|
||||||
}
|
}
|
||||||
setUserProfile(response.data);
|
setUserProfile(response.data);
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!accessToken) {
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
getProfile();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const handleUploadResume = () => {
|
||||||
|
const fileInput = document.createElement("input");
|
||||||
|
fileInput.type = "file";
|
||||||
|
fileInput.accept = ".pdf,.doc,.docx";
|
||||||
|
fileInput.onchange = async () => {
|
||||||
|
const file = fileInput.files?.[0];
|
||||||
|
if (file) {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append("file", file);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await http.post("/User/upload-resume", formData, {
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "multipart/form-data",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.status === 200) {
|
||||||
|
getProfile();
|
||||||
|
} else {
|
||||||
|
toast.error("Upload failed: " + response);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
toast.error("Error uploading file: " + error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fileInput.click();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDownloadResume = async () => {
|
||||||
|
try {
|
||||||
|
const response = await http.get("/User/resume", {
|
||||||
|
responseType: "blob", // Ensure response is treated as a file
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.status === 200) {
|
||||||
|
if (!userProfile) return;
|
||||||
|
let fileName = userProfile.resumeName;
|
||||||
|
|
||||||
|
const url = window.URL.createObjectURL(new Blob([response.data]));
|
||||||
|
const link = document.createElement("a");
|
||||||
|
link.href = url;
|
||||||
|
link.setAttribute("download", fileName);
|
||||||
|
document.body.appendChild(link);
|
||||||
|
link.click();
|
||||||
|
document.body.removeChild(link);
|
||||||
|
} else {
|
||||||
|
console.error("Failed to download resume", response);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error downloading resume", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="absolute inset-0 w-full h-full flex flex-col justify-center items-center bg-indigo-500/10 dark:bg-indigo-500/20">
|
<div className="absolute inset-0 w-full h-full flex flex-col justify-center items-center bg-indigo-500/10 dark:bg-indigo-500/20">
|
||||||
{userProfile && (
|
{userProfile && (
|
||||||
@@ -48,17 +109,36 @@ export default function MemberPage() {
|
|||||||
/>
|
/>
|
||||||
<div className="flex flex-col gap-2">
|
<div className="flex flex-col gap-2">
|
||||||
<p>Resume</p>
|
<p>Resume</p>
|
||||||
|
<div className="w-full flex flex-col gap-2">
|
||||||
|
<Input
|
||||||
|
value={userProfile.resumeName}
|
||||||
|
readOnly
|
||||||
|
className="w-full"
|
||||||
|
placeholder="No resume uploaded"
|
||||||
|
/>
|
||||||
|
<div className="w-72 flex flex-row gap-2 *:w-full">
|
||||||
|
<Button
|
||||||
|
startContent={<IconUpload size={18} />}
|
||||||
|
onPress={handleUploadResume}
|
||||||
|
variant="flat"
|
||||||
|
>
|
||||||
|
Upload
|
||||||
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant="flat"
|
variant="flat"
|
||||||
isDisabled={userProfile.resumeName.length <= 0}
|
isDisabled={userProfile.resumeName.length <= 0}
|
||||||
|
startContent={<IconDownload size={18} />}
|
||||||
|
onPress={handleDownloadResume}
|
||||||
>
|
>
|
||||||
Download
|
Download
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div className="flex flex-col gap-2">
|
<div className="flex flex-col gap-2">
|
||||||
<p>Who am I</p>
|
<p>Who am I</p>
|
||||||
<Card className="p-4 bg-neutral-500/20 h-full min-w-96">
|
<Card className="p-4 bg-white dark:bg-black h-full min-w-96">
|
||||||
{userProfile.whoAmI.length > 0 ? (
|
{userProfile.whoAmI.length > 0 ? (
|
||||||
<Markdown
|
<Markdown
|
||||||
className="prose dark:prose-invert prose-neutral overflow-auto w-full h-full"
|
className="prose dark:prose-invert prose-neutral overflow-auto w-full h-full"
|
||||||
|
|||||||
Reference in New Issue
Block a user