Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add in ability to edit pins #95

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open

Add in ability to edit pins #95

wants to merge 13 commits into from

Conversation

jfangrad
Copy link
Collaborator

@jfangrad jfangrad commented Dec 1, 2018

This PR adds in the feature to edit/delete locations.

Also adds in database update migration. (createOrUpdateDatabase function in database.js)

To edit/delete a pin, simply press and hold and drag the location to one of the options and then release it.

Deleting is only available if the location has never been uploaded to the database. (It will only delete the local version anyways, it doesn't even attempt to delete anything on the server side).

Editing is always available. Location version details are now kept with each location. If you attempt to edit a location that has a newer version on the server you will receive an error that states that the edit failed due to a newer version existing on the server. It will then update that location and inform the user that they can now try again editing the latest version.

Todo:

  • Need translations
  • Possibly some more testing (Scott would you mind testing using this branch and seeing if the database migrates correctly?) (Scott performed more testing. It failed a bunch, but I think I have updated it to be safer)
  • Better contrast on the change buttons
  • Confirm how modifications work with remote values
  • Test changing a point which has been pushed
  • Test a change which has happened to a remote point
  • Test conflicting updates
  • Review https://stackoverflow.com/questions/989558/best-practices-for-in-app-database-migration-for-sqlite

@jfangrad jfangrad requested review from smaclell and Robwiebe December 1, 2018 17:19
@jfangrad
Copy link
Collaborator Author

jfangrad commented Dec 1, 2018

@jfangrad
Copy link
Collaborator Author

jfangrad commented Dec 1, 2018

Local Editing/Draft Data

Copy link
Owner

@smaclell smaclell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is going to be great. I have a bunch of questions about it and a few things I am worried about. Thanks for working on this amazing feature.

@@ -134,13 +159,58 @@ export function createLocation(options) {
return;
}

const { created: location, saved } = await apis.createLocation(regionKey, locationData, key);
const { created: location, saved } = await apiCall(regionKey, key, localLocation);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ It looks like this call switched from using locationData to localLocation. I cannot tell is that is a bad thing. It sure is different.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is done on purpose. The data is updated or created in the local database first and the result of that is then used to send to the server since the localLocation object contains info like the location version number, where as the locationData object does not.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does versioning/changes work if it is only local?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you be a little more specific? When sending to the remote we do store the version info. It's just that the locationData object here doesn't necessarily include that information.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was expecting the version number to be remote since we need to make sure data is synced correctly in firebase.

Your comment cleared it up a bit. So we do send it, just not necessarily initially.

apis/database.js Outdated Show resolved Hide resolved
apis/database.js Outdated
updated: oldLocation.uploaded ? oldLocation.updated + 1 : oldLocation.updated,
});

await executeTransaction('update locations set resources = ?, status = ?, uploaded = 0, updated = ? where key = ?', [
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this also need a transaction or to enforce that update is equal to update - 1 before it is being set?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure that's totally necessary. The value of updated will always be less than the new value. If it is less than the new value -1 then we are just making an even newer update to the local location and it should be a non-issue. Is there something else I am overlooking?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you might be okay with the local version, but you might not be able to guarantee that you are the only person to write to the remote data.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But I already do a check to ensure the remote data hasn't been updated more recently no?

Copy link
Owner

@smaclell smaclell Jan 20, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You do, but there is still a race condition. Multiple people could try to update it at the same time which would still result in one overwriting the other if the concurrency bit is only set locally. I was expecting something to be passed up with the update to prevent races in firebase.

We can setup a remote rule for firebase to prevent updates if the version number is not expected.

apis/database.js Show resolved Hide resolved
apis/database.js Show resolved Hide resolved
containers/LocationMarker.js Outdated Show resolved Hide resolved
reducers/locations.js Outdated Show resolved Hide resolved
deleteLocalLocation(pinLocation.key);
} else {
// Is there a better way to get the pin to rerender??? Cause this is actually gross...
this.setState(() => ({ editingPinKey: pinLocation.key }), () => this.setState(() => ({ editingPinKey: null })));
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you might be able to call a method to force it to rerender. You are right. This is gross.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apparently, there is something weird with markers and they only fully redraw when their key prop changes so I had to use a Date.now() to build a unique key every time the LocationMarker component rerenders. But I think that's still better than the old way.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh interesting? Are they pure or have a shouldComponentUpdate?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I can see it's not pure and doesn't have a shouldComponentUpdate

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Odd. Must be something from the maps library. I think I saw one of the items higher in the hierarchy was pure, but that could just be a red herring.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mind adding a comment as to why we are doing this odd things?

screenHeight = Dimensions.get('window').height * (Platform.OS === 'ios' ? 1 : Dimensions.get('window').scale);

createTempPin = (coord, editingPinKey) => {
this.setState(() => ({ tempLocation: coord, editingPinKey }));
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style: I have since learned it is better to use the following. It updates just those keys whereas what you are doing will overwrite alot more.

Suggested change
this.setState(() => ({ tempLocation: coord, editingPinKey }));
this.setState({ tempLocation: coord, editingPinKey });

screens/overviewMap.js Show resolved Hide resolved
apis/index.js Outdated Show resolved Hide resolved
containers/LocationMarker.js Show resolved Hide resolved
containers/LocationMarker.js Outdated Show resolved Hide resolved
@smaclell
Copy link
Owner

I like the back up and think you are well on your way. Let's sync up on hangouts to see what is left to get this one out. I think it might be ready.

@smaclell
Copy link
Owner

I have performed a basic round of testing. It has filled me with more respect/fear for this feature. Added a few more things to test to my list. May try to think of simpler ways we can roll this out.

@smaclell smaclell dismissed their stale review March 1, 2019 02:15

Since I have been adding fixes/improvements I don't think I my previous review applies.

@smaclell
Copy link
Owner

smaclell commented Mar 1, 2019

@jfangrad what stops a baddy from editing all the pins they want? Could one bad actor wipe out all our data?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants