fix: restore error handling and deduplicate goBack helper (#21)

- Replace `finally` with `catch` in [id].tsx handleSave so goBack is
  not called when updateTask/setTagsForTask fails
- Extract shared goBack helper into src/lib/navigation.ts
- Both [id].tsx and new.tsx now import goBack from the shared module

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
medic-bot 2026-03-09 21:06:05 -04:00
parent 2296126ba4
commit 4c73a16302
3 changed files with 22 additions and 22 deletions

View file

@ -25,6 +25,7 @@ import { colors } from '@/src/theme/colors';
import { useSettingsStore } from '@/src/stores/useSettingsStore';
import { isValidUUID } from '@/src/lib/validation';
import { getPriorityOptions } from '@/src/lib/priority';
import { goBack } from '@/src/lib/navigation';
import { RECURRENCE_OPTIONS } from '@/src/lib/recurrence';
import {
getTaskById,
@ -112,14 +113,6 @@ export default function TaskDetailScreen() {
setSubtasks(result as SubtaskData[]);
};
const goBack = () => {
if (router.canGoBack()) {
router.back();
} else {
router.replace('/');
}
};
const handleSave = async () => {
if (saving) return;
if (!task || !title.trim()) return;
@ -134,8 +127,9 @@ export default function TaskDetailScreen() {
listId: selectedListId,
});
await setTagsForTask(task.id, selectedTagIds);
goBack();
} finally {
goBack(router);
} catch {
// Save failed — stay on screen so user can retry
setSaving(false);
}
};
@ -149,7 +143,7 @@ export default function TaskDetailScreen() {
onPress: async () => {
await deleteTask(id!);
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium);
goBack();
goBack(router);
},
},
]);
@ -193,7 +187,7 @@ export default function TaskDetailScreen() {
<View
className={`flex-row items-center justify-between border-b px-4 pb-3 pt-14 ${isDark ? 'border-[#3A3A3A]' : 'border-[#E5E7EB]'}`}
>
<Pressable onPress={goBack} className="p-2.5" hitSlop={{ top: 8, bottom: 8, left: 8, right: 8 }}>
<Pressable onPress={() => goBack(router)} className="p-2.5" hitSlop={{ top: 8, bottom: 8, left: 8, right: 8 }}>
<ArrowLeft size={24} color={isDark ? '#F5F5F5' : '#1A1A1A'} />
</Pressable>
<View className="flex-row items-center">

View file

@ -27,6 +27,7 @@ import { getInboxId, getAllLists } from '@/src/db/repository/lists';
import { getAllTags, setTagsForTask } from '@/src/db/repository/tags';
import { getPriorityOptions } from '@/src/lib/priority';
import { RECURRENCE_OPTIONS } from '@/src/lib/recurrence';
import { goBack } from '@/src/lib/navigation';
import TagChip from '@/src/components/task/TagChip';
const ICON_MAP: Record<string, LucideIcon> = {
@ -64,14 +65,6 @@ export default function NewTaskScreen() {
getAllTags().then(setAvailableTags);
}, []);
const goBack = () => {
if (router.canGoBack()) {
router.back();
} else {
router.replace('/');
}
};
const handleSave = async () => {
if (saving) return;
if (!title.trim()) return;
@ -91,7 +84,7 @@ export default function NewTaskScreen() {
for (const sub of pendingSubtasks) {
await createTask({ title: sub, listId: selectedListId, parentId: taskId });
}
goBack();
goBack(router);
} catch {
// FK constraint or other DB error — fallback to inbox
setSaving(false);
@ -128,7 +121,7 @@ export default function NewTaskScreen() {
isDark ? 'border-[#3A3A3A]' : 'border-[#E5E7EB]'
}`}
>
<Pressable onPress={goBack} className="p-2.5" hitSlop={{ top: 8, bottom: 8, left: 8, right: 8 }}>
<Pressable onPress={() => goBack(router)} className="p-2.5" hitSlop={{ top: 8, bottom: 8, left: 8, right: 8 }}>
<X size={24} color={isDark ? '#F5F5F5' : '#1A1A1A'} />
</Pressable>
<Text

13
src/lib/navigation.ts Normal file
View file

@ -0,0 +1,13 @@
import type { Router } from 'expo-router';
/**
* Navigate back if possible, otherwise replace with root.
* Shared between task screens to avoid duplication.
*/
export const goBack = (router: Router) => {
if (router.canGoBack()) {
router.back();
} else {
router.replace('/');
}
};