teemant-react/src/components/ClientView/ClientView.tsx

182 lines
4.9 KiB
TypeScript

import { IIRCLine, IRCConnectionEvents, NickListEvents } from '@icynet/irclib';
import { useEffect, useReducer } from 'react';
import { IRCConnectionWrapper, IRCManager } from '../../lib/irc-manager';
import { BufferActionKind, BufferType } from '../../lib/client-view.types';
import { ClientViewReducer, getBuffer } from '../../lib/client.reducer';
import { MessageBufferWrapper } from '../MessageBufferWrapper/MessageBufferWrapper';
import { ViewTabs } from '../ViewTabs/ViewTabs';
export const ClientView = ({ manager }: { manager: IRCManager }) => {
const [state, dispatch] = useReducer(ClientViewReducer, {
buffers: [],
activeIndex: 0,
});
useEffect(() => {
const firstConnection = manager.connections[0];
dispatch({
type: BufferActionKind.AddBuffer,
payload: {
connection: firstConnection,
toBuffer: {
type: 'server',
name: firstConnection.connection.options.host,
},
},
});
}, [manager.connections]);
useEffect(() => {
const handlers: [
IRCConnectionWrapper,
keyof IRCConnectionEvents,
(...args: any) => void,
][] = [];
manager.connections.forEach((conn) => {
const lineHandler = (line: IIRCLine, processed: boolean) => {
if (processed) return;
let target: BufferType = 'server';
let targetName: string | undefined;
if (line.arguments[1] || (!line.arguments[1] && line.arguments[0])) {
const targetTest = line.arguments[line.arguments.length - 1];
const exists = getBuffer(state, {
connection: conn,
toBuffer: {
name: targetTest,
},
});
if (exists) {
target = exists.type;
targetName = exists.name;
}
}
if (
(line.command === 'NOTICE' || line.command === 'PRIVMSG') &&
line.arguments[0] === conn.connection.options.nick &&
line.user.nickname
) {
dispatch({
type: BufferActionKind.AddBuffer,
payload: {
connection: conn,
toBuffer: {
type: 'user',
name: line.user.nickname,
},
},
});
target = 'user';
targetName = line.user.nickname;
}
dispatch({
type: BufferActionKind.AddBufferLine,
payload: {
connection: conn,
toBuffer: {
type: target,
name: targetName,
},
message: {
type: 'privmsg',
time: new Date(),
sender: line.user
? line.user.nickname || line.user.hostname
: '--',
message: line.trailing,
},
},
});
if (
line.command === 'JOIN' &&
line.user.nickname === conn.connection.options.nick
) {
dispatch({
type: BufferActionKind.AddBuffer,
payload: {
connection: conn,
toBuffer: {
type: 'channel',
name: line.trailing,
},
},
});
}
if (line.command === '332' || line.command === 'TOPIC') {
dispatch({
type: BufferActionKind.SetTopic,
payload: {
connection: conn,
toBuffer: {
type: 'channel',
name: line.arguments[line.arguments.length - 1],
},
topic: line.trailing,
},
});
}
};
conn.connection.on('line', lineHandler);
handlers.push([conn, 'line', lineHandler]);
});
return () =>
handlers.forEach(([main, evt, handler]) =>
main.connection.removeEventListener(evt, handler),
);
}, [manager.connections, state]);
useEffect(() => {
const handlers: [
IRCConnectionWrapper,
keyof NickListEvents,
(...args: any) => void,
][] = [];
manager.connections.forEach((conn) => {
const handler = (channels?: string[]) => {
dispatch({
type: BufferActionKind.UpdateNicklist,
payload: {
connection: conn,
channels,
},
});
};
conn.nicklist.on('update', handler);
handlers.push([conn, 'update', handler]);
});
return () =>
handlers.forEach(([main, evt, handler]) =>
main.nicklist.removeEventListener(evt, handler),
);
}, [manager.connections]);
return (
<>
<ViewTabs
buffers={state.buffers}
activeIndex={state.activeIndex}
setActive={(index) => {
dispatch({
type: BufferActionKind.SetActiveBuffer,
payload: {
activeIndex: index,
},
});
}}
/>
<MessageBufferWrapper state={state} dispatch={dispatch} />
</>
);
};