Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions frontend/src/components/Navbar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,13 @@ import type { Speaker } from "@/dto/speakers";
import type { Member } from "@/dto/members";
import { useMagicKeys } from "@vueuse/core";
import Notification from "./navbar/Notification.vue";
import { usePermissions } from "@/composables/usePermissions";

const isOpen = ref(false);
const authStore = useAuthStore();
const { isCoordinatorOrAdmin } = usePermissions();

const showCoordination = computed(() => {
const role = authStore.decoded?.role as string | undefined;
return role === "COORDINATOR" || role === "ADMIN";
});
const showCoordination = computed(() => isCoordinatorOrAdmin.value === true);
const router = useRouter();

const logout = () => {
Expand Down
8 changes: 3 additions & 5 deletions frontend/src/components/cards/CompanyCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ import { useCompanyInfoMutation } from "@/mutations/companies";
import { useCompanyImageUploadMutation } from "@/mutations/companies";
import { usePackageQuery } from "@/mutations/packages";
import { deleteCompany } from "@/api/companies";
import { useAuthStore } from "@/stores/auth";
import { usePermissions } from "@/composables/usePermissions";
import { useQueryCache } from "@pinia/colada";
import { useRouter } from "vue-router";
import Card from "../ui/card/Card.vue";
Expand Down Expand Up @@ -184,7 +184,7 @@ const isDescriptionExpanded = ref(false);
const isEditing = ref(false);
const isDeleteConfirmOpen = ref(false);
const isDeleting = ref(false);
const authStore = useAuthStore();
const { isCoordinatorOrAdmin } = usePermissions();
const queryCache = useQueryCache();
const router = useRouter();

Expand Down Expand Up @@ -287,9 +287,7 @@ const formatLinkedIn = (url: string): string => {
};

const canDelete = computed(() => {
if (!authStore.decoded) return false;
const role = (authStore.decoded as { role?: string }).role;
return role === "COORDINATOR" || role === "ADMIN";
return isCoordinatorOrAdmin.value === true;
});

const handleDelete = async () => {
Expand Down
8 changes: 3 additions & 5 deletions frontend/src/components/cards/SpeakerCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,6 @@ import type {
import { useSpeakerInfoMutation } from "@/mutations/speakers";
import { useSpeakerImageUploadMutation } from "@/mutations/speakers";
import { deleteSpeaker } from "@/api/speakers";
import { useAuthStore } from "@/stores/auth";
import { useQueryCache } from "@pinia/colada";
import { useRouter } from "vue-router";
import Card from "../ui/card/Card.vue";
Expand All @@ -148,6 +147,7 @@ import SpeakerInfoForm from "../speakers/SpeakerInfoForm.vue";
import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover";
import { TrashIcon } from "lucide-vue-next";
import ConfirmDelete from "@/components/ConfirmDelete.vue";
import { usePermissions } from "@/composables/usePermissions";
import ParticipationStatusBadge from "@/components/ParticipationStatusBadge.vue";

const props = defineProps<{
Expand All @@ -163,7 +163,7 @@ const isBioExpanded = ref(false);
const isEditing = ref(false);
const isDeleteConfirmOpen = ref(false);
const isDeleting = ref(false);
const authStore = useAuthStore();
const { isCoordinatorOrAdmin } = usePermissions();
const queryCache = useQueryCache();
const router = useRouter();

Expand Down Expand Up @@ -250,9 +250,7 @@ const toggleBio = () => {
};

const canDelete = computed(() => {
if (!authStore.decoded) return false;
const role = (authStore.decoded as { role?: string }).role;
return role === "COORDINATOR" || role === "ADMIN";
return isCoordinatorOrAdmin.value === true;
});

const handleDelete = async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@
id="confirmed-date"
v-model="editForm.confirmed"
type="datetime-local"
class="w-full px-3 py-2 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
class="w-full px-3 py-2 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:opacity-50 disabled:bg-gray-100 disabled:cursor-not-allowed"
:disabled="!canEditConfirmedDate"
/>
</div>

Expand Down Expand Up @@ -170,7 +171,7 @@
</template>

<script setup lang="ts">
import { ref, reactive, watch } from "vue";
import { ref, reactive, watch, computed } from "vue";
import useToast from "@/lib/toast";
import { useQuery } from "@pinia/colada";
import { getAllEvents } from "@/api/events";
Expand All @@ -183,6 +184,7 @@ import { Label } from "@/components/ui/label";
import MemberSelect from "@/components/members/MemberSelect.vue";
import { useCompanyParticipationPackageMutation } from "@/mutations/companies";
import { usePackagesQuery, usePackageQuery } from "@/mutations/packages";
import { usePermissions } from "@/composables/usePermissions";
import type { Package } from "@/dto/packages";
import type {
CompanyParticipation,
Expand All @@ -205,6 +207,11 @@ interface Props {

const props = defineProps<Props>();

const { isCoordinatorOrAdmin } = usePermissions();
const canEditConfirmedDate = computed(() => {
return isCoordinatorOrAdmin.value === true;
});

const isEditing = ref(false);
const isSaving = ref(false);

Expand Down
35 changes: 35 additions & 0 deletions frontend/src/composables/usePermissions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { computed } from "vue";
import { useAuthStore } from "@/stores/auth";

export function usePermissions() {
const authStore = useAuthStore();

/**
* The user's role, or undefined if not authenticated.
*/
const role = computed<string | undefined>(() => authStore.decoded?.role);

const isAdmin = computed(() => role.value === "ADMIN");
const isCoordinator = computed(() => role.value === "COORDINATOR");
const isTeamLeader = computed(() => role.value === "TEAMLEADER");
const isMember = computed(() => role.value === "MEMBER");

// Composite permissions
const isCoordinatorOrAdmin = computed(
() => isCoordinator.value || isAdmin.value,
);

const isTeamLeaderOrHigher = computed(
() => isTeamLeader.value || isCoordinatorOrAdmin.value,
);

return {
role,
isAdmin,
isCoordinator,
isTeamLeader,
isMember,
isCoordinatorOrAdmin,
isTeamLeaderOrHigher,
};
}
Loading