mirror of
				https://github.com/lingble/chatwoot.git
				synced 2025-10-31 02:57:57 +00:00 
			
		
		
		
	Feat: Show notes panel on crm page (#2320)
* Feat: Show notes panel on CRM page Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
This commit is contained in:
		 Nithin David Thomas
					Nithin David Thomas
				
			
				
					committed by
					
						 GitHub
						GitHub
					
				
			
			
				
	
			
			
			 GitHub
						GitHub
					
				
			
						parent
						
							75d05e55ae
						
					
				
				
					commit
					fe2af370e0
				
			
							
								
								
									
										9
									
								
								app/javascript/dashboard/api/contactNotes.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								app/javascript/dashboard/api/contactNotes.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | |||||||
|  | import ApiClient from './ApiClient'; | ||||||
|  |  | ||||||
|  | class ContactNotes extends ApiClient { | ||||||
|  |   constructor() { | ||||||
|  |     super('contact_notes', { accountScoped: true }); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export default new ContactNotes(); | ||||||
| @@ -8,6 +8,7 @@ | |||||||
| } | } | ||||||
|  |  | ||||||
| .card { | .card { | ||||||
|  |   margin-bottom: var(--space-small); | ||||||
|   padding: var(--space-small); |   padding: var(--space-small); | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -4,27 +4,28 @@ | |||||||
|       <contact-panel v-if="!uiFlags.isFetchingItem" :contact="contact" /> |       <contact-panel v-if="!uiFlags.isFetchingItem" :contact="contact" /> | ||||||
|     </div> |     </div> | ||||||
|     <div class="center"></div> |     <div class="center"></div> | ||||||
|     <div class="right"></div> |     <div class="right"> | ||||||
|  |       <contact-notes :contact-id="Number(contactId)" /> | ||||||
|  |     </div> | ||||||
|   </div> |   </div> | ||||||
| </template> | </template> | ||||||
|  |  | ||||||
| <script> | <script> | ||||||
| import { mapGetters } from 'vuex'; | import { mapGetters } from 'vuex'; | ||||||
| import ContactPanel from './ContactPanel'; | import ContactPanel from './ContactPanel'; | ||||||
|  | import ContactNotes from 'dashboard/modules/notes/NotesOnContactPage'; | ||||||
|  |  | ||||||
| export default { | export default { | ||||||
|   components: { |   components: { | ||||||
|     ContactPanel, |     ContactPanel, | ||||||
|  |     ContactNotes, | ||||||
|   }, |   }, | ||||||
|   props: { |   props: { | ||||||
|     contactId: { |     contactId: { | ||||||
|       type: [String, Number], |       type: [String, Number], | ||||||
|       default: 0, |       required: true, | ||||||
|     }, |     }, | ||||||
|   }, |   }, | ||||||
|   data() { |  | ||||||
|     return {}; |  | ||||||
|   }, |  | ||||||
|   computed: { |   computed: { | ||||||
|     ...mapGetters({ |     ...mapGetters({ | ||||||
|       uiFlags: 'contacts/getUIFlags', |       uiFlags: 'contacts/getUIFlags', | ||||||
| @@ -38,13 +39,12 @@ export default { | |||||||
|     }, |     }, | ||||||
|   }, |   }, | ||||||
|   mounted() { |   mounted() { | ||||||
|     this.getContactDetails(); |     this.fetchContactDetails(); | ||||||
|   }, |   }, | ||||||
|   methods: { |   methods: { | ||||||
|     getContactDetails() { |     fetchContactDetails() { | ||||||
|       if (this.contactId) { |       const { contactId: id } = this; | ||||||
|         this.$store.dispatch('contacts/show', { id: this.contactId }); |       this.$store.dispatch('contacts/show', { id }); | ||||||
|       } |  | ||||||
|     }, |     }, | ||||||
|   }, |   }, | ||||||
| }; | }; | ||||||
| @@ -67,4 +67,8 @@ export default { | |||||||
|   border-right: 1px solid var(--color-border); |   border-right: 1px solid var(--color-border); | ||||||
|   border-left: 1px solid var(--color-border); |   border-left: 1px solid var(--color-border); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | .right { | ||||||
|  |   padding: var(--space-normal); | ||||||
|  | } | ||||||
| </style> | </style> | ||||||
|   | |||||||
| @@ -0,0 +1,43 @@ | |||||||
|  | <template> | ||||||
|  |   <note-list :notes="notes" @add="onAdd" @delete="onDelete" /> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import NoteList from './components/NoteList'; | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   components: { | ||||||
|  |     NoteList, | ||||||
|  |   }, | ||||||
|  |   props: { | ||||||
|  |     contactId: { | ||||||
|  |       type: Number, | ||||||
|  |       required: true, | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  |   computed: { | ||||||
|  |     notes() { | ||||||
|  |       return this.$store.getters['contactNotes/getAllNotesByContact']( | ||||||
|  |         this.contactId | ||||||
|  |       ); | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  |   mounted() { | ||||||
|  |     this.fetchContactNotes(); | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     fetchContactNotes() { | ||||||
|  |       const { contactId } = this; | ||||||
|  |       if (contactId) this.$store.dispatch('contactNotes/get', { contactId }); | ||||||
|  |     }, | ||||||
|  |     onAdd(content) { | ||||||
|  |       const { contactId } = this; | ||||||
|  |       this.$store.dispatch('contactNotes/create', { content, contactId }); | ||||||
|  |     }, | ||||||
|  |     onDelete(noteId) { | ||||||
|  |       const { contactId } = this; | ||||||
|  |       this.$store.dispatch('contactNotes/delete', { noteId, contactId }); | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  | }; | ||||||
|  | </script> | ||||||
| @@ -17,7 +17,7 @@ | |||||||
|         @delete="onDeleteNote" |         @delete="onDeleteNote" | ||||||
|       /> |       /> | ||||||
|       <div class="button-wrap"> |       <div class="button-wrap"> | ||||||
|         <woot-button variant="clear link" class="button" @click="onclick"> |         <woot-button variant="link" @click="onclick"> | ||||||
|           {{ $t('NOTES.FOOTER.BUTTON') }} |           {{ $t('NOTES.FOOTER.BUTTON') }} | ||||||
|           <i class="ion-arrow-right-c" /> |           <i class="ion-arrow-right-c" /> | ||||||
|         </woot-button> |         </woot-button> | ||||||
| @@ -48,13 +48,13 @@ export default { | |||||||
|       this.$emit('show'); |       this.$emit('show'); | ||||||
|     }, |     }, | ||||||
|     onAddNote(value) { |     onAddNote(value) { | ||||||
|       this.$emit('addNote', value); |       this.$emit('add', value); | ||||||
|     }, |     }, | ||||||
|     onEditNote(value) { |     onEditNote(value) { | ||||||
|       this.$emit('editNote', value); |       this.$emit('edit', value); | ||||||
|     }, |     }, | ||||||
|     onDeleteNote(value) { |     onDeleteNote(value) { | ||||||
|       this.$emit('deleteNote', value); |       this.$emit('delete', value); | ||||||
|     }, |     }, | ||||||
|   }, |   }, | ||||||
| }; | }; | ||||||
| @@ -1,5 +1,5 @@ | |||||||
| import { action } from '@storybook/addon-actions'; | import { action } from '@storybook/addon-actions'; | ||||||
| import AddNote from './AddNote.vue'; | import AddNote from '../components/AddNote.vue'; | ||||||
| 
 | 
 | ||||||
| export default { | export default { | ||||||
|   title: 'Components/Notes/Add', |   title: 'Components/Notes/Add', | ||||||
| @@ -1,5 +1,5 @@ | |||||||
| import { action } from '@storybook/addon-actions'; | import { action } from '@storybook/addon-actions'; | ||||||
| import ContactNote from './ContactNote.vue'; | import ContactNote from '../components/ContactNote.vue'; | ||||||
| 
 | 
 | ||||||
| export default { | export default { | ||||||
|   title: 'Components/Notes/Note', |   title: 'Components/Notes/Note', | ||||||
| @@ -1,15 +1,15 @@ | |||||||
| import { action } from '@storybook/addon-actions'; | import { action } from '@storybook/addon-actions'; | ||||||
| import noteList from './NoteList'; | import NoteList from '../components/NoteList'; | ||||||
| 
 | 
 | ||||||
| export default { | export default { | ||||||
|   title: 'Components/Notes/List', |   title: 'Components/Notes/List', | ||||||
|   component: noteList, |   component: NoteList, | ||||||
|   argTypes: {}, |   argTypes: {}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| const Template = (args, { argTypes }) => ({ | const Template = (args, { argTypes }) => ({ | ||||||
|   props: Object.keys(argTypes), |   props: Object.keys(argTypes), | ||||||
|   components: { noteList }, |   components: { NoteList }, | ||||||
|   template: |   template: | ||||||
|     '<note-list v-bind="$props" @addNote="onAddNote" @editNote="onEditNote" @deleteNote="onDeleteNote" @show="onClick"></note-list>', |     '<note-list v-bind="$props" @addNote="onAddNote" @editNote="onEditNote" @deleteNote="onDeleteNote" @show="onClick"></note-list>', | ||||||
| }); | }); | ||||||
| @@ -27,6 +27,7 @@ import webhooks from './modules/webhooks'; | |||||||
| import teams from './modules/teams'; | import teams from './modules/teams'; | ||||||
| import teamMembers from './modules/teamMembers'; | import teamMembers from './modules/teamMembers'; | ||||||
| import campaigns from './modules/campaigns'; | import campaigns from './modules/campaigns'; | ||||||
|  | import contactNotes from './modules/contactNotes'; | ||||||
|  |  | ||||||
| Vue.use(Vuex); | Vue.use(Vuex); | ||||||
| export default new Vuex.Store({ | export default new Vuex.Store({ | ||||||
| @@ -57,5 +58,6 @@ export default new Vuex.Store({ | |||||||
|     teams, |     teams, | ||||||
|     teamMembers, |     teamMembers, | ||||||
|     campaigns, |     campaigns, | ||||||
|  |     contactNotes, | ||||||
|   }, |   }, | ||||||
| }); | }); | ||||||
|   | |||||||
							
								
								
									
										107
									
								
								app/javascript/dashboard/store/modules/contactNotes.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								app/javascript/dashboard/store/modules/contactNotes.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,107 @@ | |||||||
|  | import * as types from '../mutation-types'; | ||||||
|  | import Vue from 'vue'; | ||||||
|  | import ContactNotesAPI from '../../api/contactNotes'; | ||||||
|  |  | ||||||
|  | export const state = { | ||||||
|  |   records: {}, | ||||||
|  |   uiFlags: { | ||||||
|  |     isFetching: false, | ||||||
|  |     isCreating: false, | ||||||
|  |     isDeleting: false, | ||||||
|  |   }, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | export const getters = { | ||||||
|  |   getAllNotesByContact: _state => contactId => { | ||||||
|  |     return _state.records[contactId] || []; | ||||||
|  |   }, | ||||||
|  |   getUIFlags(_state) { | ||||||
|  |     return _state.uiFlags; | ||||||
|  |   }, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | export const actions = { | ||||||
|  |   async get({ commit }, { contactId }) { | ||||||
|  |     commit(types.default.SET_CONTACT_NOTES_UI_FLAG, { | ||||||
|  |       isFetching: true, | ||||||
|  |     }); | ||||||
|  |     try { | ||||||
|  |       const { data } = await ContactNotesAPI.get(contactId); | ||||||
|  |       commit(types.default.SET_CONTACT_NOTES, { contactId, data }); | ||||||
|  |     } catch (error) { | ||||||
|  |       throw new Error(error); | ||||||
|  |     } finally { | ||||||
|  |       commit(types.default.SET_CONTACT_NOTES_UI_FLAG, { | ||||||
|  |         isFetching: false, | ||||||
|  |       }); | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |  | ||||||
|  |   async create({ commit }, { contactId, content }) { | ||||||
|  |     commit(types.default.SET_CONTACT_NOTES_UI_FLAG, { | ||||||
|  |       isCreating: true, | ||||||
|  |     }); | ||||||
|  |     try { | ||||||
|  |       const { data } = await ContactNotesAPI.create({ | ||||||
|  |         content, | ||||||
|  |         contactId, | ||||||
|  |       }); | ||||||
|  |       commit(types.default.ADD_CONTACT_NOTE, { | ||||||
|  |         contactId, | ||||||
|  |         data, | ||||||
|  |       }); | ||||||
|  |     } catch (error) { | ||||||
|  |       throw new Error(error); | ||||||
|  |     } finally { | ||||||
|  |       commit(types.default.SET_CONTACT_NOTES_UI_FLAG, { | ||||||
|  |         isCreating: false, | ||||||
|  |       }); | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |  | ||||||
|  |   async delete({ commit }, { noteId, contactId }) { | ||||||
|  |     commit(types.default.SET_CONTACT_NOTES_UI_FLAG, { | ||||||
|  |       isDeleting: true, | ||||||
|  |     }); | ||||||
|  |     try { | ||||||
|  |       await ContactNotesAPI.delete(contactId, noteId); | ||||||
|  |       commit(types.default.DELETE_CONTACT_NOTE, { contactId, noteId }); | ||||||
|  |     } catch (error) { | ||||||
|  |       throw new Error(error); | ||||||
|  |     } finally { | ||||||
|  |       commit(types.default.SET_CONTACT_NOTES_UI_FLAG, { | ||||||
|  |         isDeleting: false, | ||||||
|  |       }); | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | export const mutations = { | ||||||
|  |   [types.default.SET_CONTACT_NOTES_UI_FLAG](_state, data) { | ||||||
|  |     _state.uiFlags = { | ||||||
|  |       ..._state.uiFlags, | ||||||
|  |       ...data, | ||||||
|  |     }; | ||||||
|  |   }, | ||||||
|  |  | ||||||
|  |   [types.default.SET_CONTACT_NOTES]($state, { data, contactId }) { | ||||||
|  |     Vue.set($state.records, contactId, data); | ||||||
|  |   }, | ||||||
|  |   [types.default.ADD_CONTACT_NOTE]($state, { data, contactId }) { | ||||||
|  |     const contactNotes = $state.records[contactId] || []; | ||||||
|  |     $state.records[contactId] = [...contactNotes, data]; | ||||||
|  |   }, | ||||||
|  |   [types.default.DELETE_CONTACT_NOTE]($state, { noteId, contactId }) { | ||||||
|  |     const contactNotes = $state.records[contactId]; | ||||||
|  |     const withoutDeletedNote = contactNotes.filter(note => note.id !== noteId); | ||||||
|  |     $state.records[contactId] = [...withoutDeletedNote]; | ||||||
|  |   }, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   namespaced: true, | ||||||
|  |   state, | ||||||
|  |   getters, | ||||||
|  |   actions, | ||||||
|  |   mutations, | ||||||
|  | }; | ||||||
| @@ -0,0 +1,78 @@ | |||||||
|  | import axios from 'axios'; | ||||||
|  | import { actions } from '../../contactNotes'; | ||||||
|  | import * as types from '../../../mutation-types'; | ||||||
|  | import notesData from './fixtures'; | ||||||
|  |  | ||||||
|  | const commit = jest.fn(); | ||||||
|  | global.axios = axios; | ||||||
|  | jest.mock('axios'); | ||||||
|  |  | ||||||
|  | describe('#actions', () => { | ||||||
|  |   describe('#get', () => { | ||||||
|  |     it('sends correct actions if API is success', async () => { | ||||||
|  |       axios.get.mockResolvedValue({ data: notesData }); | ||||||
|  |       await actions.get({ commit }, { contactId: 23 }); | ||||||
|  |       expect(commit.mock.calls).toEqual([ | ||||||
|  |         [types.default.SET_CONTACT_NOTES_UI_FLAG, { isFetching: true }], | ||||||
|  |         [types.default.SET_CONTACT_NOTES, { contactId: 23, data: notesData }], | ||||||
|  |         [types.default.SET_CONTACT_NOTES_UI_FLAG, { isFetching: false }], | ||||||
|  |       ]); | ||||||
|  |     }); | ||||||
|  |     it('sends correct actions if API is error', async () => { | ||||||
|  |       axios.get.mockRejectedValue({ message: 'Incorrect header' }); | ||||||
|  |       await expect(actions.get({ commit }, { contactId: 23 })).rejects.toThrow( | ||||||
|  |         Error | ||||||
|  |       ); | ||||||
|  |       expect(commit.mock.calls).toEqual([ | ||||||
|  |         [types.default.SET_CONTACT_NOTES_UI_FLAG, { isFetching: true }], | ||||||
|  |         [types.default.SET_CONTACT_NOTES_UI_FLAG, { isFetching: false }], | ||||||
|  |       ]); | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  |   describe('#create', () => { | ||||||
|  |     it('sends correct actions if API is success', async () => { | ||||||
|  |       axios.post.mockResolvedValue({ data: { id: 2, content: 'hi' } }); | ||||||
|  |       await actions.create({ commit }, { contactId: 1, content: 'hi' }); | ||||||
|  |       expect(commit.mock.calls).toEqual([ | ||||||
|  |         [types.default.SET_CONTACT_NOTES_UI_FLAG, { isCreating: true }], | ||||||
|  |         [ | ||||||
|  |           types.default.ADD_CONTACT_NOTE, | ||||||
|  |           { contactId: 1, data: { id: 2, content: 'hi' } }, | ||||||
|  |         ], | ||||||
|  |         [types.default.SET_CONTACT_NOTES_UI_FLAG, { isCreating: false }], | ||||||
|  |       ]); | ||||||
|  |     }); | ||||||
|  |     it('sends correct actions if API is error', async () => { | ||||||
|  |       axios.post.mockRejectedValue({ message: 'Incorrect header' }); | ||||||
|  |       await expect( | ||||||
|  |         actions.create({ commit }, { contactId: 1, content: 'hi' }) | ||||||
|  |       ).rejects.toThrow(Error); | ||||||
|  |       expect(commit.mock.calls).toEqual([ | ||||||
|  |         [types.default.SET_CONTACT_NOTES_UI_FLAG, { isCreating: true }], | ||||||
|  |         [types.default.SET_CONTACT_NOTES_UI_FLAG, { isCreating: false }], | ||||||
|  |       ]); | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   describe('#delete', () => { | ||||||
|  |     it('sends correct actions if API is success', async () => { | ||||||
|  |       axios.delete.mockResolvedValue({ data: notesData[0] }); | ||||||
|  |       await actions.delete({ commit }, { contactId: 1, noteId: 2 }); | ||||||
|  |       expect(commit.mock.calls).toEqual([ | ||||||
|  |         [types.default.SET_CONTACT_NOTES_UI_FLAG, { isDeleting: true }], | ||||||
|  |         [types.default.DELETE_CONTACT_NOTE, { contactId: 1, noteId: 2 }], | ||||||
|  |         [types.default.SET_CONTACT_NOTES_UI_FLAG, { isDeleting: false }], | ||||||
|  |       ]); | ||||||
|  |     }); | ||||||
|  |     it('sends correct actions if API is error', async () => { | ||||||
|  |       axios.delete.mockRejectedValue({ message: 'Incorrect header' }); | ||||||
|  |       await expect( | ||||||
|  |         actions.delete({ commit }, { contactId: 1, noteId: 2 }) | ||||||
|  |       ).rejects.toThrow(Error); | ||||||
|  |       expect(commit.mock.calls).toEqual([ | ||||||
|  |         [types.default.SET_CONTACT_NOTES_UI_FLAG, { isDeleting: true }], | ||||||
|  |         [types.default.SET_CONTACT_NOTES_UI_FLAG, { isDeleting: false }], | ||||||
|  |       ]); | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  | }); | ||||||
| @@ -0,0 +1,21 @@ | |||||||
|  | export default [ | ||||||
|  |   { | ||||||
|  |     id: 12345, | ||||||
|  |     content: 'It is a long established fact that a reader will be distracted.', | ||||||
|  |     user: { | ||||||
|  |       name: 'John Doe', | ||||||
|  |       thumbnail: 'https://randomuser.me/api/portraits/men/69.jpg', | ||||||
|  |     }, | ||||||
|  |     created_at: 1618046084, | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     id: 12346, | ||||||
|  |     content: | ||||||
|  |       'It is simply dummy text of the printing and typesetting industry.', | ||||||
|  |     user: { | ||||||
|  |       name: 'Pearl Cruz', | ||||||
|  |       thumbnail: 'https://randomuser.me/api/portraits/women/29.jpg', | ||||||
|  |     }, | ||||||
|  |     created_at: 1616046076, | ||||||
|  |   }, | ||||||
|  | ]; | ||||||
| @@ -0,0 +1,24 @@ | |||||||
|  | import { getters } from '../../contactNotes'; | ||||||
|  | import notesData from './fixtures'; | ||||||
|  |  | ||||||
|  | describe('#getters', () => { | ||||||
|  |   it('getAllNotesByContact', () => { | ||||||
|  |     const state = { records: { 1: notesData } }; | ||||||
|  |     expect(getters.getAllNotesByContact(state)(1)).toEqual(notesData); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('getUIFlags', () => { | ||||||
|  |     const state = { | ||||||
|  |       uiFlags: { | ||||||
|  |         isFetching: true, | ||||||
|  |         isCreating: false, | ||||||
|  |         isDeleting: false, | ||||||
|  |       }, | ||||||
|  |     }; | ||||||
|  |     expect(getters.getUIFlags(state)).toEqual({ | ||||||
|  |       isFetching: true, | ||||||
|  |       isCreating: false, | ||||||
|  |       isDeleting: false, | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  | }); | ||||||
| @@ -0,0 +1,37 @@ | |||||||
|  | import types from '../../../mutation-types'; | ||||||
|  | import { mutations } from '../../contactNotes'; | ||||||
|  | import allNotes from './fixtures'; | ||||||
|  |  | ||||||
|  | describe('#mutations', () => { | ||||||
|  |   describe('#SET_CONTACT_NOTES', () => { | ||||||
|  |     it('set allNotes records', () => { | ||||||
|  |       const state = { records: {} }; | ||||||
|  |       mutations[types.SET_CONTACT_NOTES](state, { | ||||||
|  |         data: allNotes, | ||||||
|  |         contactId: 1, | ||||||
|  |       }); | ||||||
|  |       expect(state.records).toEqual({ 1: allNotes }); | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   describe('#ADD_CONTACT_NOTE', () => { | ||||||
|  |     it('push newly created note to the store', () => { | ||||||
|  |       const state = { records: { 1: [allNotes[0]] } }; | ||||||
|  |       mutations[types.ADD_CONTACT_NOTE](state, { | ||||||
|  |         data: allNotes[1], | ||||||
|  |         contactId: 1, | ||||||
|  |       }); | ||||||
|  |       expect(state.records[1]).toEqual([allNotes[0], allNotes[1]]); | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  |   describe('#DELETE_CONTACT_NOTE', () => { | ||||||
|  |     it('Delete existing note from records', () => { | ||||||
|  |       const state = { records: { 1: [{ id: 2 }] } }; | ||||||
|  |       mutations[types.DELETE_CONTACT_NOTE](state, { | ||||||
|  |         noteId: 2, | ||||||
|  |         contactId: 1, | ||||||
|  |       }); | ||||||
|  |       expect(state.records[1]).toEqual([]); | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  | }); | ||||||
| @@ -154,4 +154,11 @@ export default { | |||||||
|   SET_CAMPAIGNS: 'SET_CAMPAIGNS', |   SET_CAMPAIGNS: 'SET_CAMPAIGNS', | ||||||
|   ADD_CAMPAIGN: 'ADD_CAMPAIGN', |   ADD_CAMPAIGN: 'ADD_CAMPAIGN', | ||||||
|   EDIT_CAMPAIGN: 'EDIT_CAMPAIGN', |   EDIT_CAMPAIGN: 'EDIT_CAMPAIGN', | ||||||
|  |  | ||||||
|  |   // Contact notes | ||||||
|  |   SET_CONTACT_NOTES_UI_FLAG: 'SET_CONTACT_NOTES_UI_FLAG', | ||||||
|  |   SET_CONTACT_NOTES: 'SET_CONTACT_NOTES', | ||||||
|  |   ADD_CONTACT_NOTE: 'ADD_CONTACT_NOTE', | ||||||
|  |   EDIT_CONTACT_NOTE: 'EDIT_CONTACT_NOTE', | ||||||
|  |   DELETE_CONTACT_NOTE: 'DELETE_CONTACT_NOTE', | ||||||
| }; | }; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user