feat: Adds keyboard shortcuts for conversation actions (#2672)

* feat: Adds keyboard shortcuts for conversation actions

* Minor fixes

* Minor fixes

* Minor fixes and add new shortcut

* MInor fixes

* Review fixes

* Minor fixes

* Code cleanup

* Minor fixes

* Uses Alt or Option key instead of shift-key

* Review fixes

* Review fixes

Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
This commit is contained in:
Sivin Varghese 2021-08-09 13:08:52 +05:30 committed by GitHub
parent c7482696d4
commit c523a953f7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 311 additions and 51 deletions

View file

@ -10,8 +10,11 @@
</template>
<script>
import wootConstants from '../../constants';
import eventListenerMixins from 'shared/mixins/eventListenerMixins';
import { hasPressedAltAndNKey } from 'shared/helpers/KeyboardHelpers';
export default {
mixins: [eventListenerMixins],
props: {
items: {
type: Array,
@ -28,6 +31,15 @@ export default {
},
},
methods: {
handleKeyEvents(e) {
if (hasPressedAltAndNKey(e)) {
if (this.activeTab === wootConstants.ASSIGNEE_TYPE.ALL) {
this.onTabChange(0);
} else {
this.onTabChange(this.activeTabIndex + 1);
}
}
},
onTabChange(selectedTabIndex) {
if (this.items[selectedTabIndex].key !== this.activeTab) {
this.$emit('chatTabChange', this.items[selectedTabIndex].key);

View file

@ -78,11 +78,17 @@
<script>
import FileUpload from 'vue-upload-component';
import {
hasPressedAltAndWKey,
hasPressedAltAndAKey,
} from 'shared/helpers/KeyboardHelpers';
import eventListenerMixins from 'shared/mixins/eventListenerMixins';
import { REPLY_EDITOR_MODES } from './constants';
export default {
name: 'ReplyTopPanel',
components: { FileUpload },
mixins: [eventListenerMixins],
props: {
mode: {
type: String,
@ -156,6 +162,14 @@ export default {
},
},
methods: {
handleKeyEvents(e) {
if (hasPressedAltAndWKey(e)) {
this.toggleFormatMode();
}
if (hasPressedAltAndAKey(e)) {
this.$refs.upload.$children[1].$el.click();
}
},
toggleFormatMode() {
this.setFormatMode(!this.isFormatMode);
},

View file

@ -32,11 +32,17 @@
<script>
import { REPLY_EDITOR_MODES, CHAR_LENGTH_WARNING } from './constants';
import EmojiOrIcon from 'shared/components/EmojiOrIcon';
import {
hasPressedAltAndPKey,
hasPressedAltAndLKey,
} from 'shared/helpers/KeyboardHelpers';
import eventListenerMixins from 'shared/mixins/eventListenerMixins';
export default {
name: 'ReplyTopPanel',
components: {
EmojiOrIcon,
},
mixins: [eventListenerMixins],
props: {
mode: {
type: String,
@ -76,6 +82,14 @@ export default {
},
},
methods: {
handleKeyEvents(e) {
if (hasPressedAltAndPKey(e)) {
this.handleNoteClick();
}
if (hasPressedAltAndLKey(e)) {
this.handleReplyClick();
}
},
handleReplyClick() {
this.setReplyMode(REPLY_EDITOR_MODES.REPLY);
},

View file

@ -12,12 +12,29 @@
<script>
import wootConstants from '../../../constants';
import eventListenerMixins from 'shared/mixins/eventListenerMixins';
import { hasPressedAltAndBKey } from 'shared/helpers/KeyboardHelpers';
export default {
mixins: [eventListenerMixins],
data: () => ({
activeStatus: wootConstants.STATUS_TYPE.OPEN,
}),
methods: {
handleKeyEvents(e) {
if (hasPressedAltAndBKey(e)) {
if (this.activeStatus === wootConstants.STATUS_TYPE.OPEN) {
this.activeStatus = wootConstants.STATUS_TYPE.RESOLVED;
} else if (this.activeStatus === wootConstants.STATUS_TYPE.RESOLVED) {
this.activeStatus = wootConstants.STATUS_TYPE.PENDING;
} else if (this.activeStatus === wootConstants.STATUS_TYPE.PENDING) {
this.activeStatus = wootConstants.STATUS_TYPE.SNOOZED;
} else if (this.activeStatus === wootConstants.STATUS_TYPE.SNOOZED) {
this.activeStatus = wootConstants.STATUS_TYPE.OPEN;
}
}
this.onTabChange();
},
onTabChange() {
this.$store.dispatch('setChatFilter', this.activeStatus);
this.$emit('statusFilterChange', this.activeStatus);

View file

@ -68,7 +68,9 @@ import { mapGetters } from 'vuex';
import MoreActions from './MoreActions';
import Thumbnail from '../Thumbnail';
import agentMixin from '../../../mixins/agentMixin.js';
import eventListenerMixins from 'shared/mixins/eventListenerMixins';
import AvailabilityStatusBadge from '../conversation/AvailabilityStatusBadge';
import { hasPressedAltAndOKey } from 'shared/helpers/KeyboardHelpers';
export default {
components: {
@ -76,7 +78,7 @@ export default {
Thumbnail,
AvailabilityStatusBadge,
},
mixins: [agentMixin],
mixins: [agentMixin, eventListenerMixins],
props: {
chat: {
type: Object,
@ -117,6 +119,11 @@ export default {
},
methods: {
handleKeyEvents(e) {
if (hasPressedAltAndOKey(e)) {
this.$emit('contact-panel-toggle');
}
},
assignAgent(agent) {
this.$store
.dispatch('assignAgent', {

View file

@ -74,6 +74,7 @@
import { mapGetters } from 'vuex';
import { mixin as clickaway } from 'vue-clickaway';
import alertMixin from 'shared/mixins/alertMixin';
import eventListenerMixins from 'shared/mixins/eventListenerMixins';
import EmojiInput from 'shared/components/emoji/EmojiInput';
import CannedResponse from './CannedResponse';
@ -105,7 +106,13 @@ export default {
ReplyBottomPanel,
WootMessageEditor,
},
mixins: [clickaway, inboxMixin, uiSettingsMixin, alertMixin],
mixins: [
clickaway,
inboxMixin,
uiSettingsMixin,
alertMixin,
eventListenerMixins,
],
props: {
selectedTweet: {
type: [Object, String],
@ -289,12 +296,6 @@ export default {
}
},
},
mounted() {
document.addEventListener('keydown', this.handleKeyEvents);
},
destroyed() {
document.removeEventListener('keydown', this.handleKeyEvents);
},
methods: {
toggleUserMention(currentMentionState) {
this.hasUserMention = currentMentionState;
@ -353,6 +354,9 @@ export default {
if (this.showRichContentEditor) {
return;
}
if (this.$refs.messageInput === undefined) {
return;
}
this.$nextTick(() => this.$refs.messageInput.focus());
},
emojiOnClick(emoji) {