Skip to content

Commit

Permalink
change lots of things about reducing
Browse files Browse the repository at this point in the history
  • Loading branch information
arshaw committed Apr 18, 2020
1 parent 0f0e809 commit accf2dd
Show file tree
Hide file tree
Showing 17 changed files with 110 additions and 91 deletions.
2 changes: 1 addition & 1 deletion packages-premium
31 changes: 17 additions & 14 deletions packages/core/src/Calendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ export class Calendar {
interactionsStore: { [componentUid: string]: Interaction[] } = {}

get view() { return this.state.viewApi } // for public API
get component() { return this.componentRef.current } // used to get view-specific business hours :(


constructor(el: HTMLElement, optionOverrides: OptionsInput = {}) {
Expand All @@ -94,7 +93,6 @@ export class Calendar {
optionOverrides
})

// must go after INIT
this.calendarInteractions = this.state.pluginHooks.calendarInteractions
.map((calendarInteractionClass) => {
return new calendarInteractionClass(this.state)
Expand Down Expand Up @@ -146,7 +144,12 @@ export class Calendar {


runAction(action: Action) {
this.state = this.reducer.reduce(this.state, action, this.emitter, this)
this.state = this.reducer.reduce(this.state, action, this.dispatch, this.emitter, this.getCurrentState, this)
}


getCurrentState = () => {
return this.state
}


Expand Down Expand Up @@ -333,26 +336,26 @@ export class Calendar {

if ((dateOrRange as DateRangeInput).start && (dateOrRange as DateRangeInput).end) { // a range
this.dispatch({
type: 'SET_VIEW_TYPE',
type: 'CHANGE_VIEW_TYPE',
viewType,
})
this.dispatch({
this.dispatch({ // not very efficient to do two dispatches
type: 'SET_OPTION',
optionName: 'visibleRange',
optionValue: dateOrRange
})

} else {
this.dispatch({
type: 'SET_VIEW_TYPE',
type: 'CHANGE_VIEW_TYPE',
viewType,
dateMarker: this.state.dateEnv.createMarker(dateOrRange as DateInput)
})
}

} else {
this.dispatch({
type: 'SET_VIEW_TYPE',
type: 'CHANGE_VIEW_TYPE',
viewType
})
}
Expand All @@ -373,14 +376,14 @@ export class Calendar {

if (spec) {
this.dispatch({
type: 'SET_VIEW_TYPE',
type: 'CHANGE_VIEW_TYPE',
viewType: spec.type,
dateMarker
})

} else {
this.dispatch({
type: 'SET_DATE',
type: 'CHANGE_DATE',
dateMarker
})
}
Expand Down Expand Up @@ -429,7 +432,7 @@ export class Calendar {
prevYear() {
this.unselect()
this.dispatch({
type: 'SET_DATE',
type: 'CHANGE_DATE',
dateMarker: this.state.dateEnv.addYears(this.state.currentDate, -1)
})
}
Expand All @@ -438,7 +441,7 @@ export class Calendar {
nextYear() {
this.unselect()
this.dispatch({
type: 'SET_DATE',
type: 'CHANGE_DATE',
dateMarker: this.state.dateEnv.addYears(this.state.currentDate, 1)
})
}
Expand All @@ -447,7 +450,7 @@ export class Calendar {
today() {
this.unselect()
this.dispatch({
type: 'SET_DATE',
type: 'CHANGE_DATE',
dateMarker: this.getNow()
})
}
Expand All @@ -456,7 +459,7 @@ export class Calendar {
gotoDate(zonedDateInput) {
this.unselect()
this.dispatch({
type: 'SET_DATE',
type: 'CHANGE_DATE',
dateMarker: this.state.dateEnv.createMarker(zonedDateInput)
})
}
Expand All @@ -468,7 +471,7 @@ export class Calendar {
if (delta) { // else, warn about invalid input?
this.unselect()
this.dispatch({
type: 'SET_DATE',
type: 'CHANGE_DATE',
dateMarker: this.state.dateEnv.add(this.state.currentDate, delta)
})
}
Expand Down
6 changes: 1 addition & 5 deletions packages/core/src/CalendarComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { Toolbar } from './Toolbar'
import { DateProfileGenerator, DateProfile } from './DateProfileGenerator'
import { rangeContainsMarker } from './datelib/date-range'
import { EventUiHash } from './component/event-ui'
import { parseBusinessHours } from './structs/business-hours'
import { memoize } from './util/memoize'
import { DateMarker } from './datelib/marker'
import { CalendarState } from './reducers/types'
Expand Down Expand Up @@ -44,7 +43,6 @@ export class CalendarComponent extends Component<CalendarComponentProps, Calenda
context: never

private buildViewContext = memoize(buildViewContext)
private parseBusinessHours = memoize((input) => parseBusinessHours(input, this.props))
private buildViewPropTransformers = memoize(buildViewPropTransformers)
private buildToolbarProps = memoize(buildToolbarProps)
private reportClassNames = memoize(reportClassNames)
Expand All @@ -54,8 +52,6 @@ export class CalendarComponent extends Component<CalendarComponentProps, Calenda
private footerRef = createRef<Toolbar>()
private viewRef = createRef<ViewComponent>()

get view() { return this.viewRef.current }

state = {
forPrint: false
}
Expand Down Expand Up @@ -105,12 +101,12 @@ export class CalendarComponent extends Component<CalendarComponentProps, Calenda
props.viewApi,
props.options,
props.computedOptions,
props.dateProfile,
props.dateProfileGenerator,
props.dateEnv,
props.theme,
props.pluginHooks,
props.dispatch,
props.getCurrentState,
props.emitter,
props.calendar
)
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/DateProfileGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export interface DateProfile {
currentRangeUnit: string
isRangeAllDay: boolean
validRange: OpenDateRange
activeRange: DateRange
activeRange: DateRange | null
renderRange: DateRange
slotMinTime: Duration
slotMaxTime: Duration
Expand Down
54 changes: 33 additions & 21 deletions packages/core/src/ViewApi.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,44 @@
import { DateEnv } from './datelib/env';
import { DateProfile } from './DateProfileGenerator';

export interface ViewApi {
type: string
title: string
activeStart: Date
activeEnd: Date
currentStart: Date
currentEnd: Date
}
import { DateEnv } from './datelib/env'
import { CalendarState } from 'fullcalendar'


export class ViewApi {
export class ViewApi { // always represents the current view

constructor(
public type: string,
dateProfile: DateProfile,
public title: string,
private options: any,
dateEnv: DateEnv
private getCurrentState: () => CalendarState,
private dateEnv: DateEnv
) {
this.activeStart = dateEnv.toDate(dateProfile.activeRange.start)
this.activeEnd = dateEnv.toDate(dateProfile.activeRange.end)
this.currentStart = dateEnv.toDate(dateProfile.currentRange.start)
this.currentEnd = dateEnv.toDate(dateProfile.currentRange.end)
}


get title() {
return this.getCurrentState().viewTitle
}


get activeStart() {
return this.dateEnv.toDate(this.getCurrentState().dateProfile.activeRange.start)
}


get activeEnd() {
return this.dateEnv.toDate(this.getCurrentState().dateProfile.activeRange.end)
}


get currentStart() {
return this.dateEnv.toDate(this.getCurrentState().dateProfile.currentRange.start)
}


get currentEnd() {
return this.dateEnv.toDate(this.getCurrentState().dateProfile.currentRange.end)
}


getOption(name: string) {
return this.options[name]
return this.getCurrentState().options[name] // are the view-specific options
}

}
3 changes: 2 additions & 1 deletion packages/core/src/component/ComponentContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ export function buildViewContext(
viewApi: ViewApi,
options: any,
computedOptions: any,
dateProfile: DateProfile,
dateProfileGenerator: DateProfileGenerator,
dateEnv: DateEnv,
theme: Theme,
pluginHooks: PluginHooks,
dispatch: (action: Action) => void,
getCurrentState: () => CalendarState,
emitter: Emitter,
calendar: Calendar
): ComponentContext {
Expand All @@ -50,6 +50,7 @@ export function buildViewContext(
pluginHooks,
emitter,
dispatch,
getCurrentState,
calendar
}

Expand Down
20 changes: 13 additions & 7 deletions packages/core/src/reducers/CalendarStateReducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { diffWholeDays } from '../datelib/marker'
import { createFormatter } from '../datelib/formatting'
import { DateRange } from '../datelib/date-range'
import { ViewApi } from '../ViewApi'
import { parseBusinessHours } from '../structs/business-hours'


export class CalendarStateReducer {
Expand All @@ -49,9 +50,10 @@ export class CalendarStateReducer {
private computeTitle = memoize(computeTitle)
private buildViewApi = memoize(buildViewApi)
private buildLocale = memoize(buildLocale)
private parseContextBusinessHours = memoizeObjArg(parseContextBusinessHours)


reduce(state: CalendarState, action: Action, emitter: Emitter, calendar: Calendar): CalendarState {
reduce(state: CalendarState, action: Action, dispatch: (action: Action) => void, emitter: Emitter, getCurrentState: () => CalendarState, calendar: Calendar): CalendarState {
let optionOverrides = state.optionOverrides || {}
let dynamicOptionOverrides = state.dynamicOptionOverrides || {}

Expand Down Expand Up @@ -135,14 +137,14 @@ export class CalendarStateReducer {
emitter.trigger('_init') // for tests. needs to happen after emitter.setOptions
}

let dispatch = state.dispatch || calendar.dispatch.bind(calendar) // will reuse past functions! TODO: memoize? TODO: calendar should bind?
let reducerContext: ReducerContext = {
dateEnv,
options: viewOptions,
computedOptions: this.buildComputedOptions(viewOptions),
pluginHooks,
emitter,
dispatch,
getCurrentState,
calendar
}

Expand Down Expand Up @@ -174,11 +176,12 @@ export class CalendarStateReducer {
}

let viewTitle = this.computeTitle(dateProfile, viewOptions, dateEnv)
let viewApi = this.buildViewApi(viewSpec.type, dateProfile, viewTitle, viewOptions, dateEnv)
let viewApi = this.buildViewApi(viewSpec.type, getCurrentState, dateEnv)

let nextState: CalendarState = {
...(state as object), // preserve previous state from plugin reducers. tho remove type to make sure all data is provided right now
...reducerContext,
businessHours: this.parseContextBusinessHours(reducerContext),
calendarOptions,
optionOverrides,
dynamicOptionOverrides,
Expand Down Expand Up @@ -303,12 +306,15 @@ function buildEventUiBases(eventDefs: EventDefHash, eventUiSingleBase: EventUi,

function buildViewApi(
type: string,
dateProfile: DateProfile,
title: string,
options: any,
getCurrentState: () => CalendarState,
dateEnv: DateEnv
) {
return new ViewApi(type, dateProfile, title, options, dateEnv)
return new ViewApi(type, getCurrentState, dateEnv)
}


function parseContextBusinessHours(context: ReducerContext) {
return parseBusinessHours(context.options.businessHours, context)
}


Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/reducers/ReducerContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Calendar } from '../Calendar'
import { Emitter } from '../common/Emitter'
import { parseFieldSpecs } from '../util/misc'
import { createDuration, Duration } from '../datelib/duration'
import { CalendarState } from '../reducers/types'


export interface ReducerContext {
Expand All @@ -14,6 +15,7 @@ export interface ReducerContext {
pluginHooks: PluginHooks
emitter: Emitter
dispatch(action: Action): void
getCurrentState(): CalendarState
calendar: Calendar
}

Expand Down
21 changes: 13 additions & 8 deletions packages/core/src/reducers/current-date.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,26 @@ export function reduceCurrentDate(currentDate: DateMarker, action: Action, dateP
// on INIT, currentDate will already be set

switch (action.type) {
case 'PREV':
case 'NEXT':
if (!rangeContainsMarker(dateProfile.currentRange, currentDate)) {

case 'CHANGE_DATE':
case 'CHANGE_VIEW_TYPE':
if (action.dateMarker) {
currentDate = action.dateMarker
}
// fall through...
case 'INIT':
if (dateProfile.activeRange && !rangeContainsMarker(dateProfile.activeRange, currentDate)) {
return dateProfile.currentRange.start
} else {
return currentDate
}

case 'SET_DATE':
case 'SET_VIEW_TYPE':
let newDate = action.dateMarker || currentDate
if (dateProfile.activeRange && !rangeContainsMarker(dateProfile.activeRange, newDate)) {
case 'PREV':
case 'NEXT':
if (!rangeContainsMarker(dateProfile.currentRange, currentDate)) {
return dateProfile.currentRange.start
} else {
return newDate
return currentDate
}

default:
Expand Down

0 comments on commit accf2dd

Please sign in to comment.