Skip to content

Commit

Permalink
feat: Implement notifications handling (#25)
Browse files Browse the repository at this point in the history
* feat: Implement ´DirectMessageModal´ component

* feat: Abstract logic into ´useUserSearch´ and ´useInvitationLink´ hooks

* feat: Implement ´DirectChatRecent´ component

* feat: Implement ´DirectMessageModal´ for SidebarActions

* fix: Resolve comments of the PR

* feat: Implement `useDebounced` hook

* feat: More use `useCallback` for `useSidebarActions`

* refactor: Convert `SidebarActions` as smart component

* refactor: Improve `Modal` component for use `createPortal`

* refactor: More use `Modal` component

* refactor: Improve modals handling for `SidebarActions` component

* feat: Implement `NotificationsModal` and `Notification` components

* fix: Fix visual problems for `Modal`

* refactor: Resolve PR comments about tailwindcss class

* refactor: Remove redundant tailwindcss class

* feat: Implement `useNotification` hook

* refactor: Resolve PR comments.

* refactor: Fix TailwindCss class problems

* feat: Implement notifications handling for `useNotifications` hook

* feat: Implement `useSidebarModalActiveStore`

* fix: Fix visual problems for components.

* fix: Fix storybook stories problems

* feat: Upgrade `Typography` component

* feat: Upgrade `UserProfile` component

* refactor: Refactor storybook stories

* feat: Implement `useChatInput` for `ChatContainer` component

* fix: Fix visual problem for `TextMessage`

* feat: Implement `useCachedNotifications` hook

* Merge with cristian/upgrade-components

* refactor: Remove footer for `Readme.md`

* fix: Fix `pre-commit` problems

* feat: Implement events handling for notifications

* feat: Improve notifications handling

* fix: Test eslint actions

* Revert "fix: Test eslint actions"

This reverts commit 0553f60.

* feat: Implement room member events for notifications

* feat: Implement mention for notification

* feat: Upgrade `saveNotification` for `useCachedNotifications`

* fix: Improve code for `NotificationsModal`

* feat: Implement power levels event for notifications

* feat: Implement deploy-pages for deployment

* refactor: Upgrade deploy-pages

* feat: Implement deploy from dev for github actions

* fix: Resolve PR comments

* feat: Implement delete notification action

* feat: Implement mark as read for notifications

* feat: Implement `markAsReadAllNotifications` function for `useCachedNotifications`

* feat: Implement `useNotificationsStateStore`

* fix: Fix PR comments

* feat: Implement handling directs room for notifications

* fix: Fix PR problems

* feat: Upgrade local notifications handling

* feat: Implement other type of notification handling

* feat: Upgrade new notification handling

* feat: Upgrade `power levels` event for notifications

* feat: Upgrade members event for notifications

* refactor: Fix PR comments

* fix: Upgrade `saveNotification` function

* fix: Resolve PR comments

* fix: Use key for lists

* refactor: Use yarn for `pre-commit`

* fix: Fix prettier problems
  • Loading branch information
criss8X authored Apr 7, 2024
1 parent 9714693 commit 9344de6
Show file tree
Hide file tree
Showing 29 changed files with 733 additions and 259 deletions.
5 changes: 4 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
]
},
"extends": [
"eslint:recommended",
"plugin:react/jsx-runtime",
"standard-with-typescript",
"eslint-config-prettier",
"plugin:storybook/recommended",
Expand Down Expand Up @@ -82,6 +84,7 @@
],
"promise/always-return": "off",
"unicorn/number-literal-case": "off",
"unicorn/prefer-spread": "off"
"unicorn/prefer-spread": "off",
"react/jsx-key": "error"
}
}
26 changes: 26 additions & 0 deletions .github/workflows/deploy-push-master.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Build and Deploy to GitHub Pages

on:
push:
branches:
- main

jobs:
build-and-deploy:
runs-on: ubuntu-latest

steps:
- name: Checkout Repository
uses: actions/checkout@v2

- name: Install Dependencies
run: yarn

- name: Build Project
run: yarn build

- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./dist
4 changes: 2 additions & 2 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npx eslint "src/**/*.ts"
npx commitlint --edit "$1"
yarn lint
yarn commitlint --edit
8 changes: 0 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,3 @@ npm run dev
- [Storybook.js](https://storybook.js.org/): Isolated component development environment

<hr />
<div align="center">
<i>
Please feel free to reach out to me on <a href="https://www.linkedin.com/in/yurixander/">LinkedIn</a> for business inquiries.<br />
Images generated with DALL·E 3, and edited with Figma.<br />
&copy; 2023 Yurixander Ricardo<br /><br />
<img alt="Thumbs up illustration" src="./github/thumbs-up.png" />
</i>
</div>
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@
"eslint-plugin-n": "^16.6.2",
"eslint-plugin-no-use-extend-native": "^0.5.0",
"eslint-plugin-promise": "^6.1.1",
"eslint-plugin-react": "^7.34.0",
"eslint-plugin-react": "^7.34.1",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-regexp": "^2.3.0",
"eslint-plugin-sonarjs": "^0.24.0",
Expand Down
2 changes: 1 addition & 1 deletion src/components/ContextMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from "react"
import type React from "react"
import {useCallback, useEffect, type FC} from "react"
import {create} from "zustand"

Expand Down
4 changes: 3 additions & 1 deletion src/components/IconButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export type IconButtonProps = {
onClick: () => void
tooltip: string
Icon: IconType
size?: number
color?: string
isDisabled?: boolean
isDotVisible?: boolean
Expand All @@ -19,6 +20,7 @@ const IconButton: FC<IconButtonProps> = ({
color,
isDisabled,
isDotVisible,
size,
className,
}) => {
const isDisabledClass = isDisabled
Expand All @@ -38,7 +40,7 @@ const IconButton: FC<IconButtonProps> = ({
className
)}>
<NotificationDot isVisible={isDotVisible ?? false}>
<Icon style={{color}} size={20} className="text-neutral-300" />
<Icon style={{color}} size={size ?? 20} className="text-neutral-300" />
</NotificationDot>
</div>
)
Expand Down
3 changes: 2 additions & 1 deletion src/components/Input.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, {useState, type FC} from "react"
import type React from "react"
import {useState, type FC} from "react"
import IconButton from "./IconButton"
import Label from "./Label"
import {twMerge} from "tailwind-merge"
Expand Down
3 changes: 2 additions & 1 deletion src/components/Modal.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {assert} from "@/utils/util"
import React, {type FC} from "react"
import type React from "react"
import {type FC} from "react"
import {createPortal} from "react-dom"
import {twMerge} from "tailwind-merge"

Expand Down
6 changes: 3 additions & 3 deletions src/components/RosterUser.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import UserProfile, {
} from "./UserProfile"

export enum UserPowerLevel {
Admin,
Moderator,
Member,
Admin = 100,
Moderator = 50,
Member = 0,
}

export type RosterUserProps = {
Expand Down
10 changes: 6 additions & 4 deletions src/components/SidebarActions/DirectMessageModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,11 +118,13 @@ const DirectMessageModal: FC = () => {

<div className="flex h-full flex-col gap-1 overflow-y-scroll scrollbar-hide">
{results === null
? directChats.map(directChatProps => (
<DirectChatRecent {...directChatProps} />
? directChats.map((directChatProps, index) => (
<DirectChatRecent key={index} {...directChatProps} />
))
: results.map(userProps => (
<div className="w-full cursor-pointer rounded-lg p-2 hover:bg-neutral-200">
: results.map((userProps, index) => (
<div
key={index}
className="w-full cursor-pointer rounded-lg p-2 hover:bg-neutral-200">
<UserProfile {...userProps} />
</div>
))}
Expand Down
151 changes: 151 additions & 0 deletions src/components/SidebarActions/Notification.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
import useMatrixAction from "@/hooks/matrix/useMatrixAction"
import {
deleteNotificationById,
markAsReadByNotificationId,
} from "@/utils/notifications"
import {stringToColor, timeFormatter} from "@/utils/util"
import {type FC} from "react"
import {IoTime, IoCheckbox, IoTrash} from "react-icons/io5"
import {twMerge} from "tailwind-merge"
import AvatarImage, {AvatarType} from "../Avatar"
import Button, {ButtonColor, ButtonSize, ButtonVariant} from "../Button"
import IconButton from "../IconButton"
import Typography, {TypographyVariant} from "../Typography"
import {type LocalNotificationData} from "./useCachedNotifications"

export interface NotificationProps extends LocalNotificationData {
onRequestChanges: () => void
hasActions: boolean
}

const Notification: FC<NotificationProps> = ({
body,
notificationTime,
hasActions,
senderName,
avatarSenderUrl,
notificationId,
isRead,
onRequestChanges,
}) => {
const onJoinRoom = useMatrixAction(client => {
if (!hasActions) {
return null
}

void client.joinRoom(notificationId)
deleteNotificationById(notificationId)
onRequestChanges()
})

// TODO: Launch `Toast` if you rejected the room invitation.
const onLeaveRoom = useMatrixAction(client => {
if (!hasActions) {
return
}

void client.leave(notificationId)
deleteNotificationById(notificationId)
onRequestChanges()
})

const userComponent =
senderName === undefined ? undefined : (
<b style={{color: stringToColor(senderName)}}>{senderName}</b>
)

return (
<div
className={twMerge(
"flex gap-2 p-2",
!isRead && "rounded-lg bg-slate-100"
)}>
{senderName !== undefined && (
<div className="size-full max-h-8 max-w-8 overflow-hidden rounded-lg">
<AvatarImage
isRounded={false}
isLarge={false}
avatarType={AvatarType.Message}
displayName={senderName}
avatarUrl={avatarSenderUrl}
/>
</div>
)}

<div className="flex flex-col gap-1">
<div className="flex flex-row">
<Typography variant={TypographyVariant.P}>
{userComponent} {body}
</Typography>
</div>

<div className="flex items-center gap-[2px]">
<IoTime size={13} />

<Typography variant={TypographyVariant.P}>
{timeFormatter(notificationTime)}
</Typography>
</div>

{hasActions && (
<div className="mt-2 flex flex-row gap-1">
<Button
label="Accept"
color={ButtonColor.Black}
size={ButtonSize.Small}
onClick={() => {
if (onJoinRoom === null) {
return
}

void onJoinRoom()
}}
/>

<Button
label="Decline"
variant={ButtonVariant.TextLink}
color={ButtonColor.Black}
size={ButtonSize.Small}
onClick={() => {
if (onLeaveRoom === null) {
return
}

void onLeaveRoom()
}}
/>
</div>
)}
</div>

<div className="ml-auto flex">
{!isRead && (
<IconButton
className="size-min"
size={14}
tooltip="Remove notification"
Icon={IoCheckbox}
onClick={() => {
markAsReadByNotificationId(notificationId)
onRequestChanges()
}}
/>
)}

<IconButton
className="size-min"
size={14}
tooltip="Remove notification"
Icon={IoTrash}
onClick={() => {
deleteNotificationById(notificationId)
onRequestChanges()
}}
/>
</div>
</div>
)
}

export default Notification
Loading

0 comments on commit 9344de6

Please sign in to comment.