subscribe to all available categories, instead of subscribing to them when you click on them if that makes sense
This commit is contained in:
parent
57e72d24c7
commit
d35198e88e
9 changed files with 83 additions and 81 deletions
|
@ -3,9 +3,12 @@ import gatewayConnection from '../../Gateway/globalGatewayConnection';
|
||||||
|
|
||||||
import { useHistory } from 'react-router-dom';
|
import { useHistory } from 'react-router-dom';
|
||||||
|
|
||||||
export default function CategoryButton({ category }) {
|
export default function CategoryButton({ category, selected }) {
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
|
|
||||||
|
let buttonClasses = 'button category-button';
|
||||||
|
if (selected) buttonClasses += ' pressed';
|
||||||
|
|
||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
if (gatewayConnection.isConnected) {
|
if (gatewayConnection.isConnected) {
|
||||||
history.push(`/categories/${category._id}`);
|
history.push(`/categories/${category._id}`);
|
||||||
|
@ -13,7 +16,7 @@ export default function CategoryButton({ category }) {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button className="button category-button" onClick={ handleClick }>
|
<button className={ buttonClasses } onClick={ handleClick }>
|
||||||
<CategoryProfile category={ category } size="32" />
|
<CategoryProfile category={ category } size="32" />
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
|
|
|
@ -3,13 +3,14 @@ import CategoryButton from './CategoryButton';
|
||||||
import APIRequest from '../../APIRequest';
|
import APIRequest from '../../APIRequest';
|
||||||
import { couldNotReach } from '../../Errors';
|
import { couldNotReach } from '../../Errors';
|
||||||
|
|
||||||
import { useDispatch } from 'react-redux'
|
import { connect, useDispatch } from 'react-redux'
|
||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
import Logger from '../../Logger';
|
import Logger from '../../Logger';
|
||||||
|
import gatewayConnection from '../../Gateway/globalGatewayConnection';
|
||||||
|
|
||||||
const { log: loaderLog } = Logger([ 'CategoryList', 'Loader' ]);
|
const { log: loaderLog } = Logger([ 'CategoryList', 'Loader' ]);
|
||||||
|
|
||||||
export default function CategoryList() {
|
function CategoryList({ selectedCategoryId }) {
|
||||||
const [ categoryList, setCategoryList ] = useState();
|
const [ categoryList, setCategoryList ] = useState();
|
||||||
const [ error, setError ] = useState();
|
const [ error, setError ] = useState();
|
||||||
|
|
||||||
|
@ -24,6 +25,9 @@ export default function CategoryList() {
|
||||||
loaderLog('Got category list from server, dispatching...');
|
loaderLog('Got category list from server, dispatching...');
|
||||||
setCategoryList(json.categories || []);
|
setCategoryList(json.categories || []);
|
||||||
dispatch({ type: 'categories/updatecategorylist', categories: json.categories });
|
dispatch({ type: 'categories/updatecategorylist', categories: json.categories });
|
||||||
|
loaderLog('Subscribing to all categories...');
|
||||||
|
// TODO: IMPORTANT: Subscribing to a lot of channels puts strain on the server
|
||||||
|
gatewayConnection.subscribeToCategoryChats(json.categories.map(category => category._id));
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
setError(true);
|
setError(true);
|
||||||
|
@ -49,10 +53,16 @@ export default function CategoryList() {
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<div className="category-list">
|
<div className="category-list">
|
||||||
{categoryList.map((category) =>
|
{ categoryList.map((category) => ( <CategoryButton key={ category._id } category={ category } selected={ (category._id === selectedCategoryId) } /> )) }
|
||||||
<CategoryButton key={ category._id } category={ category } />
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const stateToProps = (state) => {
|
||||||
|
return {
|
||||||
|
selectedCategoryId: state?.selectedCategoryId
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default connect(stateToProps)(CategoryList);
|
|
@ -1,24 +1,7 @@
|
||||||
import defaultProfile from '../../Images/defaultprofile_256px-256px.png'
|
import ProfileLink from '../UI/ProfileLink'
|
||||||
|
|
||||||
export default function CategoryProfile({ category, size }) {
|
export default function CategoryProfile({ category, size }) {
|
||||||
let picture;
|
|
||||||
|
|
||||||
if (!size) size = 32;
|
|
||||||
|
|
||||||
// TODO: Make a debug error message for then the size does not exist
|
|
||||||
const pictureClass = `profile-picture profile-picture-${size}`;
|
|
||||||
|
|
||||||
if (category.picture) {
|
|
||||||
// Not actually implemented on the server and can be unsafe, this is just futureproofing
|
|
||||||
picture = <img className={ pictureClass } src={ category.picture } alt="Profile"></img>
|
|
||||||
} else {
|
|
||||||
picture = <img className={ pictureClass } src={ defaultProfile } alt="Profile"></img>
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="profile-link">
|
<ProfileLink object={ category } size={ size } type="category" />
|
||||||
{ picture }
|
);
|
||||||
<span className="profile-username">{ category.title }</span>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
}
|
|
@ -7,7 +7,7 @@ import { useParams } from 'react-router-dom';
|
||||||
import { connect, useDispatch } from 'react-redux';
|
import { connect, useDispatch } from 'react-redux';
|
||||||
import { useState, useRef, useEffect } from 'react';
|
import { useState, useRef, useEffect } from 'react';
|
||||||
|
|
||||||
function CategoryView({ categories, messages, isHandlingRoute=true, subscribedToCategories, gateway: { isConnected: isGatewayConnected } }) {
|
function CategoryView({ categories, messages }) {
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
const [ textInput, setTextInput ] = useState('');
|
const [ textInput, setTextInput ] = useState('');
|
||||||
const [ category, setCategory ] = useState();
|
const [ category, setCategory ] = useState();
|
||||||
|
@ -32,29 +32,24 @@ function CategoryView({ categories, messages, isHandlingRoute=true, subscribedTo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (isHandlingRoute) {
|
|
||||||
if (!id || id === '') return;
|
|
||||||
if (!isGatewayConnected ) return;
|
|
||||||
if (subscribedToCategories.includes(id)) return;
|
|
||||||
|
|
||||||
dispatch({ type: 'categories/selectcategory', categoryId: id });
|
|
||||||
gatewayConnection.subscribeToCategoryChat(id);
|
|
||||||
}
|
|
||||||
}, [dispatch, id, isHandlingRoute, subscribedToCategories, isGatewayConnected]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!categories) return;
|
if (!categories) return;
|
||||||
|
|
||||||
setCategory(categories.find(x => x._id === id));
|
setCategory(categories.find(x => x._id === id));
|
||||||
}, [ categories, id ]);
|
}, [ categories, id ]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!category) return;
|
||||||
|
|
||||||
|
dispatch({ type: 'categories/selectcategory', categoryId: category._id });
|
||||||
|
}, [ category, dispatch ]);
|
||||||
|
|
||||||
if (category) {
|
if (category) {
|
||||||
let messagesView = messages.map(m => <Message key={ m._id } message={ m } />);
|
let messagesView = messages.map(m => <Message key={ m._id } message={ m } />);
|
||||||
|
|
||||||
if (messagesView === undefined || messagesView.length <= 0) {
|
if (messagesView === undefined || messagesView.length <= 0) {
|
||||||
messagesView = (
|
messagesView = (
|
||||||
<div class='no-messages-warning'>
|
<div className='no-messages-warning'>
|
||||||
A bit empty in here...
|
A bit empty in here...
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -98,8 +93,6 @@ const stateToProps = (state, ownProps) => {
|
||||||
return {
|
return {
|
||||||
categories: state?.categories,
|
categories: state?.categories,
|
||||||
messages: state?.messages[categoryId] || [],
|
messages: state?.messages[categoryId] || [],
|
||||||
subscribedToCategories: state?.subscribedToCategories || [],
|
|
||||||
gateway: state?.gateway
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
30
bfrontend/src/Components/UI/ProfileLink.js
Normal file
30
bfrontend/src/Components/UI/ProfileLink.js
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import defaultProfile from '../../Images/defaultprofile_256px-256px.png'
|
||||||
|
|
||||||
|
export default function ProfileLink({ object, size, type }) {
|
||||||
|
let picture;
|
||||||
|
|
||||||
|
if (!size) size = 32;
|
||||||
|
if (size !== 0) {
|
||||||
|
// TODO: Make a debug error message for then the size does not exist
|
||||||
|
const pictureClass = `profile-picture profile-picture-${size}`;
|
||||||
|
|
||||||
|
if (object.picture) {
|
||||||
|
// Not actually implemented on the server and can be unsafe, this is just futureproofing
|
||||||
|
picture = <img className={ pictureClass } src={ object.picture } alt="Profile"></img>
|
||||||
|
} else {
|
||||||
|
picture = <img className={ pictureClass } src={ defaultProfile } alt="Profile"></img>
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
picture = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const classes = type === 'user' ? 'profile-link user-profile-link' : 'profile-link';
|
||||||
|
const title = type === 'category' ? object.title : object.username;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={ classes }>
|
||||||
|
{ picture }
|
||||||
|
<span className="profile-username">{ title }</span>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
|
@ -1,27 +1,7 @@
|
||||||
import defaultProfile from '../../Images/defaultprofile_256px-256px.png'
|
import ProfileLink from '../UI/ProfileLink'
|
||||||
|
|
||||||
export default function UserProfileLink({ user, size }) {
|
|
||||||
let picture;
|
|
||||||
|
|
||||||
if (!size) size = 32;
|
|
||||||
if (size !== 0) {
|
|
||||||
// TODO: Make a debug error message for then the size does not exist
|
|
||||||
const pictureClass = `profile-picture profile-picture-${size}`;
|
|
||||||
|
|
||||||
if (user.picture) {
|
|
||||||
// Not actually implemented on the server and can be unsafe, this is just futureproofing
|
|
||||||
picture = <img className={ pictureClass } src={ user.picture } alt="Profile"></img>
|
|
||||||
} else {
|
|
||||||
picture = <img className={ pictureClass } src={ defaultProfile } alt="Profile"></img>
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
picture = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
export default function CategoryProfile({ user, size }) {
|
||||||
return (
|
return (
|
||||||
<div className="profile-link user-profile-link">
|
<ProfileLink object={ user } size={ size } type="user" />
|
||||||
{ picture }
|
);
|
||||||
<span className="profile-username">{ user.username }</span>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
}
|
|
@ -74,14 +74,12 @@ GatewayConnection.prototype.sendMessage = function(categoryId, content) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
GatewayConnection.prototype.subscribeToCategoryChat = function(categoryId) {
|
GatewayConnection.prototype.subscribeToCategoryChats = function(categoryIds) {
|
||||||
if (!this.isConnected) return;
|
if (!this.isConnected) return;
|
||||||
|
|
||||||
const request = [categoryId];
|
gatewayLog('Subscribing to channel(s)', categoryIds);
|
||||||
|
|
||||||
gatewayLog('Subscribing to channel(s)', request);
|
this.socket.emit('subscribe', categoryIds);
|
||||||
|
|
||||||
this.socket.emit('subscribe', request);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default GatewayConnection;
|
export default GatewayConnection;
|
|
@ -1,7 +1,7 @@
|
||||||
$nord0darker: #22262e;
|
$nord0darker: #22262e;
|
||||||
$nord1darker: #282b36;
|
$nord1darker: #282b36;
|
||||||
$nord2darker: #333947;
|
$nord2darker: #333947;
|
||||||
|
$nord3darker: #40495a;
|
||||||
$nord4darker: #9da2ad;
|
$nord4darker: #9da2ad;
|
||||||
|
|
||||||
$nord0: #2E3440;
|
$nord0: #2E3440;
|
||||||
|
@ -32,6 +32,7 @@ $nord15: #B48EAD;
|
||||||
|
|
||||||
--accent-color-dark: #{$nord1darker};
|
--accent-color-dark: #{$nord1darker};
|
||||||
--accent-color-light: #{$nord2darker};
|
--accent-color-light: #{$nord2darker};
|
||||||
|
--accent-color-very-light: #{$nord3darker};
|
||||||
|
|
||||||
--category-top-bar-color: var(--accent-color-light);
|
--category-top-bar-color: var(--accent-color-light);
|
||||||
--category-bottom-text-bar-color: var(--accent-color-light);
|
--category-bottom-text-bar-color: var(--accent-color-light);
|
||||||
|
@ -171,11 +172,11 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
&.pressed {
|
&.pressed {
|
||||||
background-color: var(--accent-color-light);
|
background-color: var(--accent-color-very-light);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.button:hover {
|
.button:hover:not(.pressed) {
|
||||||
background-color: var(--accent-color-light);
|
background-color: var(--accent-color-light);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,6 +275,10 @@ body {
|
||||||
color: var(--darker-text-color);
|
color: var(--darker-text-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.unread-indicator {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: 600px) {
|
@media only screen and (max-width: 600px) {
|
||||||
.button.category-button {
|
.button.category-button {
|
||||||
min-width: 100px;
|
min-width: 100px;
|
||||||
|
|
|
@ -2,11 +2,14 @@ import { createStore } from 'redux';
|
||||||
|
|
||||||
const intitialState = {
|
const intitialState = {
|
||||||
user: null,
|
user: null,
|
||||||
|
|
||||||
categories: null,
|
categories: null,
|
||||||
|
|
||||||
gateway: { isConnected: false },
|
gateway: { isConnected: false },
|
||||||
messages: {},
|
messages: {},
|
||||||
subscribedToCategories: [],
|
categoryPresenceClientList: {},
|
||||||
categoryPresenceClientList: {}
|
|
||||||
|
selectedCategoryId: undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
const reducer = (state = intitialState, payload) => {
|
const reducer = (state = intitialState, payload) => {
|
||||||
|
@ -50,10 +53,7 @@ const reducer = (state = intitialState, payload) => {
|
||||||
case 'categories/selectcategory': {
|
case 'categories/selectcategory': {
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
subscribedToCategories: [
|
selectedCategoryId: payload.categoryId
|
||||||
...state.subscribedToCategories || [],
|
|
||||||
payload.categoryId
|
|
||||||
]
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue