Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Entity pulse effect on rejected submissions #2018

Draft
wants to merge 3 commits into
base: development
Choose a base branch
from
Draft
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 @@ -482,6 +482,8 @@ const SubmissionsTable = ({ toggleView }) => {
projectId: projectId,
reviewState: row?.__system?.reviewState,
taskUid: taskUid,
entity_id: row?.feature,
label: row?.meta?.entity?.label,
}),
);
}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import { UpdateReviewStateService } from '@/api/SubmissionService';
import TextArea from '../common/TextArea';
import Button from '../common/Button';
import { useAppSelector } from '@/types/reduxTypes';
import { PostProjectComments } from '@/api/Project';
import { PostProjectComments, UpdateEntityState } from '@/api/Project';
import { entity_state } from '@/types/enums';

// Note these id values must be camelCase to match what ODK Central requires
const reviewList: reviewListType[] = [
Expand All @@ -23,12 +24,6 @@ const reviewList: reviewListType[] = [
className: 'fmtm-bg-[#E9DFCF] fmtm-text-[#D99F00] fmtm-border-[#D99F00]',
hoverClass: 'hover:fmtm-text-[#D99F00] hover:fmtm-border-[#D99F00]',
},
{
id: 'rejected',
title: 'Rejected',
className: 'fmtm-bg-[#E8D5D5] fmtm-text-[#D73F37] fmtm-border-[#D73F37]',
hoverClass: 'hover:fmtm-text-[#D73F37] hover:fmtm-border-[#D73F37]',
},
];

const UpdateReviewStatusModal = () => {
Expand Down Expand Up @@ -57,6 +52,17 @@ const UpdateReviewStatusModal = () => {
},
),
);

dispatch(
UpdateEntityState(
`${import.meta.env.VITE_API_URL}/projects/${updateReviewStatusModal.projectId}/entity/status`,
{
entity_id: updateReviewStatusModal.entity_id,
status: reviewStatus === 'approved' ? entity_state['SURVEY_SUBMITTED'] : entity_state['MARKED_BAD'],
label: updateReviewStatusModal.label,
},
),
);
}
if (noteComments.trim().length > 0) {
dispatch(
Expand All @@ -79,6 +85,8 @@ const UpdateReviewStatusModal = () => {
taskId: null,
reviewState: '',
taskUid: null,
entity_id: null,
label: null,
}),
);
dispatch(SubmissionActions.UpdateReviewStateLoading(false));
Expand All @@ -91,11 +99,11 @@ const UpdateReviewStatusModal = () => {
<h2 className="!fmtm-text-lg fmtm-font-archivo fmtm-tracking-wide">Update Review Status</h2>
</div>
}
className="!fmtm-w-fit !fmtm-outline-none fmtm-rounded-xl"
className="!fmtm-w-[23rem] !fmtm-outline-none fmtm-rounded-xl"
description={
<div className="fmtm-mt-9">
<div className="fmtm-mb-4">
<div className="fmtm-flex fmtm-justify-between fmtm-gap-2">
<div className="fmtm-flex fmtm-gap-2">
{reviewList.map((reviewBtn) => (
<button
key={reviewBtn.id}
Expand Down Expand Up @@ -131,6 +139,8 @@ const UpdateReviewStatusModal = () => {
taskId: null,
reviewState: '',
taskUid: null,
entity_id: null,
label: null,
}),
);
}}
Expand All @@ -157,6 +167,8 @@ const UpdateReviewStatusModal = () => {
taskId: null,
reviewState: '',
taskUid: null,
entity_id: null,
label: null,
}),
);
}}
Expand Down
2 changes: 2 additions & 0 deletions src/frontend/src/store/slices/SubmissionSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ const initialState: SubmissionStateTypes = {
projectId: null,
reviewState: '',
taskUid: null,
entity_id: null,
label: null,
},
updateReviewStateLoading: false,
mappedVsValidatedTask: [],
Expand Down
2 changes: 2 additions & 0 deletions src/frontend/src/store/types/ISubmissions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ type updateReviewStatusModal = {
projectId: number | null;
reviewState: string;
taskUid: string | null;
entity_id: string | null;
label: string | null;
};

export type filterType = {
Expand Down
2 changes: 2 additions & 0 deletions src/frontend/src/views/SubmissionDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,8 @@ const SubmissionDetails = () => {
taskId: taskId,
reviewState: restSubmissionDetails?.__system?.reviewState,
taskUid: taskUid,
entity_id: restSubmissionDetails?.feature,
label: restSubmissionDetails?.meta?.entity?.label,
}),
);
}}
Expand Down
2 changes: 1 addition & 1 deletion src/mapper/src/lib/components/map/flatgeobuf-layer.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
metadataFunc?: (headerMetadata: HeaderMeta) => void;
promoteId?: string;
children?: Snippet;
processGeojson?: (geojson: GeoJSON) => GeoJSON;
processGeojson?: (geojson: FeatureCollection) => FeatureCollection;
geojsonUpdateDependency?: any;
}

Expand Down
76 changes: 72 additions & 4 deletions src/mapper/src/lib/components/map/main.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
import { polygon } from '@turf/helpers';
import { buffer } from '@turf/buffer';
import { bbox } from '@turf/bbox';
import type { Position, Geometry as GeoJSONGeometry, FeatureCollection } from 'geojson';
import type { Position, Geometry as GeoJSONGeometry, FeatureCollection, Feature } from 'geojson';

import LocationArcImg from '$assets/images/locationArc.png';
import LocationDotImg from '$assets/images/locationDot.png';
Expand Down Expand Up @@ -76,6 +76,8 @@
let selectedBaselayer: string = $state('OSM');
let taskAreaClicked: boolean = $state(false);
let projectSetupStep: number | null = $state(null);
let lineWidth = $state(1); // Initial line width of the rejected entities
let expanding = true; // Whether the line is expanding

// Trigger adding the PMTiles layer to baselayers, if PmtilesUrl is set
let allBaseLayers: maplibregl.StyleSpecification[] = $derived(
Expand Down Expand Up @@ -257,7 +259,7 @@
}
});

function addStatusToGeojsonProperty(geojsonData: FeatureCollection) {
function addStatusToGeojsonProperty(geojsonData: FeatureCollection): FeatureCollection {
return {
...geojsonData,
features: geojsonData.features.map((feature) => {
Expand All @@ -274,6 +276,26 @@
};
}

function getRejectedEntities(geojsonData: FeatureCollection): FeatureCollection {
const rejectedEntityStatusList = entitiesStore.entitiesStatusList.filter(
(entity) => entity.status === 'MARKED_BAD',
);
return {
...geojsonData,
features: rejectedEntityStatusList?.map((entity) => {
const feature = geojsonData.features.find((feature) => feature?.properties?.osm_id === entity.osmid);
return {
...feature,
properties: {
...feature?.properties,
status: entity.status,
entity_id: entity.entity_id,
},
};
}) as Feature[],
};
}

function zoomToProject() {
const taskBuffer = buffer(taskStore.featcol, 5, { units: 'meters' });
if (taskBuffer && map) {
Expand All @@ -296,6 +318,16 @@
await loadOfflinePmtiles(projectId);
selectedBaselayer = 'PMTiles';
}

setInterval(() => {
if (expanding) {
lineWidth += 0.3;
if (lineWidth >= 6) expanding = false; // Maximum width
} else {
lineWidth -= 0.3;
if (lineWidth <= 1) expanding = true; // Minimum width
}
}, 50); // Update every 50ms for smooth animation
});
</script>

Expand Down Expand Up @@ -421,6 +453,8 @@
'#fae15f',
'SURVEY_SUBMITTED',
'#71bf86',
'MARKED_BAD',
'#fa1100',
'#c5fbf5', // default color if no match is found
],
'fill-outline-color': [
Expand All @@ -432,6 +466,8 @@
'#ffd603',
'SURVEY_SUBMITTED',
'#32a852',
'MARKED_BAD',
'#fa1100',
'#c5fbf5',
],
}}
Expand All @@ -442,8 +478,40 @@
layout={{ 'line-cap': 'round', 'line-join': 'round' }}
paint={{
'line-color': '#fa1100',
'line-width': ['case', ['==', ['get', 'osm_id'], entitiesStore.selectedEntity], 1, 0],
'line-opacity': ['case', ['==', ['get', 'osm_id'], entitiesStore.selectedEntity], 1, 0.35],
'line-width': ['case', ['==', ['get', 'osm_id'], entitiesStore.selectedEntity || ''], 1, 0],
'line-opacity': ['case', ['==', ['get', 'osm_id'], entitiesStore.selectedEntity || ''], 1, 0.35],
}}
beforeLayerType="symbol"
manageHoverState
/>
</FlatGeobuf>

<!-- pulse effect layer representing rejected entities -->
<FlatGeobuf
id="rejected-entities"
url={entitiesUrl}
extent={{ type: 'Polygon', coordinates: projectOutlineCoords }}
extractGeomCols={true}
promoteId="id"
processGeojson={(geojsonData) => getRejectedEntities(geojsonData)}
geojsonUpdateDependency={entitiesStore.entitiesStatusList}
>
<FillLayer
id="rejected-entity-fill-layer"
paint={{
'fill-opacity': 0.6,
'fill-color': '#9c9a9a',
'fill-outline-color': '#9c9a9a',
}}
beforeLayerType="symbol"
manageHoverState
/>
<LineLayer
layout={{ 'line-cap': 'round', 'line-join': 'round' }}
paint={{
'line-color': '#fa1100',
'line-width': ['case', ['==', ['get', 'osm_id'], entitiesStore.selectedEntity || ''], 1, lineWidth],
'line-opacity': ['case', ['==', ['get', 'osm_id'], entitiesStore.selectedEntity || ''], 1, 0.35],
}}
beforeLayerType="symbol"
manageHoverState
Expand Down
Loading