LTS Code. Tried to add DMs *I failed

This commit is contained in:
root 2025-03-22 16:23:24 +00:00
parent e6e063366d
commit 77f611886b
7 changed files with 151 additions and 5 deletions

View File

@ -6,7 +6,22 @@ import { WSEvent } from './ws-event';
export default class implements WSEvent<'CHANNEL_CREATE'> {
public on = 'CHANNEL_CREATE' as const;
public async invoke(ws: WebSocket, client: Socket, { name, guildId, type }: WS.Params.ChannelCreate) {
public async invoke(ws: WebSocket, client: Socket, params: WS.Params.ChannelCreate) {
const { name, guildId, type, userIds } = params;
if (type === 'DM') {
if (!userIds) throw new TypeError('userIds required for DM creation');
const channel = await deps.channels.createDM(userIds);
return [{
emit: this.on,
to: userIds,
send: {
channel,
creatorId: ws.sessions.get(client.id),
},
}];
}
if (!name || !guildId || !type)
throw new TypeError('Not enough options were provided');
@ -23,4 +38,4 @@ export default class implements WSEvent<'CHANNEL_CREATE'> {
},
}];
}
}
}

View File

@ -7,6 +7,7 @@ import OverviewPage from './pages/overview-page';
import LogoutPage from './pages/auth/logout-page';
import PrivateRoute from './routing/private-route';
import NotFoundPage from './pages/not-found-page';
import DMPage from './pages/dm-page';
import { useEffect } from 'react';
import { useDispatch } from 'react-redux';
import { ready } from '../store/auth';
@ -38,6 +39,7 @@ export default function App() {
{/* Users must be logged in to use private routes. */}
<PrivateRoute exact path="/themes/:themeCode" component={ThemePage} />
<PrivateRoute exact path="/channels/@me" component={OverviewPage} />
<PrivateRoute exact path="/channels/@me/:channelId?" component={DMPage} />
<PrivateRoute exact path="/channels/:guildId/:channelId?" component={GuildPage} />
{/* This route is a catch-all for any other routes that don't exist. */}

View File

@ -11,7 +11,7 @@ import { Util } from '@acrd/types';
const TextBasedChannel: React.FunctionComponent = () => {
const dispatch = useDispatch();
const channel = useSelector((s: Store.AppState) => s.ui.activeChannel)!;
const guild = useSelector((s: Store.AppState) => s.ui.activeGuild)!;
const guild = useSelector((s: Store.AppState) => s.ui.activeGuild);
const messages = useSelector(getChannelMessages(channel.id));
const perms = usePerms();
const [cachedContent, setCachedContent] = useState<Util.Dictionary>({});
@ -41,7 +41,11 @@ const TextBasedChannel: React.FunctionComponent = () => {
dispatch(fetchMessages(channel.id, back));
}
const canRead = perms.canInChannel('READ_MESSAGES', guild.id, channel.id);
const canRead = channel.type === 'DM'
? true
: guild
? perms.canInChannel('READ_MESSAGES', guild.id, channel.id)
: false;
const LoadingIndicator: React.FunctionComponent = () => (
<>

View File

@ -0,0 +1,36 @@
import { useSelector } from 'react-redux';
import { Link } from 'react-router-dom';
import { getDMChannels } from '../../../store/channels';
import FoundUsername from '../../user/username';
import { ChannelTypes } from '@acrd/types';
const DMList: React.FunctionComponent = () => {
const channels = useSelector(getDMChannels());
const selfUser = useSelector((s: Store.AppState) => s.auth.user)!;
const users = useSelector((s: Store.AppState) => s.entities.users);
return (
<div className="channels px-2 w-60 bg-bg-secondary">
<div className="mt-2">
{channels.map(c => {
const otherUserId = (c as ChannelTypes.DM).userIds
.find(id => id !== selfUser.id);
const otherUser = users.find(u => u.id === otherUserId);
if (!otherUser) return null;
return (
<Link
key={c.id}
to={`/channels/@me/${c.id}`}
className="flex items-center rounded p-2 mb-2 hover:bg-bg-modifier-hover">
<FoundUsername user={otherUser} size="sm" />
</Link>
);
})}
</div>
</div>
);
}
export default DMList;

View File

@ -0,0 +1,58 @@
import { useDispatch, useSelector } from 'react-redux';
import AppNavbar from '../navigation/app-navbar';
import Sidebar from '../navigation/sidebar/sidebar';
import { Redirect, useParams } from 'react-router-dom';
import { actions as uiActions } from '../../store/ui';
import TextBasedChannel from '../channel/text-based-channel';
import { useEffect } from 'react';
import PageWrapper from './page-wrapper';
import { getDMChannel, createDM } from '../../store/channels';
import WSListener from '../ws-listener';
import DMList from '../navigation/sidebar/dm-list';
const DMPage: React.FunctionComponent = () => {
const { channelId }: any = useParams();
const dispatch = useDispatch();
const channel = useSelector(getDMChannel(channelId));
const users = useSelector((s: Store.AppState) => s.entities.users);
const selfUser = useSelector((s: Store.AppState) => s.auth.user)!;
const ui = useSelector((s: Store.AppState) => s.ui);
useEffect(() => {
if (!channel && channelId) {
const otherUser = users.find(u => u.id === channelId);
if (otherUser) {
dispatch(createDM(otherUser.id));
}
}
dispatch(uiActions.pageSwitched({ channel }));
}, [channel, channelId]);
if (!channel && !channelId)
return <Redirect to="/channels/@me" />;
const otherUser = users.find(u =>
channel?.type === 'DM' && channel.userIds.includes(u.id) && u.id !== selfUser.id);
return (
<PageWrapper pageTitle={otherUser?.username ?? 'Direct Messages'}>
<WSListener />
<div className="flex">
<Sidebar />
<div className="bg-bg-primary flex-1">
<AppNavbar />
<div
style={{ height: 'calc(100vh - 48px)' }}
className="flex">
{channel && ui.activeChannel && {
'DM': <TextBasedChannel />,
}[channel.type]}
<DMList />
</div>
</div>
</div>
</PageWrapper>
);
}
export default DMPage;

View File

@ -40,6 +40,7 @@ const GuildPage: React.FunctionComponent = () => {
className="flex">
{ui.activeChannel && {
'TEXT': <TextBasedChannel />,
'DM': <TextBasedChannel />,
'VOICE': <div className="w-full p-2">Add something cool here for voice channels?</div>,
}[channel.type]}
<MemberList />

View File

@ -67,6 +67,11 @@ export const getChannel = (id: string) => createSelector(
channels => channels.find(c => c.id === id),
);
export const getDMChannel = (id: string) => createSelector(
state => state.entities.channels,
channels => channels.find(c => c.id === id && c.type === 'DM')
);
export const getChannelByName = (guildId: string, name: string) => createSelector(
state => state.entities.channels,
channels => {
@ -80,4 +85,29 @@ export const getChannelUsers = (channelId: string) => createSelector(
const vc = channels.find(c => c.id === channelId) as ChannelTypes.Voice;
return vc.userIds.map(id => users.find(u => u.id === id))
},
);
);
export const getDMChannels = () => createSelector(
state => state.entities.channels,
channels => channels.filter(c => c.type === 'DM')
);
export const createDM = (userId: string) => (dispatch, getState: () => Store.AppState) => {
const selfUser = getState().auth.user!;
const existingDM = getState().entities.channels
.find(c => c.type === 'DM' &&
c.userIds.includes(selfUser.id) &&
c.userIds.includes(userId));
if (existingDM) return;
dispatch(api.wsCallBegan({
event: 'CHANNEL_CREATE',
data: {
type: 'DM',
userIds: [selfUser.id, userId],
name: 'DM',
guildId: '0'
} as unknown as WS.Params.ChannelCreate,
}));
}