Skip to content

Commit

Permalink
feat: add tambah ajuan page
Browse files Browse the repository at this point in the history
  • Loading branch information
chowjustin committed Nov 6, 2024
1 parent b4e3b0e commit 41aa924
Show file tree
Hide file tree
Showing 10 changed files with 1,519 additions and 36 deletions.
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
"@nextui-org/system": "^2.2.6",
"@nextui-org/theme": "^2.2.11",
"@radix-ui/react-dialog": "^1.1.2",
"@react-pdf-viewer/core": "^3.12.0",
"@react-pdf-viewer/default-layout": "^3.12.0",
"@tanstack/react-query": "^5.32.0",
"aos": "^2.3.4",
"auto-zustand-selectors-hook": "^2.0.5",
Expand All @@ -35,12 +37,14 @@
"immer": "^10.1.1",
"next": "14.2.1",
"next-sitemap": "^4.2.3",
"pdfjs-dist": "3.11.174",
"react": "^18",
"react-dom": "^18",
"react-dropzone": "^14.3.5",
"react-hook-form": "^7.51.3",
"react-hot-toast": "^2.4.1",
"react-icons": "^5.1.0",
"react-select": "^5.8.2",
"tailwind-merge": "^2.2.2",
"tailwindcss-animate": "^1.0.7",
"universal-cookie": "^7.1.0",
Expand Down
1,077 changes: 1,065 additions & 12 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

Binary file added public/images/bgbreadcrumb.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 5 additions & 12 deletions src/app/(auth)/signup/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ type SignUpRequest = {
username: string;
email: string;
password: string;
ttd: File | null;
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
file: any;
};

export default function SignUp() {
Expand All @@ -36,23 +37,15 @@ export default function SignUp() {
SignUpRequest
>({
mutationFn: async (data: SignUpRequest) => {
// return await api.post("/users/signup", data);
// return await api.post("/users/signup", data, {
// headers: {
// "Content-Type": "multipart/form-data",
// },
// });
// },
const formData = new FormData();

// Append form fields to the FormData
formData.append("name", data.name);
formData.append("username", data.username);
formData.append("email", data.email);
formData.append("password", data.password);

if (data.ttd) {
formData.append("ttd", data.ttd);
if (data.file && data.file[0]) {
formData.append("file", data.file[0]);
}

return await api.post("/users/signup", formData, {
Expand Down Expand Up @@ -143,7 +136,7 @@ export default function SignUp() {
<div>
<UploadFile
label="Upload File"
id="image"
id="file"
maxSize={2000000}
helperText="Format file .jpeg .jpg .png .pdf, maksimum 2 MB"
validation={{ required: "This field is required" }}
Expand Down
2 changes: 1 addition & 1 deletion src/app/dashboard/profile/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ function Profile() {
Preview TTD
</Typography>
<NextImage
src="/Signify Logo.png"
src={user?.ttd || "/Signify Logo.png"}
width={500}
height={500}
alt="TTD Preview"
Expand Down
216 changes: 215 additions & 1 deletion src/app/dashboard/tambah/page.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,217 @@
"use client";

import {
useForm,
FormProvider,
SubmitHandler,
useWatch,
} from "react-hook-form";
import SelectableInput from "@/components/form/SelectableInput";
import { useRouter } from "next/navigation";
import { AxiosError, AxiosResponse } from "axios";
import { useMutation } from "@tanstack/react-query";
import { ApiError } from "@/types/api";
import api from "@/lib/api";
import toast from "react-hot-toast";
import Typography from "@/components/Typography";
import Input from "@/components/form/Input";
import UploadFile from "@/components/form/UploadFile";
import Button from "@/components/buttons/Button";
import LabelText from "@/components/form/LabelText";
import NextImage from "@/components/NextImage";
import BreadCrumbs from "@/components/BreadCrumbs";
import TextArea from "@/components/form/TextArea";
import "@react-pdf-viewer/core/lib/styles/index.css";
import { Worker, Viewer, SpecialZoomLevel } from "@react-pdf-viewer/core";
import { RenderPageProps } from "@react-pdf-viewer/core";
import { useState } from "react";

type SignUpRequest = {
name: string;
username: string;
email: string;
password: string;
file: FileList | null;
};

const breadCrumbs = [
{ href: "/dashboard", Title: "Dashboard" },
{ href: "/dashboard/profile", Title: "Profil" },
];

export default function TambahAjuan() {
return <div>Tambah Ajuan</div>;
const methods = useForm<SignUpRequest>({ mode: "onChange" });

const { handleSubmit, control } = methods;
const router = useRouter();

// Watch for file upload changes
const file = useWatch({ control, name: "file" });

const [coordinates, setCoordinates] = useState<{
x: number;
y: number;
} | null>(null);

const handlePageClick = (e: React.MouseEvent, page: HTMLElement) => {
if (page instanceof HTMLElement) {
const rect = page.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
setCoordinates({ x, y });
}
};

const renderPage = (props: RenderPageProps) => {
return (
<div
style={{
position: "relative",
display: "flex",
justifyContent: "center",
alignItems: "center",
width: "100%",
height: "100%",
overflow: "hidden",
cursor: "crosshair",
zIndex: 100,
}}
onClick={(e) => handlePageClick(e, e.currentTarget)}
>
{props.canvasLayer.children}
</div>
);
};

const { mutate: SignUpMutation, isPending } = useMutation<
AxiosResponse,
AxiosError<ApiError>,
SignUpRequest
>({
mutationFn: async (data: SignUpRequest) => {
const formData = new FormData();
formData.append("name", data.name);
formData.append("username", data.username);
formData.append("email", data.email);
formData.append("password", data.password);

if (data.file && data.file[0]) {
formData.append("file", data.file[0]);
}

return await api.post("/users/signup", formData, {
headers: { "Content-Type": "multipart/form-data" },
});
},
onSuccess: () => {
toast.success("Berhasil melakukan registrasi!");
},
onError: (err) => {
toast.error(err.message);
},
});

const onSubmit: SubmitHandler<SignUpRequest> = (data) => {
SignUpMutation(data);
};

const fileUrl = file?.[0] ? URL.createObjectURL(file[0]) : null;

return (
<section className="p-6">
<div className="relative w-full h-full rounded-[15px] min-h-[64px] overflow-hidden">
<NextImage
src="/bgbreadcrumb.png"
width={1920}
height={1080}
alt="Background"
className="w-full h-full -z-10 min-h-[64px]"
imgClassName="w-full h-[64px] md:h-[80px]"
/>
<div className="absolute z-10 top-4 left-6 max-md:top-2 max-md:left-3 max-md:mb-0">
<BreadCrumbs breadcrumbs={breadCrumbs} />
<span className="font-semibold text-white max-md:-pt-1">
Tambah Ajuan Tanda Tangan
</span>
</div>
</div>
<div className="flex justify-between gap-6">
<div className="w-[40%]">
<FormProvider {...methods}>
<form
onSubmit={handleSubmit(onSubmit)}
className="flex flex-col w-full mt-6 h-full"
>
<LabelText required>Masukkan Username Tujuan</LabelText>
<div className="space-y-4">
<SelectableInput
id="username"
title="Username"
errorMessage="Username Tujuan harus diisi"
/>
<Input
id="title"
label="Topik"
placeholder="Topik Surat"
validation={{ required: "Topik surat harus diisi" }}
/>
<div>
<UploadFile
label="Upload Surat"
id="file"
maxSize={2000000}
helperText="Format file .pdf, maksimum 2 MB"
validation={{ required: "File surat wajib diupload" }}
/>
</div>
<TextArea
id="coverletter"
label="Cover Letter"
placeholder="Cover Letter"
className="min-h-[200px]"
/>
</div>
{coordinates && (
<div className="mt-4 text-gray-700">
<LabelText>
Selected Coordinates: X: {coordinates.x.toFixed(2)}, Y:{" "}
{coordinates.y.toFixed(2)}
</LabelText>
</div>
)}

<div className="mt-4 w-full flex justify-center overflow-y-auto">
<Button
variant="primary"
type="submit"
onClick={handleSubmit(onSubmit)}
size="base"
className=""
isLoading={isPending}
>
Ajukan
</Button>
</div>
</form>
</FormProvider>
</div>
{/* File Preview */}
<div className="w-[50%] bg-gray-100 h-[80dvh] mt-6 p-4 border-3 border-primary border-dashed rounded-lg overflow-auto">
{fileUrl ? (
<Worker
workerUrl={`https://unpkg.com/[email protected]/build/pdf.worker.min.js`}
>
<Viewer
fileUrl={fileUrl}
defaultScale={SpecialZoomLevel.PageFit}
renderPage={renderPage}
/>
</Worker>
) : (
<p className="text-center text-gray-500">File not uploaded</p>
)}
</div>
</div>
</section>
);
}
2 changes: 1 addition & 1 deletion src/components/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export default function Sidebar({ topNav }: SidenavProps) {
return (
<>
<div
className={`transition-all max-lg:hidden duration-300 ${
className={`transition-all max-lg:hidden duration-300 z-50 ${
isOpen ? "w-full lg:w-[22rem]" : "w-full lg:w-[7rem]"
} h-screen lg:py-8 bg-[#F8F9FA] lg:drop-shadow-2xl`}
>
Expand Down
Loading

0 comments on commit 41aa924

Please sign in to comment.