diff --git a/src/app/(auth)/signup/page.tsx b/src/app/(auth)/signup/page.tsx index 8aa5111..d8dcb89 100644 --- a/src/app/(auth)/signup/page.tsx +++ b/src/app/(auth)/signup/page.tsx @@ -128,7 +128,13 @@ export default function SignUp() { id="username" label="Username" placeholder="Username" - validation={{ required: "Username is required" }} + validation={{ + required: "Username is required", + pattern: { + value: /^\S+$/, + message: "Username must not contain spaces", + }, + }} /> { - toast.success("Berhasil menandatangani dokumen!"); setResponse("submitted"); }, onError: (err) => { diff --git a/src/app/dashboard/[id]/modal/modifyModal.tsx b/src/app/dashboard/[id]/modal/modifyModal.tsx index ae5cf83..3be083a 100644 --- a/src/app/dashboard/[id]/modal/modifyModal.tsx +++ b/src/app/dashboard/[id]/modal/modifyModal.tsx @@ -41,7 +41,6 @@ export function ModifyModal({ return await api.patch(`/sign/modify`, updatedData); }, onSuccess: () => { - toast.success("Berhasil menandatangani dokumen di posisi baru!"); setResponse("submitted"); }, onError: (err) => { @@ -131,7 +130,7 @@ export function ModifyModal({ Batal { - toast.success("Berhasil menolak dokumen!"); setResponse("submitted"); }, onError: (err) => { diff --git a/src/app/dashboard/layout.tsx b/src/app/dashboard/layout.tsx index 3add9c3..bdd6f09 100644 --- a/src/app/dashboard/layout.tsx +++ b/src/app/dashboard/layout.tsx @@ -4,7 +4,6 @@ import { ReactNode } from "react"; import { FaRegUser } from "react-icons/fa"; import { FiFileText } from "react-icons/fi"; import { IoHome } from "react-icons/io5"; -import { MdRocketLaunch } from "react-icons/md"; type ChildrenLayoutProps = { children: ReactNode; @@ -12,14 +11,9 @@ type ChildrenLayoutProps = { const NavbarLinks = [ { - title: "Home", + title: "Dashboard", icon: IoHome, - link: "/", - }, - { - title: "Profile", - icon: FaRegUser, - link: "/dashboard/profile", + link: "/dashboard", }, { title: "Tambah Ajuan", @@ -27,9 +21,9 @@ const NavbarLinks = [ link: "/dashboard/tambah", }, { - title: "Dashboard", - icon: MdRocketLaunch, - link: "/dashboard", + title: "Profile", + icon: FaRegUser, + link: "/dashboard/profile", }, ]; diff --git a/src/app/dashboard/settings/modals/deleteUserModal.tsx b/src/app/dashboard/profile/modals/deleteUserModal.tsx similarity index 100% rename from src/app/dashboard/settings/modals/deleteUserModal.tsx rename to src/app/dashboard/profile/modals/deleteUserModal.tsx diff --git a/src/app/dashboard/settings/modals/editEmailModal.tsx b/src/app/dashboard/profile/modals/editEmailModal.tsx similarity index 100% rename from src/app/dashboard/settings/modals/editEmailModal.tsx rename to src/app/dashboard/profile/modals/editEmailModal.tsx diff --git a/src/app/dashboard/settings/modals/editNameModal.tsx b/src/app/dashboard/profile/modals/editNameModal.tsx similarity index 100% rename from src/app/dashboard/settings/modals/editNameModal.tsx rename to src/app/dashboard/profile/modals/editNameModal.tsx diff --git a/src/app/dashboard/settings/modals/editPasswordModal.tsx b/src/app/dashboard/profile/modals/editPasswordModal.tsx similarity index 100% rename from src/app/dashboard/settings/modals/editPasswordModal.tsx rename to src/app/dashboard/profile/modals/editPasswordModal.tsx diff --git a/src/app/dashboard/settings/modals/editTTDModal.tsx b/src/app/dashboard/profile/modals/editTTDModal.tsx similarity index 100% rename from src/app/dashboard/settings/modals/editTTDModal.tsx rename to src/app/dashboard/profile/modals/editTTDModal.tsx diff --git a/src/app/dashboard/settings/modals/editUsernameModal.tsx b/src/app/dashboard/profile/modals/editUsernameModal.tsx similarity index 100% rename from src/app/dashboard/settings/modals/editUsernameModal.tsx rename to src/app/dashboard/profile/modals/editUsernameModal.tsx diff --git a/src/app/dashboard/profile/page.tsx b/src/app/dashboard/profile/page.tsx index dbc161f..b6cc480 100644 --- a/src/app/dashboard/profile/page.tsx +++ b/src/app/dashboard/profile/page.tsx @@ -5,103 +5,142 @@ import BreadCrumbs from "@/components/BreadCrumbs"; import NextImage from "@/components/NextImage"; import Typography from "@/components/Typography"; import withAuth from "@/components/hoc/withAuth"; +import { FaPenToSquare } from "react-icons/fa6"; +import { EditNameModal } from "./modals/editNameModal"; +import { EditUsernameModal } from "./modals/editUsernameModal"; +import { EditEmailModal } from "./modals/editEmailModal"; +import { EditPasswordModal } from "./modals/editPasswordModal"; +import { EditTTDModal } from "./modals/editTTDModal"; +import { DeleteUserModal } from "./modals/deleteUserModal"; +import Button from "@/components/buttons/Button"; const breadCrumbs = [ { href: "/dashboard", Title: "Dashboard" }, - { href: "/dashboard/profile", Title: "Profil" }, + { href: "/dashboard/profile", Title: "Profile" }, ]; -export default withAuth(Profile, "user"); -function Profile() { +export default withAuth(Settings, "user"); +function Settings() { const { user } = useAuthStore(); - const getAccountAge = (createdDate: string): string => { - const createdAt = new Date(createdDate); - const now = new Date(); - - let years = now.getFullYear() - createdAt.getFullYear(); - let months = now.getMonth() - createdAt.getMonth(); - let days = now.getDate() - createdAt.getDate(); - - if (days < 0) { - months -= 1; - days += new Date(now.getFullYear(), now.getMonth(), 0).getDate(); - } - - if (months < 0) { - years -= 1; - months += 12; - } - - return `${years} years ${months} months ${days} days`; - }; - - const accountAge = user?.createdAt ? getAccountAge(user.createdAt) : "N/A"; - return ( -
- -
- - - Profil Anda - -
- -
+
+
-
- - {user?.name} - - - {user?.username} - +
+ + Profile
-
-
- - Email : - - -  {user?.email} - -
-
- - Account Age : +
+
+ + Account Information - -  {accountAge} - -
-
- - Preview TTD - - - TTD Preview +
+ + Nama : {user?.name} + +
+ + {({ openModal }) => ( + + )} + +
+
+
+ + Username : {user?.username} + +
+ + {({ openModal }) => ( + + )} + +
+
+
+ + Email : {user?.email} + +
+ + {({ openModal }) => ( + + )} + +
+
+
+ + Password : ******** + +
+ + {({ openModal }) => ( + + )} + +
+
+
+
+ + Preview TTD + + + {({ openModal }) => ( + + )} + +
+
+ TTD Preview +
+
+
+ + {({ openModal }) => ( + + )} + +
diff --git a/src/app/dashboard/settings/page.tsx b/src/app/dashboard/settings/page.tsx deleted file mode 100644 index 41f2cf4..0000000 --- a/src/app/dashboard/settings/page.tsx +++ /dev/null @@ -1,150 +0,0 @@ -"use client"; - -import useAuthStore from "@/app/stores/useAuthStore"; -import BreadCrumbs from "@/components/BreadCrumbs"; -import NextImage from "@/components/NextImage"; -import Typography from "@/components/Typography"; -import withAuth from "@/components/hoc/withAuth"; -import { FaPenToSquare } from "react-icons/fa6"; -import { EditNameModal } from "./modals/editNameModal"; -import { EditUsernameModal } from "./modals/editUsernameModal"; -import { EditEmailModal } from "./modals/editEmailModal"; -import { EditPasswordModal } from "./modals/editPasswordModal"; -import { EditTTDModal } from "./modals/editTTDModal"; -import { DeleteUserModal } from "./modals/deleteUserModal"; -import Button from "@/components/buttons/Button"; - -const breadCrumbs = [ - { href: "/dashboard", Title: "Dashboard" }, - { href: "/dashboard/settings", Title: "Settings" }, -]; - -export default withAuth(Settings, "user"); -function Settings() { - const { user } = useAuthStore(); - - return ( -
-
- -
- - - Settings - -
-
-
-
- - Account Information - -
- - Nama : {user?.name} - -
- - {({ openModal }) => ( - - )} - -
-
-
- - Username : {user?.username} - -
- - {({ openModal }) => ( - - )} - -
-
-
- - Email : {user?.email} - -
- - {({ openModal }) => ( - - )} - -
-
-
- - Password : ******** - -
- - {({ openModal }) => ( - - )} - -
-
-
-
- - Preview TTD - - - {({ openModal }) => ( - - )} - -
-
- TTD Preview -
-
-
- - {({ openModal }) => ( - - )} - -
-
-
-
- ); -} diff --git a/src/app/dashboard/tambah/page.tsx b/src/app/dashboard/tambah/page.tsx index e516f16..04948a8 100644 --- a/src/app/dashboard/tambah/page.tsx +++ b/src/app/dashboard/tambah/page.tsx @@ -17,6 +17,7 @@ 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 { useEffect, useRef, useState } from "react"; +import useFileStore from "@/app/stores/useFileStore"; type SignUpRequest = { recipient: string; @@ -222,15 +223,27 @@ export default function TambahAjuan() { SignUpMutation(formData); }; + const { isFileDeleted, setIsFileDeleted } = useFileStore(); + const [fileUrl, setFileUrl] = useState(""); // biome-ignore lint/suspicious/noExplicitAny: const handleFileUpload = (files: any) => { if (files.length > 0) { setFileUrl(files[0].preview); + setIsFileDeleted(false); + } else { + setFileUrl(""); + setIsFileDeleted(true); } }; + useEffect(() => { + if (isFileDeleted) { + setFileUrl(""); + } + }, [isFileDeleted]); + return (
@@ -316,6 +329,7 @@ export default function TambahAjuan() { workerUrl={`https://unpkg.com/pdfjs-dist@3.11.174/build/pdf.worker.min.js`} > { + const createdAt = new Date(createdDate); + const now = new Date(); + + let years = now.getFullYear() - createdAt.getFullYear(); + let months = now.getMonth() - createdAt.getMonth(); + let days = now.getDate() - createdAt.getDate(); + + if (days < 0) { + months -= 1; + days += new Date(now.getFullYear(), now.getMonth(), 0).getDate(); + } + + if (months < 0) { + years -= 1; + months += 12; + } + + return `${years} years ${months} months ${days} days`; + }; + + const accountAge = user?.createdAt ? getAccountAge(user.createdAt) : "N/A"; + + return ( +
+ +
+ + + Profil Anda + +
+ +
+ +
+ + {user?.name} + + + {user?.username} + +
+
+
+
+ + Email : + + +  {user?.email} + +
+
+ + Account Age : + + +  {accountAge} + +
+
+ + Preview TTD + + + TTD Preview +
+
+
+ ); +} diff --git a/src/app/landing-page/page.tsx b/src/app/landing-page/page.tsx deleted file mode 100644 index 6e93c55..0000000 --- a/src/app/landing-page/page.tsx +++ /dev/null @@ -1,125 +0,0 @@ -import ButtonLink from "@/components/links/ButtonLink"; -import NextImage from "@/components/NextImage"; -import Typography from "@/components/Typography"; -import Layout from "@/layouts/Layout"; - -import { cn } from "@nextui-org/theme"; - -export default function LandingPage() { - return ( - -
-
- -
- - Discover the power of
our products! -
- - Signify is a streamlined document-signing web application designed - to simplify and accelerate the signing process. With Signify, - users can complete document signing with a single click. Users - upload their documents and send a request to a specified username - for signature approval. The recipient can then easily approve or - reject the request. Upon approval, the document is automatically - signed and promptly returned to the requester, fully signed and - ready for use. Signify’s efficient workflow eliminates the hassle - of manual signatures, providing a secure, fast, and user-friendly - solution for managing document approvals digitally. - - -
- - Sign Up - - - Sign In - -
-
-
-
-
- - Signing has never been easier with us! - - -
- -
- - The Best Digital Signature Adder - -
-
- -
-
- - - © 2024 Signify - -
-
-
- ); -} diff --git a/src/app/stores/useFileStore.tsx b/src/app/stores/useFileStore.tsx new file mode 100644 index 0000000..d2594c7 --- /dev/null +++ b/src/app/stores/useFileStore.tsx @@ -0,0 +1,13 @@ +import { create } from "zustand"; + +interface FileStore { + isFileDeleted: boolean; + setIsFileDeleted: (value: boolean) => void; +} + +const useFileStore = create((set) => ({ + isFileDeleted: false, + setIsFileDeleted: (value: boolean) => set({ isFileDeleted: value }), +})); + +export default useFileStore; diff --git a/src/components/Sidebar.tsx b/src/components/Sidebar.tsx index f3670bb..56c79be 100644 --- a/src/components/Sidebar.tsx +++ b/src/components/Sidebar.tsx @@ -4,12 +4,7 @@ import Link from "next/link"; import { usePathname } from "next/navigation"; import * as React from "react"; import { IconType } from "react-icons"; -import { - FiChevronsLeft, - FiChevronsRight, - FiLogOut, - FiSettings, -} from "react-icons/fi"; +import { FiChevronsLeft, FiChevronsRight, FiLogOut } from "react-icons/fi"; import NextImage from "@/components/NextImage"; import IconButton from "@/components/buttons/IconButton"; import useAuthStore from "@/app/stores/useAuthStore"; @@ -112,7 +107,7 @@ export default function Sidebar({ topNav }: SidenavProps) {
- Pengaturan

- + */} {({ openModal }) => ( @@ -212,14 +207,14 @@ export default function Sidebar({ topNav }: SidenavProps) { ))}
- setIsSheetOpen(false)} >

Pengaturan

- + */}
{ diff --git a/src/components/form/SelectableInput.tsx b/src/components/form/SelectableInput.tsx index f5e1008..56e6ce1 100644 --- a/src/components/form/SelectableInput.tsx +++ b/src/components/form/SelectableInput.tsx @@ -6,6 +6,7 @@ import React, { useState, useEffect, useRef } from "react"; import { useFormContext } from "react-hook-form"; import ErrorMessage from "./ErrorMessage"; import useAuthStore from "@/app/stores/useAuthStore"; +import { FaAngleDown, FaAngleUp } from "react-icons/fa6"; export type SelectableInputProps = { id: string; @@ -26,6 +27,7 @@ const SelectableInput: React.FC = ({ defaultValue || null, ); const [searchTerm, setSearchTerm] = useState(""); + const [isOpen, setIsOpen] = useState(false); const dropdownRef = useRef(null); const { user } = useAuthStore(); @@ -37,7 +39,7 @@ const SelectableInput: React.FC = ({ } = useFormContext(); const { data, isLoading, error } = useQuery({ - queryKey: ["cabang"], + queryKey: ["user"], queryFn: async () => { const response = await api.get("/users/all"); return response.data.data; @@ -61,6 +63,7 @@ const SelectableInput: React.FC = ({ !dropdownRef.current.contains(event.target as Node) ) { setSearchTerm(""); + setIsOpen(false); } }; document.addEventListener("mousedown", handleClickOutside); @@ -73,13 +76,13 @@ const SelectableInput: React.FC = ({ return ( <>
- {/* Search Input Button */} -
+
setSearchTerm(e.target.value)} + onFocus={() => setIsOpen(true)} className={cn( "w-full mt-2 inline-flex items-center gap-x-2 text-sm rounded-[15px]", "h-full w-full rounded-[15px] border border-[#E2E8F0] px-[20px] py-[15px] caret-[#4FD1C5]", @@ -97,8 +100,21 @@ const SelectableInput: React.FC = ({ />
- {/* Options List */} - {searchTerm && filteredData?.length > 0 && ( + + + {isOpen && searchTerm && filteredData?.length > 0 && (
= ({ onClick={() => { setSelectedSize(username); setSearchTerm(""); + setIsOpen(false); + }} + > + {username} +

+ ))} +
+ )} + + {isOpen && !searchTerm && data && ( +
+ {data.map((username: string, id: number) => ( +

{ + setSelectedSize(username); + setSearchTerm(""); + setIsOpen(false); }} > {username} @@ -119,7 +158,6 @@ const SelectableInput: React.FC = ({

)} - {/* No Results Found */} {searchTerm && filteredData?.length === 0 && (

No results found @@ -127,7 +165,6 @@ const SelectableInput: React.FC = ({ )}

- {/* Hidden Input Field for Form Registration */} { const updatedFiles = files.filter((_, i) => i !== index); setFiles(updatedFiles); setValue(id, updatedFiles); + setIsFileDeleted(true); }; React.useEffect(() => {