Sprava eventu
This commit is contained in:
@@ -0,0 +1,28 @@
|
|||||||
|
<script setup>
|
||||||
|
const props = defineProps({
|
||||||
|
avatars: {
|
||||||
|
type: Array,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div style="height: 80px">
|
||||||
|
<q-avatar
|
||||||
|
v-for="(avatar, idx) in avatars"
|
||||||
|
:key="idx"
|
||||||
|
class="overlapping"
|
||||||
|
:style="`left: ${(idx+1) * 20}px`"
|
||||||
|
>
|
||||||
|
<img :src="avatar"/>
|
||||||
|
<!-- <q-icon name="flight" v-else />-->
|
||||||
|
</q-avatar>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<style lang="sass" scoped>
|
||||||
|
.overlapping
|
||||||
|
position: absolute
|
||||||
|
</style>
|
||||||
@@ -3,7 +3,6 @@ import BasicListSkeleton from "components/basicSkeletons/BasicListSkeleton.vue";
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<q-card class="flight-detail-card">
|
<q-skeleton type="rect" class="q-my-lg" style="width: 200px; height: 40px" />
|
||||||
<BasicListSkeleton :items-count-min="1" :items-count-max="5"/>
|
<BasicListSkeleton :items-count-min="1" :items-count-max="5"/>
|
||||||
</q-card>
|
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup></script>
|
<script setup></script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<em>Copilot skeleton</em>
|
<q-skeleton type="QInput" />
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<script setup>
|
||||||
|
import BasicListSkeleton from "components/basicSkeletons/BasicListSkeleton.vue";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<q-card class="flight-detail-card">
|
||||||
|
<BasicListSkeleton :items-count-min="1" :items-count-max="5"/>
|
||||||
|
</q-card>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<script setup></script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<em>Copilot skeleton</em>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
<script setup>
|
||||||
|
|
||||||
|
import {onMounted, reactive} from "vue";
|
||||||
|
import {setDefaultData} from "src/composables/form/formHandling";
|
||||||
|
import FormWrapper from "components/FormWrapper.vue";
|
||||||
|
import {commonProps} from "src/composables/inputs";
|
||||||
|
import {isRequestPending} from "src/composables/form/props";
|
||||||
|
import {isRequired} from "src/composables/form/rules";
|
||||||
|
import RichTextEditor from "components/inputs/RichTextEditor.vue";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
event: {
|
||||||
|
type: Object
|
||||||
|
},
|
||||||
|
isRequestPending
|
||||||
|
})
|
||||||
|
|
||||||
|
const formData = reactive({
|
||||||
|
name: null,
|
||||||
|
isPublic: false,
|
||||||
|
description: "",
|
||||||
|
});
|
||||||
|
|
||||||
|
const rules = {
|
||||||
|
name: [isRequired]
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (props.event) {
|
||||||
|
setDefaultData(formData, props.event);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<FormWrapper v-model="formData" :is-request-pending="props.isRequestPending">
|
||||||
|
<q-input
|
||||||
|
v-bind="commonProps"
|
||||||
|
label="Jméno"
|
||||||
|
:rules="rules.name"
|
||||||
|
v-model="formData.name"
|
||||||
|
/>
|
||||||
|
<RichTextEditor v-model="formData.description" v-bind="commonProps" label="Popis letu, poznámky, ..."/>
|
||||||
|
<q-checkbox v-model="formData.isPublic" label="Veřejný?"/>
|
||||||
|
|
||||||
|
</FormWrapper>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
<script setup>
|
||||||
|
|
||||||
|
import AvatarsGroup from "components/AvatarsGroup.vue";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
items: {
|
||||||
|
type: Array,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const getCoverPhotos = (item) => item.flights.filter(f => !!f.coverPhoto).map(f => f.coverPhoto.thumbnailUrl);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<q-list bordered separator>
|
||||||
|
<q-item clickable v-ripple v-for="event of items" :key="event" :to="{name: 'eventDetail', params: {id: event.id }}">
|
||||||
|
<q-item-section>
|
||||||
|
<q-item-label>
|
||||||
|
|
||||||
|
<q-avatar icon="event" color="primary" text-color="white" v-if="event.flights.length === 0"/>
|
||||||
|
<AvatarsGroup :avatars="getCoverPhotos(event)" v-else/>
|
||||||
|
|
||||||
|
{{ event.name }}
|
||||||
|
</q-item-label>
|
||||||
|
<q-item-label lines="4" caption>
|
||||||
|
<article v-html="event.description"/>
|
||||||
|
</q-item-label>
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
</q-list>
|
||||||
|
</template>
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import BasicListSkeleton from "components/basicSkeletons/BasicListSkeleton.vue";
|
import BasicListSkeleton from "components/basicSkeletons/BasicListSkeleton.vue";
|
||||||
|
import {randomInt} from "src/composables/random";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
step: {
|
step: {
|
||||||
@@ -10,27 +11,61 @@ const props = defineProps({
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<q-card class="" v-if="step !== 'photos'">
|
<template v-if="step === 'basic'">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<q-card class="q-my-sm">
|
||||||
<q-card-section>
|
<q-card-section>
|
||||||
<q-skeleton type="QInput" class="q-my-sm" v-for="i in 3" :key="i"/>
|
<q-skeleton type="QInput" class="q-my-sm" v-for="i in 2" :key="i"/>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
</q-card>
|
</q-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<template v-if="step === 'photos'">
|
<div class="row">
|
||||||
|
<div class="col col-12 col-md-6" v-for="i in 2" :key="i">
|
||||||
|
<q-card class="q-mr-md-sm q-my-sm">
|
||||||
|
<q-card-section>
|
||||||
|
<q-skeleton type="QInput" class="q-my-sm" v-for="i in 2" :key="i"/>
|
||||||
|
</q-card-section>
|
||||||
|
</q-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<q-card v-else-if="step === 'copilot'">
|
||||||
|
<q-card class="q-mr-md-sm q-my-sm">
|
||||||
|
<q-card-section>
|
||||||
|
<q-skeleton type="QInput" class="q-my-sm"/>
|
||||||
|
</q-card-section>
|
||||||
|
</q-card>
|
||||||
|
</q-card>
|
||||||
|
|
||||||
|
<template v-else-if="step === 'track'">
|
||||||
<q-card>
|
<q-card>
|
||||||
<q-card-section>
|
<q-card-section>
|
||||||
|
<q-skeleton type="QInput" class="q-my-sm" v-for="i in 2" :key="i"/>
|
||||||
<q-skeleton type="QInput" class="q-my-sm"/>
|
|
||||||
|
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
|
|
||||||
</q-card>
|
</q-card>
|
||||||
|
|
||||||
|
<BasicListSkeleton :items-count-min="2" :items-count-max="6"/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-else-if="step === 'photos'">
|
||||||
|
<q-card class="q-my-lg">
|
||||||
|
<q-card-section>
|
||||||
|
<q-skeleton type="QInput" class="q-my-sm"/>
|
||||||
|
</q-card-section>
|
||||||
|
</q-card>
|
||||||
|
|
||||||
<q-card v-for="i in randomInt(3, 10)" :key="i">
|
<q-card v-for="i in randomInt(3, 10)" :key="i">
|
||||||
<q-skeleton type="rect"/>
|
<q-skeleton type="rect"/>
|
||||||
</q-card>
|
</q-card>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<div v-else-if="step === 'notes'">
|
||||||
|
<q-skeleton type="QInput" class="q-my-sm" v-for="i in 2" :key="i"/>
|
||||||
|
<q-skeleton type="rect" width="100%" height="500px"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,34 +1,44 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import {onMounted, ref} from "vue";
|
import {onMounted, reactive, ref, watch} from "vue";
|
||||||
import FormWrapper from "components/FormWrapper.vue";
|
import FormWrapper from "components/FormWrapper.vue";
|
||||||
import {setDefaultData} from "src/composables/form/formHandling";
|
import {setDefaultData} from "src/composables/form/formHandling";
|
||||||
import RichTextEditor from "components/inputs/RichTextEditor.vue";
|
import RichTextEditor from "components/inputs/RichTextEditor.vue";
|
||||||
import {commonProps} from "src/composables/inputs";
|
import {commonProps} from "src/composables/inputs";
|
||||||
|
import ComboboxInput from "components/inputs/ComboboxInput.vue";
|
||||||
|
import {isRequestPending} from "src/composables/objects/flight";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
flight: {
|
flight: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: false
|
required: false
|
||||||
},
|
},
|
||||||
|
events: {
|
||||||
|
type: Array,
|
||||||
|
required: false,
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const formData = ref({
|
const formData = reactive({
|
||||||
name: "",
|
name: "",
|
||||||
|
event: null,
|
||||||
description: ""
|
description: ""
|
||||||
})
|
})
|
||||||
|
|
||||||
const isMounted = ref(false);
|
watch(() => props.flight, (newVal) => {
|
||||||
onMounted(() => {
|
if (newVal) {
|
||||||
if (props.flight)
|
setDefaultData(formData, newVal);
|
||||||
setDefaultData(formData.value, props.flight);
|
|
||||||
|
|
||||||
isMounted.value = true;
|
if (newVal.event) {
|
||||||
})
|
formData.event = {id: newVal.event.id, name: newVal.event.name};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {immediate: true});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<FormWrapper v-model="formData" v-if="isMounted">
|
<FormWrapper v-model="formData" :is-request-pending="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"/>
|
||||||
<RichTextEditor v-model="formData.description" v-bind="commonProps" label="Popis letu, poznámky, ..."/>
|
<RichTextEditor v-model="formData.description" v-bind="commonProps" label="Popis letu, poznámky, ..."/>
|
||||||
</FormWrapper>
|
</FormWrapper>
|
||||||
|
|||||||
@@ -110,5 +110,9 @@ const filterFn = (val, update, abort) => {
|
|||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<template #append>
|
||||||
|
<slot name="append" />
|
||||||
|
</template>
|
||||||
</q-select>
|
</q-select>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import {FORMAT_DATE, formatDatetime} from "src/composables/datetimeUtils";
|
||||||
|
import {useEventsStore} from "stores/Events";
|
||||||
|
import {ref} from "vue";
|
||||||
|
import {storeToRefs} from "pinia";
|
||||||
|
import {confirmObject} from "src/composables/dialog";
|
||||||
|
import {useAppStore} from "stores/App";
|
||||||
|
export const loading = ref(true);
|
||||||
|
export const event = ref(null);
|
||||||
|
export const fetchEvent = (eventId, username) => {
|
||||||
|
loading.value = true;
|
||||||
|
return useEventsStore().fetchDetail(parseInt(eventId), username)
|
||||||
|
.then(respEvent => {
|
||||||
|
event.value = respEvent;
|
||||||
|
return respEvent;
|
||||||
|
})
|
||||||
|
.finally(() => loading.value = false);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const events = storeToRefs(useEventsStore()).items;
|
||||||
|
|
||||||
|
export const fetchEvents = (username = null) => {
|
||||||
|
loading.value = true;
|
||||||
|
useEventsStore().fetch(username).finally(() => {
|
||||||
|
loading.value = false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export const handleDeleteEvent = ($q, eventId, onOkCallback = () => {
|
||||||
|
}) => {
|
||||||
|
$q.dialog(confirmObject(`Opravdu chceš smazat tento let?`))
|
||||||
|
.onOk(() => {
|
||||||
|
useEventsStore().delete(eventId).then(onOkCallback);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const isRequestPending = storeToRefs(useEventsStore()).isRequestPending;
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import gql from "graphql-tag";
|
||||||
|
|
||||||
|
export const FRAGMENT_EVENT_LIST_INFO = gql`
|
||||||
|
fragment eventListInfo on Event {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
description
|
||||||
|
isPublic
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const FRAGMENT_EVENT_FULL_INFO = gql`
|
||||||
|
fragment eventFullInfo on Event {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
description
|
||||||
|
isPublic
|
||||||
|
}
|
||||||
|
`;
|
||||||
@@ -41,6 +41,12 @@ fragment flightFullInfo on Flight {
|
|||||||
id
|
id
|
||||||
name
|
name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
event {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
}
|
||||||
|
|
||||||
gpxTrackUrl
|
gpxTrackUrl
|
||||||
gpxTrack {
|
gpxTrack {
|
||||||
coordinates {
|
coordinates {
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import gql from "graphql-tag";
|
||||||
|
import {FRAGMENT_EVENT_FULL_INFO} from "src/graphql/fragments/event";
|
||||||
|
|
||||||
|
export const CREATE_EVENT = gql`
|
||||||
|
mutation createEvent($input: CreateEventInput!) {
|
||||||
|
createEvent(input: $input) {
|
||||||
|
...eventFullInfo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
${FRAGMENT_EVENT_FULL_INFO}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const EDIT_EVENT = gql`
|
||||||
|
mutation editEvent($id: Int!, $input: EditEventInput!) {
|
||||||
|
editEvent(id: $id, input: $input) {
|
||||||
|
...eventFullInfo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
${FRAGMENT_EVENT_FULL_INFO}
|
||||||
|
`;
|
||||||
|
export const DELETE_EVENT = gql`
|
||||||
|
mutation deleteEvent($id: Int!) {
|
||||||
|
deleteEvent(id: $id) {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import gql from "graphql-tag";
|
||||||
|
import {FRAGMENT_FLIGHT_LIST_INFO} from "src/graphql/fragments/flight_list";
|
||||||
|
import {FRAGMENT_EVENT_FULL_INFO, FRAGMENT_EVENT_LIST_INFO} from "src/graphql/fragments/event";
|
||||||
|
|
||||||
|
export const EVENTS_LIST = gql`
|
||||||
|
query eventsList {
|
||||||
|
events {
|
||||||
|
...eventListInfo
|
||||||
|
|
||||||
|
flights {
|
||||||
|
coverPhoto {
|
||||||
|
thumbnailUrl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
${FRAGMENT_EVENT_LIST_INFO}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const EVENT_DETAIL = gql`
|
||||||
|
query event($id: Int!) {
|
||||||
|
event(id: $id) {
|
||||||
|
...eventFullInfo
|
||||||
|
|
||||||
|
flights {
|
||||||
|
...flightListInfo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
${FRAGMENT_EVENT_FULL_INFO}
|
||||||
|
${FRAGMENT_FLIGHT_LIST_INFO}
|
||||||
|
`;
|
||||||
@@ -103,23 +103,32 @@ const linksList = [
|
|||||||
to: {name: "myFlights"}
|
to: {name: "myFlights"}
|
||||||
},
|
},
|
||||||
{separator: true},
|
{separator: true},
|
||||||
|
{
|
||||||
|
title: 'Události',
|
||||||
|
icon: 'event',
|
||||||
|
to: {name: "events"}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: 'Letadla',
|
title: 'Letadla',
|
||||||
icon: "connecting_airports",
|
icon: "connecting_airports",
|
||||||
to: {name: "aircrafts"}
|
to: {name: "aircrafts"}
|
||||||
},
|
},
|
||||||
{separator: true},
|
|
||||||
{
|
{
|
||||||
title: 'Zajímavá místa',
|
title: 'Zajímavá místa',
|
||||||
icon: "place",
|
icon: "place",
|
||||||
to: {name: "poi"}
|
to: {name: "poi"}
|
||||||
},
|
},
|
||||||
{separator: true},
|
|
||||||
{
|
{
|
||||||
title: 'Spolucestující',
|
title: 'Spolucestující',
|
||||||
icon: "people",
|
icon: "people",
|
||||||
to: {name: "copilots"}
|
to: {name: "copilots"}
|
||||||
},
|
},
|
||||||
|
{separator: true},
|
||||||
|
{
|
||||||
|
title: 'Organizace',
|
||||||
|
icon: "groups",
|
||||||
|
to: {name: "organizations"}
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
const leftDrawerOpen = ref(false)
|
const leftDrawerOpen = ref(false)
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
<script setup>
|
||||||
|
import {onMounted} from "vue";
|
||||||
|
import {loading, event, fetchEvent, isRequestPending} from "src/composables/objects/event";
|
||||||
|
import {useAppStore} from "stores/App";
|
||||||
|
import {useRoute, useRouter} from "vue-router";
|
||||||
|
import {useEventsStore} from "stores/Events";
|
||||||
|
import {successObject} from "src/composables/dialog";
|
||||||
|
import {useQuasar} from "quasar";
|
||||||
|
import EventEditSkeleton from "components/event/EventEditSkeleton.vue";
|
||||||
|
import EventForm from "components/event/EventForm.vue";
|
||||||
|
|
||||||
|
const eventId = parseInt(useRoute().params.id);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
fetchEvent(eventId).then(() => {
|
||||||
|
useAppStore().setPageTitle(`${event.value.name} - editace`);
|
||||||
|
useAppStore().setBreadcrumbs([
|
||||||
|
{to: {name: "events"}, label: "Události"},
|
||||||
|
{to: {name: "eventDetail", params: {id: eventId}}, label: event.value.name},
|
||||||
|
{label: "Editace"}
|
||||||
|
])
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
const $q = useQuasar();
|
||||||
|
const $router = useRouter();
|
||||||
|
|
||||||
|
const handleSave = (formData) => {
|
||||||
|
useEventsStore().update(eventId, formData).then(() => {
|
||||||
|
$q.notify(successObject("Událost úspěšně upravena"));
|
||||||
|
$router.push({name: "eventDetail", params: {id: eventId}});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<EventEditSkeleton v-if="loading"/>
|
||||||
|
|
||||||
|
<EventForm
|
||||||
|
v-else
|
||||||
|
:event="event"
|
||||||
|
:is-request-pending="isRequestPending"
|
||||||
|
@save="handleSave"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
<script setup>
|
||||||
|
import {useRoute} from "vue-router";
|
||||||
|
import {onMounted} from "vue";
|
||||||
|
import {event, fetchEvent, loading} from "src/composables/objects/event";
|
||||||
|
import EventDetailSkeleton from "components/event/EventDetailSkeleton.vue";
|
||||||
|
import {useAppStore} from "stores/App";
|
||||||
|
import FAB from "components/FAB.vue";
|
||||||
|
import FlightsList from "components/flights/FlightsList.vue";
|
||||||
|
|
||||||
|
const eventId = parseInt(useRoute().params.id);
|
||||||
|
onMounted(() => {
|
||||||
|
fetchEvent(eventId).then(() => {
|
||||||
|
useAppStore().setPageTitle(event.value.name);
|
||||||
|
useAppStore().setBreadcrumbs([
|
||||||
|
{to: {name: "events"}, label: "Události"},
|
||||||
|
{label: event.value.name}
|
||||||
|
])
|
||||||
|
});
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<EventDetailSkeleton v-if="loading || !event"/>
|
||||||
|
|
||||||
|
<template v-else>
|
||||||
|
<article v-html="event.description" />
|
||||||
|
|
||||||
|
<h3>Lety</h3>
|
||||||
|
|
||||||
|
<q-banner v-if="event.flights.length === 0" class="bg-light-blue text-white">
|
||||||
|
Zatím tu nemáš uložené žádné lety.
|
||||||
|
</q-banner>
|
||||||
|
|
||||||
|
<FlightsList :items="event.flights" v-else/>
|
||||||
|
|
||||||
|
<FAB mode="edit" :router-link="{name: 'eventEdit', params: {id: eventId}}"/>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<script setup>
|
||||||
|
import {onMounted} from "vue";
|
||||||
|
import {useAppStore} from "stores/App";
|
||||||
|
import FAB from "components/FAB.vue";
|
||||||
|
import BasicListSkeleton from "components/basicSkeletons/BasicListSkeleton.vue";
|
||||||
|
import BasicInfoBanner from "components/banners/BasicInfoBanner.vue";
|
||||||
|
import {events, fetchEvents, loading} from "src/composables/objects/event";
|
||||||
|
import EventsList from "components/event/EventsList.vue";
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
fetchEvents();
|
||||||
|
});
|
||||||
|
|
||||||
|
useAppStore().setPageTitle("Letecké události")
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<BasicListSkeleton :items-count-min="3" :items-count-max="8" v-if="loading"/>
|
||||||
|
<BasicInfoBanner
|
||||||
|
v-else-if="!loading && events.length === 0"
|
||||||
|
:route-add="{name: 'addEvent'}"
|
||||||
|
label-add="Přidat"
|
||||||
|
>
|
||||||
|
Nemáš tu uloženou žádnou událost. Události slouží ke sloučení letů z jedné akce/výletu do přehledné skupiny.
|
||||||
|
</BasicInfoBanner>
|
||||||
|
|
||||||
|
<EventsList
|
||||||
|
v-else
|
||||||
|
:items="events"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<FAB :router-link="{name: 'addEvent'}" mode="add"/>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<script setup>
|
||||||
|
import {useRouter} from "vue-router";
|
||||||
|
import {useQuasar} from "quasar";
|
||||||
|
import {successObject} from "src/composables/dialog";
|
||||||
|
import {useEventsStore} from "stores/Events";
|
||||||
|
import {useAppStore} from "stores/App";
|
||||||
|
import {isRequestPending} from "src/composables/objects/event";
|
||||||
|
import EventForm from "components/event/EventForm.vue";
|
||||||
|
|
||||||
|
const $q = useQuasar();
|
||||||
|
const router = useRouter();
|
||||||
|
const handleSave = (formData) => {
|
||||||
|
useEventsStore().create(formData).then(() => {
|
||||||
|
$q.notify(successObject("Událost úspěšně vytvořena"));
|
||||||
|
router.push({name: "events"});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
useAppStore().setPageTitle("Nová událost");
|
||||||
|
useAppStore().setBreadcrumbs([
|
||||||
|
{to: {name: "events"}, label: "Události"},
|
||||||
|
{label: "Nová"}
|
||||||
|
]);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<EventForm @save="handleSave" :is-request-pending="isRequestPending"/>
|
||||||
|
</template>
|
||||||
@@ -25,6 +25,7 @@ import BatchPhotoFormDialog from "components/photos/BatchPhotoFormDialog.vue";
|
|||||||
import {useAppStore} from "stores/App";
|
import {useAppStore} from "stores/App";
|
||||||
import {editBatchPhotos, handleBatchPhotoEdit, openBatchEdit, openBatchPhotoForm} from "src/composables/photos/batchEdit";
|
import {editBatchPhotos, handleBatchPhotoEdit, openBatchEdit, openBatchPhotoForm} from "src/composables/photos/batchEdit";
|
||||||
import {editPhoto, handlePhotoUpdate, openEdit, openPhotoEdit} from "src/composables/photos/simpleEdit";
|
import {editPhoto, handlePhotoUpdate, openEdit, openPhotoEdit} from "src/composables/photos/simpleEdit";
|
||||||
|
import {fetchEvents, events} from "src/composables/objects/event";
|
||||||
|
|
||||||
const $q = useQuasar();
|
const $q = useQuasar();
|
||||||
const $route = useRoute();
|
const $route = useRoute();
|
||||||
@@ -35,6 +36,7 @@ const locations = storeToRefs(usePointsOfInterestStore()).items;
|
|||||||
const airports = storeToRefs(useAirportsStore()).items;
|
const airports = storeToRefs(useAirportsStore()).items;
|
||||||
const copilots = storeToRefs(useCopilotsStore()).items;
|
const copilots = storeToRefs(useCopilotsStore()).items;
|
||||||
|
|
||||||
|
|
||||||
const formStep = ref("");
|
const formStep = ref("");
|
||||||
watch(() => $route.params.step, (val) => formStep.value = val);
|
watch(() => $route.params.step, (val) => formStep.value = val);
|
||||||
|
|
||||||
@@ -46,6 +48,8 @@ onMounted(() => {
|
|||||||
useAirportsStore().fetch();
|
useAirportsStore().fetch();
|
||||||
useCopilotsStore().fetch();
|
useCopilotsStore().fetch();
|
||||||
|
|
||||||
|
fetchEvents();
|
||||||
|
|
||||||
fetchFlight(flightId).then(() => {
|
fetchFlight(flightId).then(() => {
|
||||||
const flightNameFormatted = flightName(flight.value);
|
const flightNameFormatted = flightName(flight.value);
|
||||||
|
|
||||||
@@ -98,8 +102,6 @@ const deletePhoto = (id) => {
|
|||||||
flight.value.photos.splice(_findPhotoIndex(data.id), 1);
|
flight.value.photos.splice(_findPhotoIndex(data.id), 1);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -164,7 +166,7 @@ const deletePhoto = (id) => {
|
|||||||
</q-tab-panel>
|
</q-tab-panel>
|
||||||
|
|
||||||
<q-tab-panel name="notes">
|
<q-tab-panel name="notes">
|
||||||
<FlightFormNotes @save="handleFlightEdit" :flight="flight"/>
|
<FlightFormNotes @save="handleFlightEdit" :events="events" :flight="flight"/>
|
||||||
</q-tab-panel>
|
</q-tab-panel>
|
||||||
</q-tab-panels>
|
</q-tab-panels>
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ import {storeToRefs} from "pinia";
|
|||||||
const $q = useQuasar();
|
const $q = useQuasar();
|
||||||
const $router = useRouter();
|
const $router = useRouter();
|
||||||
const flightId = parseInt(useRoute().params.id);
|
const flightId = parseInt(useRoute().params.id);
|
||||||
|
|
||||||
const loggedUser = storeToRefs(useUserStore()).user;
|
const loggedUser = storeToRefs(useUserStore()).user;
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<script setup>
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
organizace
|
||||||
|
</template>
|
||||||
@@ -40,6 +40,12 @@ const routes = [
|
|||||||
{path: 'aircrafts/new', name: "addAircraft", component: () => import('pages/profile/aircraft/NewAircraftsPage.vue')},
|
{path: 'aircrafts/new', name: "addAircraft", component: () => import('pages/profile/aircraft/NewAircraftsPage.vue')},
|
||||||
{path: 'aircrafts/:id', name: "aircraftDetail", component: () => import('pages/profile/aircraft/AircraftDetailPage.vue')},
|
{path: 'aircrafts/:id', name: "aircraftDetail", component: () => import('pages/profile/aircraft/AircraftDetailPage.vue')},
|
||||||
{path: 'aircrafts/:id/edit', name: "aircraftEdit", component: () => import('pages/profile/aircraft/EditAircraftPage.vue')},
|
{path: 'aircrafts/:id/edit', name: "aircraftEdit", component: () => import('pages/profile/aircraft/EditAircraftPage.vue')},
|
||||||
|
|
||||||
|
{path: 'events', name: "events", component: () => import('pages/profile/event/EventsPage.vue')},
|
||||||
|
{path: 'events/add', name: "addEvent", component: () => import('pages/profile/event/NewEventPage.vue')},
|
||||||
|
{path: 'events/:id', name: "eventDetail", component: () => import('pages/profile/event/EventDetailPage.vue')},
|
||||||
|
{path: 'events/:id/edit', name: "eventEdit", component: () => import('pages/profile/event/EditEventPage.vue')},
|
||||||
|
{path: 'organizations', name: "organizations", component: () => import('pages/profile/organization/OrganizationsPage.vue')},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
import {defineStore} from 'pinia'
|
||||||
|
import {apolloWrapper} from "src/graphql/apollo";
|
||||||
|
import {CREATE_EVENT, EDIT_EVENT} from "src/graphql/mutations/event";
|
||||||
|
import {updateInItems} from "stores/helpers";
|
||||||
|
import {EVENT_DETAIL, EVENTS_LIST} from "src/graphql/queries/event";
|
||||||
|
|
||||||
|
export const useEventsStore = defineStore('SecondPilots', {
|
||||||
|
state: () => ({
|
||||||
|
items: [],
|
||||||
|
isMutationRunning: false,
|
||||||
|
}),
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
fetchDetail(eventId) {
|
||||||
|
return apolloWrapper.query(EVENT_DETAIL, {id: eventId}).then(({data}) => data.event);
|
||||||
|
},
|
||||||
|
fetch() {
|
||||||
|
return apolloWrapper.query(EVENTS_LIST).then(result => {
|
||||||
|
this.items = result.data.events;
|
||||||
|
return result.data.events;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
create(formData) {
|
||||||
|
delete formData['id'];
|
||||||
|
|
||||||
|
this.isMutationRunning = true;
|
||||||
|
return apolloWrapper.mutate(CREATE_EVENT, {input: formData}).then(({data}) => {
|
||||||
|
const event = data.createEvent;
|
||||||
|
this.items.push(event);
|
||||||
|
return event;
|
||||||
|
}).finally(() => this.isMutationRunning = false);
|
||||||
|
},
|
||||||
|
update(id, formData) {
|
||||||
|
return apolloWrapper.mutate(EDIT_EVENT, {id: id, input: formData}).then(({data}) => {
|
||||||
|
const event = data.editEvent;
|
||||||
|
updateInItems(this.items, "id", event);
|
||||||
|
return event;
|
||||||
|
}).finally(() => this.isMutationRunning = false);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user