Mobile layout / .NET 6 #28

Merged
danieljsummers merged 4 commits from v2-mobile into main 2021-09-17 16:13:33 +00:00
27 changed files with 93 additions and 108 deletions
Showing only changes of commit 7ee3d86662 - Show all commits

View File

@ -10,11 +10,12 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent } from "vue" import { defineComponent, onMounted } from "vue"
import "bootstrap/dist/css/bootstrap.min.css" import "bootstrap/dist/css/bootstrap.min.css"
import { Citizen } from "./api" import { Citizen } from "./api"
import { Mutations, useStore } from "./store"
import AppFooter from "./components/layout/AppFooter.vue" import AppFooter from "./components/layout/AppFooter.vue"
import AppNav from "./components/layout/AppNav.vue" import AppNav from "./components/layout/AppNav.vue"
import AppToaster from "./components/layout/AppToaster.vue" import AppToaster from "./components/layout/AppToaster.vue"
@ -29,6 +30,10 @@ export default defineComponent({
} }
}) })
const store = useStore()
onMounted(() => store.commit(Mutations.SetTitle, "Jobs, Jobs, Jobs"))
/** /**
* Return "Yes" for true and "No" for false * Return "Yes" for true and "No" for false
* *

View File

@ -1,28 +0,0 @@
<template lang="pug">
p(v-if="false")
</template>
<script setup lang="ts">
import { onMounted, watch } from "vue"
const props = defineProps<{
title: string
}>()
/** The name of the application */
const appName = "Jobs, Jobs, Jobs"
/** Set the page title based on the input title attribute */
const setTitle = () => {
if (props.title === "") {
document.title = appName
} else {
document.title = `${props.title} | ${appName}`
}
}
onMounted(setTitle)
/** Change the page title when the property changes */
watch(() => props.title, setTitle)
</script>

View File

@ -3,13 +3,11 @@ import App from "./App.vue"
import router from "./router" import router from "./router"
import store, { key } from "./store" import store, { key } from "./store"
import Icon from "./components/Icon.vue" import Icon from "./components/Icon.vue"
import PageTitle from "./components/PageTitle.vue"
const app = createApp(App) const app = createApp(App)
.use(router) .use(router)
.use(store, key) .use(store, key)
app.component("Icon", Icon) app.component("Icon", Icon)
app.component("PageTitle", PageTitle)
app.mount("#app") app.mount("#app")

View File

@ -3,10 +3,9 @@ import {
createWebHistory, createWebHistory,
RouteLocationNormalized, RouteLocationNormalized,
RouteLocationNormalizedLoaded, RouteLocationNormalizedLoaded,
RouteRecordName,
RouteRecordRaw RouteRecordRaw
} from "vue-router" } from "vue-router"
import store from "@/store" import store, { Mutations } from "@/store"
import Home from "@/views/Home.vue" import Home from "@/views/Home.vue"
import LogOn from "@/views/citizen/LogOn.vue" import LogOn from "@/views/citizen/LogOn.vue"
@ -29,124 +28,141 @@ const routes: Array<RouteRecordRaw> = [
{ {
path: "/", path: "/",
name: "Home", name: "Home",
component: Home component: Home,
meta: { title: "Welcome!" }
}, },
{ {
path: "/how-it-works", path: "/how-it-works",
name: "HowItWorks", name: "HowItWorks",
component: () => import(/* webpackChunkName: "help" */ "../views/HowItWorks.vue") component: () => import(/* webpackChunkName: "help" */ "../views/HowItWorks.vue"),
meta: { title: "How It Works" }
}, },
{ {
path: "/privacy-policy", path: "/privacy-policy",
name: "PrivacyPolicy", name: "PrivacyPolicy",
component: () => import(/* webpackChunkName: "legal" */ "../views/PrivacyPolicy.vue") component: () => import(/* webpackChunkName: "legal" */ "../views/PrivacyPolicy.vue"),
meta: { title: "Privacy Policy" }
}, },
{ {
path: "/terms-of-service", path: "/terms-of-service",
name: "TermsOfService", name: "TermsOfService",
component: () => import(/* webpackChunkName: "legal" */ "../views/TermsOfService.vue") component: () => import(/* webpackChunkName: "legal" */ "../views/TermsOfService.vue"),
meta: { title: "Terms of Service" }
}, },
// Citizen URLs // Citizen URLs
{ {
path: "/citizen/log-on", path: "/citizen/log-on",
name: "LogOn", name: "LogOn",
component: LogOn component: LogOn,
meta: { title: "Log On" }
}, },
{ {
path: "/citizen/:abbr/authorized", path: "/citizen/:abbr/authorized",
name: "CitizenAuthorized", name: "CitizenAuthorized",
component: () => import(/* webpackChunkName: "dashboard" */ "../views/citizen/Authorized.vue") component: () => import(/* webpackChunkName: "dashboard" */ "../views/citizen/Authorized.vue"),
meta: { title: "Logging On" }
}, },
{ {
path: "/citizen/dashboard", path: "/citizen/dashboard",
name: "Dashboard", name: "Dashboard",
component: () => import(/* webpackChunkName: "dashboard" */ "../views/citizen/Dashboard.vue") component: () => import(/* webpackChunkName: "dashboard" */ "../views/citizen/Dashboard.vue"),
meta: { auth: true, title: "Dashboard" }
}, },
{ {
path: "/citizen/profile", path: "/citizen/profile",
name: "EditProfile", name: "EditProfile",
component: () => import(/* webpackChunkName: "profedit" */ "../views/citizen/EditProfile.vue") component: () => import(/* webpackChunkName: "profedit" */ "../views/citizen/EditProfile.vue"),
meta: { auth: true, title: "Edit Profile" }
}, },
{ {
path: "/citizen/log-off", path: "/citizen/log-off",
name: "LogOff", name: "LogOff",
component: () => import(/* webpackChunkName: "logoff" */ "../views/citizen/LogOff.vue") component: () => import(/* webpackChunkName: "logoff" */ "../views/citizen/LogOff.vue"),
meta: { auth: true, title: "Logging Off" }
}, },
// Job Listing URLs // Job Listing URLs
{ {
path: "/help-wanted", path: "/help-wanted",
name: "HelpWanted", name: "HelpWanted",
component: () => import(/* webpackChunkName: "joblist" */ "../views/listing/HelpWanted.vue") component: () => import(/* webpackChunkName: "joblist" */ "../views/listing/HelpWanted.vue"),
meta: { auth: true, title: "Help Wanted" }
}, },
{ {
path: "/listing/:id/edit", path: "/listing/:id/edit",
name: "EditListing", name: "EditListing",
component: () => import(/* webpackChunkName: "jobedit" */ "../views/listing/ListingEdit.vue") component: () => import(/* webpackChunkName: "jobedit" */ "../views/listing/ListingEdit.vue"),
meta: { auth: true, title: "Edit Job Listing" }
}, },
{ {
path: "/listing/:id/expire", path: "/listing/:id/expire",
name: "ExpireListing", name: "ExpireListing",
component: () => import(/* webpackChunkName: "jobedit" */ "../views/listing/ListingExpire.vue") component: () => import(/* webpackChunkName: "jobedit" */ "../views/listing/ListingExpire.vue"),
meta: { auth: true, title: "Expire Job Listing" }
}, },
{ {
path: "/listing/:id/view", path: "/listing/:id/view",
name: "ViewListing", name: "ViewListing",
component: () => import(/* webpackChunkName: "joblist" */ "../views/listing/ListingView.vue") component: () => import(/* webpackChunkName: "joblist" */ "../views/listing/ListingView.vue"),
meta: { auth: true, title: "Loading Job Listing..." }
}, },
{ {
path: "/listings/mine", path: "/listings/mine",
name: "MyListings", name: "MyListings",
component: () => import(/* webpackChunkName: "joblist" */ "../views/listing/MyListings.vue") component: () => import(/* webpackChunkName: "joblist" */ "../views/listing/MyListings.vue"),
meta: { auth: true, title: "My Job Listings" }
}, },
// Profile URLs // Profile URLs
{ {
path: "/profile/:id/view", path: "/profile/:id/view",
name: "ViewProfile", name: "ViewProfile",
component: () => import(/* webpackChunkName: "profview" */ "../views/profile/ProfileView.vue") component: () => import(/* webpackChunkName: "profview" */ "../views/profile/ProfileView.vue"),
meta: { auth: true, title: "Loading Profile..." }
}, },
{ {
path: "/profile/search", path: "/profile/search",
name: "SearchProfiles", name: "SearchProfiles",
component: () => import(/* webpackChunkName: "profview" */ "../views/profile/ProfileSearch.vue") component: () => import(/* webpackChunkName: "profview" */ "../views/profile/ProfileSearch.vue"),
meta: { auth: true, title: "Search Profiles" }
}, },
{ {
path: "/profile/seeking", path: "/profile/seeking",
name: "PublicSearchProfiles", name: "PublicSearchProfiles",
component: () => import(/* webpackChunkName: "seeking" */ "../views/profile/Seeking.vue") component: () => import(/* webpackChunkName: "seeking" */ "../views/profile/Seeking.vue"),
meta: { auth: false, title: "People Seeking Work" }
}, },
// "So Long" URLs // "So Long" URLs
{ {
path: "/so-long/options", path: "/so-long/options",
name: "DeletionOptions", name: "DeletionOptions",
component: () => import(/* webpackChunkName: "so-long" */ "../views/so-long/DeletionOptions.vue") component: () => import(/* webpackChunkName: "so-long" */ "../views/so-long/DeletionOptions.vue"),
meta: { auth: true, title: "Account Deletion Options" }
}, },
{ {
path: "/so-long/success/:abbr", path: "/so-long/success/:abbr",
name: "DeletionSuccess", name: "DeletionSuccess",
component: () => import(/* webpackChunkName: "so-long" */ "../views/so-long/DeletionSuccess.vue") component: () => import(/* webpackChunkName: "so-long" */ "../views/so-long/DeletionSuccess.vue"),
meta: { auth: false, title: "Account Deletion Success" }
}, },
// Success Story URLs // Success Story URLs
{ {
path: "/success-story/list", path: "/success-story/list",
name: "ListStories", name: "ListStories",
component: () => import(/* webpackChunkName: "success" */ "../views/success-story/StoryList.vue") component: () => import(/* webpackChunkName: "success" */ "../views/success-story/StoryList.vue"),
meta: { auth: false, title: "Success Stories" }
}, },
{ {
path: "/success-story/:id/edit", path: "/success-story/:id/edit",
name: "EditStory", name: "EditStory",
component: () => import(/* webpackChunkName: "succedit" */ "../views/success-story/StoryEdit.vue") component: () => import(/* webpackChunkName: "succedit" */ "../views/success-story/StoryEdit.vue"),
meta: { auth: false, title: "Edit Success Story" }
}, },
{ {
path: "/success-story/:id/view", path: "/success-story/:id/view",
name: "ViewStory", name: "ViewStory",
component: () => import(/* webpackChunkName: "success" */ "../views/success-story/StoryView.vue") component: () => import(/* webpackChunkName: "success" */ "../views/success-story/StoryView.vue"),
meta: { auth: false, title: "Success Story" }
} }
] ]
/** The routes that do not require logins */
const publicRoutes : Array<RouteRecordName> = [
"Home", "HowItWorks", "PrivacyPolicy", "TermsOfService", "LogOn", "CitizenAuthorized", "PublicSearchProfiles",
"DeletionSuccess"
]
const router = createRouter({ const router = createRouter({
history: createWebHistory(process.env.BASE_URL), history: createWebHistory(process.env.BASE_URL),
@ -158,11 +174,12 @@ const router = createRouter({
}) })
// eslint-disable-next-line // eslint-disable-next-line
router.beforeEach((to : RouteLocationNormalized, from : RouteLocationNormalized) =>{ router.beforeEach((to : RouteLocationNormalized, from : RouteLocationNormalized) => {
if (store.state.user === undefined && !publicRoutes.includes(to.name ?? "")) { if (store.state.user === undefined && (to.meta.auth || false)) {
window.localStorage.setItem(AFTER_LOG_ON_URL, to.fullPath) window.localStorage.setItem(AFTER_LOG_ON_URL, to.fullPath)
return "/citizen/log-on" return "/citizen/log-on"
} }
store.commit(Mutations.SetTitle, to.meta.title ?? "")
}) })
export default router export default router

View File

@ -1,3 +1,4 @@
import { useTitle } from "@vueuse/core"
import { InjectionKey } from "vue" import { InjectionKey } from "vue"
import { createStore, Store, useStore as baseUseStore } from "vuex" import { createStore, Store, useStore as baseUseStore } from "vuex"
import api, { Continent, Instance, LogOnSuccess } from "../api" import api, { Continent, Instance, LogOnSuccess } from "../api"
@ -6,14 +7,16 @@ import * as Mutations from "./mutations"
/** The state tracked by the application */ /** The state tracked by the application */
export interface State { export interface State {
/** The document's current title */
pageTitle : string
/** The currently logged-on user */ /** The currently logged-on user */
user: LogOnSuccess | undefined user : LogOnSuccess | undefined
/** The state of the log on process */ /** The state of the log on process */
logOnState: string logOnState : string
/** All continents (use `ensureContinents` action) */ /** All continents (use `ensureContinents` action) */
continents: Continent[] continents : Continent[]
/** All instances (use `ensureInstances` action) */ /** All instances (use `ensureInstances` action) */
instances: Instance[] instances : Instance[]
} }
/** An injection key to identify this state with Vue */ /** An injection key to identify this state with Vue */
@ -24,9 +27,13 @@ export function useStore () : Store<State> {
return baseUseStore(key) return baseUseStore(key)
} }
/** The application name */
const appName = "Jobs, Jobs, Jobs"
export default createStore({ export default createStore({
state: () : State => { state: () : State => {
return { return {
pageTitle: "",
user: undefined, user: undefined,
logOnState: "<em>Welcome back!</em>", logOnState: "<em>Welcome back!</em>",
continents: [], continents: [],
@ -34,6 +41,10 @@ export default createStore({
} }
}, },
mutations: { mutations: {
[Mutations.SetTitle]: (state, title : string) => {
state.pageTitle = title === "" ? appName : `${title} | ${appName}`
useTitle(state.pageTitle)
},
[Mutations.SetUser]: (state, user : LogOnSuccess) => { state.user = user }, [Mutations.SetUser]: (state, user : LogOnSuccess) => { state.user = user },
[Mutations.ClearUser]: (state) => { state.user = undefined }, [Mutations.ClearUser]: (state) => { state.user = undefined },
[Mutations.SetLogOnState]: (state, message : string) => { state.logOnState = message }, [Mutations.SetLogOnState]: (state, message : string) => { state.logOnState = message },

View File

@ -1,3 +1,6 @@
/** Set the page title */
export const SetTitle = "setTitle"
/** Set the logged-on user */ /** Set the logged-on user */
export const SetUser = "setUser" export const SetUser = "setUser"

View File

@ -1,6 +1,5 @@
<template lang="pug"> <template lang="pug">
article article
page-title(title="Welcome!")
p &nbsp; p &nbsp;
p. p.
Welcome to Jobs, Jobs, Jobs (AKA No Agenda Careers), where citizens of Gitmo Nation can assist one another in Welcome to Jobs, Jobs, Jobs (AKA No Agenda Careers), where citizens of Gitmo Nation can assist one another in

View File

@ -1,6 +1,5 @@
<template lang="pug"> <template lang="pug">
article article
page-title(title="How It Works")
h3 How It Works h3 How It Works
h5.pb-3.text-muted: em Last Updated August 29#[sup th], 2021 h5.pb-3.text-muted: em Last Updated August 29#[sup th], 2021
p: em. p: em.

View File

@ -1,6 +1,5 @@
<template lang="pug"> <template lang="pug">
article article
page-title(title="Privacy Policy")
h3 Privacy Policy h3 Privacy Policy
p: em (as of September 6#[sup th], 2021) p: em (as of September 6#[sup th], 2021)

View File

@ -1,6 +1,5 @@
<template lang="pug"> <template lang="pug">
article article
page-title(title="Terms of Service")
h3 Terms of Service h3 Terms of Service
p: em (as of September 6#[sup th], 2021) p: em (as of September 6#[sup th], 2021)

View File

@ -1,6 +1,5 @@
<template lang="pug"> <template lang="pug">
article article
page-title(title="Logging on...")
p &nbsp; p &nbsp;
p(v-html="message") p(v-html="message")
</template> </template>

View File

@ -1,6 +1,5 @@
<template lang="pug"> <template lang="pug">
article.container article.container
page-title(title="Dashboard")
h3.pb-4 Welcome, {{user.name}} h3.pb-4 Welcome, {{user.name}}
load-data(:load="retrieveData"): .row.row-cols-1.row-cols-md-2 load-data(:load="retrieveData"): .row.row-cols-1.row-cols-md-2
.col: .card.h-100 .col: .card.h-100

View File

@ -1,6 +1,5 @@
<template lang="pug"> <template lang="pug">
article article
page-title(title="Edit Profile")
h3.pb-3 My Employment Profile h3.pb-3 My Employment Profile
load-data(:load="retrieveData"): form.row.g-3 load-data(:load="retrieveData"): form.row.g-3
.col-12.col-sm-10.col-md-8.col-lg-6 .col-12.col-sm-10.col-md-8.col-lg-6

View File

@ -1,6 +1,5 @@
<template lang="pug"> <template lang="pug">
article article
page-title(title="Logging off...")
p &nbsp; p &nbsp;
p.fst-italic Logging off&hellip; p.fst-italic Logging off&hellip;
</template> </template>

View File

@ -1,6 +1,5 @@
<template lang="pug"> <template lang="pug">
article article
page-title(title="Help Wanted")
h3.pb-3 Help Wanted h3.pb-3 Help Wanted
p(v-if="!searched"). p(v-if="!searched").
Enter relevant criteria to find results, or just click &ldquo;Search&rdquo; to see all current job listings. Enter relevant criteria to find results, or just click &ldquo;Search&rdquo; to see all current job listings.

View File

@ -1,6 +1,5 @@
<template lang="pug"> <template lang="pug">
article article
page-title(:title="isNew ? 'Add a Job Listing' : 'Edit Job Listing'")
h3.pb-3(v-if="isNew") Add a Job Listing h3.pb-3(v-if="isNew") Add a Job Listing
h3.pb-3(v-else) Edit Job Listing h3.pb-3(v-else) Edit Job Listing
load-data(:load="retrieveData"): form.row.g-3 load-data(:load="retrieveData"): form.row.g-3
@ -44,7 +43,7 @@ import { required } from "@vuelidate/validators"
import api, { Listing, ListingForm, LogOnSuccess } from "@/api" import api, { Listing, ListingForm, LogOnSuccess } from "@/api"
import { toastError, toastSuccess } from "@/components/layout/AppToaster.vue" import { toastError, toastSuccess } from "@/components/layout/AppToaster.vue"
import { useStore } from "@/store" import { Mutations, useStore } from "@/store"
import ContinentList from "@/components/ContinentList.vue" import ContinentList from "@/components/ContinentList.vue"
import LoadData from "@/components/LoadData.vue" import LoadData from "@/components/LoadData.vue"
@ -99,6 +98,7 @@ const v$ = useVuelidate(rules, listing, { $lazy: true })
/** Retrieve the listing being edited (or set up the form for a new listing) */ /** Retrieve the listing being edited (or set up the form for a new listing) */
const retrieveData = async (errors : string[]) => { const retrieveData = async (errors : string[]) => {
if (isNew.value) store.commit(Mutations.SetTitle, "Add a Job Listing")
const listResult = isNew.value ? newListing : await api.listings.retreive(id, user) const listResult = isNew.value ? newListing : await api.listings.retreive(id, user)
if (typeof listResult === "string") { if (typeof listResult === "string") {
errors.push(listResult) errors.push(listResult)

View File

@ -1,6 +1,5 @@
<template lang="pug"> <template lang="pug">
article article
page-title(title="Expire Job Listing")
load-data(:load="retrieveListing") load-data(:load="retrieveListing")
h3.pb-3 Expire Job Listing ({{listing.title}}) h3.pb-3 Expire Job Listing ({{listing.title}})
p: em. p: em.

View File

@ -1,6 +1,5 @@
<template lang="pug"> <template lang="pug">
article article
page-title(:title="title")
load-data(:load="retrieveListing") load-data(:load="retrieveListing")
h3 h3
| {{it.listing.title}} | {{it.listing.title}}
@ -24,7 +23,7 @@ import { formatNeededBy } from "./"
import api, { Citizen, ListingForView, LogOnSuccess } from "@/api" import api, { Citizen, ListingForView, LogOnSuccess } from "@/api"
import { citizenName } from "@/App.vue" import { citizenName } from "@/App.vue"
import { toHtml } from "@/markdown" import { toHtml } from "@/markdown"
import { useStore } from "@/store" import { Mutations, useStore } from "@/store"
import LoadData from "@/components/LoadData.vue" import LoadData from "@/components/LoadData.vue"
const store = useStore() const store = useStore()
@ -48,6 +47,7 @@ const retrieveListing = async (errors : string[]) => {
errors.push("Job Listing not found") errors.push("Job Listing not found")
} else { } else {
it.value = listingResp it.value = listingResp
store.commit(Mutations.SetTitle, `${listingResp.listing.title} | Job Listing`)
const citizenResp = await api.citizen.retrieve(listingResp.listing.citizenId, user) const citizenResp = await api.citizen.retrieve(listingResp.listing.citizenId, user)
if (typeof citizenResp === "string") { if (typeof citizenResp === "string") {
errors.push(citizenResp) errors.push(citizenResp)
@ -59,9 +59,6 @@ const retrieveListing = async (errors : string[]) => {
} }
} }
/** The page title (changes once the listing is loaded) */
const title = computed(() => it.value ? `${it.value.listing.title} | Job Listing` : "Loading Job Listing...")
/** The HTML details of the job listing */ /** The HTML details of the job listing */
const details = computed(() => toHtml(it.value?.listing.text ?? "")) const details = computed(() => toHtml(it.value?.listing.text ?? ""))

View File

@ -1,6 +1,5 @@
<template lang="pug"> <template lang="pug">
article article
page-title(title="My Job Listings")
h3.pb-3 My Job Listings h3.pb-3 My Job Listings
p: router-link.btn.btn-outline-primary(to="/listing/new/edit") Add a New Job Listing p: router-link.btn.btn-outline-primary(to="/listing/new/edit") Add a New Job Listing
load-data(:load="getListings") load-data(:load="getListings")

View File

@ -1,6 +1,5 @@
<template lang="pug"> <template lang="pug">
article article
page-title(title="Search Profiles")
h3.pb-3 Search Profiles h3.pb-3 Search Profiles
p(v-if="!searched"). p(v-if="!searched").
Enter one or more criteria to filter results, or just click &ldquo;Search&rdquo; to list all profiles. Enter one or more criteria to filter results, or just click &ldquo;Search&rdquo; to list all profiles.
@ -13,23 +12,25 @@ article
thead: tr thead: tr
th(scope="col") Profile th(scope="col") Profile
th(scope="col") Name th(scope="col") Name
th.text-center(scope="col") Seeking? th.text-center(scope="col" v-if="wideDisplay") Seeking?
th.text-center(scope="col") Remote? th.text-center(scope="col") Remote?
th.text-center(scope="col") Full-Time? th.text-center(scope="col" v-if="wideDisplay") Full-Time?
th(scope="col") Last Updated th(scope="col" v-if="wideDisplay") Last Updated
tbody: tr(v-for="profile in results" :key="profile.citzenId") tbody: tr(v-for="profile in results" :key="profile.citzenId")
td: router-link(:to="`/profile/${profile.citizenId}/view`") View td: router-link(:to="`/profile/${profile.citizenId}/view`") View
td(:class="{ 'fw-bold' : profile.seekingEmployment }") {{profile.displayName}} td(:class="{ 'fw-bold' : profile.seekingEmployment }") {{profile.displayName}}
td.text-center {{yesOrNo(profile.seekingEmployment)}} td.text-center(v-if="wideDisplay") {{yesOrNo(profile.seekingEmployment)}}
td.text-center {{yesOrNo(profile.remoteWork)}} td.text-center {{yesOrNo(profile.remoteWork)}}
td.text-center {{yesOrNo(profile.fullTime)}} td.text-center(v-if="wideDisplay") {{yesOrNo(profile.fullTime)}}
td: full-date(:date="profile.lastUpdatedOn") td(v-if="wideDisplay"): full-date(:date="profile.lastUpdatedOn")
p.pt-3(v-else-if="searched") No results found for the specified criteria p.pt-3(v-else-if="searched") No results found for the specified criteria
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { defineComponent, Ref, ref, watch } from "vue" import { Ref, ref, watch } from "vue"
import { useRoute, useRouter } from "vue-router" import { useRoute, useRouter } from "vue-router"
import { useBreakpoints, breakpointsBootstrapV5 } from "@vueuse/core"
import { yesOrNo } from "@/App.vue" import { yesOrNo } from "@/App.vue"
import api, { LogOnSuccess, ProfileSearch, ProfileSearchResult } from "@/api" import api, { LogOnSuccess, ProfileSearch, ProfileSearchResult } from "@/api"
import { queryValue } from "@/router" import { queryValue } from "@/router"
@ -43,6 +44,7 @@ import ProfileSearchForm from "@/components/profile/SearchForm.vue"
const store = useStore() const store = useStore()
const route = useRoute() const route = useRoute()
const router = useRouter() const router = useRouter()
const breakpoints = useBreakpoints(breakpointsBootstrapV5)
/** Any errors encountered while retrieving data */ /** Any errors encountered while retrieving data */
const errors : Ref<string[]> = ref([]) const errors : Ref<string[]> = ref([])
@ -70,6 +72,9 @@ const results : Ref<ProfileSearchResult[]> = ref([])
/** Whether the search criteria should be collapsed */ /** Whether the search criteria should be collapsed */
const isCollapsed = ref(searched.value && results.value.length > 0) const isCollapsed = ref(searched.value && results.value.length > 0)
/** Hide certain columns if the display is too narrow */
const wideDisplay = breakpoints.greater("sm")
/** Set up the page to match its requested state */ /** Set up the page to match its requested state */
const setUpPage = async () => { const setUpPage = async () => {
if (queryValue(route, "searched") === "true") { if (queryValue(route, "searched") === "true") {

View File

@ -34,7 +34,7 @@ import { mdiPencil } from "@mdi/js"
import api, { LogOnSuccess, ProfileForView } from "@/api" import api, { LogOnSuccess, ProfileForView } from "@/api"
import { citizenName } from "@/App.vue" import { citizenName } from "@/App.vue"
import { toHtml } from "@/markdown" import { toHtml } from "@/markdown"
import { useStore } from "@/store" import { Mutations, useStore } from "@/store"
import LoadData from "@/components/LoadData.vue" import LoadData from "@/components/LoadData.vue"
const store = useStore() const store = useStore()
@ -66,14 +66,10 @@ const retrieveProfile = async (errors : string[]) => {
errors.push("Profile not found") errors.push("Profile not found")
} else { } else {
it.value = profileResp it.value = profileResp
store.commit(Mutations.SetTitle, `Employment profile for ${citizenName(profileResp.citizen)}`)
} }
} }
/** The title of the page (changes once the profile is loaded) */
const title = computed(() => it.value
? `Employment profile for ${citizenName(it.value.citizen)}`
: "Loading Profile...")
/** The HTML version of the citizen's professional biography */ /** The HTML version of the citizen's professional biography */
const bioHtml = computed(() => toHtml(it.value?.profile.biography ?? "")) const bioHtml = computed(() => toHtml(it.value?.profile.biography ?? ""))

View File

@ -1,6 +1,5 @@
<template lang="pug"> <template lang="pug">
article article
page-title(title="People Seeking Work")
h3.pb-3 People Seeking Work h3.pb-3 People Seeking Work
p(v-if="!searched"). p(v-if="!searched").
Enter one or more criteria to filter results, or just click &ldquo;Search&rdquo; to list all profiles. Enter one or more criteria to filter results, or just click &ldquo;Search&rdquo; to list all profiles.

View File

@ -1,6 +1,5 @@
<template lang="pug"> <template lang="pug">
article article
page-title(title="Account Deletion Options")
h3.pb-3 Account Deletion Options h3.pb-3 Account Deletion Options
h4.pb-3 Option 1 &ndash; Delete Your Profile h4.pb-3 Option 1 &ndash; Delete Your Profile
p. p.

View File

@ -1,6 +1,5 @@
<template lang="pug"> <template lang="pug">
article article
page-title(title="Account Deletion Success")
h3.pb-3 Account Deletion Success h3.pb-3 Account Deletion Success
p. p.
Your account has been successfully deleted. To revoke the permissions you have previously granted to this Your account has been successfully deleted. To revoke the permissions you have previously granted to this

View File

@ -1,6 +1,5 @@
<template lang="pug"> <template lang="pug">
article article
page-title(:title="title")
h3.pb-3 {{title}} h3.pb-3 {{title}}
load-data(:load="retrieveStory") load-data(:load="retrieveStory")
p(v-if="isNew"). p(v-if="isNew").
@ -26,7 +25,7 @@ import useVuelidate from "@vuelidate/core"
import api, { LogOnSuccess, StoryForm } from "@/api" import api, { LogOnSuccess, StoryForm } from "@/api"
import { toastError, toastSuccess } from "@/components/layout/AppToaster.vue" import { toastError, toastSuccess } from "@/components/layout/AppToaster.vue"
import { useStore } from "@/store" import { Mutations, useStore } from "@/store"
import LoadData from "@/components/LoadData.vue" import LoadData from "@/components/LoadData.vue"
import MarkdownEditor from "@/components/MarkdownEditor.vue" import MarkdownEditor from "@/components/MarkdownEditor.vue"
@ -45,9 +44,6 @@ const id = route.params.id as string
/** Whether this is a new story */ /** Whether this is a new story */
const isNew = computed(() => id === "new") const isNew = computed(() => id === "new")
/** The page title */
const title = computed(() => isNew.value ? "Tell Your Success Story" : "Edit Success Story")
/** The form for editing the story */ /** The form for editing the story */
const story = reactive(new StoryForm()) const story = reactive(new StoryForm())
@ -64,6 +60,7 @@ const v$ = useVuelidate(rules, story, { $lazy: true })
const retrieveStory = async (errors : string[]) => { const retrieveStory = async (errors : string[]) => {
if (isNew.value) { if (isNew.value) {
story.id = "new" story.id = "new"
store.commit(Mutations.SetTitle, "Tell Your Success Story")
} else { } else {
const storyResult = await api.success.retrieve(id, user) const storyResult = await api.success.retrieve(id, user)
if (typeof storyResult === "string") { if (typeof storyResult === "string") {

View File

@ -1,6 +1,5 @@
<template lang="pug"> <template lang="pug">
article article
page-title(title="Success Stories")
h3.pb-3 Success Stories h3.pb-3 Success Stories
load-data(:load="retrieveStories") load-data(:load="retrieveStories")
table.table.table-sm.table-hover(v-if="stories?.length > 0") table.table.table-sm.table-hover(v-if="stories?.length > 0")

View File

@ -1,6 +1,5 @@
<template lang="pug"> <template lang="pug">
article article
page-title(title="Success Story")
load-data(:load="retrieveStory") load-data(:load="retrieveStory")
h3 h3
| {{citizenName}}&rsquo;s Success Story | {{citizenName}}&rsquo;s Success Story