-
Notifications
You must be signed in to change notification settings - Fork 3
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
wr-419: Display notification about New articles written by followed authors on all pages #451
Changes from 8 commits
228fa5a
165a282
04d584f
f7d2c35
9b0e6d6
b54976d
a722986
50ceaeb
3038159
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
import { type Knex } from 'knex'; | ||
|
||
const NOT_STARTED_ARTICLE_ACHIEVEMENT_DESCRIPTION = | ||
'Get started on your writing journey! Your first article is just a few keystrokes away. Dive in and share your thoughts with the world.'; | ||
const NOT_STARTED_COMMENT_ACHIEVEMENT_DESCRIPTION = | ||
'Ready to join the conversation? Leave your first comment and become a part of the discussion!'; | ||
const UPDATED_ACHIEVEMENTS = [ | ||
{ | ||
key: 'write_first_article', | ||
description: { | ||
notStarted: NOT_STARTED_ARTICLE_ACHIEVEMENT_DESCRIPTION, | ||
earlyStage: NOT_STARTED_ARTICLE_ACHIEVEMENT_DESCRIPTION, | ||
inProgress: NOT_STARTED_ARTICLE_ACHIEVEMENT_DESCRIPTION, | ||
done: 'Congratulations on completing your first article! 🎉 Your journey as a writer has begun. Share your work with pride!', | ||
}, | ||
}, | ||
{ | ||
key: 'write_5_articles', | ||
description: { | ||
notStarted: NOT_STARTED_ARTICLE_ACHIEVEMENT_DESCRIPTION, | ||
earlyStage: | ||
'You are off to a great start with your first article! Keep those ideas flowing and your pen moving.', | ||
inProgress: | ||
'You are making progress on your path to writing five articles! Keep those creative juices flowing, and you will reach your next milestone soon.', | ||
done: 'Congratulations on writing your fifth article! 🎉 You are building a substantial body of work. Keep the momentum going!', | ||
}, | ||
}, | ||
{ | ||
key: 'write_10_articles', | ||
description: { | ||
notStarted: NOT_STARTED_ARTICLE_ACHIEVEMENT_DESCRIPTION, | ||
earlyStage: | ||
'You are making progress toward writing ten articles! Stay committed, and you will soon reach this significant milestone.', | ||
inProgress: | ||
'You are well on your way to completing your tenth article! Keep up the excellent work, and you will achieve this milestone in no time.', | ||
done: 'Congratulations on writing your tenth article! 🎉 You have proven your dedication to writing. Keep the creativity flowing!', | ||
}, | ||
}, | ||
{ | ||
key: 'write_15_articles', | ||
description: { | ||
notStarted: NOT_STARTED_ARTICLE_ACHIEVEMENT_DESCRIPTION, | ||
earlyStage: 'You are making progress toward writing fifteen articles!', | ||
inProgress: | ||
'You are well on your way to completing your fifteenth article! Keep up the excellent work!', | ||
done: 'Congratulations on writing your fifteenth article! 🎉 Your dedication to writing is truly impressive. Keep those creative ideas flowing!', | ||
}, | ||
}, | ||
{ | ||
key: 'write_25_articles', | ||
description: { | ||
notStarted: NOT_STARTED_ARTICLE_ACHIEVEMENT_DESCRIPTION, | ||
earlyStage: | ||
'You are making headway toward writing twenty-five articles! Keep those creative juices flowing, and you will soon achieve this significant milestone.', | ||
inProgress: | ||
'You are well on your way to completing your twenty-fifth article! Your dedication to writing is paying off. Keep up the great work!', | ||
done: 'Congratulations on writing your twenty-fifth article! 🎉 Your body of work is substantial, and your commitment to writing is commendable. Keep inspiring others!', | ||
}, | ||
}, | ||
{ | ||
key: 'write_50_articles', | ||
description: { | ||
notStarted: NOT_STARTED_ARTICLE_ACHIEVEMENT_DESCRIPTION, | ||
earlyStage: | ||
'You are on your way to writing fifty articles! Keep the momentum going!', | ||
inProgress: | ||
'You are getting closer to writing your fiftieth article! Your dedication to writing is evident. Keep pushing forward!', | ||
done: 'Congratulations on writing your fiftieth article! 🎉 You are a prolific writer, and your dedication is an inspiration to others. Keep the words flowing!', | ||
}, | ||
}, | ||
{ | ||
key: 'write_first_comment', | ||
description: { | ||
notStarted: NOT_STARTED_COMMENT_ACHIEVEMENT_DESCRIPTION, | ||
earlyStage: NOT_STARTED_COMMENT_ACHIEVEMENT_DESCRIPTION, | ||
inProgress: NOT_STARTED_COMMENT_ACHIEVEMENT_DESCRIPTION, | ||
done: 'Congratulations on leaving your first comment! 🎉 Your voice matters, and you are making an impact in the community.', | ||
}, | ||
}, | ||
{ | ||
key: 'write_5_comments', | ||
description: { | ||
notStarted: NOT_STARTED_COMMENT_ACHIEVEMENT_DESCRIPTION, | ||
earlyStage: | ||
'You are off to a great start with your first comment! Keep up the great work!', | ||
inProgress: | ||
'You are actively engaging with discussions! Your participation is valuable, and you are well on your way to achieving this milestone.', | ||
done: 'Congratulations on leaving your fifth comment! 🎉 You are becoming a respected voice in the community. Keep those insights flowing!', | ||
}, | ||
}, | ||
{ | ||
key: 'write_10_comments', | ||
description: { | ||
notStarted: NOT_STARTED_COMMENT_ACHIEVEMENT_DESCRIPTION, | ||
earlyStage: | ||
'You are making great strides in the world of commenting! Keep engaging with the community!', | ||
inProgress: | ||
'You are actively engaging with discussions and making an impact! Keep it up, and you will achieve this milestone in no time.', | ||
done: 'Congratulations on leaving your tenth comment! 🎉 Your contributions are valued, and you are a key part of the community.', | ||
}, | ||
}, | ||
{ | ||
key: 'write_15_comments', | ||
description: { | ||
notStarted: NOT_STARTED_COMMENT_ACHIEVEMENT_DESCRIPTION, | ||
earlyStage: | ||
'You are on your way to writing fifteen comments! Keep engaging with the community!', | ||
inProgress: | ||
'You are actively participating in discussions and making your voice heard!', | ||
done: 'Congratulations on leaving your fifteenth comment! 🎉 Your contributions are invaluable, and you are a respected member of the community.', | ||
}, | ||
}, | ||
{ | ||
key: 'write_25_comments', | ||
description: { | ||
notStarted: NOT_STARTED_COMMENT_ACHIEVEMENT_DESCRIPTION, | ||
earlyStage: | ||
'You are actively engaging with discussions and contributing to the community! Your dedication is taking you closer to this achievement.', | ||
inProgress: 'You are well on your way to leaving twenty-five comments!', | ||
done: 'Congratulations on leaving your twenty-fifth comment! 🎉 You are a valuable member of the community, and your insights are making a difference.', | ||
}, | ||
}, | ||
{ | ||
key: 'write_50_comments', | ||
description: { | ||
notStarted: NOT_STARTED_COMMENT_ACHIEVEMENT_DESCRIPTION, | ||
earlyStage: | ||
'You are making substantial contributions to discussions! Keep sharing your insights.', | ||
inProgress: | ||
'You are actively participating in discussions and leaving your mark! Your dedication to commenting is paying off as you work toward this achievement.', | ||
done: 'Congratulations on leaving your fiftieth comment! 🎉 You are a prolific commenter and a cornerstone of the community. Keep the conversations alive!', | ||
}, | ||
}, | ||
]; | ||
|
||
const TABLE_NAME = 'achievements'; | ||
|
||
const ColumnName = { | ||
KEY: 'key', | ||
DESCRIPTION: 'description', | ||
} as const; | ||
|
||
async function up(knex: Knex): Promise<void> { | ||
for (const achievement of UPDATED_ACHIEVEMENTS) { | ||
await knex(TABLE_NAME) | ||
.where(ColumnName.KEY, achievement.key) | ||
.update({ [ColumnName.DESCRIPTION]: achievement.description }); | ||
} | ||
} | ||
|
||
async function down(): Promise<void> {} | ||
|
||
export { down, up }; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,11 @@ | ||
import { AppRoute } from '~/libs/enums/app-route.enum.js'; | ||
import { useEffect, useLocation } from '~/libs/hooks/hooks.js'; | ||
import { getFullName } from '~/libs/helpers/helpers.js'; | ||
import { | ||
useAppDispatch, | ||
useAppSelector, | ||
useEffect, | ||
useLocation, | ||
} from '~/libs/hooks/hooks.js'; | ||
import { SocketNamespace, SocketRoom } from '~/libs/packages/socket/socket.js'; | ||
import { | ||
type ArticleReactionsSocketEventPayload, | ||
|
@@ -9,15 +15,16 @@ import { | |
ArticleReactionsSocketEvent, | ||
ArticleSocketEvent, | ||
} from '~/packages/articles/articles.js'; | ||
import { actions as appActions } from '~/slices/app/app.js'; | ||
import { actions as articleActions } from '~/slices/articles/articles.js'; | ||
|
||
import { useAppDispatch } from '../use-app-dispatch/use-app-dispatch.hook.js'; | ||
import { useSocketNamespace } from '../use-socket-namespace/use-socket-namespace.hook.js'; | ||
|
||
const { NEW_ARTICLE } = ArticleSocketEvent; | ||
const { NEW_REACTION } = ArticleReactionsSocketEvent; | ||
|
||
const useArticlesFeedRoom = (): void => { | ||
const { user } = useAppSelector(({ auth }) => auth); | ||
const dispatch = useAppDispatch(); | ||
const location = useLocation(); | ||
|
||
|
@@ -40,8 +47,24 @@ const useArticlesFeedRoom = (): void => { | |
articlesSocket?.on( | ||
NEW_ARTICLE, | ||
(newArticle: ArticleSocketEventPayload[typeof NEW_ARTICLE]) => { | ||
if (location.pathname === AppRoute.ARTICLES) { | ||
void dispatch(articleActions.addArticle(newArticle)); | ||
if (user?.id === newArticle.socketUserId) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not sure why we need to send There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In this case we only check the author of the article, but on the server we loop through all the sockets in the namespace and send to each user info about each socket on every loop cycle (for example if we have 5 sockets each user will get 5 payloads), so if only one user follows the author, every user will be notified of this publication due this one payload from that user. |
||
if (location.pathname === AppRoute.ARTICLES) { | ||
void dispatch(articleActions.addArticle(newArticle)); | ||
} | ||
|
||
if (newArticle.isByFollowingAuthor) { | ||
const { author } = newArticle.article; | ||
|
||
void dispatch( | ||
appActions.notify({ | ||
type: 'info', | ||
message: `New article from ${getFullName( | ||
author.firstName, | ||
author.lastName, | ||
)}`, | ||
}), | ||
); | ||
} | ||
} | ||
}, | ||
); | ||
|
@@ -52,7 +75,13 @@ const useArticlesFeedRoom = (): void => { | |
void dispatch(articleActions.addReactionToArticlesFeed(reaction)); | ||
}, | ||
); | ||
}, [dispatch, articlesSocketReference, reactionsSocketReference, location]); | ||
}, [ | ||
dispatch, | ||
articlesSocketReference, | ||
reactionsSocketReference, | ||
location, | ||
user, | ||
]); | ||
}; | ||
|
||
export { useArticlesFeedRoom }; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,35 +1,30 @@ | ||
import { Layout, Link, RouterOutlet } from '~/libs/components/components.js'; | ||
import { AppRoute } from '~/libs/enums/enums.js'; | ||
import { useArticlesFeedRoom } from '~/libs/hooks/hooks.js'; | ||
|
||
import styles from './styles.module.scss'; | ||
|
||
const ArticlesPage: React.FC = () => { | ||
useArticlesFeedRoom(); | ||
|
||
return ( | ||
<Layout> | ||
<div className={styles.wrapper}> | ||
<div className={styles.tabsWrapper}> | ||
<Link | ||
to={AppRoute.ARTICLES} | ||
className={styles.tab} | ||
activeClassName={styles.activeTab} | ||
> | ||
Feed | ||
</Link> | ||
<Link | ||
to={AppRoute.ARTICLES_MY_ARTICLES} | ||
className={styles.tab} | ||
activeClassName={styles.activeTab} | ||
> | ||
My articles | ||
</Link> | ||
</div> | ||
<RouterOutlet /> | ||
const ArticlesPage: React.FC = () => ( | ||
<Layout> | ||
<div className={styles.wrapper}> | ||
<div className={styles.tabsWrapper}> | ||
<Link | ||
to={AppRoute.ARTICLES} | ||
className={styles.tab} | ||
activeClassName={styles.activeTab} | ||
> | ||
Feed | ||
</Link> | ||
<Link | ||
to={AppRoute.ARTICLES_MY_ARTICLES} | ||
className={styles.tab} | ||
activeClassName={styles.activeTab} | ||
> | ||
My articles | ||
</Link> | ||
</div> | ||
</Layout> | ||
); | ||
}; | ||
<RouterOutlet /> | ||
</div> | ||
</Layout> | ||
); | ||
|
||
export { ArticlesPage }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe you should cooperate with @canterbery, your tasks seem to be related #458