Convert Annotation action and reducer to TS

pull/3689/head
ebb-tide 2018-06-15 15:20:24 -07:00
parent 392ee489e3
commit e90ab6433e
7 changed files with 112 additions and 61 deletions

View File

@ -1,7 +1,19 @@
import * as api from 'src/shared/apis/annotation'
import {AnnotationInterface} from 'src/types'
export type Action =
| EditingAnnotationAction
| DismissEditingAnnotationAction
| AddingAnnotationAction
| AddingAnnotationSuccessAction
| DismissAddingAnnotationAction
| MouseEnterTempAnnotationAction
| MouseLeaveTempAnnotationAction
| LoadAnnotationsAction
| UpdateAnnotationAction
| DeleteAnnotationAction
| AddAnnotationAction
export interface EditingAnnotationAction {
type: 'EDITING_ANNOTATION'
}
@ -122,8 +134,8 @@ export const addAnnotationAsync = (
}
export interface AnnotationRange {
since: string
until: string
since: number
until: number
}
export const getAnnotationsAsync = (

View File

@ -11,6 +11,7 @@ export const TEMP_ANNOTATION: AnnotationInterface = {
type: '',
startTime: null,
endTime: null,
links: {self: ''},
}
export const visibleAnnotations = (

View File

@ -1,40 +0,0 @@
import AJAX from 'src/utils/ajax'
const msToRFC = ms => ms && new Date(parseInt(ms, 10)).toISOString()
const rfcToMS = rfc3339 => rfc3339 && JSON.stringify(Date.parse(rfc3339))
const annoToMillisecond = anno => ({
...anno,
startTime: rfcToMS(anno.startTime),
endTime: rfcToMS(anno.endTime),
})
const annoToRFC = anno => ({
...anno,
startTime: msToRFC(anno.startTime),
endTime: msToRFC(anno.endTime),
})
export const createAnnotation = async (url, annotation) => {
const data = annoToRFC(annotation)
const response = await AJAX({method: 'POST', url, data})
return annoToMillisecond(response.data)
}
export const getAnnotations = async (url, since, until) => {
const {data} = await AJAX({
method: 'GET',
url,
params: {since: msToRFC(since), until: msToRFC(until)},
})
return data.annotations.map(annoToMillisecond)
}
export const deleteAnnotation = async annotation => {
const url = annotation.links.self
await AJAX({method: 'DELETE', url})
}
export const updateAnnotation = async annotation => {
const url = annotation.links.self
const data = annoToRFC(annotation)
await AJAX({method: 'PATCH', url, data})
}

View File

@ -0,0 +1,63 @@
import AJAX from 'src/utils/ajax'
import {AnnotationInterface} from 'src/types'
const msToRFCString = (ms: number) =>
ms && new Date(Math.round(ms)).toISOString()
const rfcStringToMS = (rfc3339: string) => rfc3339 && Date.parse(rfc3339)
interface ServerAnnotation {
id: string
startTime: string
endTime: string
text: string
type: string
links: {self: string}
}
const annoToMillisecond = (
annotation: ServerAnnotation
): AnnotationInterface => ({
...annotation,
startTime: rfcStringToMS(annotation.startTime),
endTime: rfcStringToMS(annotation.endTime),
})
const annoToRFC = (annotation: AnnotationInterface): ServerAnnotation => ({
...annotation,
startTime: msToRFCString(annotation.startTime),
endTime: msToRFCString(annotation.endTime),
})
export const createAnnotation = async (
url: string,
annotation: AnnotationInterface
) => {
const data = annoToRFC(annotation)
const response = await AJAX({method: 'POST', url, data})
return annoToMillisecond(response.data)
}
export const getAnnotations = async (
url: string,
since: number,
until: number
) => {
const {data} = await AJAX({
method: 'GET',
url,
params: {since: msToRFCString(since), until: msToRFCString(until)},
})
return data.annotations.map(annoToMillisecond)
}
export const deleteAnnotation = async (annotation: AnnotationInterface) => {
const url = annotation.links.self
await AJAX({method: 'DELETE', url})
}
export const updateAnnotation = async (annotation: AnnotationInterface) => {
const url = annotation.links.self
const data = annoToRFC(annotation)
await AJAX({method: 'PATCH', url, data})
}

View File

@ -1,12 +1,24 @@
import {ADDING, EDITING, TEMP_ANNOTATION} from 'src/shared/annotations/helpers'
import {Action} from 'src/shared/actions/annotations'
import {AnnotationInterface} from 'src/types'
export interface AnnotationState {
mode: string
isTempHovering: boolean
annotations: AnnotationInterface[]
}
const initialState = {
mode: null,
isTempHovering: false,
annotations: [],
}
const annotationsReducer = (state = initialState, action) => {
const annotationsReducer = (
state: AnnotationState = initialState,
action: Action
) => {
switch (action.type) {
case 'EDITING_ANNOTATION': {
return {

View File

@ -4,4 +4,5 @@ export interface AnnotationInterface {
endTime: number
text: string
type: string
links: {self: string}
}

View File

@ -1,45 +1,47 @@
import reducer from 'shared/reducers/annotations'
import reducer from 'src/shared/reducers/annotations'
import {AnnotationInterface} from 'src/types'
import {AnnotationState} from 'src/shared/reducers/annotations'
import {
addAnnotation,
deleteAnnotation,
loadAnnotations,
updateAnnotation,
} from 'shared/actions/annotations'
} from 'src/shared/actions/annotations'
const a1 = {
const a1: AnnotationInterface = {
id: '1',
group: '',
name: 'anno1',
time: '1515716169000',
duration: '',
startTime: 1515716169000,
endTime: 1515716169000,
type: '',
text: 'you have no swoggels',
links: {self: 'to/thine/own/self/be/true'},
}
const a2 = {
const a2: AnnotationInterface = {
id: '2',
group: '',
name: 'anno1',
time: '1515716169000',
duration: '',
text: 'you have no swoggels',
startTime: 1515716169000,
endTime: 1515716169002,
type: '',
text: 'you have so many swoggels',
links: {self: 'self/in/eye/of/beholder'},
}
const state = {
const state: AnnotationState = {
isTempHovering: false,
mode: null,
annotations: [],
}
describe('Shared.Reducers.annotations', () => {
it('can load the annotations', () => {
const expected = [{time: '0', duration: ''}]
const expected = [a1]
const actual = reducer(state, loadAnnotations(expected))
expect(actual.annotations).toEqual(expected)
})
it('can update an annotation', () => {
const expected = [{...a1, time: ''}]
const expected = [{...a1, startTime: 6666666666666}]
const actual = reducer(
{...state, annotations: [a1]},
updateAnnotation(expected[0])