From 28c7445dce1163c56da4625d7040980934728588 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Tue, 14 Dec 2021 15:15:12 +1100 Subject: [PATCH] refactor most of the components to outside of their Session folder (#2072) * refactor most of the components to outside of their Session folder * finish moving overlay and memberListItem to react hook * fix bug with kicked member len >2 not being displayed also sort admins first in UpdateGroupMembers dialog * fix admin leaving text of groupNotification * add a useFocusMount hook to focus input fields on mount * make click avatar convo item open only user dialog * cleanup config default.json * make sure to use convoController to build sync message * disable showing pubkey on opengroups * add a pause on audio playback Fixes #2079 --- Gruntfile.js | 10 +- _locales/en/messages.json | 2 +- config/default.json | 4 +- js/modules/signal.js | 8 +- main.js | 2 - password_preload.js | 2 +- preload.js | 4 +- stylesheets/_avatar.scss | 19 +- stylesheets/_modal.scss | 6 + stylesheets/_session.scss | 1 + stylesheets/_session_conversation.scss | 6 +- ts/components/CaptionEditor.tsx | 4 +- ts/components/MainViewController.tsx | 9 +- ts/components/MemberListItem.tsx | 43 ++ .../{session => }/SessionInboxView.tsx | 44 +- ts/components/SessionMainPanel.tsx | 2 +- .../{session => }/SessionPasswordPrompt.tsx | 4 +- .../{session => }/SessionScrollButton.tsx | 2 +- .../{session => }/SessionSearchInput.tsx | 2 +- .../{session => }/SessionToastContainer.tsx | 0 .../{session => }/SessionWrapperModal.tsx | 2 +- .../{session => }/SplitViewContainer.tsx | 0 ts/components/{ => avatar}/Avatar.tsx | 16 +- .../AvatarPlaceHolder/AvatarPlaceHolder.tsx | 2 +- .../AvatarPlaceHolder/ClosedGroupAvatar.tsx | 2 +- .../{session => basic}/PillDivider.tsx | 0 .../{session => basic}/SessionButton.tsx | 0 .../{session => basic}/SessionDropdown.tsx | 2 +- .../SessionDropdownItem.tsx | 3 +- .../SessionHTMLRenderer.tsx | 1 + ts/components/basic/SessionIdEditable.tsx | 54 ++ .../{session => basic}/SessionInput.tsx | 2 +- .../{session => basic}/SessionRadio.tsx | 0 .../{session => basic}/SessionRadioGroup.tsx | 0 .../{session => basic}/SessionSpinner.tsx | 0 .../{session => basic}/SessionToast.tsx | 2 +- .../{session => basic}/SessionToggle.tsx | 0 .../{session => }/calling/CallButtons.tsx | 8 +- .../calling/CallInFullScreenContainer.tsx | 6 +- .../calling/DraggableCallContainer.tsx | 10 +- .../calling/InConversationCallContainer.tsx | 14 +- .../calling/IncomingCallDialog.tsx | 14 +- .../conversation/ConversationHeader.tsx | 9 +- ts/components/conversation/ExpireTimer.tsx | 2 +- .../conversation/GroupNotification.tsx | 4 +- ts/components/conversation/H5AudioPlayer.tsx | 4 +- ts/components/conversation/ImageGrid.tsx | 2 +- .../conversation/SessionConversation.tsx | 44 +- .../conversation/SessionConversationDrafts.ts | 0 .../conversation/SessionEmojiPanel.tsx | 2 +- .../conversation/SessionFileDropzone.tsx | 2 +- .../conversation/SessionLastSeenIndicator.tsx | 0 .../conversation/SessionMessagesList.tsx | 21 +- .../SessionMessagesListContainer.tsx | 30 +- .../SessionQuotedMessageComposition.tsx | 12 +- .../conversation/SessionRecording.tsx | 6 +- .../conversation/SessionRightPanel.tsx | 35 +- .../conversation/SessionStagedLinkPreview.tsx | 8 +- .../conversation/StagedLinkPreview.tsx | 2 +- .../conversation/TimerNotification.tsx | 4 +- .../composition/CompositionBox.tsx | 64 +- .../composition/CompositionButtons.tsx | 0 .../media-gallery/AttachmentSection.tsx | 2 +- .../media-gallery/DocumentListItem.tsx | 2 +- .../media-gallery/MediaGallery.tsx | 2 +- .../media-gallery/MediaGridItem.tsx | 4 +- .../media-gallery/groupMediaItemsByDate.ts | 3 +- .../ClickToTrustSender.tsx | 12 +- .../MessageAttachment.tsx | 22 +- .../MessageAuthorText.tsx | 10 +- .../{ => message-content}/MessageAvatar.tsx | 15 +- .../message-content}/MessageBody.tsx | 14 +- .../{ => message-content}/MessageContent.tsx | 10 +- .../MessageContentWithStatus.tsx | 9 +- .../MessageContextMenu.tsx | 36 +- .../{ => message-content}/MessagePreview.tsx | 14 +- .../{ => message-content}/MessageQuote.tsx | 11 +- .../{ => message-content}/MessageStatus.tsx | 4 +- .../{ => message-content}/MessageText.tsx | 8 +- .../OutgoingMessageStatus.tsx | 4 +- .../{ => message/message-content}/Quote.tsx | 20 +- .../DataExtractionNotification.tsx | 10 +- .../message/{ => message-item}/DateBreak.tsx | 0 .../GenericReadableMessage.tsx | 20 +- .../message-item}/GroupInvitation.tsx | 6 +- .../{ => message/message-item}/Message.tsx | 6 +- .../message-item}/MessageDetail.tsx | 10 +- .../message-item}/ReadableMessage.tsx | 12 +- .../notification-bubble/CallNotification.tsx | 13 +- .../NotificationBubble.tsx | 2 +- .../dialog/AdminLeaveClosedGroupDialog.tsx | 5 +- ts/components/dialog/DeleteAccountModal.tsx | 10 +- ts/components/dialog/EditProfileDialog.tsx | 16 +- ts/components/dialog/InviteContactsDialog.tsx | 281 ++++----- ts/components/dialog/ModeratorsAddDialog.tsx | 8 +- .../dialog/ModeratorsRemoveDialog.tsx | 317 ++++------ .../dialog/OnionStatusPathDialog.tsx | 6 +- ts/components/dialog/SessionConfirm.tsx | 10 +- ts/components/dialog/SessionModal.tsx | 5 +- .../dialog/SessionNicknameDialog.tsx | 4 +- .../dialog/SessionPasswordDialog.tsx | 5 +- ts/components/dialog/SessionSeedModal.tsx | 4 +- .../dialog/UpdateGroupMembersDialog.tsx | 569 ++++++++---------- .../dialog/UpdateGroupNameDialog.tsx | 6 +- ts/components/dialog/UserDetailsDialog.tsx | 9 +- .../icon/DropDownAndToggleButton.tsx | 0 ts/components/{session => }/icon/Icons.tsx | 11 +- .../{session => }/icon/SessionIcon.tsx | 0 .../{session => }/icon/SessionIconButton.tsx | 2 +- .../SessionNotificationCount.tsx | 0 ts/components/{session => }/icon/index.tsx | 0 .../{session => leftpane}/ActionsPanel.tsx | 21 +- .../{ => leftpane}/ContactListItem.tsx | 7 +- .../{ => leftpane}/ConversationListItem.tsx | 56 +- ts/components/{ => leftpane}/LeftPane.tsx | 24 +- .../LeftPaneContactSection.tsx | 4 +- .../leftpane/LeftPaneMessageSection.tsx | 220 +++++++ .../LeftPaneSectionHeader.tsx | 4 +- .../LeftPaneSettingSection.tsx | 7 +- .../MessageRequestsBanner.tsx | 2 +- .../leftpane/overlay/OverlayClosedGroup.tsx | 120 ++++ .../leftpane/overlay/OverlayHeader.tsx | 33 + .../leftpane/overlay/OverlayMessage.tsx | 101 ++++ .../overlay/OverlayMessageRequest.tsx | 120 ++++ .../leftpane/overlay/OverlayOpenGroup.tsx | 89 +++ .../overlay}/SessionJoinableDefaultRooms.tsx | 21 +- ts/components/{ => lightbox}/Lightbox.tsx | 14 +- .../{ => lightbox}/LightboxGallery.tsx | 10 +- .../menu/ConversationHeaderMenu.tsx | 2 +- .../menu/ConversationListItemContextMenu.tsx | 4 +- ts/components/{session => }/menu/Menu.tsx | 36 +- .../{session => registration}/AccentText.tsx | 0 .../registration/RegistrationStages.tsx | 18 +- .../registration/RegistrationUserDetails.tsx | 2 +- .../SessionRegistrationView.tsx | 8 +- .../{session => }/registration/SignInTab.tsx | 8 +- .../{session => }/registration/SignUpTab.tsx | 6 +- .../registration/TermsAndConditions.tsx | 2 +- ts/components/{ => search}/SearchResults.tsx | 2 +- .../{ => search}/UserSearchResults.tsx | 4 +- .../session/LeftPaneMessageSection.tsx | 477 --------------- .../session/SessionClosableOverlay.tsx | 317 ---------- ts/components/session/SessionIdEditable.tsx | 73 --- .../session/SessionMemberListItem.tsx | 63 -- .../settings/BlockedUserSettings.tsx | 9 +- .../SessionNotificationGroupSettings.tsx | 2 +- .../settings/SessionSettingListItem.tsx | 7 +- .../settings/SessionSettings.tsx | 8 +- .../settings/SessionSettingsHeader.tsx | 0 .../settings/ZoomingSessionSlider.tsx | 0 .../settings/section/CategoryAppearance.tsx | 13 +- .../settings/section/CategoryPrivacy.tsx | 13 +- ts/data/opengroups.ts | 4 +- ts/hooks/useFocusMount.ts | 11 + ts/hooks/useParamSelector.ts | 30 + ts/hooks/useSet.ts | 27 + ts/hooks/useWeAreAdmin.ts | 14 + ts/interactions/conversationInteractions.ts | 20 +- .../conversations/unsendingInteractions.ts | 6 +- ts/interactions/messageInteractions.ts | 9 +- ts/models/conversation.ts | 36 +- ts/models/message.ts | 3 +- ts/receiver/attachments.ts | 6 +- ts/receiver/callMessage.ts | 2 +- ts/receiver/closedGroups.ts | 9 +- ts/receiver/configMessage.ts | 4 +- ts/receiver/contentMessage.ts | 2 - ts/receiver/receiver.ts | 8 +- .../apis/file_server_api}/FileServerApiV2.ts | 6 +- .../apis/file_server_api}/index.ts | 0 .../open_group_api}/opengroupV2/ApiAuth.ts | 8 +- .../open_group_api}/opengroupV2/ApiUtil.ts | 13 +- .../opengroupV2/JoinOpenGroupV2.ts | 8 +- .../opengroupV2/OpenGroupAPIV2.ts | 10 +- .../opengroupV2/OpenGroupAPIV2CompactPoll.ts | 6 +- .../opengroupV2/OpenGroupAPIV2Parser.ts | 0 .../opengroupV2/OpenGroupManagerV2.ts | 8 +- .../opengroupV2/OpenGroupMessageV2.ts | 4 +- .../opengroupV2/OpenGroupServerPoller.ts | 14 +- .../opengroupV2/OpenGroupUpdate.ts | 14 +- .../apis/open_group_api}/opengroupV2/index.ts | 0 .../open_group_api}/utils/OpenGroupUtils.ts | 2 +- .../apis/open_group_api}/utils/index.ts | 0 .../apis/push_notification_api}/PnServer.ts | 2 +- .../apis/push_notification_api}/index.ts | 0 .../{ => apis}/seed_node_api/SeedNodeAPI.ts | 6 +- ts/session/{ => apis}/seed_node_api/index.ts | 0 ts/session/{ => apis}/snode_api/SNodeAPI.ts | 12 +- ts/session/{ => apis}/snode_api/index.ts | 0 ts/session/{ => apis}/snode_api/lokiRpc.ts | 4 +- ts/session/{ => apis}/snode_api/onions.ts | 10 +- ts/session/{ => apis}/snode_api/snodePool.ts | 6 +- .../{ => apis}/snode_api/swarmPolling.ts | 22 +- .../conversations/ConversationController.ts | 9 +- ts/session/group/index.ts | 32 +- ts/session/onions/onionPath.ts | 6 +- ts/session/onions/onionSend.ts | 2 +- ts/session/sending/MessageQueue.ts | 2 +- ts/session/sending/MessageSender.ts | 12 +- ts/session/sending/MessageSentHandler.ts | 2 +- ts/session/utils/Attachments.ts | 2 +- ts/session/utils/AttachmentsV2.ts | 4 +- ts/session/utils/Toast.tsx | 6 +- ts/session/utils/calling/CallManager.ts | 4 +- ts/session/utils/index.ts | 2 - ts/session/utils/syncUtils.ts | 7 +- ts/state/ducks/conversations.ts | 7 +- ts/state/ducks/defaultRooms.tsx | 2 +- ts/state/ducks/index.ts | 27 + ts/state/ducks/section.tsx | 31 +- ts/state/ducks/stagedAttachments.ts | 2 +- ts/state/selectors/conversations.ts | 65 +- ts/state/selectors/index.ts | 25 + ts/state/selectors/section.ts | 9 +- ts/state/selectors/stagedAttachments.ts | 2 +- ts/state/smart/SessionConversation.ts | 2 +- .../media-gallery/groupMessagesByDate_test.ts | 2 +- ts/test/session/unit/onion/GuardNodes_test.ts | 4 +- .../session/unit/onion/OnionErrors_test.ts | 6 +- ts/test/session/unit/onion/OnionPaths_test.ts | 4 +- .../session/unit/onion/SeedNodeAPI_test.ts | 6 +- .../unit/onion/SnodePoolUpdate_test.ts | 4 +- .../unit/sending/MessageSender_test.ts | 4 +- .../unit/swarm_polling/SwarmPolling_test.ts | 4 +- ts/test/test-utils/utils/message.ts | 6 +- ts/types/index.ts | 3 + ts/util/accountManager.ts | 2 + ts/util/attachmentsUtil.ts | 2 +- ts/util/timer.ts | 2 +- tslint.json | 1 + 230 files changed, 2276 insertions(+), 2421 deletions(-) create mode 100644 ts/components/MemberListItem.tsx rename ts/components/{session => }/SessionInboxView.tsx (74%) rename ts/components/{session => }/SessionPasswordPrompt.tsx (98%) rename ts/components/{session => }/SessionScrollButton.tsx (89%) rename ts/components/{session => }/SessionSearchInput.tsx (90%) rename ts/components/{session => }/SessionToastContainer.tsx (100%) rename ts/components/{session => }/SessionWrapperModal.tsx (98%) rename ts/components/{session => }/SplitViewContainer.tsx (100%) rename ts/components/{ => avatar}/Avatar.tsx (91%) rename ts/components/{ => avatar}/AvatarPlaceHolder/AvatarPlaceHolder.tsx (98%) rename ts/components/{ => avatar}/AvatarPlaceHolder/ClosedGroupAvatar.tsx (94%) rename ts/components/{session => basic}/PillDivider.tsx (100%) rename ts/components/{session => basic}/SessionButton.tsx (100%) rename ts/components/{session => basic}/SessionDropdown.tsx (96%) rename ts/components/{session => basic}/SessionDropdownItem.tsx (93%) rename ts/components/{session => basic}/SessionHTMLRenderer.tsx (91%) create mode 100644 ts/components/basic/SessionIdEditable.tsx rename ts/components/{session => basic}/SessionInput.tsx (98%) rename ts/components/{session => basic}/SessionRadio.tsx (100%) rename ts/components/{session => basic}/SessionRadioGroup.tsx (100%) rename ts/components/{session => basic}/SessionSpinner.tsx (100%) rename ts/components/{session => basic}/SessionToast.tsx (97%) rename ts/components/{session => basic}/SessionToggle.tsx (100%) rename ts/components/{session => }/calling/CallButtons.tsx (97%) rename ts/components/{session => }/calling/CallInFullScreenContainer.tsx (93%) rename ts/components/{session => }/calling/DraggableCallContainer.tsx (93%) rename ts/components/{session => }/calling/InConversationCallContainer.tsx (93%) rename ts/components/{session => }/calling/IncomingCallDialog.tsx (86%) rename ts/components/{session => }/conversation/SessionConversation.tsx (93%) rename ts/components/{session => }/conversation/SessionConversationDrafts.ts (100%) rename ts/components/{session => }/conversation/SessionEmojiPanel.tsx (93%) rename ts/components/{session => }/conversation/SessionFileDropzone.tsx (95%) rename ts/components/{session => }/conversation/SessionLastSeenIndicator.tsx (100%) rename ts/components/{session => }/conversation/SessionMessagesList.tsx (83%) rename ts/components/{session => }/conversation/SessionMessagesListContainer.tsx (95%) rename ts/components/{session => }/conversation/SessionQuotedMessageComposition.tsx (89%) rename ts/components/{session => }/conversation/SessionRecording.tsx (98%) rename ts/components/{session => }/conversation/SessionRightPanel.tsx (92%) rename ts/components/{session => }/conversation/SessionStagedLinkPreview.tsx (92%) rename ts/components/{session => }/conversation/composition/CompositionBox.tsx (95%) rename ts/components/{session => }/conversation/composition/CompositionButtons.tsx (100%) rename ts/components/conversation/message/{ => message-content}/ClickToTrustSender.tsx (91%) rename ts/components/conversation/message/{ => message-content}/MessageAttachment.tsx (91%) rename ts/components/conversation/message/{ => message-content}/MessageAuthorText.tsx (84%) rename ts/components/conversation/message/{ => message-content}/MessageAvatar.tsx (77%) rename ts/components/conversation/{ => message/message-content}/MessageBody.tsx (90%) rename ts/components/conversation/message/{ => message-content}/MessageContent.tsx (96%) rename ts/components/conversation/message/{ => message-content}/MessageContentWithStatus.tsx (92%) rename ts/components/conversation/message/{ => message-content}/MessageContextMenu.tsx (88%) rename ts/components/conversation/message/{ => message-content}/MessagePreview.tsx (86%) rename ts/components/conversation/message/{ => message-content}/MessageQuote.tsx (90%) rename ts/components/conversation/message/{ => message-content}/MessageStatus.tsx (83%) rename ts/components/conversation/message/{ => message-content}/MessageText.tsx (86%) rename ts/components/conversation/message/{ => message-content}/OutgoingMessageStatus.tsx (93%) rename ts/components/conversation/{ => message/message-content}/Quote.tsx (95%) rename ts/components/conversation/{ => message/message-item}/DataExtractionNotification.tsx (78%) rename ts/components/conversation/message/{ => message-item}/DateBreak.tsx (100%) rename ts/components/conversation/message/{ => message-item}/GenericReadableMessage.tsx (89%) rename ts/components/conversation/{ => message/message-item}/GroupInvitation.tsx (86%) rename ts/components/conversation/{ => message/message-item}/Message.tsx (81%) rename ts/components/conversation/{ => message/message-item}/MessageDetail.tsx (92%) rename ts/components/conversation/{ => message/message-item}/ReadableMessage.tsx (92%) rename ts/components/conversation/{ => message/message-item}/notification-bubble/CallNotification.tsx (82%) rename ts/components/conversation/{ => message/message-item}/notification-bubble/NotificationBubble.tsx (94%) rename ts/components/{session => }/icon/DropDownAndToggleButton.tsx (100%) rename ts/components/{session => }/icon/Icons.tsx (99%) rename ts/components/{session => }/icon/SessionIcon.tsx (100%) rename ts/components/{session => }/icon/SessionIconButton.tsx (96%) rename ts/components/{session => icon}/SessionNotificationCount.tsx (100%) rename ts/components/{session => }/icon/index.tsx (100%) rename ts/components/{session => leftpane}/ActionsPanel.tsx (93%) rename ts/components/{ => leftpane}/ContactListItem.tsx (84%) rename ts/components/{ => leftpane}/ConversationListItem.tsx (87%) rename ts/components/{ => leftpane}/LeftPane.tsx (67%) rename ts/components/{session => leftpane}/LeftPaneContactSection.tsx (92%) create mode 100644 ts/components/leftpane/LeftPaneMessageSection.tsx rename ts/components/{session => leftpane}/LeftPaneSectionHeader.tsx (97%) rename ts/components/{session => leftpane}/LeftPaneSettingSection.tsx (95%) rename ts/components/{session => leftpane}/MessageRequestsBanner.tsx (99%) create mode 100644 ts/components/leftpane/overlay/OverlayClosedGroup.tsx create mode 100644 ts/components/leftpane/overlay/OverlayHeader.tsx create mode 100644 ts/components/leftpane/overlay/OverlayMessage.tsx create mode 100644 ts/components/leftpane/overlay/OverlayMessageRequest.tsx create mode 100644 ts/components/leftpane/overlay/OverlayOpenGroup.tsx rename ts/components/{session => leftpane/overlay}/SessionJoinableDefaultRooms.tsx (88%) rename ts/components/{ => lightbox}/Lightbox.tsx (95%) rename ts/components/{ => lightbox}/LightboxGallery.tsx (89%) rename ts/components/{session => }/menu/ConversationHeaderMenu.tsx (97%) rename ts/components/{session => }/menu/ConversationListItemContextMenu.tsx (95%) rename ts/components/{session => }/menu/Menu.tsx (95%) rename ts/components/{session => registration}/AccentText.tsx (100%) rename ts/components/{session => }/registration/RegistrationStages.tsx (93%) rename ts/components/{session => }/registration/RegistrationUserDetails.tsx (98%) rename ts/components/{session => registration}/SessionRegistrationView.tsx (86%) rename ts/components/{session => }/registration/SignInTab.tsx (97%) rename ts/components/{session => }/registration/SignUpTab.tsx (97%) rename ts/components/{session => }/registration/TermsAndConditions.tsx (77%) rename ts/components/{ => search}/SearchResults.tsx (98%) rename ts/components/{ => search}/UserSearchResults.tsx (92%) delete mode 100644 ts/components/session/LeftPaneMessageSection.tsx delete mode 100644 ts/components/session/SessionClosableOverlay.tsx delete mode 100644 ts/components/session/SessionIdEditable.tsx delete mode 100644 ts/components/session/SessionMemberListItem.tsx rename ts/components/{session => }/settings/BlockedUserSettings.tsx (80%) rename ts/components/{session => }/settings/SessionNotificationGroupSettings.tsx (94%) rename ts/components/{session => }/settings/SessionSettingListItem.tsx (91%) rename ts/components/{session => }/settings/SessionSettings.tsx (97%) rename ts/components/{session => }/settings/SessionSettingsHeader.tsx (100%) rename ts/components/{session => }/settings/ZoomingSessionSlider.tsx (100%) rename ts/components/{session => }/settings/section/CategoryAppearance.tsx (93%) rename ts/components/{session => }/settings/section/CategoryPrivacy.tsx (92%) create mode 100644 ts/hooks/useFocusMount.ts create mode 100644 ts/hooks/useSet.ts create mode 100644 ts/hooks/useWeAreAdmin.ts rename ts/{fileserver => session/apis/file_server_api}/FileServerApiV2.ts (95%) rename ts/{fileserver => session/apis/file_server_api}/index.ts (100%) rename ts/{opengroup => session/apis/open_group_api}/opengroupV2/ApiAuth.ts (97%) rename ts/{opengroup => session/apis/open_group_api}/opengroupV2/ApiUtil.ts (93%) rename ts/{opengroup => session/apis/open_group_api}/opengroupV2/JoinOpenGroupV2.ts (96%) rename ts/{opengroup => session/apis/open_group_api}/opengroupV2/OpenGroupAPIV2.ts (98%) rename ts/{opengroup => session/apis/open_group_api}/opengroupV2/OpenGroupAPIV2CompactPoll.ts (98%) rename ts/{opengroup => session/apis/open_group_api}/opengroupV2/OpenGroupAPIV2Parser.ts (100%) rename ts/{opengroup => session/apis/open_group_api}/opengroupV2/OpenGroupManagerV2.ts (96%) rename ts/{opengroup => session/apis/open_group_api}/opengroupV2/OpenGroupMessageV2.ts (95%) rename ts/{opengroup => session/apis/open_group_api}/opengroupV2/OpenGroupServerPoller.ts (97%) rename ts/{opengroup => session/apis/open_group_api}/opengroupV2/OpenGroupUpdate.ts (84%) rename ts/{opengroup => session/apis/open_group_api}/opengroupV2/index.ts (100%) rename ts/{opengroup => session/apis/open_group_api}/utils/OpenGroupUtils.ts (98%) rename ts/{opengroup => session/apis/open_group_api}/utils/index.ts (100%) rename ts/{pushnotification => session/apis/push_notification_api}/PnServer.ts (96%) rename ts/{pushnotification => session/apis/push_notification_api}/index.ts (100%) rename ts/session/{ => apis}/seed_node_api/SeedNodeAPI.ts (98%) rename ts/session/{ => apis}/seed_node_api/index.ts (100%) rename ts/session/{ => apis}/snode_api/SNodeAPI.ts (99%) rename ts/session/{ => apis}/snode_api/index.ts (100%) rename ts/session/{ => apis}/snode_api/lokiRpc.ts (97%) rename ts/session/{ => apis}/snode_api/onions.ts (98%) rename ts/session/{ => apis}/snode_api/snodePool.ts (98%) rename ts/session/{ => apis}/snode_api/swarmPolling.ts (95%) create mode 100644 ts/state/ducks/index.ts create mode 100644 ts/state/selectors/index.ts create mode 100644 ts/types/index.ts diff --git a/Gruntfile.js b/Gruntfile.js index 365942e8f..76e83b0db 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -151,14 +151,6 @@ module.exports = grunt => { grunt.file.write(configPath, `${JSON.stringify(localConfig)}\n`); } - grunt.registerTask('getExpireTime', () => { - grunt.task.requires('gitinfo'); - const gitinfo = grunt.config.get('gitinfo'); - const committed = gitinfo.local.branch.current.lastCommitTime; - const time = Date.parse(committed) + 1000 * 60 * 60 * 24 * 90; - updateLocalConfig({ buildExpiration: time }); - }); - grunt.registerTask('getCommitHash', () => { grunt.task.requires('gitinfo'); const gitinfo = grunt.config.get('gitinfo'); @@ -167,7 +159,7 @@ module.exports = grunt => { }); grunt.registerTask('dev', ['default', 'watch']); - grunt.registerTask('date', ['gitinfo', 'getExpireTime']); + grunt.registerTask('date', ['gitinfo']); grunt.registerTask('default', [ 'exec:build-protobuf', 'exec:transpile', diff --git a/_locales/en/messages.json b/_locales/en/messages.json index ad32e9b07..7f08d23c9 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -327,7 +327,7 @@ "addAsModerator": "Add as Moderator", "removeFromModerators": "Remove From Moderators", "add": "Add", - "addingContacts": "Adding contacts to", + "addingContacts": "Adding contacts to $name$", "noContactsToAdd": "No contacts to add", "noMembersInThisGroup": "No other members in this group", "noModeratorsToRemove": "no moderators to remove", diff --git a/config/default.json b/config/default.json index 8a3b35bb1..bb1eab171 100644 --- a/config/default.json +++ b/config/default.json @@ -16,8 +16,6 @@ ], "updatesEnabled": false, "openDevTools": false, - "buildExpiration": 0, "commitHash": "", - "import": false, - "serverTrustRoot": "BbqY1DzohE4NUZoVF+L18oUPrK3kILllLEJh2UnPSsEx" + "import": false } diff --git a/js/modules/signal.js b/js/modules/signal.js index 282e18487..ecd4a9b01 100644 --- a/js/modules/signal.js +++ b/js/modules/signal.js @@ -8,12 +8,14 @@ const OS = require('../../ts/OS'); const Settings = require('./settings'); const Util = require('../../ts/util'); const LinkPreviews = require('./link_previews'); -const { Message } = require('../../ts/components/conversation/Message'); +const { Message } = require('../../ts/components/conversation/message/message-item/Message'); // Components -const { SessionRegistrationView } = require('../../ts/components/session/SessionRegistrationView'); +const { + SessionRegistrationView, +} = require('../../ts/components/registration/SessionRegistrationView'); -const { SessionInboxView } = require('../../ts/components/session/SessionInboxView'); +const { SessionInboxView } = require('../../ts/components/SessionInboxView'); // Types const AttachmentType = require('./types/attachment'); diff --git a/main.js b/main.js index 307069835..f636f636e 100644 --- a/main.js +++ b/main.js @@ -154,7 +154,6 @@ function prepareURL(pathSegments, moreKeys) { name: packageJson.productName, locale: locale.name, version: app.getVersion(), - buildExpiration: config.get('buildExpiration'), commitHash: config.get('commitHash'), serverUrl: config.get('serverUrl'), localUrl: config.get('localUrl'), @@ -167,7 +166,6 @@ function prepareURL(pathSegments, moreKeys) { appInstance: process.env.NODE_APP_INSTANCE, proxyUrl: process.env.HTTPS_PROXY || process.env.https_proxy, contentProxyUrl: config.contentProxyUrl, - serverTrustRoot: config.get('serverTrustRoot'), appStartInitialSpellcheckSetting, ...moreKeys, }, diff --git a/password_preload.js b/password_preload.js index 2c064ba98..dac1e01d8 100644 --- a/password_preload.js +++ b/password_preload.js @@ -21,7 +21,7 @@ window.getEnvironment = () => config.environment; window.getVersion = () => config.version; window.getAppInstance = () => config.appInstance; -const { SessionPasswordPrompt } = require('./ts/components/session/SessionPasswordPrompt'); +const { SessionPasswordPrompt } = require('./ts/components/SessionPasswordPrompt'); window.Signal = { Components: { diff --git a/preload.js b/preload.js index e53586ed7..115b2150a 100644 --- a/preload.js +++ b/preload.js @@ -30,11 +30,9 @@ window.getEnvironment = () => config.environment; window.getAppInstance = () => config.appInstance; window.getVersion = () => config.version; window.isDev = () => config.environment === 'development'; -window.getExpiration = () => config.buildExpiration; window.getCommitHash = () => config.commitHash; window.getNodeVersion = () => config.node_version; window.getHostName = () => config.hostname; -window.getServerTrustRoot = () => config.serverTrustRoot; window.isBehindProxy = () => Boolean(config.proxyUrl); window.lokiFeatureFlags = { @@ -214,7 +212,7 @@ window.Signal = Signal.setup({ logger: window.log, }); -window.getSwarmPollingInstance = require('./ts/session/snode_api/').getSwarmPollingInstance; +window.getSwarmPollingInstance = require('./ts/session/apis/snode_api/').getSwarmPollingInstance; const WorkerInterface = require('./js/modules/util_worker_interface'); diff --git a/stylesheets/_avatar.scss b/stylesheets/_avatar.scss index 04a2f9978..b7abb7f64 100644 --- a/stylesheets/_avatar.scss +++ b/stylesheets/_avatar.scss @@ -8,6 +8,7 @@ $borderAvatarColor: unquote( vertical-align: middle; display: inline-block; border-radius: 50%; + flex-shrink: 0; img { object-fit: cover; @@ -16,21 +17,6 @@ $borderAvatarColor: unquote( } } -.module-avatar__label { - width: 100%; - text-align: center; - font-weight: 300; - text-transform: uppercase; - color: $color-white; -} - -.module-avatar__icon { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); -} - .module-avatar__icon--crown-wrapper { position: absolute; bottom: 0%; @@ -129,7 +115,8 @@ $borderAvatarColor: unquote( .module-avatar-clickable { transition: $session-transition-duration; + cursor: pointer; &:hover { - opacity: $session-subtle-factor; + filter: grayscale(0.7); } } diff --git a/stylesheets/_modal.scss b/stylesheets/_modal.scss index 2387092a6..4f0de6cb8 100644 --- a/stylesheets/_modal.scss +++ b/stylesheets/_modal.scss @@ -26,6 +26,12 @@ padding: 1.1em; } +.session-modal { + .contact-selection-list { + width: 100%; + } +} + .create-group-dialog, .add-moderators-dialog, .remove-moderators-dialog, diff --git a/stylesheets/_session.scss b/stylesheets/_session.scss index b60aa76a2..c16bc8a07 100644 --- a/stylesheets/_session.scss +++ b/stylesheets/_session.scss @@ -494,6 +494,7 @@ label { .group-member-list__selection { overflow-y: auto; + width: 100%; } &__centered { diff --git a/stylesheets/_session_conversation.scss b/stylesheets/_session_conversation.scss index a48783836..bcc4fbcfe 100644 --- a/stylesheets/_session_conversation.scss +++ b/stylesheets/_session_conversation.scss @@ -158,10 +158,8 @@ z-index: 1; .session-icon-button { - // & > .session-icon-button { margin-right: $session-margin-sm; - } - .session-icon-button { + display: flex; justify-content: center; align-items: center; @@ -169,7 +167,7 @@ &:hover { opacity: 1; - transform: scale(0.93); + filter: brightness(0.9); transition: $session-transition-duration; } diff --git a/ts/components/CaptionEditor.tsx b/ts/components/CaptionEditor.tsx index 68d6eae5a..4e842e77b 100644 --- a/ts/components/CaptionEditor.tsx +++ b/ts/components/CaptionEditor.tsx @@ -5,9 +5,9 @@ import * as GoogleChrome from '../util/GoogleChrome'; import { AttachmentType } from '../types/Attachment'; -import { SessionInput } from './session/SessionInput'; -import { SessionButton, SessionButtonColor, SessionButtonType } from './session/SessionButton'; import autoBind from 'auto-bind'; +import { SessionButton, SessionButtonColor, SessionButtonType } from './basic/SessionButton'; +import { SessionInput } from './basic/SessionInput'; interface Props { attachment: AttachmentType; diff --git a/ts/components/MainViewController.tsx b/ts/components/MainViewController.tsx index 9c222c93f..dcbf8c278 100644 --- a/ts/components/MainViewController.tsx +++ b/ts/components/MainViewController.tsx @@ -1,6 +1,5 @@ import React from 'react'; -import { ContactType } from './session/SessionMemberListItem'; import { ToastUtils } from '../session/utils'; import { createClosedGroup as createClosedGroupV2 } from '../receiver/closedGroups'; import { VALIDATION } from '../session/constants'; @@ -38,7 +37,7 @@ export class MessageView extends React.Component { */ async function createClosedGroup( groupName: string, - groupMembers: Array + groupMemberIds: Array ): Promise { // Validate groupName and groupMembers length if (groupName.length === 0) { @@ -53,16 +52,14 @@ async function createClosedGroup( // >= because we add ourself as a member AFTER this. so a 10 group is already invalid as it will be 11 with ourself // the same is valid with groups count < 1 - if (groupMembers.length < 1) { + if (groupMemberIds.length < 1) { ToastUtils.pushToastError('pickClosedGroupMember', window.i18n('pickClosedGroupMember')); return false; - } else if (groupMembers.length >= VALIDATION.CLOSED_GROUP_SIZE_LIMIT) { + } else if (groupMemberIds.length >= VALIDATION.CLOSED_GROUP_SIZE_LIMIT) { ToastUtils.pushToastError('closedGroupMaxSize', window.i18n('closedGroupMaxSize')); return false; } - const groupMemberIds = groupMembers.map(m => m.id); - await createClosedGroupV2(groupName, groupMemberIds); return true; diff --git a/ts/components/MemberListItem.tsx b/ts/components/MemberListItem.tsx new file mode 100644 index 000000000..79e56532f --- /dev/null +++ b/ts/components/MemberListItem.tsx @@ -0,0 +1,43 @@ +import React from 'react'; +import classNames from 'classnames'; +import { Avatar, AvatarSize } from './avatar/Avatar'; +import { Constants } from '../session'; +import { SessionIcon } from './icon'; +import { useConversationUsernameOrShorten } from '../hooks/useParamSelector'; + +const AvatarItem = (props: { memberPubkey: string }) => { + return ; +}; + +export const MemberListItem = (props: { + pubkey: string; + isSelected: boolean; + // this bool is used to make a zombie appear with less opacity than a normal member + isZombie?: boolean; + onSelect?: (pubkey: string) => void; + onUnselect?: (pubkey: string) => void; +}) => { + const { isSelected, pubkey, isZombie, onSelect, onUnselect } = props; + + const memberName = useConversationUsernameOrShorten(pubkey); + + return ( +
{ + isSelected ? onUnselect?.(pubkey) : onSelect?.(pubkey); + }} + role="button" + > +
+ + + + {memberName} +
+ + + +
+ ); +}; diff --git a/ts/components/session/SessionInboxView.tsx b/ts/components/SessionInboxView.tsx similarity index 74% rename from ts/components/session/SessionInboxView.tsx rename to ts/components/SessionInboxView.tsx index 57fb092c9..6a58f07f2 100644 --- a/ts/components/session/SessionInboxView.tsx +++ b/ts/components/SessionInboxView.tsx @@ -1,32 +1,32 @@ import React from 'react'; import { Provider } from 'react-redux'; import { bindActionCreators } from 'redux'; -import { getConversationController } from '../../session/conversations'; -import { UserUtils } from '../../session/utils'; -import { createStore } from '../../state/createStore'; -import { - actions as conversationActions, - getEmptyConversationState, - openConversationWithMessages, -} from '../../state/ducks/conversations'; -import { initialDefaultRoomState } from '../../state/ducks/defaultRooms'; -import { initialModalState } from '../../state/ducks/modalDialog'; -import { initialOnionPathState } from '../../state/ducks/onion'; -import { initialSearchState } from '../../state/ducks/search'; -import { initialSectionState } from '../../state/ducks/section'; -import { initialThemeState } from '../../state/ducks/theme'; -import { initialUserConfigState } from '../../state/ducks/userConfig'; -import { StateType } from '../../state/reducer'; -import { makeLookup } from '../../util'; -import { LeftPane } from '../LeftPane'; -import { SessionMainPanel } from '../SessionMainPanel'; +import { LeftPane } from './leftpane/LeftPane'; // tslint:disable-next-line: no-submodule-imports import { PersistGate } from 'redux-persist/integration/react'; import { persistStore } from 'redux-persist'; -import { TimerOptionsArray } from '../../state/ducks/timerOptions'; -import { getEmptyStagedAttachmentsState } from '../../state/ducks/stagedAttachments'; -import { initialCallState } from '../../state/ducks/call'; +import { getConversationController } from '../session/conversations'; +import { UserUtils } from '../session/utils'; +import { initialCallState } from '../state/ducks/call'; +import { + actions as conversationActions, + getEmptyConversationState, + openConversationWithMessages, +} from '../state/ducks/conversations'; +import { initialDefaultRoomState } from '../state/ducks/defaultRooms'; +import { initialModalState } from '../state/ducks/modalDialog'; +import { initialOnionPathState } from '../state/ducks/onion'; +import { initialSearchState } from '../state/ducks/search'; +import { initialSectionState } from '../state/ducks/section'; +import { getEmptyStagedAttachmentsState } from '../state/ducks/stagedAttachments'; +import { initialThemeState } from '../state/ducks/theme'; +import { TimerOptionsArray } from '../state/ducks/timerOptions'; +import { initialUserConfigState } from '../state/ducks/userConfig'; +import { StateType } from '../state/reducer'; +import { makeLookup } from '../util'; +import { SessionMainPanel } from './SessionMainPanel'; +import { createStore } from '../state/createStore'; // Workaround: A react component's required properties are filtering up through connect() // https://github.com/DefinitelyTyped/DefinitelyTyped/issues/31363 diff --git a/ts/components/SessionMainPanel.tsx b/ts/components/SessionMainPanel.tsx index 47e05a9a4..035275712 100644 --- a/ts/components/SessionMainPanel.tsx +++ b/ts/components/SessionMainPanel.tsx @@ -4,7 +4,7 @@ import { useAppIsFocused } from '../hooks/useAppFocused'; import { getFocusedSettingsSection } from '../state/selectors/section'; import { SmartSessionConversation } from '../state/smart/SessionConversation'; -import { SessionSettingsView } from './session/settings/SessionSettings'; +import { SessionSettingsView } from './settings/SessionSettings'; const FilteredSettingsView = SessionSettingsView as any; diff --git a/ts/components/session/SessionPasswordPrompt.tsx b/ts/components/SessionPasswordPrompt.tsx similarity index 98% rename from ts/components/session/SessionPasswordPrompt.tsx rename to ts/components/SessionPasswordPrompt.tsx index a4c9bbeef..5b5333e44 100644 --- a/ts/components/session/SessionPasswordPrompt.tsx +++ b/ts/components/SessionPasswordPrompt.tsx @@ -2,10 +2,10 @@ import React from 'react'; import classNames from 'classnames'; import { SessionIcon } from './icon'; -import { SessionButton, SessionButtonColor, SessionButtonType } from './SessionButton'; -import { Constants } from '../../session'; import { withTheme } from 'styled-components'; import autoBind from 'auto-bind'; +import { SessionButton, SessionButtonColor, SessionButtonType } from './basic/SessionButton'; +import { Constants } from '../session'; interface State { error: string; diff --git a/ts/components/session/SessionScrollButton.tsx b/ts/components/SessionScrollButton.tsx similarity index 89% rename from ts/components/session/SessionScrollButton.tsx rename to ts/components/SessionScrollButton.tsx index 20cf7d0f7..314396f05 100644 --- a/ts/components/session/SessionScrollButton.tsx +++ b/ts/components/SessionScrollButton.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { useSelector } from 'react-redux'; import styled from 'styled-components'; -import { getShowScrollButton } from '../../state/selectors/conversations'; +import { getShowScrollButton } from '../state/selectors/conversations'; import { SessionIconButton } from './icon'; diff --git a/ts/components/session/SessionSearchInput.tsx b/ts/components/SessionSearchInput.tsx similarity index 90% rename from ts/components/session/SessionSearchInput.tsx rename to ts/components/SessionSearchInput.tsx index 3c25f4301..1ed173796 100644 --- a/ts/components/session/SessionSearchInput.tsx +++ b/ts/components/SessionSearchInput.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { useSelector } from 'react-redux'; -import { getConversationsCount } from '../../state/selectors/conversations'; +import { getConversationsCount } from '../state/selectors/conversations'; import { SessionIconButton } from './icon'; type Props = { diff --git a/ts/components/session/SessionToastContainer.tsx b/ts/components/SessionToastContainer.tsx similarity index 100% rename from ts/components/session/SessionToastContainer.tsx rename to ts/components/SessionToastContainer.tsx diff --git a/ts/components/session/SessionWrapperModal.tsx b/ts/components/SessionWrapperModal.tsx similarity index 98% rename from ts/components/session/SessionWrapperModal.tsx rename to ts/components/SessionWrapperModal.tsx index ff615e5c6..f34453342 100644 --- a/ts/components/session/SessionWrapperModal.tsx +++ b/ts/components/SessionWrapperModal.tsx @@ -2,10 +2,10 @@ import React, { useEffect, useRef } from 'react'; import classNames from 'classnames'; import { SessionIconButton } from './icon/'; -import { SessionButton } from './SessionButton'; // tslint:disable-next-line: no-submodule-imports import useKey from 'react-use/lib/useKey'; +import { SessionButton } from './basic/SessionButton'; export type SessionWrapperModalType = { title?: string; diff --git a/ts/components/session/SplitViewContainer.tsx b/ts/components/SplitViewContainer.tsx similarity index 100% rename from ts/components/session/SplitViewContainer.tsx rename to ts/components/SplitViewContainer.tsx diff --git a/ts/components/Avatar.tsx b/ts/components/avatar/Avatar.tsx similarity index 91% rename from ts/components/Avatar.tsx rename to ts/components/avatar/Avatar.tsx index 4af7040f9..1b1da7c76 100644 --- a/ts/components/Avatar.tsx +++ b/ts/components/avatar/Avatar.tsx @@ -1,15 +1,15 @@ import React, { useState } from 'react'; import classNames from 'classnames'; -import { useEncryptedFileFetch } from '../hooks/useEncryptedFileFetch'; +import { useEncryptedFileFetch } from '../../hooks/useEncryptedFileFetch'; import _ from 'underscore'; import { useAvatarPath, useConversationUsername, useIsClosedGroup, -} from '../hooks/useParamSelector'; +} from '../../hooks/useParamSelector'; import { AvatarPlaceHolder } from './AvatarPlaceHolder/AvatarPlaceHolder'; import { ClosedGroupAvatar } from './AvatarPlaceHolder/ClosedGroupAvatar'; -import { useDisableDrag } from '../hooks/useDisableDrag'; +import { useDisableDrag } from '../../hooks/useDisableDrag'; export enum AvatarSize { XS = 28, @@ -111,10 +111,12 @@ const AvatarInner = (props: Props) => { hasImage ? 'module-avatar--with-image' : 'module-avatar--no-image', isClickable && 'module-avatar-clickable' )} - onClick={e => { - e.stopPropagation(); - e.preventDefault(); - props.onAvatarClick?.(); + onMouseDown={e => { + if (props.onAvatarClick) { + e.stopPropagation(); + e.preventDefault(); + props.onAvatarClick?.(); + } }} role="button" data-testid={dataTestId} diff --git a/ts/components/AvatarPlaceHolder/AvatarPlaceHolder.tsx b/ts/components/avatar/AvatarPlaceHolder/AvatarPlaceHolder.tsx similarity index 98% rename from ts/components/AvatarPlaceHolder/AvatarPlaceHolder.tsx rename to ts/components/avatar/AvatarPlaceHolder/AvatarPlaceHolder.tsx index 2aa30a550..3136d728c 100644 --- a/ts/components/AvatarPlaceHolder/AvatarPlaceHolder.tsx +++ b/ts/components/avatar/AvatarPlaceHolder/AvatarPlaceHolder.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useState } from 'react'; -import { getInitials } from '../../util/getInitials'; +import { getInitials } from '../../../util/getInitials'; type Props = { diameter: number; diff --git a/ts/components/AvatarPlaceHolder/ClosedGroupAvatar.tsx b/ts/components/avatar/AvatarPlaceHolder/ClosedGroupAvatar.tsx similarity index 94% rename from ts/components/AvatarPlaceHolder/ClosedGroupAvatar.tsx rename to ts/components/avatar/AvatarPlaceHolder/ClosedGroupAvatar.tsx index c54fee35f..486993064 100644 --- a/ts/components/AvatarPlaceHolder/ClosedGroupAvatar.tsx +++ b/ts/components/avatar/AvatarPlaceHolder/ClosedGroupAvatar.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { useMembersAvatars } from '../../hooks/useMembersAvatars'; +import { useMembersAvatars } from '../../../hooks/useMembersAvatars'; import { Avatar, AvatarSize } from '../Avatar'; type Props = { diff --git a/ts/components/session/PillDivider.tsx b/ts/components/basic/PillDivider.tsx similarity index 100% rename from ts/components/session/PillDivider.tsx rename to ts/components/basic/PillDivider.tsx diff --git a/ts/components/session/SessionButton.tsx b/ts/components/basic/SessionButton.tsx similarity index 100% rename from ts/components/session/SessionButton.tsx rename to ts/components/basic/SessionButton.tsx diff --git a/ts/components/session/SessionDropdown.tsx b/ts/components/basic/SessionDropdown.tsx similarity index 96% rename from ts/components/session/SessionDropdown.tsx rename to ts/components/basic/SessionDropdown.tsx index 4c678251f..20c3348e1 100644 --- a/ts/components/session/SessionDropdown.tsx +++ b/ts/components/basic/SessionDropdown.tsx @@ -1,6 +1,6 @@ import React, { useState } from 'react'; +import { SessionIcon, SessionIconType } from '../icon'; -import { SessionIcon, SessionIconType } from './icon/'; import { SessionDropdownItem, SessionDropDownItemType } from './SessionDropdownItem'; // THIS IS DROPDOWN ACCORDIAN STYLE OPTIONS SELECTOR ELEMENT, NOT A CONTEXTMENU diff --git a/ts/components/session/SessionDropdownItem.tsx b/ts/components/basic/SessionDropdownItem.tsx similarity index 93% rename from ts/components/session/SessionDropdownItem.tsx rename to ts/components/basic/SessionDropdownItem.tsx index 7fccb5b98..3ef0ccc4f 100644 --- a/ts/components/session/SessionDropdownItem.tsx +++ b/ts/components/basic/SessionDropdownItem.tsx @@ -1,7 +1,6 @@ import React from 'react'; import classNames from 'classnames'; - -import { SessionIcon, SessionIconType } from './icon/'; +import { SessionIcon, SessionIconType } from '../icon'; export enum SessionDropDownItemType { Default = 'default', diff --git a/ts/components/session/SessionHTMLRenderer.tsx b/ts/components/basic/SessionHTMLRenderer.tsx similarity index 91% rename from ts/components/session/SessionHTMLRenderer.tsx rename to ts/components/basic/SessionHTMLRenderer.tsx index da0310f72..225a907f9 100644 --- a/ts/components/session/SessionHTMLRenderer.tsx +++ b/ts/components/basic/SessionHTMLRenderer.tsx @@ -20,6 +20,7 @@ export const SessionHtmlRenderer: React.SFC = ({ tag = 'div', key, html, return React.createElement(tag, { key, className, + // tslint:disable-next-line: react-no-dangerous-html dangerouslySetInnerHTML: { __html: clean }, }); }; diff --git a/ts/components/basic/SessionIdEditable.tsx b/ts/components/basic/SessionIdEditable.tsx new file mode 100644 index 000000000..b43d8d526 --- /dev/null +++ b/ts/components/basic/SessionIdEditable.tsx @@ -0,0 +1,54 @@ +import React, { ChangeEvent, KeyboardEvent, useRef } from 'react'; +import classNames from 'classnames'; +import { useFocusMount } from '../../hooks/useFocusMount'; + +type Props = { + placeholder?: string; + value?: string; + text?: string; + editable?: boolean; + onChange?: (value: string) => void; + onPressEnter?: any; + maxLength?: number; + isGroup?: boolean; +}; + +export const SessionIdEditable = (props: Props) => { + const { placeholder, onPressEnter, onChange, editable, text, value, maxLength, isGroup } = props; + const inputRef = useRef(null); + + useFocusMount(inputRef, editable); + function handleChange(e: ChangeEvent) { + if (editable && onChange) { + const eventValue = e.target.value?.replace(/(\r\n|\n|\r)/gm, ''); + onChange(eventValue); + } + } + + function handleKeyDown(e: KeyboardEvent) { + if (editable && e.key === 'Enter') { + e.preventDefault(); + // tslint:disable-next-line: no-unused-expression + onPressEnter && onPressEnter(); + } + } + + return ( +
+