first commit
This commit is contained in:
40
ui/src/utils/dispatch-action-for-all-modules.js
Normal file
40
ui/src/utils/dispatch-action-for-all-modules.js
Normal file
@@ -0,0 +1,40 @@
|
||||
import allModules from '@state/modules'
|
||||
import store from '@state/store'
|
||||
|
||||
export default function dispatchActionForAllModules(
|
||||
actionName,
|
||||
{ modules = allModules, modulePrefix = '', flags = {} } = {}
|
||||
) {
|
||||
// For every module...
|
||||
for (const moduleName in modules) {
|
||||
const moduleDefinition = modules[moduleName]
|
||||
|
||||
// If the action is defined on the module...
|
||||
if (moduleDefinition.actions && moduleDefinition.actions[actionName]) {
|
||||
// Dispatch the action if the module is namespaced. Otherwise,
|
||||
// set a flag to dispatch the action globally at the end.
|
||||
if (moduleDefinition.namespaced) {
|
||||
store.dispatch(`${modulePrefix}${moduleName}/${actionName}`)
|
||||
} else {
|
||||
flags.dispatchGlobal = true
|
||||
}
|
||||
}
|
||||
|
||||
// If there are any nested sub-modules...
|
||||
if (moduleDefinition.modules) {
|
||||
// Also dispatch the action for these sub-modules.
|
||||
dispatchActionForAllModules(actionName, {
|
||||
modules: moduleDefinition.modules,
|
||||
modulePrefix: modulePrefix + moduleName + '/',
|
||||
flags,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// If this is the root and at least one non-namespaced module
|
||||
// was found with the action...
|
||||
if (!modulePrefix && flags.dispatchGlobal) {
|
||||
// Dispatch the action globally.
|
||||
store.dispatch(actionName)
|
||||
}
|
||||
}
|
||||
138
ui/src/utils/dispatch-action-for-all-modules.unit.js
Normal file
138
ui/src/utils/dispatch-action-for-all-modules.unit.js
Normal file
@@ -0,0 +1,138 @@
|
||||
describe('@utils/dispatch-action-for-all-modules', () => {
|
||||
beforeEach(() => {
|
||||
jest.resetModules()
|
||||
})
|
||||
|
||||
it('dispatches actions from NOT namespaced modules', () => {
|
||||
jest.doMock('@state/modules', () => ({
|
||||
moduleA: {
|
||||
actions: {
|
||||
someAction: jest.fn(),
|
||||
otherAction: jest.fn(),
|
||||
},
|
||||
},
|
||||
moduleB: {
|
||||
actions: {
|
||||
someAction: jest.fn(),
|
||||
otherAction: jest.fn(),
|
||||
},
|
||||
},
|
||||
}))
|
||||
|
||||
require('./dispatch-action-for-all-modules').default('someAction')
|
||||
|
||||
const { moduleA, moduleB } = require('@state/modules')
|
||||
expect(moduleA.actions.someAction).toHaveBeenCalledTimes(1)
|
||||
expect(moduleB.actions.someAction).toHaveBeenCalledTimes(1)
|
||||
expect(moduleA.actions.otherAction).not.toHaveBeenCalled()
|
||||
expect(moduleB.actions.otherAction).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('dispatches actions from namespaced modules', () => {
|
||||
jest.doMock('@state/modules', () => ({
|
||||
moduleA: {
|
||||
namespaced: true,
|
||||
actions: {
|
||||
someAction: jest.fn(),
|
||||
otherAction: jest.fn(),
|
||||
},
|
||||
},
|
||||
moduleB: {
|
||||
namespaced: true,
|
||||
actions: {
|
||||
someAction: jest.fn(),
|
||||
otherAction: jest.fn(),
|
||||
},
|
||||
},
|
||||
}))
|
||||
|
||||
require('./dispatch-action-for-all-modules').default('someAction')
|
||||
|
||||
const { moduleA, moduleB } = require('@state/modules')
|
||||
expect(moduleA.actions.someAction).toHaveBeenCalledTimes(1)
|
||||
expect(moduleB.actions.someAction).toHaveBeenCalledTimes(1)
|
||||
expect(moduleA.actions.otherAction).not.toHaveBeenCalled()
|
||||
expect(moduleB.actions.otherAction).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('dispatches actions from deeply nested NOT namespaced modules', () => {
|
||||
jest.doMock('@state/modules', () => ({
|
||||
moduleA: {
|
||||
actions: {
|
||||
someAction: jest.fn(),
|
||||
otherAction: jest.fn(),
|
||||
},
|
||||
modules: {
|
||||
moduleB: {
|
||||
actions: {
|
||||
someAction: jest.fn(),
|
||||
otherAction: jest.fn(),
|
||||
},
|
||||
modules: {
|
||||
moduleC: {
|
||||
actions: {
|
||||
someAction: jest.fn(),
|
||||
otherAction: jest.fn(),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}))
|
||||
|
||||
require('./dispatch-action-for-all-modules').default('someAction')
|
||||
|
||||
const { moduleA } = require('@state/modules')
|
||||
const { moduleB } = moduleA.modules
|
||||
const { moduleC } = moduleB.modules
|
||||
expect(moduleA.actions.someAction).toHaveBeenCalledTimes(1)
|
||||
expect(moduleB.actions.someAction).toHaveBeenCalledTimes(1)
|
||||
expect(moduleC.actions.someAction).toHaveBeenCalledTimes(1)
|
||||
expect(moduleA.actions.otherAction).not.toHaveBeenCalled()
|
||||
expect(moduleB.actions.otherAction).not.toHaveBeenCalled()
|
||||
expect(moduleC.actions.otherAction).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('dispatches actions from deeply nested namespaced modules', () => {
|
||||
jest.doMock('@state/modules', () => ({
|
||||
moduleA: {
|
||||
namespaced: true,
|
||||
actions: {
|
||||
someAction: jest.fn(),
|
||||
otherAction: jest.fn(),
|
||||
},
|
||||
modules: {
|
||||
moduleB: {
|
||||
namespaced: true,
|
||||
actions: {
|
||||
someAction: jest.fn(),
|
||||
otherAction: jest.fn(),
|
||||
},
|
||||
modules: {
|
||||
moduleC: {
|
||||
namespaced: true,
|
||||
actions: {
|
||||
someAction: jest.fn(),
|
||||
otherAction: jest.fn(),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}))
|
||||
|
||||
require('./dispatch-action-for-all-modules').default('someAction')
|
||||
|
||||
const { moduleA } = require('@state/modules')
|
||||
const { moduleB } = moduleA.modules
|
||||
const { moduleC } = moduleB.modules
|
||||
expect(moduleA.actions.someAction).toHaveBeenCalledTimes(1)
|
||||
expect(moduleB.actions.someAction).toHaveBeenCalledTimes(1)
|
||||
expect(moduleC.actions.someAction).toHaveBeenCalledTimes(1)
|
||||
expect(moduleA.actions.otherAction).not.toHaveBeenCalled()
|
||||
expect(moduleB.actions.otherAction).not.toHaveBeenCalled()
|
||||
expect(moduleC.actions.otherAction).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
8
ui/src/utils/format-date-relative.js
Normal file
8
ui/src/utils/format-date-relative.js
Normal file
@@ -0,0 +1,8 @@
|
||||
// https://date-fns.org/docs/formatDistance
|
||||
import formatDistance from 'date-fns/formatDistance'
|
||||
// https://date-fns.org/docs/isToday
|
||||
import isToday from 'date-fns/isToday'
|
||||
|
||||
export default function formatDateRelative(fromDate, toDate = new Date()) {
|
||||
return formatDistance(fromDate, toDate) + (isToday(toDate) ? ' ago' : '')
|
||||
}
|
||||
30
ui/src/utils/format-date-relative.unit.js
Normal file
30
ui/src/utils/format-date-relative.unit.js
Normal file
@@ -0,0 +1,30 @@
|
||||
import formatDateRelative from './format-date-relative'
|
||||
|
||||
describe('@utils/format-date-relative', () => {
|
||||
it('correctly compares dates years apart', () => {
|
||||
const fromDate = new Date(2002, 5, 1)
|
||||
const toDate = new Date(2017, 4, 10)
|
||||
const timeAgoInWords = formatDateRelative(fromDate, toDate)
|
||||
expect(timeAgoInWords).toEqual('almost 15 years')
|
||||
})
|
||||
|
||||
it('correctly compares dates months apart', () => {
|
||||
const fromDate = new Date(2017, 8, 1)
|
||||
const toDate = new Date(2017, 11, 10)
|
||||
const timeAgoInWords = formatDateRelative(fromDate, toDate)
|
||||
expect(timeAgoInWords).toEqual('3 months')
|
||||
})
|
||||
|
||||
it('correctly compares dates days apart', () => {
|
||||
const fromDate = new Date(2017, 11, 1)
|
||||
const toDate = new Date(2017, 11, 10)
|
||||
const timeAgoInWords = formatDateRelative(fromDate, toDate)
|
||||
expect(timeAgoInWords).toEqual('9 days')
|
||||
})
|
||||
|
||||
it('compares to now when passed only one date', () => {
|
||||
const fromDate = new Date(2010, 11, 1)
|
||||
const timeAgoInWords = formatDateRelative(fromDate)
|
||||
expect(timeAgoInWords).toContain('years ago')
|
||||
})
|
||||
})
|
||||
15
ui/src/utils/format-date.js
Normal file
15
ui/src/utils/format-date.js
Normal file
@@ -0,0 +1,15 @@
|
||||
// https://date-fns.org/docs/format
|
||||
import format from 'date-fns/format'
|
||||
import parseISO from 'date-fns/parseISO'
|
||||
|
||||
export default function formatDate(date) {
|
||||
return format(date, 'MMM do, yyyy')
|
||||
}
|
||||
|
||||
export function parseAndFormatDate(date) {
|
||||
return format(parseISO(date), 'MMM dd, yyyy')
|
||||
}
|
||||
|
||||
export function parseAndFormatDateTime(date) {
|
||||
return format(parseISO(date), 'MMM dd, yyyy hh:mm aa')
|
||||
}
|
||||
21
ui/src/utils/format-date.unit.js
Normal file
21
ui/src/utils/format-date.unit.js
Normal file
@@ -0,0 +1,21 @@
|
||||
import formatDate from './format-date'
|
||||
|
||||
describe('@utils/format-date', () => {
|
||||
it('correctly compares dates years apart', () => {
|
||||
const date = new Date(2002, 5, 1)
|
||||
const formattedDate = formatDate(date)
|
||||
expect(formattedDate).toEqual('Jun 1st, 2002')
|
||||
})
|
||||
|
||||
it('correctly compares dates months apart', () => {
|
||||
const date = new Date(2017, 8, 1)
|
||||
const formattedDate = formatDate(date)
|
||||
expect(formattedDate).toEqual('Sep 1st, 2017')
|
||||
})
|
||||
|
||||
it('correctly compares dates days apart', () => {
|
||||
const date = new Date(2017, 11, 11)
|
||||
const formattedDate = formatDate(date)
|
||||
expect(formattedDate).toEqual('Dec 11th, 2017')
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user