Jiny pristup k vytvareni letu, polofunkcni editace letu

This commit is contained in:
Michal Kváček
2023-06-27 22:45:24 +02:00
parent 4d9950e362
commit d399e1aaf1
20 changed files with 672 additions and 261 deletions
-213
View File
@@ -1,213 +0,0 @@
<script setup>
import LocationInput from "components/inputs/LocationInput.vue";
import TabsStepper from "components/TabsStepper.vue";
import FormWrapper from "components/FormWrapper.vue";
import {computed, reactive, ref, watch} from "vue";
import {isRequired} from "src/composables/form/rules";
import DatetimePicker from "components/inputs/DatetimePicker.vue";
const props = defineProps({
aircrafts: {
type: Array,
required: true
},
airports: {
type: Array,
required: true
},
locations: {
type: Array,
required: true
}
}
)
const formData = reactive({
aircraftId: 43,
takeoffAirportId: 3,
landingAirportId: 3,
takeoffDatetime: new Date("2023-06-05T09:55:01"),
landingDatetime: new Date("2023-06-05T10:41:51"),
photos: [],
// turnPoints: [],
copilotId: null,
solo: true,
withInstructor: false,
durationPic: 0,
durationTotal: null,
landings: 1,
name: "",
description: ""
})
const rules = {
aircraft: [isRequired],
takeoffAirport: [],
landingAirport: [],
}
const recalculateDuration = () => {
const diff = formData.landingDatetime - formData.takeoffDatetime;
formData.durationTotal = diff / 1000 / 60;
}
watch(() => formData.takeoffDatetime, () => recalculateDuration())
watch(() => formData.landingDatetime, () => recalculateDuration())
const formSteps = ["basic", "copilot", "track", "photos", "notes"]
const formStep = ref(formSteps[0]);
const basicInfoFilled = computed(() => {
return (
formData.aircraftId && formData.takeoffAirportId && formData.landingAirportId && formData.takeoffDatetime
&& formData.landingDatetime
)
})
</script>
<template>
<FormWrapper v-model="formData">
<template #default>
<pre>{{ formData }}</pre>
<q-tabs
v-model="formStep"
outside-arrows
mobile-arrows
left-icon="chevron_left"
right-icon="chevron_right"
active-color="primary"
class="q-mb-lg"
>
<q-tab name="basic" icon="flight_takeoff" label="Základní informace"/>
<q-tab name="copilot" icon="person_add" label="Spolucestující"/>
<q-tab name="track" icon="route" label="Trasa"/>
<q-tab name="photos" icon="add_a_photo" label="Fotky"/>
<q-tab name="notes" icon="edit_note" label="Poznámky"/>
</q-tabs>
<q-tab-panels v-model="formStep" animated>
<q-tab-panel name="basic">
<div class="row">
<div class="col">
<q-select
v-model="formData.aircraftId"
option-label="name"
option-value="id"
emit-value
map-options
:rules="rules.aircraft"
:options="aircrafts"
label="Letadlo"
>
<template #prepend>
<q-icon name="flight"></q-icon>
</template>
</q-select>
</div>
</div>
<template v-if="formData.aircraftId">
<div class="row">
<div class="col">
<h3>Vzlet</h3>
<DatetimePicker v-model="formData.takeoffDatetime" label="Datum a čas vzletu"/>
<LocationInput label="Letiště vzletu" :rules="rules.takeoffAirport" :locations="airports" v-model="formData.takeoffAirportId" prepend-icon="flight_takeoff"/>
</div>
</div>
<div class="row" v-if="!!formData.takeoffDatetime && !!formData.takeoffAirportId">
<div class="col">
<h3>Přistání</h3>
<LocationInput label="Letiště přistání" :rules="rules.landingAirport" :locations="airports" v-model="formData.landingAirportId" prepend-icon="flight_land"/>
<DatetimePicker v-model="formData.landingDatetime" label="Datum a čas přistání"/>
<div class="row">
<div class="col">
<q-input v-model="formData.landings" label="Počet přistání" type="number" min="1"/>
</div>
<div class="col">
<q-input v-model="formData.durationTotal" readonly min=0 label="Délka letu (v minutách)" type="number"/>
</div>
</div>
</div>
</div>
<TabsStepper v-model="formStep" next-step="track" v-if="formData.landingAirportId"/>
</template>
</q-tab-panel>
<q-tab-panel name="copilot">
<q-btn-toggle spread no-caps v-model="formData.solo" toggle-color="primary" :options="[{label: 'Solo flight', value: true}, {label: 'Flight with someone', value: false}]"/>
<div v-if="!formData.solo">
<q-input type="text" v-model="formData.secondPilot" label="Second pilot"/>
<q-checkbox v-model="formData.instructor" v-if="formData.secondPilot !== ''" label="Instructor"/>
<!-- <q-input v-model="formData.picTime" label="PIC time"/>-->
</div>
<TabsStepper v-model="formStep" previous-step="basic" next-step="track"/>
</q-tab-panel>
<q-tab-panel name="track">
<!-- <template v-for="i in turnPointsCount" :key="`${i}-${turnPointsCount}`">-->
<!-- <LocationInput label="Turn point" :locations="locations" v-model="formData.turnPoints[i-1]">-->
<!-- <template #append v-if="i > 1">-->
<!-- <q-btn @click="removeTurnPoint(i - 1)">-</q-btn>-->
<!-- </template>-->
<!-- </LocationInput>-->
<!-- </template>-->
<!-- <q-btn @click="turnPointsCount++">-->
<!-- Add turn point-->
<!-- </q-btn>-->
<q-uploader
label="Upload GPX track"
url="http://localhost:4444/upload"
class="q-mx-sm"
style="width: 100%"
auto-upload
color="secondary"
/>
<TabsStepper v-model="formStep" previous-step="copilot" next-step="photos"/>
</q-tab-panel>
<q-tab-panel name="photos">
<q-file
label="Upload photos"
multiple
style="width: 100%;"
color="secondary"
/>
<TabsStepper v-model="formStep" previous-step="copilot" next-step="notes"/>
</q-tab-panel>
<q-tab-panel name="notes">
<q-input type="text" v-model="formData.name" label="Nazev"/>
<q-editor v-model="formData.description" height="60vh" label="Poznámky"/>
<TabsStepper v-model="formStep" previous-step="photos"/>
</q-tab-panel>
</q-tab-panels>
</template>
<template #saveButton>
<q-page-sticky expand position="bottom" :offset="[10, 10]" v-if="basicInfoFilled">
<div>
<q-btn type="submit" size="lg" class="full-width" color="primary" icon="save" label="Save flight"/>
</div>
</q-page-sticky>
</template>
</FormWrapper>
</template>
+88
View File
@@ -0,0 +1,88 @@
<script setup>
import LocationInput from "components/inputs/LocationInput.vue";
import TabsStepper from "components/TabsStepper.vue";
import FormWrapper from "components/FormWrapper.vue";
import {computed, reactive, ref, watch} from "vue";
import {isRequired} from "src/composables/form/rules";
import DatetimePicker from "components/inputs/DatetimePicker.vue";
import FlightFormBasic from "components/flights/form/FlightFormBasic.vue";
const rules = {
aircraft: [isRequired],
takeoffAirport: [],
landingAirport: [],
}
const formSteps = ["basic", "copilot", "track", "photos", "notes"]
const formStep = ref(formSteps[0]);
const basicInfoFilled = computed(() => {
return (
formData.aircraftId && formData.takeoffAirportId && formData.landingAirportId && formData.takeoffDatetime
&& formData.landingDatetime
)
})
</script>
<template>
<!-- <FormWrapper v-model="formData">-->
<!-- <template #default>-->
<pre>{{ formData }}</pre>
<q-tab-panels v-model="formStep" animated>
<q-tab-panel name="track">
<!-- <template v-for="i in turnPointsCount" :key="`${i}-${turnPointsCount}`">-->
<!-- <LocationInput label="Turn point" :locations="locations" v-model="formData.turnPoints[i-1]">-->
<!-- <template #append v-if="i > 1">-->
<!-- <q-btn @click="removeTurnPoint(i - 1)">-</q-btn>-->
<!-- </template>-->
<!-- </LocationInput>-->
<!-- </template>-->
<!-- <q-btn @click="turnPointsCount++">-->
<!-- Add turn point-->
<!-- </q-btn>-->
<q-file
label="Upload GPX track"
class="q-mx-sm"
style="width: 100%"
color="secondary"
/>
<TabsStepper v-model="formStep" previous-step="copilot" next-step="photos"/>
</q-tab-panel>
<q-tab-panel name="photos">
<q-file
label="Upload photos"
v-model="formData.photos"
multiple
style="width: 100%;"
color="secondary"
/>
<TabsStepper v-model="formStep" previous-step="copilot" next-step="notes"/>
</q-tab-panel>
</q-tab-panels>
<!-- </template>-->
<!-- <template #saveButton>-->
<!-- <q-page-sticky expand position="bottom" :offset="[10, 10]" v-if="basicInfoFilled">-->
<!-- <div>-->
<!-- <q-btn type="submit" size="lg" class="full-width" color="primary" icon="save" label="Save flight"/>-->
<!-- </div>-->
<!-- </q-page-sticky>-->
<!-- </template>-->
<!-- </FormWrapper>-->
</template>
@@ -0,0 +1,148 @@
<script setup>
import DatetimePicker from "components/inputs/DatetimePicker.vue";
import {onMounted, reactive, ref, watch} from "vue";
import FormWrapper from "components/FormWrapper.vue";
import {setDefaultData} from "src/composables/form/formHandling";
import {formatDate, parseDate} from "src/composables/datetimeUtils";
const props = defineProps({
aircrafts: {
type: Array,
required: true
},
airports: {
type: Array,
required: true
},
locations: {
type: Array,
required: true
},
flight: {
type: Object,
required: false
}
}
)
const formData = reactive({
aircraftId: 43,
takeoffAirportId: null,
landingAirportId: null,
takeoffDatetime: null,
landingDatetime: null,
durationTotal: null,
landings: 1,
solo: true,
durationPic: 0,
withInstructor: false,
copilotId: null,
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);
}
isMounted.value = true;
});
</script>
<template>
<FormWrapper v-model="formData" v-if="isMounted">
{{ formData }}
<hr>
{{ flight }}
<hr>
<div class="row">
<div class="col">
<q-select
v-model="formData.aircraftId"
option-label="name"
option-value="id"
emit-value
map-options
:rules="rules.aircraft"
:options="aircrafts"
label="Letadlo"
>
<template #prepend>
<q-icon name="flight"></q-icon>
</template>
</q-select>
</div>
</div>
<template v-if="formData.aircraftId">
<div class="row">
<div class="col">
<h3>Vzlet</h3>
<DatetimePicker v-model="formData.takeoffDatetime" label="Datum a čas vzletu"/>
<q-select
v-model="formData.takeoffAirportId"
emit-value
map-options
option-label="name"
option-value="id"
clearable
:options="airports"
label="Letiště vzletu">
<template #prepend>
<q-icon name="flight_takeoff"/>
</template>
</q-select>
<q-checkbox v-model="formData.solo" label="Solo?"/>
</div>
<div class="col" data-if="!!formData.takeoffDatetime && !!formData.takeoffAirportId">
<h3>Přistání</h3>
<DatetimePicker v-model="formData.landingDatetime" label="Datum a čas přistání"/>
<q-select
v-model="formData.landingAirportId"
emit-value
map-options
option-label="name"
option-value="id"
clearable
:options="airports"
label="Letiště přistání">
<template #append>
<q-icon name="flight_land"/>
</template>
</q-select>
</div>
</div>
<div class="row" v-if="formData.landingAirportId">
<div class="col">
<q-input v-model="formData.landings" label="Počet přistání" type="number" min="1"/>
</div>
<div class="col">
<q-input v-model="formData.durationTotal" readonly min=0 label="Délka letu (v minutách)" type="number"/>
</div>
</div>
<!-- <TabsStepper v-model="formStep" next-step="track" v-if="formData.landingAirportId"/>-->
</template>
</FormWrapper>
</template>
@@ -0,0 +1,35 @@
<script setup>
import {reactive} from "vue";
import FormWrapper from "components/FormWrapper.vue";
const props = defineProps({
flight: {
type: Object,
required: false
},
copilots: {
type: Array,
required: true
}
});
const formData = reactive({
solo: true,
withInstructor: false,
copilotId: null,
})
</script>
<template>
<FormWrapper v-model="formData">
<q-btn-toggle spread no-caps v-model="formData.solo" toggle-color="primary" :options="[{label: 'Solo', value: true}, {label: 'S někým', value: false}]"/>
<div v-if="!formData.solo">
<q-input type="text" v-model="formData.secondPilot" label="Druhý pilot"/>
<q-checkbox v-model="formData.withInstructor" v-if="formData.secondPilot !== ''" label="Instruktor"/>
<!-- <q-input v-model="formData.picTime" label="PIC time"/>-->
</div>
</FormWrapper>
</template>
@@ -0,0 +1,34 @@
<script setup>
import {onMounted, ref} from "vue";
import FormWrapper from "components/FormWrapper.vue";
import {setDefaultData} from "src/composables/form/formHandling";
import RichTextEditor from "components/inputs/RichTextEditor.vue";
const props = defineProps({
flight: {
type: Object,
required: false
},
});
const formData = ref({
name: "",
description: ""
})
const isMounted = ref(false);
onMounted(() => {
if (props.flight)
setDefaultData(formData.value, props.flight);
isMounted.value = true;
})
</script>
<template>
<FormWrapper v-model="formData" v-if="isMounted">
<q-input type="text" v-model="formData.name" label="Název"/>
<RichTextEditor v-model="formData.description" label="Popis letu, poznámky, ..." />
</FormWrapper>
</template>
@@ -0,0 +1,26 @@
<script setup>
import {formatDate, parseDate} from "src/composables/datetimeUtils";
import FormWrapper from "components/FormWrapper.vue";
import {reactive} from "vue";
const props = defineProps({
flight: {
type: Object,
required: false
}
}
)
const formData = reactive({});
const testDate = "2023-06-09T22:00:00.000+02:00";
</script>
<template>
<FormWrapper v-model="formData">
<q-banner>
Test date: {{testDate}} => {{ parseDate(testDate) }}
</q-banner>
</FormWrapper>
</template>
@@ -0,0 +1,66 @@
<script setup>
import {onMounted, ref, watch} from "vue";
const props = defineProps({
modelValue: String,
disabled: {
type: Array,
required: false,
default: () => []
},
routerEditMode: {
type: Boolean,
required: false,
default: false,
},
flightId: {
type: Number,
required: false,
}
})
const currentStep = ref("");
onMounted(() => {
currentStep.value = props.modelValue;
})
const steps = [
{name: "basic", icon: "flight_takeoff", label: "Základní informace"},
{name: "copilot", icon: "person_add", label: "Spolucestující"},
{name: "track", icon: "route", label: "Trasa"},
{name: "photos", icon: "add_a_photo", label: "Fotky"},
{name: "notes", icon: "edit_note", label: "Poznámky"},
];
const emit = defineEmits(["update:modelValue"])
watch(currentStep, (val) => emit("update:modelValue", val));
</script>
<template>
<q-tabs v-if="routerEditMode" active-color="primary" class="q-mb-lg">
<q-route-tab
v-for="step in steps"
:key="step.name"
:icon="step.icon"
:label="step.label"
replace
:to="{name: 'flightEdit', params: {id: flightId, step: step.name}}"
:disable="disabled.includes(step.name)"
exact
/>
</q-tabs>
<q-tabs
v-else
v-model="currentStep"
outside-arrows
mobile-arrows
left-icon="chevron_left"
right-icon="chevron_right"
active-color="primary"
class="q-mb-lg"
>
<q-tab v-for="step in steps" :key="step.name" v-bind="step" :disable="disabled.includes(step.name)"/>
</q-tabs>
</template>
+29 -14
View File
@@ -1,17 +1,18 @@
<script setup>
import {computed, onMounted, ref, watch} from "vue";
import {parseDate} from "src/composables/datetimeUtils";
const props = defineProps({
modelValue: {
type: Date,
type: [String, Date]
},
dateMask: {
type: String, Boolean,
type: [String, Boolean],
required: false,
default: "YYYY-MM-DD"
},
timeMask: {
type: String, Boolean,
type: [String, Boolean],
required: false,
default: "HH:mm"
}
@@ -19,35 +20,49 @@ const props = defineProps({
let dateModel = ref("");
let timeModel = ref("");
onMounted(() => {
let date = "";
let time = "";
let emitDefaultValue = false;
if (props.modelValue) {
let modelVal = props.modelValue;
if (typeof modelVal === 'string') {
modelVal = parseDate(props.modelValue);
emitDefaultValue = true;
}
date = props.dateMask.replace("YYYY", props.modelValue.getFullYear())
.replace("MM", ('0' + props.modelValue.getMonth()).slice(-2))
.replace("DD", ('0' + props.modelValue.getDate()).slice(-2));
date = props.dateMask
.replace("YYYY", modelVal.getFullYear().toString())
.replace("MM", ('0' + modelVal.getMonth()).slice(-2))
.replace("DD", ('0' + modelVal.getDate()).slice(-2));
time = props.timeMask.replace("HH", ('0' + props.modelValue.getHours()).slice(-2))
.replace("mm", ('0' + props.modelValue.getMinutes()).slice(-2))
}
time = props.timeMask
.replace("HH", ('0' + modelVal.getHours()).slice(-2))
.replace("mm", ('0' + modelVal.getMinutes()).slice(-2))
.replace("ss", ('0' + modelVal.getSeconds()).slice(-2))
if (time === '') {
time = "00:00";
// if (time === '') {
// time = "00:00";
// }
}
dateModel.value = date;
timeModel.value = time;
if (emitDefaultValue) {
emitModelUpdate();
}
});
const model = computed(() => dateModel.value + " " + timeModel.value);
const model = computed(() => dateModel.value + " " + timeModel.value);
const emit = defineEmits(['update:modelValue']);
const emitModelUpdate = () => {
const now = new Date();
const val = new Date(model.value);
val.setHours(val.getHours() + now.getTimezoneOffset());
const val = parseDate(model.value);
// val.setHours(val.getHours() + now.getTimezoneOffset());
emit("update:modelValue", val);
}
watch([dateModel, timeModel], emitModelUpdate)
+60
View File
@@ -0,0 +1,60 @@
<script setup>
import {onMounted, ref, watch} from "vue";
const props = defineProps({
modelValue: {
type: String,
required: false
},
height: {
type: String,
required: false,
default: "60vh"
},
label: {
type: String,
required: false,
default: ""
},
rules: {
type: Array,
required: false,
default: () => []
},
})
const emit = defineEmits(["update:modelValue"]);
const content = ref("");
onMounted(() => {
content.value = props.modelValue;
})
watch(content, () => emit("update:modelValue", content.value));
const definitions = {
left: {icon: "format_align_left"},
center: {icon: "format_align_center"},
right: {icon: "format_align_right"},
justify: {icon: "format_align_justify"},
bold: {icon: 'format_bold'},
italic: {icon: 'format_italic'},
strike: {icon: 'strikethrough_s'},
underline: {icon: 'format_underline'},
unordered: {icon: 'format_list_bulleted'},
ordered: {icon: 'format_list_numbered'},
undo: {icon: 'undo'},
redo: {icon: 'redo'},
}
const toolbar = [
["bold", "italic", "strike"],
["left", "center", "justify", "right"],
['unordered', 'ordered'],
["undo", "redo"]
]
</script>
<template>
<q-editor v-model="content" :definitions="definitions" :toolbar="toolbar" :height="height" :label="label" :rules="rules"/>
</template>
+29 -3
View File
@@ -4,9 +4,35 @@ export const minutesToHumanReadable = (totalMinutes) => {
return `${hours}h ${minutes}min`
}
export const formatDate = (date) => {
export const formatDate = (date, format = "DD. MM. YYYY") => {
if (typeof date === 'string') {
date = new Date(date);
date = parseDate(date);
}
return date.getDate()+". "+date.getMonth()+". "+date.getFullYear();
return format
.replace("DD", date.getDate().toString())
.replace("MM", (date.getMonth() + 1).toString())
.replace("YYYY", date.getFullYear().toString());
}
export const parseDate = (datetime) => {
// const [date, time] = datetime.split("T");
// const [year, month, day] = date.split("-");
// const [hour, minute] = time.split(":");
//
// const dateObject = new Date(year, month, day, hour, minute, 0);
// ^ tohle funguje ok
const timestamp = Date.parse(datetime);
const now = new Date();
const dateObject = new Date(timestamp);
// dateObject.setHours(dateObject.getHours() + now.getTimezoneOffset());
// console.log("date", date);
// console.log("time", time);
// console.log("month", month, dateObject.getMonth(), dateObject.getUTCMonth());
// console.log("day", day, dateObject.getDate(), dateObject.getUTCDate());
return dateObject;
}
+8
View File
@@ -0,0 +1,8 @@
export const flightName = (flight) => {
const date = flight.takeoffDatetime;//.getDay() + ". " + flight.takeoffDatetime.getMonth() + ". " + flight.takeoffDatetime.getFullYear();
if (flight.name !== '') {
return `${flight.name} (${date}})`
} else {
return `${flight.takeoffAirport.icaoCode} - ${flight.takeoffAirport.icaoCode} (${date})`;
}
}
+3 -6
View File
@@ -1,15 +1,12 @@
export const setDefaultData = (formData, defaultData) => {
console.log("setting default data ", formData, defaultData);
const ignoredFields = ['__typename'];
for (const key in defaultData) {
for (const key in formData) {
if (ignoredFields.includes(key)) continue;
if (typeof formData[key] === 'undefined') {
console.error(`Key ${key} not in formData, skipping!`)
if (typeof defaultData[key] === 'undefined') {
console.error(`Key ${key} not in defaultData, skipping!`)
continue;
}
formData[key] = defaultData[key];
}
}
+11 -5
View File
@@ -8,20 +8,18 @@ fragment flightFullInfo on Flight {
takeoffDatetime
landingDatetime
durationMinCalculated
solo
takeoffAirport {
id
name
icaoCode
}
landingAirport {
id
name
icaoCode
}
aircraft {
id
name
@@ -30,6 +28,14 @@ fragment flightFullInfo on Flight {
}
`;
export const FRAGMENT_FLIGHT_EDIT_IDS = gql`
fragment flightEditIds on Flight {
landingAirportId
takeoffAirportId
aircraftId
copilotId
}
`;
// export const FRAGMENT_LOCATION = gql`
// fragment airportInfo on Airport {
+10
View File
@@ -10,3 +10,13 @@ mutation createFlight($input: CreateFlightInput!) {
${FRAGMENT_FLIGHT_FULL_INFO}
`
export const EDIT_FLIGHT = gql`
mutation editFlight($id: Int!, $input: EditFlightInput!) {
editFlight(id: $id, input: $input) {
...flightFullInfo
}
}
${FRAGMENT_FLIGHT_FULL_INFO}
`;
+3 -1
View File
@@ -1,5 +1,5 @@
import gql from "graphql-tag";
import {FRAGMENT_FLIGHT_FULL_INFO} from "src/graphql/fragments/flight";
import {FRAGMENT_FLIGHT_EDIT_IDS, FRAGMENT_FLIGHT_FULL_INFO} from "src/graphql/fragments/flight";
export const FLIGHTS_LIST = gql`
query FlightsList {
@@ -14,9 +14,11 @@ export const FLIGHT_DETAIL = gql`
query FlightDetail($id: Int!) {
flight(id: $id) {
...flightFullInfo
...flightEditIds
}
}
${FRAGMENT_FLIGHT_FULL_INFO}
${FRAGMENT_FLIGHT_EDIT_IDS}
`;
+98 -1
View File
@@ -1,7 +1,104 @@
<script setup>
import FlightFormSteps from "components/flights/form/FlightFormSteps.vue";
import {computed, onMounted, reactive, ref, watch} from "vue";
import {useRoute} from "vue-router";
import {useFlightsStore} from "stores/Flights";
import FlightFormBasic from "components/flights/form/FlightFormBasic.vue";
import {useAircraftsStore} from "stores/Aircrafts";
import {usePointsOfInterestStore} from "stores/PointsOfInterest";
import {useAirportsStore} from "stores/Airports";
import {useMeta, useQuasar} from "quasar";
import {storeToRefs} from "pinia";
import {flightName} from "src/composables/flight";
import FlightFormCopilot from "components/flights/form/FlightFormCopilot.vue";
import {useSecondPilotsStore} from "stores/SecondPilots";
import FlightFormNotes from "components/flights/form/FlightFormNotes.vue";
import FlightFormPhotos from "components/flights/form/FlightFormPhotos.vue";
useMeta({title: "Editace letu"});
const $q = useQuasar();
const route = useRoute();
const flightId = parseInt(route.params.id);
const aircrafts = storeToRefs(useAircraftsStore()).items;
const locations = storeToRefs(usePointsOfInterestStore()).items;
const airports = storeToRefs(useAirportsStore()).items;
const copilots = storeToRefs(useSecondPilotsStore()).items;
let flight = ref({});
const disabledSteps = computed(() => flight.value.solo ? ["copilot"] : [flight.value.solo]);
const loading = ref(false);
const fetchFlight = (flightId) => {
loading.value = true;
useFlightsStore().fetchDetail(flightId)
.then(f => flight.value = f)
.finally(() => loading.value = false);
}
const formStep = ref("");
watch(() => route.params.step, (val) => formStep.value = val);
onMounted(() => {
formStep.value = route.params.step || "basic";
useAircraftsStore().fetch();
usePointsOfInterestStore().fetch();
useFlightsStore().fetch();
useAirportsStore().fetch();
useSecondPilotsStore().fetch();
fetchFlight(flightId);
});
const handleFlightEdit = (data) => {
useFlightsStore().update(flightId, data).then(() => {
$q.notify({message: "Uspesne upraveno", position: "top", color: "positive"});
fetchFlight(flightId);
})
}
</script>
<template>
flight edit
<div v-if="loading">loading</div>
<template v-else>
<q-breadcrumbs :key="loading">
<q-breadcrumbs-el :to="{name: 'myFlights'}">Moje lety</q-breadcrumbs-el>
<q-breadcrumbs-el :to="{name: 'flightDetail', params: {id: flightId}}">{{ flightName(flight) }}</q-breadcrumbs-el>
<q-breadcrumbs-el>Editace</q-breadcrumbs-el>
</q-breadcrumbs>
<FlightFormSteps :router-edit-mode="true" :flightId="flightId" :disabled="disabledSteps"/>
<q-tab-panels v-model="formStep">
<q-tab-panel name="basic">
<FlightFormBasic
@save="handleFlightEdit"
:flight="flight"
:locations="locations"
:airports="airports"
:aircrafts="aircrafts"
/>
</q-tab-panel>
<q-tab-panel name="copilot">
<FlightFormCopilot @save="handleFlightEdit" :flight="flight" :copilots="copilots"/>
</q-tab-panel>
<q-tab-panel name="photos">
<FlightFormPhotos
@save="handleFlightEdit"
:flight="flight" />
</q-tab-panel>
<q-tab-panel name="notes">
<FlightFormNotes @save="handleFlightEdit" :flight="flight"/>
</q-tab-panel>
</q-tab-panels>
</template>
</template>
+8 -16
View File
@@ -6,8 +6,10 @@ import {useRouter} from "vue-router";
import {usePointsOfInterestStore} from "stores/PointsOfInterest";
import {storeToRefs} from "pinia";
import {useMeta} from "quasar";
import FlightForm from "components/flights/FlightForm.vue";
import FlightForm from "components/flights/__FlightForm.vue";
import {useAirportsStore} from "stores/Airports";
import FlightFormSteps from "components/flights/form/FlightFormSteps.vue";
import FlightFormBasic from "components/flights/form/FlightFormBasic.vue";
const aircraftsStore = useAircraftsStore();
const poiStore = usePointsOfInterestStore();
@@ -27,26 +29,15 @@ const aircrafts = storeToRefs(aircraftsStore).items;
const locations = storeToRefs(poiStore).items;
const airports = storeToRefs(airportStore).items;
const turnPointsCount = ref(1);
// watch(() => formData.takeOffLocation, (newVal) => {
// if (!formData.landingLocation) {
// formData.landingLocation = locations.value.find(l => l.id === newVal);
// }
// })
const router = useRouter();
const handleSave = (formData) => {
flightsStore.create(formData).then(() => {
router.push({name: "myFlights"});
flightsStore.create(formData).then((flight) => {
router.push({name: "flightEdit", params: {id: flight.id, step: "copilot"}});
});
}
const formStep = ref("basic")
const removeTurnPoint = (idx) => {
formData.turnPoints.splice(idx, 1);
turnPointsCount.value--;
}
</script>
<template>
@@ -58,7 +49,8 @@ const removeTurnPoint = (idx) => {
<!-- {{ formData }}-->
<FlightForm @save="handleSave" :aircrafts="aircrafts" :airports="airports" :locations="locations"/>
<FlightFormSteps :disabled="['copilot', 'track', 'photos', 'notes']"/>
<FlightFormBasic @save="handleSave" :aircrafts="aircrafts" :airports="airports" :locations="locations" />
</template>
+1 -1
View File
@@ -20,7 +20,7 @@ const routes = [
{path: 'my-flights', name: "myFlights", component: () => import('pages/profile/lists/FlightsPage.vue')},
{path: 'my-flights/add', name: "addFlight", component: () => import('pages/profile/forms/FlightLogPage.vue')},
{path: 'my-flights/:id', name: "flightDetail", component: () => import('pages/profile/details/FlightDetailPage.vue')},
{path: 'my-flights/:id/edit', name: "flightEdit", component: () => import('pages/profile/forms/FlightEditPage.vue')},
{path: 'my-flights/:id/edit/:step?', name: "flightEdit", component: () => import('pages/profile/forms/FlightEditPage.vue')},
{path: 'poi', name: "poi", component: () => import('pages/profile/lists/PointsOfInterestPage.vue')},
{path: 'poi/:id', name: "poiDetail", component: () => import('pages/profile/details/PointOfInterestDetailPage.vue')},
{path: 'pilots', name: "pilots", component: () => import('pages/profile/lists/SecondPilotPage.vue')},
+10 -1
View File
@@ -1,7 +1,7 @@
import {defineStore} from 'pinia'
import {apolloWrapper} from "src/graphql/apollo"
import {FLIGHT_DETAIL, FLIGHTS_LIST} from "src/graphql/queries/flights";
import {CREATE_FLIGHT} from "src/graphql/mutations/flight";
import {EDIT_FLIGHT, CREATE_FLIGHT} from "src/graphql/mutations/flight";
export const useFlightsStore = defineStore('Flights', {
state: () => ({
@@ -23,7 +23,16 @@ export const useFlightsStore = defineStore('Flights', {
return data.createFlight;
})
},
update(id, formData) {
return apolloWrapper.mutate(EDIT_FLIGHT, {id: id, input: formData}).then(({data}) => {
console.log("Pridat update ve storu")
return data.editFlight;
});
},
fetchDetail(id) {
if (typeof id !== "number") {
id = parseInt(id);
}
return apolloWrapper.query(FLIGHT_DETAIL, {id}).then(result => result.data.flight);
},
fetch() {
+5
View File
@@ -2086,6 +2086,11 @@ minimist@^1.2.6:
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
moment@^2.29.4:
version "2.29.4"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108"
integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==
ms@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"