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

WIP Undocumented/canvass UI cleanup #2268

Open
wants to merge 8 commits into
base: undocumented/wizard-visits
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export async function GET(request: NextRequest, { params }: RouteMeta) {

const canvassAssignment: ZetkinCanvassAssignment = {
campaign: { id: canvassAssignmentModel.campId },
end_date: canvassAssignmentModel.end_date,
id: canvassAssignmentModel._id.toString(),
metrics: (canvassAssignmentModel.metrics || []).map((metric) => ({
definesDone: metric.definesDone || false,
Expand All @@ -45,6 +46,7 @@ export async function GET(request: NextRequest, { params }: RouteMeta) {
question: metric.question,
})),
organization: { id: orgId },
start_date: canvassAssignmentModel.start_date,
title: canvassAssignmentModel.title,
};

Expand All @@ -64,7 +66,7 @@ export async function PATCH(request: NextRequest, { params }: RouteMeta) {
await mongoose.connect(process.env.MONGODB_URL || '');

const payload = await request.json();
const { metrics: newMetrics, title } = payload;
const { metrics: newMetrics, title, start_date, end_date } = payload;

if (newMetrics) {
// Find existing metrics to remove
Expand Down Expand Up @@ -118,11 +120,30 @@ export async function PATCH(request: NextRequest, { params }: RouteMeta) {
}
}
}
type UpdateFieldsType = Partial<
Pick<ZetkinCanvassAssignment, 'title' | 'start_date' | 'end_date'>
>;

await CanvassAssignmentModel.updateOne(
{ _id: params.canvassAssId },
{ title }
);
const updateFields: UpdateFieldsType = {};

if (title !== null) {
updateFields.title = title;
}

if (Object.prototype.hasOwnProperty.call(payload, 'start_date')) {
updateFields.start_date = start_date;
}

if (Object.prototype.hasOwnProperty.call(payload, 'end_date')) {
updateFields.end_date = end_date;
}

if (Object.keys(updateFields).length > 0) {
await CanvassAssignmentModel.updateOne(
{ _id: params.canvassAssId },
{ $set: updateFields }
);
}
const model = await CanvassAssignmentModel.findById(
params.canvassAssId
).populate('metrics');
Expand All @@ -134,6 +155,7 @@ export async function PATCH(request: NextRequest, { params }: RouteMeta) {
return NextResponse.json({
data: {
campaign: { id: model.campId },
end_date: model.end_date,
id: model._id.toString(),
metrics: (model.metrics || []).map((metric) => ({
definesDone: metric.definesDone || false,
Expand All @@ -143,6 +165,7 @@ export async function PATCH(request: NextRequest, { params }: RouteMeta) {
question: metric.question,
})),
organization: { id: orgId },
start_date: model.start_date,
title: model.title,
},
});
Expand Down
4 changes: 4 additions & 0 deletions src/app/beta/orgs/[orgId]/canvassassignments/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export async function GET(request: NextRequest, { params }: RouteMeta) {
campaign: {
id: assignment.campId,
},
end_date: assignment.end_date,
id: assignment._id.toString(),
metrics: (assignment.metrics || []).map((metric) => ({
definesDone: metric.definesDone || false,
Expand All @@ -38,6 +39,7 @@ export async function GET(request: NextRequest, { params }: RouteMeta) {
organization: {
id: orgId,
},
start_date: assignment.start_date,
title: assignment.title,
})),
});
Expand Down Expand Up @@ -69,6 +71,7 @@ export async function POST(request: NextRequest, { params }: RouteMeta) {
return NextResponse.json({
data: {
campaign: { id: model.campId },
end_date: model.end_date,
id: model._id.toString(),
metrics: model.metrics.map((metric) => ({
definesDone: metric.definesDone || false,
Expand All @@ -78,6 +81,7 @@ export async function POST(request: NextRequest, { params }: RouteMeta) {
question: metric.question,
})),
organization: { id: orgId },
start_date: model.start_date,
title: model.title,
},
});
Expand Down
130 changes: 44 additions & 86 deletions src/features/areas/components/AreasMap/index.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,12 @@
import 'leaflet/dist/leaflet.css';
import { FC, useEffect, useRef, useState } from 'react';
import { MapContainer } from 'react-leaflet';
import {
Add,
Close,
Create,
GpsFixed,
Home,
Remove,
Save,
} from '@mui/icons-material';
import { Close, Create, Save } from '@mui/icons-material';
import {
Autocomplete,
Box,
Button,
ButtonGroup,
CircularProgress,
Divider,
MenuItem,
TextField,
Expand All @@ -32,6 +23,7 @@ import AreaOverlay from '../AreaOverlay';
import MapRenderer from './MapRenderer';
import AreaFilterProvider from '../AreaFilters/AreaFilterContext';
import AreaFilterButton from '../AreaFilters/AreaFilterButton';
import MapControls from 'features/canvassAssignments/components/MapControls';

interface MapProps {
areas: ZetkinArea[];
Expand Down Expand Up @@ -108,6 +100,41 @@ const Map: FC<MapProps> = ({ areas }) => {

const filteredAreas = filterAreas(areas, filterText);

const zoomIn = () => {
mapRef.current?.zoomIn();
};

const zoomOut = () => {
mapRef.current?.zoomOut();
};

const fitBounds = () => {
const map = mapRef.current;
if (map) {
if (areas.length) {
const totalBounds = latLngBounds(
areas[0].points.map((p) => objToLatLng(p))
);

areas.forEach((area) => {
const areaBounds = latLngBounds(
area.points.map((p) => objToLatLng(p))
);
totalBounds.extend(areaBounds);
});

if (totalBounds) {
map.fitBounds(totalBounds, { animate: true });
}
}
}
};

const onLocate = () => ({
locating,
setLocating,
});

return (
<AreaFilterProvider>
<Box
Expand Down Expand Up @@ -206,82 +233,13 @@ const Map: FC<MapProps> = ({ areas }) => {
)}

<Box flexGrow={1} position="relative">
<Box
sx={{
left: 16,
position: 'absolute',
top: 16,
zIndex: 999,
}}
>
<ButtonGroup orientation="vertical" variant="contained">
<Button onClick={() => mapRef.current?.zoomIn()}>
<Add />
</Button>
<Button onClick={() => mapRef.current?.zoomOut()}>
<Remove />
</Button>
<Button
onClick={() => {
const map = mapRef.current;
if (map) {
if (areas.length) {
// Start with first area
const totalBounds = latLngBounds(
areas[0].points.map((p) => objToLatLng(p))
);

// Extend with all areas
areas.forEach((area) => {
const areaBounds = latLngBounds(
area.points.map((p) => objToLatLng(p))
);
totalBounds.extend(areaBounds);
});

if (totalBounds) {
map.fitBounds(totalBounds, { animate: true });
}
}
}
}}
>
<Home />
</Button>
<Button
onClick={() => {
setLocating(true);
navigator.geolocation.getCurrentPosition(
(pos) => {
setLocating(false);

const zoom = 16;
const latLng = {
lat: pos.coords.latitude,
lng: pos.coords.longitude,
};

mapRef.current?.flyTo(latLng, zoom, {
animate: true,
duration: 0.8,
});
},
() => {
// When an error occurs just stop the loading indicator
setLocating(false);
},
{ enableHighAccuracy: true, timeout: 5000 }
);
}}
>
{locating ? (
<CircularProgress color="inherit" size={24} />
) : (
<GpsFixed />
)}
</Button>
</ButtonGroup>
</Box>
<MapControls
mapRef={mapRef}
onFitBounds={fitBounds}
onLocate={onLocate}
onZoomIn={zoomIn}
onZoomOut={zoomOut}
/>
{selectedArea && (
<AreaOverlay
area={editingArea || selectedArea}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { FC } from 'react';
import { Map } from '@mui/icons-material';
import { Map, Person } from '@mui/icons-material';

import { CanvassAssignmentActivity } from 'features/campaigns/types';
import getStatusColor from 'features/campaigns/utils/getStatusColor';
import OverviewListItem from './OverviewListItem';
import useCanvassSessions from 'features/canvassAssignments/hooks/useCanvassSessions';
import getCanvassers from 'features/canvassAssignments/utils/getCanvassers';
import { useNumericRouteParams } from 'core/hooks';

type Props = {
activity: CanvassAssignmentActivity;
Expand All @@ -15,18 +18,26 @@ const CanvassAssignmentOverviewListItem: FC<Props> = ({
focusDate,
}) => {
const assignment = activity.data;
const { orgId } = useNumericRouteParams();

const allSessions = useCanvassSessions(orgId, assignment.id).data || [];
const sessions = allSessions.filter(
(session) => session.assignment.id === assignment.id
);

const canvassers = getCanvassers(sessions);

return (
<OverviewListItem
color={getStatusColor(activity.visibleFrom, activity.visibleUntil)}
endDate={activity.visibleUntil}
endNumber={''}
endNumber={canvassers.length}
focusDate={focusDate}
href={`/organize/${assignment.organization.id}/projects/${
assignment.campaign?.id ?? 'standalone'
}/canvassassignments/${assignment.id}`}
PrimaryIcon={Map}
SecondaryIcon={null}
SecondaryIcon={Person}
startDate={activity.visibleFrom}
statusBar={null}
title={assignment.title || ''}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { FC } from 'react';
import { Map } from '@mui/icons-material';
import { Map, Person } from '@mui/icons-material';

import ActivityListItem, { STATUS_COLORS } from './ActivityListItem';
import useCanvassAssignment from 'features/canvassAssignments/hooks/useCanvassAssignment';
import useCanvassSessions from 'features/canvassAssignments/hooks/useCanvassSessions';
import getCanvassers from 'features/canvassAssignments/utils/getCanvassers';

type Props = {
caId: string;
Expand All @@ -12,21 +14,27 @@ type Props = {
const CanvassAssignmentListItem: FC<Props> = ({ caId, orgId }) => {
const { data: assignment } = useCanvassAssignment(orgId, caId);

const allSessions = useCanvassSessions(orgId, caId).data || [];
const sessions = allSessions.filter(
(session) => session.assignment.id === caId
);

if (!assignment) {
return null;
}

const canvassers = getCanvassers(sessions);
const color = STATUS_COLORS.GRAY;

return (
<ActivityListItem
color={color}
endNumber={''}
endNumber={canvassers.length}
href={`/organize/${orgId}/projects/${
assignment?.campaign?.id ?? 'standalone'
}/canvassassignments/${caId}`}
PrimaryIcon={Map}
SecondaryIcon={Map}
SecondaryIcon={Person}
title={assignment?.title || ''}
/>
);
Expand Down
Loading
Loading