<template>
|
|
<div :class="['page-container', { 'nav-is-showing': isPickerVisible }]">
|
|
<header>
|
|
<div class="header__col">
|
|
<template v-if="!isPickerVisible">
|
|
<button class="btn btn--primary" @click="showPicker">
|
|
tap the map or <svg
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
class="icon icon-tabler icon-tabler-search"
|
|
width="24"
|
|
height="24"
|
|
viewBox="0 0 24 24"
|
|
stroke-width="3"
|
|
stroke="#ffffff"
|
|
fill="none"
|
|
stroke-linecap="round"
|
|
stroke-linejoin="round"
|
|
>
|
|
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
|
<circle cx="10" cy="10" r="7" />
|
|
<line x1="21" y1="21" x2="15" y2="15" />
|
|
</svg>
|
|
</button>
|
|
</template>
|
|
<template v-if="isPickerVisible">
|
|
<button class="btn btn--primary" @click="showPicker">
|
|
hide search <svg
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
class="icon icon-tabler icon-tabler-arrow-bar-to-up"
|
|
width="24"
|
|
height="24"
|
|
viewBox="0 0 24 24"
|
|
stroke-width="3"
|
|
stroke="#ffffff"
|
|
fill="none"
|
|
stroke-linecap="round"
|
|
stroke-linejoin="round"
|
|
>
|
|
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
|
<line x1="12" y1="10" x2="12" y2="20" />
|
|
<line x1="12" y1="10" x2="16" y2="14" />
|
|
<line x1="12" y1="10" x2="8" y2="14" />
|
|
<line x1="4" y1="4" x2="20" y2="4" />
|
|
</svg>
|
|
</button>
|
|
</template>
|
|
</div>
|
|
<div class="header__col">
|
|
<Logo />
|
|
<div v-if="!selectedOrig.iata && !isPickerVisible" class="logo-blurb">
|
|
from one of <strong>{{ airports_orig.length }}</strong> <span style="color: white;">local</span> airports
|
|
</div>
|
|
<div v-if="selectedOrig.iata && !selectedDest.iata && airports_dest.length > 1 && !isPickerVisible" class="logo-blurb">
|
|
to one of <strong>{{ airports_dest.length }}</strong> {{ getCompliment() }} destinations
|
|
</div>
|
|
</div>
|
|
<div class="header__col" />
|
|
</header>
|
|
<!-- <pre style="position: fixed; z-index: 500; right: 0; top: 2rem; font-size: 0.6rem; color: gray;">
|
|
{{ selectedOrig }}
|
|
{{ selectedDest }}
|
|
</pre> -->
|
|
<main>
|
|
<nav v-if="isMounted" :class="['nav', { 'nav--show': isPickerVisible },{ 'nav--hide': !isPickerVisible }]">
|
|
<AirportPicker
|
|
:airports="airports_orig"
|
|
:selected-airport="selectedOrig"
|
|
leg="start here ►"
|
|
@select-airport="makeOrigin"
|
|
@deselect-airport="clearOrigin"
|
|
/>
|
|
<AirportPicker
|
|
v-show="selectedOrig.iata"
|
|
:airports="airports_dest"
|
|
:selected-airport="selectedDest"
|
|
leg="land here ■"
|
|
@select-airport="makeDestination"
|
|
@deselect-airport="clearDestination"
|
|
/>
|
|
</nav>
|
|
<Map
|
|
ref="mapComponent"
|
|
:airports-orig="airports_orig"
|
|
:airports-dest="airports_dest"
|
|
:selected-orig="selectedOrig"
|
|
:selected-dest="selectedDest"
|
|
@make-origin="makeOrigin"
|
|
@make-destination="makeDestination"
|
|
@clear-origin="clearOrigin"
|
|
@clear-destination="clearDestination"
|
|
/>
|
|
<div :class="['flyout-container',{ 'flyout-container--hide': !selectedOrig.iata || !selectedDest.iata },{ 'flyout-container--show': selectedOrig.iata && selectedDest.iata }]">
|
|
<FlightsFlyout
|
|
v-if="selectedOrig.iata && selectedDest.iata"
|
|
:selected-orig="selectedOrig"
|
|
:selected-dest="selectedDest"
|
|
/>
|
|
</div>
|
|
</main>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
// import AirportPicker from '../components/AirportPicker.vue'
|
|
export default {
|
|
// components: { AirportPicker },
|
|
data () {
|
|
return {
|
|
isMounted: false,
|
|
color: 'red',
|
|
isSidebarVisible: false,
|
|
isPickerVisible: false,
|
|
airports_orig: [],
|
|
airports_dest: [],
|
|
airportFetch_filterFormula: 'AND(Is_Origin=1,{IsCurrent-AsOrigin}=\'Yes\')',
|
|
airportFetch_fields: [
|
|
'Airport_IATA',
|
|
'Icon_Url',
|
|
'Latitude_Deg',
|
|
'Longitude_Deg',
|
|
'Municipality',
|
|
'Airport_Name',
|
|
'Type',
|
|
'Search_Field'
|
|
],
|
|
airportFetch_sort: '&sort[0][field]=Airport_IATA&sort[0][direction]=asc',
|
|
selectedOrig: {
|
|
iata: '',
|
|
lat: '',
|
|
long: '',
|
|
icon: '',
|
|
name: '',
|
|
municipality: '',
|
|
type: '',
|
|
search: ''
|
|
},
|
|
selectedDest: {
|
|
iata: '',
|
|
lat: '',
|
|
long: '',
|
|
icon: '',
|
|
name: '',
|
|
municipality: '',
|
|
type: '',
|
|
search: ''
|
|
},
|
|
emptyAirport: {
|
|
iata: '',
|
|
lat: '',
|
|
long: '',
|
|
icon: '',
|
|
name: '',
|
|
municipality: '',
|
|
type: '',
|
|
search: ''
|
|
}
|
|
}
|
|
},
|
|
async fetch () {
|
|
let offset
|
|
let data = []
|
|
|
|
while (true) {
|
|
const offsetParam = offset ? `&offset=${offset}` : ''
|
|
const res = await fetch(`https://api.airtable.com/v0/appiQwfVZixRgRICe/Airports_IATA?filterByFormula=${this.airportFetch_filterFormula}${this.airportFetch_fields_string}${this.airportFetch_sort}${offsetParam}`, {
|
|
method: 'GET',
|
|
headers: {
|
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
Authorization: 'Bearer keyJ2ht64ZSN57AG1'
|
|
}
|
|
})
|
|
|
|
const json = await res.json()
|
|
offset = await json.offset
|
|
data = [...data, ...await json.records]
|
|
await console.log(data.length)
|
|
|
|
if (await !offset) { break } // Were done let's stop this thing
|
|
}
|
|
|
|
// console.log('Look ma! I waited!') // Won't run till the while is done
|
|
|
|
this.airports_orig = data.map((record) => {
|
|
return {
|
|
iata: record.fields.Airport_IATA,
|
|
lat: record.fields.Latitude_Deg,
|
|
long: record.fields.Longitude_Deg,
|
|
icon: record.fields.Icon_Url,
|
|
name: record.fields.Airport_Name,
|
|
municipality: record.fields.Municipality,
|
|
type: record.fields.Type,
|
|
search: record.fields.Search_Field
|
|
}
|
|
})
|
|
},
|
|
computed: {
|
|
airportFetch_fields_string () {
|
|
const vm = this
|
|
const array = vm.airportFetch_fields.map((field) => {
|
|
return '&fields[]=' + field
|
|
})
|
|
return array.join('')
|
|
}
|
|
},
|
|
created () {
|
|
// console.log(this.$route.path)
|
|
|
|
if (this.$route && this.$route.params && this.$route.params.o) {
|
|
this.fetchSingleAirport(this.$route.params.o, true)
|
|
}
|
|
if (this.$route && this.$route.params && this.$route.params.d) {
|
|
this.fetchSingleAirport(this.$route.params.d, false)
|
|
}
|
|
},
|
|
mounted () {
|
|
this.isMounted = true
|
|
},
|
|
// watch: {
|
|
// history (to, from) {
|
|
// console.log(`routed from ${from} to ${to}`)
|
|
// }
|
|
// },
|
|
methods: {
|
|
getCompliment () {
|
|
const arr = [
|
|
'beautiful', 'gorgeous', 'breathtaking', 'wild', 'adventurous', 'amazing', 'majestic', 'uncharted', 'unpredictable', 'pristine', 'untamed'
|
|
]
|
|
return arr[Math.floor(Math.random() * arr.length)]
|
|
},
|
|
makeOrigin (airport) {
|
|
// console.log(airport)
|
|
|
|
this.selectedOrig = { ...airport }
|
|
|
|
this.selectedDest = { ...this.emptyAirport }
|
|
|
|
history.pushState(
|
|
{},
|
|
null,
|
|
'/go/' + encodeURIComponent(airport.iata)
|
|
)
|
|
|
|
this.fetchDestinations(airport.iata)
|
|
},
|
|
makeDestination (airport) {
|
|
this.selectedDest = { ...airport }
|
|
|
|
this.isPickerVisible = false
|
|
|
|
history.pushState(
|
|
{},
|
|
null,
|
|
'/go/' + encodeURIComponent(this.selectedOrig.iata) + '/' + encodeURIComponent(airport.iata)
|
|
)
|
|
},
|
|
clearOrigin () {
|
|
this.selectedOrig = { ...this.emptyAirport }
|
|
this.selectedDest = { ...this.emptyAirport }
|
|
history.pushState(
|
|
{},
|
|
null,
|
|
'/go/'
|
|
)
|
|
},
|
|
clearDestination () {
|
|
this.selectedDest = { ...this.emptyAirport }
|
|
history.pushState(
|
|
{},
|
|
null,
|
|
'/go/' + encodeURIComponent(this.selectedOrig.iata)
|
|
)
|
|
},
|
|
async fetchDestinations (iata) {
|
|
const airportFetchDestfilterFormula = `AND(Is_Destination=1,{IsCurrent-AsDest}="Yes",(FIND("${iata}", Associated_Origin_Search)>0))`
|
|
|
|
let offset
|
|
let data = []
|
|
|
|
while (true) {
|
|
const offsetParam = offset ? `&offset=${offset}` : ''
|
|
const res = await fetch(`https://api.airtable.com/v0/appiQwfVZixRgRICe/Airports_IATA?filterByFormula=${airportFetchDestfilterFormula}${this.airportFetch_fields_string}${this.airportFetch_sort}${offsetParam}`, {
|
|
method: 'GET',
|
|
headers: {
|
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
Authorization: 'Bearer keyJ2ht64ZSN57AG1'
|
|
}
|
|
})
|
|
|
|
const json = await res.json()
|
|
offset = await json.offset
|
|
data = [...data, ...await json.records]
|
|
// await console.log(data.length)
|
|
|
|
if (await !offset) { break } // Were done let's stop this thing
|
|
}
|
|
|
|
// console.log('Look ma! I waited!') // Won't run till the while is done
|
|
|
|
this.airports_dest = data.map((record) => {
|
|
return {
|
|
iata: record.fields.Airport_IATA,
|
|
lat: record.fields.Latitude_Deg,
|
|
long: record.fields.Longitude_Deg,
|
|
icon: record.fields.Icon_Url,
|
|
name: record.fields.Airport_Name,
|
|
municipality: record.fields.Municipality,
|
|
type: record.fields.Type,
|
|
search: record.fields.Search_Field
|
|
}
|
|
})
|
|
},
|
|
async fetchSingleAirport (iata, isOrig) {
|
|
const airportFetchFilterFormula =
|
|
isOrig
|
|
? `AND(Is_Origin=1,{IsCurrent-AsOrigin}="Yes",Airport_IATA="${iata}")`
|
|
: `AND(Is_Destination=1,{IsCurrent-AsDest}="Yes",Airport_IATA="${iata}")`
|
|
|
|
const response = await fetch(`https://api.airtable.com/v0/appiQwfVZixRgRICe/Airports_IATA?filterByFormula=${airportFetchFilterFormula}${this.airportFetch_fields_string}`, {
|
|
method: 'GET',
|
|
headers: {
|
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
Authorization: 'Bearer keyJ2ht64ZSN57AG1'
|
|
}
|
|
})
|
|
|
|
const mapData = await response.json()
|
|
|
|
const thisAirport = {
|
|
iata: mapData.records[0].fields.Airport_IATA,
|
|
lat: mapData.records[0].fields.Latitude_Deg,
|
|
long: mapData.records[0].fields.Longitude_Deg,
|
|
icon: mapData.records[0].fields.Icon_Url,
|
|
name: mapData.records[0].fields.Airport_Name,
|
|
municipality: mapData.records[0].fields.Municipality,
|
|
type: mapData.records[0].fields.Type,
|
|
search: mapData.records[0].fields.Search_Field
|
|
}
|
|
|
|
switch (isOrig) {
|
|
case true:
|
|
this.selectedOrig = { ...thisAirport }
|
|
this.fetchDestinations(thisAirport.iata)
|
|
break
|
|
|
|
case false:
|
|
this.selectedDest = { ...thisAirport }
|
|
break
|
|
|
|
default:
|
|
break
|
|
}
|
|
},
|
|
showPicker () {
|
|
const vm = this
|
|
vm.isPickerVisible = !vm.isPickerVisible
|
|
setTimeout(function () {
|
|
vm.$refs.mapComponent.resize()
|
|
}, 500)
|
|
},
|
|
showSidebar () {
|
|
this.isSidebarVisible = !this.isSidebarVisible
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
|
|
.logo-blurb {
|
|
position: absolute;
|
|
left: clamp(47% + 1rem, 51% - 2rem, 47%);
|
|
font-size: clamp(10px, 1rem, 18px);
|
|
color: white;
|
|
top: clamp(20px + 0.25rem, 4rem + 0.25rem, 50px + 0.25rem);
|
|
white-space: nowrap;
|
|
}
|
|
|
|
</style>
|