parent
321ba83ab0
commit
9d44c90de6
|
@ -1 +0,0 @@
|
|||
[{"tagName":"script","closeTag":true,"attributes":{"type":"text/javascript","src":"/js/chunk-vendors-legacy.12c801f9.js"}},{"tagName":"script","closeTag":true,"attributes":{"type":"text/javascript","src":"/js/app-legacy.3c452240.js"}}]
|
|
@ -112,9 +112,7 @@ const ProgressSymbol = Symbol('Progress events')
|
|||
|
||||
export default createComponent({
|
||||
name: 'app',
|
||||
components: {
|
||||
Navigation
|
||||
},
|
||||
components: { Navigation },
|
||||
setup () {
|
||||
const pkg = require('../package.json')
|
||||
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
<script lang="ts">
|
||||
import { computed, createElement, onBeforeUnmount, onMounted, ref } from '@vue/composition-api'
|
||||
import { computed, createComponent, createElement, onBeforeUnmount, onMounted, ref } from '@vue/composition-api'
|
||||
import moment from 'moment'
|
||||
|
||||
export default {
|
||||
name: 'date-from-now',
|
||||
export default createComponent({
|
||||
props: {
|
||||
tag: {
|
||||
type: String,
|
||||
|
@ -18,7 +17,7 @@ export default {
|
|||
default: 10000
|
||||
}
|
||||
},
|
||||
setup (props: any) {
|
||||
setup (props) {
|
||||
/** Interval ID for updating relative time */
|
||||
let intervalId: number = 0
|
||||
|
||||
|
@ -47,5 +46,5 @@ export default {
|
|||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed } from '@vue/composition-api'
|
||||
import { computed, createComponent } from '@vue/composition-api'
|
||||
import { Store } from 'vuex' // eslint-disable-line no-unused-vars
|
||||
|
||||
import { AppState } from '../../store/types' // eslint-disable-line no-unused-vars
|
||||
|
@ -36,7 +36,7 @@ import { useAuth } from '../../plugins/auth'
|
|||
import { useRouter } from '../../plugins/router'
|
||||
import { useStore } from '../../plugins/store'
|
||||
|
||||
export default {
|
||||
export default createComponent({
|
||||
setup () {
|
||||
/** The Vuex store */
|
||||
const store = useStore() as Store<AppState>
|
||||
|
@ -72,5 +72,5 @@ export default {
|
|||
showHelp
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -4,9 +4,9 @@ h1(v-if='!hideOnPage'
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { watch } from '@vue/composition-api'
|
||||
import { createComponent, watch, ref } from '@vue/composition-api'
|
||||
|
||||
export default {
|
||||
export default createComponent({
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
|
@ -17,11 +17,11 @@ export default {
|
|||
default: false
|
||||
}
|
||||
},
|
||||
setup (props: any) {
|
||||
watch(props.title, (title, prevTitle) => {
|
||||
setup (props) {
|
||||
watch(ref(props.title), (title: string, prevTitle: string) => {
|
||||
document.title = `${props.title.replace('’', "'")} « myPrayerJournal`
|
||||
})
|
||||
return { }
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -14,7 +14,7 @@ md-content(role='main').mpj-main-content
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { ref, onMounted } from '@vue/composition-api'
|
||||
import { createComponent, onMounted, ref } from '@vue/composition-api'
|
||||
|
||||
import RequestList from './RequestList.vue'
|
||||
|
||||
|
@ -22,7 +22,7 @@ import api from '../../api'
|
|||
import { JournalRequest } from '../../store/types' // eslint-disable-line no-unused-vars
|
||||
import { useProgress, useSnackbar } from '../../App.vue'
|
||||
|
||||
export default {
|
||||
export default createComponent({
|
||||
components: {
|
||||
RequestList
|
||||
},
|
||||
|
@ -59,5 +59,5 @@ export default {
|
|||
isLoaded
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template lang="pug">
|
||||
md-content(role='main').mpj-narrow
|
||||
page-title(:title='title')
|
||||
page-title(:title='title.value')
|
||||
md-field
|
||||
label(for='request_text') Prayer Request
|
||||
md-textarea(v-model='form.requestText'
|
||||
|
@ -8,7 +8,7 @@ md-content(role='main').mpj-narrow
|
|||
md-autogrow
|
||||
autofocus).mpj-full-width
|
||||
br
|
||||
template(v-if='!isNew')
|
||||
template(v-if='!isNew.value')
|
||||
label Also Mark As
|
||||
br
|
||||
md-radio(v-model='form.status'
|
||||
|
@ -34,141 +34,191 @@ md-content(role='main').mpj-narrow
|
|||
label Count
|
||||
md-input(v-model='form.recur.count'
|
||||
type='number'
|
||||
:disabled='!showRecurrence')
|
||||
:disabled='!showRecurrence.value')
|
||||
.md-layout-item.md-size-20
|
||||
md-field
|
||||
label Interval
|
||||
md-select(v-model='form.recur.other'
|
||||
:disabled='!showRecurrence')
|
||||
:disabled='!showRecurrence.value')
|
||||
md-option(value='Hours') hours
|
||||
md-option(value='Days') days
|
||||
md-option(value='Weeks') weeks
|
||||
.mpj-text-right
|
||||
md-button(:disabled='!isValidRecurrence'
|
||||
md-button(:disabled='!isValidRecurrence.value'
|
||||
@click.stop='saveRequest()').md-primary.md-raised #[md-icon save] Save
|
||||
md-button(@click.stop='goBack()').md-raised #[md-icon arrow_back] Cancel
|
||||
</template>
|
||||
|
||||
<script>
|
||||
'use strict'
|
||||
<script lang="ts">
|
||||
import { createComponent, ref, computed, onMounted } from '@vue/composition-api'
|
||||
import { Store } from 'vuex' // eslint-disable-line no-unused-vars
|
||||
|
||||
import { mapState } from 'vuex'
|
||||
import { Actions, AppState, AddRequestAction, UpdateRequestAction } from '../../store/types' // eslint-disable-line no-unused-vars
|
||||
import { useProgress, useSnackbar } from '../../App.vue'
|
||||
import { useStore } from '../../plugins/store'
|
||||
import { useRouter } from '../../plugins/router'
|
||||
|
||||
import { Actions } from '@/store/types'
|
||||
/** The recurrence settings for the request */
|
||||
class RecurrenceForm {
|
||||
/** The type of recurrence */
|
||||
typ = 'Immediate'
|
||||
|
||||
export default {
|
||||
name: 'edit-request',
|
||||
inject: [
|
||||
'messages',
|
||||
'progress'
|
||||
],
|
||||
/** The type of recurrence (other than immediate) */
|
||||
other = ''
|
||||
|
||||
/** The count of non-immediate intervals */
|
||||
count = ''
|
||||
|
||||
/**
|
||||
* The recurrence represented by the given form
|
||||
* @param x The recurrence form
|
||||
*/
|
||||
static recurrence = (x: RecurrenceForm) => x.typ === 'Immediate' ? 'Immediate' : x.other
|
||||
|
||||
/**
|
||||
* The interval represented by the given form
|
||||
* @param x The recurrence form
|
||||
*/
|
||||
static interval = (x: RecurrenceForm) => x.typ === 'Immediate' ? 0 : Number.parseInt(x.count)
|
||||
}
|
||||
|
||||
/** The form for editing the request */
|
||||
class EditForm {
|
||||
/** The ID of the request */
|
||||
requestId = ''
|
||||
|
||||
/** The text of the request */
|
||||
requestText = ''
|
||||
|
||||
/** The status associated with this update */
|
||||
status = 'Updated'
|
||||
|
||||
/** The recurrence for the request */
|
||||
recur = new RecurrenceForm()
|
||||
}
|
||||
|
||||
export default createComponent({
|
||||
props: {
|
||||
id: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
title: 'Edit Prayer Request',
|
||||
isNew: false,
|
||||
form: {
|
||||
requestId: '',
|
||||
requestText: '',
|
||||
status: 'Updated',
|
||||
recur: {
|
||||
typ: 'Immediate',
|
||||
other: '',
|
||||
count: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isValidRecurrence () {
|
||||
if (this.form.recur.typ === 'Immediate') return true
|
||||
const count = Number.parseInt(this.form.recur.count)
|
||||
if (isNaN(count) || this.form.recur.other === '') return false
|
||||
if (this.form.recur.other === 'Hours' && count > (365 * 24)) return false
|
||||
if (this.form.recur.other === 'Days' && count > 365) return false
|
||||
if (this.form.recur.other === 'Weeks' && count > 52) return false
|
||||
setup (props) {
|
||||
/** The Vuex store */
|
||||
const store = useStore() as Store<AppState>
|
||||
|
||||
/** The snackbar component properties */
|
||||
const snackbar = useSnackbar()
|
||||
|
||||
/** The progress bar component properties */
|
||||
const progress = useProgress()
|
||||
|
||||
/** The application router */
|
||||
const router = useRouter()
|
||||
|
||||
/** The page title */
|
||||
const title = ref('Edit Prayer Request')
|
||||
|
||||
/** Whether this is a new request */
|
||||
const isNew = ref(false)
|
||||
|
||||
/** The input form */
|
||||
const form = new EditForm()
|
||||
|
||||
/** Is the selected recurrence a valid recurrence? */
|
||||
const isValidRecurrence = computed(() => {
|
||||
if (form.recur.typ === 'Immediate') return true
|
||||
const count = Number.parseInt(form.recur.count)
|
||||
if (isNaN(count) || form.recur.other === '') return false
|
||||
if (form.recur.other === 'Hours' && count > (365 * 24)) return false
|
||||
if (form.recur.other === 'Days' && count > 365) return false
|
||||
if (form.recur.other === 'Weeks' && count > 52) return false
|
||||
return true
|
||||
},
|
||||
showRecurrence () {
|
||||
return this.form.recur.typ !== 'Immediate'
|
||||
},
|
||||
...mapState(['journal'])
|
||||
},
|
||||
async mounted () {
|
||||
await this.ensureJournal()
|
||||
if (this.id === 'new') {
|
||||
this.title = 'Add Prayer Request'
|
||||
this.isNew = true
|
||||
this.form.requestId = ''
|
||||
this.form.requestText = ''
|
||||
this.form.status = 'Created'
|
||||
this.form.recur.typ = 'Immediate'
|
||||
this.form.recur.other = ''
|
||||
this.form.recur.count = ''
|
||||
} else {
|
||||
this.title = 'Edit Prayer Request'
|
||||
this.isNew = false
|
||||
if (this.journal.length === 0) {
|
||||
await this.$store.dispatch(Actions.LoadJournal, this.progress)
|
||||
}
|
||||
const req = this.journal.filter(r => r.requestId === this.id)[0]
|
||||
this.form.requestId = this.id
|
||||
this.form.requestText = req.text
|
||||
this.form.status = 'Updated'
|
||||
if (req.recurType === 'Immediate') {
|
||||
this.form.recur.typ = 'Immediate'
|
||||
this.form.recur.other = ''
|
||||
this.form.recur.count = ''
|
||||
})
|
||||
|
||||
/** Whether the recurrence should be shown */
|
||||
const showRecurrence = computed(() => form.recur.typ !== 'Immediate')
|
||||
|
||||
/** Go back 1 in browser history */
|
||||
const goBack = () => { router.go(-1) }
|
||||
|
||||
/** Trim the request text */
|
||||
const trimText = () => { form.requestText = form.requestText.trim() }
|
||||
|
||||
/** Save the edited request */
|
||||
const saveRequest = async () => {
|
||||
if (isNew.value) {
|
||||
const opts: AddRequestAction = {
|
||||
progress,
|
||||
requestText: form.requestText,
|
||||
recurType: RecurrenceForm.recurrence(form.recur),
|
||||
recurCount: RecurrenceForm.interval(form.recur)
|
||||
}
|
||||
await store.dispatch(Actions.AddRequest, opts)
|
||||
snackbar.events.$emit('info', 'New prayer request added')
|
||||
} else {
|
||||
this.form.recur.typ = 'other'
|
||||
this.form.recur.other = req.recurType
|
||||
this.form.recur.count = req.recurCount
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
goBack () {
|
||||
this.$router.go(-1)
|
||||
},
|
||||
trimText () {
|
||||
this.form.requestText = this.form.requestText.trim()
|
||||
},
|
||||
async ensureJournal () {
|
||||
if (!Array.isArray(this.journal)) {
|
||||
await this.$store.dispatch(Actions.LoadJournal, this.progress)
|
||||
}
|
||||
},
|
||||
async saveRequest () {
|
||||
if (this.isNew) {
|
||||
await this.$store.dispatch(Actions.AddRequest, {
|
||||
progress: this.progress,
|
||||
requestText: this.form.requestText,
|
||||
recurType: this.form.recur.typ === 'Immediate' ? 'Immediate' : this.form.recur.other,
|
||||
recurCount: this.form.recur.typ === 'Immediate' ? 0 : Number.parseInt(this.form.recur.count)
|
||||
})
|
||||
this.messages.$emit('info', 'New prayer request added')
|
||||
} else {
|
||||
await this.$store.dispatch(Actions.UpdateRequest, {
|
||||
progress: this.progress,
|
||||
requestId: this.form.requestId,
|
||||
updateText: this.form.requestText,
|
||||
status: this.form.status,
|
||||
recurType: this.form.recur.typ === 'Immediate' ? 'Immediate' : this.form.recur.other,
|
||||
recurCount: this.form.recur.typ === 'Immediate' ? 0 : Number.parseInt(this.form.recur.count)
|
||||
})
|
||||
if (this.form.status === 'Answered') {
|
||||
this.messages.$emit('info', 'Request updated and removed from active journal')
|
||||
const opts: UpdateRequestAction = {
|
||||
progress,
|
||||
requestId: form.requestId,
|
||||
updateText: form.requestText,
|
||||
status: form.status,
|
||||
recurType: RecurrenceForm.recurrence(form.recur),
|
||||
recurCount: RecurrenceForm.interval(form.recur)
|
||||
}
|
||||
await store.dispatch(Actions.UpdateRequest, opts)
|
||||
if (form.status === 'Answered') {
|
||||
snackbar.events.$emit('info', 'Request updated and removed from active journal')
|
||||
} else {
|
||||
this.messages.$emit('info', 'Request updated')
|
||||
snackbar.events.$emit('info', 'Request updated')
|
||||
}
|
||||
}
|
||||
this.goBack()
|
||||
goBack()
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
if (!Array.isArray(store.state.journal)) {
|
||||
await store.dispatch(Actions.LoadJournal, progress)
|
||||
}
|
||||
if (props.id === 'new') {
|
||||
title.value = 'Add Prayer Request'
|
||||
isNew.value = true
|
||||
form.requestId = ''
|
||||
form.requestText = ''
|
||||
form.status = 'Created'
|
||||
form.recur.typ = 'Immediate'
|
||||
form.recur.other = ''
|
||||
form.recur.count = ''
|
||||
} else {
|
||||
title.value = 'Edit Prayer Request'
|
||||
isNew.value = false
|
||||
const req = store.state.journal.filter(r => r.requestId === props.id)[0]
|
||||
form.requestId = props.id
|
||||
form.requestText = req.text
|
||||
form.status = 'Updated'
|
||||
if (req.recurType === 'Immediate') {
|
||||
form.recur.typ = 'Immediate'
|
||||
form.recur.other = ''
|
||||
form.recur.count = ''
|
||||
} else {
|
||||
form.recur.typ = 'other'
|
||||
form.recur.other = req.recurType
|
||||
form.recur.count = req.recurCount.toString()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
form,
|
||||
goBack,
|
||||
isNew,
|
||||
isValidRecurrence,
|
||||
journal: store.state.journal,
|
||||
saveRequest,
|
||||
showRecurrence,
|
||||
title,
|
||||
trimText
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -23,7 +23,7 @@ md-content(role='main').mpj-main-content
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { createComponent, onMounted, computed } from '@vue/composition-api'
|
||||
import { computed, createComponent, onMounted } from '@vue/composition-api'
|
||||
import moment from 'moment'
|
||||
|
||||
import api from '../../api'
|
||||
|
@ -45,13 +45,16 @@ export default createComponent({
|
|||
const progress = useProgress()
|
||||
|
||||
/** The request being displayed */
|
||||
let request: JournalRequest = undefined
|
||||
let request = new JournalRequest()
|
||||
|
||||
/** The history entry where the request was marked as answered */
|
||||
const answer = computed(() => request.history.find(hist => hist.status === 'Answered'))
|
||||
|
||||
/** Whether this request is answered */
|
||||
const isAnswered = computed(() => request.history.find(hist => hist.status === 'Answered'))
|
||||
const isAnswered = computed(() => answer.value !== undefined)
|
||||
|
||||
/** The date/time this request was answered */
|
||||
const answered = computed(() => request.history.find(hist => hist.status === 'Answered').asOf)
|
||||
const answered = computed(() => answer.value ? answer.value.asOf : undefined)
|
||||
|
||||
/** The last recorded text for the request */
|
||||
const lastText = computed(() => request.history.filter(hist => hist.text).sort(asOfDesc)[0].text)
|
||||
|
@ -68,8 +71,9 @@ export default createComponent({
|
|||
|
||||
/** The number of days this request [was|has been] open */
|
||||
const openDays = computed(() => {
|
||||
const asOf = isAnswered.value ? answered.value : Date.now()
|
||||
return Math.floor((asOf - request.history.find(hist => hist.status === 'Created').asOf) / 1000 / 60 / 60 / 24)
|
||||
const asOf = answered.value ? answered.value : Date.now()
|
||||
return Math.floor(
|
||||
(asOf - request.history.filter(hist => hist.status === 'Created')[0].asOf) / 1000 / 60 / 60 / 24)
|
||||
})
|
||||
|
||||
/** How many times this request has been prayed for */
|
||||
|
@ -82,7 +86,7 @@ export default createComponent({
|
|||
progress.events.$emit('show', 'indeterminate')
|
||||
try {
|
||||
const req = await api.getFullRequest(props.id)
|
||||
request = req.data
|
||||
request = req.data as JournalRequest
|
||||
} catch (e) {
|
||||
console.log(e) // eslint-disable-line no-console
|
||||
} finally {
|
||||
|
|
|
@ -11,7 +11,7 @@ md-dialog(:md-active.sync='notesVisible').mpj-note-dialog
|
|||
md-button(@click='saveNotes()').md-primary #[md-icon save] Save
|
||||
md-button(@click='closeDialog()') #[md-icon undo] Cancel
|
||||
md-dialog-content(md-scrollbar='true').mpj-dialog-content
|
||||
div(v-if='hasPriorNotes')
|
||||
div(v-if='hasPriorNotes.value')
|
||||
p.mpj-text-center: strong Prior Notes for This Request
|
||||
.mpj-note-list
|
||||
p(v-for='note in priorNotes'
|
||||
|
@ -19,88 +19,125 @@ md-dialog(:md-active.sync='notesVisible').mpj-note-dialog
|
|||
small.mpj-muted-text: date-from-now(:value='note.asOf')
|
||||
br
|
||||
span.mpj-request-text {{ note.notes }}
|
||||
div(v-else-if='noPriorNotes').mpj-text-center.mpj-muted-text There are no prior notes for this request
|
||||
div(v-else-if='noPriorNotes.value').mpj-text-center.mpj-muted-text There are no prior notes for this request
|
||||
div(v-else).mpj-text-center
|
||||
hr
|
||||
md-button(@click='loadNotes()') #[md-icon cloud_download] Load Prior Notes
|
||||
</template>
|
||||
|
||||
<script>
|
||||
'use strict'
|
||||
<script lang="ts">
|
||||
import { computed, createComponent, ref } from '@vue/composition-api'
|
||||
|
||||
import api from '@/api'
|
||||
import api from '../../api'
|
||||
|
||||
export default {
|
||||
name: 'notes-edit',
|
||||
inject: [
|
||||
'journalEvents',
|
||||
'messages',
|
||||
'progress'
|
||||
],
|
||||
data () {
|
||||
return {
|
||||
notesVisible: false,
|
||||
form: {
|
||||
requestId: '',
|
||||
notes: ''
|
||||
},
|
||||
priorNotes: [],
|
||||
priorNotesLoaded: false
|
||||
import { useEvents } from '../Journal.vue'
|
||||
import { NotesEntry, JournalRequest } from '../../store/types' // eslint-disable-line no-unused-vars
|
||||
import { useProgress, useSnackbar } from '../../App.vue'
|
||||
|
||||
/** The input form for the notes dialog */
|
||||
class NotesForm {
|
||||
/** The ID of the request */
|
||||
requestId = ''
|
||||
/** The actual notes */
|
||||
notes = ''
|
||||
}
|
||||
|
||||
/** The prior notes for this request */
|
||||
class PriorNotes {
|
||||
/** The prior notes */
|
||||
notes: NotesEntry[] = []
|
||||
/** Have the prior notes been loaded? */
|
||||
isLoaded = false
|
||||
}
|
||||
|
||||
export default createComponent({
|
||||
setup () {
|
||||
/** The event bus for the journal page */
|
||||
const events = useEvents()
|
||||
|
||||
/** The snackbar component properties */
|
||||
const snackbar = useSnackbar()
|
||||
|
||||
/** The progress bar component properties */
|
||||
const progress = useProgress()
|
||||
|
||||
/** Is this dialog visible? */
|
||||
const notesVisible = ref(false)
|
||||
|
||||
/** The input form */
|
||||
const form = new NotesForm()
|
||||
|
||||
/** The prior notes */
|
||||
const prior = new PriorNotes()
|
||||
|
||||
/** Are there prior notes? */
|
||||
const hasPriorNotes = computed(() => prior.isLoaded && prior.notes.length > 0)
|
||||
|
||||
/** Are there no prior notes? */
|
||||
const noPriorNotes = computed(() => prior.isLoaded && prior.notes.length === 0)
|
||||
|
||||
/** Close this dialog */
|
||||
const closeDialog = () => {
|
||||
form.requestId = ''
|
||||
form.notes = ''
|
||||
prior.notes = []
|
||||
prior.isLoaded = false
|
||||
notesVisible.value = false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
hasPriorNotes () {
|
||||
return this.priorNotesLoaded && this.priorNotes.length > 0
|
||||
},
|
||||
noPriorNotes () {
|
||||
return this.priorNotesLoaded && this.priorNotes.length === 0
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.journalEvents.$on('notes', this.openDialog)
|
||||
},
|
||||
methods: {
|
||||
closeDialog () {
|
||||
this.form.requestId = ''
|
||||
this.form.notes = ''
|
||||
this.priorNotes = []
|
||||
this.priorNotesLoaded = false
|
||||
this.notesVisible = false
|
||||
},
|
||||
async loadNotes () {
|
||||
this.progress.$emit('show', 'indeterminate')
|
||||
|
||||
/** Load the notes for this request */
|
||||
const loadNotes = async () => {
|
||||
progress.events.$emit('show', 'indeterminate')
|
||||
try {
|
||||
const notes = await api.getNotes(this.form.requestId)
|
||||
this.priorNotes = notes.data.sort((a, b) => b.asOf - a.asOf)
|
||||
this.progress.$emit('done')
|
||||
const notes = await api.getNotes(form.requestId)
|
||||
prior.notes = (notes.data as NotesEntry[]).sort((a, b) => b.asOf - a.asOf)
|
||||
} catch (e) {
|
||||
console.error(e) // eslint-disable-line no-console
|
||||
this.progress.$emit('done')
|
||||
} finally {
|
||||
this.priorNotesLoaded = true
|
||||
progress.events.$emit('done')
|
||||
prior.isLoaded = true
|
||||
}
|
||||
},
|
||||
openDialog (request) {
|
||||
this.form.requestId = request.requestId
|
||||
this.notesVisible = true
|
||||
},
|
||||
async saveNotes () {
|
||||
this.progress.$emit('show', 'indeterminate')
|
||||
}
|
||||
|
||||
/** Open this dialog */
|
||||
const openDialog = (request: JournalRequest) => {
|
||||
form.requestId = request.requestId
|
||||
notesVisible.value = true
|
||||
}
|
||||
|
||||
/** Save the notes entered on this dialog */
|
||||
const saveNotes = async () => {
|
||||
progress.events.$emit('show', 'indeterminate')
|
||||
try {
|
||||
await api.addNote(this.form.requestId, this.form.notes)
|
||||
this.progress.$emit('done')
|
||||
this.messages.$emit('info', 'Added notes')
|
||||
this.closeDialog()
|
||||
await api.addNote(form.requestId, form.notes)
|
||||
snackbar.events.$emit('info', 'Added notes')
|
||||
closeDialog()
|
||||
} catch (e) {
|
||||
console.error(e) // eslint-disable-line no-console
|
||||
this.progress.$emit('done')
|
||||
} finally {
|
||||
progress.events.$emit('done')
|
||||
}
|
||||
},
|
||||
trimText () {
|
||||
this.form.notes = this.form.notes.trim()
|
||||
}
|
||||
|
||||
/** Trim the note text */
|
||||
const trimText = () => { form.notes = form.notes.trim() }
|
||||
|
||||
events.$on('notes', openDialog)
|
||||
|
||||
return {
|
||||
closeDialog,
|
||||
form,
|
||||
hasPriorNotes,
|
||||
loadNotes,
|
||||
noPriorNotes,
|
||||
notesVisible,
|
||||
openDialog,
|
||||
prior,
|
||||
saveNotes,
|
||||
trimText
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="sass">
|
||||
|
|
|
@ -24,48 +24,78 @@ md-card(v-if='shouldDisplay'
|
|||
p.mpj-text-right: small.mpj-muted-text: em (last activity #[date-from-now(:value='request.asOf')])
|
||||
</template>
|
||||
|
||||
<script>
|
||||
'use strict'
|
||||
<script lang="ts">
|
||||
import { createComponent, computed } from '@vue/composition-api'
|
||||
|
||||
import { Actions } from '@/store/types'
|
||||
import { Actions, JournalRequest, UpdateRequestAction } from '../../store/types' // eslint-disable-line no-unused-vars
|
||||
|
||||
export default {
|
||||
name: 'request-card',
|
||||
inject: [
|
||||
'journalEvents',
|
||||
'messages',
|
||||
'progress'
|
||||
],
|
||||
import { useEvents } from '../Journal.vue'
|
||||
import { useStore } from '../../plugins/store'
|
||||
import { useProgress, useSnackbar } from '../../App.vue'
|
||||
import { useRouter } from '../../plugins/router'
|
||||
|
||||
export default createComponent({
|
||||
props: {
|
||||
request: { required: true }
|
||||
},
|
||||
computed: {
|
||||
shouldDisplay () {
|
||||
const now = Date.now()
|
||||
return Math.max(now, this.request.showAfter, this.request.snoozedUntil) === now
|
||||
request: {
|
||||
type: JournalRequest,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async markPrayed () {
|
||||
await this.$store.dispatch(Actions.UpdateRequest, {
|
||||
progress: this.progress,
|
||||
requestId: this.request.requestId,
|
||||
setup (props) {
|
||||
/** The Vuex store */
|
||||
const store = useStore()
|
||||
|
||||
/** The application router */
|
||||
const router = useRouter()
|
||||
|
||||
/** The progress bar component properties */
|
||||
const progress = useProgress()
|
||||
|
||||
/** The snackbar component properties */
|
||||
const snackbar = useSnackbar()
|
||||
|
||||
/** The journal event bus */
|
||||
const events = useEvents()
|
||||
|
||||
/** Should this request be displayed? */
|
||||
const shouldDisplay = computed(() => {
|
||||
const now = Date.now()
|
||||
return Math.max(now, props.request.showAfter, props.request.snoozedUntil) === now
|
||||
})
|
||||
|
||||
/** Mark the request as prayed */
|
||||
const markPrayed = async () => {
|
||||
const opts: UpdateRequestAction = {
|
||||
progress,
|
||||
requestId: props.request.requestId,
|
||||
status: 'Prayed',
|
||||
updateText: ''
|
||||
})
|
||||
this.messages.$emit('info', 'Request marked as prayed')
|
||||
},
|
||||
showEdit () {
|
||||
this.$router.push({ name: 'EditRequest', params: { id: this.request.requestId } })
|
||||
},
|
||||
showNotes () {
|
||||
this.journalEvents.$emit('notes', this.request)
|
||||
},
|
||||
snooze () {
|
||||
this.journalEvents.$emit('snooze', this.request.requestId)
|
||||
updateText: '',
|
||||
recurType: '',
|
||||
recurCount: 0
|
||||
}
|
||||
await store.dispatch(Actions.UpdateRequest, opts)
|
||||
snackbar.events.$emit('info', 'Request marked as prayed')
|
||||
}
|
||||
|
||||
/** Show the edit page for this request */
|
||||
const showEdit = () => { router.push({ name: 'EditRequest', params: { id: props.request.requestId } }) }
|
||||
|
||||
/** Show the request notes dialog */
|
||||
const showNotes = () => events.$emit('notes', props.request)
|
||||
|
||||
/** Show the snooze request dialog */
|
||||
const snooze = () => events.$emit('snooze', props.request.requestId)
|
||||
|
||||
return {
|
||||
markPrayed,
|
||||
request: props.request,
|
||||
shouldDisplay,
|
||||
showEdit,
|
||||
showNotes,
|
||||
snooze
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="sass">
|
||||
|
|
|
@ -77,9 +77,7 @@ export default createComponent({
|
|||
}
|
||||
await store.dispatch(Actions.SnoozeRequest, opts)
|
||||
snackbar.events.$emit('info', 'Request un-snoozed')
|
||||
if (parent) {
|
||||
parent.$emit('requestUnsnoozed')
|
||||
}
|
||||
if (parent) parent.$emit('requestUnsnoozed')
|
||||
}
|
||||
|
||||
/** Edit the given request */
|
||||
|
@ -94,9 +92,7 @@ export default createComponent({
|
|||
}
|
||||
await store.dispatch(Actions.ShowRequestNow, opts)
|
||||
snackbar.events.$emit('info', 'Recurrence skipped; request now shows in journal')
|
||||
if (parent) {
|
||||
parent.$emit('requestNowShown')
|
||||
}
|
||||
if (parent) parent.$emit('requestNowShown')
|
||||
}
|
||||
|
||||
/** View the full request */
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template lang="pug">
|
||||
md-dialog(:md-active.sync='snoozeVisible').mpj-skinny
|
||||
md-dialog(:md-active.sync='isVisible.value').mpj-skinny
|
||||
md-dialog-title Snooze Prayer Request
|
||||
md-content.mpj-dialog-content
|
||||
span.mpj-text-muted Until
|
||||
|
@ -7,63 +7,90 @@ md-dialog(:md-active.sync='snoozeVisible').mpj-skinny
|
|||
:md-disabled-dates='datesInPast'
|
||||
md-immediately)
|
||||
md-dialog-actions
|
||||
md-button(:disabled='!isValid'
|
||||
md-button(:disabled='!isValid.value'
|
||||
@click='snoozeRequest()').md-primary #[md-icon snooze] Snooze
|
||||
md-button(@click='closeDialog()') #[md-icon undo] Cancel
|
||||
</template>
|
||||
|
||||
<script>
|
||||
'use strict'
|
||||
<script lang="ts">
|
||||
import { createComponent, ref, computed } from '@vue/composition-api'
|
||||
|
||||
import { Actions } from '@/store/types'
|
||||
import { Actions, SnoozeRequestAction } from '../../store/types' // eslint-disable-line no-unused-vars
|
||||
|
||||
export default {
|
||||
name: 'snooze-request',
|
||||
inject: [
|
||||
'journalEvents',
|
||||
'messages',
|
||||
'progress'
|
||||
],
|
||||
props: {
|
||||
events: { required: true }
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
snoozeVisible: false,
|
||||
datesInPast: date => date < new Date(),
|
||||
form: {
|
||||
requestId: '',
|
||||
snoozedUntil: ''
|
||||
import { useProgress, useSnackbar } from '../../App.vue'
|
||||
import { useEvents } from '../Journal.vue'
|
||||
import { useStore } from '../../plugins/store'
|
||||
|
||||
/** The input form */
|
||||
class SnoozeForm {
|
||||
/** The ID of the request */
|
||||
requestId = ''
|
||||
|
||||
/** The date until which the request will be snoozed */
|
||||
snoozedUntil = ''
|
||||
}
|
||||
|
||||
export default createComponent({
|
||||
setup () {
|
||||
/** The Vuex store */
|
||||
const store = useStore()
|
||||
|
||||
/** The progress bar component properties */
|
||||
const progress = useProgress()
|
||||
|
||||
/** The snackbar component properties */
|
||||
const snackbar = useSnackbar()
|
||||
|
||||
/** The journal event bus */
|
||||
const events = useEvents()
|
||||
|
||||
/** Whether this dialog is visible */
|
||||
const isVisible = ref(false)
|
||||
|
||||
/** The input form */
|
||||
const form = new SnoozeForm()
|
||||
|
||||
/** Is the input date valid? */
|
||||
const isValid = computed(() => !isNaN(Date.parse(form.snoozedUntil)))
|
||||
|
||||
/** Close the dialog */
|
||||
const closeDialog = () => {
|
||||
form.requestId = ''
|
||||
form.snoozedUntil = ''
|
||||
isVisible.value = false
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the dialog
|
||||
* @param requestId The ID of the request to be snoozed
|
||||
*/
|
||||
const openDialog = (requestId: string) => {
|
||||
form.requestId = requestId
|
||||
isVisible.value = true
|
||||
}
|
||||
|
||||
const snoozeRequest = async () => {
|
||||
const opts: SnoozeRequestAction = {
|
||||
progress,
|
||||
requestId: form.requestId,
|
||||
until: Date.parse(form.snoozedUntil)
|
||||
}
|
||||
await store.dispatch(Actions.SnoozeRequest, opts)
|
||||
snackbar.events.$emit('info', `Request snoozed until ${form.snoozedUntil}`)
|
||||
closeDialog()
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.journalEvents.$on('snooze', this.openDialog)
|
||||
},
|
||||
computed: {
|
||||
isValid () {
|
||||
return !isNaN(Date.parse(this.form.snoozedUntil))
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
closeDialog () {
|
||||
this.form.requestId = ''
|
||||
this.form.snoozedUntil = ''
|
||||
this.snoozeVisible = false
|
||||
},
|
||||
openDialog (requestId) {
|
||||
this.form.requestId = requestId
|
||||
this.snoozeVisible = true
|
||||
},
|
||||
async snoozeRequest () {
|
||||
await this.$store.dispatch(Actions.SnoozeRequest, {
|
||||
progress: this.progress,
|
||||
requestId: this.form.requestId,
|
||||
until: Date.parse(this.form.snoozedUntil)
|
||||
})
|
||||
this.messages.$emit('info', `Request snoozed until ${this.form.snoozedUntil}`)
|
||||
this.closeDialog()
|
||||
|
||||
events.$on('snooze', openDialog)
|
||||
|
||||
return {
|
||||
closeDialog,
|
||||
datesInPast: (date: Date) => date < new Date(),
|
||||
form,
|
||||
isValid,
|
||||
isVisible,
|
||||
openDialog,
|
||||
snoozeRequest
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
article.mpj-main-content(role='main')
|
||||
page-title(title='Snoozed Requests'
|
||||
hide-on-page=true)
|
||||
template(v-if='loaded')
|
||||
template(v-if='isLoaded.value')
|
||||
md-empty-state(v-if='requests.length === 0'
|
||||
md-icon='sentiment_dissatisfied'
|
||||
md-label='No Snoozed Requests'
|
||||
|
@ -14,47 +14,51 @@ article.mpj-main-content(role='main')
|
|||
p(v-else) Loading journal...
|
||||
</template>
|
||||
|
||||
<script>
|
||||
'use strict'
|
||||
<script lang="ts">
|
||||
import { createComponent, ref, onMounted } from '@vue/composition-api'
|
||||
import { Store } from 'vuex' // eslint-disable-line no-unused-vars
|
||||
|
||||
import { mapState } from 'vuex'
|
||||
import RequestList from './RequestList.vue'
|
||||
|
||||
import { Actions } from '@/store/types'
|
||||
import { Actions, AppState, JournalRequest } from '../../store/types' // eslint-disable-line no-unused-vars
|
||||
import { useStore } from '../../plugins/store'
|
||||
import { useProgress } from '../../App.vue'
|
||||
|
||||
import RequestList from '@/components/request/RequestList'
|
||||
export default createComponent({
|
||||
components: { RequestList },
|
||||
setup () {
|
||||
/** The Vuex store */
|
||||
const store = useStore() as Store<AppState>
|
||||
|
||||
export default {
|
||||
name: 'snoozed-requests',
|
||||
inject: ['progress'],
|
||||
components: {
|
||||
RequestList
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
requests: [],
|
||||
loaded: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(['journal', 'isLoadingJournal'])
|
||||
},
|
||||
created () {
|
||||
this.$on('requestUnsnoozed', this.ensureJournal)
|
||||
},
|
||||
methods: {
|
||||
async ensureJournal () {
|
||||
if (!Array.isArray(this.journal)) {
|
||||
this.loaded = false
|
||||
await this.$store.dispatch(Actions.LoadJournal, this.progress)
|
||||
/** The progress bar component properties */
|
||||
const progress = useProgress()
|
||||
|
||||
/** The snoozed requests */
|
||||
let requests: JournalRequest[] = []
|
||||
|
||||
/** Have snoozed requests been loaded? */
|
||||
const isLoaded = ref(false)
|
||||
|
||||
/** Ensure the latest journal is loaded, and filter it to snoozed requests */
|
||||
const ensureJournal = async () => {
|
||||
if (!Array.isArray(store.state.journal)) {
|
||||
isLoaded.value = false
|
||||
await store.dispatch(Actions.LoadJournal, progress)
|
||||
}
|
||||
this.requests = this.journal
|
||||
requests = store.state.journal
|
||||
.filter(req => req.snoozedUntil > Date.now())
|
||||
.sort((a, b) => a.snoozedUntil - b.snoozedUntil)
|
||||
this.loaded = true
|
||||
isLoaded.value = true
|
||||
}
|
||||
|
||||
onMounted(ensureJournal)
|
||||
|
||||
// this.$on('requestUnsnoozed', ensureJournal)
|
||||
|
||||
return {
|
||||
requests,
|
||||
isLoaded
|
||||
}
|
||||
},
|
||||
async mounted () {
|
||||
await this.ensureJournal()
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -5,17 +5,18 @@ article.mpj-main-content(role='main')
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { onBeforeMount } from '@vue/composition-api'
|
||||
import { createComponent, onBeforeMount } from '@vue/composition-api'
|
||||
import VueRouter from 'vue-router' // eslint-disable-line no-unused-vars
|
||||
import { Store } from 'vuex' // eslint-disable-line no-unused-vars
|
||||
|
||||
import { AppState } from '../../store/types' // eslint-disable-line no-unused-vars
|
||||
import { AuthService } from '../../auth' // eslint-disable-line no-unused-vars
|
||||
|
||||
import { useAuth } from '../../plugins/auth'
|
||||
import { useRouter } from '../../plugins/router'
|
||||
import { useStore } from '../../plugins/store'
|
||||
|
||||
export default {
|
||||
export default createComponent({
|
||||
setup () {
|
||||
/** Auth service instance */
|
||||
const auth = useAuth() as AuthService
|
||||
|
@ -36,5 +37,5 @@ export default {
|
|||
|
||||
return { }
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -10,7 +10,9 @@ import {
|
|||
JournalRequest,
|
||||
Mutations,
|
||||
SnoozeRequestAction,
|
||||
ShowRequestAction
|
||||
ShowRequestAction,
|
||||
AddRequestAction,
|
||||
UpdateRequestAction
|
||||
} from './types'
|
||||
import { ProgressProps } from '@/types'
|
||||
|
||||
|
@ -101,16 +103,17 @@ const store : StoreOptions<AppState> = {
|
|||
}
|
||||
},
|
||||
actions: {
|
||||
async [Actions.AddRequest] ({ commit }, { progress, requestText, recurType, recurCount }) {
|
||||
progress.$emit('show', 'indeterminate')
|
||||
async [Actions.AddRequest] ({ commit }, p: AddRequestAction) {
|
||||
const { progress, requestText, recurType, recurCount } = p
|
||||
progress.events.$emit('show', 'indeterminate')
|
||||
try {
|
||||
await setBearer()
|
||||
const newRequest = await api.addRequest(requestText, recurType, recurCount)
|
||||
commit(Mutations.RequestAdded, newRequest.data)
|
||||
progress.$emit('done')
|
||||
} catch (err) {
|
||||
logError(err)
|
||||
progress.$emit('done')
|
||||
} finally {
|
||||
progress.events.$emit('done')
|
||||
}
|
||||
},
|
||||
async [Actions.CheckAuthentication] ({ commit }) {
|
||||
|
@ -129,19 +132,19 @@ const store : StoreOptions<AppState> = {
|
|||
try {
|
||||
const jrnl = await api.journal()
|
||||
commit(Mutations.LoadedJournal, jrnl.data)
|
||||
progress.events.$emit('done')
|
||||
} catch (err) {
|
||||
logError(err)
|
||||
progress.events.$emit('done')
|
||||
} finally {
|
||||
progress.events.$emit('done')
|
||||
commit(Mutations.LoadingJournal, false)
|
||||
}
|
||||
},
|
||||
async [Actions.UpdateRequest] ({ commit, state }, { progress, requestId, status, updateText, recurType, recurCount }) {
|
||||
progress.$emit('show', 'indeterminate')
|
||||
async [Actions.UpdateRequest] ({ commit, state }, p: UpdateRequestAction) {
|
||||
const { progress, requestId, status, updateText, recurType, recurCount } = p
|
||||
progress.events.$emit('show', 'indeterminate')
|
||||
try {
|
||||
await setBearer()
|
||||
const oldReq: any = (state.journal.filter(req => req.requestId === requestId) || [])[0] || {}
|
||||
const oldReq = (state.journal.filter(req => req.requestId === requestId) || [])[0] || {}
|
||||
if (!(status === 'Prayed' && updateText === '')) {
|
||||
if (status !== 'Answered' && (oldReq.recurType !== recurType || oldReq.recurCount !== recurCount)) {
|
||||
await api.updateRecurrence(requestId, recurType, recurCount)
|
||||
|
@ -152,10 +155,10 @@ const store : StoreOptions<AppState> = {
|
|||
}
|
||||
const request = await api.getRequest(requestId)
|
||||
commit(Mutations.RequestUpdated, request.data)
|
||||
progress.$emit('done')
|
||||
} catch (err) {
|
||||
logError(err)
|
||||
progress.$emit('done')
|
||||
} finally {
|
||||
progress.events.$emit('done')
|
||||
}
|
||||
},
|
||||
async [Actions.ShowRequestNow] ({ commit }, p: ShowRequestAction) {
|
||||
|
@ -166,9 +169,9 @@ const store : StoreOptions<AppState> = {
|
|||
await api.showRequest(requestId, showAfter)
|
||||
const request = await api.getRequest(requestId)
|
||||
commit(Mutations.RequestUpdated, request.data)
|
||||
progress.events.$emit('done')
|
||||
} catch (err) {
|
||||
logError(err)
|
||||
} finally {
|
||||
progress.events.$emit('done')
|
||||
}
|
||||
},
|
||||
|
@ -180,9 +183,9 @@ const store : StoreOptions<AppState> = {
|
|||
await api.snoozeRequest(requestId, until)
|
||||
const request = await api.getRequest(requestId)
|
||||
commit(Mutations.RequestUpdated, request.data)
|
||||
progress.events.$emit('done')
|
||||
} catch (err) {
|
||||
logError(err)
|
||||
} finally {
|
||||
progress.events.$emit('done')
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,15 @@ export class HistoryEntry {
|
|||
text?: string = undefined
|
||||
}
|
||||
|
||||
/** An entry with notes for a request */
|
||||
export class NotesEntry {
|
||||
/** The date/time the notes were recorded */
|
||||
asOf = 0
|
||||
|
||||
/** The notes */
|
||||
notes = ''
|
||||
}
|
||||
|
||||
/** A prayer request that is part of the user's journal */
|
||||
export class JournalRequest {
|
||||
/** The ID of the request (just the CUID part) */
|
||||
|
@ -45,7 +54,7 @@ export class JournalRequest {
|
|||
history: HistoryEntry[] = []
|
||||
|
||||
/** Note entries for the request */
|
||||
notes: any[] = [] // Note list
|
||||
notes: NotesEntry[] = []
|
||||
}
|
||||
|
||||
/** The state of myPrayerJournal */
|
||||
|
@ -108,9 +117,21 @@ const mutations = {
|
|||
}
|
||||
export { mutations as Mutations }
|
||||
|
||||
/** The shape of the parameter to the add request action */
|
||||
export interface AddRequestAction {
|
||||
/** The progress bar component properties */
|
||||
progress: ProgressProps
|
||||
/** The text of the request */
|
||||
requestText: string
|
||||
/** The recurrence type */
|
||||
recurType: string
|
||||
/** The number of intervals for non-immediate recurrence */
|
||||
recurCount: number
|
||||
}
|
||||
|
||||
/** The shape of the parameter to the show request action */
|
||||
export interface ShowRequestAction {
|
||||
/** The progress bar component instance */
|
||||
/** The progress bar component properties */
|
||||
progress: ProgressProps
|
||||
/** The ID of the prayer request being shown */
|
||||
requestId: string
|
||||
|
@ -120,10 +141,26 @@ export interface ShowRequestAction {
|
|||
|
||||
/** The shape of the parameter to the snooze request action */
|
||||
export interface SnoozeRequestAction {
|
||||
/** The progress bar component instance */
|
||||
/** The progress bar component properties */
|
||||
progress: ProgressProps
|
||||
/** The ID of the prayer request being snoozed/unsnoozed */
|
||||
requestId: string
|
||||
/** The date/time after which the request will be once again shown */
|
||||
until: number
|
||||
}
|
||||
|
||||
/** The shape of the parameter to the update request action */
|
||||
export interface UpdateRequestAction {
|
||||
/** The progress bar component properties */
|
||||
progress: ProgressProps
|
||||
/** The ID of the prayer request */
|
||||
requestId: string
|
||||
/** The text of the update */
|
||||
updateText: string
|
||||
/** The status associated with the update */
|
||||
status: string
|
||||
/** The type of recurrence for the request */
|
||||
recurType: string
|
||||
/** The number of intervals for non-immediate recurrence */
|
||||
recurCount: number
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user