Mapa s trasami letu u eventu, drobna uprava vizualu eventu
This commit is contained in:
+1
-1
@@ -36,7 +36,7 @@ services:
|
|||||||
- ./src-ssr:/app/src-ssr
|
- ./src-ssr:/app/src-ssr
|
||||||
- ./public:/app/public
|
- ./public:/app/public
|
||||||
# - ./node_modules:/app/node_modules:delegated
|
# - ./node_modules:/app/node_modules:delegated
|
||||||
command: quasar dev -m ssr
|
command: quasar dev # -m ssr
|
||||||
environment:
|
environment:
|
||||||
API_URL: "http://127.0.0.1:8000"
|
API_URL: "http://127.0.0.1:8000"
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<script setup>
|
||||||
|
import {FORMAT_DATE, formatDatetime, minutesToHumanReadable} from "src/composables/datetimeUtils";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
event: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<q-chip icon="date_range" v-if="event.dateFrom || event.dateTo">
|
||||||
|
<template v-if="event.dateFrom !== event.dateTo">
|
||||||
|
{{ formatDatetime(event.dateFrom, FORMAT_DATE) }} - {{ formatDatetime(event.dateTo, FORMAT_DATE) }}
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
{{ formatDatetime(event.dateFrom, FORMAT_DATE) }}
|
||||||
|
</template>
|
||||||
|
</q-chip>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
<script setup>
|
||||||
|
import MapWithMarkers from "components/map/MapWithMarkers.vue";
|
||||||
|
import {ref} from "vue";
|
||||||
|
import {useEventsStore} from "stores/Events";
|
||||||
|
import {minutesToHumanReadable} from "../../composables/datetimeUtils";
|
||||||
|
import {pluralize} from "../../composables/utils";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
event: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
onlyPublic: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const tracks = ref([]);
|
||||||
|
const totalTime = ref(0);
|
||||||
|
const totalFlights = ref(0);
|
||||||
|
|
||||||
|
useEventsStore().fetchFlightsTracks({
|
||||||
|
eventId: props.event.id,
|
||||||
|
onlyPublic: props.onlyPublic
|
||||||
|
}).then((data) => {
|
||||||
|
if (!data.flights) return;
|
||||||
|
|
||||||
|
totalFlights.value = data.flights.length;
|
||||||
|
|
||||||
|
for (const flightTrack of data.flights) {
|
||||||
|
totalTime.value += flightTrack.durationMinCalculated;
|
||||||
|
|
||||||
|
if (flightTrack.gpxTrack) {
|
||||||
|
tracks.value.push(flightTrack.gpxTrack.coordinates);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<template v-if="tracks.length > 1">
|
||||||
|
<h3>Trasy letů</h3>
|
||||||
|
|
||||||
|
<MapWithMarkers
|
||||||
|
style="width: 100%; height: 500px;"
|
||||||
|
:tracks="tracks"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div class="text-center q-my-md">
|
||||||
|
<q-chip>
|
||||||
|
<q-avatar>{{ totalFlights }}</q-avatar>
|
||||||
|
{{ pluralize(totalFlights, "let", "lety", "letů") }}
|
||||||
|
</q-chip>
|
||||||
|
|
||||||
|
<q-chip icon="schedule">
|
||||||
|
{{ minutesToHumanReadable(totalTime) }}
|
||||||
|
</q-chip>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"name": "event",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git@kvacek.cz:poletani.cz/app.git"
|
||||||
|
},
|
||||||
|
"private": true
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ import AvatarFromPhoto from "components/avatars/AvatarFromPhoto.vue";
|
|||||||
import FlightsListSkeleton from "components/flights/skeletons/FlightsListSkeleton.vue";
|
import FlightsListSkeleton from "components/flights/skeletons/FlightsListSkeleton.vue";
|
||||||
import {computed} from "vue";
|
import {computed} from "vue";
|
||||||
import LoadMoreList from "components/LoadMoreList.vue";
|
import LoadMoreList from "components/LoadMoreList.vue";
|
||||||
|
import {pluralize} from "../../composables/utils";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
items: {
|
items: {
|
||||||
@@ -37,16 +38,8 @@ const routeDetail = (flight) => {
|
|||||||
else
|
else
|
||||||
return {name: "flightDetail", params: {id: flight.id}}
|
return {name: "flightDetail", params: {id: flight.id}}
|
||||||
};
|
};
|
||||||
|
|
||||||
const pluralize = (count, singular, plural, pluralMore) => {
|
|
||||||
if (count === 1) return singular;
|
|
||||||
else if (count < 5) return plural;
|
|
||||||
else return pluralMore;
|
|
||||||
}
|
|
||||||
const loadMoreCount = computed(() => {
|
const loadMoreCount = computed(() => {
|
||||||
const remaining = props.totalItemsCount - props.items.length;
|
return Math.min(props.itemsPerPage, props.totalItemsCount - props.items.length);
|
||||||
|
|
||||||
return Math.min(props.itemsPerPage, remaining);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,14 +1,20 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import MapWrapper from "components/map/MapWrapper.vue";
|
import MapWrapper from "components/map/MapWrapper.vue";
|
||||||
import {Marker, Polyline, InfoWindow} from "vue3-google-map";
|
import {Marker, Polyline, InfoWindow} from "vue3-google-map";
|
||||||
import {computed, onMounted, ref} from "vue";
|
import {computed} from "vue";
|
||||||
import {axios} from "boot/axios";
|
|
||||||
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
gpxTrack: {
|
gpxTrack: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: false,
|
required: false,
|
||||||
|
default: () => {
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tracks: {
|
||||||
|
type: Array,
|
||||||
|
required: false,
|
||||||
|
default: () => []
|
||||||
},
|
},
|
||||||
markers: {
|
markers: {
|
||||||
type: Array,
|
type: Array,
|
||||||
@@ -26,12 +32,47 @@ const props = defineProps({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const track = ref([]);
|
|
||||||
const bounds = computed(() => {
|
const bounds = computed(() => {
|
||||||
const photosTransformed = props.photos.map(p => ({position: {lat: p.gpsLatitude, lng: p.gpsLongitude}}));
|
const photosTransformed = props.photos.map(p => ({position: {lat: p.gpsLatitude, lng: p.gpsLongitude}}));
|
||||||
const allData = [...props.markers, ...track.value, ...photosTransformed];
|
const coordinates = [
|
||||||
return allData.filter(i => !!i.position).map(i => i.position);
|
...[...props.markers, ...photosTransformed].filter(i => !!i.position).map(i => i.position),
|
||||||
|
...(props.gpxTrack || []),
|
||||||
|
...(props.tracks || []).flat()
|
||||||
|
];
|
||||||
|
|
||||||
|
const minLat = Math.min(...coordinates.map(i => i.lat));
|
||||||
|
const maxLat = Math.max(...coordinates.map(i => i.lat));
|
||||||
|
const minLng = Math.min(...coordinates.map(i => i.lng));
|
||||||
|
const maxLng = Math.max(...coordinates.map(i => i.lng));
|
||||||
|
|
||||||
|
return [
|
||||||
|
{lat: minLat, lng: minLng},
|
||||||
|
{lat: minLat, lng: maxLng},
|
||||||
|
{lat: maxLat, lng: minLng},
|
||||||
|
{lat: maxLat, lng: maxLng},
|
||||||
|
];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
const getRandomColor = () => {
|
||||||
|
const r = Math.floor(Math.random() * 256);
|
||||||
|
const g = Math.floor(Math.random() * 256);
|
||||||
|
const b = Math.floor(Math.random() * 256);
|
||||||
|
|
||||||
|
return `rgb(${r}, ${g}, ${b})`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const getColor = (i) => {
|
||||||
|
const colors = [
|
||||||
|
'#FF0000',
|
||||||
|
'#5733FF', '#4bec41', '#8d3f25',
|
||||||
|
'#33A1FF', '#6d7e59', '#FF3333', '#0e1c48',
|
||||||
|
'#A133FF', '#FFFF33', '#c9decc'
|
||||||
|
]
|
||||||
|
return colors[i] || getRandomColor()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -47,6 +88,12 @@ const bounds = computed(() => {
|
|||||||
<Polyline :options="{path: gpxTrack, geodesic: true, strokeColor: '#ff0000', strokeOpacity: 0.3, strokeWeight: 5}"/>
|
<Polyline :options="{path: gpxTrack, geodesic: true, strokeColor: '#ff0000', strokeOpacity: 0.3, strokeWeight: 5}"/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<template v-if="tracks && tracks.length > 0">
|
||||||
|
<template v-for="(track, i) in tracks" :key="track">
|
||||||
|
<Polyline :options="{path: track, geodesic: false, strokeColor: getColor(i), strokeOpacity: 1, strokeWeight: 3}"/>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
|
||||||
<Marker v-if="highlightPosition" :options="{position: highlightPosition, icon: '/mapIcons/currentPosition32x32.png'}"/>
|
<Marker v-if="highlightPosition" :options="{position: highlightPosition, icon: '/mapIcons/currentPosition32x32.png'}"/>
|
||||||
|
|
||||||
</MapWrapper>
|
</MapWrapper>
|
||||||
|
|||||||
@@ -14,34 +14,6 @@ export const minutesToHumanReadable = (totalMinutes) => {
|
|||||||
return `${hoursPart}${minutes}min`
|
return `${hoursPart}${minutes}min`
|
||||||
}
|
}
|
||||||
|
|
||||||
export const formatDatetimeNative = (date, format = "DD. MM. YYYY") => {
|
|
||||||
if (typeof date === 'string') {
|
|
||||||
date = parseDate(date);
|
|
||||||
}
|
|
||||||
|
|
||||||
return format
|
|
||||||
.replace("DD", date.getDate().toString())
|
|
||||||
.replace("MM", (date.getMonth() + 1).toString())
|
|
||||||
.replace("YYYY", date.getFullYear().toString())
|
|
||||||
|
|
||||||
// todo: doplnit pocatecni nuly
|
|
||||||
.replace("hh", date.getHours().toString())
|
|
||||||
.replace("mm", date.getMinutes().toString())
|
|
||||||
.replace("ss", date.getSeconds().toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
export const parseDateNative = (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);
|
|
||||||
return new Date(timestamp);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export const parseDate = (datetimeStr, format = FORMAT_ISO) => {
|
export const parseDate = (datetimeStr, format = FORMAT_ISO) => {
|
||||||
return date.extractDate(datetimeStr, format)
|
return date.extractDate(datetimeStr, format)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,3 +2,9 @@ export const roundWithPrecision = (number, precision) => {
|
|||||||
const factor = Math.pow(10, precision);
|
const factor = Math.pow(10, precision);
|
||||||
return Math.round(number * factor) / factor;
|
return Math.round(number * factor) / factor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const pluralize = (count, singular, plural, pluralMore) => {
|
||||||
|
if (count === 1) return singular;
|
||||||
|
else if (count < 5) return plural;
|
||||||
|
else return pluralMore;
|
||||||
|
}
|
||||||
|
|||||||
@@ -20,13 +20,29 @@ query eventsList($limit: Int!, $offset: Int) {
|
|||||||
${FRAGMENT_EVENT_LIST_INFO}
|
${FRAGMENT_EVENT_LIST_INFO}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const EVENTS_FLIGHTS_TRACKS = gql`
|
||||||
|
query eventsFlightsTracks($eventId: Int!, $onlyPublic: Boolean) {
|
||||||
|
event(id: $eventId) {
|
||||||
|
flights(onlyPublic: $onlyPublic) {
|
||||||
|
durationMinCalculated
|
||||||
|
gpxTrack {
|
||||||
|
coordinates {
|
||||||
|
lat
|
||||||
|
lng
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
export const EVENTS_PUBLIC_LIST = gql`
|
export const EVENTS_PUBLIC_LIST = gql`
|
||||||
query eventsPublicList($username: String, $limit: Int!, $offset: Int) {
|
query eventsPublicList($username: String, $limit: Int!, $offset: Int) {
|
||||||
events(username: $username, limit: $limit, offset: $offset, public: true) {
|
events(username: $username, limit: $limit, offset: $offset, public: true) {
|
||||||
items {
|
items {
|
||||||
...eventListInfo
|
...eventListInfo
|
||||||
|
|
||||||
flights {
|
flights(onlyPublic: true) {
|
||||||
titlePhoto {
|
titlePhoto {
|
||||||
thumbnailUrl
|
thumbnailUrl
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import EventDetailSkeleton from "components/event/skeletons/EventDetailSkeleton.
|
|||||||
import {useAppStore} from "stores/App";
|
import {useAppStore} from "stores/App";
|
||||||
import FAB from "components/FAB.vue";
|
import FAB from "components/FAB.vue";
|
||||||
import FlightsList from "components/flights/FlightsList.vue";
|
import FlightsList from "components/flights/FlightsList.vue";
|
||||||
import {FORMAT_DATE, formatDatetime} from "src/composables/datetimeUtils";
|
|
||||||
import {useEventsStore} from "stores/Events";
|
import {useEventsStore} from "stores/Events";
|
||||||
import {storeToRefs} from "pinia";
|
import {storeToRefs} from "pinia";
|
||||||
import {filters, loadPage, paginationLimit} from "src/composables/pagination";
|
import {filters, loadPage, paginationLimit} from "src/composables/pagination";
|
||||||
@@ -13,9 +12,10 @@ import {useFlightsStore} from "stores/Flights";
|
|||||||
import PublishButton from "components/inputs/PublishButton.vue";
|
import PublishButton from "components/inputs/PublishButton.vue";
|
||||||
import {useLoggedUserStore} from "stores/LoggedUser";
|
import {useLoggedUserStore} from "stores/LoggedUser";
|
||||||
import {toggleVisibility} from "src/composables/form/formHandling";
|
import {toggleVisibility} from "src/composables/form/formHandling";
|
||||||
import {TOGGLE_FLIGHT_PUBLISH} from "src/graphql/mutations/flight";
|
|
||||||
import {useQuasar} from "quasar";
|
import {useQuasar} from "quasar";
|
||||||
import CopyLinkButton from "components/inputs/CopyLinkButton.vue";
|
import CopyLinkButton from "components/inputs/CopyLinkButton.vue";
|
||||||
|
import EventFlightsMap from "components/event/EventFlightsMap.vue";
|
||||||
|
import EventBasicInfo from "components/event/EventBasicInfo.vue";
|
||||||
|
|
||||||
const eventId = parseInt(useRoute().params.id);
|
const eventId = parseInt(useRoute().params.id);
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
@@ -35,7 +35,6 @@ const togglePublicVisibility = (variables) => toggleVisibility({
|
|||||||
$q, store: useEventsStore(), object: event.value, variables
|
$q, store: useEventsStore(), object: event.value, variables
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
const {isQueryRunning, event} = storeToRefs(useEventsStore());
|
const {isQueryRunning, event} = storeToRefs(useEventsStore());
|
||||||
|
|
||||||
filters.value = {eventId: eventId}
|
filters.value = {eventId: eventId}
|
||||||
@@ -51,19 +50,7 @@ const loggedUser = storeToRefs(useLoggedUserStore()).user;
|
|||||||
<EventDetailSkeleton v-if="isQueryRunning || !event"/>
|
<EventDetailSkeleton v-if="isQueryRunning || !event"/>
|
||||||
|
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<q-list bordered separator class="q-my-lg" v-if="event.dateFrom && event.dateTo">
|
<EventBasicInfo :event="event"/>
|
||||||
<q-item>
|
|
||||||
<q-item-section>
|
|
||||||
Od: {{ formatDatetime(event.dateFrom, FORMAT_DATE) }}
|
|
||||||
</q-item-section>
|
|
||||||
</q-item>
|
|
||||||
|
|
||||||
<q-item>
|
|
||||||
<q-item-section>
|
|
||||||
Do: {{ formatDatetime(event.dateTo, FORMAT_DATE) }}
|
|
||||||
</q-item-section>
|
|
||||||
</q-item>
|
|
||||||
</q-list>
|
|
||||||
|
|
||||||
<PublishButton
|
<PublishButton
|
||||||
:url-prefix="`${loggedUser.publicUsername}/udalosti/`"
|
:url-prefix="`${loggedUser.publicUsername}/udalosti/`"
|
||||||
@@ -75,11 +62,13 @@ const loggedUser = storeToRefs(useLoggedUserStore()).user;
|
|||||||
:route="{name: 'publicEventDetail', params: {username: loggedUser.publicUsername, eventSlug: event.urlSlug}}"
|
:route="{name: 'publicEventDetail', params: {username: loggedUser.publicUsername, eventSlug: event.urlSlug}}"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<article v-html="event.description"/>
|
<article class="q-my-lg" v-html="event.description"/>
|
||||||
|
|
||||||
|
<EventFlightsMap :event="event" :only-public="false" />
|
||||||
|
|
||||||
<h3>Lety</h3>
|
<h3>Lety</h3>
|
||||||
|
|
||||||
<q-banner v-if="event.flights.length === 0" class="bg-light-blue text-white">
|
<q-banner v-if="flights.length === 0" class="bg-light-blue text-white">
|
||||||
Zatím tu nemáš uložené žádné lety.
|
Zatím tu nemáš uložené žádné lety.
|
||||||
</q-banner>
|
</q-banner>
|
||||||
|
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ const togglePublicVisibility = (variables) => toggleVisibility({
|
|||||||
<FlightBasicInfo
|
<FlightBasicInfo
|
||||||
:flight="flight"
|
:flight="flight"
|
||||||
:poi-detail-route="{name: 'poiDetail'}"
|
:poi-detail-route="{name: 'poiDetail'}"
|
||||||
:event-detail-route="{name: 'eventDetail', params: {id: flight.event.id}}"
|
:event-detail-route="flight.event ? {name: 'eventDetail', params: {id: flight.event.id}} : null"
|
||||||
:aircraft-detail-route="{name: 'aircraftDetail'}"
|
:aircraft-detail-route="{name: 'aircraftDetail'}"
|
||||||
:copilot-detail-route="{name: 'copilotDetail'}"
|
:copilot-detail-route="{name: 'copilotDetail'}"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ export default {
|
|||||||
<script setup>
|
<script setup>
|
||||||
import {useAppStore} from "stores/App";
|
import {useAppStore} from "stores/App";
|
||||||
import EventDetailSkeleton from "components/event/skeletons/EventDetailSkeleton.vue";
|
import EventDetailSkeleton from "components/event/skeletons/EventDetailSkeleton.vue";
|
||||||
import {FORMAT_DATE, formatDatetime} from "src/composables/datetimeUtils";
|
|
||||||
import FlightsList from "components/flights/FlightsList.vue";
|
import FlightsList from "components/flights/FlightsList.vue";
|
||||||
import {storeToRefs} from "pinia";
|
import {storeToRefs} from "pinia";
|
||||||
import {filters, loadPage, paginationLimit} from "src/composables/pagination";
|
import {filters, loadPage, paginationLimit} from "src/composables/pagination";
|
||||||
@@ -19,6 +18,8 @@ import {useFlightsStore} from "stores/Flights";
|
|||||||
import FlightsListSkeleton from "components/flights/skeletons/FlightsListSkeleton.vue";
|
import FlightsListSkeleton from "components/flights/skeletons/FlightsListSkeleton.vue";
|
||||||
import {useMeta} from "quasar";
|
import {useMeta} from "quasar";
|
||||||
import {metaData} from "src/composables/meta";
|
import {metaData} from "src/composables/meta";
|
||||||
|
import EventBasicInfo from "components/event/EventBasicInfo.vue";
|
||||||
|
import EventFlightsMap from "components/event/EventFlightsMap.vue";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
pilot: {
|
pilot: {
|
||||||
@@ -55,21 +56,12 @@ const {flights, totalItemsCount, isQueryRunning: areFlightsLoading} = storeToRef
|
|||||||
<EventDetailSkeleton v-if="isQueryRunning || !event"/>
|
<EventDetailSkeleton v-if="isQueryRunning || !event"/>
|
||||||
|
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<q-list bordered separator class="q-my-lg" v-if="event.dateFrom && event.dateTo">
|
<EventBasicInfo :event="event"/>
|
||||||
<q-item>
|
|
||||||
<q-item-section>
|
|
||||||
Od: {{ formatDatetime(event.dateFrom, FORMAT_DATE) }}
|
|
||||||
</q-item-section>
|
|
||||||
</q-item>
|
|
||||||
|
|
||||||
<q-item>
|
<article class="q-my-lg" v-html="event.description"/>
|
||||||
<q-item-section>
|
|
||||||
Do: {{ formatDatetime(event.dateTo, FORMAT_DATE) }}
|
<EventFlightsMap :event="event" :only-public="true"/>
|
||||||
</q-item-section>
|
|
||||||
</q-item>
|
|
||||||
</q-list>
|
|
||||||
|
|
||||||
<article v-html="event.description"/>
|
|
||||||
<h3>Lety</h3>
|
<h3>Lety</h3>
|
||||||
|
|
||||||
<q-banner v-if="event.flights.length === 0" class="bg-light-blue text-white">
|
<q-banner v-if="event.flights.length === 0" class="bg-light-blue text-white">
|
||||||
@@ -87,7 +79,6 @@ const {flights, totalItemsCount, isQueryRunning: areFlightsLoading} = storeToRef
|
|||||||
:public="true"
|
:public="true"
|
||||||
@load-more="loadNextFlightsPage(true)"
|
@load-more="loadNextFlightsPage(true)"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import {defineStore} from 'pinia'
|
|||||||
import {CREATE_EVENT, EDIT_EVENT} from "src/graphql/mutations/event";
|
import {CREATE_EVENT, EDIT_EVENT} from "src/graphql/mutations/event";
|
||||||
import {mutate, query, rewriteObject, setItems, updateInItems} from "stores/helpers";
|
import {mutate, query, rewriteObject, setItems, updateInItems} from "stores/helpers";
|
||||||
import {ref} from "vue";
|
import {ref} from "vue";
|
||||||
import {EVENT_DETAIL, EVENT_PUBLIC_DETAIL, EVENTS_LIST, EVENTS_PUBLIC_LIST} from "src/graphql/queries/event";
|
import {EVENT_DETAIL, EVENT_PUBLIC_DETAIL, EVENTS_FLIGHTS_TRACKS, EVENTS_LIST, EVENTS_PUBLIC_LIST} from "src/graphql/queries/event";
|
||||||
|
|
||||||
export const useEventsStore = defineStore('Events', () => {
|
export const useEventsStore = defineStore('Events', () => {
|
||||||
const event = ref(null);
|
const event = ref(null);
|
||||||
@@ -27,6 +27,13 @@ export const useEventsStore = defineStore('Events', () => {
|
|||||||
}).then(item => event.value = item);
|
}).then(item => event.value = item);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const fetchFlightsTracks = ({eventId, onlyPublic}) => {
|
||||||
|
return query({
|
||||||
|
query: EVENTS_FLIGHTS_TRACKS,
|
||||||
|
variables: {eventId, onlyPublic}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const fetch = ({limit = 100, offset, appendItems}) => {
|
const fetch = ({limit = 100, offset, appendItems}) => {
|
||||||
return query({
|
return query({
|
||||||
isQueryRunning,
|
isQueryRunning,
|
||||||
@@ -65,6 +72,6 @@ export const useEventsStore = defineStore('Events', () => {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
event, events, isMutationRunning, isQueryRunning, fetch, fetchDetail, create, update,
|
event, events, isMutationRunning, isQueryRunning, fetch, fetchDetail, create, update,
|
||||||
fetchPublic, fetchPublicDetail, totalItemsCount
|
fetchPublic, fetchPublicDetail, totalItemsCount, fetchFlightsTracks
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -39,7 +39,9 @@ export const query = ({isQueryRunning, query, variables, refreshUnauthorized}) =
|
|||||||
|
|
||||||
query._refreshUnauthorizedUser = typeof refreshUnauthorized === 'undefined' ? true : refreshUnauthorized;
|
query._refreshUnauthorizedUser = typeof refreshUnauthorized === 'undefined' ? true : refreshUnauthorized;
|
||||||
|
|
||||||
|
if (isQueryRunning)
|
||||||
isQueryRunning.value = true;
|
isQueryRunning.value = true;
|
||||||
|
|
||||||
const queryName = query.definitions[0].selectionSet.selections[0].name.value;
|
const queryName = query.definitions[0].selectionSet.selections[0].name.value;
|
||||||
return apolloWrapper.query(query, variables)
|
return apolloWrapper.query(query, variables)
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
@@ -49,12 +51,18 @@ export const query = ({isQueryRunning, query, variables, refreshUnauthorized}) =
|
|||||||
return result.data[queryName]
|
return result.data[queryName]
|
||||||
})
|
})
|
||||||
.catch(e => Promise.reject(e))
|
.catch(e => Promise.reject(e))
|
||||||
.finally(() => isQueryRunning.value = false);
|
.finally(() => {
|
||||||
|
if (isQueryRunning)
|
||||||
|
isQueryRunning.value = false
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export const mutate = ({isMutationRunning, mutation, variables}) => {
|
export const mutate = ({isMutationRunning, mutation, variables}) => {
|
||||||
isMutationRunning.value = true;
|
isMutationRunning.value = true;
|
||||||
let mutationName = getOperationName(mutation);
|
let mutationName = getOperationName(mutation);
|
||||||
|
|
||||||
|
// TODO: pridat refresh tokenu!
|
||||||
|
|
||||||
return apolloWrapper.mutate(mutation, variables)
|
return apolloWrapper.mutate(mutation, variables)
|
||||||
.then(result => {
|
.then(result => {
|
||||||
if (typeof result.data[mutationName] === 'undefined') {
|
if (typeof result.data[mutationName] === 'undefined') {
|
||||||
|
|||||||
Reference in New Issue
Block a user