Skip to content

Commit

Permalink
Refactoring & optimizing
Browse files Browse the repository at this point in the history
  • Loading branch information
wojtekmaj committed Jul 29, 2017
1 parent 6ca7f72 commit 93a8307
Show file tree
Hide file tree
Showing 24 changed files with 281 additions and 298 deletions.
1 change: 1 addition & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
},
"rules": {
"global-require": "off",
"max-len": "error",
"no-param-reassign": ["error", { "props": true, "ignorePropertyModificationsFor": ["canvas", "element"] }],
"prefer-destructuring": "warn",
"prefer-spread": "warn",
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-calendar",
"version": "0.2.0-alpha",
"version": "0.3.0-alpha",
"description": "Ultimate date picker for your React application.",
"main": "build/entry.js",
"es6": "src/entry.js",
Expand Down
167 changes: 77 additions & 90 deletions src/Calendar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import MonthView from './MonthView';

import { getBegin, getRange } from './shared/dates';
import { setLocale } from './shared/locales';
import { isCalendarType } from './shared/propTypes';
import { isCalendarType, isValue } from './shared/propTypes';
import { mergeFunctions } from './shared/utils';

const allViews = ['century', 'decade', 'year', 'month'];
const allValueTypes = [...allViews.slice(1), 'day'];
Expand All @@ -32,20 +33,47 @@ export default class Calendar extends Component {
}

/**
* Returns views array with disallowed values cut off.
* Returns value type that can be returned with currently applied settings.
*/
getLimitedViews(props = this.props) {
const { minDetail, maxDetail } = props;
get valueType() {
const { maxDetail } = this.props;
return allValueTypes[allViews.indexOf(maxDetail)];
}

return allViews.slice(allViews.indexOf(minDetail), allViews.indexOf(maxDetail) + 1);
get valueFrom() {
const { value } = this.props;
return this.getValueFrom(value);
}

get valueTo() {
const { value } = this.props;
return this.getValueTo(value);
}

getValueArray(value) {
if (value instanceof Array) {
return value;
}
return getRange(this.valueType, value);
}

getValueFrom(value) {
const rawValueFrom = value instanceof Array ? value[0] : value;
return getRange(this.valueType, rawValueFrom)[0];
}

getValueTo(value) {
const rawValueFrom = value instanceof Array ? value[1] : value;
return getRange(this.valueType, rawValueFrom)[1];
}

/**
* Returns value type that can be returned with currently applied settings.
* Returns views array with disallowed values cut off.
*/
getValueType(props = this.props) {
const { maxDetail } = props;
return allValueTypes[allViews.indexOf(maxDetail)];
getLimitedViews(props = this.props) {
const { minDetail, maxDetail } = props;

return allViews.slice(allViews.indexOf(minDetail), allViews.indexOf(maxDetail) + 1);
}

/**
Expand All @@ -60,24 +88,23 @@ export default class Calendar extends Component {
/**
* Gets current value in a desired format.
*/
getValueFromRange(valueRange = this.state.value) {
getProcessedValue(value) {
const { returnValue } = this.props;

switch (returnValue) {
case 'start':
return valueRange[0];
return this.getValueFrom(value);
case 'end':
return valueRange[1];
return this.getValueTo(value);
case 'range':
return valueRange;
return this.getValueArray(value);
default:
throw new Error('Invalid returnValue.');
}
}

state = {
activeStartDate: this.getActiveStartDate(),
value: this.getValue(),
view: this.getView(),
}

Expand All @@ -93,11 +120,22 @@ export default class Calendar extends Component {
nextProps.maxDetail !== props.maxDetail
);

const valueChanged = (
(nextProps.value && !props.value) ||
(nextProps.value && props.value && nextProps.value.getTime() !== props.value.getTime())
const nextValueFrom = this.getValueFrom(nextProps.value);
const valueFrom = this.getValueFrom(props.value);
const valueFromChanged = (
(nextValueFrom && !valueFrom) ||
(nextValueFrom && valueFrom && nextValueFrom.getTime() !== valueFrom.getTime())
);

const nextValueTo = this.getValueTo(nextProps.value);
const valueTo = this.getValueTo(props.value);
const valueToChanged = (
(nextValueTo && !valueTo) ||
(nextValueTo && valueTo && nextValueTo.getTime() !== valueTo.getTime())
);

const valueChanged = valueFromChanged || valueToChanged;

const nextState = {};

if (nextProps.locale !== props.locale) {
Expand All @@ -111,7 +149,6 @@ export default class Calendar extends Component {
}

if (allowedViewChanged || valueChanged) {
nextState.value = this.getValue(nextProps);
nextState.activeStartDate = this.getActiveStartDate(nextProps);
}

Expand All @@ -120,12 +157,7 @@ export default class Calendar extends Component {

getActiveStartDate(props = this.props) {
const rangeType = this.getView(props);
return getBegin(rangeType, props.value);
}

getValue(props = this.props) {
const rangeType = this.getValueType(props);
return getRange(rangeType, props.value);
return getBegin(rangeType, this.getValueFrom(props.value));
}

getView(props = this.props) {
Expand Down Expand Up @@ -153,29 +185,17 @@ export default class Calendar extends Component {
});
}

/**
* Called when the user uses navigation buttons.
*/
setActiveRange = (activeRange) => {
const [activeStartDate] = activeRange;

this.setState({
activeStartDate,
});
}

/**
* Called when the user uses navigation buttons.
*/
setActiveStartDate = activeStartDate => this.setState({ activeStartDate })

drillDown = (activeRange) => {
drillDown = (activeStartDate) => {
if (!this.drillDownAvailable) {
return;
}

const views = this.getLimitedViews();
const [activeStartDate] = activeRange;

this.setState(prevState => ({
activeStartDate,
Expand All @@ -195,80 +215,55 @@ export default class Calendar extends Component {
}));
}

onChange = (valueRange) => {
const { onChange } = this.props;

this.setState({ value: valueRange });
onChange = (value) => {
this.setState({ value });

const value = this.getValueFromRange(valueRange);

if (onChange) onChange(value);
}

/**
* Called when the user clicks an item on any view.
* If they "hit the bottom" and they can't drill further down, onChange will be called.
* Otherwise, drillDown will be called.
*/
onDrillDown = callback => (range) => {
if (callback) callback();

if (this.drillDownAvailable) {
this.drillDown(range);
} else {
this.onChange(range);
}
const { onChange } = this.props;
const processedValue = this.getProcessedValue(value);
if (onChange) onChange(processedValue);
}

renderContent() {
const { setView } = this;
const {
activeStartDate,
value,
view,
} = this.state;
const {
calendarType,
onClickDay,
onClickDecade,
onClickMonth,
onClickYear,
showWeekNumbers,
} = this.props;
const { setView, valueType } = this;
const { calendarType, showWeekNumbers, value } = this.props;
const { activeStartDate, view } = this.state;

const commonProps = {
activeStartDate,
setView,
value,
valueType,
};

const clickAction = this.drillDownAvailable ? this.drillDown : this.onChange;

switch (view) {
case 'century':
return (
<CenturyView
onClickItem={this.onDrillDown(onClickDecade)}
onChange={mergeFunctions(clickAction, this.props.onClickDecade)}
{...commonProps}
/>
);
case 'decade':
return (
<DecadeView
onClickItem={this.onDrillDown(onClickYear)}
onChange={mergeFunctions(clickAction, this.props.onClickYear)}
{...commonProps}
/>
);
case 'year':
return (
<YearView
onClickItem={this.onDrillDown(onClickMonth)}
onChange={mergeFunctions(clickAction, this.props.onClickMonth)}
{...commonProps}
/>
);
case 'month':
return (
<MonthView
calendarType={calendarType}
onClickItem={this.onDrillDown(onClickDay)}
onChange={mergeFunctions(clickAction, this.props.onClickDay)}
showWeekNumbers={showWeekNumbers}
{...commonProps}
/>
Expand All @@ -279,23 +274,15 @@ export default class Calendar extends Component {
}

renderNavigation() {
const {
prevLabel,
prev2Label,
nextLabel,
next2Label,
} = this.props;

return (
<Navigation
activeRange={this.state.activeRange}
activeStartDate={this.state.activeStartDate}
drillUp={this.drillUp}
nextLabel={nextLabel}
next2Label={next2Label}
prevLabel={prevLabel}
prev2Label={prev2Label}
setActiveRange={this.setActiveRange}
nextLabel={this.props.nextLabel}
next2Label={this.props.next2Label}
prevLabel={this.props.prevLabel}
prev2Label={this.props.prev2Label}
setActiveStartDate={this.setActiveStartDate}
view={this.state.view}
views={this.getLimitedViews()}
Expand Down Expand Up @@ -336,6 +323,6 @@ Calendar.propTypes = {
prevLabel: PropTypes.string,
returnValue: PropTypes.oneOf(['start', 'end', 'range']).isRequired,
showWeekNumbers: PropTypes.bool,
value: PropTypes.instanceOf(Date),
value: isValue,
view: PropTypes.oneOf(allViews), // eslint-disable-line react/no-unused-prop-types
};
35 changes: 14 additions & 21 deletions src/Calendar/Navigation.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,33 +57,26 @@ export default class Navigation extends Component {
setActiveStartDate(getBeginNext2(view, date));
}

render() {
const { activeStartDate: date, drillUp, view } = this.props;
get label() {
const { activeStartDate: date, view } = this.props;

let label;
switch (view) {
case 'century':
label = getCenturyLabel(date);
break;
return getCenturyLabel(date);
case 'decade':
label = getDecadeLabel(date);
break;
return getDecadeLabel(date);
case 'year':
label = getYear(date);
break;
return getYear(date);
case 'month':
label = formatMonthYear(date);
break;
return formatMonthYear(date);
default:
throw new Error(`Invalid view: ${view}.`);
}
}

const {
prevLabel,
prev2Label,
nextLabel,
next2Label,
} = this.props;
render() {
const { label } = this;
const { drillUp, view } = this.props;

return (
<div className="react-calendar__navigation">
Expand All @@ -93,14 +86,14 @@ export default class Navigation extends Component {
disabled={this.prev2ButtonDisabled}
onClick={this.onClickPrevious2}
>
{prev2Label}
{this.props.prev2Label}
</button>
}
<button
disabled={this.prevButtonDisabled}
onClick={this.onClickPrevious}
>
{prevLabel}
{this.props.prevLabel}
</button>
<button
className="react-calendar__navigation__label"
Expand All @@ -112,14 +105,14 @@ export default class Navigation extends Component {
<button
onClick={this.onClickNext}
>
{nextLabel}
{this.props.nextLabel}
</button>
{
view !== 'century' &&
<button
onClick={this.onClickNext2}
>
{next2Label}
{this.props.next2Label}
</button>
}
</div>
Expand Down
Loading

0 comments on commit 93a8307

Please sign in to comment.