@@ -29,6 +29,7 @@ const AddSubscriptionScreen: React.FC = () => {
2929 description : '' ,
3030 category : SubscriptionCategory . OTHER ,
3131 price : 0 ,
32+ priceError : '' ,
3233 currency : 'USD' ,
3334 billingCycle : BillingCycle . MONTHLY ,
3435 nextBillingDate : new Date ( ) ,
@@ -99,8 +100,8 @@ const AddSubscriptionScreen: React.FC = () => {
99100 return ;
100101 }
101102
102- if ( formData . price <= 0 ) {
103- Alert . alert ( 'Error' , 'Please enter a valid price' ) ;
103+ if ( formData . priceError || ! formData . price || formData . price <= 0 || Number . isNaN ( formData . price ) ) {
104+ Alert . alert ( 'Error' , formData . priceError || 'Please enter a valid price' ) ;
104105 return ;
105106 }
106107
@@ -149,7 +150,7 @@ const AddSubscriptionScreen: React.FC = () => {
149150 < KeyboardAvoidingView
150151 style = { styles . keyboardAvoidingView }
151152 behavior = { Platform . OS === 'ios' ? 'padding' : 'height' } >
152- < ScrollView style = { styles . scrollView } >
153+ < ScrollView style = { styles . scrollView } keyboardShouldPersistTaps = "handled" >
153154 < View style = { styles . header } >
154155 < View style = { styles . headerContent } >
155156 < TouchableOpacity onPress = { handleCancel } style = { styles . cancelButton } >
@@ -224,14 +225,33 @@ const AddSubscriptionScreen: React.FC = () => {
224225 style = { styles . priceInput }
225226 value = { formData . price > 0 ? formData . price . toString ( ) : '' }
226227 onChangeText = { ( text ) => {
227- const numValue = parseFloat ( text ) || 0 ;
228+ if ( text . trim ( ) === '' ) {
229+ handleInputChange ( 'priceError' , '' ) ;
230+ handleInputChange ( 'price' , 0 ) ;
231+ return ;
232+ }
233+ // Reject non-numeric input (allow digits, one dot, leading/trailing spaces)
234+ if ( ! / ^ [ \d . , \s ] * $ / . test ( text . trim ( ) ) ) {
235+ handleInputChange ( 'priceError' , 'Price must be a valid number' ) ;
236+ return ;
237+ }
238+ const normalized = text . replace ( / , / g, '.' ) . trim ( ) ;
239+ const numValue = parseFloat ( normalized ) ;
240+ if ( Number . isNaN ( numValue ) ) {
241+ handleInputChange ( 'priceError' , 'Price must be a valid number' ) ;
242+ } else {
243+ handleInputChange ( 'priceError' , '' ) ;
244+ }
228245 handleInputChange ( 'price' , numValue ) ;
229246 } }
230247 placeholder = "0.00"
231248 placeholderTextColor = { colors . textSecondary }
232249 keyboardType = "decimal-pad"
233250 />
234251 </ View >
252+ { formData . priceError ? (
253+ < Text style = { styles . errorText } > { formData . priceError } </ Text >
254+ ) : null }
235255 </ View >
236256
237257 < View style = { styles . inputGroup } >
@@ -416,6 +436,11 @@ const styles = StyleSheet.create({
416436 marginBottom : spacing . xs ,
417437 fontWeight : '500' ,
418438 } ,
439+ errorText : {
440+ color : colors . error || '#e74c3c' ,
441+ fontSize : 12 ,
442+ marginTop : spacing . xs ,
443+ } ,
419444 textInput : {
420445 backgroundColor : colors . surface ,
421446 padding : spacing . md ,
0 commit comments