Skip to content

DateTimePicker - start deprecation of moment props #2625

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 49 additions & 7 deletions demo/src/screens/componentScreens/DateTimePickerScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,23 @@
import React, {Component} from 'react';
import {ScrollView} from 'react-native';
import {DateTimePicker, DateTimePickerProps, View, Text} from 'react-native-ui-lib'; // eslint-disable-line
import moment from 'moment';
import * as LightDate from 'light-date';
import {DateTimePicker, DateTimePickerProps, DateTimePickerMode, View, Text, Switch} from 'react-native-ui-lib';

interface State {
mode: DateTimePickerMode;
dateTimeFormatter: 'moment' | 'light-date';
}

export default class DateTimePickerScreen extends Component<{}, State> {
constructor(props: any) {
super(props);
this.state = {
mode: 'time',
dateTimeFormatter: 'moment'
};
}

export default class DateTimePickerScreen extends Component {
getCustomInputValue = (value?: string) => {
if (!value) {
return 'Default';
Expand All @@ -21,7 +36,27 @@ export default class DateTimePickerScreen extends Component {
);
};

toggleTimeOrDate = () => {
this.setState({mode: this.state.mode === 'time' ? 'date' : 'time'});
};

toggleFormatter = () => {
this.setState({dateTimeFormatter: this.state.dateTimeFormatter === 'moment' ? 'light-date' : 'moment'});
};

getFormatter = (): DateTimePickerProps['dateTimeFormatter'] => {
const {dateTimeFormatter} = this.state;
if (dateTimeFormatter === 'moment') {
return (value: Date, mode: DateTimePickerMode) =>
moment(value).format(mode === 'date' ? 'MMM D, YYYY' : 'h:mm A');
} else {
return (value: Date, mode: DateTimePickerMode) =>
LightDate.format(value, mode === 'date' ? '{mm}-{dd}-{yyyy}' : '{HH}:{mm}');
}
};

render() {
const {mode, dateTimeFormatter} = this.state;
return (
<ScrollView>
<View padding-page>
Expand All @@ -31,15 +66,13 @@ export default class DateTimePickerScreen extends Component {
containerStyle={{marginVertical: 20}}
label={'Date'}
placeholder={'Select a date'}
// dateFormat={'MMM D, YYYY'}
// value={new Date('October 13, 2014')}
/>
<DateTimePicker
migrateTextField
mode={'time'}
label={'Time'}
placeholder={'Select time'}
// timeFormat={'h:mm A'}
// value={new Date('2015-03-25T12:00:00-06:30')}
/>

Expand All @@ -64,13 +97,22 @@ export default class DateTimePickerScreen extends Component {
<Text text60R marginT-40>
Custom Input
</Text>
<View row marginV-20 centerV spread>
<View row>
<Text text80>{mode}</Text>
<Switch value={mode === 'time'} onValueChange={this.toggleTimeOrDate} marginL-10/>
</View>
<View row>
<Text text80>{dateTimeFormatter}</Text>
<Switch value={dateTimeFormatter === 'moment'} onValueChange={this.toggleFormatter} marginL-10/>
</View>
</View>
<DateTimePicker
migrateTextField
containerStyle={{marginVertical: 20}}
label={'Date'}
placeholder={'Select a date'}
renderInput={this.renderCustomInput}
dateFormat={'MMM D, YYYY'}
mode={mode}
dateTimeFormatter={this.getFormatter()}
// value={new Date('2015-03-25T12:00:00-06:30')}
/>
</View>
Expand Down
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,10 @@
"prop-types": "^15.5.10",
"react-freeze": "^1.0.0",
"react-native-redash": "^12.0.3",
"wix-react-native-text-size": "~1.0.0",
"semver": "^5.5.0",
"tinycolor2": "^1.4.2",
"url-parse": "^1.2.0"
"url-parse": "^1.2.0",
"wix-react-native-text-size": "~1.0.0"
},
"devDependencies": {
"@babel/cli": "^7.16.8",
Expand All @@ -66,7 +66,6 @@
"@formatjs/intl-locale": "^3.0.3",
"@formatjs/intl-numberformat": "^8.0.4",
"@formatjs/intl-pluralrules": "^5.0.3",
"react-native-mmkv": "2.6.1",
"@react-native-community/blur": "4.3.0",
"@react-native-community/datetimepicker": "^3.4.6",
"@react-native-community/netinfo": "^5.6.2",
Expand Down Expand Up @@ -96,6 +95,7 @@
"eslint-plugin-uilib": "file:./eslint-rules",
"gh-pages": "^1.1.0",
"jest": "^29.2.1",
"light-date": "^1.2.0",
"metro-react-native-babel-preset": "0.73.7",
"mocha": "^5.0.0",
"moment": "^2.24.0",
Expand All @@ -110,6 +110,7 @@
"react-native-gesture-handler": "2.9.0",
"react-native-haptic-feedback": "^1.11.0",
"react-native-linear-gradient": "2.6.2",
"react-native-mmkv": "2.6.1",
"react-native-navigation": "7.32.1",
"react-native-reanimated": "3.1.0",
"react-native-shimmer-placeholder": "^2.0.6",
Expand Down
13 changes: 6 additions & 7 deletions src/components/dateTimePicker/dateTimePicker.api.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,11 @@
{"name": "editable", "type": "boolean", "description": "Should this input be editable or disabled"},
{"name": "minimumDate", "type": "Date", "description": "The minimum date or time value to use"},
{"name": "maximumDate", "type": "Date", "description": "The maximum date or time value to use"},
{"name": "dateFormat", "type": "string", "description": "The date format for the text display"},
{"name": "dateFormatter", "type": "() => Date", "description": "A callback function to format date"},
{"name": "timeFormat", "type": "string", "description": "The time format for the text display"},
{"name": "timeFormatter", "type": "() => Date", "description": "A callback function to format time"},
{
"name": "dateTimeFormatter",
"type": "(value: Date, mode: DateTimePickerMode) => string",
"description": "A callback function to format the time or date"
},
{
"name": "locale",
"type": "string",
Expand Down Expand Up @@ -62,7 +63,5 @@
"description": "Override system theme variant (dark or light mode) used by the date picker"
}
],
"snippet": [
"<DateTimePicker title={'Select time'$1} placeholder={'Placeholder'$2} mode={'time'$3}/>"
]
"snippet": ["<DateTimePicker title={'Select time'$1} placeholder={'Placeholder'$2} mode={'time'$3}/>"]
}
61 changes: 20 additions & 41 deletions src/components/dateTimePicker/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import React, {
ForwardedRef
} from 'react';
import {StyleProp, StyleSheet, ViewStyle} from 'react-native';
import {DateTimePickerPackage as RNDateTimePicker, MomentPackage as moment} from '../../optionalDependencies';
import {DateTimePickerPackage as RNDateTimePicker} from '../../optionalDependencies';
import {useDidUpdate} from '../../hooks';
import {Colors} from '../../style';
import Assets from '../../assets';
Expand All @@ -20,17 +20,15 @@ import View from '../view';
import Button from '../button';
import ExpandableOverlay, {ExpandableOverlayMethods, RenderCustomOverlayProps} from '../../incubator/expandableOverlay';
import type {TextFieldProps, TextFieldMethods} from '../../incubator/TextField';
import useOldApi, {OldApiProps} from './useOldApi';

const MODES = {
DATE: 'date',
TIME: 'time'
};
export type DateTimePickerMode = 'date' | 'time';

export type DateTimePickerProps = Omit<TextFieldProps, 'value' | 'onChange'> & {
export type DateTimePickerProps = OldApiProps & Omit<TextFieldProps, 'value' | 'onChange'> & {
/**
* The type of picker to display ('date' or 'time')
*/
mode?: 'date' | 'time';
mode?: DateTimePickerMode;
/**
* The initial value to set the picker to. Defaults to device's date / time
*/
Expand All @@ -52,21 +50,11 @@ export type DateTimePickerProps = Omit<TextFieldProps, 'value' | 'onChange'> & {
*/
maximumDate?: Date;
/**
* The date format for the text display
*/
dateFormat?: string;
/**
* A callback function to format date
* A callback function to format the time or date
* @param mode the type of the picker ('date' or 'time')
* @returns the formatted string to display
*/
dateFormatter?: (date: Date) => string;
/**
* The time format for the text display
*/
timeFormat?: string;
/**
* A callback function to format time
*/
timeFormatter?: (date: Date) => string;
dateTimeFormatter?: (value: Date, mode: DateTimePickerMode) => string;
/**
* Allows changing of the locale of the component (iOS only)
*/
Expand Down Expand Up @@ -126,11 +114,12 @@ const DateTimePicker = forwardRef((props: DateTimePickerPropsInternal, ref: Forw
value: propsValue,
renderInput,
editable,
mode = MODES.DATE,
mode = 'date',
dateFormat,
timeFormat,
dateFormatter,
timeFormatter,
dateTimeFormatter,
minimumDate,
maximumDate,
locale,
Expand Down Expand Up @@ -161,16 +150,11 @@ const DateTimePicker = forwardRef((props: DateTimePickerPropsInternal, ref: Forw

useEffect(() => {
if (!RNDateTimePicker) {
// eslint-disable-next-line max-len
console.error(`RNUILib DateTimePicker component requires installing "@react-native-community/datetimepicker" dependency`);
}
}, []);

useEffect(() => {
if (!moment && (dateFormat || timeFormat)) {
console.error(`RNUILib DateTimePicker component with date/time format requires installing "moment" dependency`);
}
}, [dateFormat, timeFormat]);

useDidUpdate(() => {
setValue(propsValue);
}, [propsValue]);
Expand All @@ -193,21 +177,16 @@ const DateTimePicker = forwardRef((props: DateTimePickerPropsInternal, ref: Forw
};
}, [dialogProps, testID]);

const {getStringValue: getStringValueOld} = useOldApi({dateFormat, dateFormatter, timeFormat, timeFormatter});

const getStringValue = () => {
if (value) {
switch (mode) {
case MODES.DATE:
return dateFormatter
? dateFormatter(value)
: dateFormat && moment
? moment(value).format(dateFormat)
: value.toLocaleDateString();
case MODES.TIME:
return timeFormatter
? timeFormatter(value)
: timeFormat && moment
? moment(value).format(timeFormat)
: value.toLocaleTimeString();
if (dateTimeFormatter) {
return dateTimeFormatter(value, mode);
} else {
return getStringValueOld(value, mode);
// TODO: once we remove the old implementation, add the following:
// return mode === 'time' ? value.toLocaleTimeString() : value.toLocaleDateString();
}
}
};
Expand Down
64 changes: 64 additions & 0 deletions src/components/dateTimePicker/useOldApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// TODO: delete whole file in v8
import {useEffect} from 'react';
import {MomentPackage as moment} from '../../optionalDependencies';

export interface OldApiProps {
/**
* @deprecated
* The date format for the text display
*/
dateFormat?: string;
/**
* @deprecated
* A callback function to format date
*/
dateFormatter?: (date: Date) => string;
/**
* @deprecated
* The time format for the text display
*/
timeFormat?: string;
/**
* @deprecated
* A callback function to format time
*/
timeFormatter?: (date: Date) => string;
}

// This file will be deleted in the next major version,
// duplicating these here will make this less complicated
// than removing the duplication
type Mode = 'date' | 'time';

const useOldApi = (props: OldApiProps) => {
const {dateFormat, dateFormatter, timeFormat, timeFormatter} = props;

useEffect(() => {
if (!moment && (dateFormat || timeFormat)) {
console.error(`RNUILib DateTimePicker component with date/time format requires installing "moment" dependency`);
}
}, [dateFormat, timeFormat]);

const getStringValue = (value: Date, mode: Mode) => {
if (value) {
switch (mode) {
case 'date':
return dateFormatter
? dateFormatter(value)
: dateFormat && moment
? moment(value).format(dateFormat)
: value.toLocaleDateString();
case 'time':
return timeFormatter
? timeFormatter(value)
: timeFormat && moment
? moment(value).format(timeFormat)
: value.toLocaleTimeString();
}
}
};

return {getStringValue};
};

export default useOldApi;
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export {default as ColorSliderGroup, ColorSliderGroupProps} from './components/s
export {default as ColorSwatch, ColorSwatchProps} from './components/colorSwatch';
export {default as ConnectionStatusBar, ConnectionStatusBarProps} from './components/connectionStatusBar';
export {default as Dash, DashProps} from './components/dash';
export {default as DateTimePicker, DateTimePickerProps} from './components/dateTimePicker';
export {default as DateTimePicker, DateTimePickerProps, DateTimePickerMode} from './components/dateTimePicker';
export {default as Dialog, DialogProps, DialogDirections, DialogDirectionsEnum} from './components/dialog';
export {default as Drawer, DrawerProps, DrawerItemProps} from './components/drawer';
export {default as ExpandableSection, ExpandableSectionProps} from './components/expandableSection';
Expand Down