diff --git a/apps/web/src/components/timeline/AllocationPopover.tsx b/apps/web/src/components/timeline/AllocationPopover.tsx index 96244e7..cfd569a 100644 --- a/apps/web/src/components/timeline/AllocationPopover.tsx +++ b/apps/web/src/components/timeline/AllocationPopover.tsx @@ -2,6 +2,7 @@ import { clsx } from "clsx"; import { useEffect, useRef, useState } from "react"; +import { createPortal } from "react-dom"; import type { AllocationLike, AllocationReadModel, Assignment } from "@capakraken/shared"; import { trpc } from "~/lib/trpc/client.js"; import { useInvalidateTimeline } from "~/hooks/useInvalidatePlanningViews.js"; @@ -89,16 +90,17 @@ export function AllocationPopover({ } if (isLoading || !allocation) { - return ( + const loadingPopover = (
Loading...
); + return typeof document === "undefined" ? loadingPopover : createPortal(loadingPopover, document.body); } const dailyCostEUR = ((hoursPerDay ?? allocation.hoursPerDay) * (allocation.resource?.lcrCents ?? 0) / 100).toFixed(2); - return ( + const popover = (
); + + return typeof document === "undefined" ? popover : createPortal(popover, document.body); } diff --git a/apps/web/src/components/timeline/BatchAssignPopover.tsx b/apps/web/src/components/timeline/BatchAssignPopover.tsx index 034a321..5dd8f84 100644 --- a/apps/web/src/components/timeline/BatchAssignPopover.tsx +++ b/apps/web/src/components/timeline/BatchAssignPopover.tsx @@ -2,6 +2,7 @@ import { clsx } from "clsx"; import { useEffect, useRef, useState } from "react"; +import { createPortal } from "react-dom"; import { AllocationStatus } from "@capakraken/shared"; import { trpc } from "~/lib/trpc/client.js"; import { useInvalidateTimeline } from "~/hooks/useInvalidatePlanningViews.js"; @@ -96,7 +97,7 @@ export function BatchAssignPopover({ const canAssign = !!selectedProjectId && resourceIds.length > 0 && hoursPerDay > 0; - return ( + const popover = (
); + + return typeof document === "undefined" ? popover : createPortal(popover, document.body); } diff --git a/apps/web/src/components/timeline/DemandPopover.tsx b/apps/web/src/components/timeline/DemandPopover.tsx index 42fe775..eeed6f5 100644 --- a/apps/web/src/components/timeline/DemandPopover.tsx +++ b/apps/web/src/components/timeline/DemandPopover.tsx @@ -1,5 +1,6 @@ "use client"; +import { createPortal } from "react-dom"; import type { TimelineDemandEntry } from "./TimelineContext.js"; import { formatCents, formatDateLong } from "~/lib/format.js"; import { useViewportPopover } from "~/hooks/useViewportPopover.js"; @@ -36,7 +37,7 @@ export function DemandPopover({ const totalHours = demand.hoursPerDay * days; const budgetCents = demand.dailyCostCents * days; - return ( + const popover = (
); + + return typeof document === "undefined" ? popover : createPortal(popover, document.body); } diff --git a/apps/web/src/components/timeline/NewAllocationPopover.tsx b/apps/web/src/components/timeline/NewAllocationPopover.tsx index c58e29b..1e1f27c 100644 --- a/apps/web/src/components/timeline/NewAllocationPopover.tsx +++ b/apps/web/src/components/timeline/NewAllocationPopover.tsx @@ -2,6 +2,7 @@ import { clsx } from "clsx"; import { useEffect, useRef, useState } from "react"; +import { createPortal } from "react-dom"; import { AllocationStatus } from "@capakraken/shared"; import { trpc } from "~/lib/trpc/client.js"; import { useInvalidateTimeline } from "~/hooks/useInvalidatePlanningViews.js"; @@ -88,7 +89,7 @@ export function NewAllocationPopover({ const canCreate = !!selectedProjectId && !!start && !!end && hoursPerDay > 0; - return ( + const popover = (
); + + return typeof document === "undefined" ? popover : createPortal(popover, document.body); } diff --git a/apps/web/src/components/timeline/ResourceHoverCard.tsx b/apps/web/src/components/timeline/ResourceHoverCard.tsx index f69539e..b759772 100644 --- a/apps/web/src/components/timeline/ResourceHoverCard.tsx +++ b/apps/web/src/components/timeline/ResourceHoverCard.tsx @@ -1,5 +1,6 @@ "use client"; +import { createPortal } from "react-dom"; import { trpc } from "~/lib/trpc/client.js"; import { formatCents } from "~/lib/format.js"; import type { SkillEntry } from "@capakraken/shared"; @@ -33,7 +34,7 @@ export function ResourceHoverCard({ resourceId, anchorEl, onClose }: ResourceHov .sort((a, b) => b.proficiency - a.proficiency) .slice(0, 6); - return ( + const hoverCard = (
); + + return typeof document === "undefined" ? hoverCard : createPortal(hoverCard, document.body); }