This commit is contained in:
Michal Kváček
2023-08-26 11:45:50 +02:00
parent ccc8ff22e2
commit dcc3230cbe
18 changed files with 132 additions and 42 deletions
+1 -1
View File
@@ -35,7 +35,7 @@ services:
- ./node_modules:/app/node_modules:delegated
command: quasar dev
environment:
VUE_API_URL: "http://localhost:8000"
API_URL: "http://localhost:8000"
# nginx:
# image:
+29
View File
@@ -0,0 +1,29 @@
<script setup>
import {poi} from "src/composables/objects/poi";
const props = defineProps({
routeBack: {
type: Object,
required: false
},
labelBack: {
type: String,
required: false,
default: "Přejít zpět na detail"
}
});
</script>
<template>
<q-banner class="bg-red text-white">
<template v-slot:avatar>
<q-icon name="warning"/>
</template>
Tato data ti nepatří a proto je nemůžeš měnit.
<template v-slot:action v-if="routeBack">
<q-btn flat color="white" :to="routeBack" :label="labelBack"/>
</template>
</q-banner>
</template>
+1 -1
View File
@@ -55,7 +55,7 @@ const fullwidthBtn = computed(() => $q.screen.width <= $q.screen.sizes.md);
{{ props.saveButton.label }}
<template v-slot:loading>
Loading...
<q-spinner />
</template>
</q-btn>
</div>
@@ -18,6 +18,15 @@ const props = defineProps({
<template>
<q-list bordered separator>
<q-item>
<q-item-section avatar>
<q-icon name="flight"/>
</q-item-section>
<q-item-section>
{{ flight.aircraft.callSign }}
</q-item-section>
</q-item>
<q-item>
<q-item-section avatar>
<q-icon name="event"/>
+1 -1
View File
@@ -50,7 +50,7 @@ const mapPhotos = computed(() => {
const displayMap = computed(() => {
return (
!!flight.value.gpsTrackUrl ||
!!flight.value.gpxTrackUrl ||
mapPhotos.value.length > 0 ||
trackWithGPS.value.length > 0 ||
flight.value.landingAirport.id !== flight.value.takeoffAirport.id
@@ -7,6 +7,10 @@ const props = defineProps({
flight: {
type: Object,
required: false
},
isRequestPending: {
type: Boolean,
required: true
}
}
)
@@ -16,7 +20,7 @@ const formData = reactive({
</script>
<template>
<FormWrapper v-model="formData" :save-button='{
<FormWrapper v-model="formData" :is-request-pending="isRequestPending" :save-button='{
label: "Nahrát",
icon: "upload",
align: "left"
@@ -31,7 +35,7 @@ const formData = reactive({
label="Vybert fotky k nahrání"
>
<template #prepend>
<q-icon name="upload" />
<q-icon name="upload"/>
</template>
</q-file>
</FormWrapper>
+4 -3
View File
@@ -4,14 +4,15 @@ import {commonProps} from "src/composables/inputs";
import {reactive, watch} from "vue";
import {setDefaultData} from "src/composables/form/formHandling";
import AvatarFromPhoto from "components/AvatarFromPhoto.vue";
import {user as pilot} from "src/composables/objects/user";
import {isRequestPending} from "src/composables/form/props";
const props = defineProps({
user: {
type: Object,
required: false,
default: null
}
},
isRequestPending
});
const formData = reactive({
avatarImage: null,
@@ -25,7 +26,7 @@ watch(() => props.user, (newVal) => {
<template>
<FormWrapper v-model="formData">
<FormWrapper v-model="formData" :is-request-pending="props.isRequestPending">
<div class="text-center">
<AvatarFromPhoto :size="200" :src="user.avatarImageUrl" v-if="user.avatarImageUrl" />
+5 -2
View File
@@ -6,13 +6,16 @@ import {commonProps} from "src/composables/inputs";
import RichTextEditor from "components/inputs/RichTextEditor.vue";
import FormWrapper from "components/FormWrapper.vue";
import {setDefaultData} from "src/composables/form/formHandling";
import {isRequestPending} from "src/composables/form/props";
const props = defineProps({
user: {
type: Object,
required: false,
default: null
}
},
isRequestPending,
})
const formData = reactive({
@@ -26,7 +29,7 @@ watch(() => props.user, (newVal) => {
</script>
<template>
<FormWrapper v-model="formData">
<FormWrapper v-model="formData" :is-request-pending="props.isRequestPending">
<q-list>
<q-item v-if="user.publicUsername">
+2 -4
View File
@@ -4,13 +4,11 @@ import {FRAGMENT_FLIGHT_FULL_INFO} from "src/graphql/fragments/flight";
export const CREATE_FLIGHT = gql`
mutation createFlight($input: CreateFlightInput!) {
createFlight(input: $input) {
...flightFullInfo
id
}
}
${FRAGMENT_FLIGHT_FULL_INFO}
`
// ^^ nesmim se tu ptat na aircraft, jinak mi to upadne
export const EDIT_FLIGHT = gql`
mutation editFlight($id: Int!, $input: EditFlightInput!) {
editFlight(id: $id, input: $input) {
+11 -3
View File
@@ -20,13 +20,21 @@
<q-icon name="person" v-else/>
<q-menu auto-close>
<q-list>
<q-list style="min-width: 200px">
<q-item clickable :to="{name: 'profile'}">
<q-item-section avatar>
<q-icon name="person"/>
</q-item-section>
<q-item-section>Osobní nastavení</q-item-section>
</q-item>
<q-item clickable @click="logout">
<q-item-section>Odhlásit</q-item-section>
<q-item clickable @click="logout" class="q-mt-lg">
<q-item-section avatar>
<q-icon name="logout"/>
</q-item-section>
<q-item-section>
Odhlásit
</q-item-section>
</q-item>
</q-list>
+7 -7
View File
@@ -13,11 +13,11 @@ useAppStore().setPageTitle("Profil");
const loggedUser = storeToRefs(useUserStore()).user;
const $q = useQuasar();
const handleSave = (formData) => {
useUserStore().update(loggedUser.id, formData).then((user) => {
$q.notify(successObject("Uspesne upraveno"));
});
const handleSave = async (formData) => {
await useUserStore().update(formData);
$q.notify(successObject("Úspěšně uloženo"));
};
const isRequestPending = storeToRefs(useUserStore()).isMutationRunning;
const openedTab = ref("profile");
</script>
@@ -30,15 +30,15 @@ const openedTab = ref("profile");
<q-tab-panels v-model="openedTab">
<q-tab-panel name="profile">
<ProfileImagesForm :user="loggedUser" @save="handleSave"/>
<ProfileImagesForm :user="loggedUser" :isRequestPending="isRequestPending" @save="handleSave"/>
</q-tab-panel>
<q-tab-panel name="changePassword">
<ChangePasswordForm @save="handleSave" />
<ChangePasswordForm @save="handleSave" :isRequestPending="isRequestPending" />
</q-tab-panel>
<q-tab-panel name="publicProfile">
<PublicProfileInfo @save="handleSave" :user="loggedUser" />
<PublicProfileInfo @save="handleSave" :isRequestPending="isRequestPending" :user="loggedUser" />
</q-tab-panel>
</q-tab-panels>
@@ -10,6 +10,7 @@ import FAB from "components/FAB.vue";
import {useAppStore} from "stores/App";
import FlightsList from "components/flights/FlightsList.vue";
import {copilot} from "src/composables/objects/copilot";
import {flight} from "src/composables/objects/flight";
const aircraftId = parseInt(useRoute().params.id);
onMounted(() => {
@@ -44,6 +45,21 @@ watch(aircraft, (newVal) => {
<q-card class="q-mx-md q-my-md flight-detail-card">
<q-img :src="aircraft.photoUrl" v-if="aircraft.photoUrl" />
<q-card-actions class="q-my-md">
<div class="col-grow">
<q-btn
flat
:to='{name: "aircraftEdit", params: {id: aircraft.id}}'
icon="edit"
text-color="primary"
label="Upravit"
/>
</div>
<q-btn @click="confirmDelete(aircraft.id)" icon="delete" flat text-color="red" label="Smazat"/>
</q-card-actions>
<q-card-section>
<q-list>
<q-item v-if="aircraft.manufacturer">
@@ -55,9 +71,10 @@ watch(aircraft, (newVal) => {
</q-list>
</q-card-section>
<q-card-actions align="right">
<q-btn @click="confirmDelete(aircraft.id)" icon="delete" text-color="red" rounded flat/>
</q-card-actions>
<!-- <q-card-actions align="right">-->
<!-- <q-btn :to='{name: "aircraftEdit", params: {id: aircraft.id}}' icon="edit" text-color="primary" rounded flat/>-->
<!-- <q-btn @click="confirmDelete(aircraft.id)" icon="delete" text-color="red" rounded flat/>-->
<!-- </q-card-actions>-->
</q-card>
<q-card class="flight-detail-card" flat>
@@ -68,7 +85,7 @@ watch(aircraft, (newVal) => {
<FlightsList :items="aircraft.flights" v-else/>
</q-card>
<FAB :router-link='{name: "aircraftEdit", params: {id: aircraft.id}}' mode="edit"/>
<!-- <FAB :router-link='{name: "aircraftEdit", params: {id: aircraft.id}}' mode="edit"/>-->
</template>
@@ -55,6 +55,8 @@ const handleFlightEdit = (data) => {
})
}
const isRequestPending = storeToRefs(useFlightsStore()).isMutationRunning;
const handlePhotosUpload = (data) => {
const promises = [];
for (const photo of data.photos) {
@@ -134,6 +136,7 @@ const openPhotoEdit = (photo) => {
<q-tab-panel name="photos">
<FlightFormPhotos
:flight="flight"
:is-request-pending="isRequestPending"
@save="handlePhotosUpload"
/>
@@ -144,6 +147,8 @@ const openPhotoEdit = (photo) => {
@save="handlePhotoUpdate"
/>
Tu nejsou videt fotky po nahrani
<PhotosList
:photos="flight.photos"
@edit="openPhotoEdit"
@@ -10,6 +10,8 @@ import {successObject} from "src/composables/dialog";
import {usePointsOfInterestTypeStore} from "stores/PointOfInterestType";
import {storeToRefs} from "pinia";
import POIForm from "components/poi/POIForm.vue";
import {useUserStore} from "stores/User";
import AccessDeniedBanner from "components/AccessDeniedBanner.vue";
const poiId = parseInt(useRoute().params.id);
@@ -27,6 +29,7 @@ onMounted(() => {
})
const poiTypes = storeToRefs(usePointsOfInterestTypeStore()).items;
const loggedUser = storeToRefs(useUserStore()).user;
const $q = useQuasar();
const router = useRouter();
@@ -40,6 +43,6 @@ const handleSave = (data) => {
<template>
<POIEditSkeleton v-if="loading"/>
<AccessDeniedBanner v-else-if="poi.createdbyId !== loggedUser.id" :route-back="{name: 'poiDetail', params: {id: poiId}}"/>
<POIForm :poi="poi" :types="poiTypes" v-else @save="handleSave"/>
</template>
@@ -29,7 +29,7 @@ onMounted(() => {
<POIDetailSkeleton v-if="loading || !poi"/>
<template v-else>
<article v-html="poi.description" />
<article v-html="poi.description" class="q-my-lg" />
<EmbeddedMap
v-if="poi.gpsLatitude && poi.gpsLongitude"
@@ -51,7 +51,7 @@ onMounted(() => {
Pokud přidáš toto místo k nějaké fotce, zobrazí se tu.
</BasicInfoBanner>
<FlightsList :items="poi.flights" />
<FlightsList :items="poi.flights" v-if="poi.flights.length > 0 && loggedUser.id === poi.createdById"/>
<FAB v-if="poi.createdById === loggedUser.id" :router-link="{name: 'poiEdit', params:{id: poi.id}}" mode="edit"/>
</template>
+8 -5
View File
@@ -6,7 +6,8 @@ import {deleteFromItems, updateInItems} from "stores/helpers";
export const useAircraftsStore = defineStore('Aircrafts', {
state: () => ({
items: []
items: [],
isMutationRunning: false
}),
getters: {
@@ -15,18 +16,19 @@ export const useAircraftsStore = defineStore('Aircrafts', {
actions: {
fetchDetail(id) {
console.log(id);
return apolloWrapper
.query(AIRCRAFT_DETAIL, {id})
.then((result) => result.data.aircraft);
},
create(formData) {
delete formData['id'];
this.isMutationRunning = true;
return apolloWrapper.mutate(CREATE_AIRCRAFT, {input: formData}).then(({data}) => {
this.items.push(data.createAircraft);
// this.items.push(data.createAircraft);
return data.createAircraft;
})
}).finally(() => this.isMutationRunning = false);
},
delete(id) {
return apolloWrapper.mutate(DELETE_AIRCRAFT, {id}).then(({data}) => {
@@ -36,11 +38,12 @@ export const useAircraftsStore = defineStore('Aircrafts', {
});
},
update(id, formData) {
this.isMutationRunning = true;
return apolloWrapper.mutate(EDIT_AIRCRAFT, {id: id, input: formData}).then(({data}) => {
const aircraft = data.editAircraft;
updateInItems(this.items, 'id', aircraft);
return aircraft;
});
}).finally(() => this.isMutationRunning = false);
},
fetch() {
return apolloWrapper
+10 -3
View File
@@ -6,7 +6,8 @@ import {updateInItems} from "stores/helpers";
export const useFlightsStore = defineStore('Flights', {
state: () => ({
items: []
items: [],
isMutationRunning: false
}),
getters: {
@@ -19,18 +20,24 @@ export const useFlightsStore = defineStore('Flights', {
create(formData) {
delete formData['id'];
return apolloWrapper.mutate(CREATE_FLIGHT, {input: formData}).then(({data}) => {
this.items.push(data.createFlight);
const flightId = data.createFlight.id;
// pitomy ohack kvuli tomu, ze se mi nedari dostat z API rovnou informace o nove vytvorenem letadle
this.fetchDetail(flightId).then(flight => {
this.items.push(flight);
})
return data.createFlight;
})
},
update(id, formData) {
this.isMutationRunning = true;
return apolloWrapper.mutate(EDIT_FLIGHT, {id: id, input: formData}).then(({data}) => {
const flight = data.editFlight;
updateInItems(this.items, "id", flight);
return flight;
});
}).finally(() => this.isMutationRunning = false);
},
fetchDetail(id, username = null) {
if (typeof id !== "number") {
+6 -3
View File
@@ -8,15 +8,18 @@ export const useUserStore = defineStore('LoggedUser', {
state: () => ({
user: {},
isRefreshing: false,
isMutationRunning: false,
}),
actions: {
update(id, formData) {
apolloWrapper.mutate(EDIT_USER, {id, input: formData}).then((response) => {
update(formData) {
this.isMutationRunning = true;
apolloWrapper.mutate(EDIT_USER, {input: formData}).then((response) => {
const user = response.data?.editLoggedUser;
this.user = user;
return user;
});
}).finally(() => this.isMutationRunning = false);
},
fetchLoggedUserDetail() {