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 87bdfa9..05eae8a 100644 --- a/src/components/TransactionHistory.tsx +++ b/src/components/TransactionHistory.tsx @@ -60,7 +60,7 @@ export default function TransactionHistory({ if (loading) { return ( - + + {error} - void loadPayments()} - accessibilityRole="button" - style={{ - marginTop: spacing.xs, - paddingVertical: spacing.sm, - paddingHorizontal: spacing.md, - minHeight: 44, - justifyContent: 'center', - }} - > - Retry + + + Retry + ); @@ -131,7 +129,7 @@ export default function TransactionHistory({ borderColor: colors.border, }} > - + {isSent ? '↗️' : '↙️'} diff --git a/src/screens/EditProfileScreen.tsx b/src/screens/EditProfileScreen.tsx index 1f23eb5..924ea7d 100644 --- a/src/screens/EditProfileScreen.tsx +++ b/src/screens/EditProfileScreen.tsx @@ -72,17 +72,9 @@ export default function EditProfileScreen() { > navigation.goBack()} + style={{ marginBottom: spacing.md }} + accessibilityLabel="Cancel editing profile" accessibilityRole="button" - accessibilityLabel="Cancel" - style={{ - alignSelf: 'flex-start', - paddingVertical: spacing.sm, - paddingHorizontal: spacing.md, - marginLeft: -spacing.md, - marginBottom: spacing.md, - minHeight: 44, - justifyContent: 'center', - }} > Cancel @@ -112,6 +104,7 @@ export default function EditProfileScreen() { onChangeText={setName} placeholder="Your name" placeholderTextColor={colors.textSecondary} + accessibilityLabel="Display Name input" style={{ backgroundColor: colors.surface, borderRadius: 12, @@ -138,6 +131,7 @@ export default function EditProfileScreen() { onChangeText={setBio} placeholder="Tell others about yourself" placeholderTextColor={colors.textSecondary} + accessibilityLabel="Bio input" multiline numberOfLines={4} textAlignVertical="top" @@ -157,6 +151,8 @@ export default function EditProfileScreen() { void handleSave()} disabled={isSaving} + accessibilityLabel="Save Changes" + accessibilityRole="button" style={{ padding: spacing.md, backgroundColor: colors.primary, @@ -165,7 +161,10 @@ export default function EditProfileScreen() { opacity: isSaving ? 0.5 : 1, }} > - + {isSaving ? 'Saving...' : 'Save Changes'} diff --git a/src/screens/HomeScreen.tsx b/src/screens/HomeScreen.tsx index 62c7955..0b9b756 100644 --- a/src/screens/HomeScreen.tsx +++ b/src/screens/HomeScreen.tsx @@ -64,7 +64,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()}, @@ -178,6 +182,8 @@ export default function HomeScreen() { navigation.navigate('Tasks')} + accessibilityLabel="Browse Tasks" + accessibilityRole="button" style={{ padding: spacing.lg, backgroundColor: colors.primary, @@ -190,7 +196,14 @@ export default function HomeScreen() { Browse Tasks - 🌿 + + 🌿 + @@ -262,7 +275,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 5f5c115..671d1be 100644 --- a/src/screens/MapScreen.tsx +++ b/src/screens/MapScreen.tsx @@ -261,8 +261,14 @@ export default function MapScreen() { {/* ── Header ── */} - - πŸ—ΊοΈ Discover Tasks + + + πŸ—ΊοΈ Discover Tasks + {isLoading && ( )} {error != null && ( - void refresh()} + Retry @@ -289,6 +297,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, @@ -312,6 +322,8 @@ export default function MapScreen() { { mapRef.current?.animateToRegion( { @@ -324,14 +336,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 7952fa1..6a3a455 100644 --- a/src/screens/NotificationPreferencesScreen.tsx +++ b/src/screens/NotificationPreferencesScreen.tsx @@ -80,6 +80,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, @@ -100,6 +102,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, @@ -113,6 +117,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 776d514..feb0f5c 100644 --- a/src/screens/OnboardingScreen.tsx +++ b/src/screens/OnboardingScreen.tsx @@ -72,7 +72,14 @@ export default function OnboardingScreen() { }} > - 🌱 + + 🌱 + {error} @@ -109,6 +117,8 @@ export default function OnboardingScreen() { void connectFreighter()} disabled={busy} + accessibilityLabel="Connect Freighter wallet" + accessibilityRole="button" style={{ padding: spacing.md, backgroundColor: colors.primary, @@ -130,6 +140,8 @@ export default function OnboardingScreen() { void connectLobstr()} disabled={busy} + accessibilityLabel="Connect Lobstr wallet" + accessibilityRole="button" style={{ padding: spacing.md, backgroundColor: colors.surface, @@ -149,6 +161,8 @@ export default function OnboardingScreen() { void handleCreateWallet()} disabled={busy} + accessibilityLabel="Create Test Wallet" + accessibilityRole="button" style={{ padding: spacing.md, backgroundColor: colors.surface, @@ -167,6 +181,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, @@ -188,6 +204,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} @@ -205,6 +222,8 @@ export default function OnboardingScreen() { void handleImport()} disabled={busy || !secretKey.trim()} + accessibilityLabel="Import Wallet" + accessibilityRole="button" style={{ padding: spacing.md, backgroundColor: colors.primary, diff --git a/src/screens/ProfileScreen.tsx b/src/screens/ProfileScreen.tsx index a8df86e..c6b724f 100644 --- a/src/screens/ProfileScreen.tsx +++ b/src/screens/ProfileScreen.tsx @@ -48,7 +48,12 @@ export default function ProfileScreen() { borderColor: colors.primary, }} > - + {profile?.avatarUrl ? 'πŸ‘€' : '🌱'} @@ -155,6 +160,8 @@ export default function ProfileScreen() { disconnectWallet(); logout(); }} + accessibilityLabel="Disconnect and Sign Out" + accessibilityRole="button" style={{ marginTop: spacing.lg, padding: spacing.md, @@ -184,6 +191,8 @@ function SettingsRow({ return ( - navigation.goBack()} - accessibilityRole="button" - accessibilityLabel="Cancel" - style={{ - alignSelf: 'flex-start', - paddingVertical: spacing.sm, - paddingHorizontal: spacing.md, - marginLeft: -spacing.md, - minHeight: 44, - justifyContent: 'center', - }} - > + 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, @@ -288,6 +281,7 @@ export default function SendTokensScreen() { {error && ( void handleSend()} disabled={isSending} + accessibilityRole="button" + accessibilityLabel={isLobstr ? 'Send via Lobstr' : 'Send'} + accessibilityState={{ disabled: isSending }} style={{ padding: spacing.md, backgroundColor: colors.primary, diff --git a/src/screens/SubmitProofScreen.tsx b/src/screens/SubmitProofScreen.tsx index 09398eb..83f1b35 100644 --- a/src/screens/SubmitProofScreen.tsx +++ b/src/screens/SubmitProofScreen.tsx @@ -200,22 +200,8 @@ export default function SubmitProofScreen() { return ( - navigation.goBack()} - accessibilityRole="button" - accessibilityLabel="Back" - style={{ - alignSelf: 'flex-start', - paddingVertical: spacing.sm, - paddingHorizontal: spacing.md, - marginLeft: -spacing.md, - minHeight: 44, - justifyContent: 'center', - }} - > - - {'\u2190'} Back - + navigation.goBack()} accessibilityRole="button" accessibilityLabel="Go back"> + Back ) : ( - πŸ“· + πŸ“· @@ -266,15 +252,10 @@ export default function SubmitProofScreen() { {hasPermission === false && ( void requestPermission()} + onPress={requestPermission} accessibilityRole="button" - style={{ - marginTop: spacing.md, - paddingVertical: spacing.sm, - paddingHorizontal: spacing.md, - minHeight: 44, - justifyContent: 'center', - }} + accessibilityLabel="Grant Permission" + style={{ marginTop: spacing.md, padding: spacing.sm }} > Grant Permission @@ -307,6 +288,7 @@ export default function SubmitProofScreen() { {progress !== 'idle' && ( void handleCapture()} disabled={isSubmitting} + accessibilityRole="button" + accessibilityLabel="Take Photo" + accessibilityState={{ disabled: isSubmitting }} style={{ flex: 1, padding: spacing.md, @@ -368,6 +354,9 @@ export default function SubmitProofScreen() { setActivityId(null); }} disabled={isSubmitting} + accessibilityRole="button" + accessibilityLabel="Retake Photo" + accessibilityState={{ disabled: isSubmitting }} style={{ flex: 1, padding: spacing.md, @@ -383,6 +372,9 @@ export default function SubmitProofScreen() { void handleSubmit()} disabled={isSubmitting} + accessibilityRole="button" + accessibilityLabel="Submit Proof" + accessibilityState={{ disabled: isSubmitting }} style={{ flex: 1, padding: spacing.md, diff --git a/src/screens/SubmitScreen.tsx b/src/screens/SubmitScreen.tsx index 565fbe8..ed3bcad 100644 --- a/src/screens/SubmitScreen.tsx +++ b/src/screens/SubmitScreen.tsx @@ -45,7 +45,7 @@ export default function SubmitScreen() { Submit Proof - πŸ“Έ + πŸ“Έ 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 1a6a0f7..d80d469 100644 --- a/src/screens/TaskDetailScreen.tsx +++ b/src/screens/TaskDetailScreen.tsx @@ -62,18 +62,8 @@ export default function TaskDetailScreen() { alignItems: 'center', }} > - {error || 'Task not found'} - void loadTask()} - accessibilityRole="button" - style={{ - marginTop: spacing.md, - paddingVertical: spacing.sm, - paddingHorizontal: spacing.md, - minHeight: 44, - justifyContent: 'center', - }} - > + {error || 'Task not found'} + Try Again @@ -91,24 +81,15 @@ export default function TaskDetailScreen() { navigation.goBack()} accessibilityRole="button" - accessibilityLabel="Back" - style={{ - alignSelf: 'flex-start', - paddingVertical: spacing.sm, - paddingHorizontal: spacing.md, - marginLeft: -spacing.md, - marginTop: spacing.xl, - marginBottom: spacing.md, - minHeight: 44, - justifyContent: 'center', - }} + accessibilityLabel="Go back" + style={{ marginBottom: spacing.md, marginTop: spacing.xl }} > {'\u2190'} Back - + {TASK_TYPE_CONFIG[task.type]?.icon || 'πŸ“'} @@ -213,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 a297f55..21bb833 100644 --- a/src/screens/TaskListScreen.tsx +++ b/src/screens/TaskListScreen.tsx @@ -121,18 +121,8 @@ export default function TaskListScreen() { alignItems: 'center', }} > - {error} - void refresh()} - accessibilityRole="button" - style={{ - marginTop: spacing.md, - paddingVertical: spacing.sm, - paddingHorizontal: spacing.md, - minHeight: 44, - justifyContent: 'center', - }} - > + {error} + Retry @@ -168,6 +158,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', @@ -209,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, @@ -243,6 +239,7 @@ export default function TaskListScreen() { placeholderTextColor={colors.textSecondary} autoCapitalize="none" autoCorrect={false} + accessibilityLabel="Search tasks" style={{ backgroundColor: colors.surface, borderRadius: 12, @@ -268,6 +265,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, @@ -303,6 +303,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 722eb1e..f614f86 100644 --- a/src/screens/WalletScreen.tsx +++ b/src/screens/WalletScreen.tsx @@ -149,6 +149,8 @@ export default function WalletScreen() { navigation.navigate('SendTokens')} + accessibilityRole="button" + accessibilityLabel="Send Tokens" style={{ marginTop: spacing.xl, padding: spacing.md, @@ -162,6 +164,8 @@ export default function WalletScreen() {