From f832056b63598f1e8c15a5effa32ae0c128571cb Mon Sep 17 00:00:00 2001
From: Rabi <134292357+Rabi94@users.noreply.github.com>
Date: Thu, 23 Jul 2026 11:56:04 -0300
Subject: [PATCH 1/3] Improve role chip overflow in Family Screen V2
requirements
---
.../src/Families/ApprovalsDataGridV2.tsx | 51 +++++++++++++++++--
1 file changed, 46 insertions(+), 5 deletions(-)
diff --git a/src/caretogether-pwa/src/Families/ApprovalsDataGridV2.tsx b/src/caretogether-pwa/src/Families/ApprovalsDataGridV2.tsx
index 45bf768b..770f7009 100644
--- a/src/caretogether-pwa/src/Families/ApprovalsDataGridV2.tsx
+++ b/src/caretogether-pwa/src/Families/ApprovalsDataGridV2.tsx
@@ -1,5 +1,5 @@
import ChevronRightIcon from '@mui/icons-material/ChevronRight';
-import { Box, Chip, Typography, useTheme } from '@mui/material';
+import { Box, Chip, Tooltip, Typography, useTheme } from '@mui/material';
import { DataGrid, GridColDef, GridToolbar } from '@mui/x-data-grid';
import { useRef } from 'react';
import { useUserLookup } from '../Model/DirectoryModel';
@@ -22,14 +22,28 @@ type ApprovalsDataGridV2Props = {
rows: ApprovalLedgerRow[];
};
-function ChipList({ labels }: { labels: string[] }) {
+const MAX_VISIBLE_ROLE_CHIPS = 3;
+
+function OverflowRoleChipList({ labels }: { labels: string[] }) {
if (labels.length === 0) {
return -;
}
+ const visibleLabels = labels.slice(0, MAX_VISIBLE_ROLE_CHIPS);
+ const hiddenLabels = labels.slice(MAX_VISIBLE_ROLE_CHIPS);
+
return (
-
- {labels.map((label) => (
+
+ {visibleLabels.map((label) => (
))}
+ {hiddenLabels.length > 0 && (
+
+ {hiddenLabels.map((label) => (
+
+ {label}
+
+ ))}
+
+ }
+ >
+
+
+ )}
);
}
@@ -128,7 +169,7 @@ function buildColumns(
flex: 0.9,
valueGetter: (_value, row) => row.neededForRoleLabels.join(', '),
renderCell: ({ row }) => (
-
+
),
},
{
From 3617afedbcb0e66c193ac8e9bfd909e9bed212bc Mon Sep 17 00:00:00 2001
From: PabloDinella
Date: Wed, 29 Jul 2026 12:07:47 -0300
Subject: [PATCH 2/3] Show needed role tooltip on chip list
---
.../src/Families/ApprovalsDataGridV2.tsx | 63 +++++++++++--------
1 file changed, 37 insertions(+), 26 deletions(-)
diff --git a/src/caretogether-pwa/src/Families/ApprovalsDataGridV2.tsx b/src/caretogether-pwa/src/Families/ApprovalsDataGridV2.tsx
index 770f7009..ee155a39 100644
--- a/src/caretogether-pwa/src/Families/ApprovalsDataGridV2.tsx
+++ b/src/caretogether-pwa/src/Families/ApprovalsDataGridV2.tsx
@@ -29,11 +29,28 @@ function OverflowRoleChipList({ labels }: { labels: string[] }) {
return -;
}
+ const hasRoleTooltip = labels.length > 1;
const visibleLabels = labels.slice(0, MAX_VISIBLE_ROLE_CHIPS);
const hiddenLabels = labels.slice(MAX_VISIBLE_ROLE_CHIPS);
+ const roleTooltipTitle = (
+
+ {labels.map((label) => (
+
+ {label}
+
+ ))}
+
+ );
- return (
+ const chipList = (
{visibleLabels.map((label) => (
@@ -53,34 +71,27 @@ function OverflowRoleChipList({ labels }: { labels: string[] }) {
/>
))}
{hiddenLabels.length > 0 && (
-
- {hiddenLabels.map((label) => (
-
- {label}
-
- ))}
-
- }
- >
-
-
+
)}
);
+
+ if (!hasRoleTooltip) {
+ return chipList;
+ }
+
+ return (
+
+ {chipList}
+
+ );
}
function AppliesToChips({ row }: { row: ApprovalLedgerRow }) {
From b83a92750aa04538f1458c52b2fa53515ff40558 Mon Sep 17 00:00:00 2001
From: PabloDinella
Date: Wed, 29 Jul 2026 13:28:56 -0300
Subject: [PATCH 3/3] Show hidden role count by cell width
---
.../src/Families/ApprovalsDataGridV2.tsx | 187 ++++++++++++++++--
1 file changed, 167 insertions(+), 20 deletions(-)
diff --git a/src/caretogether-pwa/src/Families/ApprovalsDataGridV2.tsx b/src/caretogether-pwa/src/Families/ApprovalsDataGridV2.tsx
index ee155a39..2ba94a7d 100644
--- a/src/caretogether-pwa/src/Families/ApprovalsDataGridV2.tsx
+++ b/src/caretogether-pwa/src/Families/ApprovalsDataGridV2.tsx
@@ -1,7 +1,7 @@
import ChevronRightIcon from '@mui/icons-material/ChevronRight';
import { Box, Chip, Tooltip, Typography, useTheme } from '@mui/material';
import { DataGrid, GridColDef, GridToolbar } from '@mui/x-data-grid';
-import { useRef } from 'react';
+import { useCallback, useLayoutEffect, useRef, useState } from 'react';
import { useUserLookup } from '../Model/DirectoryModel';
import { PersonName } from './PersonName';
import type { ApprovalLedgerRow } from './approvalLedgerViewModel';
@@ -22,16 +22,120 @@ type ApprovalsDataGridV2Props = {
rows: ApprovalLedgerRow[];
};
-const MAX_VISIBLE_ROLE_CHIPS = 3;
-
function OverflowRoleChipList({ labels }: { labels: string[] }) {
+ const chipListRef = useRef(null);
+ const chipStripRef = useRef(null);
+ const moreIndicatorMeasurementsRef = useRef(null);
+ const moreIndicatorRef = useRef(null);
+ const [widthHiddenLabelCount, setWidthHiddenLabelCount] = useState(0);
+
+ const measureWidthOverflow = useCallback(() => {
+ const chipList = chipListRef.current;
+ const chipStrip = chipStripRef.current;
+ const moreIndicatorMeasurements = moreIndicatorMeasurementsRef.current;
+
+ if (!chipList || !chipStrip || !moreIndicatorMeasurements) {
+ return;
+ }
+
+ const chipListWidth = chipList.clientWidth;
+ const chipWidths = Array.from(chipStrip.children).flatMap((child) =>
+ child instanceof HTMLElement ? [child.offsetWidth] : []
+ );
+ const gap = parseFloat(window.getComputedStyle(chipList).columnGap) || 0;
+ const totalChipWidth =
+ chipWidths.reduce((total, width) => total + width, 0) +
+ Math.max(0, chipWidths.length - 1) * gap;
+
+ if (totalChipWidth <= Math.ceil(chipListWidth)) {
+ setWidthHiddenLabelCount(0);
+ return;
+ }
+
+ const moreIndicatorWidth = (hiddenLabelCount: number) => {
+ const measurement = moreIndicatorMeasurements.querySelector(
+ `[data-hidden-label-count="${hiddenLabelCount}"]`
+ );
+
+ if (!(measurement instanceof HTMLElement)) {
+ return 0;
+ }
+
+ return measurement.offsetWidth;
+ };
+ const chipWidthSums = chipWidths.reduce(
+ (widthSums, chipWidth) => [
+ ...widthSums,
+ widthSums[widthSums.length - 1] + chipWidth,
+ ],
+ [0]
+ );
+
+ for (
+ let visibleChipCount = labels.length - 1;
+ visibleChipCount >= 0;
+ visibleChipCount -= 1
+ ) {
+ const hiddenLabelCount = labels.length - visibleChipCount;
+ const visibleChipGapCount = Math.max(0, visibleChipCount - 1);
+ const indicatorGapCount = visibleChipCount > 0 ? 1 : 0;
+ const requiredWidth =
+ chipWidthSums[visibleChipCount] +
+ visibleChipGapCount * gap +
+ indicatorGapCount * gap +
+ moreIndicatorWidth(hiddenLabelCount);
+
+ if (requiredWidth <= Math.ceil(chipListWidth)) {
+ setWidthHiddenLabelCount(hiddenLabelCount);
+ return;
+ }
+ }
+
+ setWidthHiddenLabelCount(labels.length);
+ }, [labels.length]);
+
+ useLayoutEffect(() => {
+ measureWidthOverflow();
+
+ const chipList = chipListRef.current;
+ const chipStrip = chipStripRef.current;
+
+ if (!chipList || !chipStrip) {
+ return;
+ }
+
+ const animationFrame = window.requestAnimationFrame(measureWidthOverflow);
+
+ if (typeof ResizeObserver === 'undefined') {
+ window.addEventListener('resize', measureWidthOverflow);
+
+ return () => {
+ window.cancelAnimationFrame(animationFrame);
+ window.removeEventListener('resize', measureWidthOverflow);
+ };
+ }
+
+ const resizeObserver = new ResizeObserver(measureWidthOverflow);
+ resizeObserver.observe(chipList);
+ resizeObserver.observe(chipStrip);
+
+ if (moreIndicatorRef.current) {
+ resizeObserver.observe(moreIndicatorRef.current);
+ }
+
+ return () => {
+ window.cancelAnimationFrame(animationFrame);
+ resizeObserver.disconnect();
+ };
+ }, [labels, measureWidthOverflow]);
+
if (labels.length === 0) {
return -;
}
const hasRoleTooltip = labels.length > 1;
- const visibleLabels = labels.slice(0, MAX_VISIBLE_ROLE_CHIPS);
- const hiddenLabels = labels.slice(MAX_VISIBLE_ROLE_CHIPS);
+ const hiddenLabelCount = widthHiddenLabelCount;
+ const hasMoreIndicator = hiddenLabelCount > 0;
const roleTooltipTitle = (
{labels.map((label) => (
@@ -48,34 +152,77 @@ function OverflowRoleChipList({ labels }: { labels: string[] }) {
const chipList = (
- {visibleLabels.map((label) => (
- {label}}
- size="small"
- variant="outlined"
- />
- ))}
- {hiddenLabels.length > 0 && (
+
+ {labels.map((_label, index) => {
+ const hiddenLabelCount = index + 1;
+
+ return (
+
+ );
+ })}
+
+
+ {labels.map((label) => (
+ {label}
+ }
+ size="small"
+ sx={{ flex: '0 0 auto' }}
+ variant="outlined"
+ />
+ ))}
+
+ {hasMoreIndicator && (