From 75303e58f0180991f07757c528adb9134e5ef8ed Mon Sep 17 00:00:00 2001 From: "Lucian I. Last" Date: Mon, 13 May 2024 10:37:28 +0200 Subject: [PATCH] Only show edit icon is chain admin --- app/src/components/Chat/ChatWindow.tsx | 90 +++++++++++++++----------- app/src/pages/Chat.tsx | 19 ++++-- server/internal/controllers/chat.go | 26 ++++++++ server/internal/services/chat.go | 16 +++++ 4 files changed, 109 insertions(+), 42 deletions(-) diff --git a/app/src/components/Chat/ChatWindow.tsx b/app/src/components/Chat/ChatWindow.tsx index 534b02ea6..ef101fe94 100644 --- a/app/src/components/Chat/ChatWindow.tsx +++ b/app/src/components/Chat/ChatWindow.tsx @@ -3,17 +3,16 @@ import { IsChainAdmin, MmData, StoreContext } from "../../stores/Store"; import ChatInput, { SendingMsgState } from "./ChatInput"; import { Channel } from "@mattermost/types/channels"; import { IonActionSheet, IonAlert, IonIcon, useIonAlert } from "@ionic/react"; -import { addOutline } from "ionicons/icons"; +import { addOutline, build as buildFilled } from "ionicons/icons"; import { useTranslation } from "react-i18next"; import { IonAlertCustomEvent } from "@ionic/core"; import { PostList } from "@mattermost/types/posts"; import { User } from "../../api/types"; import ChatPost from "./ChatPost"; import { useIntersectionObserver } from "@uidotdev/usehooks"; -import { useContext, useEffect, useRef, useState } from "react"; +import { useContext, useEffect, useMemo, useRef, useState } from "react"; import { useDebouncedCallback } from "use-debounce"; import { useLongPress } from "use-long-press"; -import { c } from "vitest/dist/reporters-5f784f42"; interface Props { channels: Channel[]; @@ -22,7 +21,7 @@ interface Props { authUser: User; onCreateChannel: (n: string) => void; onSelectChannel: (c: Channel) => void; - onRenameChannel: (n: string) => void; + onRenameChannel: (c: Channel, n: string) => void; onDeleteChannel: () => void; onScrollTop: (topPostId: string) => void; onSendMessage: (msg: string, callback: Function) => Promise; @@ -31,7 +30,7 @@ interface Props { // This follows the controller / view component pattern export default function ChatWindow(props: Props) { const { t } = useTranslation(); - const { isChainAdmin } = useContext(StoreContext); + const { isChainAdmin, chain } = useContext(StoreContext); const slowTriggerScrollTop = useDebouncedCallback(() => { const lastPostId = props.postList.order.at(-1); if (lastPostId) { @@ -54,6 +53,14 @@ export default function ChatWindow(props: Props) { } }, [entry?.isIntersecting]); + const chainChannels = useMemo(() => { + if (!chain || !chain.chat_room_ids) return []; + console.log("chainChannels", props.channels); + return props.channels + .filter((c) => chain.chat_room_ids?.includes(c.id)) + .sort((a, b) => (a.create_at > b.create_at ? 1 : 0)); + }, [props.channels, chain]); + function onCreateChannelSubmit(e: IonAlertCustomEvent) { if (e?.detail?.role === "submit" && e.detail?.data?.values?.name) { props.onCreateChannel(e.detail.data.values.name); @@ -61,7 +68,8 @@ export default function ChatWindow(props: Props) { } function onRenameChannelSubmit(name: string) { - props.onRenameChannel(name); + if (!props.selectedChannel) return; + props.onRenameChannel(props.selectedChannel, name); } function onDeleteChannelSubmit() { @@ -106,8 +114,8 @@ export default function ChatWindow(props: Props) { ], }); } else if (value == "rename") { - const handler = (newChannelName: string) => { - onRenameChannelSubmit(newChannelName); + const handler = (e: { newChannelName: string }) => { + onRenameChannelSubmit(e.newChannelName); }; presentAlert({ header: "Rename chat room?", @@ -123,7 +131,7 @@ export default function ChatWindow(props: Props) { ], inputs: [ { - placeholder: props.selectedChannel?.name, + placeholder: props.selectedChannel?.display_name, name: "newChannelName", }, ], @@ -134,42 +142,48 @@ export default function ChatWindow(props: Props) { return (
- {props.channels?.map((cr, i) => { + {chainChannels.map((cr, i) => { const initials = cr.display_name .split(" ") .map((word) => word[0]) .join(""); const isSelected = cr.id === props.selectedChannel?.id; return ( -
- {isSelected ? ( - - ) : ( - + ); })} {isChainAdmin ? ( diff --git a/app/src/pages/Chat.tsx b/app/src/pages/Chat.tsx index 06baa0977..82408280e 100644 --- a/app/src/pages/Chat.tsx +++ b/app/src/pages/Chat.tsx @@ -44,7 +44,8 @@ type WebSocketMessagePosted = WebSocketMessage<{ // This follows the controller / view component pattern export default function Chat() { const { t } = useTranslation(); - const { chain, mmData, setMmData, isThemeDefault } = useContext(StoreContext); + const { chain, setChain, mmData, setMmData, isThemeDefault } = + useContext(StoreContext); const [mmWsClient, setMmWsClient] = useState(null); const [channels, setChannels] = useState([]); @@ -163,9 +164,12 @@ export default function Chat() { ...(chain.chat_room_ids || []), id, ]); + const _channel = _channels.find((c) => c.id == id) || null; + setChannels(_channels); - const _channel = _channels.at(-1) || null; setSelectedChannel(_channel); + // update chain object from server to update chain.room_ids value + await setChain(chain.uid, authUser); if (!_channel) return; reqPostList(mmClient, _channel, ""); } catch (err) { @@ -173,7 +177,7 @@ export default function Chat() { } } - async function onRenameChannel(name: string) { + async function onRenameChannel(channel: Channel, name: string) { if (!chain || !mmClient) { if (!chain) console.error("chain not found"); if (!mmClient) console.error("mmClient not found"); @@ -181,7 +185,14 @@ export default function Chat() { } try { console.info("Updating channel name", name); - // Update channel name + channel.display_name = name; + await mmClient.updateChannel(channel); + const _channels = await getChannels( + mmClient, + mmData, + chain?.chat_room_ids || [], + ); + setChannels(_channels); } catch (err) { console.error(err); } diff --git a/server/internal/controllers/chat.go b/server/internal/controllers/chat.go index a6698a68d..b3dd31883 100644 --- a/server/internal/controllers/chat.go +++ b/server/internal/controllers/chat.go @@ -85,6 +85,32 @@ func ChatCreateChannel(c *gin.Context) { }) } +func ChatDeleteChannel(c *gin.Context) { + db := getDB(c) + + var body struct { + ChainUID string `json:"chain_uid" binding:"required,uuid"` + ChannelID string `json:"channel_id" binding:"required"` + } + if err := c.ShouldBindJSON(&body); err != nil { + c.AbortWithError(http.StatusBadRequest, err) + return + } + + ok, _, chain := auth.Authenticate(c, db, auth.AuthState3AdminChainUser, body.ChainUID) + if !ok { + return + } + + err := services.ChatDeleteChannel(db, c.Request.Context(), chain, body.ChannelID) + if err != nil { + c.AbortWithError(http.StatusInternalServerError, err) + return + } + + c.Status(http.StatusOK) +} + func ChatJoinChannels(c *gin.Context) { db := getDB(c) diff --git a/server/internal/services/chat.go b/server/internal/services/chat.go index 12e92c085..ae19ccc5a 100644 --- a/server/internal/services/chat.go +++ b/server/internal/services/chat.go @@ -88,6 +88,22 @@ func ChatCreateChannel(db *gorm.DB, ctx context.Context, chain *models.Chain, mm return newChannel, nil } +func ChatDeleteChannel(db *gorm.DB, ctx context.Context, chain *models.Chain, mmChannelID string) error { + _, err := app.ChatClient.DeleteChannel(ctx, mmChannelID) + if err != nil { + return err + } + + chain.ChatRoomIDs = lo.Filter(chain.ChatRoomIDs, func(roomID string, _ int) bool { + return roomID != mmChannelID + }) + err = chain.SaveChannelIDs(db) + if err != nil { + return err + } + return nil +} + func chatChannelAddUser(ctx context.Context, mmChannelId string, mmUserId string, setRoleAdmin bool) error { member, _, err := app.ChatClient.AddChannelMember(ctx, mmChannelId, mmUserId) if err != nil {