From a97bebcda967d7388538bbe13a16b85ea78f5619 Mon Sep 17 00:00:00 2001 From: Thibaut Mouton Date: Fri, 3 May 2024 13:53:58 +0200 Subject: [PATCH] chore():multiples fix --- .github/workflows/maven.yml | 2 +- .../mercure/controller/MessageController.java | 12 ++++ .../mercure/controller/WsFileController.java | 8 ++- .../mercure/repository/FileRepository.java | 7 +- .../mercure/repository/MessageRepository.java | 3 + .../java/com/mercure/service/FileService.java | 8 ++- .../com/mercure/service/GroupService.java | 1 - .../mercure/service/GroupUserJoinService.java | 14 ++++ .../com/mercure/service/MessageService.java | 21 ++++-- .../com/mercure/utils/MessageTypeEnum.java | 2 +- .../CreateConversationComponent.tsx | 5 +- frontend-web/src/components/home.tsx | 59 +++++++--------- .../src/components/login/LoginComponent.tsx | 43 ++++++------ .../messages/CreateMessageComponent.tsx | 5 +- .../components/partials/alert-component.tsx | 55 ++++++++++----- .../list-items/MultimediaListComponent.tsx | 70 +++++++++++++++++++ .../list-items/MultimediaListStyle.css | 11 +++ .../src/components/register/register-form.css | 10 ++- .../user-account/UseAccountComponent.tsx | 8 ++- .../websocket/websocket-chat-component.tsx | 2 +- .../websocket-group-actions-component.tsx | 10 +-- .../websocket/websocket-groups-component.tsx | 4 +- frontend-web/src/context/AlertContext.tsx | 6 +- frontend-web/src/context/GroupContext.tsx | 2 + frontend-web/src/index.tsx | 4 +- .../src/service/http-group-service.ts | 8 +++ frontend-web/src/service/http-main.service.ts | 9 ++- 27 files changed, 275 insertions(+), 114 deletions(-) create mode 100644 frontend-web/src/components/partials/list-items/MultimediaListComponent.tsx create mode 100644 frontend-web/src/components/partials/list-items/MultimediaListStyle.css diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 094ef7d..2048b4e 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -15,4 +15,4 @@ jobs: distribution: 'temurin' cache: maven - name: build - run: mvn compile -f backend/pom.xml + run: mvn -Dmaven.test.skip=true compile -f backend/pom.xml diff --git a/backend/src/main/java/com/mercure/controller/MessageController.java b/backend/src/main/java/com/mercure/controller/MessageController.java index e493d17..426214e 100644 --- a/backend/src/main/java/com/mercure/controller/MessageController.java +++ b/backend/src/main/java/com/mercure/controller/MessageController.java @@ -1,12 +1,15 @@ package com.mercure.controller; import com.mercure.dto.WrapperMessageDTO; +import com.mercure.service.GroupUserJoinService; import com.mercure.service.MessageService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; +import java.util.Date; + @RestController @RequestMapping(value = "/messages") @CrossOrigin(allowCredentials = "true", origins = "http://localhost:3000") @@ -17,9 +20,18 @@ public class MessageController { @Autowired private MessageService messageService; + @Autowired + private GroupUserJoinService groupUserJoinService; + @GetMapping(value = "{offset}/group/{groupUrl}") public WrapperMessageDTO fetchGroupMessages(@PathVariable String groupUrl, @PathVariable int offset) { this.log.debug("Fetching messages from conversation"); return this.messageService.getConversationMessage(groupUrl, offset); } + + @GetMapping(value = "seen/group/{groupUrl}/user/{userId}") + public void markMessageAsSeen(@PathVariable String groupUrl, @PathVariable int userId) { + this.log.debug("Mark message as seen"); + this.groupUserJoinService.saveLastMessageDate(userId, groupUrl); + } } diff --git a/backend/src/main/java/com/mercure/controller/WsFileController.java b/backend/src/main/java/com/mercure/controller/WsFileController.java index d368965..372422d 100644 --- a/backend/src/main/java/com/mercure/controller/WsFileController.java +++ b/backend/src/main/java/com/mercure/controller/WsFileController.java @@ -18,10 +18,11 @@ import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; +import java.util.Arrays; import java.util.List; @RestController -@CrossOrigin(allowCredentials = "true", origins = "http://localhost:3000") +@CrossOrigin(allowCredentials = "true", origins = "http://localhost:3000", methods = {RequestMethod.GET, RequestMethod.POST}) public class WsFileController { private static final Logger log = LoggerFactory.getLogger(WsFileController.class); @@ -68,4 +69,9 @@ public ResponseEntity uploadFile(@RequestParam(name = "file") MultipartFile f } return ResponseEntity.ok().build(); } + + @GetMapping("files/groupUrl/{groupUrl}") + public List getMultimediaContent(@PathVariable String groupUrl) { + return messageService.getMultimediaContentByGroup(groupUrl); + } } diff --git a/backend/src/main/java/com/mercure/repository/FileRepository.java b/backend/src/main/java/com/mercure/repository/FileRepository.java index 9574255..123ee93 100644 --- a/backend/src/main/java/com/mercure/repository/FileRepository.java +++ b/backend/src/main/java/com/mercure/repository/FileRepository.java @@ -6,11 +6,16 @@ import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; +import java.util.List; + @Repository -public interface FileRepository extends JpaRepository { +public interface FileRepository extends JpaRepository { FileEntity findByMessageId(int id); @Query(value = "SELECT storage.url FROM file_storage storage WHERE storage.fk_message_id = :id", nativeQuery = true) String findFileUrlByMessageId(@Param(value = "id") int id); + + @Query(value = "SELECT url FROM file_storage file INNER JOIN message m ON m.id = file.fk_message_id WHERE m.msg_group_id = :groupId", nativeQuery = true) + List findFilesUrlsByGroupId(@Param(value = "groupId") int groupId); } diff --git a/backend/src/main/java/com/mercure/repository/MessageRepository.java b/backend/src/main/java/com/mercure/repository/MessageRepository.java index 6667f22..7aadc9a 100644 --- a/backend/src/main/java/com/mercure/repository/MessageRepository.java +++ b/backend/src/main/java/com/mercure/repository/MessageRepository.java @@ -24,6 +24,9 @@ public interface MessageRepository extends JpaRepository @Query(value = "SELECT m1.id FROM message m1 INNER JOIN (SELECT MAX(m.id) as id FROM message m GROUP BY m.msg_group_id) temp ON temp.id = m1.id WHERE msg_group_id = :idOfGroup", nativeQuery = true) int findLastMessageIdByGroupId(@Param(value = "idOfGroup") int groupId); + @Query(value = "SELECT m. FROM message m WHERE m.id = :idOfGroup AND m.type = 'FILE'", nativeQuery = true) + List findAllFilesByGroupId(@Param(value = "idOfGroup") int groupId); + @Modifying @Query(value = "DELETE m, mu FROM message m JOIN message_user mu ON m.id = mu.message_id WHERE m.msg_group_id = :groupId", nativeQuery = true) void deleteMessagesDataByGroupId(@Param(value = "groupId") int groupId); diff --git a/backend/src/main/java/com/mercure/service/FileService.java b/backend/src/main/java/com/mercure/service/FileService.java index c1827dc..bcfd93b 100644 --- a/backend/src/main/java/com/mercure/service/FileService.java +++ b/backend/src/main/java/com/mercure/service/FileService.java @@ -5,6 +5,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.util.List; + @Service public class FileService { @@ -19,7 +21,11 @@ public FileEntity findByFkMessageId(int id) { return fileRepository.findByMessageId(id); } + public List getFilesUrlByGroupId(int groupId) { + return fileRepository.findFilesUrlsByGroupId(groupId); + } + public String findFileUrlByMessageId(int id) { - return fileRepository.findFileUrlByMessageId(id); + return fileRepository.findFileUrlByMessageId(id); } } diff --git a/backend/src/main/java/com/mercure/service/GroupService.java b/backend/src/main/java/com/mercure/service/GroupService.java index e864b8d..590d38f 100644 --- a/backend/src/main/java/com/mercure/service/GroupService.java +++ b/backend/src/main/java/com/mercure/service/GroupService.java @@ -9,7 +9,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import javax.swing.*; import java.sql.Timestamp; import java.util.*; import java.util.stream.Collectors; diff --git a/backend/src/main/java/com/mercure/service/GroupUserJoinService.java b/backend/src/main/java/com/mercure/service/GroupUserJoinService.java index d8a5847..3f385b5 100644 --- a/backend/src/main/java/com/mercure/service/GroupUserJoinService.java +++ b/backend/src/main/java/com/mercure/service/GroupUserJoinService.java @@ -4,11 +4,14 @@ import com.mercure.entity.GroupRoleKey; import com.mercure.entity.GroupUser; import com.mercure.repository.GroupUserJoinRepository; +import org.aspectj.weaver.ast.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.sql.Timestamp; +import java.util.Date; import java.util.List; import java.util.Optional; @@ -23,6 +26,9 @@ public class GroupUserJoinService { @Autowired private MessageService messageService; + @Autowired + private GroupService groupService; + public GroupUser save(GroupUser groupUser) { return groupUserJoinRepository.save(groupUser); } @@ -51,6 +57,14 @@ public GroupUser findGroupUser(int userId, int groupId) { return groupUserJoinRepository.getGroupUser(userId, groupId); } + public void saveLastMessageDate(int userId, String groupUrl) { + int groupId = groupService.findGroupByUrl(groupUrl); + GroupUser groupUser = groupUserJoinRepository.getGroupUser(userId, groupId); + Date date = new Date(); + Timestamp ts = new Timestamp(date.getTime()); + groupUser.setLastMessageSeenDate(ts); + } + public boolean checkIfUserIsAuthorizedInGroup(int userId, int groupId) { List ids = groupUserJoinRepository.getUsersIdInGroup(groupId); return ids.stream().noneMatch(id -> id == userId); diff --git a/backend/src/main/java/com/mercure/service/MessageService.java b/backend/src/main/java/com/mercure/service/MessageService.java index 366a2b0..2a12df8 100644 --- a/backend/src/main/java/com/mercure/service/MessageService.java +++ b/backend/src/main/java/com/mercure/service/MessageService.java @@ -3,10 +3,7 @@ import com.mercure.dto.MessageDTO; import com.mercure.dto.NotificationDTO; import com.mercure.dto.WrapperMessageDTO; -import com.mercure.entity.FileEntity; -import com.mercure.entity.GroupEntity; -import com.mercure.entity.MessageEntity; -import com.mercure.entity.UserEntity; +import com.mercure.entity.*; import com.mercure.repository.MessageRepository; import com.mercure.utils.MessageTypeEnum; import org.springframework.beans.factory.annotation.Autowired; @@ -22,6 +19,9 @@ public class MessageService { @Autowired private MessageRepository messageRepository; + @Autowired + private FileService fileService; + @Autowired private MessageService messageService; @@ -31,9 +31,6 @@ public class MessageService { @Autowired private UserService userService; - @Autowired - private FileService fileService; - public MessageEntity createAndSaveMessage(int userId, int groupId, String type, String data) { MessageEntity msg = new MessageEntity(userId, groupId, type, data); return messageRepository.save(msg); @@ -116,6 +113,10 @@ public NotificationDTO createNotificationDTO(MessageEntity msg) { notificationDTO.setType(MessageTypeEnum.TEXT); notificationDTO.setMessage(msg.getMessage()); } + if (msg.getType().equals(MessageTypeEnum.CALL.toString())) { + notificationDTO.setType(MessageTypeEnum.CALL); + notificationDTO.setMessage(msg.getMessage()); + } if (msg.getType().equals(MessageTypeEnum.FILE.toString())) { FileEntity fileEntity = fileService.findByFkMessageId(msg.getId()); notificationDTO.setType(MessageTypeEnum.FILE); @@ -154,6 +155,12 @@ public MessageDTO createNotificationMessageDTO(MessageEntity msg, int userId) { return messageDTO; } + // TODO check that the request is authorized by user making the call + public List getMultimediaContentByGroup(String groupUrl) { + int groupId = groupService.findGroupByUrl(groupUrl); + return fileService.getFilesUrlByGroupId(groupId); + } + public WrapperMessageDTO getConversationMessage(String url, int messageId) { WrapperMessageDTO wrapper = new WrapperMessageDTO(); if (url != null) { diff --git a/backend/src/main/java/com/mercure/utils/MessageTypeEnum.java b/backend/src/main/java/com/mercure/utils/MessageTypeEnum.java index 50a872c..7fd6634 100644 --- a/backend/src/main/java/com/mercure/utils/MessageTypeEnum.java +++ b/backend/src/main/java/com/mercure/utils/MessageTypeEnum.java @@ -1,5 +1,5 @@ package com.mercure.utils; public enum MessageTypeEnum { - TEXT, FILE + TEXT, FILE, CALL } diff --git a/frontend-web/src/components/create-conversation/CreateConversationComponent.tsx b/frontend-web/src/components/create-conversation/CreateConversationComponent.tsx index b29e806..343cb3e 100644 --- a/frontend-web/src/components/create-conversation/CreateConversationComponent.tsx +++ b/frontend-web/src/components/create-conversation/CreateConversationComponent.tsx @@ -4,7 +4,7 @@ import NoteAddOutlinedIcon from "@mui/icons-material/NoteAddOutlined" import {Button, Dialog, DialogActions, DialogContent, DialogTitle, TextField} from "@mui/material" import {HttpGroupService} from "../../service/http-group-service" import {AlertAction, AlertContext} from "../../context/AlertContext" -import {redirect} from "react-router-dom" +import {useNavigate} from "react-router-dom" import {GroupContext, GroupContextAction} from "../../context/GroupContext" export function CreateConversationComponent(): React.JSX.Element { @@ -14,6 +14,7 @@ export function CreateConversationComponent(): React.JSX.Element { const httpService = new HttpGroupService() const {changeGroupState} = useContext(GroupContext)! const {dispatch} = useContext(AlertContext)! + const navigate = useNavigate() function handleClickOpen() { setOpen(true) @@ -39,7 +40,7 @@ export function CreateConversationComponent(): React.JSX.Element { }) changeGroupState({type: GroupContextAction.ADD_GROUP, payload: data}) setOpen(false) - redirect(`/t/messages/${data.url}`) + navigate(`/t/messages/${data.url}`) } catch (error) { dispatch({ type: AlertAction.ADD_ALERT, diff --git a/frontend-web/src/components/home.tsx b/frontend-web/src/components/home.tsx index 49e0873..6b999e1 100644 --- a/frontend-web/src/components/home.tsx +++ b/frontend-web/src/components/home.tsx @@ -1,53 +1,44 @@ -import {Box, Card, CardContent, Grid, Typography} from "@mui/material" -import React, {useContext, useEffect} from "react" +import {Card, CardContent, Grid, Typography} from "@mui/material" +import React, {useEffect} from "react" import {generateColorMode} from "./utils/enable-dark-mode" import {useThemeContext} from "../context/theme-context" import {FooterComponent} from "./partials/footer-component" import {LoginComponent} from "./login/LoginComponent" -import {UserContext} from "../context/UserContext" export const HomeComponent = (): React.JSX.Element => { const {theme} = useThemeContext() - const {user} = useContext(UserContext)! useEffect(() => { document.title = "Home | FLM" }, []) return ( -
- - - - - - - Welcome to FastLiteMessage {user?.firstName} - +
+ + + + + + Welcome to FastLiteMessage + - {"test + {"test - - Simple, fast and secure - -
FastLiteMessage allow to communicate with other people, create groups, make - serverless video calls in an easy way. Log into your account or register to start - using FastLiteMessage. -
- -
-
-
- - - + + Simple, fast and secure + +
FastLiteMessage allow to communicate with other people, create groups, make + serverless video calls in an easy way. Log into your account or register to start + using FastLiteMessage. +
+ + +
- + + + +
) } diff --git a/frontend-web/src/components/login/LoginComponent.tsx b/frontend-web/src/components/login/LoginComponent.tsx index 15bd2d8..2c7405b 100644 --- a/frontend-web/src/components/login/LoginComponent.tsx +++ b/frontend-web/src/components/login/LoginComponent.tsx @@ -1,10 +1,9 @@ import LockIcon from "@mui/icons-material/Lock" -import {Button, Grid, Typography} from "@mui/material" +import {Button, Grid, TextField, Typography} from "@mui/material" import React, {useContext, useEffect, useState} from "react" -import {Link, redirect} from "react-router-dom" +import {Link, useNavigate} from "react-router-dom" import {useThemeContext} from "../../context/theme-context" import {generateIconColorMode, generateLinkColorMode} from "../utils/enable-dark-mode" -import {CustomTextField} from "../partials/custom-material-textfield" import {HttpGroupService} from "../../service/http-group-service" import {LoaderContext} from "../../context/loader-context" import {AlertAction, AlertContext} from "../../context/AlertContext" @@ -13,6 +12,7 @@ export function LoginComponent(): React.JSX.Element { const [username, setUsername] = useState("") const [password, setPassword] = useState("") + const navigate = useNavigate() const {dispatch} = useContext(AlertContext)! const {setLoading} = useContext(LoaderContext) const {theme} = useThemeContext() @@ -52,7 +52,7 @@ export function LoginComponent(): React.JSX.Element { username, password }) - redirect("t/messages") + navigate("/t/messages") } catch (err: any) { dispatch({ type: AlertAction.ADD_ALERT, @@ -73,7 +73,7 @@ export function LoginComponent(): React.JSX.Element { return (
@@ -91,25 +91,24 @@ export function LoginComponent(): React.JSX.Element {
- + - diff --git a/frontend-web/src/components/messages/CreateMessageComponent.tsx b/frontend-web/src/components/messages/CreateMessageComponent.tsx index 1a661f2..99fc033 100644 --- a/frontend-web/src/components/messages/CreateMessageComponent.tsx +++ b/frontend-web/src/components/messages/CreateMessageComponent.tsx @@ -22,8 +22,8 @@ export function CreateMessageComponent({groupUrl}: CreateMessageComponentProps): const [, setImageLoaded] = useState(false) const [message, setMessage] = useState("") const [file, setFile] = React.useState(null) - const [imagePreviewUrl, setImagePreviewUrl] = React.useState("") + const groupService = new HttpGroupService() function submitMessage(event: any) { if (event.key !== undefined && event.shiftKey && event.keyCode === 13) { @@ -86,7 +86,8 @@ export function CreateMessageComponent({groupUrl}: CreateMessageComponentProps): } } - function markMessageSeen() { + async function markMessageSeen() { + await groupService.markMessageAsSeen(user?.id || 0, groupUrl) changeGroupState({ type: GroupContextAction.UPDATE_SEEN_MESSAGE, payload: {groupUrl, isMessageSeen: true} }) diff --git a/frontend-web/src/components/partials/alert-component.tsx b/frontend-web/src/components/partials/alert-component.tsx index ffc8e19..c297d12 100644 --- a/frontend-web/src/components/partials/alert-component.tsx +++ b/frontend-web/src/components/partials/alert-component.tsx @@ -1,34 +1,51 @@ -import {Alert, AlertTitle, Collapse} from "@mui/material" +import {Alert, AlertTitle, Collapse, Snackbar} from "@mui/material" import React, {useContext} from "react" -import {AlertAction, AlertContext} from "../../context/AlertContext" +import {AlertAction, AlertContext, AlertSeverityType} from "../../context/AlertContext" -export const AlertComponent: React.FunctionComponent = () => { +export function AlertComponent(): React.JSX.Element { const {alerts, dispatch} = useContext(AlertContext)! function closeAlert(id: string) { dispatch({type: AlertAction.DELETE_ALERT, payload: id}) } + function getAlertTitle(severity: AlertSeverityType): string { + switch (severity) { + case "error": + return "Error" + case "warning": + return "Warning" + case "info": + return "Info" + case "success": + return "Success" + default: + return "Error" + } + } + return ( -
- { - alerts.map((value) => ( -
- +
+ { + alerts.map((value) => ( +
+ + closeAlert(value.id)}> closeAlert(value.id)} severity={value.alert} - variant={"standard"}> - Success + variant={"filled"}> + {getAlertTitle(value.alert)} {value.text} - -
- )) - } -
+ +
+
+ )) + } +
) } diff --git a/frontend-web/src/components/partials/list-items/MultimediaListComponent.tsx b/frontend-web/src/components/partials/list-items/MultimediaListComponent.tsx new file mode 100644 index 0000000..50f4de9 --- /dev/null +++ b/frontend-web/src/components/partials/list-items/MultimediaListComponent.tsx @@ -0,0 +1,70 @@ +import React, {useContext, useEffect, useState} from "react" +import "./MultimediaListStyle.css" +import {CircularProgress, Collapse, ListItemButton, ListItemIcon, ListItemText} from "@mui/material" +import {ExpandLess, FolderCopy} from "@mui/icons-material" +import ExpandMore from "@mui/icons-material/ExpandMore" +import {HttpGroupService} from "../../../service/http-group-service" +import {AlertAction, AlertContext} from "../../../context/AlertContext" + +interface MultimediaListProps { + isDisabled: boolean + groupUrl: string +} + +export function MultimediaListComponent({groupUrl, isDisabled}: MultimediaListProps) { + const {dispatch} = useContext(AlertContext)! + const [isListOpened, setListStatus] = useState(false) + const [multimediaContent, setMultimediaContent] = useState([]) + const http = new HttpGroupService() + const [mediaLoading, setMediaLoading] = useState(false) + + useEffect(() => { + setMultimediaContent([]) + }, [groupUrl]) + + async function changeState() { + if (!isListOpened && multimediaContent.length === 0) { + setMediaLoading(true) + try { + const {data} = await http.getMultimediaFiles(groupUrl) + setMultimediaContent(data) + } catch (error) { + dispatch({ + type: AlertAction.ADD_ALERT, + payload: { + id: crypto.randomUUID(), + text: `Cannot fetch multimedia content : ${error}`, + isOpen: true, + alert: "error", + } + }) + } finally { + + setMediaLoading(false) + } + } + setListStatus(!isListOpened) + } + + return <> + + + + + + {isListOpened ? : } + + +
+ { + multimediaContent.map((file, index) => { + return ( +
+ ) + }) + } +
+ + {mediaLoading && } + +} diff --git a/frontend-web/src/components/partials/list-items/MultimediaListStyle.css b/frontend-web/src/components/partials/list-items/MultimediaListStyle.css new file mode 100644 index 0000000..d1f8d7d --- /dev/null +++ b/frontend-web/src/components/partials/list-items/MultimediaListStyle.css @@ -0,0 +1,11 @@ +.display { + display: grid; + grid-template-rows: repeat(4, 100px); + grid-template-columns: repeat(4, 1fr); +} + +.content { + background-repeat: no-repeat; + background-position: center; + background-size: cover; +} diff --git a/frontend-web/src/components/register/register-form.css b/frontend-web/src/components/register/register-form.css index 6b222bc..adaf1bd 100644 --- a/frontend-web/src/components/register/register-form.css +++ b/frontend-web/src/components/register/register-form.css @@ -1,6 +1,4 @@ .main-register-form { - padding-top: 5px; - padding-bottom: 10px; text-align: center; display: flex; flex-direction: column; @@ -8,8 +6,8 @@ } @media (max-width: 1250px) { - .main-register-form { - margin-left: 20%; - margin-right: 20%; - } + /*.main-register-form {*/ + /* margin-left: 20%;*/ + /* margin-right: 20%;*/ + /*}*/ } diff --git a/frontend-web/src/components/user-account/UseAccountComponent.tsx b/frontend-web/src/components/user-account/UseAccountComponent.tsx index 3935771..b1fb191 100644 --- a/frontend-web/src/components/user-account/UseAccountComponent.tsx +++ b/frontend-web/src/components/user-account/UseAccountComponent.tsx @@ -29,6 +29,12 @@ export function AccountMenu() { setAnchorEl(null) } + function getUserFullName() { + const firstName = user?.firstName + const lastName = user?.lastName + return `${firstName} ${lastName}` + } + function getUserInitials() { const firstName = capitalize((user?.firstName || "").charAt(0)) const lastName = capitalize((user?.lastName || "").charAt(0)) @@ -96,7 +102,7 @@ export function AccountMenu() { anchorOrigin={{horizontal: "right", vertical: "bottom"}} > - Profile + {getUserFullName()} diff --git a/frontend-web/src/components/websocket/websocket-chat-component.tsx b/frontend-web/src/components/websocket/websocket-chat-component.tsx index 202ee0d..2503bc9 100644 --- a/frontend-web/src/components/websocket/websocket-chat-component.tsx +++ b/frontend-web/src/components/websocket/websocket-chat-component.tsx @@ -66,7 +66,7 @@ export const WebSocketChatComponent: React.FunctionComponent<{ groupUrl?: string }}>
diff --git a/frontend-web/src/components/websocket/websocket-group-actions-component.tsx b/frontend-web/src/components/websocket/websocket-group-actions-component.tsx index b7b984a..dc17c41 100644 --- a/frontend-web/src/components/websocket/websocket-group-actions-component.tsx +++ b/frontend-web/src/components/websocket/websocket-group-actions-component.tsx @@ -10,7 +10,7 @@ import { MenuItem, Tooltip } from "@mui/material" -import {ExpandLess, FolderCopy} from "@mui/icons-material" +import {ExpandLess} from "@mui/icons-material" import SecurityIcon from "@mui/icons-material/Security" import ExpandMore from "@mui/icons-material/ExpandMore" import PersonIcon from "@mui/icons-material/Person" @@ -30,6 +30,7 @@ import {WebSocketContext} from "../../context/WebsocketContext" import {GroupContext} from "../../context/GroupContext" import {UserContext} from "../../context/UserContext" import {AlertAction, AlertContext} from "../../context/AlertContext" +import {MultimediaListComponent} from "../partials/list-items/MultimediaListComponent" export const WebSocketGroupActionComponent: React.FunctionComponent<{ groupUrl?: string }> = ({groupUrl}) => { const [paramsOpen, setParamsOpen] = useState(false) @@ -328,12 +329,7 @@ export const WebSocketGroupActionComponent: React.FunctionComponent<{ groupUrl?: ))} - - - - - - + {groupUrl && }
} - - + + {!loadingState && groups && groups.map((group) => ( = ({children}) => ) } -export {AlertContextProvider, AlertAction} +export {AlertContextProvider, AlertAction, type AlertSeverityType} diff --git a/frontend-web/src/context/GroupContext.tsx b/frontend-web/src/context/GroupContext.tsx index ae8725e..7adb694 100644 --- a/frontend-web/src/context/GroupContext.tsx +++ b/frontend-web/src/context/GroupContext.tsx @@ -46,7 +46,9 @@ export const groupReducer = (state: GroupModel[], action: GroupActionType): Grou } case GroupContextAction.UPDATE_SEEN_MESSAGE: { const index = state.findIndex((group) => group.url === action.payload.groupUrl) + console.log("INDEX", index) if (index > -1) { + console.log("ACTION", action.payload.isMessageSeen) state[index].lastMessageSeen = action.payload.isMessageSeen } return state diff --git a/frontend-web/src/index.tsx b/frontend-web/src/index.tsx index 6dca1f3..220090d 100644 --- a/frontend-web/src/index.tsx +++ b/frontend-web/src/index.tsx @@ -19,7 +19,9 @@ const router = createBrowserRouter([ { path: "/", loader: async () => { - return new HttpGroupService().pingRoute().catch(() => redirect("/login")) + return new HttpGroupService().pingRoute() + .then(() => redirect("/t/messages")) + .catch(() => redirect("/login")) }, }, { diff --git a/frontend-web/src/service/http-group-service.ts b/frontend-web/src/service/http-group-service.ts index 991638c..eaa4674 100644 --- a/frontend-web/src/service/http-group-service.ts +++ b/frontend-web/src/service/http-group-service.ts @@ -77,4 +77,12 @@ export class HttpGroupService extends HttpMainService { public uploadFile(data: FormData): Promise { return this.instance.post("upload", data) } + + public getMultimediaFiles(groupUrl: string) { + return this.instance.get(`files/groupUrl/${groupUrl}`) + } + + public markMessageAsSeen(userId: number, groupUrl: string) { + return this.instance.get(`messages/seen/group/${groupUrl}/user/${userId}`) + } } diff --git a/frontend-web/src/service/http-main.service.ts b/frontend-web/src/service/http-main.service.ts index 034306f..8a75c7d 100644 --- a/frontend-web/src/service/http-main.service.ts +++ b/frontend-web/src/service/http-main.service.ts @@ -1,4 +1,4 @@ -import axios, {AxiosInstance} from "axios" +import axios, {AxiosError, AxiosInstance} from "axios" export abstract class HttpMainService { @@ -17,7 +17,12 @@ export abstract class HttpMainService { }) this.instance.interceptors.response.use((response) => { return response - }, (error) => { + }, (error: AxiosError) => { + if (error.response && error.response.status === 403) { + if (window.location.pathname !== "/login") { + window.location.pathname = "/login" + } + } console.log("ERROR", error) return Promise.reject(error) })