|
|
@ -6,7 +6,7 @@ |
|
|
|
<section id="Content" class="p-6 pb-24 max-w-3xl mx-auto"> |
|
|
|
<!-- Heading --> |
|
|
|
<h1 id="ViewHeading" class="text-4xl text-center font-light"> |
|
|
|
Discover Projects |
|
|
|
Discover Projects & People |
|
|
|
</h1> |
|
|
|
|
|
|
|
<OnboardingDialog ref="onboardingDialog" /> |
|
|
@ -15,7 +15,6 @@ |
|
|
|
<div |
|
|
|
id="QuickSearch" |
|
|
|
class="mt-8 mb-4 flex" |
|
|
|
v-on:keyup.enter="searchSelected()" |
|
|
|
:style="{ visibility: isSearchVisible ? 'visible' : 'hidden' }" |
|
|
|
> |
|
|
|
<input |
|
|
@ -23,16 +22,54 @@ |
|
|
|
v-model="searchTerms" |
|
|
|
placeholder="Search…" |
|
|
|
class="block w-full rounded-l border border-r-0 border-slate-400 px-3 py-2" |
|
|
|
v-on:keyup.enter="searchSelected()" |
|
|
|
/> |
|
|
|
<button |
|
|
|
@click="searchSelected()" |
|
|
|
class="px-4 rounded-r bg-slate-200 border border-l-0 border-slate-400" |
|
|
|
@click="searchSelected()" |
|
|
|
> |
|
|
|
<fa icon="magnifying-glass" class="fa-fw"></fa> |
|
|
|
</button> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- Result Tabs --> |
|
|
|
<!-- Top Level Selection --> |
|
|
|
<div class="text-center text-slate-500 border-b border-slate-300 mb-4"> |
|
|
|
<ul class="flex flex-wrap justify-center gap-4 -mb-px"> |
|
|
|
<li> |
|
|
|
<a |
|
|
|
href="#" |
|
|
|
@click=" |
|
|
|
projects = []; |
|
|
|
userProfiles = []; |
|
|
|
isProjectsActive = true; |
|
|
|
isPeopleActive = false; |
|
|
|
searchSelected(); |
|
|
|
" |
|
|
|
v-bind:class="computedProjectsTabStyleClassNames()" |
|
|
|
> |
|
|
|
Projects |
|
|
|
</a> |
|
|
|
</li> |
|
|
|
<li> |
|
|
|
<a |
|
|
|
href="#" |
|
|
|
@click=" |
|
|
|
projects = []; |
|
|
|
userProfiles = []; |
|
|
|
isProjectsActive = false; |
|
|
|
isPeopleActive = true; |
|
|
|
searchSelected(); |
|
|
|
" |
|
|
|
v-bind:class="computedPeopleTabStyleClassNames()" |
|
|
|
> |
|
|
|
People |
|
|
|
</a> |
|
|
|
</li> |
|
|
|
</ul> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- Secondary Tabs --> |
|
|
|
<div class="text-center text-slate-500 border-b border-slate-300"> |
|
|
|
<ul class="flex flex-wrap justify-center gap-4 -mb-px"> |
|
|
|
<li> |
|
|
@ -40,9 +77,10 @@ |
|
|
|
href="#" |
|
|
|
@click=" |
|
|
|
projects = []; |
|
|
|
userProfiles = []; |
|
|
|
isLocalActive = true; |
|
|
|
isMappedActive = false; |
|
|
|
isRemoteActive = false; |
|
|
|
isAnywhereActive = false; |
|
|
|
isSearchVisible = true; |
|
|
|
tempSearchBox = null; |
|
|
|
searchLocal(); |
|
|
@ -65,15 +103,17 @@ |
|
|
|
href="#" |
|
|
|
@click=" |
|
|
|
projects = []; |
|
|
|
userProfiles = []; |
|
|
|
isLocalActive = false; |
|
|
|
isMappedActive = true; |
|
|
|
isRemoteActive = false; |
|
|
|
isAnywhereActive = false; |
|
|
|
isSearchVisible = false; |
|
|
|
searchTerms = ''; |
|
|
|
tempSearchBox = null; |
|
|
|
" |
|
|
|
v-bind:class="computedMappedTabStyleClassNames()" |
|
|
|
> |
|
|
|
<!-- search is triggered when map component gets to "ready" state --> |
|
|
|
Mapped |
|
|
|
</a> |
|
|
|
</li> |
|
|
@ -82,9 +122,10 @@ |
|
|
|
href="#" |
|
|
|
@click=" |
|
|
|
projects = []; |
|
|
|
userProfiles = []; |
|
|
|
isLocalActive = false; |
|
|
|
isMappedActive = false; |
|
|
|
isRemoteActive = true; |
|
|
|
isAnywhereActive = true; |
|
|
|
isSearchVisible = true; |
|
|
|
tempSearchBox = null; |
|
|
|
searchAll(); |
|
|
@ -95,7 +136,7 @@ |
|
|
|
<!-- restore when the links don't jump around for different numbers |
|
|
|
<span |
|
|
|
class="font-semibold text-sm bg-slate-200 px-1.5 py-0.5 rounded-md" |
|
|
|
v-if="isRemoteActive" |
|
|
|
v-if="isAnywhereActive" |
|
|
|
> |
|
|
|
{{ remoteCount > -1 ? remoteCount : "?" }} |
|
|
|
</span> |
|
|
@ -143,13 +184,13 @@ |
|
|
|
> |
|
|
|
<fa icon="spinner" class="fa-spin-pulse"></fa> |
|
|
|
</div> |
|
|
|
<div v-else-if="projects.length === 0" class="text-center mt-8"> |
|
|
|
<div v-else-if="projects.length === 0 && userProfiles.length === 0" class="text-center mt-8"> |
|
|
|
<p class="text-lg text-slate-500"> |
|
|
|
<span v-if="isLocalActive"> |
|
|
|
<span v-if="searchBox"> None found in the selected area. </span> |
|
|
|
<!-- Otherwise there's no search area selected so we'll just leave the search box for them to click. --> |
|
|
|
</span> |
|
|
|
<span v-else-if="isRemoteActive" |
|
|
|
<span v-else-if="isAnywhereActive" |
|
|
|
>No projects were found with that search.</span |
|
|
|
> |
|
|
|
</p> |
|
|
@ -158,13 +199,15 @@ |
|
|
|
<!-- Results List --> |
|
|
|
<InfiniteScroll @reached-bottom="loadMoreData"> |
|
|
|
<ul id="listDiscoverResults"> |
|
|
|
<!-- Projects List --> |
|
|
|
<template v-if="isProjectsActive"> |
|
|
|
<li |
|
|
|
class="border-b border-slate-300" |
|
|
|
v-for="project in projects" |
|
|
|
:key="project.handleId" |
|
|
|
> |
|
|
|
<a |
|
|
|
@click="onClickLoadProject(project.handleId)" |
|
|
|
@click="onClickLoadItem(project.handleId)" |
|
|
|
class="block py-4 flex gap-4 cursor-pointer" |
|
|
|
> |
|
|
|
<div> |
|
|
@ -187,6 +230,37 @@ |
|
|
|
</div> |
|
|
|
</a> |
|
|
|
</li> |
|
|
|
</template> |
|
|
|
|
|
|
|
<!-- Profiles List --> |
|
|
|
<template v-else> |
|
|
|
<li |
|
|
|
class="border-b border-slate-300" |
|
|
|
v-for="profile in userProfiles" |
|
|
|
:key="profile.issuerDid" |
|
|
|
> |
|
|
|
<a |
|
|
|
@click="onClickLoadItem(profile.issuerDid)" |
|
|
|
class="block py-4 flex gap-4 cursor-pointer" |
|
|
|
> |
|
|
|
<div class="grow"> |
|
|
|
<div class="text-sm"> |
|
|
|
<fa icon="user" class="fa-fw text-slate-400"></fa> |
|
|
|
{{ |
|
|
|
didInfo(profile.issuerDid, activeDid, allMyDids, allContacts) |
|
|
|
}} |
|
|
|
</div> |
|
|
|
<p v-if="profile.description" class="mt-1 text-sm text-slate-600"> |
|
|
|
{{ profile.description }} |
|
|
|
</p> |
|
|
|
<div v-if="profile.locLat && profile.locLon" class="mt-1 text-xs text-slate-500"> |
|
|
|
<fa icon="location-dot" class="fa-fw"></fa> |
|
|
|
{{ profile.locLat.toFixed(2) }}, {{ profile.locLon.toFixed(2) }} |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</a> |
|
|
|
</li> |
|
|
|
</template> |
|
|
|
</ul> |
|
|
|
</InfiniteScroll> |
|
|
|
</section> |
|
|
@ -197,14 +271,14 @@ import "leaflet/dist/leaflet.css"; |
|
|
|
import * as L from "leaflet"; |
|
|
|
import { Component, Vue } from "vue-facing-decorator"; |
|
|
|
import { LMap, LTileLayer } from "@vue-leaflet/vue-leaflet"; |
|
|
|
import { Router } from "vue-router"; |
|
|
|
import { Router, RouteLocationNormalizedLoaded } from "vue-router"; |
|
|
|
|
|
|
|
import QuickNav from "@/components/QuickNav.vue"; |
|
|
|
import InfiniteScroll from "@/components/InfiniteScroll.vue"; |
|
|
|
import ProjectIcon from "@/components/ProjectIcon.vue"; |
|
|
|
import OnboardingDialog from "@/components/OnboardingDialog.vue"; |
|
|
|
import TopMessage from "@/components/TopMessage.vue"; |
|
|
|
import { NotificationIface } from "@/constants/app"; |
|
|
|
import { DEFAULT_PARTNER_API_SERVER, NotificationIface } from "@/constants/app"; |
|
|
|
import { |
|
|
|
db, |
|
|
|
logConsoleAndDb, |
|
|
@ -218,8 +292,19 @@ import { |
|
|
|
getHeaders, |
|
|
|
PlanData, |
|
|
|
} from "@/libs/endorserServer"; |
|
|
|
import { UserProfile } from "@/libs/partnerServer"; |
|
|
|
import { OnboardPage, retrieveAccountDids } from "@/libs/util"; |
|
|
|
|
|
|
|
interface Tile { |
|
|
|
indexLat: number; |
|
|
|
indexLon: number; |
|
|
|
minFoundLat: number; |
|
|
|
maxFoundLat: number; |
|
|
|
minFoundLon: number; |
|
|
|
maxFoundLon: number; |
|
|
|
recordCount: number; |
|
|
|
} |
|
|
|
|
|
|
|
@Component({ |
|
|
|
components: { |
|
|
|
InfiniteScroll, |
|
|
@ -233,25 +318,31 @@ import { OnboardPage, retrieveAccountDids } from "@/libs/util"; |
|
|
|
}) |
|
|
|
export default class DiscoverView extends Vue { |
|
|
|
$notify!: (notification: NotificationIface, timeout?: number) => void; |
|
|
|
$router!: Router; |
|
|
|
$route!: RouteLocationNormalizedLoaded; |
|
|
|
|
|
|
|
activeDid = ""; |
|
|
|
allContacts: Array<Contact> = []; |
|
|
|
allMyDids: Array<string> = []; |
|
|
|
apiServer = ""; |
|
|
|
searchTerms = ""; |
|
|
|
projects: PlanData[] = []; |
|
|
|
isLoading = false; |
|
|
|
isLocalActive = true; |
|
|
|
isMappedActive = false; |
|
|
|
isRemoteActive = false; |
|
|
|
isAnywhereActive = false; |
|
|
|
isProjectsActive = true; |
|
|
|
isPeopleActive = false; |
|
|
|
isSearchVisible = true; |
|
|
|
localCenterLat = 0; |
|
|
|
localCenterLong = 0; |
|
|
|
localCount = -1; |
|
|
|
markers: { [key: string]: L.Marker } = {}; |
|
|
|
partnerApiServer = DEFAULT_PARTNER_API_SERVER; |
|
|
|
projects: PlanData[] = []; |
|
|
|
remoteCount = -1; |
|
|
|
searchBox: { name: string; bbox: BoundingBox } | null = null; |
|
|
|
searchTerms = ""; |
|
|
|
tempSearchBox: BoundingBox | null = null; |
|
|
|
userProfiles: UserProfile[] = []; |
|
|
|
zoomedSoDoNotMove = false; |
|
|
|
|
|
|
|
// make this function available to the Vue template |
|
|
@ -261,13 +352,15 @@ export default class DiscoverView extends Vue { |
|
|
|
const settings = await retrieveSettingsForActiveAccount(); |
|
|
|
this.activeDid = (settings.activeDid as string) || ""; |
|
|
|
this.apiServer = (settings.apiServer as string) || ""; |
|
|
|
this.partnerApiServer = |
|
|
|
(settings.partnerApiServer as string) || this.partnerApiServer; |
|
|
|
this.searchBox = settings.searchBoxes?.[0] || null; |
|
|
|
|
|
|
|
this.allContacts = await db.contacts.toArray(); |
|
|
|
|
|
|
|
this.allMyDids = await retrieveAccountDids(); |
|
|
|
|
|
|
|
this.searchTerms = (this.$route as Router).query["searchText"] || ""; |
|
|
|
this.searchTerms = this.$route.query["searchText"]?.toString() || ""; |
|
|
|
|
|
|
|
if (!settings.finishedOnboarding) { |
|
|
|
(this.$refs.onboardingDialog as OnboardingDialog).open( |
|
|
@ -284,7 +377,7 @@ export default class DiscoverView extends Vue { |
|
|
|
} else { |
|
|
|
this.isLocalActive = false; |
|
|
|
this.isMappedActive = false; |
|
|
|
this.isRemoteActive = true; |
|
|
|
this.isAnywhereActive = true; |
|
|
|
await this.searchAll(); |
|
|
|
} |
|
|
|
} |
|
|
@ -298,8 +391,8 @@ export default class DiscoverView extends Vue { |
|
|
|
if (this.isLocalActive) { |
|
|
|
await this.searchLocal(); |
|
|
|
} else if (this.isMappedActive) { |
|
|
|
this.isRemoteActive = true; |
|
|
|
await this.searchAll(); |
|
|
|
const mapRef = this.$refs.projectMap as L.Map; |
|
|
|
this.requestTiles(mapRef.leafletObject); // not ideal because I found this from experimentation, not documentation |
|
|
|
} else { |
|
|
|
await this.searchAll(); |
|
|
|
} |
|
|
@ -311,6 +404,7 @@ export default class DiscoverView extends Vue { |
|
|
|
if (!beforeId) { |
|
|
|
// this was an initial search so clear any previous results |
|
|
|
this.projects = []; |
|
|
|
this.userProfiles = []; |
|
|
|
} |
|
|
|
|
|
|
|
let queryParams = "claimContents=" + encodeURIComponent(this.searchTerms); |
|
|
@ -319,34 +413,25 @@ export default class DiscoverView extends Vue { |
|
|
|
queryParams = queryParams + `&beforeId=${beforeId}`; |
|
|
|
} |
|
|
|
|
|
|
|
const endpoint = this.isProjectsActive |
|
|
|
? this.apiServer + "/api/v2/report/plans" |
|
|
|
: this.partnerApiServer + "/api/partner/userProfile"; |
|
|
|
|
|
|
|
try { |
|
|
|
this.isLoading = true; |
|
|
|
const response = await fetch( |
|
|
|
this.apiServer + "/api/v2/report/plans?" + queryParams, |
|
|
|
{ |
|
|
|
const response = await fetch(endpoint + "?" + queryParams, { |
|
|
|
method: "GET", |
|
|
|
headers: await getHeaders(this.activeDid), |
|
|
|
}, |
|
|
|
); |
|
|
|
}); |
|
|
|
|
|
|
|
if (response.status !== 200) { |
|
|
|
const details = await response.text(); |
|
|
|
console.error("Problem with full search:", details); |
|
|
|
this.$notify( |
|
|
|
{ |
|
|
|
group: "alert", |
|
|
|
type: "danger", |
|
|
|
title: "Error", |
|
|
|
text: `There was a problem accessing the server.`, |
|
|
|
}, |
|
|
|
3000, |
|
|
|
); |
|
|
|
|
|
|
|
throw details; |
|
|
|
} |
|
|
|
|
|
|
|
const results = await response.json(); |
|
|
|
|
|
|
|
if (this.isProjectsActive) { |
|
|
|
const plans: PlanData[] = results.data; |
|
|
|
if (plans) { |
|
|
|
for (const plan of plans) { |
|
|
@ -364,17 +449,26 @@ export default class DiscoverView extends Vue { |
|
|
|
} else { |
|
|
|
throw JSON.stringify(results); |
|
|
|
} |
|
|
|
} else { |
|
|
|
const profiles: UserProfile[] = results.data; |
|
|
|
if (profiles) { |
|
|
|
this.userProfiles.push(...profiles); |
|
|
|
this.remoteCount = this.userProfiles.length; |
|
|
|
} else { |
|
|
|
throw JSON.stringify(results); |
|
|
|
} |
|
|
|
} |
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any |
|
|
|
} catch (e: any) { |
|
|
|
console.error("Error with feed load:", e); |
|
|
|
console.error("Error with search all:", e); |
|
|
|
// this sometimes gives different information |
|
|
|
console.error("Error with feed load (error added): " + e); |
|
|
|
console.error("Error with search all (error added): " + e); |
|
|
|
this.$notify( |
|
|
|
{ |
|
|
|
group: "alert", |
|
|
|
type: "danger", |
|
|
|
title: "Error", |
|
|
|
text: e.userMessage || "There was a problem retrieving projects.", |
|
|
|
title: "Error Searching", |
|
|
|
text: e.userMessage || "There was a problem retrieving " + (this.isProjectsActive ? "projects" : "profiles") + ".", |
|
|
|
}, |
|
|
|
5000, |
|
|
|
); |
|
|
@ -392,12 +486,14 @@ export default class DiscoverView extends Vue { |
|
|
|
|
|
|
|
if (!searchBox) { |
|
|
|
this.projects = []; |
|
|
|
this.userProfiles = []; |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if (!beforeId) { |
|
|
|
// this was an initial search so clear any previous results |
|
|
|
this.projects = []; |
|
|
|
this.userProfiles = []; |
|
|
|
} |
|
|
|
|
|
|
|
const claimContents = |
|
|
@ -407,41 +503,33 @@ export default class DiscoverView extends Vue { |
|
|
|
claimContents, |
|
|
|
"minLocLat=" + searchBox.minLat, |
|
|
|
"maxLocLat=" + searchBox.maxLat, |
|
|
|
"westLocLon=" + searchBox.westLong, |
|
|
|
"eastLocLon=" + searchBox.eastLong, |
|
|
|
"minLocLon=" + searchBox.westLong, |
|
|
|
"maxLocLon=" + searchBox.eastLong, |
|
|
|
].join("&"); |
|
|
|
|
|
|
|
if (beforeId) { |
|
|
|
queryParams = queryParams + `&beforeId=${beforeId}`; |
|
|
|
} |
|
|
|
|
|
|
|
const endpoint = this.isProjectsActive |
|
|
|
? this.apiServer + "/api/v2/report/plansByLocation" |
|
|
|
: this.partnerApiServer + "/api/partner/userProfile"; |
|
|
|
|
|
|
|
try { |
|
|
|
this.isLoading = true; |
|
|
|
const response = await fetch( |
|
|
|
this.apiServer + "/api/v2/report/plansByLocation?" + queryParams, |
|
|
|
{ |
|
|
|
const response = await fetch(endpoint + "?" + queryParams, { |
|
|
|
method: "GET", |
|
|
|
headers: await getHeaders(this.activeDid), |
|
|
|
}, |
|
|
|
); |
|
|
|
}); |
|
|
|
|
|
|
|
if (response.status !== 200) { |
|
|
|
const details = await response.text(); |
|
|
|
console.error("Problem with nearby search:", details); |
|
|
|
this.$notify( |
|
|
|
{ |
|
|
|
group: "alert", |
|
|
|
type: "danger", |
|
|
|
title: "Error", |
|
|
|
text: "There was a problem accessing the server.", |
|
|
|
}, |
|
|
|
3000, |
|
|
|
); |
|
|
|
throw await response.text(); |
|
|
|
throw details; |
|
|
|
} |
|
|
|
|
|
|
|
const results = await response.json(); |
|
|
|
|
|
|
|
if (this.isProjectsActive) { |
|
|
|
if (results.data) { |
|
|
|
if (beforeId) { |
|
|
|
const plans: PlanData[] = results.data; |
|
|
@ -462,15 +550,24 @@ export default class DiscoverView extends Vue { |
|
|
|
} else { |
|
|
|
throw JSON.stringify(results); |
|
|
|
} |
|
|
|
} else { |
|
|
|
const profiles: UserProfile[] = results.data; |
|
|
|
if (profiles) { |
|
|
|
this.userProfiles.push(...profiles); |
|
|
|
this.localCount = this.userProfiles.length; |
|
|
|
} else { |
|
|
|
throw JSON.stringify(results); |
|
|
|
} |
|
|
|
} |
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any |
|
|
|
} catch (e: any) { |
|
|
|
console.error("Error with feed load:", e); |
|
|
|
console.error("Error with search local:", e); |
|
|
|
this.$notify( |
|
|
|
{ |
|
|
|
group: "alert", |
|
|
|
type: "danger", |
|
|
|
title: "Error", |
|
|
|
text: e.userMessage || "There was a problem retrieving projects.", |
|
|
|
text: e.userMessage || "There was a problem retrieving " + (this.isProjectsActive ? "projects" : "profiles") + ".", |
|
|
|
}, |
|
|
|
5000, |
|
|
|
); |
|
|
@ -484,14 +581,21 @@ export default class DiscoverView extends Vue { |
|
|
|
* @param payload is the flag from the InfiniteScroll indicating if it should load |
|
|
|
**/ |
|
|
|
async loadMoreData(payload: boolean) { |
|
|
|
if (this.projects.length > 0 && payload) { |
|
|
|
if (payload) { |
|
|
|
if (this.isProjectsActive && this.projects.length > 0) { |
|
|
|
const latestProject = this.projects[this.projects.length - 1]; |
|
|
|
if (this.isLocalActive) { |
|
|
|
this.searchLocal(latestProject["rowid"]); |
|
|
|
} else if (this.isMappedActive) { |
|
|
|
this.searchLocal(latestProject["rowid"]); |
|
|
|
} else if (this.isRemoteActive) { |
|
|
|
this.searchAll(latestProject["rowid"]); |
|
|
|
if (this.isLocalActive || this.isMappedActive) { |
|
|
|
this.searchLocal(latestProject.rowid); |
|
|
|
} else if (this.isAnywhereActive) { |
|
|
|
this.searchAll(latestProject.rowid); |
|
|
|
} |
|
|
|
} else if (!this.isProjectsActive && this.userProfiles.length > 0) { |
|
|
|
const latestProfile = this.userProfiles[this.userProfiles.length - 1]; |
|
|
|
if (this.isLocalActive || this.isMappedActive) { |
|
|
|
this.searchLocal(latestProfile.rowid || ""); |
|
|
|
} else if (this.isAnywhereActive) { |
|
|
|
this.searchAll(latestProfile.rowid || ""); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -503,7 +607,7 @@ export default class DiscoverView extends Vue { |
|
|
|
} |
|
|
|
|
|
|
|
// Tried but failed to use other vue-leaflet methods update:zoom and update:bounds |
|
|
|
// To access the from this.$refs, use this.$refs.projectMap.mapObject |
|
|
|
// To access the from this.$refs, use this.$refs.projectMap.leafletObject (or maybe mapObject) |
|
|
|
|
|
|
|
onMoveStart(/* event: L.LocationEvent */) { |
|
|
|
// don't remove markers because they follow the map when moving (and the experience is jarring) |
|
|
@ -540,9 +644,10 @@ export default class DiscoverView extends Vue { |
|
|
|
"westLocLon=" + bounds?.getSouthWest().lng, |
|
|
|
"eastLocLon=" + bounds?.getNorthEast().lng, |
|
|
|
].join("&"); |
|
|
|
const response = await fetch( |
|
|
|
this.apiServer + "/api/v2/report/planCountsByBBox?" + queryParams, |
|
|
|
); |
|
|
|
const endpoint = this.isProjectsActive |
|
|
|
? this.apiServer + "/api/v2/report/planCountsByBBox" |
|
|
|
: this.partnerApiServer + "/api/partner/userProfileCountsByBBox"; |
|
|
|
const response = await fetch(endpoint + "?" + queryParams); |
|
|
|
if (response.status === 200) { |
|
|
|
Object.values(this.markers).forEach((marker) => marker.remove()); |
|
|
|
this.markers = {}; |
|
|
@ -601,14 +706,16 @@ export default class DiscoverView extends Vue { |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Handle clicking on a project entry found in the list |
|
|
|
* @param id of the project |
|
|
|
* Handle clicking on a project or profile entry found in the list |
|
|
|
* @param id of the project or profile |
|
|
|
**/ |
|
|
|
onClickLoadProject(id: string) { |
|
|
|
onClickLoadItem(id: string) { |
|
|
|
const route = { |
|
|
|
path: "/project/" + encodeURIComponent(id), |
|
|
|
path: this.isProjectsActive |
|
|
|
? "/project/" + encodeURIComponent(id) |
|
|
|
: "/userProfile/" + encodeURIComponent(id), |
|
|
|
}; |
|
|
|
(this.$router as Router).push(route); |
|
|
|
this.$router.push(route); |
|
|
|
} |
|
|
|
|
|
|
|
public computedLocalTabStyleClassNames() { |
|
|
@ -654,14 +761,50 @@ export default class DiscoverView extends Vue { |
|
|
|
"rounded-t-lg": true, |
|
|
|
"border-b-2": true, |
|
|
|
|
|
|
|
active: this.isRemoteActive, |
|
|
|
"text-black": this.isRemoteActive, |
|
|
|
"border-black": this.isRemoteActive, |
|
|
|
"font-semibold": this.isRemoteActive, |
|
|
|
active: this.isAnywhereActive, |
|
|
|
"text-black": this.isAnywhereActive, |
|
|
|
"border-black": this.isAnywhereActive, |
|
|
|
"font-semibold": this.isAnywhereActive, |
|
|
|
|
|
|
|
"text-blue-600": !this.isAnywhereActive, |
|
|
|
"border-transparent": !this.isAnywhereActive, |
|
|
|
"hover:border-slate-400": !this.isAnywhereActive, |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
public computedProjectsTabStyleClassNames() { |
|
|
|
return { |
|
|
|
"inline-block": true, |
|
|
|
"py-3": true, |
|
|
|
"rounded-t-lg": true, |
|
|
|
"border-b-2": true, |
|
|
|
|
|
|
|
active: this.isProjectsActive, |
|
|
|
"text-black": this.isProjectsActive, |
|
|
|
"border-black": this.isProjectsActive, |
|
|
|
"font-semibold": this.isProjectsActive, |
|
|
|
|
|
|
|
"text-blue-600": !this.isProjectsActive, |
|
|
|
"border-transparent": !this.isProjectsActive, |
|
|
|
"hover:border-slate-400": !this.isProjectsActive, |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
public computedPeopleTabStyleClassNames() { |
|
|
|
return { |
|
|
|
"inline-block": true, |
|
|
|
"py-3": true, |
|
|
|
"rounded-t-lg": true, |
|
|
|
"border-b-2": true, |
|
|
|
|
|
|
|
active: this.isPeopleActive, |
|
|
|
"text-black": this.isPeopleActive, |
|
|
|
"border-black": this.isPeopleActive, |
|
|
|
"font-semibold": this.isPeopleActive, |
|
|
|
|
|
|
|
"text-blue-600": !this.isRemoteActive, |
|
|
|
"border-transparent": !this.isRemoteActive, |
|
|
|
"hover:border-slate-400": !this.isRemoteActive, |
|
|
|
"text-blue-600": !this.isPeopleActive, |
|
|
|
"border-transparent": !this.isPeopleActive, |
|
|
|
"hover:border-slate-400": !this.isPeopleActive, |
|
|
|
}; |
|
|
|
} |
|
|
|
} |
|
|
|