Argiris Deligiannidis 8a6a21d80c
All checks were successful
continuous-integration/drone/push Build is passing
PK index fixes
2024-04-15 02:26:34 +03:00

318 lines
12 KiB
Vue

<script>
import { defineNuxtComponent } from 'nuxt/app';
import utils from '~/assets/utils';
export default defineNuxtComponent({
props: {
modalState: {
type: Boolean,
},
weatherData: {
type: Object,
},
databaseLocations: {
type: Object,
},
locations: {
type: Object,
},
apiBaseURL: {
type: String,
},
},
computed: {
cmpDatabaseLocations() {
return this.databaseLocations;
},
},
data: () => ({
weatherIcons: utils.weatherIcons,
apiURL: '',
searchInput: '',
selectedIndex: '',
searchVisible: true,
userId: 1,
runtimeCode: 0,
locationData: [],
}),
methods: {
getDay(date) {
return utils.getDay(date);
},
closeModal() {
this.$emit('close-modal');
},
async addNewLocID(idx) {
await this.$parent.addNewLocID(idx);
},
getWeatherIcon(wmoCode) {
return utils.getWeatherIcon(wmoCode);
},
async addLocation(input) {
this.apiURL = `${this.apiBaseURL}/locations`;
if (input) {
await this.getDatabaseLocations(true);
var idx = 0;
for (let i = 0; i < this.cmpDatabaseLocations.length; i++) {
if (
this.databaseLocations[i]['name'].includes(input.name) &&
this.databaseLocations[i]['country'].includes(input.country)
) {
idx = i;
break;
}
}
if (idx > 0) {
if (!this.locations.includes(idx + 1)) {
await this.addNewLocID(idx + 1);
await this.fetchWeatherData(false, idx + 1);
}
await $fetch(this.apiURL, {
method: 'POST',
body: JSON.stringify({
id: idx + 1,
name: 'existing',
country: '',
longitude: 0,
latitude: 0,
user: this.userId,
}),
});
this.closeModal('add');
} else {
idx = 0;
for (let i = 0; i < this.databaseLocations.length; i++) {
if (this.databaseLocations[i]['id'] > idx) {
idx = this.databaseLocations[i]['id'];
}
}
await $fetch(this.apiURL, {
method: 'POST',
body: JSON.stringify({
id: idx + 1,
name: input.name,
country: input.country,
longitude: input.longitude,
latitude: input.latitude,
user: this.userId,
}),
});
await this.addNewLocID(idx + 1);
await this.fetchWeatherData(false, idx + 1);
this.displayNotification('add', input);
this.closeModal('add');
}
}
},
async searchLocations() {
this.apiURL = '';
if (this.searchInput.length > 1) {
this.locationData = [];
this.apiURL = this.apiBaseURL + '/location/search?query=' + this.searchInput;
await fetch(this.apiURL)
.then((res) => res.json())
.then((json) => {
this.locationData = json;
this.searchVisible = true;
});
} else {
this.locationData = [];
this.searchVisible = false;
}
},
getCountryFlag(countryCode) {
this.runtimeCode = 0;
try {
countryCode = countryCode.toLowerCase();
} catch (error) {
countryCode = 'xx';
this.runtimeCode = 1;
}
return `/flags/4x3/${countryCode}.svg`;
},
toggleSelection(input) {
if (this.locationData) {
if (this.selectedIndex) {
this.locationData[this.selectedIndex].selected = !this.locationData[this.selectedIndex].selected;
this.selectedIndex = '';
}
if (input != 'deselect') {
this.selectedIndex = input.index;
this.locationData[input.index].selected = !this.locationData[input.index].selected;
}
}
},
async getDatabaseLocations() {
await this.$parent.getDatabaseLocations();
},
async fetchWeatherData(bulk = false, location = null) {
await this.$parent.fetchWeatherData(bulk, location);
},
displayNotification(type, input) {
this.$parent.displayNotification(type, input);
},
},
name: 'Slideover Details',
emits: ['close-modal'],
});
const addOpen = ref(false);
defineShortcuts({
escape: {
usingInput: true,
whenever: [addOpen],
handler: () => {
addOpen.value = false;
},
},
});
</script>
<template>
<div>
<UModal
:ui="{
base: 'bg-opacity-0 overflow-visible min-w-80 min-h-50 ',
overlay: {
base: 'fixed inset-0 transition-opacity',
ring: '',
background: 'bg-black bg-opacity-80',
transition: {
enter: 'ease-out duration-300',
enterFrom: 'opacity-0',
enterTo: 'opacity-100',
leave: 'ease-in duration-200',
leaveFrom: 'opacity-100',
leaveTo: 'opacity-0',
},
},
}"
v-model="modalState"
prevent-close
:overlay="true"
@close-prevented="closeModal"
@close="closeModal"
>
<UCard
:ui="{
background: 'bg-woodsmoke-950',
divide: '',
ring: 'ring-0',
header: {
base: '',
padding: 'pb-3',
},
body: {
base: 'pt-2 px-8 pb-4',
padding: '',
},
}"
>
<template #header>
<div class="flex items-center justify-between">
<h3 class="text-base px-4 font-semibold text-gray-200">Add Location</h3>
<button
class="float-right text-justify text-md bg-shark-950 text-gray-200 hover:bg-linkwater-300 px-1 rounded-md"
@click="closeModal"
>
<UIcon name="i-heroicons-x-mark-16-solid" />
</button>
</div>
</template>
<div class="flex items-center">
<p class="text-base mx-auto text-center text-gray-200">Add Location</p>
</div>
<UInput
class="bg-mineshaft-950 border-mineshaft-950 text-gray-200 rounded-md"
v-model="searchInput"
name="q"
placeholder="Search..."
icon="i-heroicons-magnifying-glass-20-solid"
autocomplete="off"
variant="none"
@keyup="searchLocations(this.searchInput)"
:ui="{ icon: { trailing: { pointer: '' } } }"
>
<template #trailing>
<UButton
v-show="this.searchInput !== ''"
color="gray"
variant="link"
icon="i-heroicons-x-mark-20-solid"
:padded="false"
@click="
this.searchInput = '';
this.locationData = [];
"
/>
</template>
</UInput>
<div class="grid grid-rows-1">
<div
v-if="searchInput && this.runtimeCode == 0 && this.locationData"
class="text-center bg-mineshaft-950 z-50 border-mineshaft-950 text-gray-200"
v-for="(loc, index) in this.locationData"
:key="loc"
>
<div
@click="
toggleSelection({
index: index,
id: loc.id,
name: loc.name,
latitude: loc.latitude,
longitude: loc.longitude,
})
"
:class="{
'border-x-0 border-y-0 bg-linkwater-100 text-gray-800': loc.selected,
}"
class="p-2 border-b-2 columns-3 cursor-pointer hover:bg-linkwater-900"
v-if="this.searchVisible"
>
<div class="column w-1/2">
<img class="w-14" :src="getCountryFlag(loc.country_code)" alt="country flag icon" />
</div>
<div class="column">
<p>{{ loc.name }}</p>
<p>{{ loc.country }}</p>
</div>
<div class="column">
<p v-if="loc.latitude" class="text-sm">Lat: {{ loc.latitude.toFixed(4) }}</p>
<p v-if="loc.longitude" class="text-sm">Lon: {{ loc.longitude.toFixed(4) }}</p>
</div>
</div>
</div>
<div
class="text-center bg-mineshaft-950 z-50 border-mineshaft-950 text-gray-200"
v-if="searchInput && !this.searchVisible"
>
<p class="my-2">No location found!</p>
</div>
</div>
<div v-if="this.selectedIndex" class="flex items-center mt-3">
<button
class="w-full text-center text-sm bg-linkwater-100 text-gray-900 hover:bg-linkwater-300 font-bold py-2 rounded-md"
@click="this.addLocation(this.locationData[this.selectedIndex])"
>
Add Location
</button>
</div>
<div v-else class="flex items-center mt-3">
<UTooltip class="w-full" text="Select a location first" :popper="{ arrow: true }">
<button
class="cursor-not-allowed w-full text-center text-sm bg-linkwater-100 text-gray-900 hover:bg-shark-900 font-bold py-2 rounded-md"
>
Add Location
</button>
</UTooltip>
</div>
</UCard>
</UModal>
</div>
</template>