Env swap #21
|
@ -188,6 +188,11 @@ let withReconn (conn : IConnection) =
|
|||
(conn :?> Connection).Reconnect()
|
||||
| false -> ()))
|
||||
|
||||
/// Sanitize user input, and create a "contains" pattern for use with RethinkDB queries
|
||||
let regexContains (it : string) =
|
||||
System.Text.RegularExpressions.Regex.Escape it
|
||||
|> sprintf "(?i).*%s.*"
|
||||
|
||||
open JobsJobsJobs.Domain.SharedTypes
|
||||
open RethinkDb.Driver.Ast
|
||||
|
||||
|
@ -251,14 +256,14 @@ module Profile =
|
|||
match srch.skill with
|
||||
| Some skl ->
|
||||
yield (fun q -> q.Filter(ReqlFunction1(fun it ->
|
||||
upcast it.G("skills.description").Downcase().Match(skl.ToLowerInvariant ()))) :> ReqlExpr)
|
||||
upcast it.G("skills").Contains(ReqlFunction1(fun s ->
|
||||
upcast s.G("description").Match(regexContains skl))))) :> ReqlExpr)
|
||||
| None -> ()
|
||||
match srch.bioExperience with
|
||||
| Some text ->
|
||||
let txt = text.ToLowerInvariant ()
|
||||
let txt = regexContains text
|
||||
yield (fun q -> q.Filter(ReqlFunction1(fun it ->
|
||||
upcast it.G("biography" ).Downcase().Match(txt)
|
||||
.Or(it.G("experience").Downcase().Match(txt)))) :> ReqlExpr)
|
||||
upcast it.G("biography").Match(txt).Or(it.G("experience").Match(txt)))) :> ReqlExpr)
|
||||
| None -> ()
|
||||
}
|
||||
|> Seq.toList
|
||||
|
@ -290,8 +295,7 @@ module Profile =
|
|||
match srch.region with
|
||||
| Some reg ->
|
||||
yield (fun q ->
|
||||
q.Filter(ReqlFunction1(fun it ->
|
||||
upcast it.G("region").Downcase().Match(reg.ToLowerInvariant ()))) :> ReqlExpr)
|
||||
q.Filter(ReqlFunction1(fun it -> upcast it.G("region").Match(regexContains reg))) :> ReqlExpr)
|
||||
| None -> ()
|
||||
match srch.remoteWork with
|
||||
| "" -> ()
|
||||
|
@ -299,7 +303,8 @@ module Profile =
|
|||
match srch.skill with
|
||||
| Some skl ->
|
||||
yield (fun q -> q.Filter(ReqlFunction1(fun it ->
|
||||
upcast it.G("skills.description").Downcase().Match(skl.ToLowerInvariant ()))) :> ReqlExpr)
|
||||
upcast it.G("skills").Contains(ReqlFunction1(fun s ->
|
||||
upcast s.G("description").Match(regexContains skl))))) :> ReqlExpr)
|
||||
| None -> ()
|
||||
}
|
||||
|> Seq.toList
|
||||
|
@ -315,7 +320,7 @@ module Profile =
|
|||
.HashMap("skills",
|
||||
it.G("skills").Map(ReqlFunction1(fun skill ->
|
||||
upcast r.Branch(skill.G("notes").Default_("").Eq(""), skill.G("description"),
|
||||
sprintf "%O (%O)" (skill.G("description")) (skill.G("notes"))))))
|
||||
skill.G("description").Add(" (").Add(skill.G("notes")).Add(")")))))
|
||||
.With("continent", it.G("name"))))
|
||||
.Pluck("continent", "region", "skills", "remoteWork")
|
||||
.RunResultAsync<PublicSearchResult list> conn)
|
||||
|
|
|
@ -146,7 +146,7 @@ export default {
|
|||
publicSearch: async (query : PublicSearch) : Promise<PublicSearchResult[] | string | undefined> => {
|
||||
const params = new URLSearchParams()
|
||||
if (query.continentId) params.append('continentId', query.continentId)
|
||||
if (query.region) params.append('bioExperience', query.region)
|
||||
if (query.region) params.append('region', query.region)
|
||||
if (query.skill) params.append('skill', query.skill)
|
||||
params.append('remoteWork', query.remoteWork)
|
||||
return apiResult<PublicSearchResult[]>(
|
||||
|
|
|
@ -2,17 +2,19 @@
|
|||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h6 class="card-title">
|
||||
<a href="#" :class="{ 'cp-c': isCollapsed, 'cp-o': !isCollapsed }" @click.prevent="toggle">{{headerText}}</a>
|
||||
<a href="#" :class="{ 'cp-c': collapsed, 'cp-o': !collapsed }" @click.prevent="toggle">{{headerText}}</a>
|
||||
</h6>
|
||||
<slot v-if="!isCollapsed"></slot>
|
||||
<slot v-if="!collapsed"></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from 'vue'
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'CollapsePanel',
|
||||
emits: ['toggle'],
|
||||
props: {
|
||||
headerText: {
|
||||
type: String,
|
||||
|
@ -23,13 +25,9 @@ export default defineComponent({
|
|||
default: false
|
||||
}
|
||||
},
|
||||
setup (props) {
|
||||
/** Whether the panel is collapsed or not */
|
||||
const isCollapsed = ref(props.collapsed)
|
||||
|
||||
setup (props, { emit }) {
|
||||
return {
|
||||
isCollapsed,
|
||||
toggle: () => { isCollapsed.value = !isCollapsed.value }
|
||||
toggle: () => emit('toggle', !props.collapsed)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -1,19 +1,18 @@
|
|||
<template>
|
||||
<article>
|
||||
<page-title title="Search Profiles" />
|
||||
<h3>Search Profiles</h3>
|
||||
<h3 class="pb-3">Search Profiles</h3>
|
||||
|
||||
<p v-if="!searched">
|
||||
Enter one or more criteria to filter results, or just click “Search” to list all profiles.
|
||||
</p>
|
||||
<collapse-panel headerText="Search Criteria" :collapsed="isCollapsed" @toggle="toggleCollapse">
|
||||
<profile-search-form v-model="criteria" @search="doSearch" />
|
||||
</collapse-panel>
|
||||
<error-list :errors="errors">
|
||||
<p v-if="searching">Searching profiles...</p>
|
||||
<p v-if="searching" class="pt-3">Searching profiles...</p>
|
||||
<template v-else>
|
||||
<p v-if="!searched">
|
||||
Enter one or more criteria to filter results, or just click “Search” to list all profiles.
|
||||
</p>
|
||||
<collapse-panel headerText="Search Criteria" :collapsed="searched && results.length > 0">
|
||||
<profile-search-form v-model="criteria" @search="doSearch" />
|
||||
</collapse-panel>
|
||||
<br>
|
||||
<table v-if="results.length > 0" class="table table-sm table-hover">
|
||||
<table v-if="results.length > 0" class="table table-sm table-hover pt-3">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Profile</th>
|
||||
|
@ -35,7 +34,7 @@
|
|||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p v-else-if="searched">No results found for the specified criteria</p>
|
||||
<p v-else-if="searched" class="pt-3">No results found for the specified criteria</p>
|
||||
</template>
|
||||
</error-list>
|
||||
</article>
|
||||
|
@ -90,6 +89,9 @@ export default defineComponent({
|
|||
/** The current search results */
|
||||
const results : Ref<ProfileSearchResult[]> = ref([])
|
||||
|
||||
/** Whether the search criteria should be collapsed */
|
||||
const isCollapsed = ref(searched.value && results.value.length > 0)
|
||||
|
||||
/** Set up the page to match its requested state */
|
||||
const setUpPage = async () => {
|
||||
if (queryValue(route, 'searched') === 'true') {
|
||||
|
@ -114,6 +116,7 @@ export default defineComponent({
|
|||
} finally {
|
||||
searching.value = false
|
||||
}
|
||||
isCollapsed.value = searched.value && results.value.length > 0
|
||||
} else {
|
||||
searched.value = false
|
||||
criteria.value = emptyCriteria
|
||||
|
@ -127,6 +130,8 @@ export default defineComponent({
|
|||
return {
|
||||
errors,
|
||||
criteria,
|
||||
isCollapsed,
|
||||
toggleCollapse: (it : boolean) => { isCollapsed.value = it },
|
||||
doSearch: () => router.push({ query: { searched: 'true', ...criteria.value } }),
|
||||
searching,
|
||||
searched,
|
||||
|
|
|
@ -1,20 +1,19 @@
|
|||
<template>
|
||||
<article>
|
||||
<page-title title="People Seeking Work" />
|
||||
<h3>People Seeking Work</h3>
|
||||
<h3 class="pb-3">People Seeking Work</h3>
|
||||
|
||||
<p v-if="!searched">
|
||||
Enter one or more criteria to filter results, or just click “Search” to list all profiles.
|
||||
</p>
|
||||
<collapse-panel headerText="Search Criteria" :collapsed="isCollapsed" @toggle="toggleCollapse">
|
||||
<profile-public-search-form v-model="criteria" @search="doSearch" />
|
||||
</collapse-panel>
|
||||
<error-list :errors="errors">
|
||||
<p v-if="searching">Searching profiles...</p>
|
||||
<template v-else>
|
||||
<p v-if="!searched">
|
||||
Enter one or more criteria to filter results, or just click “Search” to list all profiles.
|
||||
</p>
|
||||
<collapse-panel headerText="Search Criteria" :collapsed="searched && results.length > 0">
|
||||
<profile-public-search-form v-model="criteria" @search="doSearch" />
|
||||
</collapse-panel>
|
||||
<br>
|
||||
<template v-if="results.length > 0">
|
||||
<p>
|
||||
<p class="pb-3 pt-3">
|
||||
These profiles match your search criteria. To learn more about these people, join the merry band of human
|
||||
resources in the <a href="https://noagendashow.net" target="_blank">No Agenda</a> tribe!
|
||||
</p>
|
||||
|
@ -39,9 +38,7 @@
|
|||
</tbody>
|
||||
</table>
|
||||
</template>
|
||||
<template v-else>
|
||||
<p v-if="searched">No results found for the specified criteria</p>
|
||||
</template>
|
||||
<p v-else-if="searched" class="pt-3">No results found for the specified criteria</p>
|
||||
</template>
|
||||
</error-list>
|
||||
</article>
|
||||
|
@ -91,6 +88,9 @@ export default defineComponent({
|
|||
/** The search results */
|
||||
const results : Ref<PublicSearchResult[]> = ref([])
|
||||
|
||||
/** Whether the search results are collapsed */
|
||||
const isCollapsed = ref(searched.value && results.value.length > 0)
|
||||
|
||||
/** Set up the page to match its requested state */
|
||||
const setUpPage = async () => {
|
||||
if (queryValue(route, 'searched') === 'true') {
|
||||
|
@ -115,6 +115,7 @@ export default defineComponent({
|
|||
} finally {
|
||||
searching.value = false
|
||||
}
|
||||
isCollapsed.value = searched.value && results.value.length > 0
|
||||
} else {
|
||||
searched.value = false
|
||||
criteria.value = emptyCriteria
|
||||
|
@ -128,6 +129,8 @@ export default defineComponent({
|
|||
return {
|
||||
errors,
|
||||
criteria,
|
||||
isCollapsed,
|
||||
toggleCollapse: (it : boolean) => { isCollapsed.value = it },
|
||||
doSearch: () => router.push({ query: { searched: 'true', ...criteria.value } }),
|
||||
searching,
|
||||
searched,
|
||||
|
|
Loading…
Reference in New Issue
Block a user