Permalink
Newer
100644
311 lines (269 sloc)
7.97 KB
6
Popover,
7
PopoverArrow,
8
PopoverBody,
9
PopoverCloseButton,
10
PopoverContent,
11
PopoverHeader,
12
PopoverTrigger,
26
import NewInactivityNotice from "../../components/NewInactivityNotice.js";
27
import InactivityNoticeCard from "../../components/InactivityNoticeCard.js";
29
export async function loader({ context }: { context: RequestContext }) {
30
const { current_user: currentUser } = context.data;
37
const departments = {
38
DM: 1 << 2,
39
ET: 1 << 3,
40
FM: 1 << 10,
41
WM: 1 << 9,
42
};
43
44
const newItemPermissions = {
45
game_ban: [1 << 5],
46
inactivity: [1 << 2, 1 << 9, 1 << 10],
47
infraction: [1 << 0, 1 << 2, 1 << 6, 1 << 7],
48
};
49
50
const newItemNames: { [k: string]: string } = {
51
game_ban: "Game Ban",
52
inactivity: "Inactivity Notice",
53
infraction: "Infraction",
54
};
55
56
const typePermissions = {
57
appeal: [1 << 0, 1 << 1],
58
gma: [1 << 5],
59
report: [1 << 5],
60
};
61
62
const typeNames: { [k: string]: string } = {
63
appeal: "Discord Appeals",
64
gma: "Game Appeals",
65
report: "Game Reports",
66
};
67
68
const allowedNewItems = [];
69
const allowedTypes = [];
70
71
for (const [item, ints] of Object.entries(newItemPermissions)) {
72
if (ints.find((i) => currentUser.permissions & i))
73
allowedNewItems.push({ name: newItemNames[item], value: item });
74
}
75
76
for (const [type, ints] of Object.entries(typePermissions)) {
77
if (ints.find((i) => currentUser.permissions & i))
78
allowedTypes.push({ name: typeNames[type], value: type });
79
}
80
81
if (!allowedTypes.length)
87
can_edit_ban_users: [
88
"165594923586945025",
89
"289372404541554689",
90
"396347223736057866",
91
].includes(currentUser.id),
92
departments: Object.entries(departments)
93
.filter((d) => d[1] & currentUser.permissions)
94
.map((arr) => arr[0]),
101
return [
102
{
103
title: "Moderation Queue - Car Crushers",
104
},
105
];
108
export default function () {
109
const pageProps = useLoaderData<typeof loader>();
110
const isDesktop = useBreakpointValue({ base: false, lg: true });
111
const entryTypes = [];
112
const [entries, setEntries] = useState([] as ReactElement[]);
113
const [before, setBefore] = useState(Date.now());
116
entryTypes.push(
117
<option key={type.value} value={type.value}>
118
{type.name}
128
`/api/mod-queue/list?before=${before}&showClosed=${show_closed}&type=${queue_type}`,
130
131
if (!queueReq.ok) {
132
const errorData: { error: string } = await queueReq.json();
133
134
useToast()({
135
description: errorData.error,
136
duration: 10000,
137
isClosable: true,
138
status: "error",
139
title: "Failed to load queue",
140
});
141
142
return;
143
}
145
const searchParams = new URLSearchParams(location.search);
146
const itemId = searchParams.get("id");
147
const itemType = searchParams.get("type");
148
152
if (
153
itemId &&
154
itemType &&
155
["appeal", "gma", "inactivity", "report"].includes(itemType)
156
) {
157
const itemReq = await fetch(`/api/mod-queue/${itemType}/${itemId}`);
158
159
if (!itemReq.ok) {
160
useToast()({
161
description: ((await itemReq.json()) as { error: string }).error,
162
duration: 10000,
163
isClosable: true,
164
status: "error",
165
title: "Failed to load item with id " + itemId,
166
});
167
} else {
168
const itemData: { [k: string]: any } = await itemReq.json();
169
170
entryData.unshift(itemData);
171
}
172
}
173
174
if (!entryData.length) return;
175
176
for (const entry of entryData) {
177
switch (queue_type) {
178
case "appeal":
179
newEntries.push(<AppealCard {...(entry as AppealCardProps)} />);
180
181
break;
182
183
case "gma":
184
newEntries.push(<GameAppealCard {...(entry as GameAppealProps)} />);
185
186
break;
187
188
case "inactivity":
189
newEntries.push(
190
<InactivityNoticeCard {...(entry as InactivityNoticeProps)} />,
191
);
192
193
break;
194
195
case "report":
196
newEntries.push(<ReportCard {...(entry as ReportCardProps)} />);
206
const itemModals: {
207
[k: string]: {
208
isOpen: boolean;
209
onOpen: () => void;
210
onClose: () => void;
211
[k: string]: any;
212
};
213
} = {
214
game_ban: useDisclosure(),
215
inactivity: useDisclosure(),
224
const searchParams = new URLSearchParams(location.search);
225
const modal = searchParams.get("modal");
226
227
if (!modal || !pageProps.item_types.find((m) => m.value === modal)) return;
228
229
itemModals[modal].onOpen();
230
}, []);
234
<NewGameBan
235
isOpen={itemModals.game_ban.isOpen}
236
onClose={itemModals.game_ban.onClose}
237
/>
238
<NewInactivityNotice
239
departments={pageProps.departments}
240
isOpen={itemModals.inactivity.isOpen}
241
onClose={itemModals.inactivity.onClose}
242
/>
244
isOpen={itemModals.infraction.isOpen}
245
onClose={itemModals.infraction.onClose}
248
<VStack w={isDesktop ? "container.md" : "container.lg"}>
249
{entries}
250
</VStack>
251
<Box display={isDesktop ? undefined : "none"} ml="16px" w="248px">
252
<Select
253
onChange={async (v) => {
254
setEntries([]);
255
setBefore(Date.now());
256
257
const { target } = v;
258
259
await updateQueue(
260
target.options[target.selectedIndex].value,
261
Date.now(),
262
);
263
}}
264
>
265
{entryTypes}
266
</Select>
271
<Button
272
borderRadius="50%"
273
bottom="10vh"
274
h="16"
275
position="absolute"
276
right="10vh"
277
w="16"
278
>
283
fill="currentColor"
284
viewBox="0 0 16 16"
285
>
286
<path d="M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z" />
287
</svg>
288
</Button>
289
</PopoverTrigger>
290
<PopoverContent>
291
<PopoverArrow />
292
<PopoverCloseButton />
293
<PopoverHeader>Create New</PopoverHeader>
294
<PopoverBody>
295
<VStack>
296
{pageProps.item_types.map((item) => (
297
<Button
298
key={item.value}
299
onClick={() => itemModals[item.value].onOpen()}
300
w="100%"
301
>
302
{item.name}
303
</Button>
304
))}