Skip to content

Commit

Permalink
Another massive update
Browse files Browse the repository at this point in the history
  • Loading branch information
Raajheer1 committed Oct 5, 2024
1 parent 2649303 commit 241be0f
Show file tree
Hide file tree
Showing 7 changed files with 270 additions and 13 deletions.
18 changes: 15 additions & 3 deletions src/components/profile/Discord.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@
<div class="col-span-2 flex flex-col">
<p class="font-bold text-gray-600 text-sm">Actions</p>
<div class="flex gap-x-4 m-2">
<Secondary v-if="editableUser.discord_id === ''" text="Link" icon="link" color="green" />
<Secondary v-else text="Unlink" icon="unlink" color="red" />
<Secondary text="Sync" icon="sync" color="blue" />
<Secondary v-if="editableUser.discord_id.length === 0" text="Link" icon="link" color="green" @click="link" />
<Secondary v-else text="Unlink" icon="unlink" color="red" @click="unlink" />
<!-- <Secondary text="Sync" icon="sync" color="blue" />-->
</div>
</div>
</div>
Expand All @@ -28,15 +28,27 @@

<script setup lang="ts">
import { ref } from "vue";
import useUserStore from "@/stores/user";
import { User } from "@/types";
import Secondary from "@/components/buttons/Secondary.vue";
import apiUrl from "@/utils/api";
const userStore = useUserStore();
const props = defineProps<{
user: User | null;
}>();
const editableUser = ref<User | null>(props.user);
const link = (): null => {
window.location.href = `${apiUrl}/v3/user/discord?redirect=${window.location.href}`;
};
const unlink = (): null => {
userStore.unlinkDiscord();
editableUser.value = { ...editableUser.value, discord_id: "" };
};
</script>

<style scoped></style>
138 changes: 136 additions & 2 deletions src/components/profile/Notifications.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,141 @@
<template>
<p>Notifications Email Discord Etc</p>
<div v-if="!settings" class="flex">
<Spinner />
<p class="my-auto">Loading...</p>
</div>
<div v-else class="flex md:flex-row flex-col divide-x divide-usa-grey">
<div class="w-full md:w-1/2 p-4">
<h2 class="text-usa-gray text-2xl">Enabled Notification Platforms</h2>
<div class="flex flex-col divide-y divide-usa-grey">
<div class="space-y-4 p-4">
<div class="flex items center">
<i class="h-full w-12 my-auto fa-solid fa-envelope text-usa-grey"></i>
<div class="ml-4">
<h3 class="text-usa-gray text-lg font-semibold">
Email <span v-if="settings.email" class="text-green-400">(Enabled)</span>
</h3>
<p class="text-usa-gray">Email notifications are sent to your registered VATSIM email address.</p>
</div>
<div class="ml-4 my-auto py-2">
<Primary v-if="!settings.email" text="Enable" color="green" @click="setEmail(true)" />
<Primary v-else text="Disable" color="red" @click="setEmail(false)" />
</div>
</div>
<div class="flex items center">
<i class="h-full w-12 my-auto fa-brands fa-discord text-[#5865F2]"></i>
<div class="ml-4">
<h3 class="text-usa-gray text-lg font-semibold">
Discord <span v-if="settings.discord" class="text-green-400">(Enabled)</span>
</h3>
<p class="text-usa-gray">
Discord Notifications are sent to your registered Discord account via direct message.
</p>
</div>
<div class="ml-4 my-auto py-2">
<Primary v-if="!settings.discord" text="Enable" color="green" @click="setDiscord(true)" />
<Primary v-else text="Disable" color="red" @click="setDiscord(false)" />
</div>
</div>
</div>
</div>
</div>
<div class="w-full md:w-1/2 p-4">
<h2 class="text-usa-gray text-2xl">Notification Types</h2>
<div class="flex flex-col divide-y divide-usa-grey">
<div class="space-y-4 p-4">
<div class="flex items center">
<i class="h-full w-12 my-auto fa-solid fa-chalkboard-user text-usa-grey"></i>
<div class="ml-4">
<h3 class="text-usa-gray text-lg font-semibold">
Training <span v-if="settings.training" class="text-green-400">(Enabled)</span>
</h3>
<p class="text-usa-gray">
Training notifications are sent when a training session is scheduled or updated, or a training notes has
been entered.
</p>
</div>
<div class="ml-4 my-auto py-2">
<Primary v-if="!settings.training" text="Enable" color="green" @click="setTraining(true)" />
<Primary v-else text="Disable" color="red" @click="setTraining(false)" />
</div>
</div>
<div class="flex items center">
<i class="h-full w-12 my-auto fa-solid fa-calendar-days"></i>
<div class="ml-4">
<h3 class="text-usa-gray text-lg font-semibold">
Events <span v-if="settings.events" class="text-green-400">(Enabled)</span>
</h3>
<p class="text-usa-gray">Event Notifications keep you up to date with the latest events in VATUSA.</p>
</div>
<div class="ml-4 my-auto py-2">
<Primary v-if="!settings.events" text="Enable" color="green" @click="setEvents(true)" />
<Primary v-else text="Disable" color="red" @click="setEvents(false)" />
</div>
</div>
<div class="flex items center">
<i class="h-full w-12 my-auto fa-solid fa-comment"></i>
<div class="ml-4">
<h3 class="text-usa-gray text-lg font-semibold">
Feedback <span v-if="settings.feedback" class="text-green-400">(Enabled)</span>
</h3>
<p class="text-usa-gray">
Feedback notifications will alert you when a new feedback item is submitted to you.
</p>
</div>
<div class="ml-4 my-auto py-2">
<Primary v-if="!settings.feedback" text="Enable" color="green" @click="setFeedback(true)" />
<Primary v-else text="Disable" color="red" @click="setFeedback(false)" />
</div>
</div>
</div>
</div>
</div>
</div>
</template>

<script setup lang="ts"></script>
<script setup lang="ts">
import { onMounted, ref } from "vue";
import { NotificationSettings } from "@/types";
import useUserStore from "@/stores/user";
import Primary from "@/components/buttons/Primary.vue";
import Spinner from "@/components/animations/Spinner.vue";
const userStore = useUserStore();
const settings = ref<NotificationSettings | null>();
onMounted(async () => {
settings.value = await userStore.fetchNotificationSettings(userStore.self.cid);
});
function updateSettings(): null {
userStore.updateNotificationSettings(userStore.self.cid, settings.value);
}
function setDiscord(state: boolean): void {
settings.value.discord = state;
updateSettings();
}
function setTraining(state: boolean): void {
settings.value.training = state;
updateSettings();
}
function setEvents(state: boolean): void {
settings.value.events = state;
updateSettings();
}
function setFeedback(state: boolean): void {
settings.value.feedback = state;
updateSettings();
}
function setEmail(state: boolean): void {
settings.value.email = state;
updateSettings();
}
</script>

<style scoped></style>
59 changes: 58 additions & 1 deletion src/stores/user.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { defineStore } from "pinia";
import { API } from "@/utils/api";
import { ActionLog, User } from "@/types";
import { ActionLog, NotificationSettings, User } from "@/types";
import { getControllerRating, getPilotRating } from "@/utils/rating";
import { notify } from "notiwind";

Expand Down Expand Up @@ -112,6 +112,63 @@ const useUserStore = defineStore({
return [];
}
},
async fetchNotificationSettings(cid: number): Promise<NotificationSettings> {
try {
const { data } = await API.get(`/v3/user/${cid}/notification-settings`);
return data;
} catch (e) {
console.error(e);

Check warning on line 120 in src/stores/user.ts

View workflow job for this annotation

GitHub Actions / eslint (20.x)

Unexpected console statement
return null;
}
},
async updateNotificationSettings(cid: number, updatedSettings: NotificationSettings): Promise<null> {
try {
const data = await API.put(`/v3/user/${cid}/notification-settings`, updatedSettings);
if (data.status === 200) {
return null;
}
notify(
{
group: "br-error",
title: "Operation Failed",
text: "An error occurred while trying to update the notification settings.",
},
4000
);
return null;
} catch (e) {
console.error(e);

Check warning on line 140 in src/stores/user.ts

View workflow job for this annotation

GitHub Actions / eslint (20.x)

Unexpected console statement
return null;
}
},
async unlinkDiscord(): Promise<null> {
try {
const data = await API.get(`/v3/user/discord/unlink`);
if (data.status === 200) {
notify(
{
group: "br-success",
title: "Discord Unlinked",
text: "Your Discord account has been unlinked successfully.",
},
4000
);
this.user!.discord_id = null;
}
return null;
} catch (e) {
notify(
{
group: "br-error",
title: "Operation Failed",
text: "An error occurred while trying to unlink your Discord account.",
},
4000
);
console.error(e);

Check warning on line 168 in src/stores/user.ts

View workflow job for this annotation

GitHub Actions / eslint (20.x)

Unexpected console statement
return null;
}
},
async logout(): Promise<void> {
this.fetching = true;
try {
Expand Down
10 changes: 9 additions & 1 deletion src/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export interface FeedbackRequest {
callsign: string;
controller_cid: number;
pilot_cid: number;
position: number;
position: string;
comment: string;
feedback: string;
rating: string;
Expand Down Expand Up @@ -101,3 +101,11 @@ export interface ActionLog {
updated_at: string;
updated_by: string;
}

export interface NotificationSettings {
discord: boolean;
email: boolean;
events: boolean;
feedback: boolean;
training: boolean;
}
18 changes: 16 additions & 2 deletions src/views/Profile.vue
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import Notifications from "@/components/profile/Notifications.vue";
import Page from "@/components/Page.vue";
import Profile from "@/components/profile/Profile.vue";
import ActionLog from "@/components/profile/ActionLog.vue";
import { notify } from "notiwind";
const userStore = useUserStore();
Expand All @@ -60,9 +61,9 @@ const changeTab = (tab: number): void => {
const route = useRoute();
const currentHashTab = computed(() => {
const hash = route.hash.slice(1); // Remove leading "#"
const hash = route.hash.slice(1).split("?"); // Remove leading "#"
const val = tabs.value.findIndex((tab) => tab.toLowerCase() === hash);
const val = tabs.value.findIndex((tab) => tab.toLowerCase() === hash[0]);
return val === -1 ? 0 : val;
});
Expand All @@ -75,6 +76,19 @@ watch(currentHashTab, (newTab) => {
onMounted(() => {
selectedTab.value = currentHashTab.value;
userStore.fetchRosters();
// Check if an account was just linked
const query = route.query;
if (query.name !== undefined) {
notify(
{
group: "br-success",
title: "Discord Linked",
text: `You have successfully linked your Discord account: ${query.name}!`,
},
4000
);
}
});
</script>

Expand Down
3 changes: 2 additions & 1 deletion src/views/controllers/MyFeedback.vue
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
</tr>
</tbody>
</table>
<h3 v-if="filteredFeedback.length === 0" class="text-center text-xl font-semibold m-5">No Feedback Found</h3>
</div>
</div>
</Card>
Expand All @@ -65,7 +66,7 @@
<script setup lang="ts">
import { onMounted, ref, computed } from "vue";
import useFeedbackStore from "@/stores/feedback";
import useUserStore from "@/stores/user.ts";
import useUserStore from "@/stores/user";
// Components
import Page from "@/components/Page.vue";
Expand Down
Loading

0 comments on commit 241be0f

Please sign in to comment.