Skip to content

Commit ee1ab7e

Browse files
committed
feat: enhance board and category management permissions; improve button visibility based on user access levels
1 parent b314a80 commit ee1ab7e

3 files changed

Lines changed: 62 additions & 45 deletions

File tree

app/routes/groups.$groupId.$categoryId._index.tsx

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,9 @@ export default function Boards() {
129129

130130
useFetcherResponse(fetcher, toast, () => setModalOpen(null));
131131

132+
const canManageAnyBoard = useMemo(() => boards.some((b) => canManage(b.accessLevel, user?.isDev)), [boards, user?.isDev]);
133+
const canCreateBoard = useMemo(() => canManage(category.accessLevel, user?.isDev), [category.accessLevel, user?.isDev]);
134+
132135
const finalBoards = useMemo(() => {
133136
if (!dbcSearch) return boards;
134137
return boards.filter((b) => dbcSearch ? b.name.includes(dbcSearch) : true);
@@ -146,23 +149,26 @@ export default function Boards() {
146149
name={`Boards in category: ${category.name}`}
147150
description={'List of all boards that are currently available to you in this category.'}
148151
goBackPath={`/groups/${group.id}`}
149-
customButtons={canManage(category.accessLevel, user?.isDev) ? [{
150-
type: 'normal',
151-
label: 'Manage Boards',
152-
icon: <FaTools />,
153-
isDisabled: boards.length === 0,
154-
onClick: () => setEditorMode(!editorMode),
155-
isLoading: fetcher.state === 'loading',
156-
tooltip: 'Manage boards',
157-
isActive: editorMode,
158-
}, {
159-
type: 'normal',
160-
label: 'Create Board',
161-
icon: <FaPlus />,
162-
onClick: () => setModalOpen('createBoard'),
163-
isLoading: fetcher.state === 'loading',
164-
tooltip: 'Create board',
165-
}] : []}
152+
customButtons={[
153+
...(canManageAnyBoard ? [{
154+
type: 'normal',
155+
label: 'Manage Boards',
156+
icon: <FaTools />,
157+
isDisabled: boards.length === 0,
158+
onClick: () => setEditorMode(!editorMode),
159+
isLoading: fetcher.state === 'loading',
160+
tooltip: 'Manage boards',
161+
isActive: editorMode,
162+
}] as const : []),
163+
...(canCreateBoard ? [{
164+
type: 'normal',
165+
label: 'Create Board',
166+
icon: <FaPlus />,
167+
onClick: () => setModalOpen('createBoard'),
168+
isLoading: fetcher.state === 'loading',
169+
tooltip: 'Create board',
170+
}] as const : []),
171+
]}
166172
/>
167173

168174
<SearchBar search={search} setSearch={setSearch} whatSearch={'boards'} id='boards' dividerMY={4} isShown={showSearches} />
@@ -182,7 +188,7 @@ export default function Boards() {
182188
setModalOpen('updateBoard');
183189
setBoardId(finalBoards[index]!.id);
184190
} : undefined}
185-
onReorder={editorMode ? (orderedIds) => {
191+
onReorder={editorMode && canCreateBoard ? (orderedIds) => {
186192
setTempBoards(orderedIds);
187193
} : undefined}
188194
onFlashCreate={editorMode ? (index) => {

app/routes/groups.$groupId._index.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,9 @@ export default function Categories() {
112112
setTempCategories([]);
113113
}, [fetcher, tempCategories]);
114114

115-
const canManageAnything = useMemo(() => categories.some((c) => canManage(c.accessLevel, user?.isDev)), [categories, user?.isDev]);
116-
useEffect(() => setCanInvite?.(canManageAnything), [canManageAnything, setCanInvite]);
115+
const canManageAnyCategory = useMemo(() => categories.some((c) => canManage(c.accessLevel, user?.isDev)), [categories, user?.isDev]);
116+
const canCreateCategory = useMemo(() => canManage(group.accessLevel, user?.isDev), [group.accessLevel, user?.isDev]);
117+
useEffect(() => setCanInvite?.(canManageAnyCategory), [canManageAnyCategory, setCanInvite]);
117118

118119
return (
119120
<VStack w='100%' align='center' px={4} spacing={{ base: 8, md: '30px' }} mt={{ base: 8, md: 16 }} id='a1'>
@@ -129,7 +130,7 @@ export default function Categories() {
129130
to: `/groups/${group.id}/calendar`,
130131
tooltip: 'View group calendar',
131132
reloadDocument: true,
132-
}, ...(canManage(group.accessLevel, user?.isDev) ? [{
133+
}, ...(canManageAnyCategory ? [{
133134
type: 'normal',
134135
label: 'Manage Categories',
135136
icon: <FaTools />,
@@ -138,7 +139,7 @@ export default function Categories() {
138139
isLoading: fetcher.state === 'loading',
139140
tooltip: 'Manage categories',
140141
isActive: editorMode,
141-
}, {
142+
}] as const : []), ...(canCreateCategory ? [{
142143
type: 'normal',
143144
label: 'Create Category',
144145
icon: <FaPlus />,
@@ -161,13 +162,12 @@ export default function Categories() {
161162
setModalOpen('updateCategory');
162163
setCategoryId(finalCategories[index]!.id);
163164
} : undefined}
164-
onReorder={editorMode ? (orderedIds) => {
165+
onReorder={editorMode && canCreateCategory ? (orderedIds) => {
165166
setTempCategories(orderedIds);
166167
} : undefined}
167168
cards={finalCategories.map((c) => ({
168169
id: c.id,
169170
editorMode,
170-
canManageAnything,
171171
sizeBytes: c.totalSizeBytes,
172172
isDeleteDisabled: c.boards > 0,
173173
url: `/groups/${group.id}/${c.id}`,

app/routes/groups._index.tsx

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { useCallback, useContext, useEffect, useMemo, useState } from 'react';
55
import { LoaderFunctionArgs, ActionFunctionArgs } from '@remix-run/node';
66
import { useFetcherResponse } from '~/hooks/useFetcherResponse';
77
import { canInviteAndPermit, canManage } from '~/other/utils';
8+
import { FaChartBar, FaPlus, FaTools } from 'react-icons/fa';
89
import { SearchBar } from '~/components/layout/SearchBar';
910
import { NoticeCard } from '~/components/other/Notice';
1011
import CardList from '~/components/layout/CardList';
@@ -13,7 +14,6 @@ import { authenticator } from '~/utils/auth.server';
1314
import { RootContext } from '~/components/Context';
1415
import MenuBar from '~/components/layout/MenuBar';
1516
import configServer from '~/utils/config.server';
16-
import { FaPlus, FaTools } from 'react-icons/fa';
1717
import { WebReturnType } from '~/other/types';
1818
import { api } from '~/utils/web.server';
1919

@@ -107,8 +107,9 @@ export default function Groups() {
107107
setTempGroups([]);
108108
}, [fetcher, tempGroups]);
109109

110-
const hasAdminOrDevAccess = useMemo(() => groups.some((g) => canInviteAndPermit(g.accessLevel, user?.isDev)), [groups, user?.isDev]);
111-
useEffect(() => setCanInvite?.(hasAdminOrDevAccess), [hasAdminOrDevAccess, setCanInvite]);
110+
const canManageAnyGroup = useMemo(() => user?.isDev || groups.some((g) => canManage(g.accessLevel, user?.isDev)), [groups, user?.isDev]);
111+
const canInviteAnyGroup = useMemo(() => user?.isDev || groups.some((g) => canInviteAndPermit(g.accessLevel, user?.isDev)), [groups, user?.isDev]);
112+
useEffect(() => setCanInvite?.(canInviteAnyGroup), [canInviteAnyGroup, setCanInvite]);
112113
useEffect(() => setShowAllBoards?.(groups.length !== 0), [setShowAllBoards]);
113114

114115
return (
@@ -117,24 +118,34 @@ export default function Groups() {
117118
<MenuBar
118119
name={'Category Groups'}
119120
description={'List of all groups that are currently available to you.'}
120-
customButtons={hasAdminOrDevAccess ? [{
121-
type: 'normal',
122-
label: 'Manage Groups',
123-
icon: <FaTools />,
124-
isDisabled: groups.length === 0,
125-
onClick: () => setEditorMode(!editorMode),
126-
isLoading: fetcher.state === 'loading',
127-
tooltip: 'Manage groups',
128-
isActive: editorMode,
129-
}, {
130-
type: 'normal',
131-
label: 'Create Group',
132-
icon: <FaPlus />,
133-
onClick: () => setModalOpen('createGroup'),
134-
isLoading: fetcher.state === 'loading',
135-
isDisabled: !user?.isDev,
136-
tooltip: 'Create group',
137-
}] : []}
121+
customButtons={[
122+
...(user?.isDev ? [{
123+
type: 'link',
124+
label: 'Analytics',
125+
icon: <FaChartBar />,
126+
to: '/analytics',
127+
tooltip: 'View analytics overview',
128+
reloadDocument: true,
129+
}] as const : []),
130+
...(canManageAnyGroup ? [{
131+
type: 'normal',
132+
label: 'Manage Groups',
133+
icon: <FaTools />,
134+
isDisabled: groups.length === 0,
135+
onClick: () => setEditorMode(!editorMode),
136+
isLoading: fetcher.state === 'loading',
137+
tooltip: 'Manage groups',
138+
isActive: editorMode,
139+
}] as const : []),
140+
...(user?.isDev ? [{
141+
type: 'normal',
142+
label: 'Create Group',
143+
icon: <FaPlus />,
144+
onClick: () => setModalOpen('createGroup'),
145+
isLoading: fetcher.state === 'loading',
146+
tooltip: 'Create group',
147+
}] as const : []),
148+
]}
138149
/>
139150

140151
<SearchBar search={search} setSearch={setSearch} whatSearch={'groups'} id='groups' dividerMY={4} isShown={showSearches} />

0 commit comments

Comments
 (0)