Active request page (#16)
Also: - refactored snoozed and answered list pages to use a common list format - reworked the URLs to make them more consistent - eliminated current "full" API endpoint, and renamed existing "complete" endpoint to "full"
This commit is contained in:
parent
d3aff4a110
commit
e351fe5b56
@ -267,7 +267,7 @@ type AppDbContext (opts : DbContextOptions<AppDbContext>) =
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve a request, including its history and notes, by its ID and user ID
|
/// Retrieve a request, including its history and notes, by its ID and user ID
|
||||||
member this.TryCompleteRequestById requestId userId =
|
member this.TryFullRequestById requestId userId =
|
||||||
task {
|
task {
|
||||||
match! this.TryJournalById requestId userId with
|
match! this.TryJournalById requestId userId with
|
||||||
| Some req ->
|
| Some req ->
|
||||||
@ -281,18 +281,3 @@ type AppDbContext (opts : DbContextOptions<AppDbContext>) =
|
|||||||
| None -> return None
|
| None -> return None
|
||||||
| None -> return None
|
| None -> return None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve a request, including its history, by its ID and user ID
|
|
||||||
member this.TryFullRequestById requestId userId =
|
|
||||||
task {
|
|
||||||
match! this.TryJournalById requestId userId with
|
|
||||||
| Some req ->
|
|
||||||
let! fullReq =
|
|
||||||
this.Requests.AsNoTracking()
|
|
||||||
.Include(fun r -> r.history)
|
|
||||||
.FirstOrDefaultAsync(fun r -> r.requestId = requestId && r.userId = userId)
|
|
||||||
match toOption fullReq with
|
|
||||||
| Some _ -> return Some { req with history = List.ofSeq fullReq.history }
|
|
||||||
| None -> return None
|
|
||||||
| None -> return None
|
|
||||||
}
|
|
||||||
|
@ -26,7 +26,7 @@ module Error =
|
|||||||
/// Handle 404s from the API, sending known URL paths to the Vue app so that they can be handled there
|
/// Handle 404s from the API, sending known URL paths to the Vue app so that they can be handled there
|
||||||
let notFound : HttpHandler =
|
let notFound : HttpHandler =
|
||||||
fun next ctx ->
|
fun next ctx ->
|
||||||
[ "/answered"; "/journal"; "/legal"; "/request"; "/snoozed"; "/user" ]
|
[ "/journal"; "/legal"; "/request"; "/user" ]
|
||||||
|> List.filter ctx.Request.Path.Value.StartsWith
|
|> List.filter ctx.Request.Path.Value.StartsWith
|
||||||
|> List.length
|
|> List.length
|
||||||
|> function
|
|> function
|
||||||
@ -236,16 +236,6 @@ module Request =
|
|||||||
| None -> return! Error.notFound next ctx
|
| None -> return! Error.notFound next ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
/// GET /api/request/[req-id]/complete
|
|
||||||
let getComplete reqId : HttpHandler =
|
|
||||||
authorize
|
|
||||||
>=> fun next ctx ->
|
|
||||||
task {
|
|
||||||
match! (db ctx).TryCompleteRequestById reqId (userId ctx) with
|
|
||||||
| Some req -> return! json req next ctx
|
|
||||||
| None -> return! Error.notFound next ctx
|
|
||||||
}
|
|
||||||
|
|
||||||
/// GET /api/request/[req-id]/full
|
/// GET /api/request/[req-id]/full
|
||||||
let getFull reqId : HttpHandler =
|
let getFull reqId : HttpHandler =
|
||||||
authorize
|
authorize
|
||||||
|
@ -59,7 +59,6 @@ module Configure =
|
|||||||
route "journal" Handlers.Journal.journal
|
route "journal" Handlers.Journal.journal
|
||||||
subRoute "request" [
|
subRoute "request" [
|
||||||
route "s/answered" Handlers.Request.answered
|
route "s/answered" Handlers.Request.answered
|
||||||
routef "/%s/complete" Handlers.Request.getComplete
|
|
||||||
routef "/%s/full" Handlers.Request.getFull
|
routef "/%s/full" Handlers.Request.getFull
|
||||||
routef "/%s/notes" Handlers.Request.getNotes
|
routef "/%s/notes" Handlers.Request.getNotes
|
||||||
routef "/%s" Handlers.Request.get
|
routef "/%s" Handlers.Request.get
|
||||||
|
@ -106,6 +106,12 @@ a:hover {
|
|||||||
.mpj-request-text {
|
.mpj-request-text {
|
||||||
white-space: pre-line;
|
white-space: pre-line;
|
||||||
}
|
}
|
||||||
|
.mpj-request-list p {
|
||||||
|
border-top: solid 1px lightgray;
|
||||||
|
}
|
||||||
|
.mpj-request-list p:first-child {
|
||||||
|
border-top: none;
|
||||||
|
}
|
||||||
.mpj-request-log {
|
.mpj-request-log {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
|
||||||
const http = axios.create({
|
const http = axios.create({
|
||||||
@ -39,7 +41,7 @@ export default {
|
|||||||
getAnsweredRequests: () => http.get('requests/answered'),
|
getAnsweredRequests: () => http.get('requests/answered'),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a prayer request (full; includes all history)
|
* Get a prayer request (full; includes all history and notes)
|
||||||
* @param {string} requestId The Id of the request to retrieve
|
* @param {string} requestId The Id of the request to retrieve
|
||||||
*/
|
*/
|
||||||
getFullRequest: requestId => http.get(`request/${requestId}/full`),
|
getFullRequest: requestId => http.get(`request/${requestId}/full`),
|
||||||
@ -56,11 +58,6 @@ export default {
|
|||||||
*/
|
*/
|
||||||
getRequest: requestId => http.get(`request/${requestId}`),
|
getRequest: requestId => http.get(`request/${requestId}`),
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a complete request; equivalent of "full" and "notes" combined
|
|
||||||
*/
|
|
||||||
getRequestComplete: requestId => http.get(`request/${requestId}/complete`),
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all prayer requests and their most recent updates
|
* Get all prayer requests and their most recent updates
|
||||||
*/
|
*/
|
||||||
|
@ -1,86 +0,0 @@
|
|||||||
<template lang="pug">
|
|
||||||
article.mpj-main-content(role='main')
|
|
||||||
page-title(title='Answered Request')
|
|
||||||
template(v-if='request')
|
|
||||||
p.
|
|
||||||
Answered {{ formatDate(answered) }} (#[date-from-now(:value='answered')])
|
|
||||||
#[small: em.mpj-muted-text prayed {{ prayedCount }} times, open {{ openDays }} days]
|
|
||||||
p.mpj-request-text {{ lastText }}
|
|
||||||
br
|
|
||||||
table.mpj-request-log
|
|
||||||
thead
|
|
||||||
tr
|
|
||||||
th Action
|
|
||||||
th Update / Notes
|
|
||||||
tbody
|
|
||||||
tr(v-for='item in log' :key='item.asOf')
|
|
||||||
td {{ item.status }} on #[span.mpj-text-nowrap {{ formatDate(item.asOf) }}]
|
|
||||||
td(v-if='item.text').mpj-request-text {{ item.text.fields[0] }}
|
|
||||||
td(v-else)
|
|
||||||
p(v-else) Loading request...
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
'use strict'
|
|
||||||
|
|
||||||
import moment from 'moment'
|
|
||||||
|
|
||||||
import api from '@/api'
|
|
||||||
|
|
||||||
const asOfDesc = (a, b) => b.asOf - a.asOf
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'answer-detail',
|
|
||||||
props: {
|
|
||||||
id: {
|
|
||||||
type: String,
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data () {
|
|
||||||
return {
|
|
||||||
request: null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
answered () {
|
|
||||||
return this.request.history.find(hist => hist.status === 'Answered').asOf
|
|
||||||
},
|
|
||||||
lastText () {
|
|
||||||
return this.request.history
|
|
||||||
.filter(hist => hist.text)
|
|
||||||
.sort(asOfDesc)[0].text.fields[0]
|
|
||||||
},
|
|
||||||
log () {
|
|
||||||
return (this.request.notes || [])
|
|
||||||
.map(note => ({ asOf: note.asOf, text: { case: 'Some', fields: [ note.notes ] }, status: 'Notes' }))
|
|
||||||
.concat(this.request.history)
|
|
||||||
.sort(asOfDesc)
|
|
||||||
.slice(1)
|
|
||||||
},
|
|
||||||
openDays () {
|
|
||||||
return Math.floor(
|
|
||||||
(this.answered - this.request.history.find(hist => hist.status === 'Created').asOf) / 1000 / 60 / 60 / 24)
|
|
||||||
},
|
|
||||||
prayedCount () {
|
|
||||||
return this.request.history.filter(hist => hist.status === 'Prayed').length
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async mounted () {
|
|
||||||
this.$Progress.start()
|
|
||||||
try {
|
|
||||||
const req = await api.getRequestComplete(this.id)
|
|
||||||
this.request = req.data
|
|
||||||
this.$Progress.finish()
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e)
|
|
||||||
this.$Progress.fail()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
formatDate (asOf) {
|
|
||||||
return moment(asOf).format('LL')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
@ -67,5 +67,6 @@ export default {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: row wrap;
|
flex-flow: row wrap;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
align-items: flex-start;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
@ -8,11 +8,14 @@ nav.mpj-top-nav.mpj-bg(role='menubar')
|
|||||||
router-link(v-if='isAuthenticated'
|
router-link(v-if='isAuthenticated'
|
||||||
:to="{ name: 'Journal' }"
|
:to="{ name: 'Journal' }"
|
||||||
role='menuitem') Journal
|
role='menuitem') Journal
|
||||||
|
router-link(v-if='isAuthenticated'
|
||||||
|
:to="{ name: 'ActiveRequests' }"
|
||||||
|
role='menuitem') Active
|
||||||
router-link(v-if='hasSnoozed'
|
router-link(v-if='hasSnoozed'
|
||||||
:to="{ name: 'Snoozed' }"
|
:to="{ name: 'SnoozedRequests' }"
|
||||||
role='menuitem') Snoozed
|
role='menuitem') Snoozed
|
||||||
router-link(v-if='isAuthenticated'
|
router-link(v-if='isAuthenticated'
|
||||||
:to="{ name: 'Answered' }"
|
:to="{ name: 'AnsweredRequests' }"
|
||||||
role='menuitem') Answered
|
role='menuitem') Answered
|
||||||
a(v-if='isAuthenticated'
|
a(v-if='isAuthenticated'
|
||||||
href='#'
|
href='#'
|
||||||
|
63
src/app/src/components/request/ActiveRequests.vue
Normal file
63
src/app/src/components/request/ActiveRequests.vue
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
<template lang="pug">
|
||||||
|
article.mpj-main-content(role='main')
|
||||||
|
page-title(title='Active Requests')
|
||||||
|
div(v-if='loaded').mpj-request-list
|
||||||
|
p.mpj-text-center(v-if='requests.length === 0'): em.
|
||||||
|
No active requests found; return to #[router-link(:to='{ name: "Journal" } ') your journal]
|
||||||
|
request-list-item(v-for='req in requests'
|
||||||
|
:key='req.requestId'
|
||||||
|
:request='req')
|
||||||
|
p(v-else) Loading journal...
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
import { mapState } from 'vuex'
|
||||||
|
|
||||||
|
import RequestListItem from '@/components/request/RequestListItem'
|
||||||
|
|
||||||
|
import actions from '@/store/action-types'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'active-requests',
|
||||||
|
components: {
|
||||||
|
RequestListItem
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
requests: [],
|
||||||
|
loaded: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
toast () {
|
||||||
|
return this.$parent.$refs.toast
|
||||||
|
},
|
||||||
|
...mapState(['journal', 'isLoadingJournal'])
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async ensureJournal () {
|
||||||
|
if (!Array.isArray(this.journal)) {
|
||||||
|
this.loaded = false
|
||||||
|
await this.$store.dispatch(actions.LOAD_JOURNAL, this.$Progress)
|
||||||
|
}
|
||||||
|
this.requests = this.journal
|
||||||
|
.sort((a, b) => a.showAfter - b.showAfter)
|
||||||
|
this.loaded = true
|
||||||
|
},
|
||||||
|
async cancelSnooze (requestId) {
|
||||||
|
await this.$store.dispatch(actions.SNOOZE_REQUEST, {
|
||||||
|
progress: this.$Progress,
|
||||||
|
requestId: requestId,
|
||||||
|
until: 0
|
||||||
|
})
|
||||||
|
this.toast.showToast('Request un-snoozed', { theme: 'success' })
|
||||||
|
this.ensureJournal()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async mounted () {
|
||||||
|
await this.ensureJournal()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -1,30 +1,27 @@
|
|||||||
<template lang="pug">
|
<template lang="pug">
|
||||||
article.mpj-main-content(role='main')
|
article.mpj-main-content(role='main')
|
||||||
page-title(title='Answered Requests')
|
page-title(title='Answered Requests')
|
||||||
div(v-if='loaded').mpj-answered-list
|
div(v-if='loaded').mpj-request-list
|
||||||
p.text-center(v-if='requests.length === 0'): em.
|
p.text-center(v-if='requests.length === 0'): em.
|
||||||
No answered requests found; once you have marked one as “Answered”, it will appear here
|
No answered requests found; once you have marked one as “Answered”, it will appear here
|
||||||
p.mpj-request-text(v-for='req in requests' :key='req.requestId')
|
request-list-item(v-for='req in requests'
|
||||||
| {{ req.text }}
|
:key='req.requestId'
|
||||||
br
|
:request='req')
|
||||||
br
|
|
||||||
router-link(:to='{ name: "AnsweredDetail", params: { id: req.requestId }}'
|
|
||||||
role='button'
|
|
||||||
title='View Full Request')
|
|
||||||
md-icon(icon='description')
|
|
||||||
= ' View Full Request'
|
|
||||||
small.mpj-muted-text: em.
|
|
||||||
Answered #[date-from-now(:value='req.asOf')]
|
|
||||||
p(v-else) Loading answered requests...
|
p(v-else) Loading answered requests...
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
'use static'
|
'use strict'
|
||||||
|
|
||||||
import api from '@/api'
|
import api from '@/api'
|
||||||
|
|
||||||
|
import RequestListItem from '@/components/request/RequestListItem'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'answered',
|
name: 'answered-requests',
|
||||||
|
components: {
|
||||||
|
RequestListItem
|
||||||
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
requests: [],
|
requests: [],
|
||||||
@ -52,12 +49,3 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
|
||||||
.mpj-answered-list p {
|
|
||||||
border-top: solid 1px lightgray;
|
|
||||||
}
|
|
||||||
.mpj-answered-list p:first-child {
|
|
||||||
border-top: none;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,56 +1,89 @@
|
|||||||
<template lang="pug">
|
<template lang="pug">
|
||||||
span
|
article.mpj-main-content(role='main')
|
||||||
b-modal(v-model='historyVisible'
|
page-title(title='Full Prayer Request')
|
||||||
header-bg-variant='mpj'
|
template(v-if='request')
|
||||||
header-text-variant='light'
|
p
|
||||||
size='lg'
|
span(v-if='isAnswered') Answered {{ formatDate(answered) }} (#[date-from-now(:value='answered')])
|
||||||
title='Prayer Request History'
|
small: em.mpj-muted-text prayed {{ prayedCount }} times, open {{ openDays }} days
|
||||||
@shows='focusRequestText')
|
p.mpj-request-text {{ lastText }}
|
||||||
b-list-group(v-if='null !== full'
|
br
|
||||||
flush)
|
table.mpj-request-log
|
||||||
full-request-history(v-for='item in full.history'
|
thead
|
||||||
:key='item.asOf'
|
tr
|
||||||
:history='item')
|
th Action
|
||||||
div.w-100.text-right(slot='modal-footer')
|
th Update / Notes
|
||||||
b-btn(variant='primary'
|
tbody
|
||||||
@click='closeDialog()') Close
|
tr(v-for='item in log' :key='item.asOf')
|
||||||
|
td {{ item.status }} on #[span.mpj-text-nowrap {{ formatDate(item.asOf) }}]
|
||||||
|
td(v-if='item.text').mpj-request-text {{ item.text.fields[0] }}
|
||||||
|
td(v-else)
|
||||||
|
p(v-else) Loading request...
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
import FullRequestHistory from './FullRequestHistory'
|
import moment from 'moment'
|
||||||
|
|
||||||
import api from '@/api'
|
import api from '@/api'
|
||||||
|
|
||||||
|
const asOfDesc = (a, b) => b.asOf - a.asOf
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'full-request',
|
name: 'full-request',
|
||||||
components: {
|
|
||||||
FullRequestHistory
|
|
||||||
},
|
|
||||||
props: {
|
props: {
|
||||||
events: { required: true }
|
id: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
historyVisible: false,
|
request: null
|
||||||
full: null
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created () {
|
computed: {
|
||||||
this.events.$on('full', this.openDialog)
|
answered () {
|
||||||
|
return this.request.history.find(hist => hist.status === 'Answered').asOf
|
||||||
|
},
|
||||||
|
isAnswered () {
|
||||||
|
return this.request.history.filter(hist => hist.status === 'Answered').length > 0
|
||||||
|
},
|
||||||
|
lastText () {
|
||||||
|
return this.request.history
|
||||||
|
.filter(hist => hist.text)
|
||||||
|
.sort(asOfDesc)[0].text.fields[0]
|
||||||
|
},
|
||||||
|
log () {
|
||||||
|
return (this.request.notes || [])
|
||||||
|
.map(note => ({ asOf: note.asOf, text: { case: 'Some', fields: [ note.notes ] }, status: 'Notes' }))
|
||||||
|
.concat(this.request.history)
|
||||||
|
.sort(asOfDesc)
|
||||||
|
.slice(1)
|
||||||
|
},
|
||||||
|
openDays () {
|
||||||
|
const asOf = this.isAnswered ? this.answered : Date.now()
|
||||||
|
return Math.floor(
|
||||||
|
(asOf - this.request.history.find(hist => hist.status === 'Created').asOf) / 1000 / 60 / 60 / 24)
|
||||||
|
},
|
||||||
|
prayedCount () {
|
||||||
|
return this.request.history.filter(hist => hist.status === 'Prayed').length
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async mounted () {
|
||||||
|
this.$Progress.start()
|
||||||
|
try {
|
||||||
|
const req = await api.getFullRequest(this.id)
|
||||||
|
this.request = req.data
|
||||||
|
this.$Progress.finish()
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
this.$Progress.fail()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
closeDialog () {
|
formatDate (asOf) {
|
||||||
this.full = null
|
return moment(asOf).format('LL')
|
||||||
this.historyVisible = false
|
|
||||||
},
|
|
||||||
async openDialog (requestId) {
|
|
||||||
this.historyVisible = true
|
|
||||||
this.$Progress.start()
|
|
||||||
const req = await api.getFullRequest(requestId)
|
|
||||||
this.full = req.data
|
|
||||||
this.$Progress.finish()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
<template lang="pug">
|
|
||||||
b-list-group-item
|
|
||||||
| {{ history.status }}
|
|
||||||
|
|
|
||||||
small.text-muted(:title='actualDate') {{ asOf }}
|
|
||||||
div(v-if='history.text').mpj-request-text {{ history.text.fields[0] }}
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
'use strict'
|
|
||||||
|
|
||||||
import moment from 'moment'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'full-request-history',
|
|
||||||
props: {
|
|
||||||
history: { required: true }
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
asOf () {
|
|
||||||
return moment(this.history.asOf).fromNow()
|
|
||||||
},
|
|
||||||
actualDate () {
|
|
||||||
return moment(this.history.asOf).format('LLLL')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
65
src/app/src/components/request/RequestListItem.vue
Normal file
65
src/app/src/components/request/RequestListItem.vue
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
<template lang="pug">
|
||||||
|
p.mpj-request-text
|
||||||
|
| {{ request.text }}
|
||||||
|
br
|
||||||
|
br
|
||||||
|
router-link(:to="{ name: 'FullRequest', params: { id: request.requestId } }"
|
||||||
|
role='button'
|
||||||
|
title='View Full Request')
|
||||||
|
md-icon(icon='description')
|
||||||
|
= ' View Full Request'
|
||||||
|
|
|
||||||
|
router-link(v-if='!isAnswered'
|
||||||
|
:to="{ name: 'EditRequest', params: { id: request.requestId } }"
|
||||||
|
role='button'
|
||||||
|
title='Edit Request')
|
||||||
|
md-icon(icon='edit')
|
||||||
|
= ' Edit Request'
|
||||||
|
|
|
||||||
|
button(v-if='isSnoozed' @click='cancelSnooze()')
|
||||||
|
md-icon(icon='restore')
|
||||||
|
= ' Cancel Snooze'
|
||||||
|
br(v-if='isSnoozed || isAnswered')
|
||||||
|
small(v-if='isSnoozed').mpj-muted-text: em.
|
||||||
|
Snooze expires #[date-from-now(:value='request.snoozedUntil')]
|
||||||
|
small(v-if='isAnswered').mpj-muted-text: em.
|
||||||
|
Answered #[date-from-now(:value='request.asOf')]
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
import actions from '@/store/action-types'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'request-list-item',
|
||||||
|
props: {
|
||||||
|
request: { required: true }
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
answered () {
|
||||||
|
return this.request.history.find(hist => hist.status === 'Answered').asOf
|
||||||
|
},
|
||||||
|
isAnswered () {
|
||||||
|
return this.request.lastStatus === 'Answered'
|
||||||
|
},
|
||||||
|
isSnoozed () {
|
||||||
|
return this.request.snoozedUntil > Date.now()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async cancelSnooze () {
|
||||||
|
await this.$store.dispatch(actions.SNOOZE_REQUEST, {
|
||||||
|
progress: this.$Progress,
|
||||||
|
requestId: this.request.requestId,
|
||||||
|
until: 0
|
||||||
|
})
|
||||||
|
this.toast.showToast('Request un-snoozed', { theme: 'success' })
|
||||||
|
// FIXME: communicate with the parent to refresh // this.ensureJournal()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -1,30 +1,29 @@
|
|||||||
<template lang="pug">
|
<template lang="pug">
|
||||||
article.mpj-main-content(role='main')
|
article.mpj-main-content(role='main')
|
||||||
page-title(title='Snoozed Requests')
|
page-title(title='Snoozed Requests')
|
||||||
div(v-if='loaded').mpj-snoozed-list
|
div(v-if='loaded').mpj-request-list
|
||||||
p.mpj-text-center(v-if='requests.length === 0'): em.
|
p.mpj-text-center(v-if='requests.length === 0'): em.
|
||||||
No snoozed requests found; return to #[router-link(:to='{ name: "Journal" } ') your journal]
|
No snoozed requests found; return to #[router-link(:to='{ name: "Journal" } ') your journal]
|
||||||
p.mpj-request-text(v-for='req in requests' :key='req.requestId')
|
request-list-item(v-for='req in requests'
|
||||||
| {{ req.text }}
|
:key='req.requestId'
|
||||||
br
|
:request='req')
|
||||||
br
|
|
||||||
button(@click='cancelSnooze(req.requestId)')
|
|
||||||
md-icon(icon='restore')
|
|
||||||
= ' Cancel Snooze'
|
|
||||||
small.mpj-muted-text: em.
|
|
||||||
Snooze expires #[date-from-now(:value='req.snoozedUntil')]
|
|
||||||
p(v-else) Loading journal...
|
p(v-else) Loading journal...
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
'use static'
|
'use strict'
|
||||||
|
|
||||||
import { mapState } from 'vuex'
|
import { mapState } from 'vuex'
|
||||||
|
|
||||||
import actions from '@/store/action-types'
|
import actions from '@/store/action-types'
|
||||||
|
|
||||||
|
import RequestListItem from '@/components/request/RequestListItem'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'answered',
|
name: 'snoozed-requests',
|
||||||
|
components: {
|
||||||
|
RequestListItem
|
||||||
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
requests: [],
|
requests: [],
|
||||||
@ -63,12 +62,3 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
|
||||||
.mpj-snoozed-list p {
|
|
||||||
border-top: solid 1px lightgray;
|
|
||||||
}
|
|
||||||
.mpj-snoozed-list p:first-child {
|
|
||||||
border-top: none;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,14 +1,17 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import Router from 'vue-router'
|
import Router from 'vue-router'
|
||||||
|
|
||||||
import Answered from '@/components/Answered'
|
import ActiveRequests from '@/components/request/ActiveRequests'
|
||||||
import AnsweredDetail from '@/components/AnsweredDetail'
|
import AnsweredRequests from '@/components/request/AnsweredRequests'
|
||||||
import EditRequest from '@/components/request/EditRequest'
|
import EditRequest from '@/components/request/EditRequest'
|
||||||
|
import FullRequest from '@/components/request/FullRequest'
|
||||||
import Home from '@/components/Home'
|
import Home from '@/components/Home'
|
||||||
import Journal from '@/components/Journal'
|
import Journal from '@/components/Journal'
|
||||||
import LogOn from '@/components/user/LogOn'
|
import LogOn from '@/components/user/LogOn'
|
||||||
import PrivacyPolicy from '@/components/legal/PrivacyPolicy'
|
import PrivacyPolicy from '@/components/legal/PrivacyPolicy'
|
||||||
import Snoozed from '@/components/Snoozed'
|
import SnoozedRequests from '@/components/request/SnoozedRequests'
|
||||||
import TermsOfService from '@/components/legal/TermsOfService'
|
import TermsOfService from '@/components/legal/TermsOfService'
|
||||||
|
|
||||||
Vue.use(Router)
|
Vue.use(Router)
|
||||||
@ -21,17 +24,6 @@ export default new Router({
|
|||||||
name: 'Home',
|
name: 'Home',
|
||||||
component: Home
|
component: Home
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: '/answered/:id',
|
|
||||||
name: 'AnsweredDetail',
|
|
||||||
component: AnsweredDetail,
|
|
||||||
props: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/answered',
|
|
||||||
name: 'Answered',
|
|
||||||
component: Answered
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: '/journal',
|
path: '/journal',
|
||||||
name: 'Journal',
|
name: 'Journal',
|
||||||
@ -54,9 +46,25 @@ export default new Router({
|
|||||||
props: true
|
props: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/snoozed',
|
path: '/request/:id/full',
|
||||||
name: 'Snoozed',
|
name: 'FullRequest',
|
||||||
component: Snoozed
|
component: FullRequest,
|
||||||
|
props: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/requests/active',
|
||||||
|
name: 'ActiveRequests',
|
||||||
|
component: ActiveRequests
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/requests/answered',
|
||||||
|
name: 'AnsweredRequests',
|
||||||
|
component: AnsweredRequests
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/requests/snoozed',
|
||||||
|
name: 'SnoozedRequests',
|
||||||
|
component: SnoozedRequests
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/user/log-on',
|
path: '/user/log-on',
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import Vuex from 'vuex'
|
import Vuex from 'vuex'
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user