Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export function ColumnRoleFields({
/>
<CustomSelect
id="config-date-column"
label="Date column"
label="Date column (if present)"
hint="Select a field to use as the date for a record."
value={dateColumn}
options={dataSource?.columnDefs.map((cd) => ({
Expand All @@ -50,7 +50,7 @@ export function ColumnRoleFields({
/>
<CustomSelect
id="config-date-format"
label="Date format"
label="Date format (optional)"
hint="Select a date format (if yours is not listed, contact us)."
value={dateFormat}
options={[
Expand Down
9 changes: 8 additions & 1 deletion src/app/map/[id]/colors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ export const useFillColor = ({
selectedBivariateBucket: string | null;
}): DataDrivenPropertyValueSpecification<string> => {
// useMemo to cache calculated fillColor
return useMemo(() => {
const fillColor = useMemo(() => {
if (areaStats?.secondary) {
return getBivariateFillColor(areaStats, selectedBivariateBucket);
}
Expand Down Expand Up @@ -340,6 +340,13 @@ export const useFillColor = ({
...interpolateColorStops,
];
}, [areaStats, viewConfig, selectedBivariateBucket]);

return [
"case",
["!=", ["feature-state", "value"], null],
fillColor,
DEFAULT_FILL_COLOR,
];
};

const getSteppedFillColor = (
Expand Down
24 changes: 13 additions & 11 deletions src/app/map/[id]/components/BoundaryHoverInfo/AreasList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
TableRow,
} from "@/shadcn/ui/table";

import { getDisplayValue } from "./utils";
import { getDisplayValue } from "../../utils/stats";
import type { ColumnType } from "@/server/models/DataSource";
import type { CalculationType } from "@/server/models/MapView";

Expand Down Expand Up @@ -113,18 +113,20 @@ export function AreasList({
: null;

const primaryValue = areaStats
? getDisplayValue(
areaStats.calculationType,
areaStats.primary,
areaStat?.primary,
)
? getDisplayValue(areaStat?.primary, {
calculationType: areaStats.calculationType,
columnType: areaStats.primary?.columnType,
minValue: areaStats.primary?.minValue,
maxValue: areaStats.primary?.maxValue,
})
: null;
const secondaryValue = areaStats
? getDisplayValue(
areaStats.calculationType,
areaStats.secondary,
areaStat?.secondary,
)
? getDisplayValue(areaStat?.secondary, {
calculationType: areaStats.calculationType,
columnType: areaStats.primary?.columnType,
minValue: areaStats.secondary?.minValue,
maxValue: areaStats.secondary?.maxValue,
})
: null;

return (
Expand Down
36 changes: 0 additions & 36 deletions src/app/map/[id]/components/BoundaryHoverInfo/utils.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,3 @@
import { ColumnType } from "@/server/models/DataSource";
import { CalculationType } from "@/server/models/MapView";
import { formatNumber } from "@/utils/text";

export const getDisplayValue = (
calculationType: CalculationType | null | undefined,
areaStats:
| {
columnType: ColumnType;
minValue: number;
maxValue: number;
}
| undefined
| null,
areaStatValue: unknown,
): string => {
if (
areaStatValue === undefined ||
areaStatValue === null ||
areaStatValue === ""
) {
return calculationType === CalculationType.Count ? "0" : "-";
}
if (areaStats?.columnType !== ColumnType.Number) {
return String(areaStatValue);
}
const value = Number(areaStatValue);
if (isNaN(value)) {
return "-";
}
if (areaStats?.minValue >= 0 && areaStats?.maxValue <= 1) {
return `${Math.round(value * 1000) / 10}%`;
}
return formatNumber(value);
};

export const toRGBA = (expressionResult: unknown) => {
if (
!expressionResult ||
Expand Down
1 change: 1 addition & 0 deletions src/app/map/[id]/components/Choropleth/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export default function Choropleth() {

// Custom hooks for effects
const fillColor = useChoroplethFillColor();

const opacity = (viewConfig.choroplethOpacityPct ?? 80) / 100;

const hoverSourceId = `${sourceId}-hover`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export function useChoroplethFeatureStatesEffect() {
useEffect(() => {
const map = mapRef?.current;
if (!areaStats || !map) {
prevAreaStatValues.current = new Map();
return;
Comment on lines 44 to 46
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The removal of the cleanup function from this useEffect could lead to stale state issues. The previous implementation had a cleanup function that reset areaCodesToClean.current and prevAreaStatValues.current when the effect was torn down (component unmount or dependency change).

Now, line 45 only clears prevAreaStatValues.current when !areaStats || !map, but areaCodesToClean.current is never reset. This means:

  1. If the component unmounts and remounts, areaCodesToClean.current will still have old area codes from the previous mount
  2. When dependencies change but the ref persists, old area codes might not be cleaned up properly

Consider either:

  • Restoring the cleanup function to reset both refs
  • Also resetting areaCodesToClean.current on line 45 along with prevAreaStatValues.current

Copilot uses AI. Check for mistakes.
}

Expand Down Expand Up @@ -107,10 +108,5 @@ export function useChoroplethFeatureStatesEffect() {

areaCodesToClean.current = nextAreaCodesToClean;
prevAreaStatValues.current = nextStatValues;

return () => {
areaCodesToClean.current = {};
prevAreaStatValues.current = new Map();
};
}, [areaStats, lastLoadedSourceId, layerId, mapRef, sourceId]);
}
Loading