diff --git a/apps/app/components/core/modals/link-modal.tsx b/apps/app/components/core/modals/link-modal.tsx index fc1641767..bed74fca0 100644 --- a/apps/app/components/core/modals/link-modal.tsx +++ b/apps/app/components/core/modals/link-modal.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useEffect } from "react"; // react-hook-form import { useForm } from "react-hook-form"; @@ -7,12 +7,15 @@ import { Dialog, Transition } from "@headlessui/react"; // ui import { Input, PrimaryButton, SecondaryButton } from "components/ui"; // types -import type { IIssueLink, ModuleLink } from "types"; +import type { IIssueLink, linkDetails, ModuleLink } from "types"; type Props = { isOpen: boolean; handleClose: () => void; - onFormSubmit: (formData: IIssueLink | ModuleLink) => Promise; + data?: linkDetails | null; + status: boolean; + createIssueLink: (formData: IIssueLink | ModuleLink) => Promise; + updateIssueLink: (formData: IIssueLink | ModuleLink, linkId: string) => Promise; }; const defaultValues: IIssueLink | ModuleLink = { @@ -20,7 +23,14 @@ const defaultValues: IIssueLink | ModuleLink = { url: "", }; -export const LinkModal: React.FC = ({ isOpen, handleClose, onFormSubmit }) => { +export const LinkModal: React.FC = ({ + isOpen, + handleClose, + createIssueLink, + updateIssueLink, + status, + data, +}) => { const { register, formState: { errors, isSubmitting }, @@ -30,11 +40,6 @@ export const LinkModal: React.FC = ({ isOpen, handleClose, onFormSubmit } defaultValues, }); - const onSubmit = async (formData: IIssueLink | ModuleLink) => { - await onFormSubmit({ title: formData.title, url: formData.url }); - onClose(); - }; - const onClose = () => { handleClose(); const timeout = setTimeout(() => { @@ -43,6 +48,27 @@ export const LinkModal: React.FC = ({ isOpen, handleClose, onFormSubmit } }, 500); }; + const handleFormSubmit = async (formData: IIssueLink | ModuleLink) => { + if (!data) await createIssueLink({ title: formData.title, url: formData.url }); + else await updateIssueLink({ title: formData.title, url: formData.url }, data.id); + onClose(); + }; + + const handleCreateUpdatePage = async (formData: IIssueLink | ModuleLink) => { + await handleFormSubmit(formData); + + reset({ + ...defaultValues, + }); + }; + + useEffect(() => { + reset({ + ...defaultValues, + ...data, + }); + }, [data, reset]); + return ( @@ -70,14 +96,14 @@ export const LinkModal: React.FC = ({ isOpen, handleClose, onFormSubmit } leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" > -
+
- Add Link + {status ? "Update Link" : "Add Link"}
@@ -113,7 +139,13 @@ export const LinkModal: React.FC = ({ isOpen, handleClose, onFormSubmit }
Cancel - {isSubmitting ? "Adding Link..." : "Add Link"} + {status + ? isSubmitting + ? "Updating Link..." + : "Update Link" + : isSubmitting + ? "Adding Link..." + : "Add Link"}
diff --git a/apps/app/components/core/sidebar/links-list.tsx b/apps/app/components/core/sidebar/links-list.tsx index af008fec4..fb8f3243d 100644 --- a/apps/app/components/core/sidebar/links-list.tsx +++ b/apps/app/components/core/sidebar/links-list.tsx @@ -1,25 +1,24 @@ // icons import { ArrowTopRightOnSquareIcon, LinkIcon, TrashIcon } from "@heroicons/react/24/outline"; +import { Icon } from "components/ui"; // helpers import { timeAgo } from "helpers/date-time.helper"; // types -import { IUserLite, UserAuth } from "types"; +import { linkDetails, UserAuth } from "types"; type Props = { - links: { - id: string; - created_at: Date; - created_by: string; - created_by_detail: IUserLite; - metadata: any; - title: string; - url: string; - }[]; + links: linkDetails[]; handleDeleteLink: (linkId: string) => void; + handleEditLink: (link: linkDetails) => void; userAuth: UserAuth; }; -export const LinksList: React.FC = ({ links, handleDeleteLink, userAuth }) => { +export const LinksList: React.FC = ({ + links, + handleDeleteLink, + handleEditLink, + userAuth, +}) => { const isNotAllowed = userAuth.isGuest || userAuth.isViewer; return ( @@ -28,6 +27,13 @@ export const LinksList: React.FC = ({ links, handleDeleteLink, userAuth }
{!isNotAllowed && (
+ = ({ }) => { const [deleteIssueModal, setDeleteIssueModal] = useState(false); const [linkModal, setLinkModal] = useState(false); + const [selectedLinkToUpdate, setSelectedLinkToUpdate] = useState(null); const router = useRouter(); const { workspaceSlug, projectId, issueId } = router.query; @@ -156,6 +157,43 @@ export const IssueDetailsSidebar: React.FC = ({ }); }; + const handleUpdateLink = async (formData: IIssueLink, linkId: string) => { + if (!workspaceSlug || !projectId || !issueDetail) return; + + const payload = { metadata: {}, ...formData }; + + const updatedLinks = issueDetail.issue_link.map((l) => + l.id === linkId + ? { + ...l, + title: formData.title, + url: formData.url, + } + : l + ); + + mutate( + ISSUE_DETAILS(issueDetail.id), + (prevData) => ({ ...(prevData as IIssue), issue_link: updatedLinks }), + false + ); + + await issuesService + .updateIssueLink( + workspaceSlug as string, + projectId as string, + issueDetail.id, + linkId, + payload + ) + .then((res) => { + mutate(ISSUE_DETAILS(issueDetail.id)); + }) + .catch((err) => { + console.log(err); + }); + }; + const handleDeleteLink = async (linkId: string) => { if (!workspaceSlug || !projectId || !issueDetail) return; @@ -220,14 +258,25 @@ export const IssueDetailsSidebar: React.FC = ({ const maxDate = targetDate ? new Date(targetDate) : null; maxDate?.setDate(maxDate.getDate()); + const handleEditLink = (link: linkDetails) => { + setSelectedLinkToUpdate(link); + setLinkModal(true); + }; + const isNotAllowed = memberRole.isGuest || memberRole.isViewer; return ( <> setLinkModal(false)} - onFormSubmit={handleCreateLink} + handleClose={() => { + setLinkModal(false); + setSelectedLinkToUpdate(null); + }} + data={selectedLinkToUpdate} + status={selectedLinkToUpdate ? true : false} + createIssueLink={handleCreateLink} + updateIssueLink={handleUpdateLink} /> setDeleteIssueModal(false)} @@ -490,6 +539,7 @@ export const IssueDetailsSidebar: React.FC = ({ ) : null} diff --git a/apps/app/components/modules/sidebar.tsx b/apps/app/components/modules/sidebar.tsx index 1e63f960a..0407b95aa 100644 --- a/apps/app/components/modules/sidebar.tsx +++ b/apps/app/components/modules/sidebar.tsx @@ -37,7 +37,7 @@ import { LinkIcon } from "@heroicons/react/20/solid"; import { renderDateFormat, renderShortDateWithYearFormat } from "helpers/date-time.helper"; import { capitalizeFirstLetter, copyTextToClipboard } from "helpers/string.helper"; // types -import { ICurrentUserResponse, IIssue, IModule, ModuleLink } from "types"; +import { ICurrentUserResponse, IIssue, linkDetails, IModule, ModuleLink } from "types"; // fetch-keys import { MODULE_DETAILS } from "constants/fetch-keys"; // constant @@ -61,6 +61,7 @@ type Props = { export const ModuleDetailsSidebar: React.FC = ({ module, isOpen, moduleIssues, user }) => { const [moduleDeleteModal, setModuleDeleteModal] = useState(false); const [moduleLinkModal, setModuleLinkModal] = useState(false); + const [selectedLinkToUpdate, setSelectedLinkToUpdate] = useState(null); const router = useRouter(); const { workspaceSlug, projectId, moduleId } = router.query; @@ -115,6 +116,37 @@ export const ModuleDetailsSidebar: React.FC = ({ module, isOpen, moduleIs }); }; + const handleUpdateLink = async (formData: ModuleLink, linkId: string) => { + if (!workspaceSlug || !projectId || !module) return; + + const payload = { metadata: {}, ...formData }; + + const updatedLinks = module.link_module.map((l) => + l.id === linkId + ? { + ...l, + title: formData.title, + url: formData.url, + } + : l + ); + + mutate( + MODULE_DETAILS(module.id), + (prevData) => ({ ...(prevData as IModule), link_module: updatedLinks }), + false + ); + + await modulesService + .updateModuleLink(workspaceSlug as string, projectId as string, module.id, linkId, payload) + .then((res) => { + mutate(MODULE_DETAILS(module.id)); + }) + .catch((err) => { + console.log(err); + }); + }; + const handleDeleteLink = async (linkId: string) => { if (!workspaceSlug || !projectId || !module) return; @@ -170,12 +202,23 @@ export const ModuleDetailsSidebar: React.FC = ({ module, isOpen, moduleIs ? Math.round((module.completed_issues / module.total_issues) * 100) : null; + const handleEditLink = (link: linkDetails) => { + setSelectedLinkToUpdate(link); + setModuleLinkModal(true); + }; + return ( <> setModuleLinkModal(false)} - onFormSubmit={handleCreateLink} + handleClose={() => { + setModuleLinkModal(false); + setSelectedLinkToUpdate(null); + }} + data={selectedLinkToUpdate} + status={selectedLinkToUpdate ? true : false} + createIssueLink={handleCreateLink} + updateIssueLink={handleUpdateLink} /> = ({ module, isOpen, moduleIs
-
+

Links