@@ -2,10 +2,12 @@ import Grid from '@mui/material/Grid2';
2
2
import Typography from '@mui/material/Typography' ;
3
3
import React , { useEffect , useState } from 'react' ;
4
4
import { useParams } from 'react-router' ;
5
+ import { Virtuoso } from 'react-virtuoso' ;
5
6
import DefaultPage from '../common/DefaultPage' ;
6
7
import Button from '@mui/material/Button' ;
7
8
import { useAppDispatch , useAppSelector } from '../store' ;
8
9
import { getAppName } from '../application/app-actions.ts' ;
10
+ import { IMessage } from '../types.ts' ;
9
11
import { fetchMessages , removeMessagesByApp , removeSingleMessage } from './message-actions.ts' ;
10
12
import Message from './Message' ;
11
13
import ConfirmDialog from '../common/ConfirmDialog' ;
@@ -18,20 +20,35 @@ const Messages = () => {
18
20
19
21
const [ toDeleteAll , setToDeleteAll ] = useState < boolean > ( false ) ;
20
22
21
- const heights : Record < string , number > = { } ;
22
-
23
23
const selectedApp = useAppSelector ( ( state ) => state . app . items . find ( ( app ) => app . id === appId ) ) ;
24
24
const apps = useAppSelector ( ( state ) => state . app . items ) ;
25
- const messages = useAppSelector ( ( state ) => appId === - 1 ? state . message . items : state . message . items . filter ( ( item ) => item . appid === appId ) ) ;
25
+ const messages = useAppSelector ( ( state ) =>
26
+ appId === - 1
27
+ ? state . message . items
28
+ : state . message . items . filter ( ( item ) => item . appid === appId )
29
+ ) ;
26
30
const hasMore = useAppSelector ( ( state ) => state . message . hasMore ) ;
27
31
const name = dispatch ( getAppName ( appId ) ) ;
28
32
const messagesLoaded = useAppSelector ( ( state ) => state . message . loaded ) ;
29
33
const hasMessages = messages . length !== 0 ;
30
34
31
35
useEffect ( ( ) => {
36
+ window . onscroll = ( ) => {
37
+ if (
38
+ window . innerHeight + window . scrollY >=
39
+ document . body . offsetHeight - window . innerHeight * 2
40
+ ) {
41
+ checkIfLoadMore ( ) ;
42
+ }
43
+ } ;
44
+
32
45
dispatch ( fetchMessages ( ) ) ;
33
46
} , [ dispatch ] ) ;
34
47
48
+ const checkIfLoadMore = ( ) => {
49
+ console . log ( 'checkIfLoadMore' ) ;
50
+ } ;
51
+
35
52
const label = ( text : string ) => (
36
53
< Grid size = { 12 } >
37
54
< Typography variant = "caption" component = "div" gutterBottom align = "center" >
@@ -40,6 +57,44 @@ const Messages = () => {
40
57
</ Grid >
41
58
) ;
42
59
60
+ const messageFooter = ( ) => {
61
+ if ( hasMore ) {
62
+ return < LoadingSpinner /> ;
63
+ }
64
+ if ( hasMessages ) {
65
+ return label ( "You've reached the end" ) ;
66
+ }
67
+ return null ;
68
+ } ;
69
+
70
+ const renderMessages = ( ) => (
71
+ < Virtuoso
72
+ id = "messages"
73
+ style = { { width : '100%' } }
74
+ useWindowScroll
75
+ totalCount = { messages . length }
76
+ data = { messages }
77
+ itemContent = { ( index , message ) => renderMessage ( index , message ) }
78
+ components = { {
79
+ Footer : messageFooter ,
80
+ EmptyPlaceholder : ( ) => label ( 'No messages' ) ,
81
+ } }
82
+ />
83
+ ) ;
84
+
85
+ const renderMessage = ( index : number , message : IMessage ) => (
86
+ < Message
87
+ key = { index }
88
+ fDelete = { ( ) => dispatch ( removeSingleMessage ( message ) ) }
89
+ title = { message . title }
90
+ date = { message . date }
91
+ content = { message . message }
92
+ image = { apps . find ( ( app ) => app . id == message . appid ) ?. image }
93
+ extras = { message . extras }
94
+ priority = { message . priority }
95
+ />
96
+ ) ;
97
+
43
98
return (
44
99
< DefaultPage
45
100
title = { name }
@@ -63,41 +118,7 @@ const Messages = () => {
63
118
</ Button >
64
119
</ div >
65
120
} >
66
- { ! messagesLoaded ? (
67
- < LoadingSpinner />
68
- ) : hasMessages ? (
69
- < div style = { { width : '100%' } } id = "messages" >
70
- { /* TODO: maybe replace ReactInfitite with react-window, which is also documented here: https://mui.com/material-ui/react-list/#virtualized-list */ }
71
- { /*<ReactInfinite*/ }
72
- { /* key={appId}*/ }
73
- { /* useWindowAsScrollContainer*/ }
74
- { /* preloadBatchSize={window.innerHeight * 3}*/ }
75
- { /* elementHeight={messages.map((m) => heights[m.id] || 1)}>*/ }
76
- { /* {messages.map(renderMessage)}*/ }
77
- { /*</ReactInfinite>*/ }
78
- { messages . map ( ( message ) => (
79
- < Message
80
- key = { message . id }
81
- height = { ( height : number ) => {
82
- if ( ! heights [ message . id ] ) {
83
- heights [ message . id ] = height ;
84
- }
85
- } }
86
- fDelete = { ( ) => dispatch ( removeSingleMessage ( message ) ) }
87
- title = { message . title }
88
- date = { message . date }
89
- content = { message . message }
90
- image = { apps . find ( ( app ) => app . id == message . appid ) ?. image }
91
- extras = { message . extras }
92
- priority = { message . priority }
93
- />
94
- ) ) }
95
-
96
- { hasMore ? < LoadingSpinner /> : label ( "You've reached the end" ) }
97
- </ div >
98
- ) : (
99
- label ( 'No messages' )
100
- ) }
121
+ { ! messagesLoaded ? < LoadingSpinner /> : renderMessages ( ) }
101
122
102
123
{ toDeleteAll && (
103
124
< ConfirmDialog
@@ -113,39 +134,8 @@ const Messages = () => {
113
134
/*
114
135
@observer
115
136
class Messages_old extends Component<IProps & Stores<'messagesStore' | 'appStore'>, IState> {
116
- @observable
117
- private heights: Record<string, number> = {};
118
- @observable
119
- private deleteAll = false;
120
-
121
- private static appId(props: IProps) {
122
- if (props === undefined) {
123
- return -1;
124
- }
125
- const {match} = props;
126
- return match.params.id !== undefined ? parseInt(match.params.id, 10) : -1;
127
- }
128
-
129
- public state = {appId: -1};
130
-
131
137
private isLoadingMore = false;
132
138
133
- public componentWillReceiveProps(nextProps: IProps & Stores<'messagesStore' | 'appStore'>) {
134
- this.updateAllWithProps(nextProps);
135
- }
136
-
137
- public componentWillMount() {
138
- window.onscroll = () => {
139
- if (
140
- window.innerHeight + window.pageYOffset >=
141
- document.body.offsetHeight - window.innerHeight * 2
142
- ) {
143
- this.checkIfLoadMore();
144
- }
145
- };
146
- this.updateAll();
147
- }
148
-
149
139
private updateAllWithProps = (props: IProps & Stores<'messagesStore'>) => {
150
140
const appId = Messages.appId(props);
151
141
this.setState({appId});
@@ -154,10 +144,6 @@ class Messages_old extends Component<IProps & Stores<'messagesStore' | 'appStore
154
144
}
155
145
};
156
146
157
- private updateAll = () => this.updateAllWithProps(this.props);
158
-
159
-
160
-
161
147
private checkIfLoadMore() {
162
148
const {appId} = this.state;
163
149
if (!this.isLoadingMore && this.props.messagesStore.canLoadMore(appId)) {
0 commit comments