From e989d09dc7e9b3d97d33418445fc9bfe3a059d2c Mon Sep 17 00:00:00 2001 From: Opulence Chuks Date: Thu, 20 Aug 2026 23:40:57 +0100 Subject: [PATCH] feat: improve accessibility across app components and screens --- src/components/AchievementGrid.tsx | 2 +- src/components/EarningsSummary.tsx | 2 +- src/components/EmptyState.tsx | 2 +- src/components/ErrorBoundary.tsx | 5 ++- src/components/ImpactStats.tsx | 2 +- src/components/LoadingSkeleton.tsx | 3 ++ src/components/OfflineBanner.tsx | 1 + src/components/PendingProofsBanner.tsx | 5 ++- src/components/RewardBadge.tsx | 2 +- src/components/StreakCard.tsx | 2 +- src/components/TabBarIcon.tsx | 2 + src/components/TaskCard.tsx | 5 ++- src/components/TransactionHistory.tsx | 8 ++-- src/screens/EditProfileScreen.tsx | 11 +++++- src/screens/HomeScreen.tsx | 24 ++++++++++-- src/screens/MapScreen.tsx | 37 ++++++++++++++++--- src/screens/NotificationPreferencesScreen.tsx | 6 +++ src/screens/OnboardingScreen.tsx | 21 ++++++++++- src/screens/ProfileScreen.tsx | 11 +++++- src/screens/SendTokensScreen.tsx | 11 +++++- src/screens/SubmitProofScreen.tsx | 17 ++++++++- src/screens/SubmitScreen.tsx | 4 +- src/screens/TaskDetailScreen.tsx | 11 ++++-- src/screens/TaskListScreen.tsx | 17 ++++++++- src/screens/WalletScreen.tsx | 4 ++ 25 files changed, 182 insertions(+), 33 deletions(-) diff --git a/src/components/AchievementGrid.tsx b/src/components/AchievementGrid.tsx index e339632..3fc1b5a 100644 --- a/src/components/AchievementGrid.tsx +++ b/src/components/AchievementGrid.tsx @@ -86,7 +86,7 @@ function AchievementTile({ achievement }: { achievement: Achievement }) { opacity, }} > - {achievement.icon} + {achievement.icon} - {item.icon} + {item.icon} - {icon} + {icon} { } return ( { padding: spacing.lg, }} > - ⚠️ + ⚠️ { {this.state.error?.message || 'An unexpected error occurred'} - {icon} + {icon} - πŸ“€ + πŸ“€ {count} proof{count === 1 ? '' : 's'} waiting to sync @@ -48,6 +49,8 @@ export default function PendingProofsBanner({ - + {tier.emoji} - {streak > 0 ? 'πŸ”₯' : '🧊'} + 0 ? 'Fire' : 'Ice'}>{streak > 0 ? 'πŸ”₯' : '🧊'} diff --git a/src/components/TabBarIcon.tsx b/src/components/TabBarIcon.tsx index a8f401a..7dde8d3 100644 --- a/src/components/TabBarIcon.tsx +++ b/src/components/TabBarIcon.tsx @@ -20,6 +20,8 @@ export default function TabBarIcon({ fontSize: size, opacity: focused ? 1 : 0.5, }} + accessible={true} + accessibilityLabel="Tab icon" > {emoji} diff --git a/src/components/TaskCard.tsx b/src/components/TaskCard.tsx index 4d35754..56b4900 100644 --- a/src/components/TaskCard.tsx +++ b/src/components/TaskCard.tsx @@ -41,6 +41,9 @@ export default function TaskCard({ return ( onPress(id)} + accessibilityRole="button" + accessibilityLabel={`Task: ${title}`} + accessibilityHint="Navigates to task details" style={{ backgroundColor: colors.surface, borderRadius: 12, @@ -52,7 +55,7 @@ export default function TaskCard({ borderColor: colors.border, }} > - + {TASK_TYPE_CONFIG[type]?.icon || 'πŸ“'} diff --git a/src/components/TransactionHistory.tsx b/src/components/TransactionHistory.tsx index 54fd588..c7c7540 100644 --- a/src/components/TransactionHistory.tsx +++ b/src/components/TransactionHistory.tsx @@ -60,7 +60,7 @@ export default function TransactionHistory({ if (loading) { return ( - + + {error} - + - + {isSent ? '↗️' : '↙️'} diff --git a/src/screens/EditProfileScreen.tsx b/src/screens/EditProfileScreen.tsx index 63dd658..f5ed243 100644 --- a/src/screens/EditProfileScreen.tsx +++ b/src/screens/EditProfileScreen.tsx @@ -70,6 +70,8 @@ export default function EditProfileScreen() { navigation.goBack()} style={{ marginBottom: spacing.md }} + accessibilityLabel="Cancel editing profile" + accessibilityRole="button" > Cancel @@ -99,6 +101,7 @@ export default function EditProfileScreen() { onChangeText={setName} placeholder="Your name" placeholderTextColor={colors.textSecondary} + accessibilityLabel="Display Name input" style={{ backgroundColor: colors.surface, borderRadius: 12, @@ -125,6 +128,7 @@ export default function EditProfileScreen() { onChangeText={setBio} placeholder="Tell others about yourself" placeholderTextColor={colors.textSecondary} + accessibilityLabel="Bio input" multiline numberOfLines={4} textAlignVertical="top" @@ -144,6 +148,8 @@ export default function EditProfileScreen() { - + {isSaving ? 'Saving...' : 'Save Changes'} diff --git a/src/screens/HomeScreen.tsx b/src/screens/HomeScreen.tsx index 71f8761..a25c4ae 100644 --- a/src/screens/HomeScreen.tsx +++ b/src/screens/HomeScreen.tsx @@ -65,7 +65,11 @@ export default function HomeScreen() { paddingBottom: spacing.lg, }} > - navigation.navigate('Profile')}> + navigation.navigate('Profile')} + accessibilityLabel={`Go to Profile. ${getGreeting()}, ${profile?.name || 'Eco Warrior'}`} + accessibilityRole="button" + > {getGreeting()}, @@ -181,6 +185,8 @@ export default function HomeScreen() { navigation.navigate('Tasks')} + accessibilityLabel="Browse Tasks" + accessibilityRole="button" style={{ padding: spacing.lg, backgroundColor: colors.primary, @@ -193,7 +199,14 @@ export default function HomeScreen() { Browse Tasks - 🌿 + + 🌿 + @@ -265,7 +278,12 @@ export default function HomeScreen() { a.status === 'pending' ? colors.warning : colors.border, }} > - + {TASK_TYPE_CONFIG[a.taskType as TaskType]?.icon || 'πŸ“'} diff --git a/src/screens/MapScreen.tsx b/src/screens/MapScreen.tsx index 0252496..bc70128 100644 --- a/src/screens/MapScreen.tsx +++ b/src/screens/MapScreen.tsx @@ -220,8 +220,14 @@ export default function MapScreen() { {/* ── Header ── */} - - πŸ—ΊοΈ Discover Tasks + + + πŸ—ΊοΈ Discover Tasks + {isLoading && ( )} {error != null && ( - + Retry )} @@ -245,6 +256,8 @@ export default function MapScreen() { key={km} testID={`radius-btn-${km}`} onPress={() => setRadiusKm(km)} + accessibilityLabel={`Set radius to ${km} kilometers`} + accessibilityRole="button" style={[ styles.radiusOpt, radiusKm === km && styles.radiusOptActive, @@ -268,6 +281,8 @@ export default function MapScreen() { { mapRef.current?.animateToRegion( { @@ -280,14 +295,26 @@ export default function MapScreen() { ); }} > - β—Ž + + β—Ž + )} {/* ── No-location fallback notice ── */} {!location && ( - + πŸ“ Enable location to see tasks near you diff --git a/src/screens/NotificationPreferencesScreen.tsx b/src/screens/NotificationPreferencesScreen.tsx index 5b56558..872f204 100644 --- a/src/screens/NotificationPreferencesScreen.tsx +++ b/src/screens/NotificationPreferencesScreen.tsx @@ -81,6 +81,8 @@ export default function NotificationPreferencesScreen() { quietHours.to, ); }} + accessibilityLabel={`Cycle Quiet Hours Start Time, currently ${quietHours.from}`} + accessibilityRole="button" style={{ padding: spacing.md, backgroundColor: colors.surface, @@ -101,6 +103,8 @@ export default function NotificationPreferencesScreen() { `${nh.toString().padStart(2, '0')}:${(m || 0).toString().padStart(2, '0')}`, ); }} + accessibilityLabel={`Cycle Quiet Hours End Time, currently ${quietHours.to}`} + accessibilityRole="button" style={{ padding: spacing.md, backgroundColor: colors.surface, @@ -114,6 +118,8 @@ export default function NotificationPreferencesScreen() { navigation.goBack()} + accessibilityLabel="Done editing preferences" + accessibilityRole="button" style={{ marginTop: spacing.lg, padding: spacing.md, diff --git a/src/screens/OnboardingScreen.tsx b/src/screens/OnboardingScreen.tsx index 18b699e..f222aba 100644 --- a/src/screens/OnboardingScreen.tsx +++ b/src/screens/OnboardingScreen.tsx @@ -69,7 +69,14 @@ export default function OnboardingScreen() { }} > - 🌱 + + 🌱 + {error} @@ -106,6 +114,8 @@ export default function OnboardingScreen() { setShowImport(v => !v)} disabled={busy} + accessibilityLabel={showImport ? 'Cancel Import' : 'Import Existing Wallet'} + accessibilityRole="button" style={{ padding: spacing.md, backgroundColor: colors.surface, @@ -185,6 +201,7 @@ export default function OnboardingScreen() { onChangeText={setSecretKey} placeholder="Paste your secret key (S...)" placeholderTextColor={colors.textSecondary} + accessibilityLabel="Secret Key Input" secureTextEntry autoCapitalize="none" autoCorrect={false} @@ -202,6 +219,8 @@ export default function OnboardingScreen() { - + {profile?.avatarUrl ? 'πŸ‘€' : '🌱'} @@ -156,6 +161,8 @@ export default function ProfileScreen() { disconnectWallet(); logout(); }} + accessibilityLabel="Disconnect and Sign Out" + accessibilityRole="button" style={{ marginTop: spacing.lg, padding: spacing.md, @@ -185,6 +192,8 @@ function SettingsRow({ return ( - navigation.goBack()}> + navigation.goBack()} accessibilityRole="button" accessibilityLabel="Cancel"> Cancel setAsset(a)} + accessibilityRole="button" + accessibilityLabel={`Select asset ${a}`} + accessibilityState={{ selected: asset === a }} style={{ flex: 1, padding: spacing.md, @@ -277,6 +282,7 @@ export default function SendTokensScreen() { {error && ( - navigation.goBack()}> + navigation.goBack()} accessibilityRole="button" accessibilityLabel="Go back"> Back ) : ( - πŸ“· + πŸ“· @@ -244,6 +244,8 @@ export default function SubmitProofScreen() { {hasPermission === false && ( Grant Permission @@ -277,6 +279,7 @@ export default function SubmitProofScreen() { {progress !== 'idle' && ( - πŸ“Έ + πŸ“Έ navigation.navigate('Tasks')} + accessibilityRole="button" + accessibilityLabel="Browse Tasks" style={{ marginTop: spacing.lg, paddingVertical: spacing.md, diff --git a/src/screens/TaskDetailScreen.tsx b/src/screens/TaskDetailScreen.tsx index b397fb4..00936d5 100644 --- a/src/screens/TaskDetailScreen.tsx +++ b/src/screens/TaskDetailScreen.tsx @@ -62,8 +62,8 @@ export default function TaskDetailScreen() { alignItems: 'center', }} > - {error || 'Task not found'} - + {error || 'Task not found'} + Try Again @@ -80,6 +80,8 @@ export default function TaskDetailScreen() { navigation.goBack()} + accessibilityRole="button" + accessibilityLabel="Go back" style={{ marginBottom: spacing.md, marginTop: spacing.xl }} > @@ -87,7 +89,7 @@ export default function TaskDetailScreen() { - + {TASK_TYPE_CONFIG[task.type]?.icon || 'πŸ“'} @@ -192,6 +194,9 @@ export default function TaskDetailScreen() { { selectTask({ ...task, id: task.id || taskId }); navigation.navigate('SubmitProof', { diff --git a/src/screens/TaskListScreen.tsx b/src/screens/TaskListScreen.tsx index a4b8310..60d0f51 100644 --- a/src/screens/TaskListScreen.tsx +++ b/src/screens/TaskListScreen.tsx @@ -122,8 +122,8 @@ export default function TaskListScreen() { alignItems: 'center', }} > - {error} - + {error} + Retry @@ -159,6 +159,9 @@ export default function TaskListScreen() { setActiveType(t.key)} + accessibilityRole="button" + accessibilityLabel={`Filter by ${t.label}`} + accessibilityState={{ selected: activeType === t.key }} style={{ flexDirection: 'row', alignItems: 'center', @@ -199,6 +202,9 @@ export default function TaskListScreen() { setStatusFilter(s.key)} + accessibilityRole="button" + accessibilityLabel={`Filter by status ${s.label}`} + accessibilityState={{ selected: statusFilter === s.key }} style={{ paddingHorizontal: spacing.md, paddingVertical: spacing.xs, @@ -231,6 +237,7 @@ export default function TaskListScreen() { placeholderTextColor={colors.textSecondary} autoCapitalize="none" autoCorrect={false} + accessibilityLabel="Search tasks" style={{ backgroundColor: colors.surface, borderRadius: 12, @@ -256,6 +263,9 @@ export default function TaskListScreen() { setSortMode(opt.key)} + accessibilityRole="button" + accessibilityLabel={`Sort by ${opt.label}`} + accessibilityState={{ selected: sortMode === opt.key }} style={{ paddingHorizontal: spacing.md, paddingVertical: spacing.xs, @@ -289,6 +299,9 @@ export default function TaskListScreen() { setRadiusKm(km)} + accessibilityRole="button" + accessibilityLabel={`Radius ${km} kilometers`} + accessibilityState={{ selected: radiusKm === km }} style={{ paddingHorizontal: spacing.sm, paddingVertical: spacing.xs, diff --git a/src/screens/WalletScreen.tsx b/src/screens/WalletScreen.tsx index 1cf6c1f..6fe20e7 100644 --- a/src/screens/WalletScreen.tsx +++ b/src/screens/WalletScreen.tsx @@ -156,6 +156,8 @@ export default function WalletScreen() { navigation.navigate('SendTokens')} + accessibilityRole="button" + accessibilityLabel="Send Tokens" style={{ marginTop: spacing.xl, padding: spacing.md, @@ -169,6 +171,8 @@ export default function WalletScreen() {