Add post list

This commit is contained in:
riggraz
2019-09-02 19:26:34 +02:00
parent edacfb1a4f
commit 86286b634d
13 changed files with 251 additions and 74 deletions

View File

@@ -19,8 +19,10 @@ class Board extends React.Component<Props> {
return (
<div className="boardContainer">
<NewPost board={board} isLoggedIn={isLoggedIn} authenticityToken={authenticityToken} />
<PostList />
<div className="sidebar">
<NewPost board={board} isLoggedIn={isLoggedIn} authenticityToken={authenticityToken} />
</div>
<PostList board={board} />
</div>
);
}

View File

@@ -1,12 +1,10 @@
import * as React from 'react';
import NewPostForm from './NewPostForm';
import Spinner from '../Shared/Spinner';
import Spinner from '../shared/Spinner';
import IBoard from '../../interfaces/IBoard';
import '../../stylesheets/components/Board/NewPost.scss';
interface Props {
board: IBoard;
isLoggedIn: boolean;

View File

@@ -1,7 +1,5 @@
import * as React from 'react';
import '../../stylesheets/components/Board/NewPostForm.scss';
interface Props {
title: string;
description: string;

View File

@@ -1,11 +1,78 @@
import * as React from 'react';
import '../../stylesheets/components/Board/PostList.scss';
import PostListItem from './PostListItem';
import Spinner from '../shared/Spinner';
const PostList = () => (
<div className="postListContainer">
Posts will be show here.
</div>
);
import IBoard from '../../interfaces/IBoard';
import IPost from '../../interfaces/IPost';
interface Props {
board: IBoard;
}
interface State {
posts: Array<IPost>;
isLoading: boolean;
error: string;
}
class PostList extends React.Component<Props, State> {
constructor(props) {
super(props);
this.state = {
posts: [],
isLoading: true,
error: '',
};
}
async componentDidMount() {
const boardId = this.props.board.id;
try {
let res = await fetch(`http://localhost:3000/posts?board_id=${boardId}`);
let data = await res.json();
this.setState({isLoading: false});
this.setState({
posts: data.map(post => ({
title: post.title,
description: post.description,
postStatus: {
name: post.post_status_name,
color: post.post_status_color,
},
})),
});
} catch (e) {
this.setState({
error: 'An unknown error occurred, try again.'
});
}
}
render() {
const { posts, isLoading, error } = this.state;
return (
<div className="postList">
{ isLoading ? <Spinner /> : null }
{ error ? <span className="error">{error}</span> : null }
{
posts.map((post, i) => (
<PostListItem
title={post.title}
description={post.description}
postStatus={post.postStatus}
key={i}
/>
))
}
</div>
);
}
}
export default PostList;

View File

@@ -0,0 +1,32 @@
import * as React from 'react';
interface Props {
title: string;
description?: string;
postStatus: {name: string, color: string};
}
const PostListItem = ({ title, description, postStatus}: Props) => (
<a href="#" className="postLink">
<div className="postListItem">
<div className="postTitle">{title}</div>
<div className="postDescription">
{
description && description.length > 120 ?
description.slice(0, 119) + '...'
:
description || '<No description provided.>'
}
</div>
<div className="postDetails">
<div className="postDetailsComments">💬 0 comments</div>
<div className="postDetailsStatus" style={{color: postStatus.color}}>
<div className="dot" style={{backgroundColor: postStatus.color}}></div>
<span className="postStatusName">{postStatus.name}</span>
</div>
</div>
</div>
</a>
);
export default PostListItem;

View File

@@ -1,7 +1,7 @@
import * as React from 'react';
const Spinner = () => (
<div className="spinner-border" role="status">
<div className="spinner-border d-block mx-auto" role="status">
<span className="sr-only">Loading...</span>
</div>
);

View File

@@ -6,6 +6,9 @@ interface IPost {
post_status_id?: number;
user_id: number;
created_at: string;
// associations
postStatus?: any;
}
export default IPost;

View File

@@ -4,4 +4,128 @@
justify-content: space-between;
align-items: flex-start;
flex-wrap: nowrap;
.sidebar {
top: 20px;
position: sticky;
}
.newBoardContainer {
flex: 0 0 auto;
width: 250px;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;
border: 1px solid black;
border-radius: 4px;
padding: 8px;
margin: 8px;
.boardName {
font-size: 24px;
font-weight: 600;
text-align: center;
}
.boardDescription {
color: grey;
font-size: 17px;
font-weight: 200;
text-align: center;
margin-bottom: 8px;
}
.submitBtn {
margin-bottom: 8px;
}
.success {
color: green;
text-align: center;
}
.error {
color: red;
text-align: center;
}
}
.postList {
display: flex;
flex-direction: column;
flex: 1 1 auto;
border: 1px solid black;
border-radius: 4px;
padding: 8px;
margin: 8px;
.postLink {
text-decoration: none;
border-radius: 4px;
}
.postLink:hover {
text-decoration: none;
background-color: #f5f5f5;
}
.postListItem {
display: flex;
flex-direction: column;
justify-content: space-between;
height: 114px;
margin: 4px 0;
padding: 8px 4px;
}
.postTitle {
color: black;
font-weight: 500;
font-size: 18px;
}
.postDescription {
color: grey;
font-weight: 400;
font-size: 15px;
}
.postDetails {
display: flex;
color: black;
font-size: 16px;
text-transform: uppercase;
}
.postDetailsComments {
margin-right: 16px;
}
.postDetailsStatus {
display: flex;
}
.dot {
width: 16px;
height: 16px;
border-radius: 100%;
margin-top: auto;
margin-bottom: auto;
margin-right: 4px;
}
}
}

View File

@@ -1,47 +0,0 @@
.newBoardContainer {
flex: 0 0 auto;
width: 250px;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;
border: 1px solid black;
border-radius: 4px;
padding: 8px;
margin: 8px;
}
.boardName {
font-size: 24px;
font-weight: 600;
text-align: center;
}
.boardDescription {
color: grey;
font-size: 17px;
font-weight: 200;
text-align: center;
margin-bottom: 8px;
}
.submitBtn {
margin-bottom: 8px;
}
.success {
color: green;
text-align: center;
}
.error {
color: red;
text-align: center;
}

View File

@@ -1,3 +0,0 @@
.submitBtn {
margin-bottom: 8px;
}

View File

@@ -1,9 +0,0 @@
.postListContainer {
flex: 1 1 auto;
border: 1px solid black;
border-radius: 4px;
padding: 8px;
margin: 8px;
}