Skip to content

Commit 33a22f4

Browse files
committed
add channel modal
1 parent d2f99cd commit 33a22f4

5 files changed

Lines changed: 274 additions & 6 deletions

File tree

components/forms/AddChannel.tsx

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
import { Input } from './Styles';
2+
import styles from '@/styles/Components.module.css';
3+
4+
import { Dispatch, SetStateAction, useState } from 'react';
5+
import {
6+
Control,
7+
FieldErrorsImpl,
8+
UseFormRegister,
9+
Controller,
10+
} from 'react-hook-form';
11+
import ChannelMessageIcon from '@/components/icons/ChannelMessageIcon';
12+
13+
export default function AddChannel({
14+
register,
15+
errors,
16+
control,
17+
serverError,
18+
showDesc,
19+
setShowDesc,
20+
channelType,
21+
setChannelType,
22+
}: {
23+
register: UseFormRegister<{
24+
description?: string | undefined;
25+
isMedia?: boolean | undefined;
26+
name: string;
27+
}>;
28+
errors: Partial<
29+
FieldErrorsImpl<{
30+
description: string;
31+
isMedia: NonNullable<boolean | undefined>;
32+
name: string;
33+
}>
34+
>;
35+
control: Control<
36+
{
37+
description?: string | undefined;
38+
isMedia?: boolean | undefined;
39+
name: string;
40+
},
41+
any
42+
>;
43+
serverError: string;
44+
showDesc: boolean;
45+
setShowDesc: Dispatch<SetStateAction<boolean>>;
46+
channelType: 'media' | 'text';
47+
setChannelType: Dispatch<SetStateAction<'media' | 'text'>>;
48+
}) {
49+
return (
50+
<form
51+
className="flex flex-col w-12 mb-1 mx-6"
52+
onSubmit={(e) => e.preventDefault()}
53+
>
54+
{serverError ? (
55+
<span className="my-2 text-red-700 text-sm font-bold">
56+
{serverError}
57+
</span>
58+
) : (
59+
''
60+
)}
61+
62+
<div className="flex flex-col mt-5">
63+
<div className="font-semibold tracking-wider">Channel Name</div>
64+
<input
65+
className={`${Input('bg-grey-700')} mt-2 ${styles.input}`}
66+
type="text"
67+
placeholder="Enter channel name"
68+
{...register('name')}
69+
/>
70+
{errors.name && (
71+
<p className="text-red-700 mt-2 text-sm font-bold">
72+
{errors.name.message}
73+
</p>
74+
)}
75+
<div className="font-semibold tracking-wider mt-4">Channel Type</div>
76+
<div className="flex-col flex">
77+
<Controller
78+
control={control}
79+
name="isMedia"
80+
render={({ field: { onChange, onBlur, value, ref } }) => (
81+
<>
82+
<div
83+
className={`flex ${
84+
channelType == 'text' ? 'bg-grey-600' : 'bg-grey-700'
85+
} rounded-2xl py-2 pl-6 items-center`}
86+
>
87+
<ChannelMessageIcon />
88+
<label className="ml-1 flex items-center w-full justify-between hover:cursor-pointer">
89+
Text{' '}
90+
<input
91+
className="mr-4"
92+
type="radio"
93+
onBlur={onBlur}
94+
onChange={() => onChange(false)}
95+
onClick={() => setChannelType('text')}
96+
checked={value === false}
97+
ref={ref}
98+
/>
99+
</label>
100+
</div>
101+
<div
102+
className={`flex ${
103+
channelType == 'media' ? 'bg-grey-600' : 'bg-grey-700'
104+
} rounded-2xl py-2 pl-6 mt-2 items-center`}
105+
>
106+
<ChannelMessageIcon />
107+
<label className="ml-1 flex items-center w-full justify-between hover:cursor-pointer">
108+
Voice{' '}
109+
<input
110+
className="mr-4 "
111+
type="radio"
112+
onBlur={onBlur}
113+
onChange={() => onChange(true)}
114+
onClick={() => setChannelType('media')}
115+
checked={value === true}
116+
ref={ref}
117+
/>
118+
</label>
119+
</div>
120+
</>
121+
)}
122+
/>
123+
</div>
124+
{showDesc ? (
125+
<div className="mt-4">
126+
<div className="font-semibold tracking-wider">Description</div>
127+
<input
128+
className={`${Input('bg-grey-700')} mt-2 ${styles.input}`}
129+
type="text"
130+
placeholder="Enter a description"
131+
{...register('description')}
132+
/>
133+
{errors.description && (
134+
<p className="text-red-700 mt-2 text-sm font-bold">
135+
{errors.description.message}
136+
</p>
137+
)}
138+
</div>
139+
) : (
140+
<div
141+
className={`${styles.description} mt-4 text-frost-600 font-bold tracking-wide hover:cursor-pointer hover:text-frost-500 underline underline-offset-2`}
142+
onClick={() => setShowDesc(true)}
143+
>
144+
Add a description{' '}
145+
</div>
146+
)}
147+
</div>
148+
</form>
149+
);
150+
}

components/forms/AddServer.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,7 @@ import {
1010
useEffect,
1111
} from 'react';
1212
import Image from 'next/image';
13-
import { createServerSchema, CreateServerInput } from '@/types/client/server';
1413
import { FieldErrorsImpl, useForm, UseFormRegister } from 'react-hook-form';
15-
import { zodResolver } from '@hookform/resolvers/zod';
1614

1715
export default function AddServer({
1816
serverImage,
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import AddChannel from '@/components/forms/AddChannel';
2+
import Modal from '@/components/home/Modal';
3+
import {
4+
CreateChannelInput,
5+
createChannelSchema,
6+
} from '@/types/client/channel';
7+
import { zodResolver } from '@hookform/resolvers/zod';
8+
import { Dispatch, SetStateAction, useRef, useState } from 'react';
9+
import { useForm } from 'react-hook-form';
10+
import { useSupabaseClient } from '@supabase/auth-helpers-react';
11+
12+
export default function AddChannelModal({
13+
showModal,
14+
setShowModal,
15+
serverId,
16+
}: {
17+
showModal: boolean;
18+
setShowModal: Dispatch<SetStateAction<boolean>>;
19+
serverId: number;
20+
}) {
21+
const addChannelRef = useRef<HTMLDialogElement>(null);
22+
23+
const [serverError, setServerError] = useState<string>('');
24+
const [showDesc, setSetShowDesc] = useState<boolean>(false);
25+
const [channelType, setChannelType] = useState<'media' | 'text'>('text');
26+
27+
const supabase = useSupabaseClient();
28+
29+
const {
30+
register,
31+
handleSubmit,
32+
reset,
33+
control,
34+
formState: { errors },
35+
} = useForm<CreateChannelInput>({
36+
resolver: zodResolver(createChannelSchema),
37+
mode: 'onSubmit',
38+
defaultValues: {
39+
name: '',
40+
description: '',
41+
isMedia: false,
42+
},
43+
});
44+
45+
const onSubmit = async (formData: CreateChannelInput) => {
46+
//
47+
console.log(serverId);
48+
49+
// setChannelType('text');
50+
};
51+
52+
return (
53+
<Modal
54+
modalRef={addChannelRef}
55+
showModal={showModal}
56+
title={'Create a new Channel'}
57+
onKeyDown={(e) => {
58+
if (e.key === 'Enter') {
59+
handleSubmit(onSubmit)();
60+
}
61+
}}
62+
buttons={
63+
<>
64+
<div
65+
className="hover:underline hover:cursor-pointer"
66+
onClick={() => {
67+
setShowModal(false);
68+
setSetShowDesc(false);
69+
setChannelType('text');
70+
reset();
71+
addChannelRef.current?.close();
72+
}}
73+
>
74+
Cancel
75+
</div>
76+
<div
77+
className="bg-frost-500 py-2 px-5 rounded-lg hover:cursor-pointer hover:bg-frost-700"
78+
onClick={() => {
79+
handleSubmit(onSubmit)();
80+
}}
81+
>
82+
Submit
83+
</div>
84+
</>
85+
}
86+
>
87+
<AddChannel
88+
register={register}
89+
errors={errors}
90+
serverError={serverError}
91+
showDesc={showDesc}
92+
setShowDesc={setSetShowDesc}
93+
control={control}
94+
channelType={channelType}
95+
setChannelType={setChannelType}
96+
/>
97+
</Modal>
98+
);
99+
}

components/home/ServerList.tsx

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,17 @@ import Server from '@/components/home/Server';
55
import { useSupabaseClient, useUser } from '@supabase/auth-helpers-react';
66
import styles from '@/styles/Servers.module.css';
77
import AddServerModal from '@/components/home/AddServerModal';
8+
import AddChannelModal from '@/components/home/AddChannelModal';
89
import { useGetServers, useServers } from '@/lib/store';
910
import { Tooltip } from 'react-tooltip';
1011
import PlusIcon from '@/components/icons/PlusIcon';
1112

1213
export default function ServerList() {
13-
//TODO: fetch server_users via profile id, select server_id -> fetch channels via this server_id && fetch servers with server_id
14-
//This should at minimum return server_id, author_id (serveruser id), server name, channel id, channel name
15-
1614
//TODO: Display default page (when user belongs to and has no servers)
15+
//TODO: Only show add channel if user has perms for it
1716

1817
const [showAddServer, setShowAddServer] = useState(false);
18+
const [showAddChannelModal, setShowAddChannelModal] = useState(false);
1919
const [expanded, setExpanded] = useState(0);
2020

2121
const user = useUser();
@@ -40,6 +40,11 @@ export default function ServerList() {
4040
showModal={showAddServer}
4141
setShowModal={setShowAddServer}
4242
/>
43+
<AddChannelModal
44+
showModal={showAddChannelModal}
45+
setShowModal={setShowAddChannelModal}
46+
serverId={expanded}
47+
/>
4348
<div className="flex pb-3 items-center border-b-2 border-grey-700">
4449
<h1 className=" text-5xl font-bold tracking-wide">Servers</h1>
4550
<div className="pt-2 ml-3 relative">
@@ -112,7 +117,12 @@ export default function ServerList() {
112117
clickable
113118
openOnClick={true}
114119
>
115-
<div className="flex justify-center items-center hover:text-grey-300 cursor-pointer">
120+
<div
121+
className="flex justify-center items-center hover:text-grey-300 cursor-pointer"
122+
onClick={() => {
123+
setShowAddChannelModal(true);
124+
}}
125+
>
116126
<PlusIcon width={5} height={5} />
117127
<span className="ml-1">New channel</span>
118128
</div>

types/client/channel.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { object, TypeOf, z } from 'zod';
2+
3+
export const createChannelSchema = object({
4+
name: z
5+
.string({ required_error: 'Channel name is required' })
6+
.min(3, { message: 'Must be at least 3 characters' }),
7+
description: z.string().optional(),
8+
isMedia: z.boolean().optional(),
9+
});
10+
11+
export type CreateChannelInput = TypeOf<typeof createChannelSchema>;

0 commit comments

Comments
 (0)