fix(web): portal timeline overlays above stacked panels
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import { clsx } from "clsx";
|
import { clsx } from "clsx";
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
|
import { createPortal } from "react-dom";
|
||||||
import type { AllocationLike, AllocationReadModel, Assignment } from "@capakraken/shared";
|
import type { AllocationLike, AllocationReadModel, Assignment } from "@capakraken/shared";
|
||||||
import { trpc } from "~/lib/trpc/client.js";
|
import { trpc } from "~/lib/trpc/client.js";
|
||||||
import { useInvalidateTimeline } from "~/hooks/useInvalidatePlanningViews.js";
|
import { useInvalidateTimeline } from "~/hooks/useInvalidatePlanningViews.js";
|
||||||
@@ -89,16 +90,17 @@ export function AllocationPopover({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isLoading || !allocation) {
|
if (isLoading || !allocation) {
|
||||||
return (
|
const loadingPopover = (
|
||||||
<div ref={ref} style={style} className="bg-white border border-gray-200 rounded-xl shadow-xl p-4 text-sm text-gray-500">
|
<div ref={ref} style={style} className="bg-white border border-gray-200 rounded-xl shadow-xl p-4 text-sm text-gray-500">
|
||||||
Loading...
|
Loading...
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
return typeof document === "undefined" ? loadingPopover : createPortal(loadingPopover, document.body);
|
||||||
}
|
}
|
||||||
|
|
||||||
const dailyCostEUR = ((hoursPerDay ?? allocation.hoursPerDay) * (allocation.resource?.lcrCents ?? 0) / 100).toFixed(2);
|
const dailyCostEUR = ((hoursPerDay ?? allocation.hoursPerDay) * (allocation.resource?.lcrCents ?? 0) / 100).toFixed(2);
|
||||||
|
|
||||||
return (
|
const popover = (
|
||||||
<div
|
<div
|
||||||
ref={ref}
|
ref={ref}
|
||||||
style={style}
|
style={style}
|
||||||
@@ -211,4 +213,6 @@ export function AllocationPopover({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return typeof document === "undefined" ? popover : createPortal(popover, document.body);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import { clsx } from "clsx";
|
import { clsx } from "clsx";
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
|
import { createPortal } from "react-dom";
|
||||||
import { AllocationStatus } from "@capakraken/shared";
|
import { AllocationStatus } from "@capakraken/shared";
|
||||||
import { trpc } from "~/lib/trpc/client.js";
|
import { trpc } from "~/lib/trpc/client.js";
|
||||||
import { useInvalidateTimeline } from "~/hooks/useInvalidatePlanningViews.js";
|
import { useInvalidateTimeline } from "~/hooks/useInvalidatePlanningViews.js";
|
||||||
@@ -96,7 +97,7 @@ export function BatchAssignPopover({
|
|||||||
const canAssign =
|
const canAssign =
|
||||||
!!selectedProjectId && resourceIds.length > 0 && hoursPerDay > 0;
|
!!selectedProjectId && resourceIds.length > 0 && hoursPerDay > 0;
|
||||||
|
|
||||||
return (
|
const popover = (
|
||||||
<div
|
<div
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className="fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 z-[60] w-[360px] bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-xl shadow-2xl dark:shadow-black/40 overflow-hidden"
|
className="fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 z-[60] w-[360px] bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-xl shadow-2xl dark:shadow-black/40 overflow-hidden"
|
||||||
@@ -254,4 +255,6 @@ export function BatchAssignPopover({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return typeof document === "undefined" ? popover : createPortal(popover, document.body);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
|
import { createPortal } from "react-dom";
|
||||||
import type { TimelineDemandEntry } from "./TimelineContext.js";
|
import type { TimelineDemandEntry } from "./TimelineContext.js";
|
||||||
import { formatCents, formatDateLong } from "~/lib/format.js";
|
import { formatCents, formatDateLong } from "~/lib/format.js";
|
||||||
import { useViewportPopover } from "~/hooks/useViewportPopover.js";
|
import { useViewportPopover } from "~/hooks/useViewportPopover.js";
|
||||||
@@ -36,7 +37,7 @@ export function DemandPopover({
|
|||||||
const totalHours = demand.hoursPerDay * days;
|
const totalHours = demand.hoursPerDay * days;
|
||||||
const budgetCents = demand.dailyCostCents * days;
|
const budgetCents = demand.dailyCostCents * days;
|
||||||
|
|
||||||
return (
|
const popover = (
|
||||||
<div
|
<div
|
||||||
ref={ref}
|
ref={ref}
|
||||||
style={style}
|
style={style}
|
||||||
@@ -171,4 +172,6 @@ export function DemandPopover({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return typeof document === "undefined" ? popover : createPortal(popover, document.body);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import { clsx } from "clsx";
|
import { clsx } from "clsx";
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
|
import { createPortal } from "react-dom";
|
||||||
import { AllocationStatus } from "@capakraken/shared";
|
import { AllocationStatus } from "@capakraken/shared";
|
||||||
import { trpc } from "~/lib/trpc/client.js";
|
import { trpc } from "~/lib/trpc/client.js";
|
||||||
import { useInvalidateTimeline } from "~/hooks/useInvalidatePlanningViews.js";
|
import { useInvalidateTimeline } from "~/hooks/useInvalidatePlanningViews.js";
|
||||||
@@ -88,7 +89,7 @@ export function NewAllocationPopover({
|
|||||||
|
|
||||||
const canCreate = !!selectedProjectId && !!start && !!end && hoursPerDay > 0;
|
const canCreate = !!selectedProjectId && !!start && !!end && hoursPerDay > 0;
|
||||||
|
|
||||||
return (
|
const popover = (
|
||||||
<div
|
<div
|
||||||
ref={ref}
|
ref={ref}
|
||||||
style={style}
|
style={style}
|
||||||
@@ -238,4 +239,6 @@ export function NewAllocationPopover({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return typeof document === "undefined" ? popover : createPortal(popover, document.body);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
|
import { createPortal } from "react-dom";
|
||||||
import { trpc } from "~/lib/trpc/client.js";
|
import { trpc } from "~/lib/trpc/client.js";
|
||||||
import { formatCents } from "~/lib/format.js";
|
import { formatCents } from "~/lib/format.js";
|
||||||
import type { SkillEntry } from "@capakraken/shared";
|
import type { SkillEntry } from "@capakraken/shared";
|
||||||
@@ -33,7 +34,7 @@ export function ResourceHoverCard({ resourceId, anchorEl, onClose }: ResourceHov
|
|||||||
.sort((a, b) => b.proficiency - a.proficiency)
|
.sort((a, b) => b.proficiency - a.proficiency)
|
||||||
.slice(0, 6);
|
.slice(0, 6);
|
||||||
|
|
||||||
return (
|
const hoverCard = (
|
||||||
<div
|
<div
|
||||||
ref={ref}
|
ref={ref}
|
||||||
data-resource-hover-card="true"
|
data-resource-hover-card="true"
|
||||||
@@ -160,4 +161,6 @@ export function ResourceHoverCard({ resourceId, anchorEl, onClose }: ResourceHov
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return typeof document === "undefined" ? hoverCard : createPortal(hoverCard, document.body);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user