Skip to content

Commit

Permalink
[SDESK-4721] Save location directly from location popup (superdesk#1386)
Browse files Browse the repository at this point in the history
corrected lat/lon position in the schema
  • Loading branch information
nrvikas authored and MarkLark86 committed Nov 29, 2019
1 parent 744c09e commit e15b3f2
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 164 deletions.
77 changes: 11 additions & 66 deletions client/actions/events/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
TO_BE_CONFIRMED_FIELD,
} from '../../constants';
import {EventUpdateMethods} from '../../components/Events';
import {get, isEqual, cloneDeep, pickBy, isNil, has, find, every} from 'lodash';
import {get, isEqual, cloneDeep, pickBy, has, find, every} from 'lodash';
import * as selectors from '../../selectors';
import {
eventUtils,
Expand All @@ -26,7 +26,6 @@ import moment from 'moment';

import planningApi from '../planning/api';
import eventsUi from './ui';
import locationApi from '../locations';
import main from '../main';

/**
Expand Down Expand Up @@ -1264,59 +1263,15 @@ const uploadFiles = (event) => (
}
);

/**
* Action Dispatcher for saving the location for an event
* @param {object} event - The event the location is associated with
* @return arrow function
*/
const _saveLocation = (event, original) => (
(dispatch) => {
const location = get(event, 'location');

if (!location || !location.name) {
if (!get(original, 'location')) {
delete event.location;
} else if (get(original, 'lock_action') === EVENTS.ITEM_ACTIONS.EDIT_EVENT.lock_action) {
// only if event was edited
event.location = null;
}

return Promise.resolve(event);
} else if (location.existingLocation) {
event.location = {
name: location.name,
qcode: location.guid,
address: location.address,
};

// external address might not be there.
if (get(location, 'address.external')) {
delete location.address.external;
}

return Promise.resolve(event);
} else if (isNil(location.qcode)) {
// the location is set, but doesn't have a qcode (not registered in the location collection)
return dispatch(locationApi.saveLocation(location))
.then((savedLocation) => {
event.location = savedLocation;
return Promise.resolve(event);
});
} else {
return Promise.resolve(event);
}
}
);

const _save = (original, eventUpdates) => (
const save = (original, updates) => (
(dispatch, getState, {api}) => {
let promise;

if (original) {
promise = Promise.resolve(original);
} else if (isExistingItem(eventUpdates)) {
} else if (isExistingItem(updates)) {
promise = dispatch(
self.fetchById(eventUpdates._id, {saveToStore: false, loadPlanning: false})
self.fetchById(updates._id, {saveToStore: false, loadPlanning: false})
);
} else {
promise = Promise.resolve({});
Expand All @@ -1326,29 +1281,29 @@ const _save = (original, eventUpdates) => (
const originalItem = eventUtils.modifyForServer(cloneDeep(originalEvent), true);

// clone the updates as we're going to modify it
let updates = eventUtils.modifyForServer(
cloneDeep(eventUpdates),
let eventUpdates = eventUtils.modifyForServer(
cloneDeep(updates),
true
);

originalItem.location = originalItem.location ? [originalItem.location] : null;

// remove all properties starting with _
// and updates that are the same as original
updates = pickBy(updates, (v, k) => (
eventUpdates = pickBy(eventUpdates, (v, k) => (
(k === TO_BE_CONFIRMED_FIELD || k === '_planning_item' || !k.startsWith('_')) &&
!isEqual(updates[k], originalItem[k])
!isEqual(eventUpdates[k], originalItem[k])
));

if (get(originalItem, 'lock_action') === EVENTS.ITEM_ACTIONS.EDIT_EVENT.lock_action &&
!isTemporaryId(originalItem._id)
) {
delete updates.dates;
delete eventUpdates.dates;
}
updates.update_method = get(updates, 'update_method.value') ||
eventUpdates.update_method = get(eventUpdates, 'update_method.value') ||
EventUpdateMethods[0].value;

return api('events').save(originalItem, updates);
return api('events').save(originalItem, eventUpdates);
})
.then(
(data) => Promise.resolve(get(data, '_items') || [data]),
Expand All @@ -1357,14 +1312,6 @@ const _save = (original, eventUpdates) => (
}
);

const save = (original, updates) => (
(dispatch) => (
// Returns the modified unsaved event with the locations changes
dispatch(self._saveLocation(updates, original))
.then((modifiedUpdates) => dispatch(self._save(original, modifiedUpdates)))
)
);

const updateRepetitions = (original, updates) => (
(dispatch, getState, {api}) => (
api.update(
Expand Down Expand Up @@ -1511,9 +1458,7 @@ const self = {
fetchEventHistory,
unpost,
uploadFiles,
_save,
save,
_saveLocation,
getCriteria,
fetchById,
updateRepetitions,
Expand Down
69 changes: 1 addition & 68 deletions client/actions/events/tests/api_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1089,78 +1089,11 @@ describe('actions.events.api', () => {

afterEach(() => {
restoreSinonStub(eventsApi.fetchById);
restoreSinonStub(eventsApi._saveLocation);
restoreSinonStub(eventsApi._save);
});

it('returns Promise.reject is _saveLocation fails', (done) => {
sinon.stub(eventsApi, '_saveLocation').callsFake(() => Promise.reject('Save Location Failed'));
sinon.stub(eventsApi, '_save').callsFake(() => Promise.resolve());
store.test(done, eventsApi.save(data.events[0]))
.then(null, (error) => {
expect(error).toEqual('Save Location Failed');

expect(eventsApi._saveLocation.callCount).toBe(1);
expect(eventsApi._save.callCount).toBe(0);

done();
})
.catch(done.fail);
});

it('runs _save with location information', (done) => {
sinon.stub(eventsApi, '_saveLocation').callsFake((item) => Promise.resolve(item));
sinon.stub(eventsApi, '_save').callsFake((item) => Promise.resolve(item));
store.test(done, eventsApi.save(data.events[0], {name: 'New Event'}))
.then((item) => {
expect(item).toEqual(data.events[0]);
expect(eventsApi._saveLocation.callCount).toBe(1);
expect(eventsApi._save.callCount).toBe(1);
expect(eventsApi._save.args[0]).toEqual([
data.events[0],
{name: 'New Event'},
]);

done();
})
.catch(done.fail);
});

it('_save calls api.save', (done) => (
store.test(done, eventsApi._save(null, {
_id: data.events[0]._id,
name: 'New Name',
slugline: 'New Slugline',
}))
.then((item) => {
expect(item).toEqual([data.events[0]]);

expect(eventsApi.fetchById.callCount).toBe(1);
expect(eventsApi.fetchById.args[0]).toEqual([
data.events[0]._id,
{saveToStore: false, loadPlanning: false},
]);

expect(services.api('events').save.callCount).toBe(1);
expect(services.api('events').save.args[0]).toEqual([
{
...data.events[0],
location: null,
},
{
name: 'New Name',
slugline: 'New Slugline',
update_method: 'single',
},
]);

done();
})
.catch(done.fail)
));

it('doesnt call event.api.fetchById if it is a new Event', (done) => (
store.test(done, eventsApi._save(null, {name: 'New Event', slugline: 'New Slugline'}))
store.test(done, eventsApi.save(null, {name: 'New Event', slugline: 'New Slugline'}))
.then(() => {
expect(eventsApi.fetchById.callCount).toBe(0);

Expand Down
22 changes: 0 additions & 22 deletions client/actions/locations.js
Original file line number Diff line number Diff line change
Expand Up @@ -171,28 +171,6 @@ const saveLocation = (newLocation) => (
(result) => Promise.resolve(result),
() => Promise.reject('Failed to save location.!')
);
})
.then((data) => {
const eventData = {
name: data.name,
qcode: data.guid,
};

if (data.position) {
eventData.location = {
lat: data.position.latitude,
lon: data.position.longitude,
};
}

if (get(data, 'address')) {
eventData.address = data.address;
if (eventData.address.external) {
delete eventData.address.external;
}
}

return eventData;
});
}
);
Expand Down
51 changes: 43 additions & 8 deletions client/components/GeoLookupInput/AddGeoLookupInput.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,19 @@ export class GeoLookupInputComponent extends React.Component {
}

saveNewLocation(value) {
this.props.onChange(this.props.field, value);
this.setState({
unsavedInput: '',
searching: false,
searchLocalAlways: true,
});
this.props.saveLocation(value)
.then((newLocation) => {
this.onSuggestSelect({
...newLocation,
existingLocation: true,
});

this.setState({
unsavedInput: '',
searching: false,
searchLocalAlways: true,
});
});
}

removeLocation() {
Expand Down Expand Up @@ -184,8 +191,34 @@ export class GeoLookupInputComponent extends React.Component {
* @param {Object} suggest The suggest
*/
onSuggestSelect(suggest) {
this.props.onChange(this.props.field, this.onGeocodeSuggest(suggest));
this.resetSearchResults();
const location = this.onGeocodeSuggest(suggest);
let promise = get(location, 'existingLocation') ? Promise.resolve(location) :
this.props.saveLocation(location);

promise.then((newLocation) => {
let value = {
name: newLocation.name,
qcode: newLocation.guid,
address: newLocation.address,
};

// external address might not be there.
if (get(value, 'address.external')) {
delete value.address.external;
}

if (newLocation.position) {
value = {
...value,
location: {
lat: get(newLocation, 'position.latitude'),
lon: get(newLocation, 'position.longitude'),
},
};
}

this.props.onChange(this.props.field, value);
}).finally(() => this.resetSearchResults());
}

onSuggestsLookup(userInput) {
Expand Down Expand Up @@ -332,6 +365,7 @@ GeoLookupInputComponent.propTypes = {
onPopupOpen: PropTypes.func,
onPopupClose: PropTypes.func,
allowFreeTextLocation: PropTypes.bool,
saveLocation: PropTypes.func,
};

const mapStateToProps = (state, ownProps) => ({
Expand All @@ -346,6 +380,7 @@ const mapStateToProps = (state, ownProps) => ({

const mapDispatchToProps = (dispatch) => ({
searchLocalLocations: (text) => dispatch(actions.locations.getLocation(text)),
saveLocation: (newLocation) => dispatch(actions.locations.saveLocation(newLocation)),
});

export const AddGeoLookupInput = connect(
Expand Down

0 comments on commit e15b3f2

Please sign in to comment.