Skip to content

Commit

Permalink
fix(ios) ios date props
Browse files Browse the repository at this point in the history
  • Loading branch information
gusparis committed May 3, 2020
1 parent c1856bc commit f23dca9
Show file tree
Hide file tree
Showing 10 changed files with 139 additions and 82 deletions.
32 changes: 15 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,24 +31,22 @@ import { View, Button, Text } from 'react-native';
import MonthPicker from 'react-native-month-year-picker';

const App = () => {
const [date, setDate] = useState(new Date());

const [show, setShow] = useState(false);
const [date, setDate] = useState();

const toggleMonthPicker = () => setShow(!show);

const onValueChange = (event, value) => setDate(value);
const onValueChange = (event, newDate) => setDate(newDate);

return (
<View>
<Button onPress={toggleMonthPicker} title="Open Month Picker"/>
<Text>`The selected date is: ${date}`</Text>
{show && (
<MonthPicker onChange={onValueChange} />
)}
</View>
)
}
<SafeAreaView style={styles.container}>
<Text>Month Picker Example</Text>
<MonthPicker
onChange={onValueChange}
value={date}
minimumDate={new Date()}
maximumDate={new Date(2025, 5)}
/>
</SafeAreaView>
);
};

export default App;

Expand Down Expand Up @@ -78,15 +76,15 @@ Defines the date value used in the component.

#### `maximumDate` (`optional`)

Defines the maximum date that can be selected.
Defines the maximum date that can be selected. Use year and month constructor.

```js
<RNMonthPicker maximumDate={new Date(2030, 10)} />
```

#### `minimumDate` (`optional`)

Defines the minimum date that can be selected.
Defines the minimum date that can be selected. Use year and month constructor.

```js
<RNMonthPicker minimumDate={new Date(2020, 5)} />
Expand Down
12 changes: 9 additions & 3 deletions example/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,19 @@ const styles = StyleSheet.create({
});

const App = () => {
const [date, setDate] = useState(null);
const [date, setDate] = useState(new Date());

const onValueChange = (event, newDate) => setDate(newDate);

return (
<SafeAreaView style={styles.container}>
<Text>Month Picker Example</Text>
<Text>{date}</Text>
<MonthPicker onChange={setDate} />
<MonthPicker
onChange={onValueChange}
value={date}
minimumDate={new Date()}
maximumDate={new Date(2025, 5)}
/>
</SafeAreaView>
);
};
Expand Down
4 changes: 2 additions & 2 deletions example/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
* @format
*/

import {AppRegistry} from 'react-native';
import { AppRegistry } from 'react-native';
import App from './App';
import {name as appName} from './app.json';
import { name as appName } from './app.json';

AppRegistry.registerComponent(appName, () => App);
4 changes: 2 additions & 2 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ PODS:
- React-cxxreact (= 0.62.2)
- React-jsi (= 0.62.2)
- React-jsinspector (0.62.2)
- react-native-month-year-picker (1.0.0):
- react-native-month-year-picker (1.0.1):
- React
- React-RCTActionSheet (0.62.2):
- React-Core/RCTActionSheetHeaders (= 0.62.2)
Expand Down Expand Up @@ -443,7 +443,7 @@ SPEC CHECKSUMS:
React-jsi: b6dc94a6a12ff98e8877287a0b7620d365201161
React-jsiexecutor: 1540d1c01bb493ae3124ed83351b1b6a155db7da
React-jsinspector: 512e560d0e985d0e8c479a54a4e5c147a9c83493
react-native-month-year-picker: c800ca806e87bcee6527695815d9f109dc16cc62
react-native-month-year-picker: 7dd62f9c53021394a7cead6f1ffaa3b7946790c9
React-RCTActionSheet: f41ea8a811aac770e0cc6e0ad6b270c644ea8b7c
React-RCTAnimation: 49ab98b1c1ff4445148b72a3d61554138565bad0
React-RCTBlob: a332773f0ebc413a0ce85942a55b064471587a71
Expand Down
6 changes: 3 additions & 3 deletions ios/RNMonthPicker.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
@interface RNMonthPicker : UIPickerView

@property (nonatomic, copy) RCTBubblingEventBlock onChange;
@property (nonatomic, strong) NSDate* value;
@property (nonatomic, strong) NSDate* minimumDate;
@property (nonatomic, strong) NSDate* maximumDate;
@property (nonatomic, assign) NSDate* value;
@property (nonatomic, assign) NSDate* minimumDate;
@property (nonatomic, assign) NSDate* maximumDate;

@end
132 changes: 86 additions & 46 deletions ios/RNMonthPicker.m
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,16 @@
#import <React/RCTConvert.h>
#import <React/RCTUtils.h>

#define DEFAULT_SIZE 204
#define DEFAULT_SIZE 408

@interface RNMonthPicker() <UIPickerViewDataSource, UIPickerViewDelegate>
@end

@implementation RNMonthPicker

NSCalendar *gregorian;
NSDateComponents *maxComponents;
NSDateComponents *minComponents;

NSMutableArray *months;
NSMutableArray *years;
Expand All @@ -29,33 +31,63 @@ - (instancetype)initWithFrame:(CGRect)frame
{
if ((self = [super initWithFrame:frame])) {
self.delegate = self;
NSDate *date = [NSDate date];
gregorian = [NSCalendar currentCalendar];
NSDateComponents *dateComponents = [gregorian components:(NSCalendarUnitMonth|NSCalendarUnitYear) fromDate:date];
NSInteger currentMonth = [dateComponents month];
NSInteger currentYear = [dateComponents year];

years = [NSMutableArray array];
for(NSInteger i = currentYear - DEFAULT_SIZE; i <= currentYear + DEFAULT_SIZE; i ++) {
[years addObject: [NSNumber numberWithLong:i]];
}

months = [NSMutableArray array];
NSDateFormatter *df = [[NSDateFormatter alloc] init];
for(NSInteger i = 0; i < 12; i ++){
[months addObject:[[df monthSymbols] objectAtIndex:(i)]];
}

selectedMonthRow = (DEFAULT_SIZE / 2) - 7 + currentMonth;
selectedYearRow = DEFAULT_SIZE;
[self selectRow:selectedMonthRow inComponent:0 animated:YES];
[self selectRow:selectedYearRow inComponent:1 animated:YES];
_value = nil;
_minimumDate = nil;
_maximumDate = nil;
}
return self;
}

RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)

- (void)initMonths {
months = [NSMutableArray array];
NSDateFormatter *df = [[NSDateFormatter alloc] init];
for(NSInteger i = 0; i < 12; i ++){
[months addObject:[[df monthSymbols] objectAtIndex:(i)]];
}
}

- (void)initYears:(NSInteger)selectedYear {
years = [NSMutableArray array];
for(NSInteger i = selectedYear - DEFAULT_SIZE; i <= selectedYear + DEFAULT_SIZE; i ++) {
[years addObject: [NSNumber numberWithLong:i]];
}
}

- (void)setValue:(nonnull NSDate *)value {
if (value != _value) {
NSDateComponents *selectedDateComponents = [gregorian components:(NSCalendarUnitMonth|NSCalendarUnitYear) fromDate:value];
if (!_value) {
[self initMonths];
[self initYears: [selectedDateComponents year]];

selectedMonthRow = [selectedDateComponents month] - 1;
selectedYearRow = DEFAULT_SIZE;
[self setSelectedRows: NO];
}
_value = value;
}
}

-(void)setSelectedRows:(BOOL)animated {
dispatch_async(dispatch_get_main_queue(), ^{
[self selectRow:selectedMonthRow inComponent:0 animated:animated];
[self selectRow:selectedYearRow inComponent:1 animated:animated];
});
}

- (void)setMaximumDate:(NSDate *)maximumDate {
_maximumDate = maximumDate;
maxComponents = _maximumDate ? [gregorian components:NSCalendarUnitMonth | NSCalendarUnitYear fromDate:_maximumDate] : nil;
}

- (void)setMinimumDate:(NSDate *)minimumDate {
_minimumDate = minimumDate;
minComponents = _minimumDate ? [gregorian components:NSCalendarUnitMonth | NSCalendarUnitYear fromDate:_minimumDate] : nil;
}

#pragma mark - UIPickerViewDataSource protocol
// number of columns
- (NSInteger)numberOfComponentsInPickerView:(nonnull UIPickerView *)pickerView {
Expand All @@ -66,7 +98,7 @@ - (NSInteger)numberOfComponentsInPickerView:(nonnull UIPickerView *)pickerView {
- (NSInteger)pickerView:(nonnull UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
switch (component) {
case 0:
return DEFAULT_SIZE;
return [months count];
case 1:
return [years count];
break;
Expand All @@ -80,47 +112,55 @@ - (NSInteger)pickerView:(nonnull UIPickerView *)pickerView numberOfRowsInCompone
- (NSString *)pickerView:(nonnull UIPickerView *) pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
switch (component) {
case 0:
return [NSString stringWithFormat:@"%@", months[row % 12]];
return [NSString stringWithFormat:@"%@", months[row]];
case 1:
return [NSString stringWithFormat:@"%@", years[row]];
default:
return nil;
}
}

- (void)getSelectedMonthRow:(NSInteger)row {
NSInteger month = row + 1;
NSInteger year = [years[selectedYearRow] longValue];
if (minComponents && year == [minComponents year] && month < [minComponents month]) {
selectedMonthRow = [minComponents month] - 1;
} else if (maxComponents && year == [maxComponents year] && month > [maxComponents month]) {
selectedMonthRow = [maxComponents month] - 1;
} else {
selectedMonthRow = row;
}
}

- (void)getSelectedYearRow:(NSInteger)row {
NSInteger year = [years[row] longValue];
if (minComponents && (year < [minComponents year])) {
selectedYearRow = [years indexOfObject:[NSNumber numberWithInteger:[minComponents year]]];
} else if (maxComponents && year > [maxComponents year]) {
selectedYearRow = [years indexOfObject:[NSNumber numberWithInteger:[maxComponents year]]];
} else {
selectedYearRow = row;
}
}

- (void)pickerView:(__unused UIPickerView *)pickerView
didSelectRow:(NSInteger)row inComponent:(__unused NSInteger)component
{
NSDateComponents *minComponents = _minimumDate ? [gregorian components:NSCalendarUnitMonth | NSCalendarUnitYear fromDate:_minimumDate] : nil;
NSDateComponents *maxComponents = _maximumDate ? [gregorian components:NSCalendarUnitMonth | NSCalendarUnitYear fromDate:_maximumDate] : nil;

switch (component) {
case 0: {
NSInteger tmpMonth = (row % 12) + 1;
NSInteger tmpYear = [years[selectedYearRow] longValue];
if ((minComponents && tmpYear == [minComponents year] && tmpMonth < [minComponents month]) || (maxComponents && tmpYear == [maxComponents year] && tmpMonth > [maxComponents month])) {
[self selectRow:selectedMonthRow inComponent:0 animated:true];
return;
}
selectedMonthRow = row;
break;td
}
case 1: {
NSInteger tmpYear = [years[row] longValue];
if ((minComponents && tmpYear < [minComponents year]) || (maxComponents && tmpYear > [maxComponents year])) {
[self selectRow:selectedYearRow inComponent:1 animated:true];
return;
}
selectedYearRow = row;
case 0:
[self getSelectedMonthRow:row];
break;
case 1:
[self getSelectedYearRow:row];
[self getSelectedMonthRow:selectedMonthRow];
break;
}
default:
return;
}

[self setSelectedRows: YES];
if (_onChange) {
_onChange(@{
@"newDate": [NSString stringWithFormat: @"%@-%@", [NSString stringWithFormat: @"%ld", (selectedMonthRow % 12) + 1], [NSString stringWithFormat: @"%@", years[selectedYearRow]]]
@"newDate": [NSString stringWithFormat: @"%@-%@", [NSString stringWithFormat: @"%ld", selectedMonthRow + 1], [NSString stringWithFormat: @"%@", years[selectedYearRow]]]
});
}
}
Expand Down
2 changes: 1 addition & 1 deletion ios/RNMonthPickerManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

#import "RNMonthPickerManager.h"
#import "RNMonthPicker.h"

@implementation RNMonthPickerManager

RCT_EXPORT_MODULE()
Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"readmeFilename": "README.md",
"peerDependencies": {
"react": "*",
"react-native": ">=0.60.0-rc.0 <1.0.x"
"react-native": "*"
},
"devDependencies": {
"@react-native-community/eslint-config": "^1.1.0",
Expand All @@ -38,10 +38,11 @@
"conventional-changelog-eslint": "^3.0.4",
"eslint": "^6.8.0",
"react": "16.11.0",
"react-native": "^0.62.2",
"react-native": "0.62.2",
"semantic-release": "^17.0.7"
},
"dependencies": {
"invariant": "^2.2.4",
"moment": "^2.24.0"
}
}
9 changes: 8 additions & 1 deletion src/MonthPicker.ios.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import { View, StyleSheet } from 'react-native';
import moment from 'moment';
import invariant from 'invariant';

import RNMonthPickerView from './RNMonthPickerNativeComponent';

Expand All @@ -12,7 +13,12 @@ const styles = StyleSheet.create({
picker: { flex: 1 },
});

const MonthPicker = ({ onChange, outputFormat, ...restProps }) => {
const MonthPicker = ({ onChange, value, outputFormat, ...restProps }) => {
invariant(value, 'value prop is required!');

const getLongFromDate = (selectedValue) =>
moment(selectedValue, outputFormat || DEFAULT_OUTPUT_FORMAT).valueOf();

const onValueChange = (event) => {
const date = moment(event.nativeEvent.newDate, NATIVE_FORMAT).format(
outputFormat || DEFAULT_OUTPUT_FORMAT,
Expand All @@ -25,6 +31,7 @@ const MonthPicker = ({ onChange, outputFormat, ...restProps }) => {
<RNMonthPickerView
style={styles.picker}
onChange={onValueChange}
value={getLongFromDate(value)}
{...restProps}
/>
</View>
Expand Down
Loading

0 comments on commit f23dca9

Please sign in to comment.