Skip to content

Commit 9d3f703

Browse files
committed
feat: working channel selects
1 parent 2f23a72 commit 9d3f703

19 files changed

Lines changed: 545 additions & 78 deletions

File tree

apps/website/src/app/dashboard/[id]/ama/amas/_components/AMASessionsList.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { client } from '@/data/client';
88

99
export function AMASessionsList() {
1010
const params = useParams<{ id: string }>();
11-
const { data: sessions } = client.guilds.ama.useAMAs(params.id, { include_ended: false });
11+
const { data: sessions } = client.guilds.ama.useAMAs(params.id, { include_ended: 'false' });
1212
const searchParams = useSearchParams();
1313

1414
const searchQuery = searchParams.get('search') ?? '';

apps/website/src/app/dashboard/[id]/ama/amas/layout.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ export default async function AMAsLayout({ children, params }: LayoutProps<'/das
55
const { id } = await params;
66

77
return (
8-
<HydrationBoundary state={await server.guilds(id).ama.amas({ include_ended: false }).prefetch()}>
8+
<HydrationBoundary state={await server.guilds(id).ama.amas({ include_ended: 'false' }).prefetch()}>
99
{children}
1010
</HydrationBoundary>
1111
);

apps/website/src/app/dashboard/[id]/ama/amas/new/_components/CreateAMAForm.tsx

Lines changed: 64 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
'use client';
22

33
import type { CreateAMABody } from '@chatsift/api';
4+
import { ChannelType } from 'discord-api-types/v10';
45
import { useParams, useRouter } from 'next/navigation';
56
import { useState } from 'react';
67
import { NormalPromptFields } from './NormalPromptFields';
78
import { PromptModeToggle } from './PromptModeToggle';
89
import { RawPromptField } from './RawPromptField';
9-
import { SnowflakeInput } from './SnowflakeInput';
1010
import { Button } from '@/components/common/Button';
11+
import { ChannelSelect, threadTypes } from '@/components/common/ChannelSelect';
12+
import { Skeleton } from '@/components/common/Skeleton';
1113
import { client } from '@/data/client';
1214
import { APIError } from '@/utils/fetcher';
1315

@@ -29,20 +31,6 @@ interface FormData {
2931

3032
type FormErrors = Partial<Record<keyof FormData, string>>;
3133

32-
const SNOWFLAKE_REGEX = /^\d{17,20}$/;
33-
34-
function validateSnowflake(value: string, required: boolean = true): string | undefined {
35-
if (!value) {
36-
return required ? 'This field is required' : undefined;
37-
}
38-
39-
if (!SNOWFLAKE_REGEX.test(value)) {
40-
return 'Must be a valid Discord ID (17-20 digits)';
41-
}
42-
43-
return undefined;
44-
}
45-
4634
function validateURL(value: string): string | undefined {
4735
if (!value) return undefined;
4836

@@ -75,6 +63,7 @@ export function CreateAMAForm() {
7563
});
7664
const [errors, setErrors] = useState<FormErrors>({});
7765

66+
const { data: guildInfo } = client.guilds.useInfo(guildId, { for_bot: 'AMA', force_fresh: 'false' });
7867
const createAMA = client.guilds.ama.createAMA(guildId);
7968

8069
const validateForm = (): boolean => {
@@ -86,21 +75,13 @@ export function CreateAMAForm() {
8675
newErrors.title = 'Title must be at most 255 characters';
8776
}
8877

89-
const answersChannelError = validateSnowflake(formData.answersChannelId);
90-
if (answersChannelError) newErrors.answersChannelId = answersChannelError;
91-
92-
const promptChannelError = validateSnowflake(formData.promptChannelId);
93-
if (promptChannelError) newErrors.promptChannelId = promptChannelError;
94-
95-
// Optional snowflake fields
96-
const modQueueError = validateSnowflake(formData.modQueueId, false);
97-
if (modQueueError) newErrors.modQueueId = modQueueError;
98-
99-
const flaggedQueueError = validateSnowflake(formData.flaggedQueueId, false);
100-
if (flaggedQueueError) newErrors.flaggedQueueId = flaggedQueueError;
78+
if (!formData.answersChannelId) {
79+
newErrors.answersChannelId = 'This field is required';
80+
}
10181

102-
const guestQueueError = validateSnowflake(formData.guestQueueId, false);
103-
if (guestQueueError) newErrors.guestQueueId = guestQueueError;
82+
if (!formData.promptChannelId) {
83+
newErrors.promptChannelId = 'This field is required';
84+
}
10485

10586
// Normal mode validations
10687
if (promptMode === 'normal') {
@@ -176,12 +157,31 @@ export function CreateAMAForm() {
176157
setTimeout(() => formatJSON(), 50);
177158
};
178159

160+
if (!guildInfo) {
161+
return (
162+
<div className="mt-8 space-y-6">
163+
<div className="space-y-4">
164+
<Skeleton className="h-7 w-48" />
165+
<Skeleton className="h-10 w-full" />
166+
<Skeleton className="h-10 w-full" />
167+
<Skeleton className="h-10 w-full" />
168+
<Skeleton className="h-10 w-full" />
169+
<Skeleton className="h-10 w-full" />
170+
<Skeleton className="h-10 w-full" />
171+
</div>
172+
<div className="space-y-4">
173+
<Skeleton className="h-7 w-56" />
174+
<Skeleton className="h-32 w-full" />
175+
</div>
176+
</div>
177+
);
178+
}
179+
179180
return (
180181
<form className="mt-8 space-y-6" onSubmit={handleSubmit}>
181182
{/* Base Fields */}
182183
<div className="space-y-4">
183184
<h2 className="text-xl font-medium text-primary dark:text-primary-dark">Session Details</h2>
184-
185185
<div>
186186
<label className="block text-sm font-medium text-secondary dark:text-secondary-dark mb-2" htmlFor="title">
187187
Title *
@@ -197,46 +197,56 @@ export function CreateAMAForm() {
197197
/>
198198
{errors.title && <p className="mt-1 text-sm text-misc-danger">{errors.title}</p>}
199199
</div>
200-
201-
<SnowflakeInput
200+
<ChannelSelect
201+
allowedTypes={[ChannelType.GuildText, ChannelType.GuildAnnouncement, ...threadTypes]}
202+
channels={guildInfo.channels}
202203
error={errors.answersChannelId}
203-
id="answersChannelId"
204-
label="Answers Channel ID"
204+
label="Answers Channel"
205205
onChange={(value) => setFormData({ ...formData, answersChannelId: value })}
206+
placeholder="Select the channel where answers will be posted"
206207
required
208+
selectedId="answersChannelId"
207209
value={formData.answersChannelId}
208-
/>
209-
210-
<SnowflakeInput
210+
/>{' '}
211+
<ChannelSelect
212+
allowedTypes={[ChannelType.GuildText, ChannelType.GuildAnnouncement]}
213+
channels={guildInfo.channels}
211214
error={errors.promptChannelId}
212-
id="promptChannelId"
213-
label="Prompt Channel ID"
215+
label="Prompt Channel"
214216
onChange={(value) => setFormData({ ...formData, promptChannelId: value })}
217+
placeholder="Select the channel where the prompt will be posted"
215218
required
219+
selectedId="promptChannelId"
216220
value={formData.promptChannelId}
217-
/>
218-
219-
<SnowflakeInput
221+
/>{' '}
222+
<ChannelSelect
223+
allowedTypes={[ChannelType.GuildText, ChannelType.GuildAnnouncement]}
224+
channels={guildInfo.channels}
220225
error={errors.modQueueId}
221-
id="modQueueId"
222-
label="Mod Queue ID (optional)"
226+
label="Mod Queue (optional)"
223227
onChange={(value) => setFormData({ ...formData, modQueueId: value })}
228+
placeholder="Select a channel for mod queue"
229+
selectedId="modQueueId"
224230
value={formData.modQueueId}
225-
/>
226-
227-
<SnowflakeInput
231+
/>{' '}
232+
<ChannelSelect
233+
allowedTypes={[ChannelType.GuildText, ChannelType.GuildAnnouncement]}
234+
channels={guildInfo.channels}
228235
error={errors.flaggedQueueId}
229-
id="flaggedQueueId"
230-
label="Flagged Queue ID (optional)"
236+
label="Flagged Queue (optional)"
231237
onChange={(value) => setFormData({ ...formData, flaggedQueueId: value })}
238+
placeholder="Select a channel for flagged questions"
239+
selectedId="flaggedQueueId"
232240
value={formData.flaggedQueueId}
233-
/>
234-
235-
<SnowflakeInput
241+
/>{' '}
242+
<ChannelSelect
243+
allowedTypes={[ChannelType.GuildText, ChannelType.GuildAnnouncement]}
244+
channels={guildInfo.channels}
236245
error={errors.guestQueueId}
237-
id="guestQueueId"
238-
label="Guest Queue ID (optional)"
246+
label="Guest Queue (optional)"
239247
onChange={(value) => setFormData({ ...formData, guestQueueId: value })}
248+
placeholder="Select a channel for guest queue"
249+
selectedId="guestQueueId"
240250
value={formData.guestQueueId}
241251
/>
242252
</div>
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
'use client';
2+
3+
import type { BotId } from '@chatsift/core';
4+
import { useParams } from 'next/navigation';
5+
import { Button } from '@/components/common/Button';
6+
import { SvgRefresh } from '@/components/icons/SvgRefresh';
7+
import { client } from '@/data/client';
8+
9+
interface RefreshServerDataButtonProps {
10+
readonly for_bot: BotId;
11+
}
12+
13+
export function RefreshServerDataButton({ for_bot }: RefreshServerDataButtonProps) {
14+
const params = useParams<{ id: string }>();
15+
const { id: guildId } = params;
16+
17+
const { refetch, isLoading } = client.guilds.useInfo(guildId, { for_bot, force_fresh: 'true' });
18+
19+
return (
20+
<Button
21+
className="border border-solid border-on-primary px-4 py-2 text-secondary dark:border-on-primary-dark dark:text-secondary-dark"
22+
isDisabled={isLoading}
23+
onPress={async () => {
24+
await refetch();
25+
}}
26+
>
27+
<SvgRefresh />
28+
Refresh Server Data
29+
</Button>
30+
);
31+
}

apps/website/src/app/dashboard/[id]/ama/amas/new/page.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
import { DashboardCrumbs } from '../../../../_components/DashboardCrumbs';
22
import { CreateAMAForm } from './_components/CreateAMAForm';
3+
import { RefreshServerDataButton } from './_components/RefreshServerDataButton';
34
import { Heading } from '@/components/common/Heading';
45

56
export default function NewAMAPage() {
67
return (
78
<div className="flex flex-col [&:not]:first-of-type:mt-8 [&>*]:first-of-type:mb-4">
89
<DashboardCrumbs />
9-
<Heading subtitle="Create a new AMA session" title="AMA sessions" />
10+
<div className="flex flex-col items-start justify-between gap-4 md:flex-row md:items-center">
11+
<Heading subtitle="Create a new AMA session" title="AMA sessions" />
12+
<RefreshServerDataButton for_bot="AMA" />
13+
</div>
1014
<CreateAMAForm />
1115
</div>
1216
);

apps/website/src/app/dashboard/_components/RefreshGuildsButton.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { SvgRefresh } from '@/components/icons/SvgRefresh';
55
import { client } from '@/data/client';
66

77
export function RefreshGuildsButton() {
8-
const { refetch, isLoading } = client.auth.useMe({ force_fresh: true });
8+
const { refetch, isLoading } = client.auth.useMe({ force_fresh: 'true' });
99

1010
return (
1111
<Button

0 commit comments

Comments
 (0)