messages, answered requests

- Created view for journal query so we can use the calculated fields in
a where clause
- Changed journal ordering from newest-first to oldest-first; that way,
clicking "prayed" at the top, one right after the other, will let the
user pray through their list with minimal distraction
- Answered requests now drop off the active journal (still need to write
the ability to review answered requests)
- All the activities now send messages to the user, so they have
confirmation that their action has completed
This commit is contained in:
Daniel J. Summers 2017-09-23 21:28:43 -05:00
parent 8cb58cc2d3
commit ec08bfbc74
7 changed files with 69 additions and 35 deletions

View File

@ -52,6 +52,33 @@ const ddl = [
fix: ` fix: `
CREATE INDEX "idx_request_userId" ON mpj.request ("userId"); CREATE INDEX "idx_request_userId" ON mpj.request ("userId");
COMMENT ON INDEX "idx_request_userId" IS 'Requests are retrieved by user'` COMMENT ON INDEX "idx_request_userId" IS 'Requests are retrieved by user'`
},
{
name: 'journal View',
check: `SELECT 1 FROM pg_views WHERE schemaname='mpj' AND viewname='journal'`,
fix: `
CREATE VIEW mpj.journal AS
SELECT
request."requestId",
request."userId",
(SELECT "text"
FROM mpj.history
WHERE history."requestId" = request."requestId"
AND "text" IS NOT NULL
ORDER BY "asOf" DESC
LIMIT 1) AS "text",
(SELECT "asOf"
FROM mpj.history
WHERE history."requestId" = request."requestId"
ORDER BY "asOf" DESC
LIMIT 1) AS "asOf",
(SELECT "status"
FROM mpj.history
WHERE history."requestId" = request."requestId"
ORDER BY "asOf" DESC
LIMIT 1) AS "lastStatus"
FROM mpj.request;
COMMENT ON VIEW mpj.journal IS 'Requests with latest text'`
} }
] ]

View File

@ -4,24 +4,12 @@ import { Pool } from 'pg'
import cuid from 'cuid' import cuid from 'cuid'
const currentRequestSql = ` const currentRequestSql = `
SELECT SELECT "requestId", "text", "asOf", "lastStatus"
request."requestId", FROM mpj.journal`
(SELECT "text"
FROM mpj.history
WHERE history."requestId" = request."requestId"
AND "text" IS NOT NULL
ORDER BY "asOf" DESC
LIMIT 1) AS "text",
(SELECT "asOf"
FROM mpj.history
WHERE history."requestId" = request."requestId"
ORDER BY "asOf" DESC
LIMIT 1) AS "asOf"
FROM mpj.request`
const journalSql = `${currentRequestSql} const journalSql = `${currentRequestSql}
WHERE "userId" = $1 WHERE "userId" = $1
GROUP BY request."requestId"` AND "lastStatus" <> 'Answered'`
const requestNotFound = { const requestNotFound = {
requestId: '', requestId: '',
@ -40,7 +28,10 @@ export default function (pool) {
addHistory: async (requestId, status, updateText) => { addHistory: async (requestId, status, updateText) => {
const asOf = Date.now() const asOf = Date.now()
await pool.query(` await pool.query(`
INSERT INTO mpj.history ("requestId", "asOf", "status", "text") VALUES ($1, $2, $3, NULLIF($4, ''))`, INSERT INTO mpj.history
("requestId", "asOf", "status", "text")
VALUES
($1, $2, $3, NULLIF($4, ''))`,
[ requestId, asOf, status, updateText ]) [ requestId, asOf, status, updateText ])
}, },
@ -70,10 +61,10 @@ export default function (pool) {
} finally { } finally {
client.release() client.release()
} }
return { requestId: id, text: requestText, asOf: enteredOn } return { requestId: id, text: requestText, asOf: enteredOn, lastStatus: 'Created' }
})().catch(e => { })().catch(e => {
console.error(e.stack) console.error(e.stack)
return { requestId: '', text: 'error', asOf: 0 } return { requestId: '', text: 'error', asOf: 0, lastStatus: 'Errored' }
}) })
}, },
@ -86,8 +77,7 @@ export default function (pool) {
byId: async (userId, requestId) => { byId: async (userId, requestId) => {
const reqs = await pool.query(`${currentRequestSql} const reqs = await pool.query(`${currentRequestSql}
WHERE "requestId" = $1 WHERE "requestId" = $1
AND "userId" = $2 AND "userId" = $2`,
GROUP BY request."requestId"`,
[ requestId, userId ]) [ requestId, userId ])
return (0 < reqs.rowCount) ? reqs.rows[0] : requestNotFound return (0 < reqs.rowCount) ? reqs.rows[0] : requestNotFound
}, },
@ -124,15 +114,7 @@ export default function (pool) {
* @param {string} userId The Id of the user * @param {string} userId The Id of the user
* @return The requests that make up the current journal * @return The requests that make up the current journal
*/ */
journal: async userId => (await pool.query(`${journalSql} ORDER BY "asOf" DESC`, [ userId ])).rows, journal: async userId => (await pool.query(`${journalSql} ORDER BY "asOf"`, [ userId ])).rows
/**
* Get the least-recently-updated prayer request for the given user
* @param {string} userId The Id of the current user
* @return The least-recently-updated request for the given user
*/
oldest: async userId => (await pool.query(`${journalSql} ORDER BY "asOf" LIMIT 1`, [ userId ])).rows[0]
} }
} }

View File

@ -4,7 +4,6 @@ article
p(v-if="isLoadingJournal") Loading your prayer journal... p(v-if="isLoadingJournal") Loading your prayer journal...
template(v-if="!isLoadingJournal") template(v-if="!isLoadingJournal")
new-request new-request
p journal has {{ journal.length }} entries
el-row el-row
el-col(:span='4'): strong Actions el-col(:span='4'): strong Actions
el-col(:span='16'): strong Request el-col(:span='16'): strong Request
@ -38,6 +37,10 @@ export default {
}, },
async created () { async created () {
await this.$store.dispatch(actions.LOAD_JOURNAL, this.$Progress) await this.$store.dispatch(actions.LOAD_JOURNAL, this.$Progress)
this.$message({
message: `Loaded ${this.journal.length} prayer requests`,
type: 'success'
})
} }
} }
</script> </script>

View File

@ -49,6 +49,17 @@ export default {
updateText: this.form.requestText, updateText: this.form.requestText,
status: this.form.status status: this.form.status
}) })
if (this.form.status === 'Answered') {
this.$message({
message: 'Request updated and removed from active journal',
type: 'success'
})
} else {
this.$message({
message: 'Request updated',
type: 'success'
})
}
this.editVisible = false this.editVisible = false
} }
} }

View File

@ -1,6 +1,6 @@
<template lang="pug"> <template lang="pug">
div div
el-button(@click='openDialog()') Add a New Request el-button(icon='plus' @click='openDialog()') Add a New Request
el-dialog(title='Add a New Prayer Request' :visible.sync='showNewVisible') el-dialog(title='Add a New Prayer Request' :visible.sync='showNewVisible')
el-form(:model='form' :label-position='top') el-form(:model='form' :label-position='top')
el-form-item(label='Prayer Request') el-form-item(label='Prayer Request')
@ -39,7 +39,11 @@ export default {
progress: this.$Progress, progress: this.$Progress,
requestText: this.form.requestText requestText: this.form.requestText
}) })
this.showNewVisible = false this.$message({
message: 'New prayer request added',
type: 'success'
})
this.closeDialog()
} }
} }
} }

View File

@ -4,7 +4,7 @@ el-row.journal-request
el-button(icon='check' @click='markPrayed()' title='Pray') el-button(icon='check' @click='markPrayed()' title='Pray')
edit-request(:request='request') edit-request(:request='request')
full-request(:request='request') full-request(:request='request')
el-col(:span='16'): p {{ request.text }} el-col(:span='16'): p {{ text }}
el-col(:span='4'): p {{ asOf }} el-col(:span='4'): p {{ asOf }}
</template> </template>
@ -33,11 +33,18 @@ export default {
status: 'Prayed', status: 'Prayed',
updateText: '' updateText: ''
}) })
this.$message({
message: 'Request marked as prayed',
type: 'success'
})
} }
}, },
computed: { computed: {
asOf () { asOf () {
return moment(this.request.asOf).fromNow() return moment(this.request.asOf).fromNow()
},
text () {
return this.request.text.split('\n').join('<br>')
} }
} }
} }

View File

@ -45,11 +45,11 @@ export default new Vuex.Store({
state.journal = journal state.journal = journal
}, },
[mutations.REQUEST_ADDED] (state, newRequest) { [mutations.REQUEST_ADDED] (state, newRequest) {
state.journal.unshift(newRequest) state.journal.push(newRequest)
}, },
[mutations.REQUEST_UPDATED] (state, request) { [mutations.REQUEST_UPDATED] (state, request) {
let jrnl = state.journal.filter(it => it.requestId !== request.requestId) let jrnl = state.journal.filter(it => it.requestId !== request.requestId)
jrnl.unshift(request) if (request.lastStatus !== 'Answered') jrnl.push(request)
state.journal = jrnl state.journal = jrnl
}, },
[mutations.USER_LOGGED_OFF] (state) { [mutations.USER_LOGGED_OFF] (state) {