Skip to content

Commit

Permalink
feat(eventing): Emit new annotations_staged_change event (#570)
Browse files Browse the repository at this point in the history
  • Loading branch information
Conrad Chan authored Sep 8, 2020
1 parent e1f73ca commit a8b1938
Show file tree
Hide file tree
Showing 4 changed files with 182 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/@types/events.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
enum Event {
ACTIVE_CHANGE = 'annotations_active_change',
ACTIVE_SET = 'annotations_active_set',
CREATOR_STAGED_CHANGE = 'creator_staged_change',
ANNOTATION_CREATE = 'annotations_create',
ANNOTATION_FETCH_ERROR = 'annotations_fetch_error',
ANNOTATION_REMOVE = 'annotations_remove',
Expand Down
117 changes: 117 additions & 0 deletions src/store/eventing/__tests__/staged-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import eventManager from '../../../common/EventManager';
import { AppState } from '../../types';
import { getStatus, getType, handleSetStagedAction, handleResetCreatorAction } from '../staged';
import { createStore } from '../..';
import { CreatorItemHighlight, CreatorItemRegion, CreatorState } from '../../creator';
import { Event } from '../../../@types';

jest.mock('../../../common/EventManager');

describe('store/eventing/staged', () => {
const getStagedHighlight = (): CreatorItemHighlight => ({
location: 1,
shapes: [
{
type: 'rect',
height: 50,
width: 50,
x: 10,
y: 10,
},
],
});

const getStagedRegion = (): CreatorItemRegion => ({
location: 1,
shape: {
type: 'rect',
height: 50,
width: 50,
x: 10,
y: 10,
},
});

const getCreatorHighlight = (): CreatorState =>
({
staged: getStagedHighlight(),
} as CreatorState);

const getCreatorRegion = (): CreatorState =>
({
staged: getStagedRegion(),
} as CreatorState);

const getCreatorState = (isHighlight = true): AppState => {
const creator = isHighlight ? getCreatorHighlight() : getCreatorRegion();
return createStore({ creator }).getState();
};

describe('getStatus()', () => {
test.each`
prev | next | expectedStatus
${null} | ${null} | ${null}
${null} | ${'notnull'} | ${'create'}
${'notnull'} | ${null} | ${null}
${'notnull'} | ${'notnull'} | ${'update'}
`(
'should return $expectedStatus if prevStaged=$prev and nextStaged=$next',
({ prev, next, expectedStatus }) => {
expect(getStatus(prev, next)).toBe(expectedStatus);
},
);
});

describe('getType()', () => {
test.each`
staged | expectedType
${null} | ${null}
${getStagedHighlight()} | ${'highlight'}
${getStagedRegion()} | ${'region'}
`('should returned $expectedType if staged=$staged', ({ staged, expectedType }) => {
expect(getType(staged)).toBe(expectedType);
});
});

describe('handleSetStagedAction()', () => {
test.each`
prev | next
${createStore().getState()} | ${createStore().getState()}
${getCreatorState()} | ${createStore().getState()}
`('should not emit event if status or type is null', ({ prev, next }) => {
handleSetStagedAction(prev, next);

expect(eventManager.emit).not.toHaveBeenCalled();
});

test.each`
prev | next | type | status
${createStore().getState()} | ${getCreatorState()} | ${'highlight'} | ${'create'}
${createStore().getState()} | ${getCreatorState(false)} | ${'region'} | ${'create'}
${getCreatorState(false)} | ${getCreatorState(false)} | ${'region'} | ${'update'}
`('should emit event with type=$type and status=$status', ({ prev, next, type, status }) => {
handleSetStagedAction(prev, next);

expect(eventManager.emit).toHaveBeenCalledWith(Event.CREATOR_STAGED_CHANGE, { type, status });
});
});

describe('handleResetCreatorAction()', () => {
test('should not emit event if type is null', () => {
const prevState = createStore().getState();
handleResetCreatorAction(prevState);

expect(eventManager.emit).not.toHaveBeenCalled();
});

test.each`
prev | type
${getCreatorState()} | ${'highlight'}
${getCreatorState(false)} | ${'region'}
`('should emit cancel event if with type=$type', ({ prev, type }) => {
handleResetCreatorAction(prev);

expect(eventManager.emit).toHaveBeenCalledWith(Event.CREATOR_STAGED_CHANGE, { type, status: 'cancel' });
});
});
});
4 changes: 4 additions & 0 deletions src/store/eventing/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ import { handleActiveAnnotationEvents } from './active';
import { handleAnnotationsInitialized } from './init';
import { handleCreateErrorEvents, handleCreatePendingEvents, handleCreateSuccessEvents } from './create';
import { handleFetchErrorEvents } from './fetch';
import { handleResetCreatorAction, handleSetStagedAction } from './staged';
import { handleToggleAnnotationModeAction } from './mode';
import { resetCreatorAction, setStagedAction } from '../creator';
import { toggleAnnotationModeAction } from '../common/actions';

// Array of event handlers based on redux action. To add handling for new events add an entry keyed by action
Expand All @@ -20,8 +22,10 @@ const eventHandlers: EventHandlerMap = {
[createAnnotationAction.pending.toString()]: handleCreatePendingEvents,
[createAnnotationAction.rejected.toString()]: handleCreateErrorEvents,
[fetchAnnotationsAction.rejected.toString()]: handleFetchErrorEvents,
[resetCreatorAction.toString()]: handleResetCreatorAction,
[setActiveAnnotationIdAction.toString()]: handleActiveAnnotationEvents,
[setIsInitialized.toString()]: handleAnnotationsInitialized,
[setStagedAction.toString()]: handleSetStagedAction,
[toggleAnnotationModeAction.toString()]: handleToggleAnnotationModeAction,
};

Expand Down
60 changes: 60 additions & 0 deletions src/store/eventing/staged.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import eventManager from '../../common/EventManager';
import { AppState } from '../types';
import { CreatorItem, getCreatorStaged, isCreatorStagedHighlight, isCreatorStagedRegion } from '../creator';
import { Event } from '../../@types';

type Status = 'create' | 'update' | 'cancel';

type Type = 'highlight' | 'region';

export const getStatus = (prevStaged: CreatorItem, nextStaged: CreatorItem): Status | null => {
let status: Status | null = null;

if (prevStaged === null && nextStaged !== null) {
status = 'create';
}

if (prevStaged !== null && nextStaged !== null) {
status = 'update';
}

return status;
};

export const getType = (staged: CreatorItem): Type | null => {
let type: Type | null = null;

if (isCreatorStagedRegion(staged)) {
type = 'region';
}

if (isCreatorStagedHighlight(staged)) {
type = 'highlight';
}

return type;
};

export const handleSetStagedAction = (prevState: AppState, nextState: AppState): void => {
const prevStaged = getCreatorStaged(prevState);
const nextStaged = getCreatorStaged(nextState);
const status = getStatus(prevStaged, nextStaged);
const type = getType(prevStaged) || getType(nextStaged);

if (!status || !type) {
return;
}

eventManager.emit(Event.CREATOR_STAGED_CHANGE, { type, status });
};

export const handleResetCreatorAction = (prevState: AppState): void => {
const prevStaged = getCreatorStaged(prevState);
const type = getType(prevStaged);

if (!type) {
return;
}

eventManager.emit(Event.CREATOR_STAGED_CHANGE, { type, status: 'cancel' });
};

0 comments on commit a8b1938

Please sign in to comment.