Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #9 from markerikson/practical-redux-part-8-final
Practical Redux Part 8 - final
- Loading branch information
Showing
24 changed files
with
522 additions
and
47 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import {createReducer} from "common/utils/reducerUtils"; | ||
|
||
import schema from "app/schema"; | ||
const defaultEditingEntities = schema.getDefaultState(); | ||
|
||
export default createReducer(defaultEditingEntities, { | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
export function getModelByType(session, itemType, itemID) { | ||
const modelClass = session[itemType]; | ||
const model = modelClass.withId(itemID); | ||
return model; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import { | ||
EDIT_ITEM_EXISTING, | ||
EDIT_ITEM_UPDATE, | ||
EDIT_ITEM_APPLY, | ||
EDIT_ITEM_STOP, | ||
EDIT_ITEM_RESET, | ||
} from "./editingConstants"; | ||
|
||
|
||
export function editExistingItem(itemType, itemID) { | ||
return { | ||
type : EDIT_ITEM_EXISTING, | ||
payload : { | ||
itemType, | ||
itemID | ||
}, | ||
}; | ||
} | ||
|
||
export function editItemAttributes(itemType, itemID, newItemAttributes) { | ||
return { | ||
type : EDIT_ITEM_UPDATE, | ||
payload : { | ||
itemType, | ||
itemID, | ||
newItemAttributes, | ||
}, | ||
}; | ||
} | ||
|
||
export function applyItemEdits(itemType, itemID) { | ||
return { | ||
type : EDIT_ITEM_APPLY, | ||
payload : { | ||
itemType, | ||
itemID | ||
}, | ||
}; | ||
} | ||
|
||
export function stopEditingItem(itemType, itemID) { | ||
return { | ||
type : EDIT_ITEM_STOP, | ||
payload : { | ||
itemType, | ||
itemID | ||
}, | ||
}; | ||
} | ||
|
||
export function resetEditedItem(itemType, itemID) { | ||
return { | ||
type : EDIT_ITEM_RESET, | ||
payload : { | ||
itemType, | ||
itemID, | ||
}, | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
export const EDIT_ITEM_EXISTING = "EDIT_ITEM_EXISTING"; | ||
export const EDIT_ITEM_UPDATE = "EDIT_ITEM_UPDATE"; | ||
export const EDIT_ITEM_APPLY = "EDIT_ITEM_APPLY"; | ||
export const EDIT_ITEM_STOP = "EDIT_ITEM_STOP"; | ||
export const EDIT_ITEM_RESET = "EDIT_ITEM_RESET"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
import {createReducer} from "common/utils/reducerUtils"; | ||
|
||
import schema from "app/schema"; | ||
|
||
import { | ||
createEntity, | ||
updateEntity, | ||
deleteEntity | ||
} from "features/entities/entityReducer"; | ||
|
||
import { | ||
EDIT_ITEM_EXISTING, | ||
EDIT_ITEM_UPDATE, | ||
EDIT_ITEM_APPLY, | ||
EDIT_ITEM_STOP, | ||
EDIT_ITEM_RESET, | ||
} from "./editingConstants"; | ||
|
||
import {getModelByType} from "common/utils/modelUtils"; | ||
|
||
import {selectEntities} from "features/entities/entitySelectors"; | ||
import {selectEditingEntities} from "./editingSelectors"; | ||
import { | ||
readEntityData, | ||
updateEntitiesState, | ||
updateEditingEntitiesState, | ||
} from "./editingUtils"; | ||
|
||
|
||
|
||
export function copyEntity(sourceEntities, destinationEntities, payload) { | ||
const {itemID, itemType} = payload; | ||
|
||
const newItemAttributes = readEntityData(sourceEntities, itemType, itemID); | ||
const creationPayload = {itemType, itemID, newItemAttributes} | ||
|
||
const updatedEntities = createEntity(destinationEntities, creationPayload); | ||
return updatedEntities; | ||
} | ||
|
||
|
||
|
||
export function updateEditedEntity(sourceEntities, destinationEntities, payload) { | ||
// Start by reading our "work-in-progress" data | ||
const readSession = schema.from(sourceEntities); | ||
|
||
const {itemType, itemID} = payload; | ||
|
||
// Look up the model instance for the requested item | ||
const model = getModelByType(readSession, itemType, itemID); | ||
|
||
|
||
// We of course will be updating our "current" relational data | ||
let writeSession = schema.from(destinationEntities); | ||
|
||
const ModelClass = writeSession[itemType]; | ||
|
||
if(ModelClass.hasId(itemID)) { | ||
// Look up the original Model instance for the top item | ||
const existingItem = ModelClass.withId(itemID); | ||
|
||
if(existingItem.updateFrom) { | ||
// Each model class should know how to properly update itself and its | ||
// relations from another model of the same type. Ask the original model to | ||
// update itself based on the "work-in-progress" model, which queues up a | ||
// series of immutable add/update/delete actions internally | ||
existingItem.updateFrom(model); | ||
} | ||
} | ||
|
||
// Immutably apply the changes and generate our new "current" relational data | ||
const updatedEntities = writeSession.reduce(); | ||
return updatedEntities; | ||
} | ||
|
||
|
||
|
||
|
||
export function editItemExisting(state, payload) { | ||
const entities = selectEntities(state); | ||
const editingEntities = selectEditingEntities(state); | ||
|
||
const updatedEditingEntities = copyEntity(entities, editingEntities, payload); | ||
|
||
return updateEditingEntitiesState(state, updatedEditingEntities); | ||
} | ||
|
||
export function editItemUpdate(state, payload) { | ||
const editingEntities = selectEditingEntities(state); | ||
|
||
const updatedEditingEntities = updateEntity(editingEntities, payload); | ||
return updateEditingEntitiesState(state, updatedEditingEntities); | ||
} | ||
|
||
export function editItemStop(state, payload) { | ||
const editingEntities = selectEditingEntities(state); | ||
|
||
const updatedEditingEntities = deleteEntity(editingEntities, payload); | ||
return updateEditingEntitiesState(state, updatedEditingEntities); | ||
} | ||
|
||
|
||
export function editItemApply(state, payload) { | ||
const entities = selectEntities(state); | ||
const editingEntities = selectEditingEntities(state); | ||
|
||
const updatedEntities = updateEditedEntity(editingEntities, entities, payload); | ||
return updateEntitiesState(state, updatedEntities); | ||
} | ||
|
||
|
||
export function editItemReset(state, payload) { | ||
const stateWithoutItem = editItemStop(state, payload); | ||
const stateWithCurrentItem = editItemExisting(stateWithoutItem, payload); | ||
|
||
return stateWithCurrentItem; | ||
} | ||
|
||
|
||
|
||
const editingFeatureReducer = createReducer({}, { | ||
[EDIT_ITEM_EXISTING] : editItemExisting, | ||
[EDIT_ITEM_UPDATE] : editItemUpdate, | ||
[EDIT_ITEM_APPLY] : editItemApply, | ||
[EDIT_ITEM_STOP] : editItemStop, | ||
[EDIT_ITEM_RESET] : editItemReset, | ||
}); | ||
|
||
export default editingFeatureReducer; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import {createSelector} from "reselect"; | ||
|
||
import schema from "app/schema"; | ||
|
||
|
||
export const selectEditingEntities = state => state.editingEntities; | ||
|
||
export const getEditingEntitiesSession = createSelector( | ||
selectEditingEntities, | ||
editingEntities => schema.from(editingEntities) | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import schema from "app/schema"; | ||
import {getModelByType} from "common/utils/modelUtils"; | ||
|
||
export function updateEditingEntitiesState(state, updatedEditingEntities) { | ||
return { | ||
...state, | ||
editingEntities : updatedEditingEntities, | ||
}; | ||
} | ||
|
||
export function updateEntitiesState(state, updatedEntities) { | ||
return { | ||
...state, | ||
entities : updatedEntities, | ||
}; | ||
} | ||
|
||
export function readEntityData(entities, itemType, itemID) { | ||
const readSession = schema.from(entities); | ||
|
||
// Look up the model instance for the requested item | ||
const model = getModelByType(readSession, itemType, itemID); | ||
const data = model.toJSON(); | ||
|
||
return data; | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,3 @@ | ||
export const ENTITY_UPDATE = "ENTITY_UPDATE"; | ||
export const ENTITY_UPDATE = "ENTITY_UPDATE"; | ||
export const ENTITY_CREATE = "ENTITY_CREATE"; | ||
export const ENTITY_DELETE = "ENTITY_DELETE"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import {createSelector} from "reselect"; | ||
|
||
import schema from "app/schema"; | ||
|
||
export const selectEntities = state => state.entities; | ||
|
||
export const getEntitiesSession = createSelector( | ||
selectEntities, | ||
entities => schema.from(entities) | ||
); |
Oops, something went wrong.