From 7e0d00f2cd6fbe7a8037ac696933490e3e01d1a8 Mon Sep 17 00:00:00 2001 From: Raajheer1 Date: Sun, 27 Oct 2024 17:48:14 -0500 Subject: [PATCH] Events & Facilities --- .github/workflows/upgrade.yaml | 43 +++++ src/components/Modal.vue | 29 ++++ src/components/event/EventPositions.vue | 100 ++++++++++++ src/components/event/PositionList.vue | 136 ++++++++++++++++ src/components/event/PositionTooltip.vue | 154 ++++++++++++++++++ src/components/profile/Notifications.vue | 17 +- src/data/sidebar.ts | 12 +- src/router/index.ts | 57 ++++++- src/stores/event.ts | 129 +++++++++++++++ src/stores/facility.ts | 16 +- src/stores/feedback.ts | 3 +- src/stores/sidebar.ts | 118 ++++++++++++++ src/stores/user.ts | 29 +++- src/types/index.d.ts | 62 ++++++- src/utils/auth.ts | 37 +++++ src/views/Event.vue | 196 +++++++++++++++++++++++ src/views/Home.vue | 39 ++++- src/views/Profile.vue | 2 +- src/views/controllers/MyFeedback.vue | 2 +- src/views/facility/Roster.vue | 157 ++++++++++++++++++ src/views/partials/Footer.vue | 1 + src/views/partials/Sidebar.vue | 40 +++-- src/views/pilots/LeaveFeedback.vue | 9 +- 23 files changed, 1340 insertions(+), 48 deletions(-) create mode 100644 .github/workflows/upgrade.yaml create mode 100644 src/components/Modal.vue create mode 100644 src/components/event/EventPositions.vue create mode 100644 src/components/event/PositionList.vue create mode 100644 src/components/event/PositionTooltip.vue create mode 100644 src/stores/event.ts create mode 100644 src/stores/sidebar.ts create mode 100644 src/utils/auth.ts create mode 100644 src/views/Event.vue create mode 100644 src/views/facility/Roster.vue diff --git a/.github/workflows/upgrade.yaml b/.github/workflows/upgrade.yaml new file mode 100644 index 0000000..a76bae8 --- /dev/null +++ b/.github/workflows/upgrade.yaml @@ -0,0 +1,43 @@ +name: Upgrade Dependencies + +on: + schedule: + - cron: '1 0 * * 0' + workflow_dispatch: + +jobs: + yarn-upgrade: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 18 + cache: 'yarn' + - name: Install Yarn + run: npm install -g yarn + - name: Setup git and create branch + env: + GITHUB_TOKEN: ${{ secrets.G_TOKEN }} + run: | + git config --global user.name "Raajheer1" + git config --global user.email "raaj.patel229@gmail.com" + + git checkout -b chore/upgrade-dependencies-$(date +%Y-%m-%d) + git push --set-upstream origin chore/upgrade-dependencies-$(date +%Y-%m-%d) + - name: Upgrade dependencies + run: yarn upgrade --latest + - name: Lint fix + run: yarn lint:fix + - name: Commit and push changes + env: + GITHUB_TOKEN: ${{ secrets.G_TOKEN }} + run: | + git add . + git commit -m "chore: upgrade dependencies" + git push + - name: Create PR + env: + GITHUB_TOKEN: ${{ secrets.G_TOKEN }} + run: | + gh pr create -t "Chore: Upgrade Dependencies" -B master -H chore/upgrade-dependencies-$(date +%Y-%m-%d) --body "Weekly automated PR to upgrade dependencies using \`yarn upgrade --latest\`. Please verify the changes and merge." diff --git a/src/components/Modal.vue b/src/components/Modal.vue new file mode 100644 index 0000000..356fad1 --- /dev/null +++ b/src/components/Modal.vue @@ -0,0 +1,29 @@ + + + + + diff --git a/src/components/event/EventPositions.vue b/src/components/event/EventPositions.vue new file mode 100644 index 0000000..68d176b --- /dev/null +++ b/src/components/event/EventPositions.vue @@ -0,0 +1,100 @@ + + + + diff --git a/src/components/event/PositionList.vue b/src/components/event/PositionList.vue new file mode 100644 index 0000000..ace3773 --- /dev/null +++ b/src/components/event/PositionList.vue @@ -0,0 +1,136 @@ + + + + diff --git a/src/components/event/PositionTooltip.vue b/src/components/event/PositionTooltip.vue new file mode 100644 index 0000000..2fb8459 --- /dev/null +++ b/src/components/event/PositionTooltip.vue @@ -0,0 +1,154 @@ + + + + diff --git a/src/components/profile/Notifications.vue b/src/components/profile/Notifications.vue index c58879d..3563f68 100644 --- a/src/components/profile/Notifications.vue +++ b/src/components/profile/Notifications.vue @@ -102,14 +102,23 @@ import Primary from "@/components/buttons/Primary.vue"; import Spinner from "@/components/animations/Spinner.vue"; const userStore = useUserStore(); -const settings = ref(); +const settings = ref({ + discord: false, + training: false, + events: false, + feedback: false, + email: false, +}); onMounted(async () => { - settings.value = await userStore.fetchNotificationSettings(userStore.self.cid); + const resp = await userStore.fetchNotificationSettings(userStore.self!.cid); + if (resp) { + settings.value = resp; + } }); -function updateSettings(): null { - userStore.updateNotificationSettings(userStore.self.cid, settings.value); +function updateSettings(): void { + userStore.updateNotificationSettings(userStore.self!.cid, settings.value); } function setDiscord(state: boolean): void { diff --git a/src/data/sidebar.ts b/src/data/sidebar.ts index 29a7e04..78a9e96 100644 --- a/src/data/sidebar.ts +++ b/src/data/sidebar.ts @@ -6,10 +6,15 @@ const SidebarLinks: Link[] = [ icon: "fa-solid fa-home", to: { name: "Home" }, }, + { + title: "My Profile", + icon: "fa-solid fa-user", + to: { name: "Profile" }, + }, { title: "My Flights", icon: "fa-solid fa-plane", - // to: { name: "My Flights" }, + to: { name: "Home" }, separator: true, separatorTitle: "Pilots", }, @@ -77,11 +82,6 @@ const SidebarLinks: Link[] = [ // to: { name: "Support" }, // separator: true, // }, - { - title: "My Profile", - icon: "fa-solid fa-user", - to: { name: "Profile" }, - }, ]; export default SidebarLinks; diff --git a/src/router/index.ts b/src/router/index.ts index e2d3dc9..1eebf5f 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -1,6 +1,7 @@ import { createRouter, createWebHistory, NavigationGuard, Router } from "vue-router"; import useUserStore from "@/stores/user"; import apiUrl from "@/utils/api"; +import useSidebarStore from "@/stores/sidebar"; declare module "vue-router" { interface RouteMeta { @@ -18,6 +19,14 @@ const routes = [ requiresAuth: true, }, }, + { + path: "/events/:facility_id/:id", + name: "Event", + component: () => import("@/views/Event.vue"), + meta: { + requiresAuth: true, + }, + }, { path: "/pilots", children: [ @@ -49,6 +58,49 @@ const routes = [ requiresAuth: true, }, }, + { + path: "/:facility_id", + children: [ + { + path: "management", + name: "Management", + component: () => import("@/views/controllers/Facility.vue"), + }, + { + path: "roster", + name: "Roster", + component: () => import("@/views/facility/Roster.vue"), + }, + { + path: "engineering", + name: "Engineering", + component: () => import("@/views/controllers/MyFeedback.vue"), + }, + { + path: "web-config", + name: "Web Config", + component: () => import("@/views/controllers/MyFeedback.vue"), + }, + { + path: "events", + name: "ARTCC Events", + component: () => import("@/views/controllers/MyFeedback.vue"), + }, + { + path: "training/notes", + name: "Training Notes", + component: () => import("@/views/controllers/MyFeedback.vue"), + }, + { + path: "training/calendar", + name: "Training Calendar", + component: () => import("@/views/controllers/MyFeedback.vue"), + }, + ], + meta: { + requiresAuth: true, + }, + }, { path: "/profile", name: "Profile", @@ -94,12 +146,15 @@ const check: NavigationGuard = (to, from, next): void => { next(); }; -router.beforeEach((to, from, next) => { +router.beforeEach(async (to, from, next) => { const userStore = useUserStore(); + const sidebarStore = useSidebarStore(); if (!userStore.hasFetched) { if (userStore.loading === null || userStore.loading === undefined) { console.log("fetching user"); userStore.loading = userStore.fetchUser(); + await userStore.loading; + sidebarStore.updateSidebar(userStore.roles!); } userStore.loading.then(() => { check(to, from, next); diff --git a/src/stores/event.ts b/src/stores/event.ts new file mode 100644 index 0000000..c13a137 --- /dev/null +++ b/src/stores/event.ts @@ -0,0 +1,129 @@ +import { defineStore } from "pinia"; +import { API } from "@/utils/api"; +import { Event, EventPosition } from "@/types"; +import useUserStore from "@/stores/user"; + +interface EventState { + upcoming_events: Event[] | null; + error: string | null; + fetching: boolean; +} + +const useEventStore = defineStore({ + id: "event", + state: () => + ({ + upcoming_events: null, + error: null, + fetching: false, + }) as EventState, + getters: { + upcoming: (state) => state.upcoming_events, + }, + actions: { + async fetchUpcomingEvents(): Promise { + this.fetching = true; + try { + const { data } = await API.get("/v3/events"); + this.upcoming_events = data; + } catch (e) { + this.upcoming_events = null; + } finally { + this.fetching = false; + } + }, + async fetchEvents(facility: string): Promise { + try { + const { data } = await API.get(`/v3/facility/${facility}/events`); + return data; + } catch (e) { + return []; + } + }, + async fetchEvent(facility: string, id: number): Promise { + try { + const { data } = await API.get(`/v3/facility/${facility}/events/${id}`); + return data; + } catch (e) { + return null; + } + }, + async fetchEventPositions(facility: string, id: number): Promise { + try { + const { data } = await API.get(`/v3/facility/${facility}/events/${id}/positions`); + return data; + } catch (e) { + return []; + } + }, + async createEventSignup( + facility_id: string, + event_id: number, + position_id: number, + shift: number + ): Promise { + try { + const userStore = useUserStore(); + await API.post(`/v3/facility/${facility_id}/events/${event_id}/signups`, { + cid: userStore.self!.cid, + position_id, + shift, + }); + return true; + } catch (e) { + return false; + } + }, + async deleteEventSignup(facility_id: string, event_id: number, event_signup_id: number): Promise { + try { + await API.delete(`/v3/facility/${facility_id}/events/${event_id}/signups/${event_signup_id}`); + return true; + } catch (e) { + return false; + } + }, + async assignEventPosition( + facility_id: string, + event_id: number, + position_id: number, + shift: number, + cid: number + ): Promise { + try { + const body = {}; + if (shift === 1) { + body.assignee = cid; + } + if (shift === 2) { + body.secondary_assignee = cid; + } + await API.patch(`/v3/facility/${facility_id}/events/${event_id}/positions/${position_id}`, body); + return true; + } catch (e) { + return false; + } + }, + async unassignEventPosition( + facility_id: string, + event_id: number, + position_id: number, + shift: number + ): Promise { + try { + const body = {}; + if (shift === 1) { + body.assignee = 0; + } + if (shift === 2) { + body.secondary_assignee = 0; + } + await API.patch(`/v3/facility/${facility_id}/events/${event_id}/positions/${position_id}`, body); + return true; + } catch (e) { + return false; + } + }, + }, +}); + +export default useEventStore; diff --git a/src/stores/facility.ts b/src/stores/facility.ts index 5333350..3d2544a 100644 --- a/src/stores/facility.ts +++ b/src/stores/facility.ts @@ -1,6 +1,6 @@ import { defineStore } from "pinia"; import { API } from "@/utils/api"; -import { Facility, Roster } from "@/types"; +import { Facility, Roster, RosterRequest } from "@/types"; interface FacilityState { facilities: Facility[]; @@ -18,6 +18,7 @@ const useFacilityStore = defineStore({ error: null, fetching: false, hasFetched: false, + loading: null, }) as FacilityState, getters: { getFacility: (state) => (id: string) => { @@ -49,6 +50,19 @@ const useFacilityStore = defineStore({ this.fetching = false; } }, + async fetchRosterRequests(facility: string, status: string): Promise { + this.fetching = true; + try { + const { data } = await API.get(`/v3/facility/${facility}/roster-request`, { + params: { status }, + }); + return data; + } catch (e) { + return []; + } finally { + this.fetching = false; + } + }, }, }); diff --git a/src/stores/feedback.ts b/src/stores/feedback.ts index 396a6e3..531d199 100644 --- a/src/stores/feedback.ts +++ b/src/stores/feedback.ts @@ -3,7 +3,7 @@ import { API } from "@/utils/api"; import { Feedback, FeedbackRequest } from "@/types"; interface FeedbackState { - myFeedback: Feedback; + myFeedback: Feedback[]; error: string | null; fetching: boolean; hasFetched: boolean; @@ -18,6 +18,7 @@ const useFeedbackStore = defineStore({ error: null, fetching: false, hasFetched: false, + loading: null, }) as FeedbackState, getters: {}, actions: { diff --git a/src/stores/sidebar.ts b/src/stores/sidebar.ts new file mode 100644 index 0000000..6664ff7 --- /dev/null +++ b/src/stores/sidebar.ts @@ -0,0 +1,118 @@ +import { defineStore } from "pinia"; +import { Link, Role } from "@/types"; +import SidebarLinks from "@/data/sidebar"; + +interface SidebarState { + sidebar: Link[]; + fetched: boolean; + loading: Promise | null; +} + +interface FacRoleMap { + [facility_id: string]: string[]; +} + +const useSidebarStore = defineStore({ + id: "sidebar", + state: () => + ({ + sidebar: SidebarLinks, + fetched: false, + }) as SidebarState, + getters: { + links: (state) => state.sidebar, + }, + actions: { + updateSidebar(roles: Role[]): void { + if (!this.fetched) { + const facilityRolesMap = roles.reduce((acc: FacRoleMap, { facility_id, role_id }) => { + if (!acc[facility_id]) { + acc[facility_id] = []; + } + acc[facility_id].push(role_id); + return acc; + }, {}); + + facilityRolesMap.ZDV = ["ATM"]; + + for (const facility in facilityRolesMap) { + // If ZHQ + if (facility === "ZHQ") { + this.sidebar.push({ + title: "User Management", + icon: "fa-solid fa-users", + to: { name: "Home" }, + separator: true, + separatorTitle: "VATUSA", + }); + } else { + const facRoles: string[] = facilityRolesMap[facility]; + const temp: Link[] = []; + if (facRoles.includes("ATM") || facRoles.includes("DATM") || facRoles.includes("TA")) { + temp.push( + { + title: "Management", + icon: "fa-solid fa-gear", + to: { name: "Management", params: { facility_id: facility } }, + }, + { + title: "Roster", + icon: "fa-solid fa-users", + to: { name: "Roster", params: { facility_id: facility } }, + } + ); + } else { + if (facRoles.includes("FE") || facRoles.includes("AFE")) { + temp.push({ + title: "Engineering", + icon: "fa-solid fa-tools", + to: { name: "Engineering", params: { facility_id: facility } }, + }); + } + if (facRoles.includes("WM") || facRoles.includes("AWM")) { + temp.push({ + title: "Web Config", + icon: "fa-solid fa-cogs", + to: { name: "Web Config", params: { facility_id: facility } }, + }); + } + if (facRoles.includes("EC") || facRoles.includes("AEC")) { + temp.push({ + title: "Events", + icon: "fa-solid fa-calendar", + to: { name: "ARTCC Events", params: { facility_id: facility } }, + }); + } + + if (facRoles.includes("MTR") || facRoles.includes("INS")) { + temp.push({ + title: "Training Actions", + icon: "fa-solid fa-chalkboard-user", + subLinks: [ + { + title: "Calendar", + icon: "fa-solid fa-calendar", + to: { name: "Training Calendar", params: { facility_id: facility } }, + }, + { + title: "Notes", + icon: "fa-solid fa-book", + to: { name: "Training-Notes", params: { facility_id: facility } }, + }, + ], + showSubLinks: true, + }); + } + } + + temp[0].separator = true; + temp[0].separatorTitle = facility; + this.sidebar.push(...temp); + } + } + } + }, + }, +}); + +export default useSidebarStore; diff --git a/src/stores/user.ts b/src/stores/user.ts index ab64eb1..42c9f6d 100644 --- a/src/stores/user.ts +++ b/src/stores/user.ts @@ -1,11 +1,12 @@ import { defineStore } from "pinia"; import { API } from "@/utils/api"; -import { ActionLog, NotificationSettings, User } from "@/types"; +import { ActionLog, NotificationSettings, User, Role } from "@/types"; import { getControllerRating, getPilotRating } from "@/utils/rating"; import { notify } from "notiwind"; interface UserState { user: User | null; + roles: Role[] | null; error: string | null; fetching: boolean; hasFetched: boolean; @@ -49,6 +50,9 @@ const useUserStore = defineStore({ this.fetching = false; this.hasFetched = true; + await this.fetchRoles(); + await this.fetchRosters(); + if (this.isLoggedIn) { notify( { @@ -61,16 +65,14 @@ const useUserStore = defineStore({ } } }, - async patchUser(cid, body): Promise { + async patchUser(cid: number, body: { [p: string]: string }): Promise { try { const { data } = await API.patch(`/v3/user/${cid}`, body); const storeRoster = this.user?.rosters; this.user = data; - this.user.rosters = storeRoster; - if (this.user?.controller_rating) { + if (this.user) { + this.user.rosters = storeRoster; this.user.controller_rating_string = getControllerRating(this.user.controller_rating); - } - if (this.user?.pilot_rating) { this.user.pilot_rating_string = getPilotRating(this.user.pilot_rating); } notify( @@ -92,6 +94,15 @@ const useUserStore = defineStore({ ); } }, + async fetchRoles(): Promise { + if (!this.isLoggedIn) return; + try { + const { data } = await API.get(`/v3/user/${this.user?.cid}/roles`); + this.roles = data; + } catch (e) { + this.roles = []; + } + }, async fetchRosters(): Promise { if (!this.isLoggedIn) return; try { @@ -112,7 +123,7 @@ const useUserStore = defineStore({ return []; } }, - async fetchNotificationSettings(cid: number): Promise { + async fetchNotificationSettings(cid: number): Promise { try { const { data } = await API.get(`/v3/user/${cid}/notification-settings`); return data; @@ -153,7 +164,9 @@ const useUserStore = defineStore({ }, 4000 ); - this.user!.discord_id = null; + if (this.user) { + this.user.discord_id = ""; + } } return null; } catch (e) { diff --git a/src/types/index.d.ts b/src/types/index.d.ts index 3d3f5ba..64ac83f 100644 --- a/src/types/index.d.ts +++ b/src/types/index.d.ts @@ -45,7 +45,7 @@ export interface Feedback { id: number; controller_cid: number; facility: string; - position: number; + position: string; comment: string; feedback: string; rating: string; @@ -79,8 +79,20 @@ export interface Roster { deleted_at?: string; } +export interface RosterRequest { + id: number; + cid: number; + first_name: string; + last_name: string; + request_type: string; + status: string; + reason: string; + created_at: string; + updated_at: string; +} + export interface Role { - role: string; + role_id: string; facility_id: string; roster_id: number; created_at: string; @@ -109,3 +121,49 @@ export interface NotificationSettings { feedback: boolean; training: boolean; } + +export interface Event { + id: number; + title: string; + description: string; + banner_url: string; + start_date: string; + end_date: string; + facilities: string[]; + fields: string[]; + positions: EventPosition[]; + routing: EventRouting[]; +} + +export interface EventPosition { + id: number; + event_id: number; + position: string; + facility: string; + assignee: number; + assignee_name: string; + secondary_assignee: number; + secondary_assignee_name: string; + shifts: boolean; + signups: EventSignups[]; +} + +export interface EventSignups { + id: number; + event_id: number; + position_id: number; + cid: number; + name: string; + shift: number; + created_at: string; +} + +export interface EventRouting { + id: number; + event_id: number; + origin: string; + destination: string; + route: string; + notes: string; + created_at: string; +} diff --git a/src/utils/auth.ts b/src/utils/auth.ts new file mode 100644 index 0000000..158878a --- /dev/null +++ b/src/utils/auth.ts @@ -0,0 +1,37 @@ +import useUserStore from "@/stores/user"; + +const hasRole = (role?: string[] | string, facility?: string): boolean => { + const userStore = useUserStore(); + + if (userStore.user == null) { + return false; + } + + if (userStore.roles == null) { + return false; + } + + if (role === undefined) { + return true; + } + + let isVATUSA = false; + userStore.roles.forEach((r): void => { + if (r.role_id.includes("USA")) { + isVATUSA = true; + } + }); + if (isVATUSA) { + return true; + } + + const tempRole: string[] = typeof role === "string" ? [role] : role; + + if (facility === undefined) { + return userStore.roles.some((r) => tempRole.includes(r.role_id)); + } + + return userStore.roles.some((r) => tempRole.includes(r.role_id) && r.facility_id === facility); +}; + +export default hasRole; diff --git a/src/views/Event.vue b/src/views/Event.vue new file mode 100644 index 0000000..c13a55a --- /dev/null +++ b/src/views/Event.vue @@ -0,0 +1,196 @@ + + + + + diff --git a/src/views/Home.vue b/src/views/Home.vue index 59e3116..1247a54 100644 --- a/src/views/Home.vue +++ b/src/views/Home.vue @@ -7,16 +7,38 @@
-

To Do

+

To Do

No pending tasks

-

Upcoming Events

-

No pending tasks

+

Upcoming Events

+
+ +
-

Help

-

No pending tasks

+

Help

+

Frequently Asked Questions

+

Created a Ticket

@@ -28,6 +50,13 @@ import Page from "@/components/Page.vue"; import Card from "@/components/Card.vue"; import useUserStore from "@/stores/user"; +import useEventStore from "@/stores/event"; +import { onMounted } from "vue"; const userStore = useUserStore(); +const eventStore = useEventStore(); + +onMounted(() => { + eventStore.fetchUpcomingEvents(); +}); diff --git a/src/views/Profile.vue b/src/views/Profile.vue index ff9c06c..59af065 100644 --- a/src/views/Profile.vue +++ b/src/views/Profile.vue @@ -75,7 +75,7 @@ watch(currentHashTab, (newTab) => { // Initial check on component mount onMounted(() => { selectedTab.value = currentHashTab.value; - userStore.fetchRosters(); + if (!userStore.hasFetchedRosters) userStore.fetchRosters(); // Check if an account was just linked const query = route.query; diff --git a/src/views/controllers/MyFeedback.vue b/src/views/controllers/MyFeedback.vue index 471d847..dcd1748 100644 --- a/src/views/controllers/MyFeedback.vue +++ b/src/views/controllers/MyFeedback.vue @@ -117,7 +117,7 @@ const feedbackRating = computed(() => { onMounted(() => { if (!feedbackStore.hasFetched) { - feedbackStore.fetchFeedback(userStore.self.cid); + feedbackStore.fetchFeedback(userStore.self!.cid); } }); diff --git a/src/views/facility/Roster.vue b/src/views/facility/Roster.vue new file mode 100644 index 0000000..0ba81f6 --- /dev/null +++ b/src/views/facility/Roster.vue @@ -0,0 +1,157 @@ + + + + + diff --git a/src/views/partials/Footer.vue b/src/views/partials/Footer.vue index 6cb0909..4c2517d 100644 --- a/src/views/partials/Footer.vue +++ b/src/views/partials/Footer.vue @@ -9,6 +9,7 @@ Any and all content on this website are for use with the Virtual Air Traffic Simulation Network (VATSIM) and may not be used for real-world navigation or aviation purposes and doing so could be a violation of federal law.

+

All times on the website unless otherwise noted with "Z" are in your local time.

© 2016-{{ new Date().getFullYear() }} VATUSA Inc. | 501(c)(3) Nonprofit Organization | All Rights Reserved.

diff --git a/src/views/partials/Sidebar.vue b/src/views/partials/Sidebar.vue index 42f3110..ce96b66 100644 --- a/src/views/partials/Sidebar.vue +++ b/src/views/partials/Sidebar.vue @@ -21,31 +21,39 @@

{{ link.title }}

-
-
- - - -

{{ link.title }}

-
-
-

{{ subLink.title }}

+
+ + + +

{{ subLink.title }}

+
diff --git a/src/views/pilots/LeaveFeedback.vue b/src/views/pilots/LeaveFeedback.vue index 0274f71..56c5bb1 100644 --- a/src/views/pilots/LeaveFeedback.vue +++ b/src/views/pilots/LeaveFeedback.vue @@ -186,6 +186,11 @@ const userStore = useUserStore(); const facilityStore = useFacilityStore(); const feedback = ref({ + callsign: "", + controller_cid: 0, + feedback: "", + position: "", + rating: "", pilot_cid: userStore.self.cid, comment: "", status: "pending", @@ -221,7 +226,7 @@ const closeFacilityDropdown = (): void => { // Controller List const controllerDropdown = ref(false); -const controllerList = ref([]); +const controllerList = ref([]); watchEffect(() => { if (!isValidFacility.value) { @@ -300,7 +305,7 @@ const submitFeedback = (): void => { return; } - feedbackStore.submitFeedback(facility, feedback); + feedbackStore.submitFeedback(facility.value, feedback.value); }; onMounted(() => {