diff --git a/src/app/molecules/image-pack/ImagePack.jsx b/src/app/molecules/image-pack/ImagePack.jsx index 79cc2036..3850ad20 100644 --- a/src/app/molecules/image-pack/ImagePack.jsx +++ b/src/app/molecules/image-pack/ImagePack.jsx @@ -201,7 +201,7 @@ function removeGlobalImagePack(mx, roomId, stateKey) { return mx.setAccountData('im.ponies.emote_rooms', content); } -function ImagePack({ roomId, stateKey }) { +function ImagePack({ roomId, stateKey, handlePackDelete }) { const mx = initMatrix.matrixClient; const room = mx.getRoom(roomId); const [viewMore, setViewMore] = useState(false); @@ -228,6 +228,17 @@ function ImagePack({ roomId, stateKey }) { const myPowerlevel = room.getMember(mx.getUserId())?.powerLevel || 0; const canChange = room.currentState.hasSufficientPowerLevelFor('state_default', myPowerlevel); + const handleDeletePack = async () => { + const isConfirmed = await confirmDialog( + 'Delete Pack', + `Are you sure that you want to delete "${pack.displayName}"?`, + 'Delete', + 'danger', + ); + if (!isConfirmed) return; + handlePackDelete(stateKey); + }; + const images = [...pack.images].slice(0, viewMore ? pack.images.size : 2); return ( @@ -264,15 +275,18 @@ function ImagePack({ roomId, stateKey }) { ))} )} - {pack.images.size > 2 && ( + {(pack.images.size > 2 || handlePackDelete) && (
- + {pack.images.size > 2 && ( + + )} + { handlePackDelete && }
)}
@@ -286,9 +300,13 @@ function ImagePack({ roomId, stateKey }) { ); } +ImagePack.defaultProps = { + handlePackDelete: null, +}; ImagePack.propTypes = { roomId: PropTypes.string.isRequired, stateKey: PropTypes.string.isRequired, + handlePackDelete: PropTypes.func, }; export default ImagePack; diff --git a/src/app/molecules/image-pack/ImagePack.scss b/src/app/molecules/image-pack/ImagePack.scss index 7c62ffc9..bd3538a0 100644 --- a/src/app/molecules/image-pack/ImagePack.scss +++ b/src/app/molecules/image-pack/ImagePack.scss @@ -19,6 +19,7 @@ &__footer { padding: var(--sp-normal); display: flex; + justify-content: space-between; gap: var(--sp-tight); } diff --git a/src/app/molecules/room-emojis/RoomEmojis.jsx b/src/app/molecules/room-emojis/RoomEmojis.jsx index a70be847..8e92b8b8 100644 --- a/src/app/molecules/room-emojis/RoomEmojis.jsx +++ b/src/app/molecules/room-emojis/RoomEmojis.jsx @@ -1,12 +1,19 @@ -import React from 'react'; +import React, { useReducer, useEffect } from 'react'; import PropTypes from 'prop-types'; +import './RoomEmojis.scss'; import initMatrix from '../../../client/initMatrix'; +import { suffixRename } from '../../../util/common'; + +import { MenuHeader } from '../../atoms/context-menu/ContextMenu'; +import Text from '../../atoms/text/Text'; +import Input from '../../atoms/input/Input'; +import Button from '../../atoms/button/Button'; import ImagePack from '../image-pack/ImagePack'; -function RoomEmojis({ roomId }) { +function useRoomPacks(room) { const mx = initMatrix.matrixClient; - const room = mx.getRoom(roomId); + const [, forceUpdate] = useReducer((count) => count + 1, 0); const packEvents = room.currentState.getStateEvents('im.ponies.room_emotes'); const unUsablePacks = []; @@ -18,13 +25,102 @@ function RoomEmojis({ roomId }) { return true; }); - return usablePacks.reverse().map((mEvent) => ( - - )); + useEffect(() => { + const handleEvent = (event, state, prevEvent) => { + if (event.getRoomId() !== room.roomId) return; + if (event.getType() !== 'im.ponies.room_emotes') return; + if (!prevEvent?.getContent()?.images || !event.getContent().images) { + forceUpdate(); + } + }; + + mx.on('RoomState.events', handleEvent); + return () => { + mx.removeListener('RoomState.events', handleEvent); + }; + }, [room, mx]); + + const isStateKeyAvailable = (key) => !room.currentState.getStateEvents('im.ponies.room_emotes', key); + + const createPack = async (name) => { + const packContent = { + pack: { display_name: name }, + images: {}, + }; + let stateKey = ''; + if (unUsablePacks.length > 0) { + const mEvent = unUsablePacks[0]; + stateKey = mEvent.getStateKey(); + } else { + stateKey = packContent.pack.display_name.replace(/\s/g, '-'); + if (!isStateKeyAvailable(stateKey)) { + stateKey = suffixRename( + stateKey, + isStateKeyAvailable, + ); + } + } + await mx.sendStateEvent(room.roomId, 'im.ponies.room_emotes', packContent, stateKey); + }; + + const deletePack = async (stateKey) => { + await mx.sendStateEvent(room.roomId, 'im.ponies.room_emotes', {}, stateKey); + }; + + return { + usablePacks, + createPack, + deletePack, + }; +} + +function RoomEmojis({ roomId }) { + const mx = initMatrix.matrixClient; + const room = mx.getRoom(roomId); + + const { usablePacks, createPack, deletePack } = useRoomPacks(room); + + const myPowerlevel = room.getMember(mx.getUserId())?.powerLevel || 0; + const canChange = room.currentState.hasSufficientPowerLevelFor('state_default', myPowerlevel); + + const handlePackCreate = (e) => { + e.preventDefault(); + const { nameInput } = e.target; + const name = nameInput.value.trim(); + if (name === '') return; + nameInput.value = ''; + + createPack(name); + }; + + return ( +
+ { canChange && ( +
+ Create Pack +
+ + +
+
+ )} + { + usablePacks.length > 0 + ? usablePacks.reverse().map((mEvent) => ( + + )) : ( +
+ No emojis or stickers pack yet. +
+ ) + } +
+ ); } RoomEmojis.propTypes = { diff --git a/src/app/molecules/room-emojis/RoomEmojis.scss b/src/app/molecules/room-emojis/RoomEmojis.scss new file mode 100644 index 00000000..7ba2b494 --- /dev/null +++ b/src/app/molecules/room-emojis/RoomEmojis.scss @@ -0,0 +1,29 @@ +.room-emojis { + .image-pack, + .room-emojis__add-pack, + .room-emojis__empty { + margin: var(--sp-normal) 0; + background-color: var(--bg-surface); + border-radius: var(--bo-radius); + box-shadow: var(--bs-surface-border); + overflow: hidden; + + & > .context-menu__header:first-child { + margin-top: 2px; + } + } + &__add-pack { + & form { + margin: var(--sp-normal); + display: flex; + gap: var(--sp-normal); + & .input-container { + flex-grow: 1; + } + } + } + &__empty { + padding: var(--sp-extra-loose) var(--sp-normal); + text-align: center; + } +} \ No newline at end of file diff --git a/src/app/organisms/room/RoomSettings.scss b/src/app/organisms/room/RoomSettings.scss index 3547e8a8..ab7fca5c 100644 --- a/src/app/organisms/room/RoomSettings.scss +++ b/src/app/organisms/room/RoomSettings.scss @@ -76,7 +76,6 @@ .room-settings .room-permissions__card, .room-settings .room-search__form, .room-settings .room-search__result-item , -.room-settings .room-members, -.room-settings .image-pack { +.room-settings .room-members { @extend .room-settings__card; } \ No newline at end of file diff --git a/src/app/organisms/space-settings/SpaceSettings.scss b/src/app/organisms/space-settings/SpaceSettings.scss index a7e83409..987f23b8 100644 --- a/src/app/organisms/space-settings/SpaceSettings.scss +++ b/src/app/organisms/space-settings/SpaceSettings.scss @@ -32,7 +32,6 @@ } .space-settings .room-permissions__card, -.space-settings .room-members, -.space-settings .image-pack { +.space-settings .room-members { @extend .space-settings__card; } \ No newline at end of file