Verejna cast, hezci 404ka, refaktoring
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
<script setup>
|
||||
import {flight} from "src/composables/objects/flight";
|
||||
import MapWithMarkers from "components/map/MapWithMarkers.vue";
|
||||
import {computed} from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
flight: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
const trackWithGPS = computed(() => {
|
||||
return flight.value.track.filter(poi => poi.pointOfInterest.gpsLatitude && poi.pointOfInterest.gpsLongitude)
|
||||
});
|
||||
|
||||
const pointsOfInterests = computed(() => {
|
||||
const path = [{
|
||||
label: flight.value.takeoffAirport.name,
|
||||
position:
|
||||
{
|
||||
lat: flight.value.takeoffAirport.gpsLatitude,
|
||||
lng: flight.value.takeoffAirport.gpsLongitude
|
||||
}
|
||||
}];
|
||||
|
||||
for (const poi of trackWithGPS.value) {
|
||||
path.push({
|
||||
label: poi.pointOfInterest.name,
|
||||
position: {lat: poi.pointOfInterest.gpsLatitude, lng: poi.pointOfInterest.gpsLongitude}
|
||||
});
|
||||
}
|
||||
|
||||
path.push({
|
||||
label: flight.value.takeoffAirport.name,
|
||||
position: {
|
||||
lat: flight.value.landingAirport.gpsLatitude,
|
||||
lng: flight.value.landingAirport.gpsLongitude
|
||||
}
|
||||
});
|
||||
|
||||
return path;
|
||||
});
|
||||
|
||||
|
||||
const mapPhotos = computed(() => {
|
||||
return flight.value.photos.filter(photo => photo.gpsLatitude && photo.gpsLongitude)
|
||||
});
|
||||
|
||||
const displayMap = computed(() => {
|
||||
return (
|
||||
!!flight.value.gpsTrackUrl ||
|
||||
mapPhotos.value.length > 0 ||
|
||||
trackWithGPS.value.length > 0 ||
|
||||
flight.value.landingAirport.id !== flight.value.takeoffAirport.id
|
||||
)
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<MapWithMarkers
|
||||
v-if="displayMap"
|
||||
style="width: 100%; height: 500px;"
|
||||
:gpx-track-url="flight.gpxTrackUrl"
|
||||
:markers="pointsOfInterests"
|
||||
:photos="mapPhotos"
|
||||
/>
|
||||
</template>
|
||||
@@ -18,7 +18,7 @@ const props = defineProps({
|
||||
displayVisibilityInfo: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
default: true
|
||||
}
|
||||
});
|
||||
|
||||
@@ -33,12 +33,12 @@ const props = defineProps({
|
||||
:to="{name: routeDetail.name, params:{...routeDetail.params, id: flight.id}}"
|
||||
>
|
||||
<q-item-section avatar>
|
||||
<q-avatar size="100px">
|
||||
<div v-if="flight.coverPhoto" :style="`width: 100px; height: 100px; background-image: url('${flight.coverPhoto.thumbnailUrl}'); background-size: cover`"></div>
|
||||
<q-avatar size="150px">
|
||||
<div v-if="flight.coverPhoto" :style="`width: 150px; height: 150px; background-image: url('${flight.coverPhoto.thumbnailUrl}'); background-size: cover`"></div>
|
||||
</q-avatar>
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
{{ flightName(flight) }}
|
||||
<h5>{{ flightName(flight) }}</h5>
|
||||
<div class="text-secondary">
|
||||
<q-icon name="flight_takeoff"/>
|
||||
{{ formatDatetime(flight.takeoffDatetime) }}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
<script setup>
|
||||
import PhotoDetail from "components/photos/PhotoDetail.vue";
|
||||
import { ref, watch} from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
photos: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
coverPhotoUrl: {
|
||||
type: String,
|
||||
required: false
|
||||
}
|
||||
})
|
||||
|
||||
const displayedPhoto = ref(null);
|
||||
const openPhotoDetail = ref(false);
|
||||
const photoData = ref(null);
|
||||
const openDetail = ({photo, idx, allPhotos}) => {
|
||||
openPhotoDetail.value = true;
|
||||
photoData.value = {photo, idx, allPhotos}
|
||||
}
|
||||
|
||||
watch(() => props.photos, (newVal) => {
|
||||
if (newVal.length === 0) return;
|
||||
displayedPhoto.value = props.coverPhotoUrl || newVal[0].url;
|
||||
}, {immediate: true});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<q-carousel
|
||||
v-if="photos.length > 0"
|
||||
animated
|
||||
v-model="displayedPhoto"
|
||||
arrows
|
||||
swipeable
|
||||
height="auto"
|
||||
infinite
|
||||
>
|
||||
<q-carousel-slide style="padding: 0" v-for="(photo, idx) in photos" :key="photo.url" :name="photo.url">
|
||||
<q-img :src="photo.url" @click="openDetail({photo, idx, allPhotos: photos})"/>
|
||||
</q-carousel-slide>
|
||||
</q-carousel>
|
||||
|
||||
<PhotoDetail
|
||||
v-if="photoData"
|
||||
v-model="openPhotoDetail"
|
||||
:photo="photoData.photo"
|
||||
:photos="photoData.allPhotos"
|
||||
:opened-index="photoData.idx"
|
||||
/>
|
||||
</template>
|
||||
@@ -21,6 +21,7 @@ const props = defineProps({
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const formData = reactive({
|
||||
aircraft: null,
|
||||
takeoffAirport: null,
|
||||
@@ -28,89 +29,107 @@ const formData = reactive({
|
||||
takeoffDatetime: null,
|
||||
landingDatetime: null,
|
||||
landings: 1,
|
||||
isPublic: false,
|
||||
name: "",
|
||||
description: "",
|
||||
})
|
||||
|
||||
const recalculateDuration = (data) => {
|
||||
const diff = data.landingDatetime - data.takeoffDatetime;
|
||||
data.durationTotal = diff / 1000 / 60;
|
||||
}
|
||||
|
||||
watch(() => [formData.takeoffDatetime, formData.landingDatetime], () => recalculateDuration(formData))
|
||||
});
|
||||
|
||||
const rules = {};
|
||||
const isMounted = ref(false);
|
||||
// tohle je blby ohack kvuli tomu, ze DatetimeInput se renderuje jeste pred mounted a do props nedostane hodnotu
|
||||
// modelu. A neumi se s tim smirit...
|
||||
onMounted(() => {
|
||||
if (props.flight) {
|
||||
setDefaultData(formData, props.flight);
|
||||
formData.aircraft = {id: formData.aircraft.id, name: formData.aircraft.callSign};
|
||||
formData.takeoffAirport = {id: formData.takeoffAirport.id, name: formData.takeoffAirport.name}
|
||||
formData.landingAirport = {id: formData.landingAirport.id, name: formData.landingAirport.name}
|
||||
watch(() => props.flight, (newVal) => {
|
||||
if (newVal) {
|
||||
setDefaultData(formData, newVal);
|
||||
formData.aircraft = {id: newVal.aircraft.id, name: newVal.aircraft.callSign};
|
||||
formData.takeoffAirport = {id: newVal.takeoffAirport.id, name: newVal.takeoffAirport.name}
|
||||
formData.landingAirport = {id: newVal.landingAirport.id, name: newVal.landingAirport.name}
|
||||
}
|
||||
isMounted.value = true;
|
||||
});
|
||||
}, {immediate: true});
|
||||
|
||||
const aircrafts = computed(() => {
|
||||
return props.aircrafts.map(a => ({id: a.id, name: a.callSign}));
|
||||
});
|
||||
|
||||
watch(() => formData.takeoffDatetime, () => {
|
||||
if (!formData.landingDatetime) {
|
||||
formData.landingDatetime = formData.takeoffDatetime;
|
||||
}
|
||||
});
|
||||
watch(() => formData.takeoffAirport, () => {
|
||||
if (!formData.landingAirport) {
|
||||
formData.landingAirport = {...formData.takeoffAirport};
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FormWrapper v-model="formData" v-if="isMounted">
|
||||
<FormWrapper v-model="formData">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<ComboboxInput
|
||||
v-bind="commonProps"
|
||||
:options="aircrafts"
|
||||
v-model="formData.aircraft"
|
||||
:key="formData.aircraft"
|
||||
label="Letadlo"
|
||||
/>
|
||||
<q-card class="q-mx-md q-my-md">
|
||||
<q-card-section>
|
||||
<div class="text-h6">Vyber letadlo</div>
|
||||
</q-card-section>
|
||||
|
||||
<q-card-section>
|
||||
<ComboboxInput
|
||||
v-bind="commonProps"
|
||||
:options="aircrafts"
|
||||
v-model="formData.aircraft"
|
||||
:key="formData.aircraft"
|
||||
label="Letadlo"
|
||||
/>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col col-12 col-md-6">
|
||||
<h3>Vzlet</h3>
|
||||
<DatetimePicker
|
||||
v-model="formData.takeoffDatetime"
|
||||
label="Datum a čas vzletu: "
|
||||
v-bind="commonProps"
|
||||
/>
|
||||
<ComboboxInput
|
||||
:options="airports"
|
||||
v-model="formData.takeoffAirport"
|
||||
label="Letiště vzletu"
|
||||
v-bind="commonProps"
|
||||
:enable-new-values="false"
|
||||
/>
|
||||
<q-card class="q-mx-md q-my-md">
|
||||
<q-card-section>
|
||||
<div class="text-h6">Vzlet</div>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
<DatetimePicker
|
||||
v-model="formData.takeoffDatetime"
|
||||
label="Datum a čas vzletu: "
|
||||
v-bind="commonProps"
|
||||
/>
|
||||
|
||||
<ComboboxInput
|
||||
:options="airports"
|
||||
v-model="formData.takeoffAirport"
|
||||
label="Letiště vzletu"
|
||||
v-bind="commonProps"
|
||||
:enable-new-values="false"
|
||||
/>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
</div>
|
||||
|
||||
<div class="col col-12 col-md-6">
|
||||
|
||||
<h3>Přistání</h3>
|
||||
<DatetimePicker
|
||||
v-model="formData.landingDatetime"
|
||||
:min-date="formData.takeoffDatetime"
|
||||
label="Datum a čas přistání"
|
||||
v-bind="commonProps"
|
||||
/>
|
||||
<q-card class="q-mx-md q-my-md">
|
||||
<q-card-section>
|
||||
<div class="text-h6">Přistání</div>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
<DatetimePicker
|
||||
v-model="formData.landingDatetime"
|
||||
:min-date="formData.takeoffDatetime"
|
||||
label="Datum a čas přistání"
|
||||
v-bind="commonProps"
|
||||
/>
|
||||
|
||||
<ComboboxInput
|
||||
:options="airports"
|
||||
v-model="formData.landingAirport"
|
||||
label="Letiště přistání"
|
||||
v-bind="commonProps"
|
||||
:enable-new-values="false"
|
||||
/>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
|
||||
|
||||
<ComboboxInput
|
||||
:options="airports"
|
||||
v-model="formData.landingAirport"
|
||||
label="Letiště přistání"
|
||||
v-bind="commonProps"
|
||||
:enable-new-values="false"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</FormWrapper>
|
||||
|
||||
@@ -51,6 +51,11 @@ onMounted(() => {
|
||||
<template>
|
||||
<FormWrapper v-model="formData">
|
||||
|
||||
<q-banner class="bg-green text-white" v-if="flight.gpxTrackUrl">
|
||||
<q-icon name="check"/>
|
||||
Trasa nahrána
|
||||
</q-banner>
|
||||
|
||||
<q-file
|
||||
accept=".gpx"
|
||||
v-model="formData.gpxTrack"
|
||||
@@ -59,14 +64,10 @@ onMounted(() => {
|
||||
hint="Slouží pro vykreslení kompletní a detailní trasy"
|
||||
>
|
||||
<template #prepend>
|
||||
<q-icon name="upload" />
|
||||
<q-icon name="upload"/>
|
||||
</template>
|
||||
</q-file>
|
||||
|
||||
<template v-if="flight.gpxTrackUrl">
|
||||
<q-icon name="check" color="green" /> Trasa nahrána
|
||||
</template>
|
||||
|
||||
<ComboboxInput
|
||||
v-bind="commonProps"
|
||||
v-model="poi"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script setup>
|
||||
import {computed, onMounted, ref} from "vue";
|
||||
import {computed, onMounted, ref, watch} from "vue";
|
||||
import {FORMAT_DATETIME_LONG, FORMAT_ISO, formatDatetime, parseDate} from "src/composables/datetimeUtils";
|
||||
import {commonProps} from "src/composables/inputs";
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
@@ -21,24 +22,25 @@ let dateModel = ref("");
|
||||
let timeModel = ref("");
|
||||
|
||||
let originalTime, originalDate;
|
||||
onMounted(() => {
|
||||
let emitDefaultValue = false;
|
||||
if (props.modelValue) {
|
||||
let modelVal = props.modelValue;
|
||||
if (typeof modelVal === 'string') {
|
||||
modelVal = parseDate(props.modelValue);
|
||||
emitDefaultValue = true;
|
||||
}
|
||||
|
||||
dateModel.value = formatDatetime(modelVal, "YYYY-MM-DD");
|
||||
timeModel.value = formatDatetime(modelVal, "HH:mm:ss");
|
||||
}
|
||||
|
||||
setOriginalValues();
|
||||
if (emitDefaultValue) {
|
||||
emitModelUpdate();
|
||||
}
|
||||
});
|
||||
// onMounted(() => {
|
||||
// let emitDefaultValue = false;
|
||||
// if (props.modelValue) {
|
||||
// let modelVal = props.modelValue;
|
||||
// if (typeof modelVal === 'string') {
|
||||
// modelVal = parseDate(props.modelValue);
|
||||
// emitDefaultValue = true;
|
||||
// }
|
||||
//
|
||||
// dateModel.value = formatDatetime(modelVal, "YYYY-MM-DD");
|
||||
// timeModel.value = formatDatetime(modelVal, "HH:mm:ss");
|
||||
// }
|
||||
//
|
||||
// setOriginalValues();
|
||||
// if (emitDefaultValue) {
|
||||
// emitModelUpdate();
|
||||
// }
|
||||
// });
|
||||
// TODO: ^^ by asi slo prepsat do watchera, viz ComboboxInput
|
||||
|
||||
|
||||
@@ -57,7 +59,9 @@ const emit = defineEmits(['update:modelValue']);
|
||||
const emitModelUpdate = () => {
|
||||
const val = parseDate(model.value);
|
||||
emit("update:modelValue", val);
|
||||
popupProxy.value.hide();
|
||||
|
||||
if (popupProxy.value)
|
||||
popupProxy.value.hide();
|
||||
}
|
||||
|
||||
const containsAnyOf = (needles, haystack) => {
|
||||
@@ -103,10 +107,28 @@ const isDateValid = (date) => {
|
||||
return date >= minDate;
|
||||
}
|
||||
|
||||
watch(() => props.modelValue, (newVal) => {
|
||||
let emitDefaultValue = false;
|
||||
if (newVal) {
|
||||
let modelVal = newVal;
|
||||
if (typeof modelVal === 'string') {
|
||||
modelVal = parseDate(newVal);
|
||||
emitDefaultValue = true;
|
||||
}
|
||||
|
||||
dateModel.value = formatDatetime(modelVal, "YYYY-MM-DD");
|
||||
timeModel.value = formatDatetime(modelVal, "HH:mm:ss");
|
||||
}
|
||||
|
||||
setOriginalValues();
|
||||
if (emitDefaultValue) {
|
||||
emitModelUpdate();
|
||||
}
|
||||
}, {immediate: true});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<q-input readonly v-model="publicModel">
|
||||
<q-input readonly v-bind="commonProps" v-model="publicModel">
|
||||
<template #append>
|
||||
<q-icon name="event"/>
|
||||
</template>
|
||||
|
||||
@@ -30,7 +30,7 @@ const openDetail = (photo, idx) => {
|
||||
<div class="col-12 col-sm-4 col-md-4 col-lg-3" v-for="(photo, idx) in photos" :key="photo.id">
|
||||
<q-card class="q-my-sm q-mx-sm">
|
||||
<q-img :src="photo.thumbnailUrl" @click="openDetail(photo, idx)">
|
||||
<div class="absolute-bottom">
|
||||
<div class="absolute-bottom" v-if="photo.name !== '' || photo.description !== ''">
|
||||
<div class="text-h6" v-if="photo.name !== ''">
|
||||
{{ photo.name }}
|
||||
</div>
|
||||
|
||||
@@ -13,9 +13,9 @@ const props = defineProps({
|
||||
}
|
||||
});
|
||||
const formData = reactive({
|
||||
name: null,
|
||||
publicUsername: null,
|
||||
description: null,
|
||||
name: '',
|
||||
publicUsername: '',
|
||||
description: '',
|
||||
avatarImage: null,
|
||||
titleImage: null,
|
||||
});
|
||||
|
||||
@@ -18,7 +18,7 @@ const openDetail = ref(false);
|
||||
|
||||
<template>
|
||||
|
||||
<q-btn rounded @click="openDetail = true" v-bind="$attrs">
|
||||
<q-btn rounded flat @click="openDetail = true" v-bind="$attrs">
|
||||
<CloudCoverIcon :cloudcover="weather.cloudcoverTotal"/>
|
||||
|
||||
<q-icon name="navigation" :style="`transform: rotate(${weather.windDirectionSurface}deg)`"/>
|
||||
|
||||
Reference in New Issue
Block a user