Finish expire; mod Success Story
Add label display to several view pages; fix lint errors
This commit is contained in:
parent
8c2ff4c84d
commit
144c34919c
|
@ -489,7 +489,7 @@ module Listing =
|
|||
let! _ =
|
||||
r.Table(Table.Listing)
|
||||
.Get(listingId)
|
||||
.Update(r.HashMap("isExpired", true).With("fromHere", fromHere).With("updatedOn", now))
|
||||
.Update(r.HashMap("isExpired", true).With("wasFilledHere", fromHere).With("updatedOn", now))
|
||||
.RunWriteAsync conn
|
||||
()
|
||||
})
|
||||
|
@ -569,4 +569,5 @@ module Success =
|
|||
it.G("naUser")))
|
||||
.With("hasStory", it.G("story").Default_("").Gt(""))))
|
||||
.Pluck("id", "citizenId", "citizenName", "recordedOn", "fromHere", "hasStory")
|
||||
.OrderBy(r.Desc("recordedOn"))
|
||||
.RunResultAsync<StoryEntry list> conn)
|
||||
|
|
|
@ -22,7 +22,7 @@ module.exports = {
|
|||
"no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off",
|
||||
"vue/no-multiple-template-root": "off",
|
||||
"vue/script-setup-uses-vars": 1,
|
||||
"quotes": ["error", "double", { avoidEscape: true }],
|
||||
"quotes": ["error", "double", { avoidEscape: true, allowTemplateLiterals: true }],
|
||||
"func-call-spacing": "off",
|
||||
"@typescript-eslint/no-unused-vars": "off"
|
||||
}
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
app-nav
|
||||
.jjj-main
|
||||
title-bar
|
||||
main.container-fluid: router-view(v-slot="{ Component }"): transition(name='fade' mode='out-in')
|
||||
component(:is='Component')
|
||||
main.container-fluid: router-view(v-slot="{ Component }"): transition(name="fade" mode="out-in")
|
||||
component(:is="Component")
|
||||
app-footer
|
||||
app-toaster
|
||||
</template>
|
||||
|
@ -63,6 +63,10 @@ a:not(.btn):hover
|
|||
label.jjj-required::after
|
||||
color: red
|
||||
content: ' *'
|
||||
.jjj-heading-label
|
||||
display: inline-block
|
||||
font-size: 1rem
|
||||
text-transform: uppercase
|
||||
// Styles for this component
|
||||
.jjj-app
|
||||
display: flex
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { parseJSON } from 'date-fns'
|
||||
import { utcToZonedTime } from 'date-fns-tz'
|
||||
import { parseJSON } from "date-fns"
|
||||
import { utcToZonedTime } from "date-fns-tz"
|
||||
|
||||
/**
|
||||
* Parse a date from its JSON representation to a UTC-aligned date
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
nav.navbar.navbar-light.bg-light
|
||||
span
|
||||
span.navbar-text.
|
||||
(…and Jobs – #[audio-clip(clip="pelosi-jobs") Let's Vote for Jobs!])
|
||||
(…and Jobs – #[audio-clip(clip="pelosi-jobs") Let’s Vote for Jobs!])
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
|
|
@ -9,7 +9,7 @@ article
|
|||
p.
|
||||
Do you not understand the terms in the paragraph above? No worries; just head over to
|
||||
#[a(href="https://noagendashow.net" target="_blank") The Best Podcast in the Universe]
|
||||
#[em #[audio-clip(clip="thats-true") (that’s true!)]] and find out what you’re missing.
|
||||
#[= " "]#[em #[audio-clip(clip="thats-true") (that’s true!)]] and find out what you’re missing.
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
|
|
@ -5,13 +5,13 @@ article
|
|||
p: em (as of February 6#[sup th], 2021)
|
||||
|
||||
p.
|
||||
{{name}} (“we,” “our,” or “us”) is committed to protecting your privacy. This Privacy Policy explains how your
|
||||
personal information is collected, used, and disclosed by {{name}}.
|
||||
{{name}} (“we,” “our,” or “us”) is committed to protecting your privacy. This
|
||||
Privacy Policy explains how your personal information is collected, used, and disclosed by {{name}}.
|
||||
p.
|
||||
This Privacy Policy applies to our website, and its associated subdomains (collectively, our “Service”) alongside
|
||||
our application, {{name}}. By accessing or using our Service, you signify that you have read, understood, and agree
|
||||
to our collection, storage, use, and disclosure of your personal information as described in this Privacy Policy and
|
||||
our Terms of Service.
|
||||
This Privacy Policy applies to our website, and its associated subdomains (collectively, our “Service”)
|
||||
alongside our application, {{name}}. By accessing or using our Service, you signify that you have read, understood,
|
||||
and agree to our collection, storage, use, and disclosure of your personal information as described in this Privacy
|
||||
Policy and our Terms of Service.
|
||||
|
||||
h4 Definitions and key terms
|
||||
p.
|
||||
|
@ -22,8 +22,8 @@ article
|
|||
Cookie: small amount of data generated by a website and saved by your web browser. It is used to identify your
|
||||
browser, provide analytics, remember information about you such as your language preference or login information.
|
||||
li.
|
||||
Company: when this policy mentions “Company,” “we,” “us,” or “our,” it refers to {{name}}, that is responsible for
|
||||
your information under this Privacy Policy.
|
||||
Company: when this policy mentions “Company,” “we,” “us,” or
|
||||
“our,” it refers to {{name}}, that is responsible for your information under this Privacy Policy.
|
||||
li Country: where {{name}} or the owners/founders of {{name}} are based, in this case is US.
|
||||
li.
|
||||
Customer: refers to the company, organization or person that signs up to use the {{name}} Service to manage the
|
||||
|
@ -193,7 +193,7 @@ article
|
|||
h4 Cookies
|
||||
p {{name}} does not use Cookies.
|
||||
|
||||
h4 Kids' Privacy
|
||||
h4 Kids’ Privacy
|
||||
p.
|
||||
We do not address anyone under the age of 13. We do not knowingly collect personally identifiable information from
|
||||
anyone under the age of 13. If You are a parent or guardian and You are aware that Your child has provided Us with
|
||||
|
@ -219,7 +219,7 @@ article
|
|||
entity for any Third-Party Services.
|
||||
p.
|
||||
Third-Party Services and links thereto are provided solely as a convenience to you and you access and use them
|
||||
entirely at your own risk and subject to such third parties' terms and conditions.
|
||||
entirely at your own risk and subject to such third parties’ terms and conditions.
|
||||
|
||||
h4 Tracking Technologies
|
||||
p.
|
||||
|
@ -278,9 +278,9 @@ article
|
|||
Service and Privacy Policy, but we will not hold it longer than 60 days.
|
||||
p.
|
||||
We are aware that if you are working with EU customers, you need to be able to provide them with the ability to
|
||||
access, update, retrieve and remove personal data. We got you! We've been set up as self service from the start and
|
||||
have always given you access to your data. Our customer support team is here for you to answer any questions you
|
||||
might have about working with the API.
|
||||
access, update, retrieve and remove personal data. We got you! We’ve been set up as self service from the
|
||||
start and have always given you access to your data. Our customer support team is here for you to answer any
|
||||
questions you might have about working with the API.
|
||||
|
||||
h4 California Residents
|
||||
p.
|
||||
|
@ -300,7 +300,7 @@ article
|
|||
li.
|
||||
Right to Delete. You may submit a verifiable request to close your account and we will delete Personal Information
|
||||
about you that we have collected.
|
||||
li Request that a business that sells a consumer's personal data, not sell the consumer's personal data.
|
||||
li Request that a business that sells a consumer’s personal data, not sell the consumer’s personal data.
|
||||
p.
|
||||
If you make a request, we have one month to respond to you. If you would like to exercise any of these rights,
|
||||
please contact us.
|
||||
|
@ -323,7 +323,9 @@ article
|
|||
li.
|
||||
Right to Delete. You may submit a verifiable request to close your account and we will delete Personal Information
|
||||
about you that we have collected.
|
||||
li Right to request that a business that sells a consumer's personal data, not sell the consumer's personal data.
|
||||
li.
|
||||
Right to request that a business that sells a consumer’s personal data, not sell the consumer’s
|
||||
personal data.
|
||||
p.
|
||||
If you make a request, we have one month to respond to you. If you would like to exercise any of these rights,
|
||||
please contact us.
|
||||
|
@ -331,7 +333,7 @@ article
|
|||
p For more information about these rights, please contact us.
|
||||
|
||||
h4 Contact Us
|
||||
p Don't hesitate to contact us if you have any questions.
|
||||
p Don’t hesitate to contact us if you have any questions.
|
||||
ul: li Via this Link: #[router-link(to="/how-it-works") https://noagendacareers.com/how-it-works]
|
||||
</template>
|
||||
|
||||
|
|
|
@ -13,11 +13,11 @@ article
|
|||
/** The authorization URL to which the user should be directed */
|
||||
const authUrl = (() => {
|
||||
/** The client ID for Jobs, Jobs, Jobs at No Agenda Social */
|
||||
const id = 'k_06zlMy0N451meL4AqlwMQzs5PYr6g3d2Q_dCT-OjU'
|
||||
const id = "k_06zlMy0N451meL4AqlwMQzs5PYr6g3d2Q_dCT-OjU"
|
||||
const client = `client_id=${id}`
|
||||
const scope = 'scope=read:accounts'
|
||||
const scope = "scope=read:accounts"
|
||||
const redirect = `redirect_uri=${document.location.origin}/citizen/authorized`
|
||||
const respType = 'response_type=code'
|
||||
const respType = "response_type=code"
|
||||
return `https://noagendasocial.com/oauth/authorize?${client}&${scope}&${redirect}&${respType}`
|
||||
})()
|
||||
document.location.assign(authUrl)
|
||||
|
|
|
@ -59,16 +59,16 @@ const user = store.state.user as LogOnSuccess
|
|||
|
||||
/** A new job listing */
|
||||
const newListing : Listing = {
|
||||
id: '',
|
||||
id: "",
|
||||
citizenId: user.citizenId,
|
||||
createdOn: '',
|
||||
title: '',
|
||||
continentId: '',
|
||||
region: '',
|
||||
createdOn: "",
|
||||
title: "",
|
||||
continentId: "",
|
||||
region: "",
|
||||
remoteWork: false,
|
||||
isExpired: false,
|
||||
updatedOn: '',
|
||||
text: '',
|
||||
updatedOn: "",
|
||||
text: "",
|
||||
neededBy: undefined,
|
||||
wasFilledHere: undefined
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@ const listing : Ref<Listing | undefined> = ref(undefined)
|
|||
|
||||
/** The data needed to expire a job listing */
|
||||
const expiration = reactive(new ListingExpireForm())
|
||||
expiration.successStory = ""
|
||||
|
||||
/** The validation rules for the form */
|
||||
const rules = computed(() => ({
|
||||
|
|
|
@ -2,14 +2,18 @@
|
|||
article
|
||||
page-title(:title="title")
|
||||
load-data(:load="retrieveListing")
|
||||
h3 {{it.listing.title}}
|
||||
h3
|
||||
| {{it.listing.title}}
|
||||
.jjj-heading-label(v-if="it.listing.isExpired")
|
||||
| #[span.badge.bg-warning.text-dark Expired]
|
||||
template(v-if="it.listing.wasFilledHere") #[span.badge.bg-success Filled via Jobs, Jobs, Jobs]
|
||||
h4.pb-3.text-muted {{it.continent.name}} / {{it.listing.region}}
|
||||
p
|
||||
template(v-if="it.listing.neededBy").
|
||||
#[strong #[em NEEDED BY {{neededBy(it.listing.neededBy)}}]] •
|
||||
| Listed by #[a(:href="profileUrl" target="_blank") {{citizenName(citizen)}}]
|
||||
hr
|
||||
div(v-html='details')
|
||||
div(v-html="details")
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
|
|
@ -4,25 +4,46 @@ article
|
|||
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")
|
||||
table.table.table-sm.table-hover.pt-3(v-if='listings.length > 0')
|
||||
h4.pb-2(v-if="expired.length > 0") Active Job Listings
|
||||
table.pb-3.table.table-sm.table-hover.pt-3(v-if="active.length > 0")
|
||||
thead: tr
|
||||
th(scope="col") Action
|
||||
th(scope="col") Title
|
||||
th(scope="col") Continent / Region
|
||||
th(scope="col") Created
|
||||
th(scope="col") Updated
|
||||
tbody: tr(v-for='it in listings' :key='it.listing.id')
|
||||
td: router-link(:to="`/listing/${it.listing.id}/edit`") Edit
|
||||
tbody: tr(v-for="it in active" :key="it.listing.id")
|
||||
td
|
||||
router-link(:to="`/listing/${it.listing.id}/edit`") Edit
|
||||
= " ~ "
|
||||
router-link(:to="`/listing/${it.listing.id}/view`") View
|
||||
= " ~ "
|
||||
router-link(:to="`/listing/${it.listing.id}/expire`") Expire
|
||||
td {{it.listing.title}}
|
||||
td {{it.continent.name}} / {{it.listing.region}}
|
||||
td: full-date-time(:date='it.listing.createdOn')
|
||||
td: full-date-time(:date='it.listing.updatedOn')
|
||||
p.fst-italic(v-else) No job listings found
|
||||
td: full-date-time(:date="it.listing.createdOn")
|
||||
td: full-date-time(:date="it.listing.updatedOn")
|
||||
p.pb-3.fst-italic(v-else) You have no active job listings
|
||||
template(v-if="expired.length > 0")
|
||||
h4.pb-2 Expired Job Listings
|
||||
table.table.table-sm.table-hover.pt-3
|
||||
thead: tr
|
||||
th(scope="col") Action
|
||||
th(scope="col") Title
|
||||
th(scope="col") Filled Here?
|
||||
th(scope="col") Expired
|
||||
tbody: tr(v-for="it in expired" :key="it.listing.id")
|
||||
td
|
||||
router-link(:to="`/listing/${it.listing.id}/view`") View
|
||||
td {{it.listing.title}}
|
||||
td {{yesOrNo(it.listing.wasFilledHere)}}
|
||||
td: full-date-time(:date="it.listing.updatedOn")
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Ref, ref } from "vue"
|
||||
import { computed, Ref, ref } from "vue"
|
||||
import api, { ListingForView, LogOnSuccess } from "@/api"
|
||||
import { yesOrNo } from "@/App.vue"
|
||||
import { useStore } from "@/store"
|
||||
|
||||
import FullDateTime from "@/components/FullDateTime.vue"
|
||||
|
@ -33,6 +54,12 @@ const store = useStore()
|
|||
/** The listings for the user */
|
||||
const listings : Ref<ListingForView[]> = ref([])
|
||||
|
||||
/** The active (non-expired) listings entered by this user */
|
||||
const active = computed(() => listings.value.filter(it => !it.listing.isExpired))
|
||||
|
||||
/** The expired listings entered by this user */
|
||||
const expired = computed(() => listings.value.filter(it => it.listing.isExpired))
|
||||
|
||||
/** Retrieve the job listing posted by the current citizen */
|
||||
const getListings = async (errors : string[]) => {
|
||||
const listResult = await api.listings.mine(store.state.user as LogOnSuccess)
|
||||
|
|
|
@ -19,7 +19,7 @@ article
|
|||
th(scope="col") Last Updated
|
||||
tbody: tr(v-for="profile in results" :key="profile.citzenId")
|
||||
td: router-link(:to="`/profile/${profile.citizenId}/view`") View
|
||||
td(:class="{ 'font-weight-bold' : profile.seekingEmployment }") {{profile.displayName}}
|
||||
td(:class="{ 'fw-bold' : profile.seekingEmployment }") {{profile.displayName}}
|
||||
td.text-center {{yesOrNo(profile.seekingEmployment)}}
|
||||
td.text-center {{yesOrNo(profile.remoteWork)}}
|
||||
td.text-center {{yesOrNo(profile.fullTime)}}
|
||||
|
@ -55,10 +55,10 @@ const searched = ref(false)
|
|||
|
||||
/** An empty set of search criteria */
|
||||
const emptyCriteria = {
|
||||
continentId: '',
|
||||
continentId: "",
|
||||
skill: undefined,
|
||||
bioExperience: undefined,
|
||||
remoteWork: ''
|
||||
remoteWork: ""
|
||||
}
|
||||
|
||||
/** The search criteria being built from the page */
|
||||
|
@ -113,5 +113,5 @@ watch(() => route.query, setUpPage, { immediate: true })
|
|||
const toggleCollapse = (it : boolean) => { isCollapsed.value = it }
|
||||
|
||||
/** Execute a search */
|
||||
const doSearch = () => router.push({ query: { searched: 'true', ...criteria.value } })
|
||||
const doSearch = () => router.push({ query: { searched: "true", ...criteria.value } })
|
||||
</script>
|
||||
|
|
|
@ -2,7 +2,10 @@
|
|||
article
|
||||
page-title(:title="title")
|
||||
load-data(:load="retrieveProfile")
|
||||
h2: a(:href="it.citizen.profileUrl" target="_blank") {{citizenName(it.citizen)}}
|
||||
h2
|
||||
a(:href="it.citizen.profileUrl" target="_blank") {{citizenName(it.citizen)}}
|
||||
.jjj-heading-label(v-if="it.profile.seekingEmployment")
|
||||
| #[span.badge.bg-dark Currently Seeking Employment]
|
||||
h4.pb-3 {{it.continent.name}}, {{it.profile.region}}
|
||||
p(v-html="workTypes")
|
||||
hr
|
||||
|
@ -47,11 +50,6 @@ const workTypes = computed(() => {
|
|||
const parts : string[] = []
|
||||
if (it.value) {
|
||||
const p = it.value.profile
|
||||
if (p.seekingEmployment) {
|
||||
parts.push("<strong><em>CURRENTLY SEEKING EMPLOYMENT</em></strong>")
|
||||
} else {
|
||||
parts.push("Not actively seeking employment")
|
||||
}
|
||||
parts.push(`${p.fullTime ? "I" : "Not i"}nterested in full-time employment`)
|
||||
parts.push(`${p.remoteWork ? "I" : "Not i"}nterested in remote opportunities`)
|
||||
}
|
||||
|
|
|
@ -52,10 +52,10 @@ const errors : Ref<string[]> = ref([])
|
|||
|
||||
/** An empty set of search criteria */
|
||||
const emptyCriteria = {
|
||||
continentId: '',
|
||||
continentId: "",
|
||||
region: undefined,
|
||||
skill: undefined,
|
||||
remoteWork: ''
|
||||
remoteWork: ""
|
||||
}
|
||||
|
||||
/** The search criteria being built from the page */
|
||||
|
@ -109,5 +109,5 @@ watch(() => route.query, setUpPage, { immediate: true })
|
|||
const toggleCollapse = (it : boolean) => { isCollapsed.value = it }
|
||||
|
||||
/** Execute a search */
|
||||
const doSearch = () => router.push({ query: { searched: 'true', ...criteria.value } })
|
||||
const doSearch = () => router.push({ query: { searched: "true", ...criteria.value } })
|
||||
</script>
|
||||
|
|
|
@ -2,10 +2,11 @@
|
|||
article
|
||||
page-title(title="Success Story")
|
||||
load-data(:load="retrieveStory")
|
||||
h3.pb-3 {{citizenName}}’s Success Story
|
||||
h4.text-muted: full-date-time(:date="story.recordedOn")
|
||||
p.fst-italic(v-if="story.fromHere"): strong Found via Jobs, Jobs, Jobs
|
||||
hr
|
||||
h3
|
||||
| {{citizenName}}’s Success Story
|
||||
.jjj-heading-label(v-if="story.fromHere")
|
||||
| #[span.badge.bg-success Via {{profileOrListing}} on Jobs, Jobs, Jobs]
|
||||
h4.pb-3.text-muted: full-date-time(:date="story.recordedOn")
|
||||
div(v-if="story.story" v-html="successStory")
|
||||
</template>
|
||||
|
||||
|
@ -15,7 +16,7 @@ import { useRoute } from "vue-router"
|
|||
|
||||
import api, { LogOnSuccess, Success } from "@/api"
|
||||
import { citizenName as citName } from "@/App.vue"
|
||||
import { toHtml } from '@/markdown'
|
||||
import { toHtml } from "@/markdown"
|
||||
import { useStore } from "@/store"
|
||||
|
||||
import FullDateTime from "@/components/FullDateTime.vue"
|
||||
|
@ -55,6 +56,9 @@ const retrieveStory = async (errors : string []) => {
|
|||
}
|
||||
}
|
||||
|
||||
/** Whether this success is from an employment profile or a job listing */
|
||||
const profileOrListing = computed(() => story.value?.source === "profile" ? "employment profile" : "job listing")
|
||||
|
||||
/** The HTML success story */
|
||||
const successStory = computed(() => toHtml(story.value?.story ?? ""))
|
||||
</script>
|
||||
|
|
Loading…
Reference in New Issue
Block a user