Update react components

This commit is contained in:
Sonny Bakker 2023-09-25 19:58:32 +02:00
parent f9105b2661
commit 6e94890e0e
6 changed files with 55 additions and 61 deletions

View file

@ -56,7 +56,7 @@ const mapStateToProps = state => {
const { error } = state.error; const { error } = state.error;
if (!isEqual(state.selected.post, {})) { if (!isEqual(state.selected.post, {})) {
const ruleId = state.selected.post.rule; const ruleId = state.selected.post.rule.id;
const rule = state.rules.items[ruleId]; const rule = state.rules.items[ruleId];
const category = state.categories.items[rule.category]; const category = state.categories.items[rule.category];

View file

@ -16,7 +16,7 @@ import { formatDatetime } from '../../../../utils.js';
class PostItem extends React.Component { class PostItem extends React.Component {
render() { render() {
const rule = { ...this.props.post.rule }; const rule = { ...this.props.post.rule };
const post = { ...this.props.post, rule: rule.id }; const post = { ...this.props.post };
const token = Cookies.get('csrftoken'); const token = Cookies.get('csrftoken');
const publicationDate = formatDatetime(post.publicationDate); const publicationDate = formatDatetime(post.publicationDate);

View file

@ -6,6 +6,7 @@ import { fetchPostsBySection, fetchSavedPosts } from '../../actions/posts.js';
import { SAVED_TYPE } from '../../constants.js'; import { SAVED_TYPE } from '../../constants.js';
import { filterPosts } from './filters.js'; import { filterPosts } from './filters.js';
import LoadingIndicator from '../../../../components/LoadingIndicator.js';
import PostItem from './PostItem.js'; import PostItem from './PostItem.js';
class PostList extends React.Component { class PostList extends React.Component {
@ -55,7 +56,7 @@ class PostList extends React.Component {
} }
render() { render() {
const isLastItem = this.props.postsByType.length - 1 == index; const isLastItem = this.props.postsByType.toReversed().find(item => !item.read);
const postItems = this.props.postsByType.map((item, index) => { const postItems = this.props.postsByType.map((item, index) => {
const defaultProps = { const defaultProps = {
@ -68,7 +69,7 @@ class PostList extends React.Component {
timezone: this.props.timezone, timezone: this.props.timezone,
}; };
if (isLastItem && !item.read) { if (isLastItem?.id === item.id) {
return <PostItem {...defaultProps} forwardedRef={this.lastPostRef} />; return <PostItem {...defaultProps} forwardedRef={this.lastPostRef} />;
} else { } else {
return <PostItem {...defaultProps} />; return <PostItem {...defaultProps} />;

View file

@ -4,31 +4,10 @@ const isEmpty = (object = {}) => {
return Object.keys(object).length === 0; return Object.keys(object).length === 0;
}; };
const sortOrdering = (firstPost, secondPost) => {
const dateOrdering =
new Date(firstPost.publicationDate) < new Date(secondPost.publicationDate);
if (firstPost.read && !secondPost.read) {
return 1;
} else if (secondPost.read && !firstPost.read) {
return -1;
}
return dateOrdering;
};
const savedOrdering = (firstPost, secondPost) => {
return new Date(firstPost.publicationDate) < new Date(secondPost.publicationDate);
};
export const filterPostsByRule = (rule = {}, posts = []) => { export const filterPostsByRule = (rule = {}, posts = []) => {
const filteredPosts = posts.filter(post => { return posts.filter(post => {
return post.rule === rule.id; return post.rule.id === rule.id;
}); });
const filteredData = filteredPosts.map(post => ({ ...post, rule: { ...rule } }));
return filteredData.sort(sortOrdering);
}; };
export const filterPostsByCategory = (category = {}, rules = [], posts = []) => { export const filterPostsByCategory = (category = {}, rules = [], posts = []) => {
@ -36,24 +15,13 @@ export const filterPostsByCategory = (category = {}, rules = [], posts = []) =>
return rule.category === category.id; return rule.category === category.id;
}); });
const filteredData = filteredRules.map(rule => { const ruleIds = filteredRules.map(rule => rule.id);
const filteredPosts = posts.filter(post => {
return post.rule === rule.id;
});
return filteredPosts.map(post => ({ ...post, rule: { ...rule } })); return [...posts].filter(post => ruleIds.includes(post.rule.id));
});
const sortedPosts = [...filteredData.flat()].sort(sortOrdering);
return sortedPosts;
}; };
export const filterPostsBySaved = (rules = [], posts = []) => { export const filterPostsBySaved = (rules = [], posts = []) => {
const filteredPosts = posts.filter(post => post.saved); return [...posts].filter(post => post.saved);
return filteredPosts
.map(post => ({ ...post, rule: { ...rules.find(rule => rule.id === post.rule) } }))
.sort(savedOrdering);
}; };
export const filterPosts = state => { export const filterPosts = state => {

View file

@ -12,56 +12,78 @@ import {
} from '../actions/posts.js'; } from '../actions/posts.js';
import { MARK_SECTION_READ } from '../actions/selected.js'; import { MARK_SECTION_READ } from '../actions/selected.js';
const defaultState = { items: {}, isFetching: false, isUpdating: false }; const sortOrdering = (firstPost, secondPost) => {
const dateOrdering =
new Date(firstPost.publicationDate) < new Date(secondPost.publicationDate);
if (firstPost.read && !secondPost.read) {
return 1;
} else if (secondPost.read && !firstPost.read) {
return -1;
}
return dateOrdering;
};
const defaultState = { items: [], isFetching: false, isUpdating: false };
export const posts = (state = { ...defaultState }, action) => { export const posts = (state = { ...defaultState }, action) => {
switch (action.type) { switch (action.type) {
case REQUEST_POSTS: case REQUEST_POSTS:
return { ...state, isFetching: true }; return { ...state, isFetching: true };
// TODO: save post per category/rule in corresponding reducers
case RECEIVE_POST: case RECEIVE_POST:
const postIndex = state.items.findIndex(post => post.id === action.post.id);
let newItems = [...state.items];
if (postIndex >= 0) {
newItems.splice(postIndex, 1, { ...action.post });
} else {
newItems = [...state.items, { ...action.post }];
}
newItems.sort(sortOrdering);
return { return {
...state, ...state,
items: { ...state.items, [action.post.id]: { ...action.post } }, items: newItems,
}; };
// TODO: save posts per category/rule in corresponding reducers
case RECEIVE_POSTS: case RECEIVE_POSTS:
const receivedItems = objectsFromArray(action.posts, 'id'); const receivedPosts = objectsFromArray(action.posts, 'id');
let mergedPosts = { ...objectsFromArray(state.items, 'id'), ...receivedPosts };
let sortedPosts = Object.values(mergedPosts).sort(sortOrdering);
return { return {
...state, ...state,
isFetching: false, isFetching: false,
items: { ...state.items, ...receivedItems }, items: sortedPosts,
}; };
case MARK_SECTION_READ: case MARK_SECTION_READ:
const updatedPosts = {}; let posts = [];
let relatedPosts = [];
// TODO: test these cases
switch (action.section.type) { switch (action.section.type) {
case CATEGORY_TYPE: case CATEGORY_TYPE:
relatedPosts = Object.values({ ...state.items }).filter(post => { posts = [...state.items].forEach(post => {
return post.rule in { ...action.section.rules }; if (!(post.rule.id in { ...action.section.rules })) return;
post.read = true;
}); });
break; break;
case RULE_TYPE: case RULE_TYPE:
relatedPosts = Object.values({ ...state.items }).filter(post => { posts = [...state.items].forEach(post => {
return post.rule === action.section.id; if (post.rule.id != action.section.id) return;
post.read = true;
}); });
break; break;
} }
relatedPosts.forEach(post => {
updatedPosts[post.id] = { ...post, read: true };
});
return { return {
...state, ...state,
items: { items: posts,
...state.items,
...updatedPosts,
},
}; };
case MARKING_POST: case MARKING_POST:
return { ...state, isUpdating: true }; return { ...state, isUpdating: true };

View file

@ -1,5 +1,6 @@
from rest_framework import serializers from rest_framework import serializers
from newsreader.news.collection.serializers import RuleSerializer
from newsreader.news.core.models import Category, Post from newsreader.news.core.models import Category, Post
@ -9,6 +10,8 @@ class PostSerializer(serializers.ModelSerializer):
) )
remoteIdentifier = serializers.CharField(source="remote_identifier", required=False) remoteIdentifier = serializers.CharField(source="remote_identifier", required=False)
rule = RuleSerializer()
class Meta: class Meta:
model = Post model = Post
fields = ( fields = (