interim commit with lots of stuff

- conversion from Element UI to Bootstrap 4 in progress (smaller, more
flexible)
- added Font Awesome for fonts, vue-toast for notifications
- added common components to main.js and out of other components
- some work on pulling answered requests (#3), added icon for notes (#8)
This commit is contained in:
Daniel J. Summers
2017-09-28 21:59:40 -05:00
parent 1e1afa9d89
commit ef88964cd0
19 changed files with 244 additions and 165 deletions

View File

@@ -22,42 +22,17 @@ export default {
</script>
<style>
@import url('../node_modules/element-ui/lib/theme-default/index.css');
body {
font-family: -apple-system,system-ui,BlinkMacSystemFont,"Segoe UI","Roboto","Helvetica Neue", Arial, sans-serif;
padding-top: 60px;
margin: 0;
}
#content {
padding: 0 10px;
}
footer {
border-top: solid 1px lightgray;
margin-top: 1rem;
padding: 0 1rem;
}
footer p {
margin: 0;
}
.text-right {
text-align: right;
}
.material-icons.md-18 {
font-size: 18px;
}
.material-icons.md-24 {
font-size: 24px;
}
.material-icons.md-36 {
font-size: 36px;
}
.material-icons.md-48 {
font-size: 48px;
}
.material-icons {
vertical-align: middle;
}
.mpj-page-title {
border-bottom: solid 1px lightgray;
margin-bottom: 20px;

View File

@@ -50,6 +50,11 @@ export default {
* Get a prayer request (full; includes all history)
* @param {string} requestId The Id of the request to retrieve
*/
getFullRequest: requestId => http.get(`request/${requestId}/full`)
getFullRequest: requestId => http.get(`request/${requestId}/full`),
/**
* Get all answered requests, along with the text they had when it was answered
*/
getAnsweredRequests: () => http.get('request/answered')
}

View File

@@ -0,0 +1,38 @@
<template lang="pug">
article
p(v-if='!loaded') Loading answered requests...
div(v-if='loaded')
</template>
<script>
'use static'
import api from '@/api'
export default {
name: 'answered',
data () {
return {
requests: [],
loaded: false
}
},
async mounted () {
this.$Progress.start()
try {
const reqs = await api.getAnsweredRequests()
this.requests = reqs.data
this.$Progress.finish()
} catch (err) {
console.error(err)
this.$message({
message: 'Error loading requests; check console for details',
type: 'error'
})
this.$Progress.fail()
} finally {
this.loaded = true
}
}
}
</script>

View File

@@ -15,12 +15,7 @@ article
<script>
'use strict'
import PageTitle from './common/PageTitle.vue'
export default {
name: 'home',
components: {
PageTitle
}
name: 'home'
}
</script>

View File

@@ -1,14 +1,13 @@
<template lang="pug">
article
page-title(:title='title')
toast(ref='toast')
p(v-if='isLoadingJournal') Loading your prayer journal...
template(v-if='!isLoadingJournal')
new-request
el-row
el-col(:span='4'): strong Actions
el-col(:span='16'): strong Request
el-col(:span='4'): strong As Of
request-list-item(v-if='journal.length > 0' v-for='request in journal' :request='request' :key='request.requestId')
br
b-row
request-list-item(v-if='journal.length > 0' v-for='request in journal' :request='request' :key='request.requestId')
p.text-center(v-if='journal.length === 0'): em No requests found; click the "Add a New Request" button to add one
</template>
@@ -17,7 +16,6 @@ article
import { mapState } from 'vuex'
import PageTitle from './common/PageTitle'
import NewRequest from './request/NewRequest'
import RequestListItem from './request/RequestListItem'
@@ -26,7 +24,6 @@ import actions from '@/store/action-types'
export default {
name: 'journal',
components: {
PageTitle,
NewRequest,
RequestListItem
},
@@ -38,10 +35,14 @@ export default {
},
async created () {
await this.$store.dispatch(actions.LOAD_JOURNAL, this.$Progress)
this.$message({
message: `Loaded ${this.journal.length} prayer requests`,
type: 'success'
})
this.$refs.toast.setOptions({ position: 'bottom right' })
this.$refs.toast.showToast(`Loaded ${this.journal.length} prayer requests`, { theme: 'success' })
}
}
/*
b-row
b-col(cols='2'): strong Actions
b-col(cols='8'): strong Request
b-col(cols='2'): strong As Of
*/
</script>

View File

@@ -1,13 +1,17 @@
<template lang="pug">
el-menu(theme='dark' mode='horizontal' class='mpj-top-nav' router='true')
el-menu-item(index='/')
b-navbar(toggleable='sm' type='dark' variant='info' fixed='top')
b-nav-toggle(target='nav_collapse')
b-navbar-brand(to='/')
span(style='font-weight:100;') my
span(style='font-weight:600;') Prayer
span(style='font-weight:700;') Journal
el-menu-item(v-if='isAuthenticated' index='/journal') Journal
el-menu-item(v-if='isAuthenticated' index='3'): a(@click.stop='logOff()') Log Off
el-menu-item(v-if='!isAuthenticated' index='4'): a(@click.stop='logOn()') Log On
el-menu-item(index='5'): a(href='https://danieljsummers.github.io/myPrayerJournal/' target='_blank' @click.stop='') Docs
b-collapse#nav_collapse(is-nav)
b-nav(is-nav-bar)
b-nav-item(v-if='isAuthenticated' to='/journal') Journal
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/' target='_blank' @click.stop='') Docs
</template>
<script>
@@ -36,15 +40,3 @@ export default {
}
}
</script>
<style>
.mpj-top-nav {
position: fixed;
top: 0px;
width: 100%;
}
.mpj-top-nav a:link,
.mpj-top-nav a:visited {
text-decoration: none;
}
</style>

View File

@@ -20,8 +20,11 @@ export default {
}
},
data () {
const dt = moment(this.value)
return {
fromNow: moment(this.value).fromNow(),
dt,
fromNow: dt.fromNow(),
actual: dt.format('LLLL'),
intervalId: null
}
},
@@ -34,12 +37,17 @@ export default {
},
methods: {
updateFromNow () {
let newFromNow = moment(this.value).fromNow()
let newFromNow = this.dt.fromNow()
if (newFromNow !== this.fromNow) this.fromNow = newFromNow
}
},
render (createElement) {
return createElement(this.tag, this.fromNow)
return createElement(this.tag, {
domProps: {
title: this.actual,
innerText: this.fromNow
}
})
}
}
</script>

View File

@@ -1,18 +1,25 @@
<template lang="pug">
span
el-button(icon='edit' @click='openDialog()' title='Edit')
el-dialog(title='Edit Prayer Request' :visible.sync='editVisible')
el-form(:model='form' :label-position='top')
el-form-item(label='Prayer Request')
el-input(type='textarea' v-model='form.requestText' :rows='10' @blur="trimText()")
el-form-item(label='Also Mark As')
el-radio-group(v-model='form.status')
el-radio-button(label='Updated') Updated
el-radio-button(label='Prayed') Prayed
el-radio-button(label='Answered') Answered
span.dialog-footer(slot='footer')
el-button(@click='closeDialog()') Cancel
el-button(type='primary' @click='saveRequest()') Save
b-btn(@click='openDialog()' title='Edit' size='sm' variant='outline-secondary'): icon(name='pencil')
b-modal(title='Edit Prayer Request'
v-model='editVisible'
size='lg'
header-bg-variant='dark'
header-text-variant='light'
@shows='focusRequestText')
b-form
b-form-group(label='Prayer Request' label-for='request_text')
b-textarea#request_text(v-model='form.requestText' :rows='10' @blur='trimText()' ref='toFocus')
b-form-group(label='Also Mark As')
b-radio-group(v-model='form.status' buttons)
b-radio(value='Updated') Updated
b-radio(value='Prayed') Prayed
b-radio(value='Answered') Answered
div.w-100.text-right(slot='modal-footer')
b-btn(variant='primary' @click='saveRequest()') Save
| &nbsp; &nbsp;
b-btn(variant='outline-secondary' @click='closeDialog()') Cancel
toast(ref='toast')
</template>
<script>
@@ -22,7 +29,9 @@ import actions from '@/store/action-types'
export default {
name: 'edit-request',
props: [ 'request' ],
props: {
request: { required: true }
},
data () {
return {
editVisible: false,
@@ -33,12 +42,18 @@ export default {
formLabelWidth: '120px'
}
},
mounted () {
this.$refs.toast.setOptions({ position: 'bottom right' })
},
methods: {
closeDialog () {
this.form.requestText = ''
this.form.status = 'Updated'
this.editVisible = false
},
focusRequestText (e) {
this.$refs.toFocus.focus()
},
openDialog () {
this.editVisible = true
},
@@ -53,15 +68,9 @@ export default {
status: this.form.status
})
if (this.form.status === 'Answered') {
this.$message({
message: 'Request updated and removed from active journal',
type: 'success'
})
this.$refs.toast.showToast('Request updated and removed from active journal', { theme: 'success' })
} else {
this.$message({
message: 'Request updated',
type: 'success'
})
this.$refs.toast.showToast('Request updated', { theme: 'success' })
}
this.editVisible = false
}

View File

@@ -1,11 +1,16 @@
<template lang="pug">
span
el-button(icon='view' @click='openDialog()' title='Show History')
el-dialog(title='Prayer Request History' :visible.sync='historyVisible')
span(v-if='null !== full')
b-btn(@click='openDialog()' title='Show History' size='sm' variant='outline-secondary'): icon(name='search')
b-modal(title='Prayer Request History'
v-model='historyVisible'
size='lg'
header-bg-variant='dark'
header-text-variant='light'
@shows='focusRequestText')
b-list-group(v-if='null !== full' flush)
full-request-history(v-for='item in full.history' :history='item' :key='item.asOf')
span.dialog-footer(slot='footer')
el-button(type='primary' @click='closeDialog()') Close
div.w-100.text-right(slot='modal-footer')
b-btn(variant='primary' @click='closeDialog()') Close
</template>
<script>
@@ -17,7 +22,9 @@ import api from '@/api'
export default {
name: 'full-request',
props: [ 'request' ],
props: {
request: { required: true }
},
data () {
return {
historyVisible: false,

View File

@@ -1,5 +1,5 @@
<template lang="pug">
p.journal-request
b-list-group-item
| {{ history.status }} {{ asOf }}
span(v-if='0 < history.text.length') &nbsp;&raquo; {{ history.text }}
</template>
@@ -11,7 +11,9 @@ import moment from 'moment'
export default {
name: 'full-request-history',
props: [ 'history' ],
props: {
history: { required: true }
},
computed: {
asOf () {
return moment(this.history.asOf).fromNow()

View File

@@ -1,13 +1,22 @@
<template lang="pug">
div
el-button(icon='plus' @click='openDialog()') Add a New Request
el-dialog(title='Add a New Prayer Request' :visible.sync='showNewVisible')
el-form(:model='form' :label-position='top')
el-form-item(label='Prayer Request')
el-input(type='textarea' v-model='form.requestText' :rows='10' @blur='trimText()')
span.dialog-footer(slot='footer')
el-button(@click='closeDialog()') Cancel
el-button(type='primary' @click='saveRequest()') Save
b-btn(@click='openDialog()' size='sm' variant='primary')
icon(name='plus')
| &nbsp; Add a New Request
b-modal(title='Add a New Prayer Request'
v-model='showNewVisible'
size='lg'
header-bg-variant='dark'
header-text-variant='light'
@shown='focusRequestText')
b-form
b-form-group(label='Prayer Request' label-for='request_text')
b-textarea#request_text(v-model='form.requestText' :rows='10' @blur='trimText()' ref='toFocus')
div.w-100.text-right(slot='modal-footer')
b-btn(variant='primary' @click='saveRequest()') Save
| &nbsp; &nbsp;
b-btn(variant='outline-secondary' @click='closeDialog()') Cancel
toast(ref='toast')
</template>
<script>
@@ -26,11 +35,17 @@ export default {
formLabelWidth: '120px'
}
},
mounted () {
this.$refs.toast.setOptions({ position: 'bottom right' })
},
methods: {
closeDialog () {
this.form.requestText = ''
this.showNewVisible = false
},
focusRequestText (e) {
this.$refs.toFocus.focus()
},
openDialog () {
this.showNewVisible = true
},
@@ -42,10 +57,7 @@ export default {
progress: this.$Progress,
requestText: this.form.requestText
})
this.$message({
message: 'New prayer request added',
type: 'success'
})
this.$refs.toast.showToast('New prayer request added', { theme: 'success' })
this.closeDialog()
}
}

View File

@@ -1,11 +1,23 @@
<template lang="pug">
el-row.journal-request
el-col(:span='4'): p
el-button(icon='check' @click='markPrayed()' title='Pray')
edit-request(:request='request')
full-request(:request='request')
el-col(:span='16'): p {{ text }}
el-col(:span='4'): p: date-from-now(:value='request.asOf')
b-col(xs='12' sm='6' md='4')
b-card(border-variant='dark' no-body)
div.card-body.p-0
p.card-text.mb-1.px-3.pt-3
| {{ text }}
p.card-text.p-0.pr-1.text-right: small.text-muted: em
= '(last activity '
date-from-now(:value='request.asOf')
| )
//-
edit-request(:request='request')
full-request(:request='request')
b-card-footer.text-center.py-1.
#[b-btn(@click='markPrayed()' variant='outline-primary' title='Pray' size='sm'): icon(name='check')]
#[b-btn(variant='outline-secondary' title='Edit' size='sm'): icon(name='pencil')]
#[b-btn(variant='outline-secondary' title='Add Notes' size='sm'): icon(name='file-text-o')]
#[b-btn(variant='outline-secondary' title='View Full Request' size='sm'): icon(name='search')]
br
toast(ref='toast')
</template>
<script>
@@ -13,7 +25,6 @@ el-row.journal-request
import moment from 'moment'
import DateFromNow from '../common/DateFromNow'
import EditRequest from './EditRequest'
import FullRequest from './FullRequest'
@@ -21,15 +32,16 @@ import actions from '@/store/action-types'
export default {
name: 'request-list-item',
props: [ 'request' ],
data () {
return { interval: null }
props: {
request: { required: true }
},
components: {
DateFromNow,
EditRequest,
FullRequest
},
mounted () {
this.$refs.toast.setOptions({ position: 'bottom right' })
},
methods: {
async markPrayed () {
await this.$store.dispatch(actions.UPDATE_REQUEST, {
@@ -38,10 +50,7 @@ export default {
status: 'Prayed',
updateText: ''
})
this.$message({
message: 'Request marked as prayed',
type: 'success'
})
this.$refs.toast.showToast('Request marked as prayed', { theme: 'success' })
}
},
computed: {
@@ -53,10 +62,13 @@ export default {
}
}
}
/*
b-row.journal-request
b-col(cols='2'): p
b-btn(@click='markPrayed()' size='sm' variant='outline-primary' title='Pray'): icon(name='check')
edit-request(:request='request')
full-request(:request='request')
b-col(cols='8'): p {{ text }}
b-col(cols='2'): p: date-from-now(:value='request.asOf')
*/
</script>
<style>
.journal-request {
border-bottom: dotted 1px lightgray;
}
</style>

View File

@@ -7,14 +7,10 @@ article
<script>
'use strict'
import PageTitle from '../common/PageTitle'
import AuthService from '@/auth/AuthService'
export default {
name: 'log-on',
components: {
PageTitle
},
created () {
this.$Progress.start()
new AuthService().handleAuthentication(this.$store, this.$router)

View File

@@ -1,20 +1,33 @@
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import ElementUI from 'element-ui'
import BootstrapVue from 'bootstrap-vue'
import Icon from 'vue-awesome/components/Icon'
import VueProgressBar from 'vue-progressbar'
import 'element-ui/lib/theme-default/index.css'
import VueToast from 'vue-toast'
import 'bootstrap-vue/dist/bootstrap-vue.css'
import 'bootstrap/dist/css/bootstrap.css'
import 'vue-toast/dist/vue-toast.min.css'
// Only import the icons we need; the whole set is ~500K!
import 'vue-awesome/icons/check'
import 'vue-awesome/icons/file-text-o'
import 'vue-awesome/icons/pencil'
import 'vue-awesome/icons/plus'
import 'vue-awesome/icons/search'
import App from './App'
import router from './router'
import store from './store'
import DateFromNow from './components/common/DateFromNow'
import PageTitle from './components/common/PageTitle'
Vue.config.productionTip = false
Vue.use(ElementUI)
Vue.use(BootstrapVue)
Vue.use(VueProgressBar, {
color: 'rgb(32, 160, 255)',
color: 'yellow',
failedColor: 'red',
height: '5px',
transition: {
@@ -24,6 +37,11 @@ Vue.use(VueProgressBar, {
}
})
Vue.component('icon', Icon)
Vue.component('date-from-now', DateFromNow)
Vue.component('page-title', PageTitle)
Vue.component('toast', VueToast)
/* eslint-disable no-new */
new Vue({
el: '#app',