mirror of
				https://github.com/lingble/chatwoot.git
				synced 2025-10-31 02:57:57 +00:00 
			
		
		
		
	feat: Inbox card context menu component (#8815)
* feat: Inbox item context menu component * chore: Minor fix * chore: Minor height fix * fix: Conflict * minor fix * chore: Fix conflicts * chore: Minor fix --------- Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
This commit is contained in:
		| @@ -12,6 +12,12 @@ | |||||||
|       "CONVERSATION_ASSIGNMENT": "A conversation has been assigned to you", |       "CONVERSATION_ASSIGNMENT": "A conversation has been assigned to you", | ||||||
|       "ASSIGNED_CONVERSATION_NEW_MESSAGE": "New message in an assigned conversation", |       "ASSIGNED_CONVERSATION_NEW_MESSAGE": "New message in an assigned conversation", | ||||||
|       "PARTICIPATING_CONVERSATION_NEW_MESSAGE": "New message in a conversation you are participating in" |       "PARTICIPATING_CONVERSATION_NEW_MESSAGE": "New message in a conversation you are participating in" | ||||||
|  |     }, | ||||||
|  |     "MENU_ITEM": { | ||||||
|  |       "MARK_AS_READ": "Mark as read", | ||||||
|  |       "MARK_AS_UNREAD": "Mark as unread", | ||||||
|  |       "SNOOZE": "Snooze", | ||||||
|  |       "DELETE": "Delete" | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -2,6 +2,7 @@ | |||||||
|   <div |   <div | ||||||
|     role="button" |     role="button" | ||||||
|     class="flex flex-col pl-5 pr-3 gap-2.5 py-3 w-full bg-white dark:bg-slate-900 border-b border-slate-50 dark:border-slate-800/50 hover:bg-slate-25 dark:hover:bg-slate-800 cursor-pointer" |     class="flex flex-col pl-5 pr-3 gap-2.5 py-3 w-full bg-white dark:bg-slate-900 border-b border-slate-50 dark:border-slate-800/50 hover:bg-slate-25 dark:hover:bg-slate-800 cursor-pointer" | ||||||
|  |     @contextmenu="openContextMenu($event)" | ||||||
|     @click="openConversation(notificationItem)" |     @click="openConversation(notificationItem)" | ||||||
|   > |   > | ||||||
|     <div class="flex relative items-center justify-between w-full"> |     <div class="flex relative items-center justify-between w-full"> | ||||||
| @@ -41,17 +42,24 @@ | |||||||
|         {{ lastActivityAt }} |         {{ lastActivityAt }} | ||||||
|       </span> |       </span> | ||||||
|     </div> |     </div> | ||||||
|  |     <inbox-context-menu | ||||||
|  |       v-if="isContextMenuOpen" | ||||||
|  |       :context-menu-position="contextMenuPosition" | ||||||
|  |       @close="closeContextMenu" | ||||||
|  |     /> | ||||||
|   </div> |   </div> | ||||||
| </template> | </template> | ||||||
| <script> | <script> | ||||||
| import PriorityIcon from './PriorityIcon.vue'; | import PriorityIcon from './PriorityIcon.vue'; | ||||||
| import StatusIcon from './StatusIcon.vue'; | import StatusIcon from './StatusIcon.vue'; | ||||||
| import InboxNameAndId from './InboxNameAndId.vue'; | import InboxNameAndId from './InboxNameAndId.vue'; | ||||||
|  | import InboxContextMenu from './InboxContextMenu.vue'; | ||||||
| import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue'; | import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue'; | ||||||
| import timeMixin from 'dashboard/mixins/time'; | import timeMixin from 'dashboard/mixins/time'; | ||||||
| export default { | export default { | ||||||
|   components: { |   components: { | ||||||
|     PriorityIcon, |     PriorityIcon, | ||||||
|  |     InboxContextMenu, | ||||||
|     StatusIcon, |     StatusIcon, | ||||||
|     InboxNameAndId, |     InboxNameAndId, | ||||||
|     Thumbnail, |     Thumbnail, | ||||||
| @@ -63,6 +71,12 @@ export default { | |||||||
|       default: () => {}, |       default: () => {}, | ||||||
|     }, |     }, | ||||||
|   }, |   }, | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       isContextMenuOpen: false, | ||||||
|  |       contextMenuPosition: { x: null, y: null }, | ||||||
|  |     }; | ||||||
|  |   }, | ||||||
|   computed: { |   computed: { | ||||||
|     primaryActor() { |     primaryActor() { | ||||||
|       return this.notificationItem?.primary_actor; |       return this.notificationItem?.primary_actor; | ||||||
| @@ -93,10 +107,26 @@ export default { | |||||||
|       return this.shortTimestamp(dynamicTime, true); |       return this.shortTimestamp(dynamicTime, true); | ||||||
|     }, |     }, | ||||||
|   }, |   }, | ||||||
|  |   unmounted() { | ||||||
|  |     this.closeContextMenu(); | ||||||
|  |   }, | ||||||
|   methods: { |   methods: { | ||||||
|     openConversation(notification) { |     openConversation(notification) { | ||||||
|       this.$emit('open-conversation', notification); |       this.$emit('open-conversation', notification); | ||||||
|     }, |     }, | ||||||
|  |     closeContextMenu() { | ||||||
|  |       this.isContextMenuOpen = false; | ||||||
|  |       this.contextMenuPosition = { x: null, y: null }; | ||||||
|  |     }, | ||||||
|  |     openContextMenu(e) { | ||||||
|  |       this.closeContextMenu(); | ||||||
|  |       e.preventDefault(); | ||||||
|  |       this.contextMenuPosition = { | ||||||
|  |         x: e.pageX || e.clientX, | ||||||
|  |         y: e.pageY || e.clientY, | ||||||
|  |       }; | ||||||
|  |       this.isContextMenuOpen = true; | ||||||
|  |     }, | ||||||
|   }, |   }, | ||||||
| }; | }; | ||||||
| </script> | </script> | ||||||
|   | |||||||
| @@ -0,0 +1,64 @@ | |||||||
|  | <template> | ||||||
|  |   <woot-context-menu | ||||||
|  |     :x="contextMenuPosition.x" | ||||||
|  |     :y="contextMenuPosition.y" | ||||||
|  |     @close="handleClose" | ||||||
|  |   > | ||||||
|  |     <div | ||||||
|  |       class="bg-white dark:bg-slate-900 w-40 py-1 border shadow-md border-slate-100 dark:border-slate-500 rounded-xl" | ||||||
|  |     > | ||||||
|  |       <menu-item | ||||||
|  |         v-for="item in menuItems" | ||||||
|  |         :key="item.key" | ||||||
|  |         :label="item.label" | ||||||
|  |         @click="onMenuItemClick(item.key)" | ||||||
|  |       /> | ||||||
|  |     </div> | ||||||
|  |   </woot-context-menu> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import MenuItem from './MenuItem.vue'; | ||||||
|  | export default { | ||||||
|  |   components: { | ||||||
|  |     MenuItem, | ||||||
|  |   }, | ||||||
|  |   props: { | ||||||
|  |     contextMenuPosition: { | ||||||
|  |       type: Object, | ||||||
|  |       default: () => ({}), | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       menuItems: [ | ||||||
|  |         { | ||||||
|  |           key: 'mark_as_read', | ||||||
|  |           label: this.$t('INBOX.MENU_ITEM.MARK_AS_READ'), | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |           key: 'mark_as_unread', | ||||||
|  |           label: this.$t('INBOX.MENU_ITEM.MARK_AS_UNREAD'), | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |           key: 'snooze', | ||||||
|  |           label: this.$t('INBOX.MENU_ITEM.SNOOZE'), | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |           key: 'delete', | ||||||
|  |           label: this.$t('INBOX.MENU_ITEM.DELETE'), | ||||||
|  |         }, | ||||||
|  |       ], | ||||||
|  |     }; | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     handleClose() { | ||||||
|  |       this.$emit('close'); | ||||||
|  |     }, | ||||||
|  |     onMenuItemClick(key) { | ||||||
|  |       this.$emit('click', key); | ||||||
|  |       this.handleClose(); | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  | }; | ||||||
|  | </script> | ||||||
| @@ -0,0 +1,25 @@ | |||||||
|  | <script setup> | ||||||
|  | import { defineProps, defineEmits } from 'vue'; | ||||||
|  |  | ||||||
|  | defineProps({ | ||||||
|  |   label: { | ||||||
|  |     type: String, | ||||||
|  |     default: '', | ||||||
|  |   }, | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | const emits = defineEmits(['click']); | ||||||
|  |  | ||||||
|  | const onMenuItemClick = () => { | ||||||
|  |   emits('click'); | ||||||
|  | }; | ||||||
|  | </script> | ||||||
|  | <template> | ||||||
|  |   <div | ||||||
|  |     role="button" | ||||||
|  |     class="py-1 px-2 w-full h-8 font-medium text-xs text-slate-800 dark:text-slate-100 flex items-center whitespace-nowrap text-ellipsis overflow-hidden hover:text-woot-600 dark:hover:text-woot-500 cursor-pointer rounded-md" | ||||||
|  |     @click.stop="onMenuItemClick" | ||||||
|  |   > | ||||||
|  |     {{ label }} | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
		Reference in New Issue
	
	Block a user
	 Sivin Varghese
					Sivin Varghese