- API is now F# / Giraffe / EF Core
- Snoozed requests are complete #17
- Updated doc links in preparation for transfer to Bit Badger Solutions organization's repository
This commit was merged in pull request #18.
This commit is contained in:
Daniel J. Summers
2018-08-06 21:21:28 -05:00
committed by GitHub
parent d1fd5f68e7
commit 8becb8cea4
30 changed files with 976 additions and 873 deletions

View File

@@ -4,8 +4,8 @@ var path = require('path')
module.exports = {
build: {
env: require('./prod.env'),
index: path.resolve(__dirname, '../../public/index.html'),
assetsRoot: path.resolve(__dirname, '../../public'),
index: path.resolve(__dirname, '../../api/MyPrayerJournal.Api/wwwroot/index.html'),
assetsRoot: path.resolve(__dirname, '../../api/MyPrayerJournal.Api/wwwroot'),
assetsSubDirectory: 'static',
assetsPublicPath: '/',
productionSourceMap: true,

View File

@@ -1,6 +1,6 @@
{
"name": "my-prayer-journal",
"version": "0.9.6",
"version": "0.9.7",
"description": "myPrayerJournal - Front End",
"author": "Daniel J. Summers <daniel@bitbadger.solutions>",
"private": true,
@@ -12,8 +12,8 @@
"e2e": "node test/e2e/runner.js",
"test": "npm run unit && npm run e2e",
"lint": "eslint --ext .js,.vue src test/unit/specs test/e2e/specs",
"apistart": "cd .. && go build -o mpj-api.exe && mpj-api.exe",
"vue": "node build/build.js prod && cd .. && go build -o mpj-api.exe && mpj-api.exe"
"apistart": "cd ../api/MyPrayerJournal.Api && dotnet run",
"vue": "node build/build.js prod && cd ../api/MyPrayerJournal.Api && dotnet run"
},
"dependencies": {
"auth0-js": "^9.3.3",

View File

@@ -12,7 +12,7 @@
em: small.
#[router-link(:to="{ name: 'PrivacyPolicy' }") Privacy Policy] &bull;
#[router-link(:to="{ name: 'TermsOfService' }") Terms of Service] &bull;
#[a(href='https://github.com/danieljsummers/myprayerjournal') Developed] and hosted by
#[a(href='https://github.com/bit-badger/myprayerjournal') Developed] and hosted by
#[a(href='https://bitbadger.solutions') Bit Badger Solutions]
</template>

View File

@@ -31,12 +31,12 @@ export default {
* Add a new prayer request
* @param {string} requestText The text of the request to be added
*/
addRequest: requestText => http.post('request/', { requestText }),
addRequest: requestText => http.post('request', { requestText }),
/**
* Get all answered requests, along with the text they had when it was answered
*/
getAnsweredRequests: () => http.get('request/answered'),
getAnsweredRequests: () => http.get('requests/answered'),
/**
* Get a prayer request (full; includes all history)
@@ -64,7 +64,14 @@ export default {
/**
* Get all prayer requests and their most recent updates
*/
journal: () => http.get('journal/'),
journal: () => http.get('journal'),
/**
* Snooze a request until the given time
* @param requestId {string} The ID of the prayer request to be snoozed
* @param until {number} The ticks until which the request should be snoozed
*/
snoozeRequest: (requestId, until) => http.post(`request/${requestId}/snooze`, { until }),
/**
* Update a prayer request

View File

@@ -10,6 +10,7 @@ article
b-table(small hover :fields='fields' :items='log')
template(slot='action' scope='data').
{{ data.item.status }} on #[span.text-nowrap {{ formatDate(data.item.asOf) }}]
template(slot='text' scope='data' v-if='data.item.text') {{ data.item.text.fields[0] }}
</template>
<script>
@@ -44,12 +45,12 @@ export default {
},
lastText () {
return this.request.history
.filter(hist => hist.text > '')
.sort(asOfDesc)[0].text
.filter(hist => hist.text)
.sort(asOfDesc)[0].text.fields[0]
},
log () {
return (this.request.notes || [])
.map(note => ({ asOf: note.asOf, text: note.notes, status: 'Notes' }))
.map(note => ({ asOf: note.asOf, text: { case: 'Some', fields: [ note.notes ] }, status: 'Notes' }))
.concat(this.request.history)
.sort(asOfDesc)
.slice(1)

View File

@@ -18,6 +18,8 @@ article
notes-edit(:events='eventBus'
:toast='toast')
full-request(:events='eventBus')
snooze-request(:events='eventBus'
:toast='toast')
</template>
<script>
@@ -31,6 +33,7 @@ import FullRequest from './request/FullRequest'
import NewRequest from './request/NewRequest'
import NotesEdit from './request/NotesEdit'
import RequestCard from './request/RequestCard'
import SnoozeRequest from './request/SnoozeRequest'
import actions from '@/store/action-types'
@@ -41,7 +44,8 @@ export default {
FullRequest,
NewRequest,
NotesEdit,
RequestCard
RequestCard,
SnoozeRequest
},
data () {
return {

View File

@@ -12,11 +12,13 @@ b-navbar(toggleable='sm'
b-navbar-nav
b-nav-item(v-if='isAuthenticated'
to='/journal') Journal
b-nav-item(v-if='hasSnoozed'
to='/snoozed') Snoozed
b-nav-item(v-if='isAuthenticated'
to='/answered') Answered
b-nav-item(v-if='isAuthenticated'): a(@click.stop='logOff()') Log Off
b-nav-item(v-if='!isAuthenticated'): a(@click.stop='logOn()') Log On
b-nav-item(href='https://danieljsummers.github.io/myPrayerJournal/'
b-nav-item(href='https://bit-badger.github.io/myPrayerJournal/'
target='_blank'
@click.stop='') Docs
</template>
@@ -35,7 +37,12 @@ export default {
}
},
computed: {
...mapState([ 'isAuthenticated' ])
hasSnoozed () {
return this.isAuthenticated &&
Array.isArray(this.journal) &&
this.journal.filter(req => req.snoozedUntil > Date.now()).length > 0
},
...mapState([ 'journal', 'isAuthenticated' ])
},
methods: {
logOn () {

View File

@@ -0,0 +1,76 @@
<template lang="pug">
article
page-title(title='Snoozed Requests')
p(v-if='!loaded') Loading journal...
div(v-if='loaded').mpj-snoozed-list
p.text-center(v-if='requests.length === 0'): em.
No snoozed requests found; return to #[router-link(:to='{ name: "Journal" } ') your journal]
p.mpj-snoozed-text(v-for='req in requests' :key='req.requestId')
| {{ req.text }}
br
br
b-btn(@click='cancelSnooze(req.requestId)'
size='sm'
variant='outline-secondary')
icon(name='times')
= ' Cancel Snooze'
small.text-muted: em.
&nbsp; Snooze expires #[date-from-now(:value='req.snoozedUntil')]
</template>
<script>
'use static'
import { mapState } from 'vuex'
import actions from '@/store/action-types'
export default {
name: 'answered',
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
.filter(req => req.snoozedUntil > Date.now())
.sort((a, b) => a.snoozedUntil - b.snoozedUntil)
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>
<style>
.mpj-snoozed-list p {
border-top: solid 1px lightgray;
}
.mpj-snoozed-list p:first-child {
border-top: none;
}
</style>

View File

@@ -2,8 +2,8 @@
b-list-group-item
| {{ history.status }}
|
small.text-muted {{ asOf }}
div(v-if='hasText').mpj-request-text {{ history.text }}
small.text-muted(:title='actualDate') {{ asOf }}
div(v-if='history.text').mpj-request-text {{ history.text.fields[0] }}
</template>
<script>
@@ -20,8 +20,8 @@ export default {
asOf () {
return moment(this.history.asOf).fromNow()
},
hasText () {
return this.history.text.length > 0
actualDate () {
return moment(this.history.asOf).format('LLLL')
}
}
}

View File

@@ -53,7 +53,7 @@ export default {
this.events.$emit('notes', this.request)
},
snooze () {
// Nothing yet
this.events.$emit('snooze', this.request.requestId)
}
}
}

View File

@@ -0,0 +1,72 @@
<template lang="pug">
b-modal(v-model='snoozeVisible'
header-bg-variant='mpj'
header-text-variant='light'
size='lg'
title='Snooze Prayer Request'
@edit='openDialog()')
b-form
b-form-group(label='Until'
label-for='until')
b-input#until(type='date'
v-model='form.snoozedUntil'
autofocus)
div.w-100.text-right(slot='modal-footer')
b-btn(variant='primary'
:disabled='!isValid'
@click='snoozeRequest()') Snooze
| &nbsp; &nbsp;
b-btn(variant='outline-secondary'
@click='closeDialog()') Cancel
</template>
<script>
'use strict'
import actions from '@/store/action-types'
export default {
name: 'snooze-request',
props: {
toast: { required: true },
events: { required: true }
},
data () {
return {
snoozeVisible: false,
form: {
requestId: '',
snoozedUntil: ''
}
}
},
created () {
this.events.$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.SNOOZE_REQUEST, {
progress: this.$Progress,
requestId: this.form.requestId,
until: Date.parse(this.form.snoozedUntil)
})
this.toast.showToast(`Request snoozed until ${this.form.snoozedUntil}`, { theme: 'success' })
this.closeDialog()
}
}
}
</script>

View File

@@ -17,6 +17,7 @@ import 'vue-awesome/icons/file-text-o'
import 'vue-awesome/icons/pencil'
import 'vue-awesome/icons/plus'
import 'vue-awesome/icons/search'
import 'vue-awesome/icons/times'
import App from './App'
import router from './router'

View File

@@ -7,6 +7,7 @@ import Home from '@/components/Home'
import Journal from '@/components/Journal'
import LogOn from '@/components/user/LogOn'
import PrivacyPolicy from '@/components/legal/PrivacyPolicy'
import Snoozed from '@/components/Snoozed'
import TermsOfService from '@/components/legal/TermsOfService'
Vue.use(Router)
@@ -45,6 +46,11 @@ export default new Router({
name: 'TermsOfService',
component: TermsOfService
},
{
path: '/snoozed',
name: 'Snoozed',
component: Snoozed
},
{
path: '/user/log-on',
name: 'LogOn',

View File

@@ -6,5 +6,7 @@ export default {
/** Action to load the user's prayer journal */
LOAD_JOURNAL: 'load-journal',
/** Action to update a request */
UPDATE_REQUEST: 'update-request'
UPDATE_REQUEST: 'update-request',
/** Action to snooze a request */
SNOOZE_REQUEST: 'snooze-request'
}

View File

@@ -109,6 +109,18 @@ export default new Vuex.Store({
logError(err)
progress.fail()
}
},
async [actions.SNOOZE_REQUEST] ({ commit }, { progress, requestId, until }) {
progress.start()
try {
await api.snoozeRequest(requestId, until)
const request = await api.getRequest(requestId)
commit(mutations.REQUEST_UPDATED, request.data)
progress.finish()
} catch (err) {
logError(err)
progress.fail()
}
}
},
getters: {},