Add the possibility to leave notes on flats
* Add a database field to store `notes` (as a memo) about flats. * Add matching UI elements to let users store their notes about flats. This commit closes issue #34.
This commit is contained in:
parent
8a50dd3302
commit
69588a9601
@ -12,6 +12,7 @@ Based on Flask-whooshalchemy by Karl Gyllstrom (Flask is still supported, but no
|
||||
:copyright: (c) 2012 by Karl Gyllstrom
|
||||
:license: BSD (see LICENSE.txt)
|
||||
"""
|
||||
# pylint: skip-file
|
||||
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
|
@ -76,6 +76,7 @@ class Flat(BASE):
|
||||
title = Column(String)
|
||||
urls = Column(MagicJSON)
|
||||
merged_ids = Column(MagicJSON)
|
||||
notes = Column(Text)
|
||||
|
||||
# Flatisfy data
|
||||
# TODO: Should be in another table with relationships
|
||||
|
@ -78,6 +78,8 @@ def get_app(config):
|
||||
app.route("/api/v1/flat/:flat_id", "GET", api_routes.flat_v1)
|
||||
app.route("/api/v1/flat/:flat_id/status", "POST",
|
||||
api_routes.update_flat_status_v1)
|
||||
app.route("/api/v1/flat/:flat_id/notes", "POST",
|
||||
api_routes.update_flat_notes_v1)
|
||||
|
||||
app.route("/api/v1/search", "POST", api_routes.search_v1)
|
||||
|
||||
|
@ -68,7 +68,24 @@ export const updateFlatStatus = function (flatId, newStatus, callback) {
|
||||
).then(callback).catch(function (ex) {
|
||||
console.error('Unable to update flat status: ' + ex)
|
||||
})
|
||||
}
|
||||
|
||||
export const updateFlatNotes = function (flatId, newNotes, callback) {
|
||||
fetch(
|
||||
'/api/v1/flat/' + encodeURIComponent(flatId) + '/notes',
|
||||
{
|
||||
credentials: 'same-origin',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
notes: newNotes
|
||||
})
|
||||
}
|
||||
).then(callback).catch(function (ex) {
|
||||
console.error('Unable to update flat notes: ' + ex)
|
||||
})
|
||||
}
|
||||
|
||||
export const getTimeToPlaces = function (callback) {
|
||||
@ -82,7 +99,6 @@ export const getTimeToPlaces = function (callback) {
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
export const doSearch = function (query, callback) {
|
||||
fetch(
|
||||
'/api/v1/search',
|
||||
@ -101,5 +117,4 @@ export const doSearch = function (query, callback) {
|
||||
}).catch(function (ex) {
|
||||
console.error('Unable to perform search: ' + ex)
|
||||
})
|
||||
|
||||
}
|
||||
|
@ -27,6 +27,12 @@ export default {
|
||||
commit(types.UPDATE_FLAT_STATUS, { flatId, newStatus })
|
||||
})
|
||||
},
|
||||
updateFlatNotes ({ commit }, { flatId, newNotes }) {
|
||||
commit(types.IS_LOADING)
|
||||
api.updateFlatNotes(flatId, newNotes, response => {
|
||||
commit(types.UPDATE_FLAT_NOTES, { flatId, newNotes })
|
||||
})
|
||||
},
|
||||
doSearch ({ commit }, { query }) {
|
||||
commit(types.IS_LOADING)
|
||||
api.doSearch(query, flats => {
|
||||
|
@ -1,5 +1,6 @@
|
||||
export const REPLACE_FLATS = 'REPLACE_FLATS'
|
||||
export const MERGE_FLATS = 'MERGE_FLATS'
|
||||
export const UPDATE_FLAT_STATUS = 'UPDATE_FLAT_STATUS'
|
||||
export const UPDATE_FLAT_NOTES = 'UPDATE_FLAT_NOTES'
|
||||
export const RECEIVE_TIME_TO_PLACES = 'RECEIVE_TIME_TO_PLACES'
|
||||
export const IS_LOADING = 'IS_LOADING'
|
||||
|
@ -32,6 +32,13 @@ export const mutations = {
|
||||
Vue.set(state.flats[index], 'status', newStatus)
|
||||
}
|
||||
},
|
||||
[types.UPDATE_FLAT_NOTES] (state, { flatId, newNotes }) {
|
||||
state.loading = false
|
||||
const index = state.flats.findIndex(flat => flat.id === flatId)
|
||||
if (index > -1) {
|
||||
Vue.set(state.flats[index], 'notes', newNotes)
|
||||
}
|
||||
},
|
||||
[types.RECEIVE_TIME_TO_PLACES] (state, { timeToPlaces }) {
|
||||
state.loading = false
|
||||
state.timeToPlaces = timeToPlaces
|
||||
|
@ -101,6 +101,14 @@
|
||||
|
||||
<FlatsMap :flats="flatMarkers" :places="timeToPlaces" :journeys="journeys"></FlatsMap>
|
||||
</div>
|
||||
<div>
|
||||
<h3>Notes</h3>
|
||||
|
||||
<form v-on:submit="updateFlatNotes">
|
||||
<textarea ref="notesTextarea" rows="10">{{ flat.notes }}</textarea>
|
||||
<p class="right"><input type="submit" value="Save"/></p>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right-panel">
|
||||
<h3>{{ $t("flatsDetails.Contact") }}</h3>
|
||||
@ -242,6 +250,14 @@ export default {
|
||||
this.$store.dispatch('updateFlatStatus', { flatId: this.$route.params.id, newStatus: status })
|
||||
},
|
||||
|
||||
updateFlatNotes () {
|
||||
const notes = this.$refs.notesTextarea.value
|
||||
this.$store.dispatch(
|
||||
'updateFlatNotes',
|
||||
{ flatId: this.$route.params.id, newNotes: notes }
|
||||
)
|
||||
},
|
||||
|
||||
humanizeTimeTo (time) {
|
||||
const minutes = Math.floor(time.as('minutes'))
|
||||
return minutes + ' ' + this.$tc('common.mins', minutes)
|
||||
@ -269,6 +285,10 @@ export default {
|
||||
grid-row: 1;
|
||||
}
|
||||
|
||||
.left-panel textarea {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.right {
|
||||
text-align: right;
|
||||
}
|
||||
|
@ -47,24 +47,24 @@ export default {
|
||||
}
|
||||
|
||||
return this.$store.getters.postalCodesFlatsBuckets(
|
||||
flat => flat.status != "duplicate" && flat.status != "ignored"
|
||||
flat => flat.status !== 'duplicate' && flat.status !== 'ignored'
|
||||
)
|
||||
},
|
||||
loading () {
|
||||
return this.$store.getters.isLoading;
|
||||
return this.$store.getters.isLoading
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
onSearch(event) {
|
||||
onSearch (event) {
|
||||
event.preventDefault()
|
||||
|
||||
let query = this.$refs.searchInput.value
|
||||
const query = this.$refs.searchInput.value
|
||||
this.$router.replace({ name: 'search', query: { query: query }})
|
||||
},
|
||||
|
||||
doSearch() {
|
||||
let query = this.$route.query.query
|
||||
doSearch () {
|
||||
const query = this.$route.query.query
|
||||
|
||||
if (query) {
|
||||
this.$store.dispatch('doSearch', { query: query })
|
||||
|
@ -147,6 +147,33 @@ def update_flat_status_v1(flat_id, db):
|
||||
}
|
||||
|
||||
|
||||
def update_flat_notes_v1(flat_id, db):
|
||||
"""
|
||||
API v1 route to update flat notes:
|
||||
|
||||
POST /api/v1/flat/:flat_id/notes
|
||||
Data: {
|
||||
"notes": "NEW_NOTES"
|
||||
}
|
||||
|
||||
:return: The new flat object in a JSON ``data`` dict.
|
||||
"""
|
||||
flat = db.query(flat_model.Flat).filter_by(id=flat_id).first()
|
||||
if not flat:
|
||||
return bottle.HTTPError(404, "No flat with id {}.".format(flat_id))
|
||||
|
||||
try:
|
||||
flat.notes = json.load(bottle.request.body)["notes"]
|
||||
except (ValueError, KeyError):
|
||||
return bottle.HTTPError(400, "Invalid notes provided.")
|
||||
|
||||
json_flat = flat.json_api_repr()
|
||||
|
||||
return {
|
||||
"data": json_flat
|
||||
}
|
||||
|
||||
|
||||
def time_to_places_v1(config):
|
||||
"""
|
||||
API v1 route to fetch the details of the places to compute time to.
|
||||
@ -165,7 +192,7 @@ def time_to_places_v1(config):
|
||||
}
|
||||
|
||||
|
||||
def search_v1(config, db):
|
||||
def search_v1(config):
|
||||
"""
|
||||
API v1 route to perform a fulltext search on flats.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user