feat: Updates widget message state to support multiple conversations
This commit is contained in:
@@ -1,60 +0,0 @@
|
|||||||
import MessageAPI from '../../api/message';
|
|
||||||
import { refreshActionCableConnector } from '../../helpers/actionCable';
|
|
||||||
|
|
||||||
const state = {
|
|
||||||
uiFlags: {
|
|
||||||
isUpdating: false,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getters = {
|
|
||||||
getUIFlags: $state => $state.uiFlags,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const actions = {
|
|
||||||
update: async (
|
|
||||||
{ commit, dispatch },
|
|
||||||
{ email, messageId, submittedValues }
|
|
||||||
) => {
|
|
||||||
commit('toggleUpdateStatus', true);
|
|
||||||
try {
|
|
||||||
const {
|
|
||||||
data: { contact: { pubsub_token: pubsubToken } = {} },
|
|
||||||
} = await MessageAPI.update({
|
|
||||||
email,
|
|
||||||
messageId,
|
|
||||||
values: submittedValues,
|
|
||||||
});
|
|
||||||
commit(
|
|
||||||
'conversation/updateMessage',
|
|
||||||
{
|
|
||||||
id: messageId,
|
|
||||||
content_attributes: {
|
|
||||||
submitted_email: email,
|
|
||||||
submitted_values: email ? null : submittedValues,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{ root: true }
|
|
||||||
);
|
|
||||||
dispatch('contacts/get', {}, { root: true });
|
|
||||||
refreshActionCableConnector(pubsubToken);
|
|
||||||
} catch (error) {
|
|
||||||
// Ignore error
|
|
||||||
}
|
|
||||||
commit('toggleUpdateStatus', false);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const mutations = {
|
|
||||||
toggleUpdateStatus($state, status) {
|
|
||||||
$state.uiFlags.isUpdating = status;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
namespaced: true,
|
|
||||||
state,
|
|
||||||
getters,
|
|
||||||
actions,
|
|
||||||
mutations,
|
|
||||||
};
|
|
||||||
157
app/javascript/widget/store/modules/message/actions.js
Normal file
157
app/javascript/widget/store/modules/message/actions.js
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
import MessagePublicAPI from 'widget/api/messagePublic';
|
||||||
|
import { refreshActionCableConnector } from 'widget/helpers/actionCable';
|
||||||
|
import {
|
||||||
|
createTemporaryMessage,
|
||||||
|
createTemporaryAttachmentMessage,
|
||||||
|
createAttachmentParams,
|
||||||
|
} from './helpers';
|
||||||
|
|
||||||
|
export const actions = {
|
||||||
|
addOrUpdate: async ({ commit, getters }, message) => {
|
||||||
|
const {
|
||||||
|
conversation_id: conversationId,
|
||||||
|
id: messageId,
|
||||||
|
echo_id: echoId,
|
||||||
|
} = message;
|
||||||
|
|
||||||
|
const messageIdInStore = echoId || messageId;
|
||||||
|
const doesMessageExist = getters.messageById(messageIdInStore);
|
||||||
|
|
||||||
|
if (doesMessageExist) {
|
||||||
|
commit(
|
||||||
|
'conversationV2/removeMessageIdFromConversation',
|
||||||
|
{ conversationId, messageId: echoId },
|
||||||
|
{ root: true }
|
||||||
|
);
|
||||||
|
commit('removeMessageEntry', echoId);
|
||||||
|
commit('removeMessageId', echoId);
|
||||||
|
}
|
||||||
|
const messages = [message];
|
||||||
|
commit('addMessagesEntry', { conversationId, messages });
|
||||||
|
commit('addMessageIds', { messages });
|
||||||
|
commit(
|
||||||
|
'conversationV2/appendMessageIdsToConversation',
|
||||||
|
{ conversationId, messages },
|
||||||
|
{ root: true }
|
||||||
|
);
|
||||||
|
},
|
||||||
|
sendMessage: async ({ commit, dispatch }, params) => {
|
||||||
|
const { content, conversationId } = params;
|
||||||
|
try {
|
||||||
|
commit(
|
||||||
|
'conversationV2/setConversationUIFlag',
|
||||||
|
{ uiFlags: { isCreating: true }, conversationId },
|
||||||
|
{ root: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
const message = createTemporaryMessage({ content });
|
||||||
|
const { id: echoId } = message;
|
||||||
|
const messages = [message];
|
||||||
|
commit('addMessagesEntry', { messages });
|
||||||
|
commit('addMessageIds', { messages });
|
||||||
|
commit(
|
||||||
|
'conversationV2/appendMessageIdsToConversation',
|
||||||
|
{ conversationId, messages },
|
||||||
|
{ root: true }
|
||||||
|
);
|
||||||
|
const { data: newMessage } = await MessagePublicAPI.create(
|
||||||
|
conversationId,
|
||||||
|
content,
|
||||||
|
echoId
|
||||||
|
);
|
||||||
|
|
||||||
|
dispatch('addOrUpdate', {
|
||||||
|
...newMessage,
|
||||||
|
echo_id: echoId,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error(error);
|
||||||
|
} finally {
|
||||||
|
commit(
|
||||||
|
'conversationV2/setConversationUIFlag',
|
||||||
|
{ uiFlags: { isCreating: false }, conversationId },
|
||||||
|
{ root: true }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
sendAttachment: async ({ commit, dispatch }, params) => {
|
||||||
|
const {
|
||||||
|
attachment: { thumbUrl, fileType },
|
||||||
|
conversationId,
|
||||||
|
} = params;
|
||||||
|
try {
|
||||||
|
commit(
|
||||||
|
'conversationV2/setConversationUIFlag',
|
||||||
|
{ uiFlags: { isCreating: true }, conversationId },
|
||||||
|
{ root: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
const tempMessage = createTemporaryAttachmentMessage({
|
||||||
|
thumbUrl,
|
||||||
|
fileType,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { id: echoId } = tempMessage;
|
||||||
|
const messages = [tempMessage];
|
||||||
|
const attachmentParams = createAttachmentParams(params);
|
||||||
|
|
||||||
|
commit('addMessagesEntry', { conversationId, messages });
|
||||||
|
commit('addMessageIds', { conversationId, messages });
|
||||||
|
commit(
|
||||||
|
'conversationV2/appendMessageIdsToConversation',
|
||||||
|
{ conversationId, messages },
|
||||||
|
{ root: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
const { data } = await MessagePublicAPI.createAttachment(
|
||||||
|
conversationId,
|
||||||
|
attachmentParams
|
||||||
|
);
|
||||||
|
dispatch('addOrUpdate', { ...data, echo_id: echoId });
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error(error);
|
||||||
|
} finally {
|
||||||
|
commit(
|
||||||
|
'conversationV2/setConversationUIFlag',
|
||||||
|
{ uiFlags: { isCreating: false }, conversationId },
|
||||||
|
{ root: true }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
updateMessage: async (
|
||||||
|
{ commit, dispatch },
|
||||||
|
{ email, messageId, submittedValues }
|
||||||
|
) => {
|
||||||
|
try {
|
||||||
|
commit('setMessageUIFlag', {
|
||||||
|
messageId,
|
||||||
|
uiFlags: { isUpdating: true },
|
||||||
|
});
|
||||||
|
const {
|
||||||
|
data: { contact: { pubsub_token: pubsubToken } = {} },
|
||||||
|
} = await MessagePublicAPI.update({
|
||||||
|
email,
|
||||||
|
messageId,
|
||||||
|
values: submittedValues,
|
||||||
|
});
|
||||||
|
commit('updateMessageEntry', {
|
||||||
|
id: messageId,
|
||||||
|
content_attributes: {
|
||||||
|
submitted_email: email,
|
||||||
|
submitted_values: email ? null : submittedValues,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
dispatch('contacts/get', {}, { root: true });
|
||||||
|
refreshActionCableConnector(pubsubToken);
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error(error);
|
||||||
|
} finally {
|
||||||
|
commit('setMessageUIFlag', {
|
||||||
|
messageId,
|
||||||
|
uiFlags: { isUpdating: false },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
7
app/javascript/widget/store/modules/message/getters.js
Normal file
7
app/javascript/widget/store/modules/message/getters.js
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export const getters = {
|
||||||
|
uIFlags: $state => $state.uiFlags,
|
||||||
|
messageById: _state => messageId => {
|
||||||
|
const message = _state.messages.byId[messageId];
|
||||||
|
return message;
|
||||||
|
},
|
||||||
|
};
|
||||||
44
app/javascript/widget/store/modules/message/helpers.js
Normal file
44
app/javascript/widget/store/modules/message/helpers.js
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import { MESSAGE_TYPE } from 'widget/helpers/constants';
|
||||||
|
import getUuid from '../../../helpers/uuid';
|
||||||
|
|
||||||
|
export const createTemporaryMessage = ({ attachments, content }) => {
|
||||||
|
const timestamp = new Date().getTime() / 1000;
|
||||||
|
return {
|
||||||
|
id: getUuid(),
|
||||||
|
content,
|
||||||
|
attachments,
|
||||||
|
status: 'in_progress',
|
||||||
|
created_at: timestamp,
|
||||||
|
message_type: MESSAGE_TYPE.INCOMING,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const createTemporaryAttachmentMessage = ({
|
||||||
|
thumbUrl,
|
||||||
|
fileType,
|
||||||
|
content,
|
||||||
|
}) => {
|
||||||
|
const attachment = {
|
||||||
|
thumb_url: thumbUrl,
|
||||||
|
data_url: thumbUrl,
|
||||||
|
file_type: fileType,
|
||||||
|
status: 'in_progress',
|
||||||
|
};
|
||||||
|
const message = createTemporaryMessage({
|
||||||
|
attachments: [attachment],
|
||||||
|
content,
|
||||||
|
});
|
||||||
|
return message;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const createAttachmentParams = ({ attachment }) => {
|
||||||
|
const { referrerURL = '' } = window;
|
||||||
|
const timestamp = new Date().toString();
|
||||||
|
const { file } = attachment;
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('message[attachments][]', file, file.name);
|
||||||
|
formData.append('message[referer_url]', referrerURL);
|
||||||
|
formData.append('message[timestamp]', timestamp);
|
||||||
|
return formData;
|
||||||
|
};
|
||||||
23
app/javascript/widget/store/modules/message/index.js
Normal file
23
app/javascript/widget/store/modules/message/index.js
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import { getters } from './getters';
|
||||||
|
import { actions } from './actions';
|
||||||
|
import { mutations } from './mutations';
|
||||||
|
|
||||||
|
const state = {
|
||||||
|
messages: {
|
||||||
|
byId: {},
|
||||||
|
allIds: [],
|
||||||
|
uiFlags: {
|
||||||
|
byId: {
|
||||||
|
// 1: { isCreating: false, isPending: false, isDeleting: false, isUpdating: false },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default {
|
||||||
|
namespaced: true,
|
||||||
|
state,
|
||||||
|
getters,
|
||||||
|
actions,
|
||||||
|
mutations,
|
||||||
|
};
|
||||||
51
app/javascript/widget/store/modules/message/mutations.js
Normal file
51
app/javascript/widget/store/modules/message/mutations.js
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
import Vue from 'vue';
|
||||||
|
|
||||||
|
export const mutations = {
|
||||||
|
addMessagesEntry($state, { messages = [] }) {
|
||||||
|
messages.forEach(message => {
|
||||||
|
Vue.set($state.messages.byId, message.id, message);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
addMessageIds($state, { messages }) {
|
||||||
|
const messageIds = messages.map(message => message.id);
|
||||||
|
const allIds = $state.messages.allIds;
|
||||||
|
const newIds = [allIds, messageIds];
|
||||||
|
const uniqIds = Array.from(new Set(newIds));
|
||||||
|
|
||||||
|
Vue.set($state.messages, 'allIds', uniqIds);
|
||||||
|
},
|
||||||
|
|
||||||
|
updateMessageEntry($state, message) {
|
||||||
|
const messageId = message.id;
|
||||||
|
if (!messageId) return;
|
||||||
|
|
||||||
|
const messageById = $state.messages.byId[messageId];
|
||||||
|
if (!messageById) return;
|
||||||
|
if (messageId !== message.id) return;
|
||||||
|
|
||||||
|
Vue.set($state.messages.byId, messageId, { ...message });
|
||||||
|
},
|
||||||
|
|
||||||
|
removeMessageEntry($state, messageId) {
|
||||||
|
if (!messageId) return;
|
||||||
|
|
||||||
|
Vue.delete($state.messages.byId, messageId);
|
||||||
|
},
|
||||||
|
|
||||||
|
removeMessageId($state, messageId) {
|
||||||
|
if (!messageId) return;
|
||||||
|
|
||||||
|
$state.messages.allIds = $state.messages.allIds.filter(
|
||||||
|
id => id !== messageId
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
setMessageUIFlag($state, { messageId, uiFlags }) {
|
||||||
|
const flags = $state.messages.uiFlags.byId[messageId];
|
||||||
|
$state.messages.uiFlags.byId[messageId] = {
|
||||||
|
...flags,
|
||||||
|
...uiFlags,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user