app\containers\SampleFullstackApps\Contact\reducers\contactConstants.js
export const FETCH_CONTACT = 'FETCH_CONTACT';
export const FETCH_CONTACT_SUCCESS = 'FETCH_CONTACT_SUCCESS';
export const FETCH_CONTACT_FAILED = 'FETCH_CONTACT_FAILED';
app\containers\SampleFullstackApps\Contact\reducers\contactActions.js
/* Load */
export const loadContactSuccess = payload => ({
type: types.FETCH_CONTACT_SUCCESS,
payload,
});
app\containers\SampleFullstackApps\Contact\reducers\contactSagas.js
function* read() {
const channel = yield call(subscribe);
while (true) {
const action = yield take(channel);
yield put(action);
}
}
function* watchContact() {
while (true) {
contactList.path = 'contacts/';
const job = yield fork(read);
yield take([FETCH_CONTACT]);
yield cancel(job);
}
}
import ContactModels from '../models';
import Init from '../models/init';
import { loadContactSuccess } from './contactActions';
const contactList = new ContactModels({
onLoad: loadContactSuccess,
}, Init);
function subscribe() {
return eventChannel(emit => contactList.subscribe(emit));
}
app\containers\SampleFullstackApps\Contact\reducers\contactReducer.js
case FETCH_CONTACT_SUCCESS:
return state.withMutations((mutableState) => {
const items = fromJS(action.payload);
mutableState
.set('contactList', new List(items))
.set('loading', false);
});
\app\containers\SampleFullstackApps\Contact\index.js
const { dataContact } = this.props;
const mapStateToProps = state => ({
dataContact: state.getIn([reducer, 'contactList']),
});
return {
<ContactList
addFn
total={dataContact.size}
addContact={add}
clippedRight
itemSelected={itemSelected}
dataContact={dataContact}
showDetail={showDetail}
search={search}
keyword={keyword}
loading={loading}
/>
}
app\components\Contact\ContactList.js
const getItem = dataArray => dataArray.map(data => {
const index = dataContact.indexOf(data);
if (data.get('name').toLowerCase().indexOf(keyword) === -1) {
return false;
}
return (
<ListItem
button
key={data.get('key')}
className={index === itemSelected ? classes.selected : ''}
onClick={() => showDetail(data)}
>
<Avatar alt={data.get('name')} src={data.get('avatar')} className={classes.avatar} />
<ListItemText primary={data.get('name')} secondary={data.get('title')} />
</ListItem>
);
});
app\containers\SampleFullstackApps\Contact\reducers\contactConstants.js
export const CREATE_CONTACT = 'CREATE_CONTACT';
export const CREATE_CONTACT_SUCCESS = 'CREATE_CONTACT_SUCCESS';
export const CREATE_CONTACT_FAILED = 'CREATE_CONTACT_FAILED';
app\containers\SampleFullstackApps\Contact\reducers\contactActions.js
export const createAction = payload => ({
type: types.CREATE_CONTACT,
payload,
});
export const createActionSuccess = payload => ({
type: types.CREATE_CONTACT_SUCCESS,
payload,
});
export const createActionFailed = error => ({
type: types.CREATE_CONTACT_FAILED,
payload: { error },
});
app\containers\SampleFullstackApps\Contact\reducers\contactSagas.js
const createContact = write.bind(null, contactList, contactList.push, createActionFailed);
function* watchCreateContact() {
while (true) {
const { payload } = yield take(CREATE_CONTACT);
yield fork(createContact, payload);
}
}
app\containers\SampleFullstackApps\Contact\reducers\todoReducer.js
case CREATE_CONTACT_SUCCESS:
return state.withMutations((mutableState) => {
const items = action.payload;
mutableState.set('contactList', state.get('contactList').unshift(items));
mutableState
.set('formValues', Map())
.set('avatarInit', '')
.set('openFrm', false)
.set('notifMsg', notif.saved);
});
app\containers\SampleFullstackApps\Contact\index.js
import { createAction } from './reducers/contactActions';
const constDispatchToProps = dispatch => ({
create: bindActionCreators(createAction, dispatch),
});
return (
<AddContact
addContact={add}
openForm={open}
closeForm={close}
submit={this.submitContact}
avatarInit={avatarInit}
processing={uploadSubmiting}
/>
)
app\components\Contact\AddContactForm.js
sendValues = (values) => {
const { submit } = this.props;
const { img } = this.state;
setTimeout(() => {
submit(values, img);
this.setState({ img: null });
}, 500);
}
return (
<form onSubmit={this.handleSubmit} noValidate>
...
</form>
)
app\containers\SampleFullstackApps\Contact\reducers\contactConstants.js
export const UPDATE_CONTACT = 'UPDATE_CONTACT';
export const UPDATE_CONTACT_SUCCESS = 'UPDATE_CONTACT_SUCCESS';
export const UPDATE_CONTACT_FAILED = 'UPDATE_CONTACT_FAILED';
app\containers\SampleFullstackApps\Contact\reducers\contactActions.js
export const updateAction = (contact, changes) => ({
type: types.UPDATE_CONTACT,
payload: { contact, changes },
});
export const updateActionSuccess = payload => ({
type: types.UPDATE_CONTACT_SUCCESS,
payload
});
export const updateActionFailed = error => ({
type: types.UPDATE_CONTACT_FAILED,
payload: { error },
});
app\containers\SampleFullstackApps\Contact\reducers\contactSagas.js
const updateContact = write.bind(null, contactList, contactList.update, updateActionFailed);
function* watchUpdateContact() {
while (true) {
const { payload } = yield take(UPDATE_CONTACT);
yield fork(updateContact, payload.contact.key, payload.changes);
}
}
app\containers\SampleFullstackApps\Contact\reducers\todoReducer.js
case UPDATE_CONTACT_SUCCESS:
return state.withMutations((mutableState) => {
mutableState.set(
'contactList',
state.get('contactList').map(contact => (contact.key === action.payload.key ? action.payload : contact))
);
mutableState
.set('formValues', Map())
.set('avatarInit', '')
.set('openFrm', false)
.set('notifMsg', notif.updated);
});
app\containers\SampleFullstackApps\Contact\index.js
import { updateAction } from './reducers/contactActions';
const constDispatchToProps = dispatch => ({
update: bindActionCreators(updateAction, dispatch),
});
submitContact = (item, avatar) => {
const {
create, update,
dataContact, itemSelected, selectedId,
} = this.props;
const value = item.toJS();
this.setState({ uploadSubmiting: true });
if (value.key === selectedId) { // Update contact
const contact = dataContact.get(itemSelected);
uploadImg(avatar, async (url) => {
value.avatar = url || null;
update(contact, value);
this.setState({ uploadSubmiting: false });
});
} else { // Create new contact
uploadImg(avatar, async (url) => {
value.avatar = url || null;
create(value);
this.setState({ uploadSubmiting: false });
});
}
}
return (
<AddContact
addContact={add}
openForm={open}
closeForm={close}
submit={this.submitContact}
avatarInit={avatarInit}
processing={uploadSubmiting}
/>
)
app\components\Contact\AddContactForm.js
sendValues = (values) => {
const { submit } = this.props;
const { img } = this.state;
setTimeout(() => {
submit(values, img);
this.setState({ img: null });
}, 500);
}
return (
<form onSubmit={this.handleSubmit} noValidate>
...
</form>
)
app\containers\SampleFullstackApps\Contact\reducers\contactConstants.js
export const DELETE_CONTACT = 'DELETE_CONTACT';
export const DELETE_CONTACT_SUCCESS = 'DELETE_CONTACT_SUCCESS';
export const DELETE_CONTACT_FAILED = 'DELETE_CONTACT_FAILED';
app\containers\SampleFullstackApps\Contact\reducers\contactActions.js
/* Delete */
export const deleteAction = payload => ({
type: types.DELETE_CONTACT,
payload,
});
export const deleteActionSuccess = payload => ({
type: types.DELETE_CONTACT_SUCCESS,
payload,
});
export const deleteActionFailed = error => ({
type: types.DELETE_CONTACT_FAILED,
payload: { error },
});
app\containers\SampleFullstackApps\Contact\reducers\contactSagas.js
const removeContact = write.bind(null, contactList, contactList.remove, deleteActionFailed);
function* watchRemoveContact() {
while (true) {
const { payload } = yield take(DELETE_CONTACT);
yield fork(removeContact, payload.key);
}
}
app\containers\SampleFullstackApps\Contact\reducers\todoReducer.js
return state.withMutations((mutableState) => {
mutableState
.set(
'contactList',
state.get('contactList').filter(contact => contact.key !== action.payload.key)
)
.set('notifMsg', notif.removed);
});
app\containers\SampleFullstackApps\Contact\index.js
import { deleteAction } from './reducers/contactActions';
const constDispatchToProps = dispatch => ({
remove: bindActionCreators(deleteAction, dispatch),
});
return (
<ContactDetail
showMobileDetail={showMobileDetail}
hideDetail={hideDetail}
dataContact={dataContact}
itemSelected={itemSelected}
edit={edit}
remove={remove}
favorite={update}
loading={loading}
/>
)
app/components/Contact/ContactDetail.js
deleteContact = (item) => {
const { remove } = this.props;
remove(item);
this.setState({ anchorElOpt: null });
}
return (
<MenuItem onClick={() => this.deleteContact(dataContact.get(itemSelected))}>
<FormattedMessage {...messages.delete} />
</MenuItem>
)