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
39 changes: 29 additions & 10 deletions src/app/map/[id]/components/Markers/DataSourceMarkers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@ export function DataSourceMarkers({
dataSourceMarkers,
isMembers,
mapConfig,
hideFilteredMarkers = false,
}: {
dataSourceMarkers: { dataSourceId: string; markers: MarkerFeature[] };
isMembers: boolean;
mapConfig: {
markerDisplayModes?: Record<string, MarkerDisplayMode>;
markerColors?: Record<string, string>;
};
hideFilteredMarkers?: boolean;
}) {
const { filteredRecords, publicFilters } = useContext(
PublicFiltersContext,
Expand All @@ -40,27 +42,44 @@ export function DataSourceMarkers({
MarkerDisplayMode.Clusters;

const safeMarkers = useMemo<FeatureCollection>(() => {
if (Object.keys(publicFilters).length === 0) {
const hasClientFilters = Object.keys(publicFilters).length > 0;

let features = dataSourceMarkers.markers;

// When hideFilteredMarkers is true, remove server-side unmatched markers
if (hideFilteredMarkers) {
features = features.filter((f) => f.properties.matched !== false);
Comment on lines +49 to +51
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

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

The filter condition f.properties.matched !== false will keep markers where matched is true, undefined, or null. However, when hiding filtered markers, you likely want to only show markers that explicitly match the filter (i.e., matched === true). Consider changing this to f.properties.matched === true to be more precise, unless there's a specific reason to keep markers with undefined/null matched values.

Suggested change
// When hideFilteredMarkers is true, remove server-side unmatched markers
if (hideFilteredMarkers) {
features = features.filter((f) => f.properties.matched !== false);
// When hideFilteredMarkers is true, keep only server-side matched markers
if (hideFilteredMarkers) {
features = features.filter((f) => f.properties.matched === true);

Copilot uses AI. Check for mistakes.
}

if (!hasClientFilters) {
return {
type: "FeatureCollection",
features: dataSourceMarkers.markers,
features,
};
}

const recordIds = (filteredRecords || [])
.map((r: { id: string | number }) => r.id)
.filter(Boolean);

const mappedFeatures = features.map((f) => ({
...f,
properties: {
...f.properties,
[MARKER_CLIENT_EXCLUDED_KEY]: !recordIds.includes(f.properties.id),
},
}));

return {
type: "FeatureCollection",
features: dataSourceMarkers.markers.map((f) => ({
...f,
properties: {
...f.properties,
[MARKER_CLIENT_EXCLUDED_KEY]: !recordIds.includes(f.properties.id),
},
})),
features: mappedFeatures,
};
Comment on lines +65 to 76
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

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

When hideFilteredMarkers is true, the code currently filters out server-side unmatched markers but still includes client-side filtered markers (marked with MARKER_CLIENT_EXCLUDED_KEY). Consider whether client-side filtered markers should also be removed from the map when this setting is enabled, rather than just marked as excluded. This would provide consistent behavior between server-side and client-side filtering.

Copilot uses AI. Check for mistakes.
}, [dataSourceMarkers.markers, filteredRecords, publicFilters]);
}, [
dataSourceMarkers.markers,
filteredRecords,
publicFilters,
hideFilteredMarkers,
]);

const sourceId = `${dataSourceMarkers.dataSourceId}-markers`;
const publicMapColor =
Expand Down
2 changes: 2 additions & 0 deletions src/app/map/[id]/components/Markers/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export default function Markers() {
dataSourceMarkers={memberMarkers}
isMembers
mapConfig={mapConfig}
hideFilteredMarkers={viewConfig.hideFilteredMarkers}
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

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

When passing viewConfig.hideFilteredMarkers to the hideFilteredMarkers prop, consider using the nullish coalescing operator (?? false) or Boolean conversion to handle the case where the value is undefined for existing views that were created before this field was added. While the DataSourceMarkers component has a default parameter value of false, it's better to be explicit and consistent with how optional boolean config values are handled in the codebase.

Copilot uses AI. Check for mistakes.
/>
)}
{otherMarkers.map((markers) => {
Expand All @@ -52,6 +53,7 @@ export default function Markers() {
dataSourceMarkers={markers}
isMembers={false}
mapConfig={mapConfig}
hideFilteredMarkers={viewConfig.hideFilteredMarkers}
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

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

When passing viewConfig.hideFilteredMarkers to the hideFilteredMarkers prop, consider using the nullish coalescing operator (?? false) or Boolean conversion to handle the case where the value is undefined for existing views that were created before this field was added. While the DataSourceMarkers component has a default parameter value of false, it's better to be explicit and consistent with how optional boolean config values are handled in the codebase.

Copilot uses AI. Check for mistakes.
/>
);
})}
Expand Down
23 changes: 23 additions & 0 deletions src/app/map/[id]/components/table/MapTableFilter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { ListFilter, XIcon } from "lucide-react";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useDataSources } from "@/app/map/[id]/hooks/useDataSources";
import { useMapConfig } from "@/app/map/[id]/hooks/useMapConfig";
import { useMapViews } from "@/app/map/[id]/hooks/useMapViews";
import { usePlacedMarkersQuery } from "@/app/map/[id]/hooks/usePlacedMarkers";
import { useTable } from "@/app/map/[id]/hooks/useTable";
import { useTurfsQuery } from "@/app/map/[id]/hooks/useTurfsQuery";
Expand All @@ -19,6 +20,8 @@ import {
CommandList,
} from "@/shadcn/ui/command";
import { Input } from "@/shadcn/ui/input";
import { Label } from "@/shadcn/ui/label";
import { Switch } from "@/shadcn/ui/switch";
import { Toggle } from "@/shadcn/ui/toggle";
import { buildName } from "@/utils/dataRecord";
import { mapColors } from "../../styles";
Expand Down Expand Up @@ -52,6 +55,7 @@ export default function MapTableFilter({

function MultiFilter({ filter, setFilter: _setFilter }: TableFilterProps) {
const { mapConfig } = useMapConfig();
const { viewConfig, updateViewConfig } = useMapViews();
const { data: turfs = [] } = useTurfsQuery();
const { data: placedMarkers = [] } = usePlacedMarkersQuery();
const { getDataSourceById } = useDataSources();
Expand Down Expand Up @@ -215,6 +219,25 @@ function MultiFilter({ filter, setFilter: _setFilter }: TableFilterProps) {
onOperatorChange={updateOperator}
/>
) : null}

{/* Show filtered markers toggle */}
{children.length > 0 ? (
<div className="flex items-center gap-1.5">
<Switch
id="hide-filtered-markers"
checked={Boolean(viewConfig.hideFilteredMarkers)}
onCheckedChange={(checked) =>
updateViewConfig({ hideFilteredMarkers: checked })
}
/>
<Label
htmlFor="hide-filtered-markers"
className="text-xs text-muted-foreground whitespace-nowrap cursor-pointer"
>
Remove filtered from map
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

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

The label text "Remove filtered from map" is grammatically incomplete. Consider using a more complete and clear label such as "Hide filtered records from map" or "Remove filtered records from map" to improve clarity and maintain consistency with professional UI standards.

Suggested change
Remove filtered from map
Hide filtered records from map

Copilot uses AI. Check for mistakes.
</Label>
</div>
) : null}
</div>
</ul>
</div>
Expand Down
1 change: 1 addition & 0 deletions src/app/map/[id]/utils/mapView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@ export const createNewViewConfig = (): MapViewConfig => {
calculationType: DEFAULT_CALCULATION_TYPE,
colorScheme: ColorScheme.RedBlue,
reverseColorScheme: false,
hideFilteredMarkers: true,
};
};
1 change: 1 addition & 0 deletions src/server/models/MapView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ export const mapViewConfigSchema = z.object({
.record(z.string(), z.array(steppedColorStepSchema))
.optional(),
customColor: z.string().optional(),
hideFilteredMarkers: z.boolean().optional(),
});

export type MapViewConfig = z.infer<typeof mapViewConfigSchema>;
Expand Down