Skip to content
Open
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
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ Tracks are lazy-loaded and cached, socket status updates prepend new positions o
**UI**
- **Patrols Feed** (`/patrols`): the patrol list, ordered start_overdue → ready_to_start → paused → active → scheduled → done → cancelled, with inline actions per row (start, resume, restore). Filters: text search, date range, patrol type, tracked-by, and status.
- **New Patrol** (`/patrols/new`): the leg form. Creating a patrol means creating its first leg, so this is the same form the leg routes use, with the patrol's title and type set here.
- **Patrol Overview** (`/patrols/:patrolId`): header with the patrol's editable title, state, track/location/bounds actions and a kebab menu (copy link, print, download track); two tabs — **Overview** (the leg table, a new leg link under it, and the activity timeline) and **History** (audit trail from `updates`); footer actions to add notes, attachments and events, update the status (pause, cancel, end), or save. Mobile-provenance patrols hide the new leg link, and replace the status dropdown with a single end-patrol action.
- **Patrol Overview** (`/patrols/:patrolId`): header with the patrol's editable title, state, track/location/bounds actions and a kebab menu (copy link, print, download track); two tabs — **Overview** (the leg table, a new leg link under it, and the activity timeline headed by the patrol's stats) and **History** (audit trail from `updates`); footer actions to add notes, attachments and events, update the status (pause, cancel, end), or save. Mobile-provenance patrols hide the new leg link, and replace the status dropdown with a single end-patrol action.
- **New Leg** (`/patrols/:patrolId/legs/new`): the leg form, adding a leg to an existing patrol. Saving it ends the current leg and starts this one.
- **Leg Overview** (`/patrols/:patrolId/legs/:legId`): header with the leg's title, status and action buttons; the leg's saved plan (times, locations, objective, team and tracking, and the patrol type's fields); its activity timeline with duration, distance and event totals; footer actions to add notes, attachments and events, or edit the leg.
- **Edit Leg** (`/patrols/:patrolId/legs/:legId/edit`): the leg form, pre-filled with the leg's current values.
Expand Down
9 changes: 5 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"buildbranch": "generated_by_build",
"buildnum": "also_generated_by_build",
"dependencies": {
"@auth0/auth0-react": "^2.23.0",
"@auth0/auth0-react": "^2.24.0",
"@dnd-kit/collision": "^0.5.0",
"@dnd-kit/dom": "^0.5.0",
"@dnd-kit/helpers": "^0.5.0",
Expand Down Expand Up @@ -94,14 +94,14 @@
"@testing-library/dom": "^10.4.1",
"@testing-library/jest-dom": "^7.0.1",
"@testing-library/react": "^16.3.2",
"@testing-library/user-event": "^14.6.3",
"@testing-library/user-event": "^14.6.4",
"@vitejs/plugin-react": "^6.0.5",
"dotenv": "^17.4.2",
"eslint-config-airbnb": "^19.0.4",
"eslint-plugin-jest": "^29.16.0",
"eslint-plugin-jest": "^29.16.1",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "^7.1.1",
"globals": "^17.9.0",
"globals": "^17.11.0",
"jest-environment-jsdom": "^30.4.1",
"jest-fixed-jsdom": "^0.0.11",
"jest-webgl-canvas-mock": "^2.5.3",
Expand All @@ -124,6 +124,7 @@
"\\.svg": "<rootDir>/jest-config/mocks/svg.js"
},
"resetMocks": true,
"restoreMocks": true,
"setupFilesAfterEnv": [
"<rootDir>/src/setupTests.js"
],
Expand Down
15 changes: 10 additions & 5 deletions public/locales/en-US/patrols.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,24 +110,29 @@
"historyTabTitle": "History",
"overview": {
"activity": {
"activeTimeLabel": "Active Time",
"activitySectionTitle": "Activity",
"collapseAllButtonLabel": "Collapse all",
"distanceLabel": "Distance",
"durationLabel": "Duration",
"emptyStateMessage": "Patrol activity will appear here",
"eventsLabel": "Events",
"expandAllButtonLabel": "Expand all",
"jumpToLocationButtonLabel": "Jump to location",
"legTransitionTitle": "Leg {{endedLeg}} Ended, Leg {{startedLeg}} Started",
"patrolEndedTitle": "Patrol Ended",
"patrolStartedTitle": "Patrol Started",
"pausedTimeLabel": "Paused Time",
"sortDirectionButtonLabel": {
"down": "Sort activity in ascending order",
"up": "Sort activity in descending order"
},
"startPatrolButton": "Start Patrol",
"summaryStats": {
"activeTimeLabel": "Active Time",
"distanceLabel": "Distance",
"distanceSubjectButtonLabel": "Distance covered by {{subject}}. Change the tracked subject",
"distanceSubjectMenuLabel": "Tracked subjects",
"durationLabel": "Duration",
"eventsLabel": "Events",
"patrolLeaderIndicator": "Patrol leader",
"pausedTimeLabel": "Paused Time"
},
"timeLabel": "Time"
},
"legs": {
Expand Down
1 change: 1 addition & 0 deletions public/locales/en-US/utils.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"displayTitleForPatrol": {
"unknown": "Unknown patrol type"
},
"distanceInKilometers": "{{distance}}km",
"filterDuplicateUploadFilenames": {
"duplicationAlert": "Can not add {{fileName}}: file already exists"
},
Expand Down
15 changes: 10 additions & 5 deletions public/locales/es/patrols.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,24 +110,29 @@
"historyTabTitle": "Historial",
"overview": {
"activity": {
"activeTimeLabel": "Tiempo activo",
"activitySectionTitle": "Actividad",
"collapseAllButtonLabel": "Colapsar todo",
"distanceLabel": "Distancia",
"durationLabel": "Duración",
"emptyStateMessage": "La actividad de la patrulla aparecerá aquí",
"eventsLabel": "Eventos",
"expandAllButtonLabel": "Expandir todo",
"jumpToLocationButtonLabel": "Ir a la ubicación",
"legTransitionTitle": "Tramo {{endedLeg}} finalizado, Tramo {{startedLeg}} iniciado",
"patrolEndedTitle": "Patrullaje finalizado",
"patrolStartedTitle": "Patrullaje iniciado",
"pausedTimeLabel": "Tiempo en pausa",
"sortDirectionButtonLabel": {
"down": "Ordenar actividad de forma ascendente",
"up": "Ordenar actividad de forma descendente"
},
"startPatrolButton": "Iniciar Patrullaje",
"summaryStats": {
"activeTimeLabel": "Tiempo activo",
"distanceLabel": "Distancia",
"distanceSubjectButtonLabel": "Distancia recorrida por {{subject}}. Cambiar el sujeto rastreado",
"distanceSubjectMenuLabel": "Sujetos rastreados",
"durationLabel": "Duración",
"eventsLabel": "Eventos",
"patrolLeaderIndicator": "Líder del patrullaje",
"pausedTimeLabel": "Tiempo en pausa"
},
"timeLabel": "Hora"
},
"legs": {
Expand Down
1 change: 1 addition & 0 deletions public/locales/es/utils.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"displayTitleForPatrol": {
"unknown": "Tipo de patrulla desconocido"
},
"distanceInKilometers": "{{distance}}km",
"filterDuplicateUploadFilenames": {
"duplicationAlert": "No se puede agregar {{fileName}}: el archivo ya existe"
},
Expand Down
15 changes: 10 additions & 5 deletions public/locales/fr/patrols.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,24 +110,29 @@
"historyTabTitle": "Historique",
"overview": {
"activity": {
"activeTimeLabel": "Temps actif",
"activitySectionTitle": "Activité",
"collapseAllButtonLabel": "Tout réduire",
"distanceLabel": "Distance",
"durationLabel": "Durée",
"emptyStateMessage": "L'activité de la patrouille apparaîtra ici",
"eventsLabel": "Événements",
"expandAllButtonLabel": "Tout développer",
"jumpToLocationButtonLabel": "Aller à l'emplacement",
"legTransitionTitle": "Étape {{endedLeg}} terminée, Étape {{startedLeg}} commencée",
"patrolEndedTitle": "Patrouille terminée",
"patrolStartedTitle": "Patrouille commencée",
"pausedTimeLabel": "Temps en pause",
"sortDirectionButtonLabel": {
"down": "Trier l'activité par ordre croissant",
"up": "Trier l'activité par ordre décroissant"
},
"startPatrolButton": "Commencer la Patrouille",
"summaryStats": {
"activeTimeLabel": "Temps actif",
"distanceLabel": "Distance",
"distanceSubjectButtonLabel": "Distance parcourue par {{subject}}. Changer le sujet suivi",
"distanceSubjectMenuLabel": "Sujets suivis",
"durationLabel": "Durée",
"eventsLabel": "Événements",
"patrolLeaderIndicator": "Chef de la patrouille",
"pausedTimeLabel": "Temps en pause"
},
"timeLabel": "Heure"
},
"legs": {
Expand Down
1 change: 1 addition & 0 deletions public/locales/fr/utils.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"displayTitleForPatrol": {
"unknown": "Type de patrouille inconnue"
},
"distanceInKilometers": "{{distance}}km",
"filterDuplicateUploadFilenames": {
"duplicationAlert": "Impossible d'ajouter {{fileName}}: le fichier existe déjà"
},
Expand Down
15 changes: 10 additions & 5 deletions public/locales/ne-NP/patrols.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,24 +110,29 @@
"historyTabTitle": "इतिहास",
"overview": {
"activity": {
"activeTimeLabel": "सक्रिय समय",
"activitySectionTitle": "गतिविधि",
"collapseAllButtonLabel": "सबै बन्द गर्नुहोस्",
"distanceLabel": "दूरी",
"durationLabel": "अवधि",
"emptyStateMessage": "गस्ती गतिविधि यहाँ देखा पर्नेछ",
"eventsLabel": "घटनाहरू",
"expandAllButtonLabel": "सबै विस्तार गर्नुहोस्",
"jumpToLocationButtonLabel": "स्थानमा जानुहोस्",
"legTransitionTitle": "खण्ड {{endedLeg}} समाप्त भयो, खण्ड {{startedLeg}} सुरु भयो",
"patrolEndedTitle": "गस्ती समाप्त भएको",
"patrolStartedTitle": "गस्ती सुरु भएको",
"pausedTimeLabel": "रोकिएको समय",
"sortDirectionButtonLabel": {
"down": "गतिविधि आरोही क्रममा क्रमबद्ध गर्नुहोस्",
"up": "गतिविधि अवरोही क्रममा क्रमबद्ध गर्नुहोस्"
},
"startPatrolButton": "गस्ती सुरु गर्नुहोस्",
"summaryStats": {
"activeTimeLabel": "सक्रिय समय",
"distanceLabel": "दूरी",
"distanceSubjectButtonLabel": "{{subject}} ले तय गरेको दूरी। ट्र्याक गरिएको विषय परिवर्तन गर्नुहोस्",
"distanceSubjectMenuLabel": "ट्र्याक गरिएका विषयहरू",
"durationLabel": "अवधि",
"eventsLabel": "घटनाहरू",
"patrolLeaderIndicator": "गस्ती नेता",
"pausedTimeLabel": "रोकिएको समय"
},
"timeLabel": "समय"
},
"legs": {
Expand Down
1 change: 1 addition & 0 deletions public/locales/ne-NP/utils.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"displayTitleForPatrol": {
"unknown": "अज्ञात गस्ती"
},
"distanceInKilometers": "{{distance}}km",
"filterDuplicateUploadFilenames": {
"duplicationAlert": "थप गर्न सकिँदैन । {{fileName}}: नामको फाइल पहिले नै अवस्थित छ"
},
Expand Down
15 changes: 10 additions & 5 deletions public/locales/pt/patrols.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,24 +110,29 @@
"historyTabTitle": "Histórico",
"overview": {
"activity": {
"activeTimeLabel": "Tempo ativo",
"activitySectionTitle": "Atividade",
"collapseAllButtonLabel": "Minimizar tudo",
"distanceLabel": "Distância",
"durationLabel": "Duração",
"emptyStateMessage": "A atividade da patrulha aparecerá aqui",
"eventsLabel": "Eventos",
"expandAllButtonLabel": "Expandir tudo",
"jumpToLocationButtonLabel": "Ir para a localização",
"legTransitionTitle": "Etapa {{endedLeg}} finalizada, Etapa {{startedLeg}} iniciada",
"patrolEndedTitle": "Patrulha finalizada",
"patrolStartedTitle": "Patrulha iniciada",
"pausedTimeLabel": "Tempo pausado",
"sortDirectionButtonLabel": {
"down": "Ordenar atividade em ordem crescente",
"up": "Ordenar atividade em ordem decrescente"
},
"startPatrolButton": "Iniciar patrulha",
"summaryStats": {
"activeTimeLabel": "Tempo ativo",
"distanceLabel": "Distância",
"distanceSubjectButtonLabel": "Distância percorrida por {{subject}}. Alterar o sujeito rastreado",
"distanceSubjectMenuLabel": "Sujeitos rastreados",
"durationLabel": "Duração",
"eventsLabel": "Eventos",
"patrolLeaderIndicator": "Líder da patrulha",
"pausedTimeLabel": "Tempo pausado"
},
"timeLabel": "Hora"
},
"legs": {
Expand Down
1 change: 1 addition & 0 deletions public/locales/pt/utils.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"displayTitleForPatrol": {
"unknown": "Tipo de patrulha desconhecido"
},
"distanceInKilometers": "{{distance}}km",
"filterDuplicateUploadFilenames": {
"duplicationAlert": "Can not add {{fileName}}: file already exists"
},
Expand Down
15 changes: 10 additions & 5 deletions public/locales/sw/patrols.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,24 +110,29 @@
"historyTabTitle": "Historia",
"overview": {
"activity": {
"activeTimeLabel": "Muda Inatekelezwa",
"activitySectionTitle": "Shughuli",
"collapseAllButtonLabel": "Ficha yote",
"distanceLabel": "Umbali",
"durationLabel": "Muda",
"emptyStateMessage": "Shughuli za doria zitaonekana hapa",
"eventsLabel": "Matukio",
"expandAllButtonLabel": "Panua yote",
"jumpToLocationButtonLabel": "Enda mahali",
"legTransitionTitle": "Kipande {{endedLeg}} kimekamilika, Kipande {{startedLeg}} kimeanza",
"patrolEndedTitle": "Doria imekamilika",
"patrolStartedTitle": "Doria imeanza",
"pausedTimeLabel": "Muda wa Kusitisha",
"sortDirectionButtonLabel": {
"down": "Panga shughuli kwa mpangilio wa kupanda",
"up": "Panga shughuli kwa mpangilio wa kushuka"
},
"startPatrolButton": "Anza Doria",
"summaryStats": {
"activeTimeLabel": "Muda Inatekelezwa",
"distanceLabel": "Umbali",
"distanceSubjectButtonLabel": "Umbali uliofikiwa na {{subject}}. Badilisha mhusika anayefuatiliwa",
"distanceSubjectMenuLabel": "Wahusika wanaofuatiliwa",
"durationLabel": "Muda",
"eventsLabel": "Matukio",
"patrolLeaderIndicator": "Kiongozi wa doria",
"pausedTimeLabel": "Muda wa Kusitisha"
},
"timeLabel": "Wakati"
},
"legs": {
Expand Down
1 change: 1 addition & 0 deletions public/locales/sw/utils.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"displayTitleForPatrol": {
"unknown": "Aina isiyojulikana ya doria"
},
"distanceInKilometers": "{{distance}}km",
"filterDuplicateUploadFilenames": {
"duplicationAlert": "Haiwezi kuongeza {{fileName}}: faili tayari ipo"
},
Expand Down
2 changes: 1 addition & 1 deletion src/PatrolDetailView/Header/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ const Header = ({ onChangeTitle, patrol, setRedirectTo, printableContentRef }) =
return <span data-testid="patrol-drawer-header-details" className={`${styles.headerDetails} ${styles.overflowedEllipsisText}`}>
{patrolElapsedTime}
<span className={styles.distanceCovered}>
<PatrolDistanceCovered patrolsData={[{ patrol, ...patrolTrackData }]} suffix=' km' />
<PatrolDistanceCovered patrolsData={[{ patrol, ...patrolTrackData }]} />
</span>
</span>;
}
Expand Down
6 changes: 6 additions & 0 deletions src/PatrolDetailView/Header/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@ describe('Header', () => {
expect(buttons[0]).toHaveClass('toggle');
});

test('shows the distance covered by an active patrol', async () => {
renderHeader({ patrol: activePatrol });

expect((await screen.findByTestId('patrol-drawer-header-details'))).toHaveTextContent('0km');
});

test('renders correctly case of an overdue patrol', async () => {
renderHeader({ patrol: overduePatrol });

Expand Down
2 changes: 1 addition & 1 deletion src/PatrolListItem/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ const PatrolListItem = ({
if (isPatrolActiveOrDone) {
return <span className={styles.titleDetails}>
<span>{patrolElapsedTime}</span> | <span>
<PatrolDistanceCovered patrolsData={patrolsData} suffix=' km' />
<PatrolDistanceCovered patrolsData={patrolsData} />
</span>
</span>;
}
Expand Down
4 changes: 4 additions & 0 deletions src/PatrolListItem/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,10 @@ describe('for active patrols', () => {
await screen.findByTestId(`patrol-list-item-track-btn-${testPatrol.id}`);
});

test('showing the distance the patrol has covered', async () => {
expect(await screen.findByText('0km')).toBeInTheDocument();
});

test('canceling the patrol from the kebab menu', async () => {
const kebabMenu = await screen.findByTestId(`patrol-list-item-kebab-menu-${testPatrol.id}`);
const kebabButton = kebabMenu.querySelector('button');
Expand Down
Loading