Slugy, webp, hromada refaktoringu

This commit is contained in:
Michal Kváček
2024-01-13 23:29:51 +01:00
parent e7cde2f425
commit 5a5c7cb645
57 changed files with 755 additions and 399 deletions
+17 -10
View File
@@ -22,7 +22,6 @@ const props = defineProps({
required: false,
default: null
}
})
</script>
@@ -34,8 +33,8 @@ const props = defineProps({
</q-item-section>
<q-item-section>
<router-link
:to="{...aircraftDetailRoute, params: {...aircraftDetailRoute.params, id: flight.aircraft.id}}"
v-if="aircraftDetailRoute"
:to="{...aircraftDetailRoute, params: {id: flight.aircraft.id, callSign: flight.aircraft.callSign}}"
v-if="aircraftDetailRoute"
>
{{ flight.aircraft.callSign }}
</router-link>
@@ -62,7 +61,9 @@ const props = defineProps({
</q-item-section>
<q-item-section>
<div>
<strong>{{ flight.takeoffAirport.icaoCode }}</strong> ({{ flight.takeoffAirport.name }}),
<template v-if="flight.takeoffAirport">
<strong>{{ flight.takeoffAirport.icaoCode }}</strong> ({{ flight.takeoffAirport.name }}),
</template>
čas vzletu: {{ formatDatetime(flight.takeoffDatetime, FORMAT_TIME) }}
<WeatherInfo class="q-mx-sm" v-if="flight.takeoffWeatherInfo" :weather="flight.takeoffWeatherInfo"/>
@@ -78,8 +79,8 @@ const props = defineProps({
<q-item-section>
<template v-if="poi.pointOfInterest">
<router-link
:to="{name: poiDetailRoute.name, params: {...poiDetailRoute.params, id: poi.pointOfInterest.id}}"
v-if="poi.pointOfInterest.isPublic"
:to="{name: poiDetailRoute.name, params: {...poiDetailRoute.params, poiSlug: poi.pointOfInterest.urlSlug, id: poi.pointOfInterest.id}}"
v-if="poi.pointOfInterest.isPublic"
>
{{ poi.pointOfInterest.name }}
</router-link>
@@ -87,7 +88,11 @@ const props = defineProps({
</template>
<span v-if="poi.airport">
<strong>{{ poi.airport.icaoCode }}</strong> ({{ poi.airport.name }}),
délka mezipřistání {{ minutesToHumanReadable(poi.landingDuration) }}
<template v-if="poi.landingDuration > 0">
délka mezipřistání {{ minutesToHumanReadable(poi.landingDuration) }}
</template>
<template v-else>touch and go</template>
</span>
</q-item-section>
</q-item>
@@ -98,7 +103,9 @@ const props = defineProps({
</q-item-section>
<q-item-section>
<div>
<strong>{{ flight.landingAirport.icaoCode }}</strong> ({{ flight.landingAirport.name }}),
<template v-if="flight.landingAirport">
<strong>{{ flight.landingAirport.icaoCode }}</strong> ({{ flight.landingAirport.name }}),
</template>
čas přistání: {{ formatDatetime(flight.landingDatetime, FORMAT_TIME) }}
<WeatherInfo class="q-mx-sm" v-if="flight.landingWeatherInfo" :weather="flight.landingWeatherInfo"/>
</div>
@@ -123,8 +130,8 @@ const props = defineProps({
</q-item-section>
<q-item-section>
<router-link
v-if="copilotDetailRoute"
:to="{name: copilotDetailRoute.name, params: {...copilotDetailRoute.params, id: copilot.id}}"
v-if="copilot.isPublic"
:to="{name: copilotDetailRoute.name, params: {...copilotDetailRoute.params, copilotSlug: copilot.urlSlug, id: copilot.id}}"
>
{{ copilot.name }}
</router-link>
+1 -1
View File
@@ -20,7 +20,7 @@ const poisWithGPS = computed(() => props.flight.track.map(poi => poi.pointOfInte
const mapMarkers = [props.flight.takeoffAirport].concat(poisWithGPS.value).concat([props.flight.landingAirport]);
const pointsOfInterests = computed(() => mapMarkers
.filter(marker => marker.gpsLatitude && marker.gpsLongitude)
.filter(marker => marker && marker.gpsLatitude && marker.gpsLongitude)
.map(
marker => ({label: marker.name, position: {lat: marker.gpsLatitude, lng: marker.gpsLongitude}})
));
+1 -1
View File
@@ -33,7 +33,7 @@ const props = defineProps({
const routeDetail = (flight) => {
if (props.public)
return {name: "publicFlightDetail", params: {username: flight.pilot.publicUsername, id: flight.id}}
return {name: "publicFlightDetail", params: {username: flight.pilot.publicUsername, flightSlug: flight.urlSlug}}
else
return {name: "flightDetail", params: {id: flight.id}}
};
+75 -68
View File
@@ -21,10 +21,10 @@ const props = defineProps({
required: false
},
isRequestPending: {
type: Boolean,
required: false,
default: false,
}
type: Boolean,
required: false,
default: false,
}
});
const airportName = (airport) => `${airport.icaoCode} (${airport.name})`;
@@ -32,8 +32,13 @@ const airportName = (airport) => `${airport.icaoCode} (${airport.name})`;
const airports = computed(() => props.airports.map(a => ({id: a.id, name: airportName(a)})));
const aircrafts = computed(() => props.aircrafts.map(a => ({id: a.id, name: a.callSign})));
const manualInput = ref(false);
const allowGPXUpload = ref(true);
const formData = reactive({
aircraft: null,
gpxTrackFile: null,
takeoffAirport: null,
landingAirport: null,
takeoffDatetime: null,
@@ -52,8 +57,14 @@ 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: airportName(newVal.takeoffAirport)}
formData.landingAirport = {id: newVal.landingAirport.id, name: airportName(newVal.landingAirport)}
if (newVal.takeoffAirport)
formData.takeoffAirport = {id: newVal.takeoffAirport.id, name: airportName(newVal.takeoffAirport)}
if (newVal.landingAirport)
formData.landingAirport = {id: newVal.landingAirport.id, name: airportName(newVal.landingAirport)}
allowGPXUpload.value = false;
manualInput.value = true;
}
}, {immediate: true});
watch(() => formData.takeoffDatetime, () => {
@@ -67,79 +78,75 @@ watch(() => formData.takeoffAirport, () => {
formData.landingAirport = {...formData.takeoffAirport};
}
});
</script>
<template>
<FormWrapper v-model="formData" :is-request-pending="props.isRequestPending">
<div class="row">
<div class="col">
<q-card class="q-my-sm">
<q-card-section>
<div class="text-h6">Vyber letadlo</div>
</q-card-section>
<q-card-section>
<ComboboxInput
:rules="rules.aircraft"
v-bind="commonProps"
:options="aircrafts"
v-model="formData.aircraft"
label="Letadlo"
/>
</q-card-section>
</q-card>
<ComboboxInput
:rules="rules.aircraft"
v-bind="commonProps"
:options="aircrafts"
v-model="formData.aircraft"
label="Letadlo"
/>
</div>
</div>
<div class="row">
<div class="col col-12 col-md-6">
<q-card class="q-mr-md-sm q-my-sm">
<q-card-section>
<div class="text-h6">Vzlet</div>
</q-card-section>
<q-card-section>
<DatetimePicker
v-model="formData.takeoffDatetime"
:rules="rules.takeoffDatetime"
label="Datum a čas vzletu: "
v-bind="commonProps"
/>
<ComboboxInput
:options="airports"
:rules="rules.takeoffAirport"
v-model="formData.takeoffAirport"
label="Letiště vzletu"
v-bind="commonProps"
/>
</q-card-section>
</q-card>
</div>
<div class="row" v-if="!manualInput">
<div class="col">
<div class="text-h6">Mám trasu v GPX, chci importovat data</div>
<q-file v-bind="commonProps" v-model="formData.gpxTrackFile" label="Trasa v GPX" hint="Z trasy se načtou letiště a časy vzletu a přistání. Tyto hodnoty je možné později upravit."/>
<div class="col col-12 col-md-6">
<q-card class="q-ml-md-sm q-my-sm">
<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"
:rules="rules.landingDatetime"
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"
:rules="rules.landingAirport"
/>
</q-card-section>
</q-card>
<div class="text-center">
<q-btn @click="manualInput = true" rounded flat>Zadat informace ručně</q-btn>
</div>
</div>
</div>
<div class="row" v-if="manualInput">
<div class="col col-12 col-md-6 q-pr-md-sm">
<div class="text-h6">Vzlet</div>
<DatetimePicker
v-model="formData.takeoffDatetime"
:rules="rules.takeoffDatetime"
label="Datum a čas vzletu: "
v-bind="commonProps"
/>
<ComboboxInput
:options="airports"
:rules="rules.takeoffAirport"
v-model="formData.takeoffAirport"
label="Letiště vzletu"
v-bind="commonProps"
/>
</div>
<div class="col col-12 col-md-6 q-pl-md-sm">
<div class="text-h6">Přistání</div>
<DatetimePicker
v-model="formData.landingDatetime"
:min-date="formData.takeoffDatetime"
:rules="rules.landingDatetime"
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"
:rules="rules.landingAirport"
/>
</div>
<div class="col-12 text-center" v-if="allowGPXUpload">
<q-btn @click="manualInput = false" rounded flat>Mám GPX, načíst informace z trasy</q-btn>
</div>
</div>
</FormWrapper>
</template>
@@ -5,6 +5,9 @@ import {setDefaultData} from "src/composables/form/formHandling";
import RichTextEditor from "components/inputs/RichTextEditor.vue";
import {commonProps} from "src/composables/inputs";
import ComboboxInput from "components/inputs/ComboboxInput.vue";
import SlugInput from "components/inputs/SlugInput.vue";
import {storeToRefs} from "pinia";
import {useLoggedUserStore} from "stores/LoggedUser";
const props = defineProps({
flight: {
@@ -25,9 +28,14 @@ const props = defineProps({
const formData = reactive({
name: "",
event: null,
description: ""
description: "",
urlSlug: "",
isPublic: null
})
const loggedUser = storeToRefs(useLoggedUserStore()).user;
watch(() => props.flight, (newVal) => {
if (newVal) {
setDefaultData(formData, newVal);
@@ -43,7 +51,18 @@ watch(() => props.flight, (newVal) => {
<template>
<FormWrapper v-model="formData" :is-request-pending="props.isRequestPending">
<ComboboxInput :options="events" v-if="events" v-model="formData.event" label="Událost" v-bind="commonProps"/>
<q-input type="text" v-model="formData.name" label="Jméno letu" v-bind="commonProps"/>
<q-input type="text" v-model="formData.name" label="Jméno letu" v-bind="commonProps" />
<template v-if="loggedUser?.publicUsername">
<SlugInput
v-if="formData.isPublic"
v-bind="commonProps"
v-model="formData.urlSlug"
label="URL"
:url="`/${loggedUser.publicUsername}/`"
:slug-source="formData.name"
/>
<q-checkbox v-model="formData.isPublic" label="Veřejný?"/>
</template>
<RichTextEditor v-model="formData.description" v-bind="commonProps" label="Popis letu, poznámky, ..."/>
</FormWrapper>
</template>
@@ -3,6 +3,7 @@ import FormWrapper from "components/FormWrapper.vue";
import {reactive, ref, watch} from "vue";
import ComboboxInput from "components/inputs/ComboboxInput.vue";
import {commonProps} from "src/composables/inputs";
import {minutesToHumanReadable} from "src/composables/datetimeUtils";
const props = defineProps({
modelValue: {
@@ -24,7 +25,7 @@ const props = defineProps({
const formData = reactive({
track: [],
gpxTrack: null
gpxTrackFile: null
});
const removeTrackItem = (index) => {
formData.track.splice(index, 1);
@@ -81,7 +82,7 @@ watch(() => props.flight.track, (newVal) => {
<q-file
accept=".gpx"
v-model="formData.gpxTrack"
v-model="formData.gpxTrackFile"
v-bind="commonProps"
label="Nahrát trasu v GPX"
hint="Slouží pro vykreslení kompletní a detailní trasy"
@@ -91,6 +92,8 @@ watch(() => props.flight.track, (newVal) => {
</template>
</q-file>
<h5>Body na mapě</h5>
<ComboboxInput
v-bind="commonProps"
v-model="poi"
@@ -103,7 +106,7 @@ watch(() => props.flight.track, (newVal) => {
/>
<div class="row">
<div class="col">
<div class="col-12 col-md-8">
<ComboboxInput
v-bind="commonProps"
v-model="airport"
@@ -111,16 +114,16 @@ watch(() => props.flight.track, (newVal) => {
:options="airports"
clearable
label="Letiště pro mezipřistání"
hint="Nastav letiště a dobu mezispřistání"
hint="Nastav letiště a dobu mezipřistání"
/>
</div>
<div class="col" v-if="airport?.name">
<div class="col-md-4 col-12" v-if="airport?.name">
<q-input
type="number"
v-bind="commonProps"
v-model="landingDuration"
label="Délka mezipřistání (minuty)"
class="q-mx-md"
class="q-mx-md-md"
>
<template #after>
<q-btn @click="addAirportToTrack(airport, landingDuration)" color="primary" icon="add"></q-btn>
@@ -136,7 +139,7 @@ watch(() => props.flight.track, (newVal) => {
<q-avatar color="primary" text-color="white" icon="flight_takeoff"/>
</q-item-section>
<q-item-section>
{{ flight.takeoffAirport.name }}
{{ flight.takeoffAirport?.name || '???' }}
</q-item-section>
</q-item>
@@ -153,7 +156,11 @@ watch(() => props.flight.track, (newVal) => {
</q-badge>
</span>
<span v-if="item.airport">
{{ item.airport.name }}, mezipřistání: {{ item.landingDuration }} minut
{{ item.airport.name }},
<template v-if="item.landingDuration > 0">
mezipřistání {{ minutesToHumanReadable(item.landingDuration) }}
</template>
<template v-else>touch and go</template>
</span>
</q-item-section>
@@ -167,7 +174,7 @@ watch(() => props.flight.track, (newVal) => {
<q-avatar color="primary" text-color="white" icon="flight_land"/>
</q-item-section>
<q-item-section>
{{ flight.landingAirport.name }}
{{ flight.landingAirport?.name || '???' }}
</q-item-section>
</q-item>
</q-list>