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);
}