Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

react_dynamic-list-of-post solution #1180

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
},
"devDependencies": {
"@cypress/react18": "^2.0.1",
"@mate-academy/scripts": "^1.8.5",
"@mate-academy/scripts": "^1.9.12",
"@mate-academy/students-ts-config": "*",
"@mate-academy/stylelint-config": "*",
"@types/node": "^20.14.10",
Expand Down
76 changes: 26 additions & 50 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,60 +1,36 @@
import classNames from 'classnames';

import React, { useEffect, useState } from 'react';
import 'bulma/css/bulma.css';
import '@fortawesome/fontawesome-free/css/all.css';
import './App.scss';

import { PostsList } from './components/PostsList';
import { PostDetails } from './components/PostDetails';
import { UserSelector } from './components/UserSelector';
import { Loader } from './components/Loader';

export const App = () => (
<main className="section">
<div className="container">
<div className="tile is-ancestor">
<div className="tile is-parent">
<div className="tile is-child box is-success">
<div className="block">
<UserSelector />
</div>

<div className="block" data-cy="MainContent">
<p data-cy="NoSelectedUser">No user selected</p>

<Loader />

<div
className="notification is-danger"
data-cy="PostsLoadingError"
>
Something went wrong!
import { User } from './types/User';
import { getUsers } from './utils/fetchFunctions';
import { MainContent } from './components/MainContent';
import { Sidebar } from './components/Sidebar';

export const App = () => {
const [users, setUsers] = useState<User[]>([]);

useEffect(() => {
getUsers().then(setUsers);
}, []);

return (
<main className="section">
<div className="container">
<div className="tile is-ancestor">
<div className="tile is-parent">
<div className="tile is-child box is-success">
<div className="block">
<UserSelector users={users} />
piyopiyo0 marked this conversation as resolved.
Show resolved Hide resolved
</div>

<div className="notification is-warning" data-cy="NoPostsYet">
No posts yet
</div>

<PostsList />
<MainContent />
</div>
</div>
</div>

<div
data-cy="Sidebar"
className={classNames(
'tile',
'is-parent',
'is-8-desktop',
'Sidebar',
'Sidebar--open',
)}
>
<div className="tile is-child box is-success ">
<PostDetails />
</div>
<Sidebar />
</div>
</div>
</div>
</main>
);
</main>
);
};
40 changes: 40 additions & 0 deletions src/components/MainContent/MainContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React, { useContext } from 'react';
import {
ActivePostContext,
ActiveUserContext,
ErrorsContext,
LoaderContext,
PostsContext,
} from '../../utils/Store';
import { Loader } from '../Loader';
import { PostsList } from './PostList/PostsList';
import { ErrorTypes } from '../../types/ErrorTypes';

export const MainContent: React.FC = () => {
const { activeUser } = useContext(ActiveUserContext);
const { activePost } = useContext(ActivePostContext);
const { posts } = useContext(PostsContext);
const { isError } = useContext(ErrorsContext);
piyopiyo0 marked this conversation as resolved.
Show resolved Hide resolved
const { isLoading } = useContext(LoaderContext);
piyopiyo0 marked this conversation as resolved.
Show resolved Hide resolved

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable 'isLoading' is correctly named according to the checklist. Ensure that you do not use 'isLoad'.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do :)


return (
<div className="block" data-cy="MainContent">
{!activeUser && <p data-cy="NoSelectedUser">No user selected</p>}

{isLoading && !activePost && <Loader />}

{(isError === ErrorTypes.Posts && (
<div className="notification is-danger" data-cy="PostsLoadingError">
Something went wrong!
</div>
)) ||
(activeUser && !posts && !isLoading && (
<div className="notification is-warning" data-cy="NoPostsYet">
No posts yet
</div>
))}

{posts && <PostsList posts={posts} />}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure that the 'PostsList' component has propTypes defined for the 'posts' prop, as required by the checklist.

</div>
);
};
67 changes: 67 additions & 0 deletions src/components/MainContent/PostList/PostItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import React, { useContext } from 'react';
import { Post } from '../../../types/Post';
import classNames from 'classnames';
import {
ActivePostContext,
CommentFormContext,
CommentListContext,
ErrorsContext,
LoaderContext,
} from '../../../utils/Store';
import { getComments } from '../../../utils/fetchFunctions';
import { ErrorTypes } from '../../../types/ErrorTypes';

interface PostItemProps {
post: Post;
}

export const PostItem: React.FC<PostItemProps> = ({ post }) => {
const { activePost, setActivePost } = useContext(ActivePostContext);
const { setIsLoading } = useContext(LoaderContext);
piyopiyo0 marked this conversation as resolved.
Show resolved Hide resolved
const { setComments } = useContext(CommentListContext);
const { setIsError } = useContext(ErrorsContext);
const { setIsActiveForm } = useContext(CommentFormContext);

function handleOpenButton() {
if (activePost?.id !== post.id) {
setActivePost(post);
} else {
return setActivePost(null);
}

setIsError(null);
setComments([]);
setIsLoading(true);
setIsActiveForm(false);

getComments(post.id)
.then(res => setComments(res))
.catch(() => {
setIsError(ErrorTypes.Comment);
})
.finally(() => {
setIsLoading(false);
});
}

return (
<tr data-cy="Post">
<td data-cy="PostId">{post.id}</td>

<td data-cy="PostTitle">{post.title}</td>

<td className="has-text-right is-vcentered">
<button
type="button"
data-cy="PostButton"
className={classNames('button is-link', {
'is-light': activePost?.id !== post.id,
})}
onClick={() => handleOpenButton()}
piyopiyo0 marked this conversation as resolved.
Show resolved Hide resolved
>
{activePost?.id === post.id ? 'Close' : 'Open'}
</button>
</td>
</tr>
);
};
32 changes: 32 additions & 0 deletions src/components/MainContent/PostList/PostsList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React from 'react';
import { Post } from '../../../types/Post';
import { PostItem } from './PostItem';

interface PostsListProps {
posts: Post[];
}

export const PostsList: React.FC<PostsListProps> = ({ posts }) => {
return (
<div data-cy="PostsList">
<p className="title">Posts:</p>

<table className="table is-fullwidth is-striped is-hoverable is-narrow">
<thead>
<tr className="has-background-link-light">
<th>#</th>
<th>Title</th>
{/* eslint-disable-next-line jsx-a11y/control-has-associated-label */}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove unused comments as per the checklist requirement.

<th> </th>
</tr>
</thead>

<tbody>
{posts.map(post => (
<PostItem key={post.id} post={post} data-cy="Post" />
piyopiyo0 marked this conversation as resolved.
Show resolved Hide resolved

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid generating keys during render. Ensure that the key is stable and unique for each item in the list to prevent potential issues with component identity.

))}
</tbody>
</table>
</div>
);
};
1 change: 1 addition & 0 deletions src/components/MainContent/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './MainContent';
103 changes: 0 additions & 103 deletions src/components/NewCommentForm.tsx

This file was deleted.

Loading