Skip to content

Commit

Permalink
Fixes and extensions (#357)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>

* lint

---------

Signed-off-by: Daniel Hawton <[email protected]>
  • Loading branch information
dhawton authored Dec 9, 2023
1 parent 8460d51 commit ef9c6e7
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 19 deletions.
7 changes: 7 additions & 0 deletions src/utils/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
};
101 changes: 84 additions & 17 deletions src/views/pages/ActivityPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@
<div v-if="loading < 3" class="flex mt-4">Loading... {{ loading }} month(s) loaded.</div>
<div v-else class="flex mt-4">
<table class="w-full">
<thead class="border-b-2 dark:border-gray-800">
<thead class="border-b-2 dark:border-neutral-800">
<tr>
<th class="text-left">Name<br />CID (Rating)</th>
<th>{{ months[4] }}</th>
<th>{{ months[3] }}</th>
<th>{{ months[2] }}</th>
<th>{{ months[1] }}</th>
<th>{{ months[0] }}</th>
<th class="text-left border-r-2 dark:border-neutral-800">Name<br />CID (Rating)</th>
<th class="border-r-1 dark:border-neutral-800">{{ months[4] }}</th>
<th class="border-r-1 dark:border-neutral-800">{{ months[3] }}</th>
<th class="border-r-1 dark:border-neutral-800">{{ months[2] }}</th>
<th class="border-r-1 dark:border-neutral-800">{{ months[1] }}</th>
<th class="border-r-1 dark:border-neutral-800">{{ months[0] }}</th>
<th class="border-l-2 dark:border-neutral-800">Controller Total</th>
</tr>
</thead>
<tbody>
Expand All @@ -22,25 +23,54 @@
class="hover:dark:bg-zinc-800 hover:bg-zinc-300 hover:cursor-pointer"
@click="goToUser(c.cid)"
>
<td class="py-2 border-b-1 dark:border-gray-900">
<td class="py-2 border-b-1 dark:border-neutral-800 border-r-2 dark:border-neutral-800">
{{ c.first_name }} {{ c.last_name }} ({{ c.operating_initials || "none" }})<br />
{{ c.cid }} ({{ c.rating }})
</td>
<td class="text-center py-2 border-b-1 dark:border-gray-900">
<td class="text-center py-2 border-b-1 border-r-1 dark:border-neutral-800">
{{ getHours(minus4.find((c2) => c2.cid === c.cid)) }}
<i :class="getCrown(c, minus4)" />
</td>
<td class="text-center py-2 border-b-1 dark:border-gray-900">
<td class="text-center py-2 border-b-1 border-r-1 dark:border-neutral-800">
{{ getHours(minus3.find((c2) => c2.cid === c.cid)) }}
<i :class="getCrown(c, minus3)" />
</td>
<td class="text-center py-2 border-b-1 dark:border-gray-900">
<td class="text-center py-2 border-b-1 border-r-1 dark:border-neutral-800">
{{ getHours(minus2.find((c2) => c2.cid === c.cid)) }}
<i :class="getCrown(c, minus2)" />
</td>
<td class="text-center py-2 border-b-1 dark:border-gray-900">
<td class="text-center py-2 border-b-1 border-r-1 dark:border-neutral-800">
{{ getHours(minus1.find((c1) => c1.cid === c.cid)) }}
<i :class="getCrown(c, minus1)" />
</td>
<td class="text-center py-2 border-b-1 dark:border-neutral-800">
{{ getHours(c) }}
<i :class="getCrown(c, curMonth)" />
</td>
<td class="text-center py-2 border-b-1 dark:border-neutral-800 border-l-2">
{{
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,
])
}}
</td>
<td class="text-center py-2 border-b-1 dark:border-gray-900">{{ getHours(c) }}</td>
</tr>
</tbody>
<tfoot>
<tr>
<th class="text-left py-2 border-r-2 border-t-2 dark:border-neutral-800">Total Hours</th>
<th class="py-2 border-r-1 border-t-2 dark:border-neutral-800">{{ getSum(minus4) }}</th>
<th class="py-2 border-r-1 border-t-2 dark:border-neutral-800">{{ getSum(minus3) }}</th>
<th class="py-2 border-r-1 border-t-2 dark:border-neutral-800">{{ getSum(minus2) }}</th>
<th class="py-2 border-r-1 border-t-2 dark:border-neutral-800">{{ getSum(minus1) }}</th>
<th class="py-2 border-r-1 border-t-2 dark:border-neutral-800">{{ getSum(curMonth) }}</th>
<th class="border-l-2 border-t-2 dark:border-neutral-800 py-2"></th>
</tr>
</tfoot>
</table>
</div>
</template>
Expand Down Expand Up @@ -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) {

Check failure on line 150 in src/views/pages/ActivityPage.vue

View workflow job for this annotation

GitHub Actions / eslint (18.x)

Unnecessary 'else' after 'return'

Check failure on line 150 in src/views/pages/ActivityPage.vue

View workflow job for this annotation

GitHub Actions / eslint (20.x)

Unnecessary 'else' after 'return'
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 => {
Expand Down
11 changes: 10 additions & 1 deletion src/views/pages/VisitingApplication.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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.
</p>
<div v-if="!applying && !error">
<div v-if="!applying && !error && !isRatingBelow(fac.minVisitorRating, userStore.user?.rating)">
<button class="btn" :class="primaryHover" type="button" @click="apply">
<i class="fa fa-paper-plane" /> Apply
</button>
</div>
<div v-else-if="isRatingBelow(fac.minVisitorRating, userStore.user?.rating)">
<p>
You do not meet the minimum rating requirement of {{ fac.minVisitorRating }} to apply for visiting status.
</p>
</div>
<div v-else-if="applying && !error">
<p>Submitting application...</p>
</div>
Expand All @@ -44,6 +49,9 @@
<li>You already have an outstanding visiting application.</li>
<li>You do not meet the eligibility requirements as listed above.</li>
<li>You are already a member of this facility.</li>
<li>
You are apart of VATUSA and assigned to the ZAE subdivision. You <b>must</b> have a home subdivision first.
</li>
</ul>
<p>The error we got from the backend was: {{ error }}</p>
<p>If you believe this is an error, please contact the facility staff for guidance.</p>
Expand Down Expand Up @@ -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";
Expand Down
2 changes: 1 addition & 1 deletion src/views/partials/events/Positions.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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 [];
});
Expand Down
4 changes: 4 additions & 0 deletions src/views/partials/roster/ControllerActions.vue
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,10 @@ const focusRemoval = (): void => {
const addVisitor = async (): Promise<void> => {
// 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;
}
Expand Down

0 comments on commit ef9c6e7

Please sign in to comment.