11"use client" ;
22
3- import {
4- ArrowClockwiseIcon ,
5- ArrowLeftIcon ,
6- GlobeIcon ,
7- HeartbeatIcon ,
8- PauseIcon ,
9- PencilIcon ,
10- PlayIcon ,
11- TrashIcon ,
12- } from "@phosphor-icons/react" ;
13- import { keepPreviousData , useMutation , useQuery } from "@tanstack/react-query" ;
14- import dynamic from "next/dynamic" ;
15- import Link from "next/link" ;
16- import { useParams , useRouter } from "next/navigation" ;
17- import { useCallback , useEffect , useMemo , useState } from "react" ;
18- import { toast } from "sonner" ;
193import { MonitorDetailLoading } from "@/app/(main)/monitors/_components/monitor-detail-loading" ;
204import { PageHeader } from "@/app/(main)/websites/_components/page-header" ;
215import { FaviconImage } from "@/components/analytics/favicon-image" ;
226import { EmptyState } from "@/components/empty-state" ;
237import { MonitorSheet } from "@/components/monitors/monitor-sheet" ;
8+ import { TransferToOrgDialog } from "@/components/transfer-to-org-dialog" ;
249import {
2510 AlertDialog ,
2611 AlertDialogAction ,
@@ -40,6 +25,23 @@ import { fromNow, localDayjs } from "@/lib/time";
4025import { LatencyChartChunkPlaceholder } from "@/lib/uptime/latency-chart-chunk-placeholder" ;
4126import { UptimeHeatmap } from "@/lib/uptime/uptime-heatmap" ;
4227import { cn } from "@/lib/utils" ;
28+ import {
29+ ArrowClockwiseIcon ,
30+ ArrowLeftIcon ,
31+ ArrowSquareOutIcon ,
32+ GlobeIcon ,
33+ HeartbeatIcon ,
34+ PauseIcon ,
35+ PencilIcon ,
36+ PlayIcon ,
37+ TrashIcon ,
38+ } from "@phosphor-icons/react" ;
39+ import { keepPreviousData , useMutation , useQuery } from "@tanstack/react-query" ;
40+ import dynamic from "next/dynamic" ;
41+ import Link from "next/link" ;
42+ import { useParams , useRouter } from "next/navigation" ;
43+ import { useCallback , useEffect , useMemo , useState } from "react" ;
44+ import { toast } from "sonner" ;
4345import {
4446 RecentActivity ,
4547 type RecentActivityCheck ,
@@ -72,6 +74,7 @@ const granularityLabels: Record<string, string> = {
7274
7375interface ScheduleData {
7476 id : string ;
77+ organizationId : string ;
7578 websiteId : string | null ;
7679 url : string ;
7780 name : string | null ;
@@ -151,6 +154,7 @@ export default function MonitorDetailsPage() {
151154 const router = useRouter ( ) ;
152155 const { dateRange } = useDateFilters ( ) ;
153156
157+ const [ isTransferOpen , setIsTransferOpen ] = useState ( false ) ;
154158 const [ isSheetOpen , setIsSheetOpen ] = useState ( false ) ;
155159 const [ editingSchedule , setEditingSchedule ] = useState < {
156160 id : string ;
@@ -205,8 +209,9 @@ export default function MonitorDetailsPage() {
205209 const deleteMutation = useMutation ( {
206210 ...orpc . uptime . deleteSchedule . mutationOptions ( ) ,
207211 } ) ;
208- const togglePublicMutation = useMutation ( {
209- ...orpc . statusPage . togglePublicMonitor . mutationOptions ( ) ,
212+
213+ const transferMutation = useMutation ( {
214+ ...orpc . uptime . transfer . mutationOptions ( ) ,
210215 } ) ;
211216
212217 // --- Recent checks (paginated) ---
@@ -470,30 +475,25 @@ export default function MonitorDetailsPage() {
470475 setIsRefreshing ( false ) ;
471476 } ;
472477
473- const handleTogglePublic = async ( ) => {
478+ const handleTransfer = async ( targetOrganizationId : string ) => {
474479 if ( ! schedule ) {
475480 return ;
476481 }
477482 try {
478- const result = await togglePublicMutation . mutateAsync ( {
483+ await transferMutation . mutateAsync ( {
479484 scheduleId : schedule . id ,
480- isPublic : ! schedule . isPublic ,
485+ targetOrganizationId ,
481486 } ) ;
482- await refetchSchedule ( ) ;
483- toast . success (
484- result . isPublic
485- ? "Monitor is now visible on the public status page"
486- : "Monitor removed from the public status page"
487- ) ;
487+ toast . success ( "Monitor transferred successfully" ) ;
488+ setIsTransferOpen ( false ) ;
489+ router . push ( "/monitors" ) ;
488490 } catch ( error ) {
489491 const errorMessage =
490- error instanceof Error ? error . message : "Failed to update visibility " ;
492+ error instanceof Error ? error . message : "Failed to transfer monitor " ;
491493 toast . error ( errorMessage ) ;
492494 }
493495 } ;
494496
495- // --- Render ---
496-
497497 if ( isLoadingSchedule ) {
498498 return < MonitorDetailLoading /> ;
499499 }
@@ -568,21 +568,6 @@ export default function MonitorDetailsPage() {
568568 className = { isRefreshing ? "animate-spin" : "" }
569569 />
570570 </ Button >
571- < Button
572- disabled = { togglePublicMutation . isPending }
573- onClick = { handleTogglePublic }
574- size = "sm"
575- type = "button"
576- variant = { schedule . isPublic ? "default" : "outline" }
577- >
578- < GlobeIcon size = { 16 } weight = "duotone" />
579- < span className = "hidden sm:inline" >
580- { schedule . isPublic ? "Public" : "Make public" }
581- </ span >
582- < span className = "sm:hidden" >
583- { schedule . isPublic ? "Listed" : "List" }
584- </ span >
585- </ Button >
586571 < Button
587572 disabled = {
588573 isPausing || pauseMutation . isPending || resumeMutation . isPending
@@ -614,6 +599,16 @@ export default function MonitorDetailsPage() {
614599 < PencilIcon size = { 16 } weight = "duotone" />
615600 < span className = "hidden sm:inline" > Configure</ span >
616601 </ Button >
602+ < Button
603+ aria-label = "Transfer monitor"
604+ onClick = { ( ) => setIsTransferOpen ( true ) }
605+ size = "sm"
606+ type = "button"
607+ variant = "outline"
608+ >
609+ < ArrowSquareOutIcon size = { 16 } weight = "duotone" />
610+ < span className = "hidden sm:inline" > Transfer</ span >
611+ </ Button >
617612 < Button
618613 aria-label = "Delete monitor"
619614 disabled = { deleteMutation . isPending }
@@ -726,6 +721,17 @@ export default function MonitorDetailsPage() {
726721 />
727722 ) : null }
728723
724+ < TransferToOrgDialog
725+ currentOrganizationId = { schedule . organizationId }
726+ description = { `Move "${ displayName } " to a different workspace.` }
727+ isPending = { transferMutation . isPending }
728+ onOpenChangeAction = { setIsTransferOpen }
729+ onTransferAction = { handleTransfer }
730+ open = { isTransferOpen }
731+ title = "Transfer Monitor"
732+ warning = "All monitoring data and configuration will be transferred to {orgName}."
733+ />
734+
729735 < AlertDialog
730736 onOpenChange = { setIsDeleteDialogOpen }
731737 open = { isDeleteDialogOpen }
0 commit comments