Skip to content

Commit 01e52d2

Browse files
authored
Merge pull request #123 from Francis6-git/feat/date-picker-issue-47
implement native date and time picker for billing date #47
2 parents d9aa012 + 5f60b68 commit 01e52d2

3 files changed

Lines changed: 99 additions & 2 deletions

File tree

package-lock.json

Lines changed: 24 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
},
3030
"dependencies": {
3131
"@react-native-async-storage/async-storage": "2.1.2",
32+
"@react-native-community/datetimepicker": "^9.1.0",
3233
"@react-native-community/netinfo": "11.4.1",
3334
"@react-navigation/bottom-tabs": "^6.5.11",
3435
"@react-navigation/native": "^6.1.9",

src/screens/AddSubscriptionScreen.tsx

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import { colors, spacing, typography, borderRadius } from '../utils/constants';
1818
import { SubscriptionCategory, BillingCycle, SubscriptionFormData } from '../types/subscription';
1919
import { useSubscriptionStore } from '../store';
2020
import { Button } from '../components/common/Button';
21+
import { formatCurrency } from '../utils/formatting';
22+
import DateTimePicker, { DateTimePickerEvent } from '@react-native-community/datetimepicker';
2123

2224
const AddSubscriptionScreen: React.FC = () => {
2325
const navigation = useNavigation<NativeStackNavigationProp<RootStackParamList>>();
@@ -44,6 +46,10 @@ const AddSubscriptionScreen: React.FC = () => {
4446
BillingCycle.MONTHLY
4547
);
4648

49+
// Date Picker States
50+
const [showPicker, setShowPicker] = useState(false);
51+
const [pickerMode, setPickerMode] = useState<'date' | 'time'>('date');
52+
4753
const handleCategorySelect = (category: SubscriptionCategory) => {
4854
setSelectedCategory(category);
4955
setFormData((prev) => ({ ...prev, category }));
@@ -56,11 +62,38 @@ const AddSubscriptionScreen: React.FC = () => {
5662

5763
const handleInputChange = (
5864
field: keyof SubscriptionFormData,
59-
value: string | number | boolean
65+
value: string | number | boolean | Date
6066
) => {
6167
setFormData((prev) => ({ ...prev, [field]: value }));
6268
};
6369

70+
const onDateChange = (event: DateTimePickerEvent, selectedDate?: Date) => {
71+
if (event.type === 'dismissed') {
72+
setShowPicker(false);
73+
return;
74+
}
75+
76+
if (selectedDate) {
77+
handleInputChange('nextBillingDate', selectedDate);
78+
79+
if (Platform.OS === 'android' && pickerMode === 'date') {
80+
setShowPicker(false);
81+
setTimeout(() => {
82+
setPickerMode('time');
83+
setShowPicker(true);
84+
}, 100);
85+
} else if (Platform.OS === 'android' && pickerMode === 'time') {
86+
setShowPicker(false);
87+
setPickerMode('date');
88+
}
89+
}
90+
};
91+
92+
const showPickerHandler = () => {
93+
setPickerMode('date');
94+
setShowPicker(true);
95+
};
96+
6497
const handleSubmit = async () => {
6598
if (!formData.name.trim()) {
6699
Alert.alert('Error', 'Please enter a subscription name');
@@ -202,6 +235,32 @@ const AddSubscriptionScreen: React.FC = () => {
202235
</View>
203236
</View>
204237

238+
<View style={styles.inputGroup}>
239+
<Text style={styles.label}>Next Billing Date *</Text>
240+
<TouchableOpacity
241+
style={styles.datePickerButton}
242+
onPress={showPickerHandler}
243+
>
244+
<Text style={styles.datePickerText}>
245+
{formData.nextBillingDate.toLocaleString([], {
246+
dateStyle: 'medium',
247+
timeStyle: 'short',
248+
})}
249+
</Text>
250+
</TouchableOpacity>
251+
252+
{showPicker && (
253+
<DateTimePicker
254+
value={formData.nextBillingDate}
255+
mode={pickerMode}
256+
is24Hour={true}
257+
display={Platform.OS === 'ios' ? 'inline' : 'default'}
258+
onChange={onDateChange}
259+
minimumDate={new Date()}
260+
/>
261+
)}
262+
</View>
263+
205264
<View style={styles.inputGroup}>
206265
<Text style={styles.label}>Billing Cycle</Text>
207266
<View style={styles.billingCycleContainer}>
@@ -395,6 +454,19 @@ const styles = StyleSheet.create({
395454
...typography.h3,
396455
fontWeight: '600',
397456
},
457+
// Date picker styling
458+
datePickerButton: {
459+
backgroundColor: colors.surface,
460+
padding: spacing.md,
461+
borderRadius: borderRadius.md,
462+
borderWidth: 1,
463+
borderColor: colors.border,
464+
justifyContent: 'center',
465+
},
466+
datePickerText: {
467+
...typography.body,
468+
color: colors.text,
469+
},
398470
categoryGrid: {
399471
flexDirection: 'row',
400472
flexWrap: 'wrap',
@@ -495,4 +567,4 @@ const styles = StyleSheet.create({
495567
},
496568
});
497569

498-
export default AddSubscriptionScreen;
570+
export default AddSubscriptionScreen;

0 commit comments

Comments
 (0)