@@ -145,9 +145,10 @@ import type {
145145 WorkspaceProjectTaskFeedbackReasonCategory ,
146146 WorkspaceProjectTaskSubmitFeedback ,
147147} from ' ~/types/projects' ;
148+ import { shapeToCenter } from ' ~/util/geojson' ;
148149
149150const route = useRoute ();
150- const workspaceId = Number (route .params .workspaceId );
151+ const workspaceId = Number (route .params .id );
151152const projectId = String (route .params .projectId );
152153const taskId = String (route .params .taskId );
153154const editorContainer = ref <HTMLDivElement | null >(null );
@@ -232,6 +233,7 @@ onMounted(() => {
232233 }
233234
234235 editorContainer .value .appendChild (manager .containerNode );
236+ syncTaskHash ();
235237 void manager .switchWorkspace (workspaceId );
236238});
237239
@@ -261,13 +263,47 @@ async function loadTaskDetail(): Promise<WorkspaceProjectTaskDetail> {
261263 );
262264 }
263265 catch (error ) {
266+ const fallbackTaskDetail = await loadTaskDetailByTaskNumber (taskId , error );
267+
268+ if (fallbackTaskDetail ) {
269+ return fallbackTaskDetail ;
270+ }
271+
264272 throw createError ({
265273 statusCode: 500 ,
266274 statusMessage: ' Failed to load task details' ,
267275 data: error ,
268276 });
269277 }
270278}
279+
280+ async function loadTaskDetailByTaskNumber(
281+ taskIdentifier : string ,
282+ error : unknown ,
283+ ): Promise <WorkspaceProjectTaskDetail | null > {
284+ if (! (error instanceof WorkspaceProjectsClientError ) || error .response .status !== 404 ) {
285+ return null ;
286+ }
287+
288+ const taskNumber = Number (taskIdentifier );
289+
290+ if (! Number .isInteger (taskNumber ) || taskNumber < 1 ) {
291+ return null ;
292+ }
293+
294+ const tasks = await workspaceProjectsClient .getWorkspaceProjectTasks (workspaceId , projectId );
295+ const matchedTask = tasks .find (candidate => candidate .taskNumber === taskNumber );
296+
297+ if (! matchedTask ) {
298+ return null ;
299+ }
300+
301+ return await workspaceProjectsClient .getWorkspaceProjectTaskDetail (
302+ workspaceId ,
303+ projectId ,
304+ matchedTask .id ,
305+ );
306+ }
271307function handleTaskAction(actionId : ' complete' | ' skip' ) {
272308 if (hasActiveEdits .value ) {
273309 return ;
@@ -327,6 +363,23 @@ function buildFeedbackPayload(): WorkspaceProjectTaskSubmitFeedback | undefined
327363 reasonCategory: feedbackReasonCategory .value || undefined ,
328364 };
329365}
366+ function generateInitialHash() {
367+ const center = shapeToCenter (task .geometry );
368+ const lat = center [0 ];
369+ const lon = center [1 ];
370+ const zoom = 17 ;
371+ return ` #map=${zoom }/${lat }/${lon } ` ;
372+ }
373+
374+ function syncTaskHash() {
375+ if (! task .geometry ) {
376+ return ;
377+ }
378+
379+ const initialHash = generateInitialHash ();
380+ const nextUrl = ` ${window .location .pathname }${window .location .search }${initialHash } ` ;
381+ window .history .replaceState (window .history .state , ' ' , nextUrl );
382+ }
330383
331384async function submitCompletedMapping() {
332385 submitErrorMessage .value = ' ' ;
@@ -399,6 +452,7 @@ function mountEditor() {
399452 }
400453
401454 editorContainer .value .appendChild (manager .containerNode );
455+ syncTaskHash ();
402456 void manager .init (workspaceId );
403457}
404458
0 commit comments