2023-12-04 06:41:36 +00:00
import { useCallback , useEffect , useState , ReactElement } from "react" ;
2023-07-13 06:04:37 +00:00
import { useRouter } from "next/router" ;
import useSWR , { mutate } from "swr" ;
import { useForm } from "react-hook-form" ;
// services
2023-12-04 06:41:36 +00:00
import { IssueService , IssueArchiveService } from "services/issue" ;
2023-07-13 06:04:37 +00:00
// hooks
import useToast from "hooks/use-toast" ;
// layouts
2023-12-04 06:41:36 +00:00
import { AppLayout } from "layouts/app-layout" ;
2023-07-13 06:04:37 +00:00
// components
import { IssueDetailsSidebar , IssueMainContent } from "components/issues" ;
2023-12-04 06:41:36 +00:00
import { ProjectArchivedIssueDetailsHeader } from "components/headers" ;
2023-07-13 06:04:37 +00:00
// ui
2023-12-04 06:41:36 +00:00
import { ArchiveIcon , Loader } from "@plane/ui" ;
// icons
import { History } from "lucide-react" ;
2023-07-13 06:04:37 +00:00
// types
import { IIssue } from "types" ;
2023-12-04 06:41:36 +00:00
import { NextPageWithLayout } from "types/app" ;
2023-07-13 06:04:37 +00:00
// fetch-keys
import { PROJECT_ISSUES_ACTIVITY , ISSUE_DETAILS } from "constants/fetch-keys" ;
2023-09-11 09:05:58 +00:00
const defaultValues : Partial < IIssue > = {
2023-07-13 06:04:37 +00:00
name : "" ,
description : "" ,
description_html : "" ,
estimate_point : null ,
state : "" ,
priority : "low" ,
target_date : new Date ( ) . toString ( ) ,
issue_cycle : null ,
issue_module : null ,
} ;
2023-12-04 06:41:36 +00:00
// services
const issueService = new IssueService ( ) ;
const issueArchiveService = new IssueArchiveService ( ) ;
2023-07-19 07:59:08 +00:00
2023-12-04 06:41:36 +00:00
const ArchivedIssueDetailsPage : NextPageWithLayout = ( ) = > {
// router
2023-07-13 06:04:37 +00:00
const router = useRouter ( ) ;
const { workspaceSlug , projectId , archivedIssueId } = router . query ;
2023-12-04 06:41:36 +00:00
// states
const [ isRestoring , setIsRestoring ] = useState ( false ) ;
// hooks
2023-07-13 06:04:37 +00:00
const { setToastAlert } = useToast ( ) ;
const { data : issueDetails , mutate : mutateIssueDetails } = useSWR < IIssue | undefined > (
workspaceSlug && projectId && archivedIssueId ? ISSUE_DETAILS ( archivedIssueId as string ) : null ,
workspaceSlug && projectId && archivedIssueId
? ( ) = >
2023-12-04 06:41:36 +00:00
issueArchiveService . retrieveArchivedIssue (
2023-07-13 06:04:37 +00:00
workspaceSlug as string ,
projectId as string ,
archivedIssueId as string
)
: null
) ;
const { reset , control , watch } = useForm < IIssue > ( {
defaultValues ,
} ) ;
const submitChanges = useCallback (
async ( formData : Partial < IIssue > ) = > {
if ( ! workspaceSlug || ! projectId || ! archivedIssueId ) return ;
mutate < IIssue > (
ISSUE_DETAILS ( archivedIssueId as string ) ,
( prevData ) = > {
if ( ! prevData ) return prevData ;
return {
. . . prevData ,
. . . formData ,
} ;
} ,
false
) ;
const payload : Partial < IIssue > = {
. . . formData ,
} ;
2023-12-04 06:41:36 +00:00
await issueService
. patchIssue ( workspaceSlug as string , projectId as string , archivedIssueId as string , payload )
2023-07-13 06:04:37 +00:00
. then ( ( ) = > {
mutateIssueDetails ( ) ;
mutate ( PROJECT_ISSUES_ACTIVITY ( archivedIssueId as string ) ) ;
} )
. catch ( ( e ) = > {
console . error ( e ) ;
} ) ;
} ,
2023-12-04 06:41:36 +00:00
[ workspaceSlug , archivedIssueId , projectId , mutateIssueDetails ]
2023-07-13 06:04:37 +00:00
) ;
useEffect ( ( ) = > {
if ( ! issueDetails ) return ;
mutate ( PROJECT_ISSUES_ACTIVITY ( archivedIssueId as string ) ) ;
reset ( {
. . . issueDetails ,
} ) ;
} , [ issueDetails , reset , archivedIssueId ] ) ;
const handleUnArchive = async ( ) = > {
if ( ! workspaceSlug || ! projectId || ! archivedIssueId ) return ;
2023-07-19 07:59:08 +00:00
setIsRestoring ( true ) ;
2023-12-04 06:41:36 +00:00
await issueArchiveService
2023-07-13 11:34:24 +00:00
. unarchiveIssue ( workspaceSlug as string , projectId as string , archivedIssueId as string )
2023-07-13 06:04:37 +00:00
. then ( ( ) = > {
setToastAlert ( {
type : "success" ,
2023-07-13 11:34:24 +00:00
title : "Success" ,
message : ` ${ issueDetails ? . project_detail ? . identifier } - ${ issueDetails ? . sequence_id } is restored successfully under the project ${ issueDetails ? . project_detail ? . name } ` ,
2023-07-13 06:04:37 +00:00
} ) ;
router . push ( ` / ${ workspaceSlug } /projects/ ${ projectId } /issues/ ${ archivedIssueId } ` ) ;
} )
. catch ( ( ) = > {
setToastAlert ( {
type : "error" ,
title : "Error!" ,
message : "Something went wrong. Please try again." ,
} ) ;
2023-07-19 07:59:08 +00:00
} )
. finally ( ( ) = > setIsRestoring ( false ) ) ;
2023-07-13 06:04:37 +00:00
} ;
return (
2023-12-04 06:41:36 +00:00
< >
2023-07-13 06:04:37 +00:00
{ issueDetails && projectId ? (
2023-07-19 07:59:08 +00:00
< div className = "flex h-full overflow-hidden" >
< div className = "w-2/3 h-full overflow-y-auto space-y-2 divide-y-2 divide-custom-border-300 p-5" >
2023-07-13 06:04:37 +00:00
{ issueDetails . archived_at && (
< div className = "flex items-center justify-between gap-2 px-2.5 py-2 text-sm border rounded-md text-custom-text-200 border-custom-border-200 bg-custom-background-90" >
< div className = "flex gap-2 items-center" >
2023-12-04 06:41:36 +00:00
< ArchiveIcon className = "h-3.5 w-3.5" / >
2023-07-13 06:04:37 +00:00
< p > This issue has been archived by Plane . < / p >
< / div >
< button
className = "flex items-center gap-2 p-1.5 text-sm rounded-md border border-custom-border-200"
onClick = { handleUnArchive }
2023-07-19 07:59:08 +00:00
disabled = { isRestoring }
2023-07-13 06:04:37 +00:00
>
2023-12-04 06:41:36 +00:00
< History className = "h-3.5 w-3.5" / >
2023-07-19 07:59:08 +00:00
< span > { isRestoring ? "Restoring..." : "Restore Issue" } < / span >
2023-07-13 06:04:37 +00:00
< / button >
< / div >
) }
2023-07-19 07:59:08 +00:00
< div className = "space-y-5 divide-y-2 divide-custom-border-200 opacity-60 pointer-events-none" >
2023-12-04 06:41:36 +00:00
< IssueMainContent issueDetails = { issueDetails } submitChanges = { submitChanges } uneditable / >
2023-07-13 06:04:37 +00:00
< / div >
< / div >
2023-07-19 07:59:08 +00:00
< div className = "w-1/3 h-full space-y-5 border-l border-custom-border-300 p-5 overflow-hidden" >
2023-07-13 06:04:37 +00:00
< IssueDetailsSidebar
control = { control }
issueDetail = { issueDetails }
submitChanges = { submitChanges }
watch = { watch }
2023-07-13 11:34:24 +00:00
uneditable
2023-07-13 06:04:37 +00:00
/ >
< / div >
< / div >
) : (
< Loader className = "flex h-full gap-5 p-5" >
< div className = "basis-2/3 space-y-2" >
< Loader.Item height = "30px" width = "40%" / >
< Loader.Item height = "15px" width = "60%" / >
< Loader.Item height = "15px" width = "60%" / >
< Loader.Item height = "15px" width = "40%" / >
< / div >
< div className = "basis-1/3 space-y-3" >
< Loader.Item height = "30px" / >
< Loader.Item height = "30px" / >
< Loader.Item height = "30px" / >
< Loader.Item height = "30px" / >
< / div >
< / Loader >
) }
2023-12-04 06:41:36 +00:00
< / >
) ;
} ;
ArchivedIssueDetailsPage . getLayout = function getLayout ( page : ReactElement ) {
return (
< AppLayout header = { < ProjectArchivedIssueDetailsHeader / > } withProjectWrapper >
{ page }
< / AppLayout >
2023-07-13 06:04:37 +00:00
) ;
} ;
export default ArchivedIssueDetailsPage ;