From a842c24d0de158818f0ce47c053b740b73160e4c Mon Sep 17 00:00:00 2001 From: Mattrixwv Date: Sat, 15 Mar 2025 16:51:13 -0400 Subject: [PATCH] Buttons hidden by permissions --- src/components/nav/ProtectedNavLinks.tsx | 47 ++++++++------ src/index.css | 4 ++ src/interface/Account.ts | 5 ++ src/interface/AccountPermission.ts | 8 +++ src/pages/protected/GamesPage.tsx | 2 +- src/pages/protected/RaidGroupPage.tsx | 25 ++++--- src/providers/AuthProvider.tsx | 8 ++- src/ui/account/AccountAdminButtons.tsx | 59 +++++++++++++++++ src/ui/account/AccountsList.tsx | 65 ++++++++++--------- .../account/RaidGroupAccountAdminButtons.tsx | 26 ++++++++ src/ui/account/RaidGroupAccountsTab.tsx | 2 +- src/ui/account/modals/AccountModal.tsx | 13 ++-- src/ui/calendar/CalendarDisplay.tsx | 18 +++++ src/ui/calendar/RaidGroupHeader.tsx | 9 ++- src/ui/calendar/modals/CalendarEventModal.tsx | 1 + src/ui/classGroup/ClassGroupButtons.tsx | 29 +++++++++ src/ui/classGroup/ClassGroupList.tsx | 7 +- src/ui/classGroup/ClassGroupsTab.tsx | 4 ++ src/ui/game/AllGamesDisplay.tsx | 4 ++ src/ui/game/GameAdminButtons.tsx | 29 +++++++++ src/ui/game/GameHeader.tsx | 7 +- src/ui/game/GamesList.tsx | 9 ++- src/ui/game/GamesListSkeleton.tsx | 3 +- src/ui/gameClass/GameClassAdminButtons.tsx | 29 +++++++++ src/ui/gameClass/GameClassCreateAndSearch.tsx | 4 ++ src/ui/gameClass/GameClassList.tsx | 9 ++- src/ui/gameClass/GameClassListSkeleton.tsx | 2 + src/ui/person/PersonAdminButtons.tsx | 39 +++++++++++ src/ui/person/PersonList.tsx | 7 +- src/ui/person/PersonTab.tsx | 4 ++ src/ui/raidGroup/RaidGroupAdminButtons.tsx | 39 +++++++++++ src/ui/raidGroup/RaidGroupsList.tsx | 12 ++-- src/ui/raidGroup/RaidGroupsListSkeleton.tsx | 8 ++- src/ui/raidGroup/modals/RaidGroupModal.tsx | 12 ++-- .../RaidGroupRequestButtons.tsx | 29 +++++++++ .../raidGroupRequest/RaidGroupRequestList.tsx | 11 +++- .../raidGroupRequest/RaidGroupRequestTab.tsx | 2 +- .../raidInstance/RaidInstanceAdminButtons.tsx | 29 +++++++++ src/ui/raidInstance/RaidInstanceList.tsx | 7 +- src/ui/raidInstance/RaidInstanceTab.tsx | 4 ++ src/ui/raidLayout/RaidLayoutAdminButtons.tsx | 30 +++++++++ src/ui/raidLayout/RaidLayoutList.tsx | 7 +- src/ui/raidLayout/RaidLayoutTab.tsx | 4 ++ src/util/PermissionUtil.ts | 46 ++++++++++++- 44 files changed, 624 insertions(+), 94 deletions(-) create mode 100644 src/interface/AccountPermission.ts diff --git a/src/components/nav/ProtectedNavLinks.tsx b/src/components/nav/ProtectedNavLinks.tsx index a1fcdb3..f7228db 100644 --- a/src/components/nav/ProtectedNavLinks.tsx +++ b/src/components/nav/ProtectedNavLinks.tsx @@ -1,29 +1,10 @@ import { useAuth } from "@/providers/AuthProvider"; +import { isSiteAdmin } from "@/util/PermissionUtil"; import { NavLink } from "react-router"; -const protectedLinks = [ - { - name: "Games", - path: "/game" - }, - { - name: "Groups", - path: "/raidGroup" - }, - { - name: "Admin", - path: "/admin" - }, - { - name: "Logout", - path: "/logout" - } -]; - - export default function ProtectedNavLinks(){ - const { jwt } = useAuth(); + const { jwt, accountPermissions } = useAuth(); if(!jwt){ @@ -31,6 +12,30 @@ export default function ProtectedNavLinks(){ } + const protectedLinks = [ + { + name: "Game", + path: "/game" + }, + { + name: "Raid Group", + path: "/raidGroup" + } + ]; + if(isSiteAdmin(accountPermissions)){ + protectedLinks.push({ + name: "Admin", + path: "/admin" + }); + } + protectedLinks.push({ + name: "Logout", + path: "/logout" + }); + + console.log("is admin = " + isSiteAdmin(accountPermissions)); + + return ( <> { diff --git a/src/index.css b/src/index.css index 9e4d088..16a30f8 100644 --- a/src/index.css +++ b/src/index.css @@ -30,6 +30,10 @@ color: var(--text-color); } +#root { + width: 100%; +} + a:hover{ color: var(--color-blue-300); } diff --git a/src/interface/Account.ts b/src/interface/Account.ts index d081a4b..640a752 100644 --- a/src/interface/Account.ts +++ b/src/interface/Account.ts @@ -6,6 +6,11 @@ export enum AccountStatus { UNCONFIRMED = "UNCONFIRMED" }; +export enum AccountPermissionType { + ADMIN = "ADMIN", + USER = "USER" +} + export interface Account { accountId: string; diff --git a/src/interface/AccountPermission.ts b/src/interface/AccountPermission.ts new file mode 100644 index 0000000..123cd0d --- /dev/null +++ b/src/interface/AccountPermission.ts @@ -0,0 +1,8 @@ +import { AccountPermissionType } from "./Account"; + + +export interface AccountPermission { + accountPermissionId?: string; + accountId: string; + accountPermissionType: AccountPermissionType; +} diff --git a/src/pages/protected/GamesPage.tsx b/src/pages/protected/GamesPage.tsx index 67d85f5..9cfdd06 100644 --- a/src/pages/protected/GamesPage.tsx +++ b/src/pages/protected/GamesPage.tsx @@ -4,7 +4,7 @@ import AllGamesDisplay from "@/ui/game/AllGamesDisplay"; export default function GamesPage(){ return (

(); @@ -33,7 +37,7 @@ export default function RaidGroupPage(){ } else if(raidGroupQuery.status === "error"){ return ( -
Error
+ Error {raidGroupQuery.error.message} ); } else if(raidGroupQuery.status === "success" && raidGroupQuery.data === undefined){ @@ -62,17 +66,20 @@ export default function RaidGroupPage(){ { tabHeader: "Raid Instances", tabContent: - }, - { - tabHeader: "Users", - tabContent: - }, - { - tabHeader: "Requests", - tabContent: } ]; + if(isRaidGroupAdmin(raidGroupId!, raidGroupPermissions, accountPermissions)){ + tabs.push({ + tabHeader: "Users", + tabContent: + }); + tabs.push({ + tabHeader: "Requests", + tabContent: + }); + } + return (
void; accountId: string | null; + accountPermissions: AccountPermission[]; raidGroupPermissions: RaidGroupPermission[]; gamePermissions: GamePermission[]; raidGroupRequests: RaidGroupRequest[]; @@ -29,6 +31,7 @@ const initialState: AuthProviderState = { expiration: null, setExpiration: () => null, accountId: null, + accountPermissions: [], raidGroupPermissions: [], gamePermissions: [], raidGroupRequests: [] @@ -44,6 +47,7 @@ export function AuthProvider({ const [ expiration, setExpiration ] = useState(null); const [ firstFetch, setFirstFetch ] = useState(true); const [ accountId, setAccountId ] = useState(null); + const [ accountPermissions, setAccountPermissions ] = useState([]); const [ raidGroupPermissions, setRaidGroupPermissions ] = useState([]); const [ gamePermissions, setGamePermissions ] = useState([]); const [ raidGroupRequests, setRaidGroupRequests ] = useState([]); @@ -62,6 +66,7 @@ export function AuthProvider({ setExpiration(new Date(decodedToken.exp * 1000)); setFirstFetch(false); setAccountId(decodedToken.accountId); + setAccountPermissions(JSON.parse(decodedToken.accountPermissions)); setRaidGroupPermissions(JSON.parse(decodedToken.raidGroupPermissions)); setGamePermissions(JSON.parse(decodedToken.gamePermissions)); setRaidGroupRequests(JSON.parse(decodedToken.raidGroupRequests)); @@ -114,10 +119,11 @@ export function AuthProvider({ expiration, setExpiration, accountId, + accountPermissions, raidGroupPermissions, gamePermissions, raidGroupRequests - }), [ jwt, setJwt, expiration, setExpiration, accountId, raidGroupPermissions, gamePermissions, raidGroupRequests ]); + }), [ jwt, setJwt, expiration, setExpiration, accountId, accountPermissions, raidGroupPermissions, gamePermissions, raidGroupRequests ]); //TODO: Return a spinner while the first token is being fetched diff --git a/src/ui/account/AccountAdminButtons.tsx b/src/ui/account/AccountAdminButtons.tsx index ca9c5d7..6a8e106 100644 --- a/src/ui/account/AccountAdminButtons.tsx +++ b/src/ui/account/AccountAdminButtons.tsx @@ -3,10 +3,14 @@ import DangerButton from "@/components/button/DangerButton"; import PrimaryButton from "@/components/button/PrimaryButton"; import TertiaryButton from "@/components/button/TertiaryButton"; import WarningButton from "@/components/button/WarningButton"; +import { Account } from "@/interface/Account"; +import { useTheme } from "@/providers/ThemeProvider"; import { BsKeyFill, BsLockFill, BsPencilFill, BsTrash3, BsXCircle } from "react-icons/bs"; +import { Tooltip } from "react-tooltip"; export default function AccountAdminButtons({ + account, buttonProps, showForcePasswordResetModal, showAccountPasswordSetModal, @@ -14,6 +18,7 @@ export default function AccountAdminButtons({ showUpdateAccountModal, showDeleteAccountModal }:{ + account?: Account; buttonProps: ButtonProps; showForcePasswordResetModal: () => void; showAccountPasswordSetModal: () => void; @@ -21,13 +26,20 @@ export default function AccountAdminButtons({ showUpdateAccountModal: () => void; showDeleteAccountModal: () => void; }){ + const { theme } = useTheme(); + const componentId = crypto.randomUUID().replaceAll("-", ""); + + return (
+ + Force Password Reset + + + Set Password + + + Revoke Refresh Token + + + Update {account?.username} + + + Delete {account?.username} +
); } diff --git a/src/ui/account/AccountsList.tsx b/src/ui/account/AccountsList.tsx index 81c8507..c16dfb9 100644 --- a/src/ui/account/AccountsList.tsx +++ b/src/ui/account/AccountsList.tsx @@ -2,6 +2,8 @@ import { ButtonProps } from "@/components/button/Button"; import Table from "@/components/table/Table"; import { Account } from "@/interface/Account"; import { RaidGroup } from "@/interface/RaidGroup"; +import { useAuth } from "@/providers/AuthProvider"; +import { isSiteAdmin } from "@/util/PermissionUtil"; import moment from "moment"; import { useState } from "react"; import AccountAdminButtons from "./AccountAdminButtons"; @@ -22,6 +24,7 @@ export default function AccountsList({ accounts: Account[]; raidGroup?: RaidGroup; }){ + const { accountPermissions } = useAuth(); const [ selectedAccount, setSelectedAccount ] = useState(undefined); const [ displayForcePasswordResetModal, setDisplayForcePasswordResetModal ] = useState(false); const [ displayAccountPasswordSetModal, setDisplayAccountPasswordSetModal ] = useState(false); @@ -40,12 +43,10 @@ export default function AccountsList({ const headElements: React.ReactNode[] = [ -
- ID -
,
Username
, + isSiteAdmin(accountPermissions) &&
Email
, @@ -64,20 +65,18 @@ export default function AccountsList({ const bodyElements: React.ReactNode[][] = accounts.map((account) => [
- {account.accountId} -
, -
{account.username}
, + isSiteAdmin(accountPermissions) &&
{account.email}
,
- {moment(account.loginDate).format("MM-DD-YYYY HH:mm")} + {account.loginDate ? moment(account.loginDate).format("MM-DD-YYYY HH:mm") : <> }
,
{account.accountStatus} @@ -90,29 +89,33 @@ export default function AccountsList({ >  
- { - setSelectedAccount(account); - setDisplayForcePasswordResetModal(true); - }} - showAccountPasswordSetModal={() => { - setSelectedAccount(account); - setDisplayAccountPasswordSetModal(true); - }} - showRevokeRefreshTokenModal={() => { - setSelectedAccount(account); - setDisplayRevokeRefreshTokenModal(true); - }} - showUpdateAccountModal={() => { - setSelectedAccount(account); - setDisplayAccountModal(true); - }} - showDeleteAccountModal={() => { - setSelectedAccount(account); - setDisplayDeleteAccountModal(true); - }} - /> + { + isSiteAdmin(accountPermissions) && + { + setSelectedAccount(account); + setDisplayForcePasswordResetModal(true); + }} + showAccountPasswordSetModal={() => { + setSelectedAccount(account); + setDisplayAccountPasswordSetModal(true); + }} + showRevokeRefreshTokenModal={() => { + setSelectedAccount(account); + setDisplayRevokeRefreshTokenModal(true); + }} + showUpdateAccountModal={() => { + setSelectedAccount(account); + setDisplayAccountModal(true); + }} + showDeleteAccountModal={() => { + setSelectedAccount(account); + setDisplayDeleteAccountModal(true); + }} + /> + } { raidGroup && void; showRemoveFromRaidGroupModal: () => void; }){ + const { theme } = useTheme(); + const componentId = crypto.randomUUID().replaceAll("-", ""); + + return (
+ + Edit Permissions + + + Remove from Raid Group +
); } diff --git a/src/ui/account/RaidGroupAccountsTab.tsx b/src/ui/account/RaidGroupAccountsTab.tsx index e8bf6f6..f4752ef 100644 --- a/src/ui/account/RaidGroupAccountsTab.tsx +++ b/src/ui/account/RaidGroupAccountsTab.tsx @@ -43,7 +43,7 @@ export default function RaidGroupAccountsTab({ return ( <>
) } - setAccountStatus(e.currentTarget.value as AccountStatus)} - /> + { + account && + setAccountStatus(e.currentTarget.value as AccountStatus)} + /> + }
} modalFooter={ diff --git a/src/ui/calendar/CalendarDisplay.tsx b/src/ui/calendar/CalendarDisplay.tsx index 36284ef..7c1aa3b 100644 --- a/src/ui/calendar/CalendarDisplay.tsx +++ b/src/ui/calendar/CalendarDisplay.tsx @@ -1,6 +1,8 @@ import { useCreateGameCalendarEvent, useCreateRaidGroupCalendarEvent, useDeleteGameCalendarEvent, useDeleteRaidGroupCalendarEvent, useUpdateGameCalendarEvent, useUpdateRaidGroupCalendarEvent } from "@/hooks/CalendarHooks"; import { CalendarEvent } from "@/interface/Calendar"; +import { useAuth } from "@/providers/AuthProvider"; import { calendarEventToFullCalendarEvent } from "@/util/CalendarUtil"; +import { isGameAdmin, isRaidGroupAdmin, isRaidGroupLeader } from "@/util/PermissionUtil"; import { EventClickArg } from "@fullcalendar/core/index.js"; import dayGridPlugin from "@fullcalendar/daygrid"; import interactionPlugin, { DateClickArg } from "@fullcalendar/interaction"; @@ -19,6 +21,7 @@ export default function CalendarDisplay({ raidGroupId?: string; gameId?: string; }){ + const { accountPermissions, gamePermissions, raidGroupPermissions } = useAuth(); const [ displayCalendarEventModal, setDisplayCalendarEventModal ] = useState(false); const [ alterCalendarEvent, setAlterCalendarEvent ] = useState(); const [ disableModal, setDisableModal ] = useState(false); @@ -39,6 +42,15 @@ export default function CalendarDisplay({ eventStartDate: dateClickArg.date, eventEndDate: moment(dateClickArg.date).add(1, "hours").toDate() } as CalendarEvent); + + if(gameId && !isGameAdmin(gameId, gamePermissions, accountPermissions)){ + setDisableModal(true); + } + + if(raidGroupId && !isRaidGroupAdmin(raidGroupId, raidGroupPermissions, accountPermissions) && !isRaidGroupLeader(raidGroupId, raidGroupPermissions, accountPermissions)){ + setDisableModal(true); + } + setDisplayCalendarEventModal(true); } @@ -47,6 +59,12 @@ export default function CalendarDisplay({ if(raidGroupId && calendarEvent?.gameId){ setDisableModal(true); } + else if(calendarEvent?.gameId && !isGameAdmin(calendarEvent?.gameId, gamePermissions, accountPermissions)){ + setDisableModal(true); + } + else if(calendarEvent?.raidGroupId && !isRaidGroupAdmin(calendarEvent?.raidGroupId, raidGroupPermissions, accountPermissions) && !isRaidGroupLeader(calendarEvent?.raidGroupId, raidGroupPermissions, accountPermissions)){ + setDisableModal(true); + } setAlterCalendarEvent(calendarEvent); setDisplayCalendarEventModal(true); diff --git a/src/ui/calendar/RaidGroupHeader.tsx b/src/ui/calendar/RaidGroupHeader.tsx index 2611cc1..9ab9c7e 100644 --- a/src/ui/calendar/RaidGroupHeader.tsx +++ b/src/ui/calendar/RaidGroupHeader.tsx @@ -1,5 +1,7 @@ import { ButtonProps } from "@/components/button/Button"; import { RaidGroup } from "@/interface/RaidGroup"; +import { useAuth } from "@/providers/AuthProvider"; +import { isRaidGroupAdmin } from "@/util/PermissionUtil"; import { useState } from "react"; import RaidGroupAdminButtons from "../raidGroup/RaidGroupAdminButtons"; import DeleteRaidGroupModal from "../raidGroup/modals/DeleteRaidGroupModal"; @@ -11,6 +13,7 @@ export default function RaidGroupHeader({ }:{ raidGroup: RaidGroup; }){ + const { accountPermissions, raidGroupPermissions } = useAuth(); const [ displayEditRaidGroupModal, setDisplayEditRaidGroupModal ] = useState(false); const [ displayDeleteRaidGroupModal, setDisplayDeleteRaidGroupModal ] = useState(false); @@ -39,7 +42,11 @@ export default function RaidGroupHeader({
setDisplayEditRaidGroupModal(true)} showDeleteRaidGroupModal={() => setDisplayDeleteRaidGroupModal(true)} hasRaidGroupPermissions={true} diff --git a/src/ui/calendar/modals/CalendarEventModal.tsx b/src/ui/calendar/modals/CalendarEventModal.tsx index 6727492..304a281 100644 --- a/src/ui/calendar/modals/CalendarEventModal.tsx +++ b/src/ui/calendar/modals/CalendarEventModal.tsx @@ -182,6 +182,7 @@ export default function CalendarEventModal({ variant="ghost" shape="square" onClick={deleteCalendarEvent} + disabled={disabled} > void; showDeleteClassGroupModal: () => void; }){ + const { theme } = useTheme(); + const componentId = crypto.randomUUID().replaceAll("-", ""); + + return (
+ + Edit {classGroup.classGroupName} + + + Delete {classGroup.classGroupName} +
); } diff --git a/src/ui/classGroup/ClassGroupList.tsx b/src/ui/classGroup/ClassGroupList.tsx index 13d9535..28c7ebb 100644 --- a/src/ui/classGroup/ClassGroupList.tsx +++ b/src/ui/classGroup/ClassGroupList.tsx @@ -4,6 +4,8 @@ import Table from "@/components/table/Table"; import { useGetGameClassesByClassGroup } from "@/hooks/GameClassHooks"; import { ClassGroup } from "@/interface/ClassGroup"; import { RaidGroup } from "@/interface/RaidGroup"; +import { useAuth } from "@/providers/AuthProvider"; +import { isRaidGroupAdmin, isRaidGroupLeader } from "@/util/PermissionUtil"; import { useState } from "react"; import ClassGroupButtons from "./ClassGroupButtons"; import ClassGroupModal from "./modal/ClassGroupModal"; @@ -17,6 +19,7 @@ export default function ClassGroupList({ classGroups: ClassGroup[]; raidGroup: RaidGroup; }){ + const { accountPermissions, raidGroupPermissions } = useAuth(); const [ selectedClassGroup, setSelectedClassGroup ] = useState(); const [ displayClassGroupModal, setDisplayClassGroupModal ] = useState(false); const [ displayDeleteClassGroupModal, setDisplayDeleteClassGroupModal ] = useState(false); @@ -26,7 +29,8 @@ export default function ClassGroupList({ const buttonProps: ButtonProps = { variant: "ghost", size: "md", - shape: "square" + shape: "square", + disabled: !isRaidGroupAdmin(raidGroup.raidGroupId!, raidGroupPermissions, accountPermissions) && !isRaidGroupLeader(raidGroup.raidGroupId!, raidGroupPermissions, accountPermissions) }; @@ -64,6 +68,7 @@ export default function ClassGroupList({  
{ setSelectedClassGroup(classGroup); diff --git a/src/ui/classGroup/ClassGroupsTab.tsx b/src/ui/classGroup/ClassGroupsTab.tsx index 03c4ffb..62f1f1f 100644 --- a/src/ui/classGroup/ClassGroupsTab.tsx +++ b/src/ui/classGroup/ClassGroupsTab.tsx @@ -3,6 +3,8 @@ import TextInput from "@/components/input/TextInput"; import Pagination from "@/components/pagination/Pagination"; import { useGetClassGroupsCount } from "@/hooks/ClassGroupHooks"; import { RaidGroup } from "@/interface/RaidGroup"; +import { useAuth } from "@/providers/AuthProvider"; +import { isRaidGroupAdmin, isRaidGroupLeader } from "@/util/PermissionUtil"; import { useEffect, useState } from "react"; import { useDebouncedCallback } from "use-debounce"; import ClassGroupsLoader from "./ClassGroupsLoader"; @@ -14,6 +16,7 @@ export default function ClassGroupsTab({ }:{ raidGroup: RaidGroup; }){ + const { accountPermissions, raidGroupPermissions } = useAuth(); const [ displayCreateClassGroupModal, setDisplayCreateClassGroupModal ] = useState(false); const [ page, setPage ] = useState(1); const [ totalPages, setTotalPages ] = useState(1); @@ -60,6 +63,7 @@ export default function ClassGroupsTab({ setDisplayCreateClassGroupModal(true)} + disabled={!isRaidGroupAdmin(raidGroup.raidGroupId!, raidGroupPermissions, accountPermissions) && !isRaidGroupLeader(raidGroup.raidGroupId!, raidGroupPermissions, accountPermissions)} > Create Class Group diff --git a/src/ui/game/AllGamesDisplay.tsx b/src/ui/game/AllGamesDisplay.tsx index 05d4ddf..60b888a 100644 --- a/src/ui/game/AllGamesDisplay.tsx +++ b/src/ui/game/AllGamesDisplay.tsx @@ -2,6 +2,8 @@ import PrimaryButton from "@/components/button/PrimaryButton"; import TextInput from "@/components/input/TextInput"; import Pagination from "@/components/pagination/Pagination"; import { useGetGamesCount } from "@/hooks/GameHooks"; +import { useAuth } from "@/providers/AuthProvider"; +import { isSiteAdmin } from "@/util/PermissionUtil"; import { useEffect, useState } from "react"; import { useDebouncedCallback } from "use-debounce"; import { GamesLoader } from "./GamesLoader"; @@ -9,6 +11,7 @@ import GameModal from "./modals/GameModal"; export default function AllGamesDisplay(){ + const { accountPermissions } = useAuth(); const [ displayCreateGameModal, setDisplayCreateGameModal ] = useState(false); const [ page, setPage ] = useState(1); const [ totalPages, setTotalPages ] = useState(1); @@ -54,6 +57,7 @@ export default function AllGamesDisplay(){ setDisplayCreateGameModal(true)} + disabled={!isSiteAdmin(accountPermissions)} > Create Game diff --git a/src/ui/game/GameAdminButtons.tsx b/src/ui/game/GameAdminButtons.tsx index 4092043..24e9ed9 100644 --- a/src/ui/game/GameAdminButtons.tsx +++ b/src/ui/game/GameAdminButtons.tsx @@ -1,25 +1,37 @@ import { ButtonProps } from "@/components/button/Button"; import DangerButton from "@/components/button/DangerButton"; import PrimaryButton from "@/components/button/PrimaryButton"; +import { Game } from "@/interface/Game"; +import { useTheme } from "@/providers/ThemeProvider"; import { BsPencilFill, BsTrash3 } from "react-icons/bs"; +import { Tooltip } from "react-tooltip"; export default function GameAdminButtons({ + game, buttonProps, showEditGameModal, showDeleteGameModal }:{ + game: Game; buttonProps: ButtonProps; showEditGameModal: () => void; showDeleteGameModal: () => void; }){ + const { theme } = useTheme(); + const componentId = crypto.randomUUID().replaceAll("-", ""); + + return (
+ + Edit {game.gameName} + + + Delete {game.gameName} +
); } diff --git a/src/ui/game/GameHeader.tsx b/src/ui/game/GameHeader.tsx index d475e1d..c080bec 100644 --- a/src/ui/game/GameHeader.tsx +++ b/src/ui/game/GameHeader.tsx @@ -1,5 +1,7 @@ import { ButtonProps } from "@/components/button/Button"; import { Game } from "@/interface/Game"; +import { useAuth } from "@/providers/AuthProvider"; +import { isGameAdmin } from "@/util/PermissionUtil"; import { useState } from "react"; import GameAdminButtons from "./GameAdminButtons"; import DeleteGameModal from "./modals/DeleteGameModal"; @@ -11,13 +13,15 @@ export default function GameHeader({ }:{ game: Game; }){ + const { gamePermissions, accountPermissions } = useAuth(); const [ displayEditGameModal, setDisplayEditGameModal ] = useState(false); const [ displayDeleteGameModal, setDisplayDeleteGameModal ] = useState(false); const buttonProps: ButtonProps = { variant: "ghost", size: "md", - shape: "square" + shape: "square", + disabled: !isGameAdmin(game.gameId ?? "", gamePermissions, accountPermissions) }; @@ -39,6 +43,7 @@ export default function GameHeader({
setDisplayEditGameModal(true)} showDeleteGameModal={() => setDisplayDeleteGameModal(true)} diff --git a/src/ui/game/GamesList.tsx b/src/ui/game/GamesList.tsx index 9f62210..9f87fcd 100644 --- a/src/ui/game/GamesList.tsx +++ b/src/ui/game/GamesList.tsx @@ -1,6 +1,8 @@ import { ButtonProps } from "@/components/button/Button"; import Table from "@/components/table/Table"; import { Game } from "@/interface/Game"; +import { useAuth } from "@/providers/AuthProvider"; +import { isGameAdmin } from "@/util/PermissionUtil"; import { useState } from "react"; import { Link } from "react-router"; import GameAdminButtons from "./GameAdminButtons"; @@ -13,6 +15,7 @@ export default function GamesList({ }:{ games: Game[]; }){ + const { accountPermissions, gamePermissions } = useAuth(); const [ selectedGame, setSelectedGame ] = useState(); const [ displayEditGameModal, setDisplayEditGameModal ] = useState(false); const [ displayDeleteGameModal, setDisplayDeleteGameModal ] = useState(false); @@ -68,7 +71,11 @@ export default function GamesList({  
{ setSelectedGame(game); setDisplayEditGameModal(true); diff --git a/src/ui/game/GamesListSkeleton.tsx b/src/ui/game/GamesListSkeleton.tsx index 0fbca22..c585a7a 100644 --- a/src/ui/game/GamesListSkeleton.tsx +++ b/src/ui/game/GamesListSkeleton.tsx @@ -1,5 +1,6 @@ import { ButtonShape, ButtonSizeType, ButtonVariant } from "@/components/button/Button"; import Table from "@/components/table/Table"; +import { Game } from "@/interface/Game"; import { elementBg } from "@/util/SkeletonUtil"; import React from "react"; import GameAdminButtons from "./GameAdminButtons"; @@ -64,7 +65,7 @@ function GameSkeleton(): React.ReactNode[]{ className={`flex flex-row items-center justify-center gap-2 pl-16`} >
 
- + ]; diff --git a/src/ui/gameClass/GameClassAdminButtons.tsx b/src/ui/gameClass/GameClassAdminButtons.tsx index 071c4d3..dd6a99d 100644 --- a/src/ui/gameClass/GameClassAdminButtons.tsx +++ b/src/ui/gameClass/GameClassAdminButtons.tsx @@ -1,25 +1,37 @@ import { ButtonProps } from "@/components/button/Button"; import DangerButton from "@/components/button/DangerButton"; import PrimaryButton from "@/components/button/PrimaryButton"; +import { GameClass } from "@/interface/GameClass"; +import { useTheme } from "@/providers/ThemeProvider"; import { BsPencilFill, BsTrash3 } from "react-icons/bs"; +import { Tooltip } from "react-tooltip"; export default function GameClassAdminButtons({ + gameClass, buttonProps, showEditGameClassModal, showDeleteGameClassModal }:{ + gameClass: GameClass; buttonProps: ButtonProps; showEditGameClassModal: () => void; showDeleteGameClassModal: () => void; }){ + const { theme } = useTheme(); + const componentId = crypto.randomUUID().replaceAll("-", ""); + + return (
+ + Edit {gameClass.gameClassName} + + + Delete {gameClass.gameClassName} +
); } diff --git a/src/ui/gameClass/GameClassCreateAndSearch.tsx b/src/ui/gameClass/GameClassCreateAndSearch.tsx index 64a5ac7..1c12dec 100644 --- a/src/ui/gameClass/GameClassCreateAndSearch.tsx +++ b/src/ui/gameClass/GameClassCreateAndSearch.tsx @@ -1,5 +1,7 @@ import PrimaryButton from "@/components/button/PrimaryButton"; import TextInput from "@/components/input/TextInput"; +import { useAuth } from "@/providers/AuthProvider"; +import { isGameAdmin } from "@/util/PermissionUtil"; import { useState } from "react"; import GameClassModal from "./modals/GameClassModal"; @@ -13,6 +15,7 @@ export default function GameClassCreateAndSearch({ searchTerm: string; setSearchTerm: (searchTerm: string) => void; }){ + const { gamePermissions, accountPermissions } = useAuth(); const [ displayGameClassModal, setDisplayGameClassModal ] = useState(false); const modalId = crypto.randomUUID().replaceAll("-", ""); @@ -33,6 +36,7 @@ export default function GameClassCreateAndSearch({ setDisplayGameClassModal(true)} + disabled={!isGameAdmin(gameId, gamePermissions, accountPermissions)} > Create Game Class diff --git a/src/ui/gameClass/GameClassList.tsx b/src/ui/gameClass/GameClassList.tsx index c8bc868..ec4224c 100644 --- a/src/ui/gameClass/GameClassList.tsx +++ b/src/ui/gameClass/GameClassList.tsx @@ -1,6 +1,8 @@ import { ButtonProps } from "@/components/button/Button"; import Table from "@/components/table/Table"; import { GameClass } from "@/interface/GameClass"; +import { useAuth } from "@/providers/AuthProvider"; +import { isGameAdmin } from "@/util/PermissionUtil"; import { useState } from "react"; import GameClassAdminButtons from "./GameClassAdminButtons"; import DeleteGameClassModal from "./modals/DeleteGameClassModal"; @@ -12,6 +14,7 @@ export default function GameClassList({ }:{ gameClasses: GameClass[]; }){ + const { gamePermissions, accountPermissions } = useAuth(); const [ selectedGameClass, setSelectedGameClass ] = useState(); const [ displayGameClassModal, setDisplayGameClassModal ] = useState(false); const [ displayDeleteGameClassModal, setDisplayDeleteGameClassModal ] = useState(false); @@ -65,7 +68,11 @@ export default function GameClassList({   { setSelectedGameClass(gameClass); setDisplayGameClassModal(true); diff --git a/src/ui/gameClass/GameClassListSkeleton.tsx b/src/ui/gameClass/GameClassListSkeleton.tsx index 6306460..82f08b2 100644 --- a/src/ui/gameClass/GameClassListSkeleton.tsx +++ b/src/ui/gameClass/GameClassListSkeleton.tsx @@ -1,5 +1,6 @@ import { ButtonShape, ButtonSizeType, ButtonVariant } from "@/components/button/Button"; import Table from "@/components/table/Table"; +import { GameClass } from "@/interface/GameClass"; import { elementBg } from "@/util/SkeletonUtil"; import GameClassAdminButtons from "./GameClassAdminButtons"; @@ -49,6 +50,7 @@ function GameClassSkeleton(): React.ReactNode[]{ shape: "square" as ButtonShape, disabled: true }, + gameClass:{} as GameClass, showEditGameClassModal: () => {}, showDeleteGameClassModal: () => {} } diff --git a/src/ui/person/PersonAdminButtons.tsx b/src/ui/person/PersonAdminButtons.tsx index c8b603c..d057e71 100644 --- a/src/ui/person/PersonAdminButtons.tsx +++ b/src/ui/person/PersonAdminButtons.tsx @@ -2,20 +2,29 @@ import { ButtonProps } from "@/components/button/Button"; import DangerButton from "@/components/button/DangerButton"; import PrimaryButton from "@/components/button/PrimaryButton"; import SuccessButton from "@/components/button/SuccessButton"; +import { Person } from "@/interface/Person"; +import { useTheme } from "@/providers/ThemeProvider"; import { BsPencilFill, BsPlusLg, BsTrash3 } from "react-icons/bs"; +import { Tooltip } from "react-tooltip"; export default function PersonAdminButtons({ + person, buttonProps, showUpdatePersonModal, showDeletePersonModal, showCreatePersonCharacterModal }:{ + person?: Person; buttonProps: ButtonProps; showUpdatePersonModal: () => void; showDeletePersonModal: () => void; showCreatePersonCharacterModal?: () => void; }){ + const { theme } = useTheme(); + const componentId = crypto.randomUUID().replaceAll("-", ""); + + return (
+ + Add Character to {person?.personName} + + + Edit {person?.personName} + + + Delete {person?.personName} +
); } diff --git a/src/ui/person/PersonList.tsx b/src/ui/person/PersonList.tsx index 3100553..5aac915 100644 --- a/src/ui/person/PersonList.tsx +++ b/src/ui/person/PersonList.tsx @@ -3,6 +3,8 @@ import PersonCharacterDisplay from "@/components/personCharacter/PersonCharacter import Table from "@/components/table/Table"; import { Person } from "@/interface/Person"; import { RaidGroup } from "@/interface/RaidGroup"; +import { useAuth } from "@/providers/AuthProvider"; +import { isRaidGroupAdmin, isRaidGroupLeader } from "@/util/PermissionUtil"; import { useState } from "react"; import { Link } from "react-router"; import PersonCharacterModal from "../personCharacter/modal/PersonCharacterModal"; @@ -18,6 +20,7 @@ export default function PersonList({ people: Person[]; raidGroup: RaidGroup; }){ + const { accountPermissions, raidGroupPermissions } = useAuth(); const [ selectedPerson, setSelectedPerson ] = useState(); const [ displayUpdatePersonModal, setDisplayUpdatePersonModal ] = useState(false); const [ displayDeletePersonModal, setDisplayDeletePersonModal ] = useState(false); @@ -27,7 +30,8 @@ export default function PersonList({ const buttonProps: ButtonProps = { variant: "ghost", size: "md", - shape: "square" + shape: "square", + disabled: !isRaidGroupAdmin(raidGroup.raidGroupId ?? "", raidGroupPermissions, accountPermissions) && !isRaidGroupLeader(raidGroup.raidGroupId ?? "", raidGroupPermissions, accountPermissions) }; @@ -78,6 +82,7 @@ export default function PersonList({   { setSelectedPerson(person); diff --git a/src/ui/person/PersonTab.tsx b/src/ui/person/PersonTab.tsx index 4fa5265..f021a94 100644 --- a/src/ui/person/PersonTab.tsx +++ b/src/ui/person/PersonTab.tsx @@ -3,6 +3,8 @@ import TextInput from "@/components/input/TextInput"; import Pagination from "@/components/pagination/Pagination"; import { useGetPeopleByRaidGroupCount } from "@/hooks/PersonHooks"; import { RaidGroup } from "@/interface/RaidGroup"; +import { useAuth } from "@/providers/AuthProvider"; +import { isRaidGroupAdmin, isRaidGroupLeader } from "@/util/PermissionUtil"; import { useEffect, useState } from "react"; import { useDebouncedCallback } from "use-debounce"; import PersonModal from "./modals/PersonModal"; @@ -14,6 +16,7 @@ export default function PersonTab({ }:{ raidGroup: RaidGroup; }){ + const { accountPermissions, raidGroupPermissions } = useAuth(); const [ displayCreatePersonModal, setDisplayCreatePersonModal ] = useState(false); const [ page, setPage ] = useState(1); const [ totalPages, setTotalPages ] = useState(1); @@ -60,6 +63,7 @@ export default function PersonTab({ setDisplayCreatePersonModal(true)} + disabled={!isRaidGroupAdmin(raidGroup.raidGroupId ?? "", raidGroupPermissions, accountPermissions) && !isRaidGroupLeader(raidGroup.raidGroupId ?? "", raidGroupPermissions, accountPermissions)} > Create Person diff --git a/src/ui/raidGroup/RaidGroupAdminButtons.tsx b/src/ui/raidGroup/RaidGroupAdminButtons.tsx index 081be87..d5f0179 100644 --- a/src/ui/raidGroup/RaidGroupAdminButtons.tsx +++ b/src/ui/raidGroup/RaidGroupAdminButtons.tsx @@ -2,10 +2,14 @@ import { ButtonProps } from "@/components/button/Button"; import DangerButton from "@/components/button/DangerButton"; import PrimaryButton from "@/components/button/PrimaryButton"; import TertiaryButton from "@/components/button/TertiaryButton"; +import { RaidGroup } from "@/interface/RaidGroup"; +import { useTheme } from "@/providers/ThemeProvider"; import { BsChatRightText, BsPencilFill, BsTrash3 } from "react-icons/bs"; +import { Tooltip } from "react-tooltip"; export default function RaidGroupAdminButtons({ + raidGroup, buttonProps, showRaidGroupRequestModal, showEditRaidGroupModal, @@ -13,6 +17,7 @@ export default function RaidGroupAdminButtons({ hasRaidGroupPermissions, hasRaidGroupRequest }:{ + raidGroup: RaidGroup; buttonProps: ButtonProps; showRaidGroupRequestModal?: () => void; showEditRaidGroupModal: () => void; @@ -20,6 +25,10 @@ export default function RaidGroupAdminButtons({ hasRaidGroupPermissions: boolean; hasRaidGroupRequest: boolean; }){ + const { theme } = useTheme(); + const componentId = crypto.randomUUID().replaceAll("-", ""); + + return (
} + + Request to join {raidGroup.raidGroupName} + + + Edit {raidGroup.raidGroupName} + + + Delete {raidGroup.raidGroupName} +
); } diff --git a/src/ui/raidGroup/RaidGroupsList.tsx b/src/ui/raidGroup/RaidGroupsList.tsx index 9aaa53f..88a4307 100644 --- a/src/ui/raidGroup/RaidGroupsList.tsx +++ b/src/ui/raidGroup/RaidGroupsList.tsx @@ -2,7 +2,7 @@ import { ButtonProps } from "@/components/button/Button"; import Table from "@/components/table/Table"; import { RaidGroup } from "@/interface/RaidGroup"; import { useAuth } from "@/providers/AuthProvider"; -import { containsRaidGroupPermission, containsRaidGroupRequest } from "@/util/PermissionUtil"; +import { containsRaidGroupPermission, containsRaidGroupRequest, isRaidGroupAdmin } from "@/util/PermissionUtil"; import { useState } from "react"; import { Link } from "react-router"; import RaidGroupRequestModal from "../raidGroupRequest/modal/RaidGroupRequestModal"; @@ -20,7 +20,7 @@ export default function RaidGroupsList({ const [ displayRaidGroupRequestModal, setDisplayRaidGroupRequestModal ] = useState(false); const [ displayEditRaidGroupModal, setDisplayEditRaidGroupModal ] = useState(false); const [ displayDeleteRaidGroupModal, setDisplayDeleteRaidGroupModal ] = useState(false); - const { raidGroupPermissions, raidGroupRequests } = useAuth(); + const { accountPermissions, raidGroupPermissions, raidGroupRequests } = useAuth(); const buttonProps: ButtonProps = { @@ -73,7 +73,11 @@ export default function RaidGroupsList({   { setSelectedRaidGroup(raidGroup); setDisplayRaidGroupRequestModal(true); @@ -86,7 +90,7 @@ export default function RaidGroupsList({ setSelectedRaidGroup(raidGroup); setDisplayDeleteRaidGroupModal(true); }} - hasRaidGroupPermissions={containsRaidGroupPermission(raidGroup.raidGroupId ?? "", raidGroupPermissions)} + hasRaidGroupPermissions={containsRaidGroupPermission(raidGroup.raidGroupId ?? "", raidGroupPermissions, accountPermissions)} hasRaidGroupRequest={containsRaidGroupRequest(raidGroup.raidGroupId ?? "", raidGroupRequests)} /> diff --git a/src/ui/raidGroup/RaidGroupsListSkeleton.tsx b/src/ui/raidGroup/RaidGroupsListSkeleton.tsx index d13df02..de848a2 100644 --- a/src/ui/raidGroup/RaidGroupsListSkeleton.tsx +++ b/src/ui/raidGroup/RaidGroupsListSkeleton.tsx @@ -1,5 +1,6 @@ import { ButtonShape, ButtonSizeType, ButtonVariant } from "@/components/button/Button"; import Table from "@/components/table/Table"; +import { RaidGroup } from "@/interface/RaidGroup"; import { elementBg } from "@/util/SkeletonUtil"; import RaidGroupAdminButtons from "./RaidGroupAdminButtons"; @@ -49,8 +50,11 @@ function RaidGroupSkeleton(): React.ReactNode[]{ shape: "square" as ButtonShape, disabled: true }, + showRaidGroupRequestModal: () => {}, showEditRaidGroupModal: () => {}, - showDeleteRaidGroupModal: () => {} + showDeleteRaidGroupModal: () => {}, + hasRaidGroupPermissions: false, + hasRaidGroupRequest: false } const elements: React.ReactNode[] = [
 
- +
]; diff --git a/src/ui/raidGroup/modals/RaidGroupModal.tsx b/src/ui/raidGroup/modals/RaidGroupModal.tsx index 7c51fd2..433bedd 100644 --- a/src/ui/raidGroup/modals/RaidGroupModal.tsx +++ b/src/ui/raidGroup/modals/RaidGroupModal.tsx @@ -32,7 +32,7 @@ export default function RaidGroupModal({ setRaidGroupName(raidGroup?.raidGroupName ?? ""); setRaidGroupIcon(raidGroup?.raidGroupIcon ?? ""); setIconFile(null); - }, [ raidGroup, setRaidGroupName, setRaidGroupIcon ]); + }, [ display, raidGroup, setRaidGroupName, setRaidGroupIcon ]); const updateRaidGroupMutate = useUpdateRaidGroup(); @@ -47,25 +47,25 @@ export default function RaidGroupModal({ useEffect(() => { if(updateRaidGroupMutate.status === "success"){ updateRaidGroupMutate.reset(); - addSuccessMessage(`Updated raid group ${raidGroupName}`); + addSuccessMessage(`Updated raid group ${raidGroup?.raidGroupName}`); close(); } else if(updateRaidGroupMutate.status === "error"){ updateRaidGroupMutate.reset(); - addErrorMessage(`Error updating raid group ${raidGroupName}: ${updateRaidGroupMutate.error.message}`); + addErrorMessage(`Error updating raid group ${raidGroup?.raidGroupName}: ${updateRaidGroupMutate.error.message}`); console.log(updateRaidGroupMutate.error); } else if(createRaidGroupMutate.status === "success"){ createRaidGroupMutate.reset(); - addSuccessMessage(`Created raid group ${raidGroupName}`); + addSuccessMessage(`Created raid group ${raidGroup?.raidGroupName}`); close(); } else if(createRaidGroupMutate.status === "error"){ createRaidGroupMutate.reset(); - addErrorMessage(`Error creating raid group ${raidGroupName}: ${createRaidGroupMutate.error.message}`); + addErrorMessage(`Error creating raid group ${raidGroup?.raidGroupName}: ${createRaidGroupMutate.error.message}`); console.log(createRaidGroupMutate.error); } - }, [ updateRaidGroupMutate, createRaidGroupMutate, raidGroupName, close, addSuccessMessage, addErrorMessage ]); + }, [ updateRaidGroupMutate, createRaidGroupMutate, raidGroup, close, addSuccessMessage, addErrorMessage ]); const updateRaidGroup = () => { diff --git a/src/ui/raidGroupRequest/RaidGroupRequestButtons.tsx b/src/ui/raidGroupRequest/RaidGroupRequestButtons.tsx index a22ed30..fe60404 100644 --- a/src/ui/raidGroupRequest/RaidGroupRequestButtons.tsx +++ b/src/ui/raidGroupRequest/RaidGroupRequestButtons.tsx @@ -1,25 +1,37 @@ import { ButtonProps } from "@/components/button/Button"; import DangerButton from "@/components/button/DangerButton"; import PrimaryButton from "@/components/button/PrimaryButton"; +import { RaidGroupRequest } from "@/interface/RaidGroupRequest"; +import { useTheme } from "@/providers/ThemeProvider"; import { BsPencilFill, BsTrash3 } from "react-icons/bs"; +import { Tooltip } from "react-tooltip"; export default function RaidGroupRequestButtons({ + request, buttonProps, showRaidGroupRequestModal, showDeleteRaidGroupRequestModal }:{ + request: RaidGroupRequest; buttonProps: ButtonProps; showRaidGroupRequestModal: () => void; showDeleteRaidGroupRequestModal: () => void; }){ + const { theme } = useTheme(); + const componentId = crypto.randomUUID().replaceAll("-", ""); + + return (
+ + Resolve raid group request from {request.username} + + + Delete raid group request from {request.username} +
); } diff --git a/src/ui/raidGroupRequest/RaidGroupRequestList.tsx b/src/ui/raidGroupRequest/RaidGroupRequestList.tsx index b03c27c..de2fec1 100644 --- a/src/ui/raidGroupRequest/RaidGroupRequestList.tsx +++ b/src/ui/raidGroupRequest/RaidGroupRequestList.tsx @@ -31,14 +31,22 @@ export default function RaidGroupRequestList({
Username
, +
+ Message +
,
Actions
]; const bodyElements: React.ReactNode[][] = raidGroupRequests.map((request) => [ -
+
{request.username}
, +
+ {request.requestMessage || <> } +
,
@@ -50,6 +58,7 @@ export default function RaidGroupRequestList({ { raidGroup && { setSelectedRequest(request); setDisplayRequestModal(true); }} showDeleteRaidGroupRequestModal={() => { setSelectedRequest(request); setDisplayDeleteRequestModal(true); }} diff --git a/src/ui/raidGroupRequest/RaidGroupRequestTab.tsx b/src/ui/raidGroupRequest/RaidGroupRequestTab.tsx index 28a3305..51b24e0 100644 --- a/src/ui/raidGroupRequest/RaidGroupRequestTab.tsx +++ b/src/ui/raidGroupRequest/RaidGroupRequestTab.tsx @@ -42,7 +42,7 @@ export default function RaidGroupRequestTab({ return ( <>
void; showDeleteRaidInstanceModal: () => void; }){ + const { theme } = useTheme(); + const componentId = crypto.randomUUID().replaceAll("-", ""); + + return (
+ + Edit {raidInstance?.raidInstanceName} + + + Delete {raidInstance?.raidInstanceName} +
); } diff --git a/src/ui/raidInstance/RaidInstanceList.tsx b/src/ui/raidInstance/RaidInstanceList.tsx index 30faaca..f6d0d76 100644 --- a/src/ui/raidInstance/RaidInstanceList.tsx +++ b/src/ui/raidInstance/RaidInstanceList.tsx @@ -2,6 +2,8 @@ import { ButtonProps } from "@/components/button/Button"; import Table from "@/components/table/Table"; import { RaidGroup } from "@/interface/RaidGroup"; import { RaidInstance } from "@/interface/RaidInstance"; +import { useAuth } from "@/providers/AuthProvider"; +import { isRaidGroupAdmin, isRaidGroupLeader } from "@/util/PermissionUtil"; import moment from "moment"; import { useState } from "react"; import { Link } from "react-router"; @@ -17,6 +19,7 @@ export default function RaidInstanceList({ raidInstances: RaidInstance[]; raidGroup: RaidGroup; }){ + const { accountPermissions, raidGroupPermissions } = useAuth(); const [ selectedRaidInstance, setSelectedRaidInstance ] = useState(); const [ displayEditRaidInstanceModal, setDisplayEditRaidInstanceModal ] = useState(false); const [ displayDeleteRaidInstanceModal, setDisplayDeleteRaidInstanceModal ] = useState(false); @@ -25,7 +28,8 @@ export default function RaidInstanceList({ const buttonProps: ButtonProps = { variant: "ghost", size: "md", - shape: "square" + shape: "square", + disabled: !isRaidGroupAdmin(raidGroup.raidGroupId ?? "", raidGroupPermissions, accountPermissions) || !isRaidGroupLeader(raidGroup.raidGroupId ?? "", raidGroupPermissions, accountPermissions) }; @@ -94,6 +98,7 @@ export default function RaidInstanceList({  
{ setSelectedRaidInstance(raidInstance); setDisplayEditRaidInstanceModal(true); }} showDeleteRaidInstanceModal={() => { setSelectedRaidInstance(raidInstance); setDisplayDeleteRaidInstanceModal(true); }} diff --git a/src/ui/raidInstance/RaidInstanceTab.tsx b/src/ui/raidInstance/RaidInstanceTab.tsx index 672f4a5..3fd5c78 100644 --- a/src/ui/raidInstance/RaidInstanceTab.tsx +++ b/src/ui/raidInstance/RaidInstanceTab.tsx @@ -3,6 +3,8 @@ import TextInput from "@/components/input/TextInput"; import Pagination from "@/components/pagination/Pagination"; import { useGetRaidInstancesByRaidGroupCount } from "@/hooks/RaidInstanceHooks"; import { RaidGroup } from "@/interface/RaidGroup"; +import { useAuth } from "@/providers/AuthProvider"; +import { isRaidGroupAdmin, isRaidGroupLeader } from "@/util/PermissionUtil"; import { useEffect, useState } from "react"; import { useDebouncedCallback } from "use-debounce"; import RaidInstanceLoader from "./RaidInstanceLoader"; @@ -14,6 +16,7 @@ export default function RaidInstanceTab({ }:{ raidGroup: RaidGroup; }){ + const { accountPermissions, raidGroupPermissions } = useAuth(); const [ displayCreateRaidInstanceModal, setDisplayCreateRaidInstanceModal ] = useState(false); const [ page, setPage ] = useState(1); const [ totalPages, setTotalPages ] = useState(1); @@ -59,6 +62,7 @@ export default function RaidInstanceTab({ setDisplayCreateRaidInstanceModal(true)} + disabled={!isRaidGroupAdmin(raidGroup.raidGroupId ?? "", raidGroupPermissions, accountPermissions) && !isRaidGroupLeader(raidGroup.raidGroupId ?? "", raidGroupPermissions, accountPermissions)} > Create Raid Instance diff --git a/src/ui/raidLayout/RaidLayoutAdminButtons.tsx b/src/ui/raidLayout/RaidLayoutAdminButtons.tsx index a247ee1..e1f7ace 100644 --- a/src/ui/raidLayout/RaidLayoutAdminButtons.tsx +++ b/src/ui/raidLayout/RaidLayoutAdminButtons.tsx @@ -1,24 +1,37 @@ import { ButtonProps } from "@/components/button/Button"; import DangerButton from "@/components/button/DangerButton"; import PrimaryButton from "@/components/button/PrimaryButton"; +import { RaidLayout } from "@/interface/RaidLayout"; +import { useTheme } from "@/providers/ThemeProvider"; import { BsPencilFill, BsTrash3 } from "react-icons/bs"; +import { Tooltip } from "react-tooltip"; + export default function RaidLayoutAdminButtons({ + raidLayout, buttonProps, showRaidLayoutModal, showDeleteRaidLayoutModal }:{ + raidLayout: RaidLayout; buttonProps: ButtonProps; showRaidLayoutModal: () => void; showDeleteRaidLayoutModal: () => void; }){ + const { theme } = useTheme(); + const componentId = crypto.randomUUID().replaceAll("-", ""); + + return (
+ + Edit {raidLayout.raidLayoutName} + + + Delete {raidLayout.raidLayoutName} +
); } diff --git a/src/ui/raidLayout/RaidLayoutList.tsx b/src/ui/raidLayout/RaidLayoutList.tsx index 1528c3a..48526db 100644 --- a/src/ui/raidLayout/RaidLayoutList.tsx +++ b/src/ui/raidLayout/RaidLayoutList.tsx @@ -5,6 +5,8 @@ import { useGetClassGroupsByRaidLayout } from "@/hooks/ClassGroupHooks"; import { ClassGroup } from "@/interface/ClassGroup"; import { RaidGroup } from "@/interface/RaidGroup"; import { RaidLayout } from "@/interface/RaidLayout"; +import { useAuth } from "@/providers/AuthProvider"; +import { isRaidGroupAdmin, isRaidGroupLeader } from "@/util/PermissionUtil"; import { useEffect, useState } from "react"; import DeleteRaidLayoutModal from "./modal/DeleteRaidLayoutModal"; import RaidLayoutModal from "./modal/RaidLayoutModal"; @@ -18,6 +20,7 @@ export default function RaidLayoutList({ raidLayouts: RaidLayout[]; raidGroup: RaidGroup; }){ + const { accountPermissions, raidGroupPermissions } = useAuth(); const [ selectedRaidLayout, setSelectedRaidLayout ] = useState(); const [ displayEditRaidLayoutModal, showEditRaidLayoutModal ] = useState(false); const [ displayDeleteRaidLayoutModal, showDeleteRaidLayoutModal ] = useState(false); @@ -32,7 +35,8 @@ export default function RaidLayoutList({ const buttonProps: ButtonProps = { variant: "ghost", size: "md", - shape: "square" + shape: "square", + disabled: !isRaidGroupAdmin(raidGroup.raidGroupId ?? "", raidGroupPermissions, accountPermissions) && !isRaidGroupLeader(raidGroup.raidGroupId ?? "", raidGroupPermissions, accountPermissions) }; @@ -78,6 +82,7 @@ export default function RaidLayoutList({  
{ setSelectedRaidLayout(raidLayout); showEditRaidLayoutModal(true); }} showDeleteRaidLayoutModal={() => { setSelectedRaidLayout(raidLayout); showDeleteRaidLayoutModal(true); }} diff --git a/src/ui/raidLayout/RaidLayoutTab.tsx b/src/ui/raidLayout/RaidLayoutTab.tsx index 950a777..196cabf 100644 --- a/src/ui/raidLayout/RaidLayoutTab.tsx +++ b/src/ui/raidLayout/RaidLayoutTab.tsx @@ -3,6 +3,8 @@ import TextInput from "@/components/input/TextInput"; import Pagination from "@/components/pagination/Pagination"; import { useGetRaidLayoutsByRaidGroupCount } from "@/hooks/RaidLayoutHooks"; import { RaidGroup } from "@/interface/RaidGroup"; +import { useAuth } from "@/providers/AuthProvider"; +import { isRaidGroupAdmin, isRaidGroupLeader } from "@/util/PermissionUtil"; import { useEffect, useState } from "react"; import { useDebouncedCallback } from "use-debounce"; import RaidLayoutModal from "./modal/RaidLayoutModal"; @@ -14,6 +16,7 @@ export default function RaidLayoutTab({ }:{ raidGroup: RaidGroup; }){ + const { accountPermissions, raidGroupPermissions } = useAuth(); const [ displayCreateRaidLayoutModal, setDisplayCreateRaidLayoutModal ] = useState(false); const [ page, setPage ] = useState(1); const [ totalPages, setTotalPages ] = useState(1); @@ -59,6 +62,7 @@ export default function RaidLayoutTab({ setDisplayCreateRaidLayoutModal(true)} + disabled={!isRaidGroupAdmin(raidGroup.raidGroupId ?? "", raidGroupPermissions, accountPermissions) && !isRaidGroupLeader(raidGroup.raidGroupId ?? "", raidGroupPermissions, accountPermissions)} > Create Raid Layout diff --git a/src/util/PermissionUtil.ts b/src/util/PermissionUtil.ts index e35e7aa..3ce5f37 100644 --- a/src/util/PermissionUtil.ts +++ b/src/util/PermissionUtil.ts @@ -1,8 +1,23 @@ +import { AccountPermissionType } from "@/interface/Account"; +import { AccountPermission } from "@/interface/AccountPermission"; +import { GamePermission, GamePermissionType } from "@/interface/GamePermission"; +import { RaidGroupPermissionType } from "@/interface/RaidGroup"; import { RaidGroupPermission } from "@/interface/RaidGroupPermission"; import { RaidGroupRequest } from "@/interface/RaidGroupRequest"; -export function containsRaidGroupPermission(raidGroupId: string, permissions: RaidGroupPermission[]): boolean{ +//! Site +export function isSiteAdmin(accountPermissions: AccountPermission[]): boolean{ + return accountPermissions.find((permission) => permission.accountPermissionType === AccountPermissionType.ADMIN) !== undefined; +} + + + +//! Raid Group +export function containsRaidGroupPermission(raidGroupId: string, permissions: RaidGroupPermission[], accountPermissions: AccountPermission[]): boolean{ + if(accountPermissions.find((permission) => permission.accountPermissionType === AccountPermissionType.ADMIN)){ + return true; + } for(const permission of permissions){ if(permission.raidGroupId === raidGroupId){ return true; @@ -11,7 +26,7 @@ export function containsRaidGroupPermission(raidGroupId: string, permissions: Ra return false; } -export function containsRaidGroupRequest(raidGroupId: string, requests: RaidGroupRequest[]){ +export function containsRaidGroupRequest(raidGroupId: string, requests: RaidGroupRequest[]): boolean{ for(const request of requests){ if(request.raidGroupId === raidGroupId){ return true; @@ -19,3 +34,30 @@ export function containsRaidGroupRequest(raidGroupId: string, requests: RaidGrou } return false; } + +export function isRaidGroupAdmin(raidGroupId: string, permissions: RaidGroupPermission[], accountPermissions: AccountPermission[]): boolean{ + if(accountPermissions.find((permission) => permission.accountPermissionType === AccountPermissionType.ADMIN)){ + return true; + } + const raidGroupPermission = permissions.find((permission) => permission.raidGroupId === raidGroupId); + return raidGroupPermission?.permission === RaidGroupPermissionType.ADMIN; +} + +export function isRaidGroupLeader(raidGroupId: string, permissions: RaidGroupPermission[], accountPermissions: AccountPermission[]): boolean{ + if(accountPermissions.find((permission) => permission.accountPermissionType === AccountPermissionType.ADMIN)){ + return true; + } + const raidGroupPermission = permissions.find((permission) => permission.raidGroupId === raidGroupId); + return raidGroupPermission?.permission === RaidGroupPermissionType.LEADER; +} + + + +//! Game +export function isGameAdmin(gameId: string, permissions: GamePermission[], accountPermissions: AccountPermission[]): boolean{ + if(accountPermissions.find((permission) => permission.accountPermissionType === AccountPermissionType.ADMIN)){ + return true; + } + const gamePermission = permissions.find((permission) => permission.gameId === gameId); + return gamePermission?.gamePermissionType === GamePermissionType.ADMIN; +}