add admin stuff

This commit is contained in:
Michael Fatemi 2021-08-11 16:09:11 -04:00
parent c61f0aa914
commit 2acdca681a
5 changed files with 136 additions and 41 deletions

View File

@ -1,7 +1,9 @@
import { useMemo } from 'react';
import { createContext, useEffect, useState } from 'react';
import { getGroup } from '../api';
import EventCreatorLink from '../EventCreator/EventCreatorLink';
import EventStream from '../EventStream';
import { useMe } from '../hooks';
import { IGroup } from '../types';
import UILink from '../UI/UILink';
import useImmutable from '../useImmutable';
@ -13,6 +15,7 @@ const DEFAULT_GROUP = (): IGroup => ({
name: '',
users: [],
events: [],
admins: [],
joinCode: null,
});
@ -21,6 +24,7 @@ export const GroupContext = createContext({ group: DEFAULT_GROUP() });
export default function Group({ id }: { id: number }) {
const [group, setGroup] = useImmutable<IGroup | null>(null);
const [loading, setLoading] = useState(false);
const me = useMe();
useEffect(() => {
setLoading(true);
@ -29,6 +33,14 @@ export default function Group({ id }: { id: number }) {
.finally(() => setLoading(false));
}, [id, setGroup]);
const isAdmin = useMemo(() => {
if (!group) {
return false;
}
return group.admins.some((a) => a.id === me?.id);
}, [group, me?.id]);
if (loading) {
return <h1>Loading...</h1>;
}
@ -48,8 +60,12 @@ export default function Group({ id }: { id: number }) {
<br />
<GroupMembersLink />
<br />
<GroupSettingsLink />
<br />
{isAdmin && (
<>
<GroupSettingsLink />
<br />
</>
)}
<EventCreatorLink />
</div>
<br />

View File

@ -1,12 +1,21 @@
import { useMemo } from 'react';
import { useCallback, useContext, useState } from 'react';
import { lightgrey } from '../../lib/colors';
import { generateCode, resetCode } from '../api';
import { useMe } from '../hooks';
import UIButton from '../UI/UIButton';
import { GroupContext } from './Group';
export default function GroupInviteCodeGenerator() {
export default function GroupInviteCode() {
const { group } = useContext(GroupContext);
const me = useMe();
const isAdmin = useMemo(
() => group.admins.some((a) => a.id === me?.id),
[group.admins, me?.id]
);
const [shown, setShown] = useState(false);
const generateJoinCode = useCallback(() => {
@ -34,44 +43,50 @@ export default function GroupInviteCodeGenerator() {
</code>{' '}
(click to show/hide)
</span>
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
<UIButton
onClick={resetJoinCode}
style={{
backgroundColor: lightgrey,
margin: '0.5rem',
flex: 1,
}}
>
Reset
</UIButton>
<UIButton
onClick={generateJoinCode}
style={{
backgroundColor: lightgrey,
margin: '0.5rem',
flex: 1,
}}
>
Regenerate
</UIButton>
</div>
{isAdmin && (
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
<UIButton
onClick={resetJoinCode}
style={{
backgroundColor: lightgrey,
margin: '0.5rem',
flex: 1,
}}
>
Reset
</UIButton>
<UIButton
onClick={generateJoinCode}
style={{
backgroundColor: lightgrey,
margin: '0.5rem',
flex: 1,
}}
>
Regenerate
</UIButton>
</div>
)}
</>
);
} else {
return (
<>
This group has no way for new members to join.
<UIButton
onClick={generateJoinCode}
style={{
backgroundColor: lightgrey,
marginTop: '0.5rem',
marginBottom: '0.5rem',
}}
>
Generate a code
</UIButton>
{isAdmin ? (
<UIButton
onClick={generateJoinCode}
style={{
backgroundColor: lightgrey,
marginTop: '0.5rem',
marginBottom: '0.5rem',
}}
>
Generate a code
</UIButton>
) : (
'Contact an admin to create a code'
)}
</>
);
}

View File

@ -1,15 +1,47 @@
import { useContext, useState } from 'react';
import { useCallback, useContext, useMemo, useState } from 'react';
import { addGroupAdmin, removeGroupAdmin } from '../api';
import { useMe } from '../hooks';
import UIPressable from '../UI/UIPressable';
import UISecondaryBox from '../UI/UISecondaryBox';
import { GroupContext } from './Group';
import GroupInviteCodeGenerator from './GroupInviteCodeGenerator';
import GroupInviteCode from './GroupInviteCode';
export default function GroupMembersLink() {
const [open, setOpen] = useState(false);
const { group } = useContext(GroupContext);
const me = useMe();
const handleClick = () => setOpen(!open);
const handleClick = useCallback(() => setOpen((o) => !o), []);
const adminIds = useMemo(
() => new Set(group.admins.map((a) => a.id)),
[group.admins]
);
const addAdmin = useCallback(
(adminId: number, adminName: string) => {
addGroupAdmin(group.id, adminId).then(({ status }) => {
if (status === 'success') {
group.admins.push({ id: adminId, name: adminName });
}
});
},
[group.admins, group.id]
);
const amIAdmin = me?.id ? adminIds.has(me.id) : false;
const removeAdmin = useCallback(
(adminId: number) => {
removeGroupAdmin(group.id, adminId).then((res) => {
if (res.status === 'success') {
group.admins = group.admins.filter((admin) => admin.id !== adminId);
}
});
},
[group]
);
return (
<>
@ -20,12 +52,24 @@ export default function GroupMembersLink() {
<UISecondaryBox style={{ width: '100%', textAlign: 'center' }}>
<h1>Members</h1>
{group.users.map(({ name }) => (
<span key={name}>{name}</span>
{group.users.map(({ name, id }) => (
<span key={id}>
{name} {adminIds.has(id) && ' (admin)'}{' '}
{amIAdmin &&
(adminIds.has(id) ? (
<button onClick={() => removeAdmin(id)}>
Remove as admin
</button>
) : (
<button onClick={() => addAdmin(id, name)}>
Add as admin
</button>
))}
</span>
))}
<br />
<GroupInviteCodeGenerator />
<GroupInviteCode />
</UISecondaryBox>
</>
)}

View File

@ -145,6 +145,22 @@ export async function createGroup(name: string): Promise<{ id: number }> {
return { id };
}
export async function addGroupAdmin(
id: number,
userId: number
): Promise<{ status: 'success' | 'error' }> {
const { status } = await post(`/groups/${id}/add_admin`, { userId });
return { status };
}
export async function removeGroupAdmin(
id: number,
userId: number
): Promise<{ status: 'success' | 'error' }> {
const { status } = await post(`/groups/${id}/remove_admin`, { userId });
return { status };
}
export async function getNotifications() {
return await get('/users/@me/received_requests_and_invites');
}

View File

@ -54,6 +54,10 @@ export type IGroup = {
id: number;
name: string;
}[];
admins: {
id: number;
name: string;
}[];
joinCode: string | null;
};