upload resume

This commit is contained in:
2025-02-09 11:49:20 +08:00
parent a8ff02f26c
commit 47bdb719c2

View File

@@ -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>
<Button <div className="w-full flex flex-col gap-2">
variant="flat" <Input
isDisabled={userProfile.resumeName.length <= 0} value={userProfile.resumeName}
> readOnly
Download className="w-full"
</Button> 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
variant="flat"
isDisabled={userProfile.resumeName.length <= 0}
startContent={<IconDownload size={18} />}
onPress={handleDownloadResume}
>
Download
</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"