Skip to content

Commit

Permalink
Merge pull request #445 from BinaryStudioAcademy/task/wr-433-add-load…
Browse files Browse the repository at this point in the history
…er-for-activities-and-latest-articles-sections

wr-433: Add Loader for activities section
  • Loading branch information
andanf-e authored Sep 29, 2023
2 parents e376d99 + 04c5a34 commit eca5d53
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 96 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
gap: 20px;
height: 100%;
padding: 20px;
text-align: center;
}

.emptyArticlesIcon {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,10 +140,6 @@
}

@media only screen and (max-width: breakpoints.$large) {
.wrapper {
align-items: flex-start;
}

.title {
display: none;
}
Expand Down
108 changes: 56 additions & 52 deletions frontend/src/pages/profile/components/user-activity/user-activity.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { DateFormat } from '~/libs/enums/enums.js';
import { Loader } from '~/libs/components/components.js';
import { DataStatus, DateFormat } from '~/libs/enums/enums.js';
import {
getFormattedDate,
getValidClassNames,
makePluralOrSingular,
} from '~/libs/helpers/helpers.js';
import { useAppSelector } from '~/libs/hooks/hooks.js';
import { type UserActivityResponseDto } from '~/packages/users/users.js';

import {
Expand All @@ -18,6 +20,8 @@ type Properties = {
};

const UserActivity: React.FC<Properties> = ({ userActivities, className }) => {
const { userActivitiesDataStatus } = useAppSelector(({ users }) => users);

const uniqueMonths: string[] = getUniqueMonths(userActivities);

const activityStatistic = userActivities.map((activity, index) => {
Expand Down Expand Up @@ -46,60 +50,60 @@ const UserActivity: React.FC<Properties> = ({ userActivities, className }) => {
);
});

const isLoading = userActivitiesDataStatus === DataStatus.PENDING;

return (
<>
{Boolean(userActivities.length) && (
<div className={styles.activityContainer}>
<h3 className={styles.title}>Your writing activity</h3>
<section className={getValidClassNames(styles.wrapper, className)}>
<div className={styles.activityWrapper}>
<div className={styles.days}>
<span className={styles.monday}>Mon</span>
<span className={styles.wednesday}>Wed</span>
<span className={styles.friday}>Fri</span>
<span className={styles.sunday}>Sun</span>
</div>
<div className={styles.innerWrapper}>
<div className={styles.months}>
{uniqueMonths.map((month) => (
<span key={month}>{month}</span>
))}
</div>
<div className={styles.activity}>{activityStatistic}</div>
</div>
<div className={styles.activityContainer}>
<h3 className={styles.title}>Your writing activity</h3>
<section className={getValidClassNames(styles.wrapper, className)}>
<Loader isLoading={isLoading} type="dots">
<div className={styles.activityWrapper}>
<div className={styles.days}>
<span className={styles.monday}>Mon</span>
<span className={styles.wednesday}>Wed</span>
<span className={styles.friday}>Fri</span>
<span className={styles.sunday}>Sun</span>
</div>
<div className={styles.breakpoints}>
Less
<span
className={getValidClassNames(
styles.breakpoint,
styles.firstBreakpoint,
)}
/>
<span
className={getValidClassNames(
styles.breakpoint,
styles.secondBreakpoint,
)}
/>
<span
className={getValidClassNames(
styles.breakpoint,
styles.thirdBreakpoint,
)}
/>
<span
className={getValidClassNames(
styles.breakpoint,
styles.fourthBreakpoint,
)}
/>
More
<div className={styles.innerWrapper}>
<div className={styles.months}>
{uniqueMonths.map((month) => (
<span key={month}>{month}</span>
))}
</div>
<div className={styles.activity}>{activityStatistic}</div>
</div>
</section>
</div>
)}
</>
</div>
<div className={styles.breakpoints}>
Less
<span
className={getValidClassNames(
styles.breakpoint,
styles.firstBreakpoint,
)}
/>
<span
className={getValidClassNames(
styles.breakpoint,
styles.secondBreakpoint,
)}
/>
<span
className={getValidClassNames(
styles.breakpoint,
styles.thirdBreakpoint,
)}
/>
<span
className={getValidClassNames(
styles.breakpoint,
styles.fourthBreakpoint,
)}
/>
More
</div>
</Loader>
</section>
</div>
);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
.wrapper {
display: flex;
flex-direction: column;
justify-content: center;
height: 100%;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Link } from '~/libs/components/components.js';
import { AppRoute } from '~/libs/enums/enums.js';
import { Link, Loader } from '~/libs/components/components.js';
import { AppRoute, DataStatus } from '~/libs/enums/enums.js';
import { getValidClassNames } from '~/libs/helpers/helpers.js';
import {
useAppDispatch,
Expand All @@ -19,9 +19,12 @@ type Properties = {

const UserLatestArticles: React.FC<Properties> = ({ className }) => {
const dispatch = useAppDispatch();
const { articles } = useAppSelector(({ articles }) => ({
articles: articles.articles,
}));
const { articles, fetchArticlesDataStatus } = useAppSelector(
({ articles }) => ({
articles: articles.articles,
fetchArticlesDataStatus: articles.fetchArticlesDataStatus,
}),
);

const hasArticles = Boolean(articles.length);

Expand All @@ -37,31 +40,36 @@ const UserLatestArticles: React.FC<Properties> = ({ className }) => {
};
}, [dispatch]);

const isLoading = fetchArticlesDataStatus === DataStatus.PENDING;

return (
<div className={styles.latestArticlesContainer}>
<h3 className={styles.listTitle}>
{hasArticles ? 'Your latest articles' : 'My articles'}
</h3>
<h3 className={styles.listTitle}>Your latest articles</h3>
<div className={getValidClassNames(className, styles.wrapper)}>
{hasArticles ? (
<>
<ul className={styles.articleList}>
{articles.map((article) => (
<li key={article.id}>
<ArticleShortCard
article={article}
className={styles.article}
/>
</li>
))}
</ul>
<Link to={AppRoute.ARTICLES_MY_ARTICLES} className={styles.showAll}>
Show all
</Link>
</>
) : (
<EmptyArticlesPlaceholder />
)}
<Loader isLoading={isLoading} type="dots">
{hasArticles ? (
<>
<ul className={styles.articleList}>
{articles.map((article) => (
<li key={article.id}>
<ArticleShortCard
article={article}
className={styles.article}
/>
</li>
))}
</ul>
<Link
to={AppRoute.ARTICLES_MY_ARTICLES}
className={styles.showAll}
>
Show all
</Link>
</>
) : (
<EmptyArticlesPlaceholder />
)}
</Loader>
</div>
</div>
);
Expand Down
13 changes: 8 additions & 5 deletions frontend/src/pages/profile/profile-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,14 @@ import styles from './styles.module.scss';

const ProfilePage: React.FC = () => {
const dispatch = useAppDispatch();
const { user, userActivities, articles } = useAppSelector(
const { user, userActivities } = useAppSelector(
({ auth, users, articles }) => ({
user: auth.user as UserAuthResponseDto,
userActivities: users.userActivities,
articles: articles.articles,
}),
);

const hasArticles = Boolean(articles.length);

useEffect(() => {
void dispatch(usersActions.getUserActivity());
}, [dispatch]);
Expand Down Expand Up @@ -65,9 +63,14 @@ const ProfilePage: React.FC = () => {
</Spoiler>
<Spoiler
breakpoint={WindowBreakpoint.MEDIUM}
summary={hasArticles ? 'Your latest articles' : 'My articles'}
summary="Your latest articles"
>
<UserLatestArticles className={styles.profileBlock} />
<UserLatestArticles
className={getValidClassNames(
styles.profileBlock,
styles.latestArticles,
)}
/>
</Spoiler>
</div>
</Layout>
Expand Down
8 changes: 7 additions & 1 deletion frontend/src/pages/profile/styles.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,22 @@
}

.achievements {
min-height: 244px;
min-height: 245px;
}

.activity {
align-items: normal;
min-height: 255px;
padding: 10px 30px 10px 10px;
}

.stats {
min-height: 436px;
}

.latestArticles {
min-height: 414px;
}
}

@media only screen and (max-width: breakpoints.$medium) {
Expand Down
20 changes: 13 additions & 7 deletions frontend/src/slices/users/users.slice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type State = {
authors: UserDetailsAuthorResponseDto[];
userArticlesGenresStats: UserArticlesGenreStatsItem[];
userArticlesGenresStatsStatus: ValueOf<typeof DataStatus>;
userActivitiesDataStatus: ValueOf<typeof DataStatus>;
};

const initialState: State = {
Expand All @@ -32,6 +33,7 @@ const initialState: State = {
userArticlesGenresStats: [],
dataStatus: DataStatus.IDLE,
userArticlesGenresStatsStatus: DataStatus.IDLE,
userActivitiesDataStatus: DataStatus.IDLE,
};

const { reducer, actions, name } = createSlice({
Expand All @@ -45,6 +47,7 @@ const { reducer, actions, name } = createSlice({
});
builder.addCase(getUserActivity.fulfilled, (state, action) => {
state.userActivities = action.payload;
state.userActivitiesDataStatus = DataStatus.FULFILLED;
});
builder.addCase(getAllAuthors.fulfilled, (state, action) => {
state.dataStatus = DataStatus.FULFILLED;
Expand All @@ -61,21 +64,24 @@ const { reducer, actions, name } = createSlice({
builder.addCase(getUserArticlesGenresStats.pending, (state) => {
state.userArticlesGenresStatsStatus = DataStatus.PENDING;
});
builder.addCase(getUserActivity.pending, (state) => {
state.userActivitiesDataStatus = DataStatus.PENDING;
});
builder.addCase(getUserArticlesGenresStats.rejected, (state) => {
state.userArticlesGenresStatsStatus = DataStatus.REJECTED;
});
builder.addCase(getUserActivity.rejected, (state) => {
state.userActivitiesDataStatus = DataStatus.REJECTED;
});
builder.addCase(loadAll.rejected, (state) => {
state.dataStatus = DataStatus.REJECTED;
});
builder.addMatcher(
isAnyOf(loadAll.pending, getUserActivity.pending, getAllAuthors.pending),
isAnyOf(loadAll.pending, getAllAuthors.pending),
(state) => {
state.dataStatus = DataStatus.PENDING;
},
);
builder.addMatcher(
isAnyOf(loadAll.rejected, getUserActivity.rejected),
(state) => {
state.dataStatus = DataStatus.REJECTED;
},
);
},
});

Expand Down

0 comments on commit eca5d53

Please sign in to comment.