Format dates/revise dashboard

Also added version and rearranged shared components into just components and layout components
This commit is contained in:
Daniel J. Summers 2021-07-25 22:21:53 -04:00
parent b0ae93cc07
commit b27e7a8055
16 changed files with 178 additions and 69 deletions

View File

@ -4853,6 +4853,16 @@
"assert-plus": "^1.0.0" "assert-plus": "^1.0.0"
} }
}, },
"date-fns": {
"version": "2.23.0",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.23.0.tgz",
"integrity": "sha512-5ycpauovVyAk0kXNZz6ZoB9AYMZB4DObse7P3BPWmyEjXNORTI8EJ6X0uaSAq4sCHzM1uajzrkr6HnsLQpxGXA=="
},
"date-fns-tz": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/date-fns-tz/-/date-fns-tz-1.1.4.tgz",
"integrity": "sha512-lQ+FF7xUxxRuRqIY7H/lagnT3PhhSnnvtGHzjE5WZKwRyLU7glJfLys05SZ7zHlEr6RXWiqkmgWq4nCkcElR+g=="
},
"debug": { "debug": {
"version": "4.3.2", "version": "4.3.2",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",

View File

@ -1,6 +1,6 @@
{ {
"name": "jobs-jobs-jobs", "name": "jobs-jobs-jobs",
"version": "1.0.1", "version": "1.9.0",
"private": true, "private": true,
"scripts": { "scripts": {
"serve": "vue-cli-service serve", "serve": "vue-cli-service serve",
@ -11,6 +11,8 @@
"dependencies": { "dependencies": {
"@mdi/font": "5.9.55", "@mdi/font": "5.9.55",
"core-js": "^3.6.5", "core-js": "^3.6.5",
"date-fns": "^2.23.0",
"date-fns-tz": "^1.1.4",
"marked": "^2.1.3", "marked": "^2.1.3",
"roboto-fontface": "*", "roboto-fontface": "*",
"vue": "^3.0.0", "vue": "^3.0.0",

View File

@ -23,9 +23,9 @@
<script lang="ts"> <script lang="ts">
import { defineComponent } from 'vue' import { defineComponent } from 'vue'
import AppFooter from './components/shared/AppFooter.vue' import AppFooter from './components/layout/AppFooter.vue'
import AppNav from './components/shared/AppNav.vue' import AppNav from './components/layout/AppNav.vue'
import TitleBar from './components/shared/TitleBar.vue' import TitleBar from './components/layout/TitleBar.vue'
export default defineComponent({ export default defineComponent({
name: 'App', name: 'App',

View File

@ -11,10 +11,10 @@ export interface Citizen {
realName : string | undefined realName : string | undefined
/** The URL for the user's Mastodon profile */ /** The URL for the user's Mastodon profile */
profileUrl : string profileUrl : string
/** When the user joined Jobs, Jobs, Jobs */ /** When the user joined Jobs, Jobs, Jobs (date) */
joinedOn : number joinedOn : string
/** When the user last logged in */ /** When the user last logged in (date) */
lastSeenOn : number lastSeenOn : string
} }
/** A continent */ /** A continent */
@ -63,8 +63,8 @@ export interface Profile {
fullTime : boolean fullTime : boolean
/** The citizen's professional biography */ /** The citizen's professional biography */
biography : string biography : string
/** When the citizen last updated their profile */ /** When the citizen last updated their profile (date) */
lastUpdatedOn : number lastUpdatedOn : string
/** The citizen's experience (topical / chronological) */ /** The citizen's experience (topical / chronological) */
experience : string | undefined experience : string | undefined
/** Skills this citizen possesses */ /** Skills this citizen possesses */

View File

@ -1,5 +1,5 @@
<template> <template>
<span @click.prevent="playFile"><slot></slot></span><audio :id="clip"><source :src="clipSource"></audio> <span @click="playFile"><slot></slot><audio :id="clip"><source :src="clipSource"></audio></span>
</template> </template>
<script lang="ts"> <script lang="ts">

View File

@ -0,0 +1,27 @@
<template>
<template v-if="true">{{formatted}}</template>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import { format, parseJSON } from 'date-fns'
import { utcToZonedTime } from 'date-fns-tz'
export default defineComponent({
name: 'FullDateTime',
props: {
date: {
type: String,
required: true
}
},
setup (props) {
return {
formatted: format(
utcToZonedTime(
parseJSON(props.date), Intl.DateTimeFormat().resolvedOptions().timeZone),
'PPPppp')
}
}
})
</script>

View File

@ -0,0 +1,38 @@
<template>
<p>
Jobs, Jobs, Jobs v{{appVersion}} &bull; <router-link to="/privacy-policy">Privacy Policy</router-link>
&bull; <router-link to="/terms-of-service">Terms of Service</router-link>
</p>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import { version } from '../../../package.json'
export default defineComponent({
name: 'AppFooter',
setup () {
let appVersion : string = version
while (appVersion.endsWith('.0')) {
appVersion = appVersion.substring(0, appVersion.length - 2)
}
return {
appVersion
}
}
})
</script>
<style lang="sass" scoped>
p
padding-top: 2rem
color: rgba(0, 0, 0, .4)
font-style: italic
font-size: .8rem
a:link,
a:visited
color: rgba(0, 0, 0, .4)
text-decoration: none
a:hover
text-decoration: underline
</style>

View File

@ -3,18 +3,18 @@
<p class="home-link"><router-link to="/">Jobs, Jobs, Jobs</router-link></p> <p class="home-link"><router-link to="/">Jobs, Jobs, Jobs</router-link></p>
<p>&nbsp;</p> <p>&nbsp;</p>
<nav> <nav>
<template v-if="!isLoggedOn"> <template v-if="isLoggedOn">
<router-link to="/"><v-icon icon="mdi-home" /> Home</router-link>
<router-link to="/profile/seeking"><v-icon icon="mdi-view-list-outline" /> Job Seekers</router-link>
<a :href="authUrl"><v-icon icon="mdi-login-variant" /> Log On</a>
</template>
<template v-else>
<router-link to="/citizen/dashboard"><v-icon icon="mdi-view-dashboard-variant" />Dashboard</router-link> <router-link to="/citizen/dashboard"><v-icon icon="mdi-view-dashboard-variant" />Dashboard</router-link>
<router-link to="/citizen/profile"><v-icon icon="mdi-pencil" /> Edit Your Profile</router-link> <router-link to="/citizen/profile"><v-icon icon="mdi-pencil" /> Edit Your Profile</router-link>
<router-link to="/profile/search"><v-icon icon="mdi-view-list-outline" /> View Profiles</router-link> <router-link to="/profile/search"><v-icon icon="mdi-view-list-outline" /> View Profiles</router-link>
<router-link to="/success-story/list"><v-icon icon="mdi-thumb-up" /> Success Stories</router-link> <router-link to="/success-story/list"><v-icon icon="mdi-thumb-up" /> Success Stories</router-link>
<router-link to="/citizen/log-off"><v-icon icon="mdi-logout-variant" /> Log Off</router-link> <router-link to="/citizen/log-off"><v-icon icon="mdi-logout-variant" /> Log Off</router-link>
</template> </template>
<template v-else>
<router-link to="/"><v-icon icon="mdi-home" /> Home</router-link>
<router-link to="/profile/seeking"><v-icon icon="mdi-view-list-outline" /> Job Seekers</router-link>
<a :href="authUrl"><v-icon icon="mdi-login-variant" /> Log On</a>
</template>
<router-link to="/how-it-works"><v-icon icon="mdi-help-circle-outline" /> How It Works</router-link> <router-link to="/how-it-works"><v-icon icon="mdi-help-circle-outline" /> How It Works</router-link>
</nav> </nav>
</aside> </aside>

View File

@ -4,7 +4,7 @@
<script lang="ts"> <script lang="ts">
import { defineComponent } from 'vue' import { defineComponent } from 'vue'
import AudioClip from './AudioClip.vue' import AudioClip from '../AudioClip.vue'
export default defineComponent({ export default defineComponent({
name: 'TitleBar', name: 'TitleBar',

View File

@ -1,19 +0,0 @@
<template>
<p>Jobs, Jobs, Jobs [version] &bull; <router-link to="/privacy-policy">Privacy Policy</router-link>
&bull; <router-link to="/terms-of-service">Terms of Service</router-link>
</p>
</template>
<style lang="sass" scoped>
p
padding-top: 2rem
color: rgba(0, 0, 0, .4)
font-style: italic
font-size: .8rem
a:link,
a:visited
color: rgba(0, 0, 0, .4)
text-decoration: none
a:hover
text-decoration: underline
</style>

View File

@ -16,7 +16,7 @@
<script lang="ts"> <script lang="ts">
import { defineComponent } from 'vue' import { defineComponent } from 'vue'
import AudioClip from '../components/shared/AudioClip.vue' import AudioClip from '../components/AudioClip.vue'
export default defineComponent({ export default defineComponent({
name: 'Home', name: 'Home',

View File

@ -3,33 +3,69 @@
<page-title title="Dashboard" /> <page-title title="Dashboard" />
<h3>Welcome, {{user.name}}</h3> <h3>Welcome, {{user.name}}</h3>
<load-data :load="retrieveData"> <load-data :load="retrieveData">
<template v-if="profile"> <v-row class="spaced">
<p> <v-col cols="12" md="6">
Your employment profile was last updated {{profile.lastUpdatedOn}}. Your profile currently lists <v-card elevation="6">
{{profile.skills.length}} skill<span v-if="profile.skills.length !== 1">s</span>. <v-card-header>
</p> <v-card-header-text>
<p><router-link :to="'/profile/view/' + user.citizenId">View Your Employment Profile</router-link></p> <v-card-title>Your Profile</v-card-title>
<p v-if="profile.seekingEmployment"> <v-card-subtitle>Last updated <full-date-time :date="profile.lastUpdatedOn" /></v-card-subtitle>
Your profile indicates that you are seeking employment. Once you find it, </v-card-header-text>
<router-link to="/success-story/add">tell your fellow citizens about it!</router-link> </v-card-header>
</p> <v-card-text>
</template> <div v-if="profile">
<template v-else> Your profile currently lists {{profile.skills.length}}
<p> skill<template v-if="profile.skills.length !== 1">s</template>.
You do not have an employment profile established; click &ldquo;Edit Profile&rdquo; in the menu to get <span v-if="profile.seekingEmployment">
started! <br><br>
</p> Your profile indicates that you are seeking employment. Once you find it,
</template> <router-link to="/success-story/add">tell your fellow citizens about it!</router-link>
<hr> </span>
<p> </div>
There <template v-if="profileCount === 1">is</template><template v-else>are</template>&nbsp; <div v-else>
<template v-if="profileCount === 0">no</template><template v-else>{{profileCount}}</template> You do not have an employment profile established; click below (or &ldquo;Edit Profile&rdquo; in the menu)
employment profile<template v-if="profileCount !== 1">s</template> from citizens of Gitmo Nation. to get started!
<template v-if="profileCount > 0">Take a look around and see if you can help them find work!</template> </div>
</p> </v-card-text>
<v-card-actions>
<template v-if="profile">
<v-btn v-if="profile" @click="viewProfile">View Profile</v-btn>
<v-btn @click="editProfile">Edit Profile</v-btn>
</template>
<v-btn v-else @click="editProfile">Create Profile</v-btn>
</v-card-actions>
</v-card>
</v-col>
<v-col cols="12" md="6">
<v-card elevation="6">
<v-card-header>
<v-card-header-text>
<v-card-title>Other Citizens</v-card-title>
<v-card-subtitle>
<template v-if="profileCount === 0">No</template><template v-else>{{profileCount}} Total</template>
Employment Profile<template v-if="profileCount !== 1">s</template>
</v-card-subtitle>
</v-card-header-text>
</v-card-header>
<v-card-text>
<div v-if="profileCount === 1 && profile">
It looks like, for now, it&rsquo;s just you&hellip;
</div>
<div v-else-if="profileCount > 0">
Take a look around and see if you can help them find work!
</div>
<div v-else>
You can click below, but you will not find anything&hellip;
</div>
</v-card-text>
<v-card-actions>
<v-btn @click="searchProfiles">Search Profiles</v-btn>
</v-card-actions>
</v-card>
</v-col>
</v-row>
</load-data> </load-data>
<hr> <p class="spaced">
<p>
To see how this application works, check out &ldquo;How It Works&rdquo; in the sidebar (last updated June To see how this application works, check out &ldquo;How It Works&rdquo; in the sidebar (last updated June
14<sup>th</sup>, 2021). 14<sup>th</sup>, 2021).
</p> </p>
@ -40,13 +76,19 @@
import { defineComponent, Ref, ref } from 'vue' import { defineComponent, Ref, ref } from 'vue'
import api, { LogOnSuccess, Profile } from '../../api' import api, { LogOnSuccess, Profile } from '../../api'
import { useStore } from '../../store' import { useStore } from '../../store'
import LoadData from '../../components/shared/LoadData.vue' import FullDateTime from '../../components/FullDateTime.vue'
import LoadData from '../../components/LoadData.vue'
import { useRouter } from 'vue-router'
export default defineComponent({ export default defineComponent({
name: 'Dashboard', name: 'Dashboard',
components: { LoadData }, components: {
LoadData,
FullDateTime
},
setup () { setup () {
const store = useStore() const store = useStore()
const router = useRouter()
/** The currently logged-in user */ /** The currently logged-in user */
const user = store.state.user as LogOnSuccess const user = store.state.user as LogOnSuccess
@ -76,8 +118,16 @@ export default defineComponent({
retrieveData, retrieveData,
user, user,
profile, profile,
profileCount profileCount,
viewProfile: () => router.push(`/profile/view/${user.citizenId}`),
editProfile: () => router.push('/citizen/profile'),
searchProfiles: () => router.push('/profile/search')
} }
} }
}) })
</script> </script>
<style lang="sass" scoped>
.spaced
margin-top: 1rem
</style>

View File

@ -113,7 +113,7 @@ import { computed, defineComponent, Ref, ref } from 'vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import api, { LogOnSuccess, Profile } from '../../api' import api, { LogOnSuccess, Profile } from '../../api'
import MarkdownEditor from '../../components/MarkdownEditor.vue' import MarkdownEditor from '../../components/MarkdownEditor.vue'
import LoadData from '../../components/shared/LoadData.vue' import LoadData from '../../components/LoadData.vue'
import { useStore } from '../../store' import { useStore } from '../../store'
export default defineComponent({ export default defineComponent({

View File

@ -36,7 +36,7 @@
import { computed, defineComponent, ref, Ref } from 'vue' import { computed, defineComponent, ref, Ref } from 'vue'
import { useRoute, useRouter } from 'vue-router' import { useRoute, useRouter } from 'vue-router'
import marked from 'marked' import marked from 'marked'
import LoadData from '../../components/shared/LoadData.vue' import LoadData from '../../components/LoadData.vue'
import { useStore } from '../../store' import { useStore } from '../../store'
import api, { LogOnSuccess, markedOptions, ProfileForView } from '../../api' import api, { LogOnSuccess, markedOptions, ProfileForView } from '../../api'

View File

@ -10,6 +10,7 @@
"esModuleInterop": true, "esModuleInterop": true,
"allowSyntheticDefaultImports": true, "allowSyntheticDefaultImports": true,
"sourceMap": true, "sourceMap": true,
"resolveJsonModule": true,
"baseUrl": ".", "baseUrl": ".",
"types": [ "types": [
"webpack-env" "webpack-env"