-
Notifications
You must be signed in to change notification settings - Fork 0
Ncto 155 make notifications system #46
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
Open
Notgoyome
wants to merge
21
commits into
main
Choose a base branch
from
NCTO-155-make-notifications-system
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
43906a0
[MISC][CLEANUP] remove useless line
Notgoyome 3850d31
[NOTIFICATIONS][FEATURE]: add notifications inbox
Notgoyome d3d7ed1
[MISC][FEATURE]: add dev docker compose to get hot reload
Notgoyome 2091eb5
[CONFIG][FIX]: update BASE URL fallback to use localhost for OpenAPI
Notgoyome 90a2826
[NOTIFICATIONS][FEATURE]: add NotificationsService and NotificationTe…
Notgoyome 2276177
[NOTIFICATIONS][FEATURE]: better notifications and reading/init notif…
Notgoyome 483d4e5
[NOTIFICATIONS][REFACTO]: refactor notification read handling and imp…
Notgoyome a4c93d2
[NOTIFICATIONS][FEAT]: api generate
Notgoyome c6cf3cd
[NOTIFICATIONS][CLEANUP]: remove comments
Notgoyome 14b2266
[NOTIFICATIONS][item]:notification item as a component for menu lisib…
Notgoyome b179283
[DOCS][UPDATE]: clean readme
Notgoyome 9019972
[NOTIFICATIONS][FEAT]: error handling
Notgoyome d25454d
[NOTIFICATIONS][FEAT]: replace Typography with MenuItem for better in…
Notgoyome df060f3
[CONFIG][UPDATE]: change default BASE URL to "none"
Notgoyome 58d34b3
[NOTIFICATIONS][UPDATE]: remove cursor pointer style from Notificatio…
Notgoyome 465c254
[NOTIFICATIONS][UPDATE]: add error handling for marking notifications…
Notgoyome 6f7ade7
[NOTIFICATIONS][UPDATE]: refactor NotificationEntry to use MenuItem a…
Notgoyome b9328ea
[API][FIX] revert
Notgoyome 31b971b
[NOTIFICATIONS][UPDATE]: refactor backend URL retrieval to use OpenAP…
Notgoyome 5c88326
[NOTIFICATIONS][UPDATE]: removed eslint disable next line
Notgoyome a4ff490
[DEV][REMOVE]: delete docker-compose.dev.yml file
Notgoyome File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,6 +4,5 @@ | |
| /* eslint-disable */ | ||
| export type AuthResponseDto = { | ||
| access_token: string; | ||
| refresh_token: string; | ||
| }; | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| /* generated using openapi-typescript-codegen -- do not edit */ | ||
| /* istanbul ignore file */ | ||
| /* tslint:disable */ | ||
| /* eslint-disable */ | ||
| export type NotificationTestDto = { | ||
| /** | ||
| * The title of the test notification | ||
| */ | ||
| title: string; | ||
| /** | ||
| * The message content of the test notification | ||
| */ | ||
| message: string; | ||
| /** | ||
| * The type of the notification (friend request, message, etc.) | ||
| */ | ||
| type: string; | ||
| }; | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| /* generated using openapi-typescript-codegen -- do not edit */ | ||
| /* istanbul ignore file */ | ||
| /* tslint:disable */ | ||
| /* eslint-disable */ | ||
| import type { NotificationTestDto } from '../models/NotificationTestDto'; | ||
| import type { CancelablePromise } from '../core/CancelablePromise'; | ||
| import { OpenAPI } from '../core/OpenAPI'; | ||
| import { request as __request } from '../core/request'; | ||
| export class NotificationsService { | ||
| /** | ||
| * Send a test notification to the current user | ||
| * @param requestBody | ||
| * @returns any Notification created and sent | ||
| * @throws ApiError | ||
| */ | ||
| public static notificationsControllerSendTestNotification( | ||
| requestBody: NotificationTestDto, | ||
| ): CancelablePromise<any> { | ||
| return __request(OpenAPI, { | ||
| method: 'POST', | ||
| url: '/notifications/test', | ||
| body: requestBody, | ||
| mediaType: 'application/json', | ||
| }); | ||
| } | ||
| /** | ||
| * set one notification as read | ||
| * @param id | ||
| * @returns any Notification marked as read | ||
| * @throws ApiError | ||
| */ | ||
| public static notificationsControllerMarkAsRead( | ||
| id: string, | ||
| ): CancelablePromise<any> { | ||
| return __request(OpenAPI, { | ||
| method: 'PATCH', | ||
| url: '/notifications/{id}/read', | ||
| path: { | ||
| 'id': id, | ||
| }, | ||
| }); | ||
| } | ||
| /** | ||
| * set notifications as read | ||
| * @returns any All notifications as read | ||
| * @throws ApiError | ||
| */ | ||
| public static notificationsControllerMarkAllAsRead(): CancelablePromise<any> { | ||
| return __request(OpenAPI, { | ||
| method: 'PATCH', | ||
| url: '/notifications/read-all', | ||
| }); | ||
| } | ||
| } |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| export class NotificationError extends Error { | ||
| constructor(message: string) { | ||
| super(message); | ||
| this.name = "NotificationError"; | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,139 @@ | ||
| import { Badge, IconButton, styled } from "@mui/material"; | ||
| import { JSX, useCallback, useEffect, useMemo, useRef, useState, type MouseEvent } from "react"; | ||
| import InfoBoxIcon from "@assets/infoBox.svg?react"; | ||
| import { useUser } from "@providers/UserProvider"; | ||
| import { LocalStorageManager } from "@utils/LocalStorageManager"; | ||
| import { NotificationMenu } from "./NotificationMenu"; | ||
| import { NotificationItem } from "./types"; | ||
| import { NotificationsService } from "@api/services/NotificationsService"; | ||
| import { OpenAPI } from "@api"; | ||
|
|
||
| const NOTIFICATION_SOCKET_PATH = "/socket/notifications"; | ||
| const MAX_NOTIFICATIONS = 50; | ||
|
|
||
| type NotificationWsMessage = | ||
| | { type: "notification"; payload: NotificationItem } | ||
| | { type: "notifications:init"; payload: NotificationItem[] }; | ||
|
|
||
| const NotificationButton = styled(IconButton)(({ theme }) => ({ | ||
| margin: theme.spacing(2), | ||
| color: theme.palette.text.primary, | ||
| })); | ||
|
|
||
| const InfoIcon = styled(InfoBoxIcon)(({ theme }) => ({ | ||
| width: 24, | ||
| height: 24, | ||
| color: theme.palette.text.primary, | ||
| })); | ||
|
|
||
| const mergeNotification = ( | ||
| previous: NotificationItem[], | ||
| notification: NotificationItem, | ||
| ): NotificationItem[] => { | ||
| const withoutCurrent = previous.filter((item) => item.id !== notification.id); | ||
| return [notification, ...withoutCurrent].slice(0, MAX_NOTIFICATIONS); | ||
| }; | ||
|
|
||
| export const NotificationBox = (): JSX.Element => { | ||
| const { user } = useUser(); | ||
| const userId = user?.id; | ||
| const token = LocalStorageManager.getToken(); | ||
| const [notifications, setNotifications] = useState<NotificationItem[]>([]); | ||
| const [showMenu, setShowMenu] = useState(false); | ||
| const [anchorEl, setAnchorEl] = useState<HTMLElement | undefined>(undefined); | ||
| const socketRef = useRef<WebSocket | null>(null); | ||
| const backendUrl = OpenAPI.BASE; | ||
|
|
||
| const unreadCount = useMemo( | ||
| () => notifications.reduce((count, notification) => count + (notification.read ? 0 : 1), 0), | ||
| [notifications], | ||
| ); | ||
|
|
||
| useEffect(() => { | ||
| if (!userId || !token || !backendUrl) { | ||
| if (socketRef.current) { | ||
| socketRef.current.close(); | ||
| socketRef.current = null; | ||
| } | ||
| setNotifications([]); | ||
| return; | ||
| } | ||
|
|
||
| const wsBase = backendUrl.replace(/^http/i, "ws").replace(/\/$/, ""); | ||
| const socketUrl = `${wsBase}${NOTIFICATION_SOCKET_PATH}`; | ||
| const socket = new WebSocket(socketUrl); | ||
|
|
||
| socketRef.current = socket; | ||
|
|
||
| socket.onopen = () => { | ||
| try { | ||
| socket.send(JSON.stringify({ type: "auth", token })); | ||
| } catch { | ||
| console.warn("Failed to send auth message over websocket"); | ||
| } | ||
| }; | ||
|
|
||
| socket.onmessage = (event: MessageEvent<string>) => { | ||
| try { | ||
| const message = JSON.parse(event.data) as NotificationWsMessage; | ||
|
|
||
| if (message.type === "notifications:init") { | ||
| setNotifications(message.payload.slice(0, MAX_NOTIFICATIONS)); | ||
| return; | ||
| } | ||
|
|
||
| if (message.type === "notification") { | ||
| setNotifications((previous) => mergeNotification(previous, message.payload)); | ||
| } | ||
| } catch (error) { | ||
| console.warn("Failed to process notification websocket message:", error); | ||
| } | ||
| }; | ||
|
|
||
| return () => { | ||
| socket.close(); | ||
| socketRef.current = null; | ||
| }; | ||
| }, [userId, token, backendUrl]); | ||
|
|
||
| const handleClick = useCallback((event: MouseEvent<HTMLElement>) => { | ||
| setAnchorEl(event.currentTarget); | ||
| setShowMenu((previous) => { | ||
| const next = !previous; | ||
|
|
||
| return next; | ||
| }); | ||
| }, []); | ||
|
|
||
| const handleClose = useCallback(() => setShowMenu(false), []); | ||
|
|
||
| const handleMarkAsRead = useCallback((notificationId: string) => { | ||
| setNotifications((current) => | ||
| current.map((notification) => | ||
| notification.id === notificationId ? { ...notification, read: true } : notification, | ||
| ), | ||
| ); | ||
| NotificationsService.notificationsControllerMarkAsRead(notificationId).catch(() => { | ||
| console.error(`Failed to mark notification ${notificationId} as read`); | ||
| }); | ||
| }, []); | ||
|
|
||
| return ( | ||
| <> | ||
| <NotificationButton onClick={handleClick} disabled={!userId}> | ||
| <Badge badgeContent={unreadCount} color="error"> | ||
| <InfoIcon /> | ||
| </Badge> | ||
| </NotificationButton> | ||
| {showMenu && ( | ||
| <NotificationMenu | ||
| anchorEl={anchorEl} | ||
| open={showMenu} | ||
| onClose={handleClose} | ||
| notifications={notifications} | ||
| onMarkAsRead={handleMarkAsRead} | ||
| /> | ||
| )} | ||
| </> | ||
| ); | ||
| }; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.