Skip to content

Commit 4a32379

Browse files
authored
Merge pull request #51 from FrostCord/FROS-Direct-Messaging
Direct Messaging
2 parents 525c4a1 + afe543c commit 4a32379

19 files changed

Lines changed: 332 additions & 91 deletions

components/forms/MiniProfile.tsx

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
import { getServerProfileForUser } from '@/services/profile.service';
2-
import { getServerIdFromMessageId } from '@/services/server.service';
3-
import { Role, ServerUser, ServerUserProfile, User } from '@/types/dbtypes';
4-
import { useSupabaseClient } from '@supabase/auth-helpers-react';
5-
import { memo, useEffect, useState } from 'react';
1+
import { useSideBarOptionSetter } from '@/context/SideBarOptionCtx';
2+
import { getOrCreateDMChannel } from '@/lib/DMChannelHelper';
3+
import { useDMChannels, useSetChannel } from '@/lib/store';
4+
import { createMessage } from '@/services/message.service';
5+
import { Role, ServerUser, User } from '@/types/dbtypes';
6+
import { useSupabaseClient, useUser } from '@supabase/auth-helpers-react';
7+
import { memo, } from 'react';
68
import UserIcon from '../icons/UserIcon';
79
import { SearchBar } from './Styles';
810

@@ -16,6 +18,12 @@ function WrappedComponent({
1618
server_user: ServerUser;
1719
roles: Role[];
1820
}) {
21+
const user = useUser();
22+
const supabase = useSupabaseClient();
23+
const dmChannels = useDMChannels();
24+
const setChannel = useSetChannel();
25+
const setSideBarOption = useSideBarOptionSetter();
26+
1927
return (
2028
<div className="flex flex-col space-y-2 items-center p-3">
2129
<UserIcon user={profile} className="!w-9 !h-9" />
@@ -42,13 +50,37 @@ function WrappedComponent({
4250
))}
4351
</div>
4452
<hr />
45-
<form>
53+
{profile.id !== user?.id && (<form>
4654
<input
4755
type="text"
4856
className={`${SearchBar('bg-grey-900')}`}
49-
placeholder={`Message @${profile.username}`}
57+
placeholder={`Message ${profile.username}`}
58+
onKeyDown={async (e) => {
59+
if (e.key === 'Enter') {
60+
e.preventDefault();
61+
const dmChannel = await getOrCreateDMChannel(
62+
supabase,
63+
profile,
64+
dmChannels
65+
);
66+
67+
if (dmChannel) {
68+
await createMessage(
69+
supabase,
70+
{
71+
content: (e.target as HTMLInputElement).value,
72+
channel_id: dmChannel.channel_id,
73+
profile_id: user!.id,
74+
}
75+
);
76+
77+
setSideBarOption('friends');
78+
setChannel(dmChannel);
79+
}
80+
}
81+
}}
5082
/>
51-
</form>
83+
</form>)}
5284
</div>
5385
);
5486
}

components/home/Chat.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ export default function Chat() {
5050
<div className="border-t-2 mx-5 border-grey-700 flex "></div>
5151

5252
<div
53-
className={`${styles.messagesParent} flex flex-col p-5 bg-grey-800 overflow-y-scroll`}
53+
className={`${styles.messagesParent} flex flex-col p-5 bg-grey-800 overflow-y-auto`}
5454
>
5555
<div className={`${styles.messageList} flex flex-col `}>
5656
{messages &&

components/home/DMessageList.tsx

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,55 @@
1+
import { Channel, DMChannelWithRecipient } from '@/types/dbtypes';
2+
import UserIcon from '../icons/UserIcon';
3+
import styles from '@/styles/Chat.module.css';
4+
import { useDMChannels, useSetChannel } from '@/lib/store';
5+
6+
function mapToComponentArray(
7+
_map: Map<string, DMChannelWithRecipient>,
8+
setChannel: (channel: Channel) => void
9+
) {
10+
const rv = [];
11+
12+
for (const [_, value] of _map) {
13+
rv.push(
14+
<div
15+
key={value.channel_id}
16+
className="flex items-center p-2 w-full hover:bg-grey-700 rounded-md transition-colors"
17+
onClick={() => {
18+
setChannel({
19+
channel_id: value.channel_id,
20+
server_id: value.server_id,
21+
name: value.recipient.username,
22+
is_media: false,
23+
description: null,
24+
created_at: null
25+
});
26+
}}
27+
>
28+
<UserIcon user={value.recipient} className="!w-6 !h-6"/>
29+
<div>{value.recipient.username}</div>
30+
</div>
31+
);
32+
}
33+
34+
return rv;
35+
}
136
export default function DMessageList() {
2-
return <>DM List...</>;
37+
const setChannel = useSetChannel();
38+
const dmChannels = useDMChannels();
39+
console.table(dmChannels);
40+
41+
return (
42+
<>
43+
<div className={`${styles.chatHeader} px-5 pt-5 mb-3`}>
44+
<div className="flex flex-row items-center space-x-3">
45+
<h1 className="text-3xl font-semibold tracking-wide">
46+
Directs
47+
</h1>
48+
</div>
49+
</div>
50+
<div className="border-t-2 mx-5 border-grey-700 flex flex-col pt-3">
51+
{ mapToComponentArray(dmChannels, setChannel) }
52+
</div>
53+
</>
54+
);
355
}

components/home/FriendsList.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { useRelations } from '@/lib/store';
22
import styles from '@/styles/Chat.module.css';
33
import { DetailedProfileRelation, ProfileRelationshipType } from '@/types/dbtypes';
4-
import { useSupabaseClient } from '@supabase/auth-helpers-react';
54
import { useEffect, useState } from 'react';
65
import { FriendRequestItem } from './FriendRequestItem';
76
import { FriendsListItem } from './FriendsListItem';

components/home/FriendsListItem.tsx

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,14 @@ import VerticalSettingsIcon from '../icons/VerticalSettingsIcon';
55
import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
66
import { removeFriendOrRequest } from '@/services/friends.service';
77
import { useSupabaseClient } from '@supabase/auth-helpers-react';
8+
import { useDMChannels, useSetChannel } from '@/lib/store';
9+
import { getOrCreateDMChannel } from '@/lib/DMChannelHelper';
810

911
export function FriendsListItem({ relation }: { relation: DetailedProfileRelation }) {
1012
const supabase = useSupabaseClient();
13+
const setChannel = useSetChannel();
14+
const dmChannels = useDMChannels();
15+
1116
return (
1217
<div key={relation.id} className="flex flex-row items-center space-x-3 p-2 w-full hover:bg-grey-900 rounded-md transition-colors">
1318
<UserIcon user={relation.target_profile} />
@@ -17,8 +22,16 @@ export function FriendsListItem({ relation }: { relation: DetailedProfileRelatio
1722
<div className='flex flex-row space-x-2'>
1823
<button
1924
className="rounded-md p-3 border-2 border-gray-500 hover:bg-gray-500"
20-
onClick={() => {
21-
console.log('DM');
25+
onClick={async () => {
26+
const dmChannel = await getOrCreateDMChannel(
27+
supabase,
28+
relation.target_profile,
29+
dmChannels
30+
);
31+
32+
if (dmChannel) {
33+
setChannel(dmChannel);
34+
}
2235
}}
2336
>
2437
<ChannelMessageIcon />

components/home/MessageHeader.tsx

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@ import UserIcon from '../icons/UserIcon';
55
import * as ContextMenu from '@radix-ui/react-context-menu';
66
import { useSupabaseClient, useUser } from '@supabase/auth-helpers-react';
77
import { acceptFriendRequest, removeFriendOrRequest, sendFriendRequest } from '@/services/friends.service';
8-
import { useRelations } from '@/lib/store';
8+
import { useChannel, useDMChannels, useRelations, useSetChannel } from '@/lib/store';
9+
import { getOrCreateDMChannel } from '@/lib/DMChannelHelper';
10+
import { useSideBarOptionSetter } from '@/context/SideBarOptionCtx';
911

1012
export function MessageHeader({
1113
profile,
1214
server_user,
13-
message_id,
1415
message_color,
1516
display_time,
1617
edited,
@@ -27,6 +28,10 @@ export function MessageHeader({
2728
const currentUser = useUser();
2829
const supabase = useSupabaseClient();
2930
const relation = useRelations().find((relation) => relation.target_profile.id === profile.id);
31+
const setChannel = useSetChannel();
32+
const _currentChannel = useChannel();
33+
const directMessages = useDMChannels();
34+
const setSideBarOption = useSideBarOptionSetter();
3035

3136
return (
3237
<ContextMenu.Root>
@@ -99,6 +104,22 @@ export function MessageHeader({
99104
: 'Remove friend'
100105
}
101106
</ContextMenu.Item>
107+
<ContextMenu.Item
108+
className='ContextMenuItem'
109+
onClick={async () => {
110+
const dmChannel = await getOrCreateDMChannel(
111+
supabase,
112+
profile,
113+
directMessages
114+
);
115+
116+
setSideBarOption('friends');
117+
setChannel(dmChannel);
118+
}}
119+
hidden={directMessages.get(profile.id) && directMessages.get(profile.id)!.channel_id === _currentChannel?.channel_id}
120+
>
121+
Message {profile.username}
122+
</ContextMenu.Item>
102123
</ContextMenu.Content>
103124
)}
104125
</ContextMenu.Root>

components/home/NavBar.tsx

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { useSideBarOptionSetter } from '@/context/SideBarOptionCtx';
22
import FriendsIcon from '@/components/icons/FriendsIcon';
33
import ServersIcon from '@/components/icons/ServersIcon';
4-
import MessagesIcon from '@/components/icons/MessagesIcon';
54
import { useState } from 'react';
65
import { useSetChannel } from '@/lib/store';
76

@@ -12,8 +11,6 @@ export default function NavBar({ type }: { type: 'vertical' | 'bottom' }) {
1211

1312
const [friendsHover, setFriendsHover] = useState(false);
1413
const [serversHover, setServersHover] = useState(false);
15-
const [messagesHover, setMessagesHover] = useState(false);
16-
1714
const bottomStyles = 'hover:cursor-pointer flex justify-center items-center';
1815
const verticalStyles = 'hover:cursor-pointer flex justify-center py-5';
1916

@@ -49,12 +46,11 @@ export default function NavBar({ type }: { type: 'vertical' | 'bottom' }) {
4946
>
5047
<ServersIcon
5148
hovered={serversHover}
52-
server={null}
5349
width={6}
5450
height={6}
5551
/>
5652
</div>
57-
<div
53+
{/* <div
5854
className={`${
5955
type == 'bottom'
6056
? `${bottomStyles} col-start-8 col-end-10`
@@ -68,7 +64,7 @@ export default function NavBar({ type }: { type: 'vertical' | 'bottom' }) {
6864
onMouseLeave={() => setMessagesHover(false)}
6965
>
7066
<MessagesIcon hovered={messagesHover} width={6} height={6} />
71-
</div>
67+
</div> */}
7268
</>
7369
);
7470
}

components/home/RenderDesktopView.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,9 @@ export function renderContent(
4141
case 'servers':
4242
if (channel) return [<ServerList key={1} />, <Chat key={2} />];
4343
return [<ServerList key={1} />, <DefaultTest key={2} />];
44-
case 'messages':
45-
if (channel) return [<DMessageList key={1} />, <Chat key={2} />];
46-
return [<DMessageList key={1} />, <DefaultTest key={2} />];
44+
// case 'messages':
45+
// if (channel) return [<DMessageList key={1} />, <Chat key={2} />];
46+
// return [<DMessageList key={1} />, <DefaultTest key={2} />];
4747
default:
4848
return [<FriendsList key={1} />, <DefaultTest key={2} />];
4949
}

components/icons/ServersIcon.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ export default function ServersIcon({
55
hovered = false,
66
className = 'w-6 h-6',
77
}: {
8-
server: Server;
98
hovered: boolean;
9+
server?: Server;
1010
width?: number;
1111
height?: number;
1212
className?: string;

hooks/useRealtimeStore.ts

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import {
1515
useServers,
1616
useUpdateMessage,
1717
useUpdateServer,
18+
useAddDMChannel,
19+
useGetDMChannels,
1820
} from '@/lib/store';
1921
import { useEffect } from 'react';
2022
import { Database } from '@/types/database.supabase';
@@ -43,6 +45,8 @@ export function useRealtimeStore(supabase: SupabaseClient<Database>) {
4345
const removeRelation = useRemoveRelation();
4446
const getRelations = useGetRelations();
4547

48+
const addDMChannel = useAddDMChannel();
49+
const getDMChannels = useGetDMChannels();
4650
const user = useUser();
4751

4852
//TODO: CASCADE DELETE ICONS
@@ -87,6 +91,7 @@ export function useRealtimeStore(supabase: SupabaseClient<Database>) {
8791
)
8892
.subscribe();
8993

94+
// START: Entrypoint for always active listeners
9095
supabase
9196
.channel('servers')
9297
.on<Server>(
@@ -136,6 +141,19 @@ export function useRealtimeStore(supabase: SupabaseClient<Database>) {
136141
removeRelation(supabase, payload.old.id as number);
137142
}
138143
)
144+
.on<Server>(
145+
'postgres_changes',
146+
{
147+
event: 'INSERT',
148+
schema: 'public',
149+
table: 'servers',
150+
filter: 'is_dm=eq.true',
151+
},
152+
async (payload) => {
153+
console.log('DM server insert event');
154+
addDMChannel(supabase, payload.new.id);
155+
}
156+
)
139157
.subscribe();
140158

141159
supabase
@@ -159,7 +177,18 @@ export function useRealtimeStore(supabase: SupabaseClient<Database>) {
159177

160178
// add return right here!
161179
// return serverUsersListener.unsubscribe();
162-
}, [addServer, supabase, user, getServers, servers, updateServer, addRelation, updateRelation, removeRelation]);
180+
}, [
181+
addServer,
182+
supabase,
183+
user,
184+
getServers,
185+
servers,
186+
updateServer,
187+
addRelation,
188+
updateRelation,
189+
removeRelation,
190+
addDMChannel
191+
]);
163192

164193
useEffect(() => {
165194
if (addMessage && getUserPerms && channel) {
@@ -245,5 +274,6 @@ export function useRealtimeStore(supabase: SupabaseClient<Database>) {
245274

246275
useEffect(() => {
247276
getRelations(supabase);
248-
}, [getRelations, supabase]);
277+
getDMChannels(supabase);
278+
}, [getRelations, getDMChannels, supabase]);
249279
}

0 commit comments

Comments
 (0)