From ef9c6e7827e31f5bbc016e60a5d54e0d47b67954 Mon Sep 17 00:00:00 2001 From: Daniel Hawton Date: Fri, 8 Dec 2023 23:50:27 -0700 Subject: [PATCH] Fixes and extensions (#357) * Fixes and extensions - Activity Page slight refresh to design - Add total hours for both controllers and monthly - Add historical trophies to the activity page - Add rating check to the visiting application page so the button isn't visible if the rating is too low - Added _FSS suffix to the enroute positions on events page (affects anyone with Oceanic) Signed-off-by: Daniel Hawton * lint --------- Signed-off-by: Daniel Hawton --- src/utils/helpers.ts | 7 ++ src/views/pages/ActivityPage.vue | 101 +++++++++++++++--- src/views/pages/VisitingApplication.vue | 11 +- src/views/partials/events/Positions.vue | 2 +- .../partials/roster/ControllerActions.vue | 4 + 5 files changed, 106 insertions(+), 19 deletions(-) diff --git a/src/utils/helpers.ts b/src/utils/helpers.ts index d5df44e..3cbc8be 100644 --- a/src/utils/helpers.ts +++ b/src/utils/helpers.ts @@ -78,3 +78,10 @@ export const toTitleCase = (str: string): string => { }); return r; }; + +export const isRatingBelow = (rating: string, ratingToCompare: string): boolean => { + const ratings = ["SUS", "OBS", "S1", "S2", "S3", "C1", "C3", "I1", "I3", "SUP", "ADM"]; + ratings[-1] = "INA"; + + return ratings.indexOf(rating) < ratings.indexOf(ratingToCompare); +}; diff --git a/src/views/pages/ActivityPage.vue b/src/views/pages/ActivityPage.vue index c623960..d03e11e 100644 --- a/src/views/pages/ActivityPage.vue +++ b/src/views/pages/ActivityPage.vue @@ -5,14 +5,15 @@
Loading... {{ loading }} month(s) loaded.
- + - - - - - - + + + + + + + @@ -22,25 +23,54 @@ class="hover:dark:bg-zinc-800 hover:bg-zinc-300 hover:cursor-pointer" @click="goToUser(c.cid)" > - - - - - + + - + + + + + + + + + + +
Name
CID (Rating)
{{ months[4] }}{{ months[3] }}{{ months[2] }}{{ months[1] }}{{ months[0] }}Name
CID (Rating)
{{ months[4] }}{{ months[3] }}{{ months[2] }}{{ months[1] }}{{ months[0] }}Controller Total
+ {{ c.first_name }} {{ c.last_name }} ({{ c.operating_initials || "none" }})
{{ c.cid }} ({{ c.rating }})
+ {{ getHours(minus4.find((c2) => c2.cid === c.cid)) }} + + {{ getHours(minus3.find((c2) => c2.cid === c.cid)) }} + + {{ getHours(minus2.find((c2) => c2.cid === c.cid)) }} + + {{ getHours(minus1.find((c1) => c1.cid === c.cid)) }} + + + {{ getHours(c) }} + + + {{ + getSum([ + minus4.find((c2) => c2.cid === c.cid), + minus3.find((c2) => c2.cid === c.cid), + minus2.find((c2) => c2.cid === c.cid), + minus1.find((c2) => c2.cid === c.cid), + c, + ]) + }} {{ getHours(c) }}
Total Hours{{ getSum(minus4) }}{{ getSum(minus3) }}{{ getSum(minus2) }}{{ getSum(minus1) }}{{ getSum(curMonth) }}
@@ -77,16 +107,53 @@ const monthNames = [ "December", ]; +const formatSecs = (seconds: number): string => { + const hours = Math.floor(seconds / 3600); + const minutes = Math.floor((seconds % 3600) / 60); + + if (hours === 0 && minutes === 0) return ""; + + return `${String(hours).padStart(1, "0")}:${String(minutes).padStart(2, "0")}`; +}; + const getHours = (controller: ControllerStats | undefined): string => { if (!controller) return ""; const secs = controller.cab + controller.terminal + controller.enroute; - const hours = Math.floor(secs / 3600); - const minutes = Math.floor((secs % 3600) / 60); - if (hours === 0 && minutes === 0) return ""; + return formatSecs(secs); +}; + +const getSum = (stats: (ControllerStats | undefined)[]): string => { + if (!stats) return ""; + + let sum = 0; + stats.forEach((c) => { + if (!c) return; + sum += c.cab + c.terminal + c.enroute; + }); + return formatSecs(sum); +}; + +const getCrown = (controller: ControllerStats | undefined, stats: ControllerStats[]): string => { + if (!controller || !stats) return "hidden"; + + // Copy stats into new array + const sorted: ControllerStats[] = stats.slice().sort((a: ControllerStats, b: ControllerStats) => { + return b.cab + b.terminal + b.enroute - (a.cab + a.terminal + a.enroute); + }); + + if (sorted.length === 0) return "hidden"; + + if (sorted[0].cid === controller.cid) { + return "fa-solid fa-trophy text-alaska-gold"; + } else if (sorted[1].cid === controller.cid) { + return "fa-solid fa-trophy text-zinc-500"; + } else if (sorted[2].cid === controller.cid) { + return "fa-solid fa-trophy text-amber-700"; + } - return `${String(hours).padStart(2, "0")}h ${String(minutes).padStart(2, "0")}m`; + return "hidden"; }; const goToUser = (cid: string | number): void => { diff --git a/src/views/pages/VisitingApplication.vue b/src/views/pages/VisitingApplication.vue index 9ff1a46..368686f 100644 --- a/src/views/pages/VisitingApplication.vue +++ b/src/views/pages/VisitingApplication.vue @@ -30,11 +30,16 @@ you will receive an email with the outcome of your application after it has been reviewed. Please allow up to 7 days to review your application before contacting staff.

-
+
+
+

+ You do not meet the minimum rating requirement of {{ fac.minVisitorRating }} to apply for visiting status. +

+

Submitting application...

@@ -44,6 +49,9 @@
  • You already have an outstanding visiting application.
  • You do not meet the eligibility requirements as listed above.
  • You are already a member of this facility.
  • +
  • + You are apart of VATUSA and assigned to the ZAE subdivision. You must have a home subdivision first. +
  • The error we got from the backend was: {{ error }}

    If you believe this is an error, please contact the facility staff for guidance.

    @@ -108,6 +116,7 @@ import { onMounted, Ref, ref } from "vue"; import Alert from "@/components/Alert.vue"; import { AxiosResponse } from "axios"; import fac from "@/facility"; +import { isRatingBelow } from "@/utils/helpers"; import { primaryHover } from "@/utils/colors"; import Spinner from "@/components/Spinner.vue"; import useUserStore from "@/stores/users"; diff --git a/src/views/partials/events/Positions.vue b/src/views/partials/events/Positions.vue index a065882..ee8088a 100644 --- a/src/views/partials/events/Positions.vue +++ b/src/views/partials/events/Positions.vue @@ -355,7 +355,7 @@ const toggleAssignDropdown = (id: number): void => { const enroutePositions = computed(() => { if (props.positions) { - return props.positions.filter((pos) => pos.position.includes("_CTR")); + return props.positions.filter((pos) => pos.position.includes("_CTR") || pos.position.includes("_FSS")); } return []; }); diff --git a/src/views/partials/roster/ControllerActions.vue b/src/views/partials/roster/ControllerActions.vue index ff5bd5a..a56d241 100644 --- a/src/views/partials/roster/ControllerActions.vue +++ b/src/views/partials/roster/ControllerActions.vue @@ -225,6 +225,10 @@ const focusRemoval = (): void => { const addVisitor = async (): Promise => { // This shouldn't be possible, in theory... if (props.controller.controller_type !== "none") { + // eslint-disable-next-line no-console + console.log("Controller is not controller_type=none."); + // eslint-disable-next-line no-console + console.log(props.controller); return; }