Skip to content

Commit

Permalink
Configurable permissions/roles on guilds
Browse files Browse the repository at this point in the history
  • Loading branch information
Alf-Melmac committed Sep 28, 2023
1 parent dd3a967 commit 6068afb
Show file tree
Hide file tree
Showing 17 changed files with 252 additions and 117 deletions.
12 changes: 10 additions & 2 deletions src/assets/locales/de/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"calendarEvent.tooltip.emptySlots": "Slots frei",
"clickHere": "hier",
"color": "Farbe",
"configuration": "Konfiguration",
"description": "Beschreibung",
"details": "Details",
"documentTitle.admin.utils": "Admin - Utils",
Expand Down Expand Up @@ -86,8 +87,8 @@
"guild.config.archive.select": "Bitte wähle einen Textkanal...",
"guild.config.language.description": "Bestimmt die verwendete Sprache für Ausgaben außerhalb der Website. Z.B. Event-Details in Discord.",
"guild.tag": "Tag",
"guild.user.add": "Mitspieler hinzufügen",
"guild.user.removed": "Spieler entfernt",
"guild.user.add": "Mitglieder hinzufügen",
"guild.user.removed": "Mitglied entfernt",
"guild.users.none": "Keine Mitglieder",
"guilds": "Communities",
"guilds.search": "Communities suchen",
Expand All @@ -106,6 +107,7 @@
"length.threeHours": "3 Stunden",
"length.twoHours": "2 Stunden",
"loading": "Lädt...",
"members": "Mitglieder",
"minute.plural": "{0} Minuten",
"minute.singular": "{0} Minute",
"moreDetails": "Weitere Details",
Expand Down Expand Up @@ -170,6 +172,12 @@
"theme.toggle.light": "Licht an",
"unsavedChanges": "Ungespeicherte Änderungen",
"user.name": "Name",
"user.role": "Rolle",
"user.role.admin": "Admin",
"user.role.admin.description": "Änderungen an der Community vornehmen.",
"user.role.eventManage": "Event-Planer",
"user.role.eventManage.description": "Planen und bearbeiten von Events.",
"user.role.member": "Mitglied",
"userMenu.admin.utils": "Utils",
"userMenu.label.admin": "Administration",
"userMenu.logout": "Logout",
Expand Down
10 changes: 9 additions & 1 deletion src/assets/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"calendarEvent.tooltip.emptySlots": "Slots open",
"clickHere": "here",
"color": "Colour",
"configuration": "Configuration",
"description": "Description",
"details": "Details",
"documentTitle.admin.utils": "Admin - Utils",
Expand Down Expand Up @@ -87,7 +88,7 @@
"guild.config.language.description": "Determines the language used for output outside the website. E.g. event details in Discord.",
"guild.tag": "Tag",
"guild.user.add": "Add member",
"guild.user.removed": "Player removed",
"guild.user.removed": "Member removed",
"guild.users.none": "No members",
"guilds": "Communities",
"guilds.search": "Search Communities",
Expand All @@ -106,6 +107,7 @@
"length.threeHours": "3 hours",
"length.twoHours": "2 hours",
"loading": "Loading...",
"members": "Members",
"minute.plural": "{0} minutes",
"minute.singular": "{0} minute",
"moreDetails": "More details",
Expand Down Expand Up @@ -170,6 +172,12 @@
"theme.toggle.light": "Light on",
"unsavedChanges": "Unsaved changes",
"user.name": "Name",
"user.role": "Role",
"user.role.admin": "Admin",
"user.role.admin.description": "Make changes to the community.",
"user.role.eventManage": "Event Planner",
"user.role.eventManage.description": "Plan and edit events.",
"user.role.member": "Member",
"userMenu.admin.utils": "Utils",
"userMenu.label.admin": "Administration",
"userMenu.logout": "Logout",
Expand Down
1 change: 0 additions & 1 deletion src/contexts/authentication/authenticationTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,4 @@ export enum ApplicationRoles {
ROLE_SYS_ADMIN = 'ROLE_SYS_ADMIN',
ROLE_ADMIN = 'ROLE_ADMIN',
ROLE_EVENT_MANAGE = 'ROLE_EVENT_MANAGE',
ROLE_USER = 'ROLE_USER',
}
28 changes: 28 additions & 0 deletions src/contexts/guild/GuildPageContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import {createContext, PropsWithChildren, useContext, useMemo} from 'react';

type GuildPage = {
guildId: string;
isAdmin: boolean;
}

const GuildPageContext = createContext<GuildPage | undefined>(undefined);

export function GuildPageProvider(props: PropsWithChildren<GuildPage>): JSX.Element {
const {guildId, isAdmin, children} = props;

const contextValue = useMemo(() => {
return {
guildId: guildId,
isAdmin: isAdmin,
};
}, [guildId, isAdmin]);
return <GuildPageContext.Provider value={contextValue}>{children}</GuildPageContext.Provider>;
}

export function useGuildPage(): GuildPage {
const context = useContext(GuildPageContext);
if (context === undefined) {
throw new Error('useGuild must be used within a GuildProvider');
}
return context;
}
4 changes: 4 additions & 0 deletions src/features/guilds/GuildRoutes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,7 @@ export const guildRoutes: RouteObject[] = [
},
notFoundRoute,
];

export type GuildPageParams = {
guildId: string;
};
4 changes: 2 additions & 2 deletions src/features/guilds/GuildsNavbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {SpotlightAction} from '@mantine/spotlight';
import {useNavigate, useParams} from 'react-router-dom';
import {Dispatch, SetStateAction, useEffect} from 'react';
import {SearchControl} from './SearchControl';
import {GuildProps} from './guild/Guild';
import {GuildPageParams} from './GuildRoutes';

const useStyles = createStyles((theme) => ({
guildButton: {
Expand All @@ -23,7 +23,7 @@ type GuildsNavbarProps = {
};

export function GuildsNavbar(props: GuildsNavbarProps): JSX.Element {
const {guildId} = useParams<GuildProps>();
const {guildId} = useParams<GuildPageParams>();
const {classes} = useStyles();
const guildsQuery = useGetGuilds();
const navigate = useNavigate();
Expand Down
21 changes: 11 additions & 10 deletions src/features/guilds/guild/Guild.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {createStyles, Image, Paper, SimpleGrid, Stack, Title} from '@mantine/core';
import {AnchorBlank} from '../../../components/Text/AnchorBlank';
import {GuildUsers} from './GuildUsers';
import {GuildUsers} from './users/GuildUsers';
import {T} from '../../../components/T';
import {useParams} from 'react-router-dom';
import {useTranslatedDocumentTitle} from '../../../hooks/useTranslatedDocumentTitle';
Expand All @@ -13,20 +13,18 @@ import {useEffect, useState} from 'react';
import {GuildDetailsDto} from '../guildTypes';
import {NotFound} from '../../error/NotFound';
import {GuildLoading} from './GuildLoading';
import {GuildPageProvider} from '../../../contexts/guild/GuildPageContext';
import {GuildPageParams} from '../GuildRoutes';

export const useGuildStyles = createStyles((theme) => ({
guildCard: {
backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark[8] : theme.white,
},
}));

export type GuildProps = {
guildId: string;
};

export function Guild(): JSX.Element {
useTranslatedDocumentTitle('documentTitle.guild');
const {guildId} = useParams<GuildProps>();
const {guildId} = useParams<GuildPageParams>();
if (!guildId) throw Error('Invalid state: Guild id required');

const {classes} = useGuildStyles();
Expand Down Expand Up @@ -78,11 +76,14 @@ export function Guild(): JSX.Element {
</Stack>
</Paper>

{isAdmin &&
<GuildConfig guildId={guildId}/>
}
<GuildPageProvider guildId={guildId} isAdmin={isAdmin}>
{isAdmin &&
<GuildConfig/>
}

<GuildUsers/>
</GuildPageProvider>

<GuildUsers guildId={guildId}/>
</>
);
}
16 changes: 8 additions & 8 deletions src/features/guilds/guild/GuildConfig.tsx
Original file line number Diff line number Diff line change
@@ -1,44 +1,44 @@
import {Accordion, Box, Stack, Title} from '@mantine/core';
import {T} from '../../../components/T';
import {GuildProps} from './Guild';
import {useGetGuildConfig} from './useGetGuild';
import {GuildEventTypes} from './GuildEventTypes';
import {GuildLanguage} from './config/GuildLanguage';
import {GuildArchive} from './config/GuildArchive';
import {useGuildPage} from '../../../contexts/guild/GuildPageContext';

export function GuildConfig(props: GuildProps): JSX.Element {
const {guildId} = props;
export function GuildConfig(): JSX.Element {
const {guildId} = useGuildPage();
const guildConfigQuery = useGetGuildConfig(guildId);
const guildConfig = guildConfigQuery.data;
if (guildConfigQuery.isLoading || !guildConfig) return <></>;

return <>
<Title order={3}>Konfiguration</Title>
<Title order={3}><T k={'configuration'}/></Title>
<Accordion variant={'separated'} mt={8}>
<Accordion.Item value={'integration.discord'}>
<Accordion.Control><T k={'integration.discord'}/></Accordion.Control>
<Accordion.Panel>
<Stack>
<Box>
<Title order={4}><T k={'language'}/></Title>
<GuildLanguage guildId={guildId} {...guildConfig}/>
<GuildLanguage {...guildConfig}/>
</Box>
<Box>
<Title order={4}><T k={'integration.discord'}/></Title>
<GuildArchive guildId={guildId} {...guildConfig}/>
<GuildArchive {...guildConfig}/>
</Box>
</Stack>
</Accordion.Panel>
</Accordion.Item>
<Accordion.Item value={'types'}>
<Accordion.Control><T k={'event.eventTypes'}/></Accordion.Control>
<Accordion.Panel>
<GuildEventTypes guildId={guildId}/>
<GuildEventTypes/>
</Accordion.Panel>
</Accordion.Item>
</Accordion>


<Title order={3} mt={'lg'}>Spieler</Title>
<Title order={3} mt={'lg'}><T k={'members'}/></Title>
</>;
}
7 changes: 3 additions & 4 deletions src/features/guilds/guild/GuildEventTypes.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import {useGetEventTypes} from '../../event/action/generalInformation/useGetEventTypes';
import {GuildProps} from './Guild';
import {Badge, ColorSwatch, CopyButton, Table} from '@mantine/core';
import {DelayedSkeleton} from '../../../components/Delayed/DelayedSkeleton';
import {T} from '../../../components/T';
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
import {faCopy} from '@fortawesome/free-regular-svg-icons';
import {useGuildPage} from '../../../contexts/guild/GuildPageContext';

export function GuildEventTypes(props: GuildProps): JSX.Element {
const {guildId} = props;

export function GuildEventTypes(): JSX.Element {
const {guildId} = useGuildPage();
const eventTypesQuery = useGetEventTypes(guildId);
const eventTypes = eventTypesQuery.data;

Expand Down
38 changes: 0 additions & 38 deletions src/features/guilds/guild/RemoveGuildUser.tsx

This file was deleted.

13 changes: 6 additions & 7 deletions src/features/guilds/guild/config/GuildArchive.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import {GuildProps} from '../Guild';
import {GuildConfigDto} from '../../guildTypes';
import {useGetDiscordIntegration} from '../useGetGuild';
import {T} from '../../../../components/T';
Expand All @@ -13,6 +12,7 @@ import {useDidUpdate} from '@mantine/hooks';
import {AnchorBlank} from '../../../../components/Text/AnchorBlank';
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
import {faDiscord} from '@fortawesome/free-brands-svg-icons';
import {useGuildPage} from '../../../../contexts/guild/GuildPageContext';

const useStyles = createStyles(() => ({
group: {
Expand All @@ -21,10 +21,9 @@ const useStyles = createStyles(() => ({
},
}));

type GuildArchiveProps = GuildProps & GuildConfigDto;

export function GuildArchive(props: GuildArchiveProps): JSX.Element {
const {guildId, archiveChannel} = props;
export function GuildArchive(props: GuildConfigDto): JSX.Element {
const {archiveChannel} = props;
const {guildId} = useGuildPage();
const {classes} = useStyles();
const {t} = useLanguage();

Expand All @@ -48,8 +47,8 @@ export function GuildArchive(props: GuildArchiveProps): JSX.Element {
if (integrationQuery.isLoading || !integrationQuery.data) return <Skeleton width={'100%'} height={60}/>;
const {connected, categories} = integrationQuery.data;
if (!connected) return <Button color={'blue'} mt={3}
leftIcon={<FontAwesomeIcon icon={faDiscord}/>}
component={AnchorBlank} href={'https://slotbot.de/invite'}>
leftIcon={<FontAwesomeIcon icon={faDiscord}/>}
component={AnchorBlank} href={'https://slotbot.de/invite'}>
<T k={'integration.discord.invite'}/>
</Button>;

Expand Down
9 changes: 4 additions & 5 deletions src/features/guilds/guild/config/GuildLanguage.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import {GuildProps} from '../Guild';
import {GuildConfigDto, Language} from '../../guildTypes';
import {useState} from 'react';
import slotbotServerClient from '../../../../hooks/slotbotServerClient';
Expand All @@ -9,11 +8,11 @@ import {useDidUpdate} from '@mantine/hooks';
import {Group, Radio} from '@mantine/core';
import {T} from '../../../../components/T';
import {DEFlag, GBFlag} from 'mantine-flagpack';
import {useGuildPage} from '../../../../contexts/guild/GuildPageContext';

type GuildLanguageProps = GuildProps & GuildConfigDto;

export function GuildLanguage(props: GuildLanguageProps): JSX.Element {
const {guildId, language} = props;
export function GuildLanguage(props: GuildConfigDto): JSX.Element {
const {language} = props;
const guildId = useGuildPage();
const [selectedLanguage, setSelectedLanguage] = useState(language);
const [savedLanguage, setSavedLanguage] = useState(language);

Expand Down
14 changes: 14 additions & 0 deletions src/features/guilds/guild/users/GuildUser.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import {AnchorLink} from '../../../../components/Text/AnchorLink';
import {Avatar, Group} from '@mantine/core';
import {TableCellProps} from './GuildUsers';

export function GuildUser(props: TableCellProps): JSX.Element {
const {id, avatarUrl, name} = props.row.original.user;

return <AnchorLink to={`/profile/${id}`}>
<Group spacing={'sm'}>
<Avatar src={avatarUrl} radius={40}/>
{name}
</Group>
</AnchorLink>;
}

0 comments on commit 6068afb

Please sign in to comment.