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) && (
@@ -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