Skip to content

Commit

Permalink
feat(experiences): fked-26 - fix api patch issue, experience editing
Browse files Browse the repository at this point in the history
  • Loading branch information
patrickocoffeyo committed Jun 6, 2018
1 parent db7f318 commit f6a5263
Show file tree
Hide file tree
Showing 8 changed files with 177 additions and 21 deletions.
53 changes: 51 additions & 2 deletions src/actions/experiences.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,15 @@

import { call, put, takeLatest } from 'redux-saga/effects';

import { EXPERIENCES_FETCH_FOR_USER, EXPERIENCES_CREATE } from '../constants';
import {
EXPERIENCES_FETCH_FOR_USER,
EXPERIENCES_CREATE,
EXPERIENCES_EDIT
} from '../constants';
import {
experiencesFetchForUser as getExperiencesForUser,
experiencesCreate as postExperiences
experiencesCreate as postExperiences,
experiencesEdit as patchExperiences
} from '../lib/api';
import actionGenerator from '../lib/actionGenerator';

Expand Down Expand Up @@ -77,7 +82,51 @@ export function* experiencesCreate({
);
}

/**
* Edits an existing experience
*
* @param {object} payload - Payload for this saga action.
* @param {object} payload.id - Unique ID of experience being updated.
* @param {string} payload.title - Title of this experience.
* @param {string} payload.body - Description for this experience.
* @param {string} payload.field_experience_path - URL slug for this experience.
* @param {function} payload.successHandler
* Function to be executed if/when this action succeeds.
* @param {object} payload.user - Object containing user data.
* @param {object} payload.user.authentication - Object containing auth data.
* @param {string} payload.user.authentication.accessToken
* Access token for the current user.
* @param {string} payload.user.authentication.csrfToken
* CSRF token for the current user.
*/
export function* experiencesEdit({
id,
user,
title,
body = '',
field_experience_path,
successHandler = () => {}
}) {
yield* actionGenerator(
EXPERIENCES_EDIT,
function* experienceEditHandler() {
const experience = yield call(
patchExperiences,
{ id, title, body, field_experience_path },
user
);

yield put({
type: `${EXPERIENCES_EDIT}_SUCCESS`,
payload: experience
});
},
successHandler
);
}

export function* watchExperiencesActions() {
yield takeLatest(EXPERIENCES_FETCH_FOR_USER, experiencesFetchForUser);
yield takeLatest(EXPERIENCES_CREATE, experiencesCreate);
yield takeLatest(EXPERIENCES_EDIT, experiencesEdit);
}
36 changes: 24 additions & 12 deletions src/components/ExperienceForm/ExperienceForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { TextField, Button, withStyles } from '@material-ui/core';

import { Message } from '../';
import ExperienceFormStyles from './ExperienceForm.style';
import { EXPERIENCES_CREATE } from '../../constants';
import { EXPERIENCES_CREATE, EXPERIENCES_EDIT } from '../../constants';

class ExperienceForm extends Component {
static propTypes = {
Expand Down Expand Up @@ -54,20 +54,35 @@ class ExperienceForm extends Component {
};

/**
* Handles a creating an experience.
* Fetches the experience that belongs to the given slug.
*/
getExperience = () => {
const {
experienceSlug,
experiences: { items }
} = this.props;
return experienceSlug
? items.find(item => item.field_experience_path === experienceSlug)
: false;
};

/**
* Handles dispatching create or update actions.
*
* @param {object} event - Submit event object.
*/
handleCreate = event => {
handleSubmit = event => {
event.preventDefault();
const {
dispatch,
user,
history: { push }
history: { push },
experienceSlug
} = this.props;
dispatch({
type: EXPERIENCES_CREATE,
type: experienceSlug ? EXPERIENCES_EDIT : EXPERIENCES_CREATE,
user,
id: this.getExperience().id,
title: event.target[0].value,
field_experience_path: event.target[1].value,
body: event.target[2].value,
Expand All @@ -83,16 +98,13 @@ class ExperienceForm extends Component {
classes,
submitHandler,
experienceSlug,
experiences: { error, items }
experiences: { error }
} = this.props;

// If this is an editorial form, grab the existing experience.
const experience = experienceSlug
? items.find(item => item.field_experience_path === experienceSlug)
: false;
const experience = this.getExperience();

return (
<form onSubmit={submitHandler || this.handleCreate}>
<form onSubmit={submitHandler || this.handleSubmit}>
{error && <Message>{error}</Message>}
<TextField
id="title"
Expand Down Expand Up @@ -131,7 +143,7 @@ class ExperienceForm extends Component {
type="submit"
className={classes.button}
>
Create
{experienceSlug ? 'Save' : 'Create'}
</Button>
</form>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ exports[`<ExperienceForm /> Matches its snapshot 1`] = `
autoComplete={undefined}
autoFocus={undefined}
className="MuiInput-input-25"
defaultValue={undefined}
defaultValue=""
disabled={false}
id="title"
name={undefined}
Expand Down Expand Up @@ -82,7 +82,7 @@ exports[`<ExperienceForm /> Matches its snapshot 1`] = `
autoComplete={undefined}
autoFocus={undefined}
className="MuiInput-input-25"
defaultValue={undefined}
defaultValue=""
disabled={false}
id="field_experience_path"
name={undefined}
Expand Down Expand Up @@ -133,7 +133,7 @@ exports[`<ExperienceForm /> Matches its snapshot 1`] = `
autoComplete={undefined}
autoFocus={undefined}
className="MuiInput-input-25 MuiInput-inputMultiline-27"
defaultValue={undefined}
defaultValue=""
disabled={false}
id="body"
name={undefined}
Expand Down
2 changes: 1 addition & 1 deletion src/constants/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@
export const API_ENDPOINT_USER_LOGIN = 'oauth/token';
export const API_ENDPOINT_XCSRF_TOKEN = 'rest/session/token';
export const API_ENDPOINT_EXPERIENCES = 'node/experience';
export const API_TYPE_EXPERIENCES = 'node--experiences';
export const API_TYPE_EXPERIENCES = 'node--experience';
1 change: 1 addition & 0 deletions src/constants/experiences.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@

export const EXPERIENCES_FETCH_FOR_USER = 'EXPERIENCES_FETCH_FOR_USER';
export const EXPERIENCES_CREATE = 'EXPERIENCES_CREATE';
export const EXPERIENCES_EDIT = 'EXPERIENCES_EDIT';
36 changes: 36 additions & 0 deletions src/lib/api/experiences.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,39 @@ export const experiencesCreate = async (
}
}
});

/**
* Takes new experience data and POSTs it to the API.
*
* @param {object} experience
* Object containing information about the experience thats being updated.
* @param {object} experience.id - Unique ID of experience being updated.
* @param {string} experience.title - Title of this experience.
* @param {string} experience.body - Description for this experience.
* @param {string} experience.field_experience_path - URL slug for this experience.
* @param {object} user - Object containing information about the current user.
* @param {object} user.authentication - Object containing auth data.
* @param {string} user.authentication.accessToken
* Access token for the current user.
* @param {string} user.authentication.csrfToken
* CSRF token for the current user.
*/
export const experiencesEdit = async (
{ id, title, field_experience_path, body = '' },
{ authentication }
) =>
axiosInstance(authentication).patch(`${API_ENDPOINT_EXPERIENCES}/${id}`, {
data: {
id,
type: API_TYPE_EXPERIENCES,
attributes: {
title,
field_experience_path,
body: {
value: body,
format: 'plain_text',
summary: ''
}
}
}
});
9 changes: 7 additions & 2 deletions src/lib/api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,17 @@

import axiosInstance from './axiosInstance';
import { getAccessToken, getCsrfToken } from './user';
import { experiencesFetchForUser, experiencesCreate } from './experiences';
import {
experiencesFetchForUser,
experiencesCreate,
experiencesEdit
} from './experiences';

export {
axiosInstance,
getAccessToken,
getCsrfToken,
experiencesFetchForUser,
experiencesCreate
experiencesCreate,
experiencesEdit
};
55 changes: 54 additions & 1 deletion src/reducers/experiences.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
* Exports reducers pertaining to experience state.
*/

import { EXPERIENCES_FETCH_FOR_USER, EXPERIENCES_CREATE } from '../constants';
import {
EXPERIENCES_FETCH_FOR_USER,
EXPERIENCES_CREATE,
EXPERIENCES_EDIT
} from '../constants';

/**
* Default experience state.
Expand Down Expand Up @@ -89,6 +93,55 @@ export default function experiences(state = defaultState, action) {
items: [...state.items]
};
}

/**
* Reducer that handles experience edit success actions.
*/
case `${EXPERIENCES_EDIT}_SUCCESS`: {
const { payload: experience } = action;

// Filter out the outdated object, and nab it's index.
let index = null;
const newItems = [...state.items].filter((item, i) => {
if (item.id === experience.id) {
index = i;
return false;
}

return true;
});

// Splice the new updated object in to the array.
newItems.splice(index, 0, experience);

return {
loading: false,
error: null,
items: newItems
};
}

/**
* Reducer that handles experience edit loading actions.
*/
case `${EXPERIENCES_EDIT}_LOADING`: {
return {
loading: true,
error: null,
items: [...state.items]
};
}

/**
* Reducer that handles experience edit failure actions.
*/
case `${EXPERIENCES_EDIT}_FAIL`: {
return {
loading: false,
error: action.payload.error,
items: [...state.items]
};
}
default:
return state;
}
Expand Down

0 comments on commit f6a5263

Please sign in to comment.