make channels from array into object

This commit is contained in:
HF 2020-11-26 19:17:00 +01:00
parent ab910619f8
commit 8f24a34a1d
13 changed files with 151 additions and 91 deletions

View File

@ -90,7 +90,7 @@ export type Action =
minecraftname: string,
blockDm: boolean,
canvases: Object,
channels: Array,
channels: Object,
blocked: Array,
userlvl: number,
}

View File

@ -4,7 +4,7 @@
*/
import React, {
useRef, useEffect, useState, useLayoutEffect,
useRef, useEffect,
} from 'react';
import { connect } from 'react-redux';
@ -23,7 +23,6 @@ const UserContextMenu = ({
close,
}) => {
const wrapperRef = useRef(null);
const [channelArray, setChannelArray] = useState([]);
useEffect(() => {
const handleClickOutside = (event) => {
@ -42,20 +41,6 @@ const UserContextMenu = ({
};
}, [wrapperRef]);
useLayoutEffect(() => {
for (let i = 0; i < channels.length; i += 1) {
const chan = channels[i];
/*
* [cid, name, type, lastMessage]
*/
// eslint-disable-next-line eqeqeq
if (chan[0] == cid) {
setChannelArray(chan);
break;
}
}
}, [channels.length]);
return (
<div
ref={wrapperRef}
@ -68,7 +53,7 @@ const UserContextMenu = ({
<div>
Mute
</div>
{(channelArray[2] !== 0)
{(channels[cid][1] !== 0)
&& (
<div
role="button"

View File

@ -5,7 +5,7 @@
*/
import React, {
useRef, useState, useEffect, useCallback,
useRef, useState, useEffect, useCallback, useLayoutEffect,
} from 'react';
import { connect } from 'react-redux';
import { MdChat } from 'react-icons/md';
@ -44,8 +44,12 @@ const ChannelDropDown = ({
}
}, []);
useEffect(() => {
useLayoutEffect(() => {
if (show) {
if (channels[chatChannel]) {
const chType = (channels[chatChannel][1] === 1) ? 1 : 0;
setType(chType);
}
document.addEventListener('mousedown', handleClickOutside);
document.addEventListener('touchstart', handleClickOutside);
} else {
@ -55,12 +59,10 @@ const ChannelDropDown = ({
}, [show]);
useEffect(() => {
for (let i = 0; i < channels.length; i += 1) {
if (channels[i][0] === chatChannel) {
setChatChannelName(channels[i][1]);
}
if (channels[chatChannel]) {
setChatChannelName(channels[chatChannel][0]);
}
}, [chatChannel, channels]);
}, [chatChannel]);
return (
<div
@ -104,8 +106,8 @@ const ChannelDropDown = ({
className="channeldds"
>
{
channels.filter((ch) => {
const chType = ch[2];
Object.keys(channels).filter((cid) => {
const chType = channels[cid][1];
if (type === 1 && chType === 1) {
return true;
}
@ -113,24 +115,27 @@ const ChannelDropDown = ({
return true;
}
return false;
}).map((ch) => (
<div
onClick={() => setChannel(ch[0])}
style={(ch[0] === chatChannel) ? {
fontWeight: 'bold',
fontSize: 17,
} : null}
className={
`chn${
(ch[0] === chatChannel) ? ' selected' : ''
}${
(chatRead[ch[0]] < ch[3]) ? ' unread' : ''
}`
}
>
{ch[1]}
</div>
))
}).map((cid) => {
const [name,, lastTs] = channels[cid];
console.log(`name ${name} lastTC ${lastTs} compare to ${chatRead[cid]}`);
return (
<div
onClick={() => setChannel(cid)}
className={
`chn${
(cid === chatChannel) ? ' selected' : ''
}`
}
>
{
(chatRead[cid] < lastTs) ? (
<span className="chnunread"></span>
) : null
}
{name}
</div>
);
})
}
</div>
</div>

View File

@ -114,16 +114,11 @@ const Chat = ({
* set channel to first available one
*/
useEffect(() => {
let i = 0;
while (i < channels.length) {
// eslint-disable-next-line eqeqeq
if (channels[i][0] == chatChannel) {
break;
if (!channels[chatChannel]) {
const cids = Object.keys(channels);
if (cids.length) {
setChannel(cids[0]);
}
i += 1;
}
if (i && i === channels.length) {
setChannel(channels[0][0]);
}
}, [chatChannel, channels]);

View File

@ -4,9 +4,10 @@
*
* @flow
*/
import Sequelize from 'sequelize';
import logger from './logger';
import { RegUser, Message } from '../data/models';
import { RegUser, Message, Channel } from '../data/models';
const MAX_BUFFER_TIME = 120000;
@ -62,6 +63,13 @@ class ChatMessageBuffer {
uid,
message,
});
Channel.update({
lastMessage: Sequelize.literal('CURRENT_TIMESTAMP'),
}, {
where: {
id: cid,
},
});
const messages = this.buffer.get(cid);
if (messages) {
messages.push([

View File

@ -10,8 +10,7 @@ import { CHAT_CHANNELS, EVENT_USER_NAME, INFO_USER_NAME } from './constants';
export class ChatProvider {
constructor() {
this.defaultChannels = [];
this.defaultChannelIds = [];
this.defaultChannels = {};
this.enChannelId = 0;
this.intChannelId = 0;
this.infoUserId = 1;
@ -48,8 +47,6 @@ export class ChatProvider {
async initialize() {
// find or create default channels
this.defaultChannels.length = 0;
this.defaultChannelIds.length = 0;
for (let i = 0; i < CHAT_CHANNELS.length; i += 1) {
const { name } = CHAT_CHANNELS[i];
// eslint-disable-next-line no-await-in-loop
@ -66,13 +63,11 @@ export class ChatProvider {
if (name === 'en') {
this.enChannelId = id;
}
this.defaultChannels.push([
id,
this.defaultChannels[id] = [
name,
type,
lastTs,
]);
this.defaultChannelIds.push(id);
];
}
// find or create default users
let name = INFO_USER_NAME;
@ -106,7 +101,7 @@ export class ChatProvider {
}
userHasChannelAccess(user, cid, write = false) {
if (this.defaultChannelIds.includes(cid)) {
if (this.defaultChannels[cid]) {
if (!write || user.regUser) {
return true;
}

View File

@ -31,10 +31,10 @@ export default async function getMe(user) {
delete userdata.mcVerified;
userdata.canvases = canvases;
userdata.channels = [
userdata.channels = {
...chatProvider.defaultChannels,
...userdata.channels,
];
};
return userdata;
}

View File

@ -28,7 +28,7 @@ class User {
// id should stay null if unregistered
this.id = id;
this.ip = ip;
this.channels = [];
this.channels = {};
this.channelIds = [];
this.blocked = [];
this.ipSub = getIPv6Subnet(ip);
@ -70,12 +70,11 @@ class User {
name = (dmu1.id === this.id) ? dmu2.name : dmu1.name;
}
this.channelIds.push(id);
this.channels.push([
id,
this.channels[id] = [
name,
type,
lastTs,
]);
];
}
}
if (reguser.blocked) {

View File

@ -6,7 +6,21 @@ import type { Action } from '../actions/types';
export type ChatState = {
inputMessage: string,
// [[cid, name, type, lastMessage], [cid2, name2, type2, lastMessage2],...]
/*
* {
* cid: [
* name,
* type,
* lastTs,
* ],
* cid2: [
* name,
* type,
* lastTs,
* ],
* ...
* }
*/
channels: Array,
// [[uId, userName], [userId2, userName2],...]
blocked: Array,
@ -16,7 +30,7 @@ export type ChatState = {
const initialState: ChatState = {
inputMessage: '',
channels: [],
channels: {},
blocked: [],
messages: {},
};
@ -56,22 +70,19 @@ export default function chat(
case 'ADD_CHAT_CHANNEL': {
const { channel } = action;
const cid = channel[0];
const channels = state.channels
.filter((ch) => (ch[0] !== cid));
channels.push(channel);
return {
...state,
channels,
channels: {
...state.channels,
...channel,
},
};
}
case 'REMOVE_CHAT_CHANNEL': {
const { cid } = action;
const channels = state.channels.filter(
// eslint-disable-next-line eqeqeq
(chan) => (chan[0] != cid),
);
const channels = { ...state.channels };
delete channels[cid];
return {
...state,
channels,
@ -106,7 +117,7 @@ export default function chat(
const {
name, text, country, channel, user,
} = action;
if (!state.messages[channel]) {
if (!state.messages[channel] || !state.channels[channel]) {
return state;
}
const messages = {
@ -119,8 +130,19 @@ export default function chat(
if (messages[channel].length > MAX_CHAT_MESSAGES) {
messages[channel].shift();
}
/*
* update timestamp of last message
*/
const channelArray = [...state.channels[channel]];
channelArray[2] = Date.now();
return {
...state,
channels: {
...state.channels,
[channel]: channelArray,
},
messages,
};
}

View File

@ -109,9 +109,15 @@ export default function gui(
}
case 'SET_CHAT_CHANNEL': {
const { cid } = action;
return {
...state,
chatChannel: action.cid,
chatChannel: cid,
chatRead: {
...state.chatRead,
cid: Date.now(),
}
};
}
@ -139,6 +145,42 @@ export default function gui(
};
}
case 'RECEIVE_ME': {
const { channels } = action;
const cids = Object.keys(channels);
const chatRead = {...state.chatRead};
for (let i = 0; i < cids.length; i += 1) {
const cid = cids[i];
chatRead[cid] = 0;
}
return {
...state,
chatRead,
};
}
case 'ADD_CHAT_CHANNEL': {
const [cid] = Object.keys(action.channel);
return {
...state,
chatRead: {
...state.chatRead,
[cid]: 0,
},
};
}
case 'REMOVE_CHAT_CHANNEL': {
const { cid } = action;
const chatRead = { ...state.chatRead };
delete chatRead[cid];
return {
...state,
chatRead,
};
}
case 'PLACE_PIXEL': {
let { pixelsPlaced } = state;
pixelsPlaced += 1;

View File

@ -105,7 +105,6 @@ async function startDm(req: Request, res: Response) {
raw: true,
});
const ChannelId = channel[0].id;
const { lastMessage } = channel[0];
const promises = [
UserChannel.findOrCreate({
@ -127,12 +126,13 @@ async function startDm(req: Request, res: Response) {
// TODO: inform websocket to add channelId to user
res.json({
channel: [
ChannelId,
userName,
1,
lastMessage,
],
channel: {
[ChannelId]: [
userName,
1,
Date.now(),
],
},
});
}

View File

@ -485,6 +485,15 @@ tr:nth-child(even) {
cursor: pointer;
}
.chn.selected, .chnunread {
font-weight: bold;
font-size: 17px;
}
.chnunread {
color: red;
}
.usermessages {
font-size: 14px;
font-weight: 500;

View File

@ -194,7 +194,7 @@ app.get('/', async (req, res) => {
// ip config
// -----------------------------------------------------------------------------
// use this if models changed:
const promise = models.sync({ alter: { drop: true } })
const promise = models.sync({ alter: { drop: false } })
// const promise = models.sync()
.catch((err) => logger.error(err.stack));
promise.then(() => {