Skip to content

Commit

Permalink
Feat: Store input in browser storage
Browse files Browse the repository at this point in the history
Signed-off-by: DorraJaouad <dorra.jaoued7@gmail.com>
  • Loading branch information
DorraJaouad committed Feb 29, 2024
1 parent e02b293 commit 4c0e6f6
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 25 deletions.
50 changes: 29 additions & 21 deletions src/components/NewMessage/NewMessage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,8 @@
</template>

<script>
import debounce from 'debounce'

import BellOff from 'vue-material-design-icons/BellOff.vue'
import CheckIcon from 'vue-material-design-icons/Check.vue'
import CloseIcon from 'vue-material-design-icons/Close.vue'
Expand Down Expand Up @@ -333,6 +335,7 @@ export default {
clipboardTimeStamp: null,
typingInterval: null,
wasTypingWithinInterval: false,
debouncedUpdateChatInput: debounce(this.updateChatInput, 200)
}
},

Expand Down Expand Up @@ -459,6 +462,10 @@ export default {
return /Android|iPhone|iPad|iPod/i.test(navigator.userAgent)
},

chatInput() {
return this.chatExtrasStore.getChatInput(this.token)
},

chatEditInput() {
return this.chatExtrasStore.getChatEditInput(this.token)
},
Expand All @@ -475,23 +482,15 @@ export default {
},

text(newValue) {
if (this.messageToEdit) {
this.chatExtrasStore.setChatEditInput({
token: this.token,
text: newValue,
parameters: this.messageToEdit.messageParameters
})
} else {
this.chatExtrasStore.setChatInput({ token: this.token, text: newValue })
}
this.debouncedUpdateChatInput(newValue)
},

messageToEdit(newValue) {
if (newValue) {
this.text = this.chatExtrasStore.getChatEditInput(this.token)
this.chatExtrasStore.removeParentIdToReply(this.token)
} else {
this.text = this.chatExtrasStore.getChatInput(this.token)
this.text = this.chatInput
}
},

Expand All @@ -512,8 +511,8 @@ export default {
handler(token) {
if (token) {
this.text = this.messageToEdit
? this.chatExtrasStore.getChatEditInput(token)
: this.chatExtrasStore.getChatInput(token)
? this.chatEditInput
: this.chatInput
} else {
this.text = ''
}
Expand All @@ -529,7 +528,6 @@ export default {
EventBus.$on('upload-start', this.handleUploadSideEffects)
EventBus.$on('upload-discard', this.handleUploadSideEffects)
EventBus.$on('retry-message', this.handleRetryMessage)
this.text = this.chatExtrasStore.getChatInput(this.token)

if (!this.$store.getters.areFileTemplatesInitialised) {
this.$store.dispatch('getFileTemplates')
Expand Down Expand Up @@ -581,13 +579,25 @@ export default {
}
},

updateChatInput(text) {
if (this.messageToEdit) {
this.chatExtrasStore.setChatEditInput({
token: this.token,
text,
parameters: this.messageToEdit.messageParameters
})
} else if (text && text !== this.chatInput) {
this.chatExtrasStore.setChatInput({ token: this.token, text })
} else if (!text && this.chatInput) {
this.chatExtrasStore.removeChatInput(this.token)
}
},

handleUploadSideEffects() {
if (this.upload) {
return
}
this.$nextTick(() => {
// reset or fill main input in chat view from the store
this.text = this.chatExtrasStore.getChatInput(this.token)
// refocus input as the user might want to type further
this.focusInput()
})
Expand Down Expand Up @@ -622,11 +632,11 @@ export default {
this.text = parseSpecialSymbols(this.text)
}

if (this.upload) {
// Clear input content from store and remove Quote component
this.chatExtrasStore.setChatInput({ token: this.token, text: '' })
this.chatExtrasStore.removeParentIdToReply(this.token)
// Clear input content from store and remove Quote component
this.chatExtrasStore.removeParentIdToReply(this.token)
this.chatExtrasStore.removeChatInput(this.token)

if (this.upload) {
if (this.$store.getters.getInitialisedUploads(this.$store.getters.currentUploadId).length) {
// If dialog contains files to upload, delegate sending
this.$emit('upload', { caption: this.text, options })
Expand All @@ -646,8 +656,6 @@ export default {
this.userData = {}
// Scrolls the message list to the last added message
EventBus.$emit('smooth-scroll-chat-to-bottom')
// Also remove the message to be replied for this conversation
this.chatExtrasStore.removeParentIdToReply(this.token)

this.broadcast
? await this.broadcastMessage(this.token, temporaryMessage.message)
Expand Down
1 change: 1 addition & 0 deletions src/store/conversationsStore.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ jest.mock('@nextcloud/event-bus')
jest.mock('../services/BrowserStorage.js', () => ({
getItem: jest.fn(),
setItem: jest.fn(),
removeItem: jest.fn(),
}))

describe('conversationsStore', () => {
Expand Down
21 changes: 21 additions & 0 deletions src/stores/__tests__/chatExtras.spec.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { setActivePinia, createPinia } from 'pinia'

import BrowserStorage from '../../services/BrowserStorage.js'
import { EventBus } from '../../services/EventBus.js'
import { getUserAbsence } from '../../services/participantsService.js'
import { generateOCSErrorResponse, generateOCSResponse } from '../../test-helpers.js'
Expand Down Expand Up @@ -103,6 +104,7 @@ describe('chatExtrasStore', () => {

// Assert
expect(chatExtrasStore.getChatInput('token-1')).toStrictEqual('message-1')
expect(BrowserStorage.getItem('chatInput_token-1')).toBe('message-1')
})

it('clears current input message', () => {
Expand All @@ -115,6 +117,25 @@ describe('chatExtrasStore', () => {
// Assert
expect(chatExtrasStore.chatInput['token-1']).not.toBeDefined()
expect(chatExtrasStore.getChatInput('token-1')).toBe('')
expect(BrowserStorage.getItem('chatInput_token-1')).toBe(null)
})

it('restores chat input from the browser storage if any', () => {
// Arrange
BrowserStorage.setItem('chatInput_token-1', 'message draft')

// Act
chatExtrasStore.restoreChatInput('token-1')

// Assert
expect(chatExtrasStore.getChatInput('token-1')).toStrictEqual('message draft')

// Arrange 2 - no chat input in the browser storage
chatExtrasStore.removeChatInput('token-1')
// Act
chatExtrasStore.restoreChatInput('token-1')
// Assert
expect(chatExtrasStore.getChatInput('token-1')).toBe('')
})
})

Expand Down
32 changes: 28 additions & 4 deletions src/stores/chatExtras.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import { defineStore } from 'pinia'
import Vue from 'vue'

import BrowserStorage from '../services/BrowserStorage.js'
import { EventBus } from '../services/EventBus.js'
import { getUserAbsence } from '../services/participantsService.js'
import { parseSpecialSymbols, parseMentions } from '../utils/textParse.js'
Expand Down Expand Up @@ -61,10 +62,6 @@ export const useChatExtrasStore = defineStore('chatExtras', {
}
},

getChatInput: (state) => (token) => {
return state.chatInput[token] ?? ''
},

getChatEditInput: (state) => (token) => {
return state.chatEditInput[token] ?? ''
},
Expand All @@ -75,6 +72,19 @@ export const useChatExtrasStore = defineStore('chatExtras', {
},

actions: {
/**
* Fetch an absence status for user and save to store
*
* @param {string} token The conversation token
* @return {string} The input text
*/
getChatInput(token) {
if (!this.chatInput[token]) {
this.restoreChatInput(token)
}
return this.chatInput[token] ?? ''
},

/**
* Fetch an absence status for user and save to store
*
Expand Down Expand Up @@ -130,6 +140,18 @@ export const useChatExtrasStore = defineStore('chatExtras', {
Vue.delete(this.parentToReply, token)
},

/**
* Restore chat input from the browser storage and save to store
*
* @param {string} token The conversation token
*/
restoreChatInput(token) {
const chatInput = BrowserStorage.getItem('chatInput_' + token)
if (chatInput) {
Vue.set(this.chatInput, token, chatInput)
}
},

/**
* Add a current input value to the store for a given conversation token
*
Expand All @@ -139,6 +161,7 @@ export const useChatExtrasStore = defineStore('chatExtras', {
*/
setChatInput({ token, text }) {
const parsedText = parseSpecialSymbols(text)
BrowserStorage.setItem('chatInput_' + token, parsedText)
Vue.set(this.chatInput, token, parsedText)
},

Expand Down Expand Up @@ -186,6 +209,7 @@ export const useChatExtrasStore = defineStore('chatExtras', {
* @param {string} token The conversation token
*/
removeChatInput(token) {
BrowserStorage.removeItem('chatInput_' + token)
Vue.delete(this.chatInput, token)
},

Expand Down

0 comments on commit 4c0e6f6

Please sign in to comment.