-
Notifications
You must be signed in to change notification settings - Fork 5
Closed
Labels
frontendFrontend/UI related changesFrontend/UI related changesrefactorCode refactoringCode refactoring
Description
Summary
Platform-specific alert/confirm patterns are duplicated approximately 93 times across 17 files in the codebase.
Related to: #154 (Daily Codebase Review - 2025-12-16)
Problem
The same pattern appears repeatedly throughout the codebase:
const confirmed =
Platform.OS === 'web'
? window.confirm(confirmMessage)
: await new Promise<boolean>((resolve) => {
Alert.alert('Confirm', confirmMessage, [
{ text: 'Cancel', style: 'cancel', onPress: () => resolve(false) },
{ text: 'OK', onPress: () => resolve(true) },
]);
});Affected files (17 total):
app/(tabs)/profile.tsx(11 occurrences)components/settings/SettingsContent.tsx(9 occurrences)app/(tabs)/tasks.tsx(5 occurrences)app/(tabs)/manage-tasks.tsx(3 occurrences)components/sheets/LogSlipUpSheet.tsx(2 occurrences)- And 12 more files...
Proposed Solution
Create a shared utility module:
lib/alert-utils.ts
import { Alert, Platform } from 'react-native';
/**
* Shows a platform-appropriate confirmation dialog.
*
* @param title - The dialog title (native only, prepended to message on web)
* @param message - The confirmation message
* @param confirmText - Text for confirm button (default: 'OK')
* @param cancelText - Text for cancel button (default: 'Cancel')
* @returns Promise resolving to true if confirmed, false if cancelled
*
* @example
* ```ts
* const shouldDelete = await confirmAsync('Delete Item', 'Are you sure?');
* if (shouldDelete) {
* await deleteItem();
* }
* ```
*/
export async function confirmAsync(
title: string,
message: string,
confirmText = 'OK',
cancelText = 'Cancel'
): Promise<boolean> {
if (Platform.OS === 'web') {
return window.confirm(`${title}\n\n${message}`);
}
return new Promise((resolve) => {
Alert.alert(title, message, [
{ text: cancelText, style: 'cancel', onPress: () => resolve(false) },
{ text: confirmText, onPress: () => resolve(true) },
]);
});
}
/**
* Shows a platform-appropriate alert dialog.
*
* @param title - The dialog title
* @param message - The alert message
* @param buttonText - Text for dismiss button (default: 'OK')
*
* @example
* ```ts
* await alertAsync('Error', 'Something went wrong');
* ```
*/
export async function alertAsync(
title: string,
message: string,
buttonText = 'OK'
): Promise<void> {
if (Platform.OS === 'web') {
window.alert(`${title}\n\n${message}`);
return;
}
return new Promise((resolve) => {
Alert.alert(title, message, [
{ text: buttonText, onPress: () => resolve() },
]);
});
}
/**
* Shows a destructive confirmation dialog with appropriate styling.
*
* @param title - The dialog title
* @param message - The confirmation message
* @param destructiveText - Text for destructive action (default: 'Delete')
* @param cancelText - Text for cancel button (default: 'Cancel')
*
* @example
* ```ts
* const shouldDelete = await confirmDestructiveAsync(
* 'Delete Account',
* 'This action cannot be undone.'
* );
* ```
*/
export async function confirmDestructiveAsync(
title: string,
message: string,
destructiveText = 'Delete',
cancelText = 'Cancel'
): Promise<boolean> {
if (Platform.OS === 'web') {
return window.confirm(`${title}\n\n${message}\n\nThis action cannot be undone.`);
}
return new Promise((resolve) => {
Alert.alert(title, message, [
{ text: cancelText, style: 'cancel', onPress: () => resolve(false) },
{ text: destructiveText, style: 'destructive', onPress: () => resolve(true) },
]);
});
}Usage After Refactor
// Before (15 lines per occurrence)
const confirmed =
Platform.OS === 'web'
? window.confirm('Disconnect from sponsor?')
: await new Promise<boolean>((resolve) => {
Alert.alert('Disconnect', 'Are you sure?', [
{ text: 'Cancel', style: 'cancel', onPress: () => resolve(false) },
{ text: 'OK', onPress: () => resolve(true) },
]);
});
// After (1 line)
const confirmed = await confirmAsync('Disconnect', 'Disconnect from sponsor?');Benefits
- DRY: Eliminates ~93 duplicated code blocks
- Maintainability: Single place to update alert behavior
- Consistency: All alerts behave the same way
- Testability: Easy to mock in tests
- Type safety: Proper TypeScript typing
Acceptance Criteria
- Create
lib/alert-utils.tswithconfirmAsync,alertAsync,confirmDestructiveAsync - Add JSDoc documentation with examples
- Create tests for all utility functions
- Refactor all occurrences to use new utilities
- Remove duplicated code from all 17 files
- All existing tests pass
- No functional changes to user experience
Priority
MEDIUM - Code quality improvement, significant DRY violation
Estimated Effort
3-4 hours (mostly mechanical refactoring)
Files to Modify
- Create:
lib/alert-utils.ts - Create:
__tests__/lib/alert-utils.test.ts - Refactor: 17 files with duplicated patterns
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
frontendFrontend/UI related changesFrontend/UI related changesrefactorCode refactoringCode refactoring