Files
orca/mobile/src/components/CodexResetCreditAction.tsx
T
kazu-42andBrennan Benson 4a71a0ecb2 feat(mobile): add safe Codex rate-limit resets (#9394)
* feat(mobile): add safe Codex rate-limit resets

* fix(mobile): address reset credit review feedback

* review: purge removed-account reset attempts, shared capability constant, rebase test mocks

* review: preserve host compatibility and reset durability

* fix(mobile): recover reset capability after cutover

* fix(mobile): validate runtime capability payloads

* fix(mobile): enforce capability payload contract

* fix(mobile): route mock terminals to selected worktree

* test(mobile): pin malformed probe retry behavior

---------

Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
2026-07-24 14:42:04 -07:00

111 lines
2.9 KiB
TypeScript

import { ActivityIndicator, Pressable, StyleSheet, Text, View } from 'react-native'
import { RotateCcw } from 'lucide-react-native'
import { colors, radii, spacing, typography } from '../theme/mobile-theme'
import type { CodexResetCreditSummary } from './codex-reset-credit'
export function CodexResetCreditAction({
summary,
scopeLabel,
busy,
disabled,
onPress
}: {
summary: CodexResetCreditSummary
scopeLabel?: string | null
busy: boolean
disabled: boolean
onPress: () => void
}) {
return (
<>
<View style={styles.separator} />
<View style={styles.row}>
<View style={styles.copy}>
<Text style={styles.title}>{summary.availabilityLabel}</Text>
<Text style={styles.subtitle}>
{[summary.expiryLabel, scopeLabel].filter(Boolean).join(' · ') ||
'Earned Codex rate-limit reset'}
</Text>
</View>
<Pressable
style={({ pressed }) => [
styles.button,
disabled && styles.buttonDisabled,
pressed && !disabled && styles.buttonPressed
]}
onPress={onPress}
disabled={disabled}
accessibilityRole="button"
accessibilityLabel={busy ? 'Resetting Codex rate limits' : 'Use Codex rate-limit reset'}
accessibilityHint={
scopeLabel
? `Uses one earned reset for ${scopeLabel}`
: 'Uses one earned reset for the active Codex account'
}
accessibilityState={{ busy, disabled }}
hitSlop={8}
>
{busy ? (
<ActivityIndicator size="small" color={colors.textPrimary} />
) : (
<RotateCcw size={14} color={colors.textPrimary} />
)}
<Text style={styles.buttonText}>{busy ? 'Resetting…' : 'Use reset'}</Text>
</Pressable>
</View>
</>
)
}
const styles = StyleSheet.create({
separator: {
height: StyleSheet.hairlineWidth,
backgroundColor: colors.borderSubtle,
marginHorizontal: spacing.md
},
row: {
flexDirection: 'row',
alignItems: 'center',
gap: spacing.md,
paddingVertical: spacing.md,
paddingHorizontal: spacing.md + 2
},
copy: {
flex: 1,
gap: spacing.xs
},
title: {
fontSize: typography.bodySize,
fontWeight: '500',
color: colors.textPrimary
},
subtitle: {
fontSize: typography.metaSize,
color: colors.textSecondary
},
button: {
minHeight: 44,
width: 104,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
gap: spacing.sm,
paddingHorizontal: spacing.md,
borderWidth: StyleSheet.hairlineWidth,
borderColor: colors.borderSubtle,
borderRadius: radii.button,
backgroundColor: colors.bgRaised
},
buttonPressed: {
opacity: 0.72
},
buttonDisabled: {
opacity: 0.5
},
buttonText: {
fontSize: typography.metaSize,
fontWeight: '600',
color: colors.textPrimary
}
})