diff --git a/src/JobsJobsJobs/App/src/App.vue b/src/JobsJobsJobs/App/src/App.vue
index 90b0321..7b63736 100644
--- a/src/JobsJobsJobs/App/src/App.vue
+++ b/src/JobsJobsJobs/App/src/App.vue
@@ -10,11 +10,12 @@
diff --git a/src/JobsJobsJobs/App/src/main.ts b/src/JobsJobsJobs/App/src/main.ts
index 7ebd125..07664fa 100644
--- a/src/JobsJobsJobs/App/src/main.ts
+++ b/src/JobsJobsJobs/App/src/main.ts
@@ -3,13 +3,11 @@ import App from "./App.vue"
import router from "./router"
import store, { key } from "./store"
import Icon from "./components/Icon.vue"
-import PageTitle from "./components/PageTitle.vue"
const app = createApp(App)
.use(router)
.use(store, key)
app.component("Icon", Icon)
-app.component("PageTitle", PageTitle)
app.mount("#app")
diff --git a/src/JobsJobsJobs/App/src/router/index.ts b/src/JobsJobsJobs/App/src/router/index.ts
index 1814410..e934cee 100644
--- a/src/JobsJobsJobs/App/src/router/index.ts
+++ b/src/JobsJobsJobs/App/src/router/index.ts
@@ -3,10 +3,9 @@ import {
createWebHistory,
RouteLocationNormalized,
RouteLocationNormalizedLoaded,
- RouteRecordName,
RouteRecordRaw
} from "vue-router"
-import store from "@/store"
+import store, { Mutations } from "@/store"
import Home from "@/views/Home.vue"
import LogOn from "@/views/citizen/LogOn.vue"
@@ -29,124 +28,141 @@ const routes: Array = [
{
path: "/",
name: "Home",
- component: Home
+ component: Home,
+ meta: { title: "Welcome!" }
},
{
path: "/how-it-works",
name: "HowItWorks",
- component: () => import(/* webpackChunkName: "help" */ "../views/HowItWorks.vue")
+ component: () => import(/* webpackChunkName: "help" */ "../views/HowItWorks.vue"),
+ meta: { title: "How It Works" }
},
{
path: "/privacy-policy",
name: "PrivacyPolicy",
- component: () => import(/* webpackChunkName: "legal" */ "../views/PrivacyPolicy.vue")
+ component: () => import(/* webpackChunkName: "legal" */ "../views/PrivacyPolicy.vue"),
+ meta: { title: "Privacy Policy" }
},
{
path: "/terms-of-service",
name: "TermsOfService",
- component: () => import(/* webpackChunkName: "legal" */ "../views/TermsOfService.vue")
+ component: () => import(/* webpackChunkName: "legal" */ "../views/TermsOfService.vue"),
+ meta: { title: "Terms of Service" }
},
// Citizen URLs
{
path: "/citizen/log-on",
name: "LogOn",
- component: LogOn
+ component: LogOn,
+ meta: { title: "Log On" }
},
{
path: "/citizen/:abbr/authorized",
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",
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",
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",
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
{
path: "/help-wanted",
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",
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",
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",
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",
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
{
path: "/profile/:id/view",
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",
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",
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
{
path: "/so-long/options",
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",
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
{
path: "/success-story/list",
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",
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",
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 = [
- "Home", "HowItWorks", "PrivacyPolicy", "TermsOfService", "LogOn", "CitizenAuthorized", "PublicSearchProfiles",
- "DeletionSuccess"
-]
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
@@ -158,11 +174,12 @@ const router = createRouter({
})
// eslint-disable-next-line
-router.beforeEach((to : RouteLocationNormalized, from : RouteLocationNormalized) =>{
- if (store.state.user === undefined && !publicRoutes.includes(to.name ?? "")) {
+router.beforeEach((to : RouteLocationNormalized, from : RouteLocationNormalized) => {
+ if (store.state.user === undefined && (to.meta.auth || false)) {
window.localStorage.setItem(AFTER_LOG_ON_URL, to.fullPath)
return "/citizen/log-on"
}
+ store.commit(Mutations.SetTitle, to.meta.title ?? "")
})
export default router
diff --git a/src/JobsJobsJobs/App/src/store/index.ts b/src/JobsJobsJobs/App/src/store/index.ts
index 3750b91..f919533 100644
--- a/src/JobsJobsJobs/App/src/store/index.ts
+++ b/src/JobsJobsJobs/App/src/store/index.ts
@@ -1,3 +1,4 @@
+import { useTitle } from "@vueuse/core"
import { InjectionKey } from "vue"
import { createStore, Store, useStore as baseUseStore } from "vuex"
import api, { Continent, Instance, LogOnSuccess } from "../api"
@@ -6,14 +7,16 @@ import * as Mutations from "./mutations"
/** The state tracked by the application */
export interface State {
+ /** The document's current title */
+ pageTitle : string
/** The currently logged-on user */
- user: LogOnSuccess | undefined
+ user : LogOnSuccess | undefined
/** The state of the log on process */
- logOnState: string
+ logOnState : string
/** All continents (use `ensureContinents` action) */
- continents: Continent[]
+ continents : Continent[]
/** All instances (use `ensureInstances` action) */
- instances: Instance[]
+ instances : Instance[]
}
/** An injection key to identify this state with Vue */
@@ -24,9 +27,13 @@ export function useStore () : Store {
return baseUseStore(key)
}
+/** The application name */
+const appName = "Jobs, Jobs, Jobs"
+
export default createStore({
state: () : State => {
return {
+ pageTitle: "",
user: undefined,
logOnState: "Welcome back!",
continents: [],
@@ -34,6 +41,10 @@ export default createStore({
}
},
mutations: {
+ [Mutations.SetTitle]: (state, title : string) => {
+ state.pageTitle = title === "" ? appName : `${title} | ${appName}`
+ useTitle(state.pageTitle)
+ },
[Mutations.SetUser]: (state, user : LogOnSuccess) => { state.user = user },
[Mutations.ClearUser]: (state) => { state.user = undefined },
[Mutations.SetLogOnState]: (state, message : string) => { state.logOnState = message },
diff --git a/src/JobsJobsJobs/App/src/store/mutations.ts b/src/JobsJobsJobs/App/src/store/mutations.ts
index fc58676..43ae9e5 100644
--- a/src/JobsJobsJobs/App/src/store/mutations.ts
+++ b/src/JobsJobsJobs/App/src/store/mutations.ts
@@ -1,3 +1,6 @@
+/** Set the page title */
+export const SetTitle = "setTitle"
+
/** Set the logged-on user */
export const SetUser = "setUser"
diff --git a/src/JobsJobsJobs/App/src/views/Home.vue b/src/JobsJobsJobs/App/src/views/Home.vue
index da66610..7052562 100644
--- a/src/JobsJobsJobs/App/src/views/Home.vue
+++ b/src/JobsJobsJobs/App/src/views/Home.vue
@@ -1,6 +1,5 @@
article
- page-title(title="Welcome!")
p
p.
Welcome to Jobs, Jobs, Jobs (AKA No Agenda Careers), where citizens of Gitmo Nation can assist one another in
diff --git a/src/JobsJobsJobs/App/src/views/HowItWorks.vue b/src/JobsJobsJobs/App/src/views/HowItWorks.vue
index 4d3810f..0e8877b 100644
--- a/src/JobsJobsJobs/App/src/views/HowItWorks.vue
+++ b/src/JobsJobsJobs/App/src/views/HowItWorks.vue
@@ -1,6 +1,5 @@
article
- page-title(title="How It Works")
h3 How It Works
h5.pb-3.text-muted: em Last Updated August 29#[sup th], 2021
p: em.
diff --git a/src/JobsJobsJobs/App/src/views/PrivacyPolicy.vue b/src/JobsJobsJobs/App/src/views/PrivacyPolicy.vue
index e77ca25..6ef22f6 100644
--- a/src/JobsJobsJobs/App/src/views/PrivacyPolicy.vue
+++ b/src/JobsJobsJobs/App/src/views/PrivacyPolicy.vue
@@ -1,6 +1,5 @@
article
- page-title(title="Privacy Policy")
h3 Privacy Policy
p: em (as of September 6#[sup th], 2021)
diff --git a/src/JobsJobsJobs/App/src/views/TermsOfService.vue b/src/JobsJobsJobs/App/src/views/TermsOfService.vue
index ceff16c..09cd89a 100644
--- a/src/JobsJobsJobs/App/src/views/TermsOfService.vue
+++ b/src/JobsJobsJobs/App/src/views/TermsOfService.vue
@@ -1,6 +1,5 @@
article
- page-title(title="Terms of Service")
h3 Terms of Service
p: em (as of September 6#[sup th], 2021)
diff --git a/src/JobsJobsJobs/App/src/views/citizen/Authorized.vue b/src/JobsJobsJobs/App/src/views/citizen/Authorized.vue
index 448f61e..3543564 100644
--- a/src/JobsJobsJobs/App/src/views/citizen/Authorized.vue
+++ b/src/JobsJobsJobs/App/src/views/citizen/Authorized.vue
@@ -1,6 +1,5 @@
article
- page-title(title="Logging on...")
p
p(v-html="message")
diff --git a/src/JobsJobsJobs/App/src/views/citizen/Dashboard.vue b/src/JobsJobsJobs/App/src/views/citizen/Dashboard.vue
index 9c1b0fc..736083d 100644
--- a/src/JobsJobsJobs/App/src/views/citizen/Dashboard.vue
+++ b/src/JobsJobsJobs/App/src/views/citizen/Dashboard.vue
@@ -1,6 +1,5 @@
article.container
- page-title(title="Dashboard")
h3.pb-4 Welcome, {{user.name}}
load-data(:load="retrieveData"): .row.row-cols-1.row-cols-md-2
.col: .card.h-100
diff --git a/src/JobsJobsJobs/App/src/views/citizen/EditProfile.vue b/src/JobsJobsJobs/App/src/views/citizen/EditProfile.vue
index e5b459f..a28f43e 100644
--- a/src/JobsJobsJobs/App/src/views/citizen/EditProfile.vue
+++ b/src/JobsJobsJobs/App/src/views/citizen/EditProfile.vue
@@ -1,6 +1,5 @@
article
- page-title(title="Edit Profile")
h3.pb-3 My Employment Profile
load-data(:load="retrieveData"): form.row.g-3
.col-12.col-sm-10.col-md-8.col-lg-6
diff --git a/src/JobsJobsJobs/App/src/views/citizen/LogOff.vue b/src/JobsJobsJobs/App/src/views/citizen/LogOff.vue
index 57506ed..d0a9ab8 100644
--- a/src/JobsJobsJobs/App/src/views/citizen/LogOff.vue
+++ b/src/JobsJobsJobs/App/src/views/citizen/LogOff.vue
@@ -1,6 +1,5 @@
article
- page-title(title="Logging off...")
p
p.fst-italic Logging off…
diff --git a/src/JobsJobsJobs/App/src/views/listing/HelpWanted.vue b/src/JobsJobsJobs/App/src/views/listing/HelpWanted.vue
index 97885dd..39ebbda 100644
--- a/src/JobsJobsJobs/App/src/views/listing/HelpWanted.vue
+++ b/src/JobsJobsJobs/App/src/views/listing/HelpWanted.vue
@@ -1,6 +1,5 @@
article
- page-title(title="Help Wanted")
h3.pb-3 Help Wanted
p(v-if="!searched").
Enter relevant criteria to find results, or just click “Search” to see all current job listings.
diff --git a/src/JobsJobsJobs/App/src/views/listing/ListingEdit.vue b/src/JobsJobsJobs/App/src/views/listing/ListingEdit.vue
index be8c1cb..6e0dfd9 100644
--- a/src/JobsJobsJobs/App/src/views/listing/ListingEdit.vue
+++ b/src/JobsJobsJobs/App/src/views/listing/ListingEdit.vue
@@ -1,6 +1,5 @@
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-else) Edit Job Listing
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 { toastError, toastSuccess } from "@/components/layout/AppToaster.vue"
-import { useStore } from "@/store"
+import { Mutations, useStore } from "@/store"
import ContinentList from "@/components/ContinentList.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) */
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)
if (typeof listResult === "string") {
errors.push(listResult)
diff --git a/src/JobsJobsJobs/App/src/views/listing/ListingExpire.vue b/src/JobsJobsJobs/App/src/views/listing/ListingExpire.vue
index 4364d8d..f6ecc6e 100644
--- a/src/JobsJobsJobs/App/src/views/listing/ListingExpire.vue
+++ b/src/JobsJobsJobs/App/src/views/listing/ListingExpire.vue
@@ -1,6 +1,5 @@
article
- page-title(title="Expire Job Listing")
load-data(:load="retrieveListing")
h3.pb-3 Expire Job Listing ({{listing.title}})
p: em.
diff --git a/src/JobsJobsJobs/App/src/views/listing/ListingView.vue b/src/JobsJobsJobs/App/src/views/listing/ListingView.vue
index 335fb6c..1173bf2 100644
--- a/src/JobsJobsJobs/App/src/views/listing/ListingView.vue
+++ b/src/JobsJobsJobs/App/src/views/listing/ListingView.vue
@@ -1,6 +1,5 @@
article
- page-title(:title="title")
load-data(:load="retrieveListing")
h3
| {{it.listing.title}}
@@ -24,7 +23,7 @@ import { formatNeededBy } from "./"
import api, { Citizen, ListingForView, LogOnSuccess } from "@/api"
import { citizenName } from "@/App.vue"
import { toHtml } from "@/markdown"
-import { useStore } from "@/store"
+import { Mutations, useStore } from "@/store"
import LoadData from "@/components/LoadData.vue"
const store = useStore()
@@ -48,6 +47,7 @@ const retrieveListing = async (errors : string[]) => {
errors.push("Job Listing not found")
} else {
it.value = listingResp
+ store.commit(Mutations.SetTitle, `${listingResp.listing.title} | Job Listing`)
const citizenResp = await api.citizen.retrieve(listingResp.listing.citizenId, user)
if (typeof citizenResp === "string") {
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 */
const details = computed(() => toHtml(it.value?.listing.text ?? ""))
diff --git a/src/JobsJobsJobs/App/src/views/listing/MyListings.vue b/src/JobsJobsJobs/App/src/views/listing/MyListings.vue
index 0f7d815..fce3b5c 100644
--- a/src/JobsJobsJobs/App/src/views/listing/MyListings.vue
+++ b/src/JobsJobsJobs/App/src/views/listing/MyListings.vue
@@ -1,6 +1,5 @@
article
- page-title(title="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
load-data(:load="getListings")
diff --git a/src/JobsJobsJobs/App/src/views/profile/ProfileSearch.vue b/src/JobsJobsJobs/App/src/views/profile/ProfileSearch.vue
index 534393b..fa11cd3 100644
--- a/src/JobsJobsJobs/App/src/views/profile/ProfileSearch.vue
+++ b/src/JobsJobsJobs/App/src/views/profile/ProfileSearch.vue
@@ -1,6 +1,5 @@
article
- page-title(title="Search Profiles")
h3.pb-3 Search Profiles
p(v-if="!searched").
Enter one or more criteria to filter results, or just click “Search” to list all profiles.
@@ -13,23 +12,25 @@ article
thead: tr
th(scope="col") Profile
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") Full-Time?
- th(scope="col") Last Updated
+ th.text-center(scope="col" v-if="wideDisplay") Full-Time?
+ th(scope="col" v-if="wideDisplay") Last Updated
tbody: tr(v-for="profile in results" :key="profile.citzenId")
td: router-link(:to="`/profile/${profile.citizenId}/view`") View
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.fullTime)}}
- td: full-date(:date="profile.lastUpdatedOn")
+ td.text-center(v-if="wideDisplay") {{yesOrNo(profile.fullTime)}}
+ td(v-if="wideDisplay"): full-date(:date="profile.lastUpdatedOn")
p.pt-3(v-else-if="searched") No results found for the specified criteria