@seamly/web-ui 20.8.0-beta.1 → 20.8.0-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/dist/lib/index.debug.js +5 -5
- package/build/dist/lib/index.debug.min.js +1 -1
- package/build/dist/lib/index.js +25 -24
- package/build/dist/lib/index.min.js +1 -1
- package/build/dist/lib/standalone.js +27 -28
- package/build/dist/lib/standalone.min.js +1 -1
- package/build/dist/lib/style-guide.js +11 -17
- package/build/dist/lib/style-guide.min.js +1 -1
- package/package.json +1 -1
- package/src/javascripts/domains/app/actions.ts +45 -41
- package/src/javascripts/domains/store/slice.ts +7 -2
- package/src/javascripts/domains/translations/slice.ts +0 -6
- package/src/javascripts/ui/hooks/use-seamly-chat.js +13 -6
|
@@ -201,7 +201,7 @@ eval("\n\nObject.defineProperty(exports, \"__esModule\", ({\n value: true\n}));
|
|
|
201
201
|
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
|
|
202
202
|
|
|
203
203
|
"use strict";
|
|
204
|
-
eval("\n\nvar __awaiter = this && this.__awaiter || function (thisArg, _arguments, P, generator) {\n function adopt(value) {\n return value instanceof P ? value : new P(function (resolve) {\n resolve(value);\n });\n }\n\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) {\n try {\n step(generator.next(value));\n } catch (e) {\n reject(e);\n }\n }\n\n function rejected(value) {\n try {\n step(generator[\"throw\"](value));\n } catch (e) {\n reject(e);\n }\n }\n\n function step(result) {\n result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);\n }\n\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n};\n\nvar __importDefault = this && this.__importDefault || function (mod) {\n return mod && mod.__esModule ? mod : {\n \"default\": mod\n };\n};\n\nObject.defineProperty(exports, \"__esModule\", ({\n value: true\n}));\nexports.resetApp = exports.initializeApp = void 0;\n\nconst toolkit_1 = __webpack_require__(/*! @reduxjs/toolkit */ \"./node_modules/@reduxjs/toolkit/dist/redux-toolkit.esm.js\");\n\nconst seamly_session_expired_error_1 = __importDefault(__webpack_require__(/*! api/errors/seamly-session-expired-error */ \"./src/javascripts/api/errors/seamly-session-expired-error.js\"));\n\nconst seamly_unavailable_error_1 = __importDefault(__webpack_require__(/*! api/errors/seamly-unavailable-error */ \"./src/javascripts/api/errors/seamly-unavailable-error.js\"));\n\nconst actions_1 = __webpack_require__(/*! domains/config/actions */ \"./src/javascripts/domains/config/actions.ts\");\n\nconst actions_2 = __webpack_require__(/*! domains/visibility/actions */ \"./src/javascripts/domains/visibility/actions.ts\");\n\nconst seamly_utils_1 = __webpack_require__(/*! ui/utils/seamly-utils */ \"./src/javascripts/ui/utils/seamly-utils.ts\");\n\nexports.initializeApp = (0, toolkit_1.createAsyncThunk)('initializeApp', (_, {\n extra: {\n api,\n config\n },\n rejectWithValue\n}) => __awaiter(void 0, void 0, void 0, function* () {\n var _a, _b, _c, _d;\n\n let locale = (_a = config === null || config === void 0 ? void 0 : config.context) === null || _a === void 0 ? void 0 : _a.locale;\n\n try {\n if (api.hasConversation()) {\n const initialState = yield api.getConversationIntitialState();\n locale = ((_b = initialState.translation) === null || _b === void 0 ? void 0 : _b.locale) || locale;\n return {\n initialState,\n locale,\n config\n };\n } else {\n if ((_c = config === null || config === void 0 ? void 0 : config.context) === null || _c === void 0 ? void 0 : _c.topic) {\n api.send('action', {\n type: seamly_utils_1.actionTypes.setTopic,\n body: {\n name: config.context.topic,\n // Separate fallback message is not needed here. Only an attached service will use this, but none will\n // be attached before the conversation has started (meaning the fallback message will never be shown).\n fallbackMessage: config.context.topic\n }\n });\n }\n\n if ((_d = config === null || config === void 0 ? void 0 : config.context) === null || _d === void 0 ? void 0 : _d.translationLocale) {\n locale = config.context.translationLocale;\n api.send('action', {\n type: seamly_utils_1.actionTypes.setTranslation,\n body: {\n enabled: true,\n locale\n }\n });\n }\n\n return {\n initialState: undefined,\n locale,\n config\n };\n }\n } catch (e) {\n if (e instanceof seamly_session_expired_error_1.default) {\n const err = new seamly_session_expired_error_1.default();\n return rejectWithValue({\n name: err.name,\n message: err.message,\n originalEvent: err.originalEvent,\n originalError: err.originalError,\n action: err.action\n });\n }\n\n const err = new seamly_unavailable_error_1.default();\n return rejectWithValue({\n name: err.name,\n message: err.message,\n langKey: err.langKey\n });\n }\n}));\nexports.resetApp = (0, toolkit_1.createAsyncThunk)('resetApp', (_, {\n dispatch,\n extra: {\n api\n }\n}) => __awaiter(void 0, void 0, void 0, function* () {\n yield api.disconnect();\n yield api.clearStore();\n dispatch((0, actions_1.resetConfig)());\n yield dispatch((0, actions_1.initializeConfig)());\n yield dispatch((0, exports.initializeApp)());\n dispatch((0,
|
|
204
|
+
eval("\n\nvar __awaiter = this && this.__awaiter || function (thisArg, _arguments, P, generator) {\n function adopt(value) {\n return value instanceof P ? value : new P(function (resolve) {\n resolve(value);\n });\n }\n\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) {\n try {\n step(generator.next(value));\n } catch (e) {\n reject(e);\n }\n }\n\n function rejected(value) {\n try {\n step(generator[\"throw\"](value));\n } catch (e) {\n reject(e);\n }\n }\n\n function step(result) {\n result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);\n }\n\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n};\n\nvar __importDefault = this && this.__importDefault || function (mod) {\n return mod && mod.__esModule ? mod : {\n \"default\": mod\n };\n};\n\nObject.defineProperty(exports, \"__esModule\", ({\n value: true\n}));\nexports.resetApp = exports.initializeApp = void 0;\n\nconst toolkit_1 = __webpack_require__(/*! @reduxjs/toolkit */ \"./node_modules/@reduxjs/toolkit/dist/redux-toolkit.esm.js\");\n\nconst seamly_session_expired_error_1 = __importDefault(__webpack_require__(/*! api/errors/seamly-session-expired-error */ \"./src/javascripts/api/errors/seamly-session-expired-error.js\"));\n\nconst seamly_unavailable_error_1 = __importDefault(__webpack_require__(/*! api/errors/seamly-unavailable-error */ \"./src/javascripts/api/errors/seamly-unavailable-error.js\"));\n\nconst actions_1 = __webpack_require__(/*! domains/config/actions */ \"./src/javascripts/domains/config/actions.ts\");\n\nconst actions_2 = __webpack_require__(/*! domains/i18n/actions */ \"./src/javascripts/domains/i18n/actions.ts\");\n\nconst actions_3 = __webpack_require__(/*! domains/visibility/actions */ \"./src/javascripts/domains/visibility/actions.ts\");\n\nconst seamly_utils_1 = __webpack_require__(/*! ui/utils/seamly-utils */ \"./src/javascripts/ui/utils/seamly-utils.ts\");\n\nexports.initializeApp = (0, toolkit_1.createAsyncThunk)('initializeApp', (_, {\n extra: {\n api,\n config\n },\n rejectWithValue,\n dispatch\n}) => __awaiter(void 0, void 0, void 0, function* () {\n var _a, _b, _c, _d;\n\n let locale = (_a = config === null || config === void 0 ? void 0 : config.context) === null || _a === void 0 ? void 0 : _a.locale;\n\n try {\n if (api.hasConversation()) {\n const initialState = yield api.getConversationIntitialState();\n locale = ((_b = initialState.translation) === null || _b === void 0 ? void 0 : _b.locale) || locale;\n return {\n initialState,\n locale,\n config\n };\n } else {\n if ((_c = config === null || config === void 0 ? void 0 : config.context) === null || _c === void 0 ? void 0 : _c.topic) {\n api.send('action', {\n type: seamly_utils_1.actionTypes.setTopic,\n body: {\n name: config.context.topic,\n // Separate fallback message is not needed here. Only an attached service will use this, but none will\n // be attached before the conversation has started (meaning the fallback message will never be shown).\n fallbackMessage: config.context.topic\n }\n });\n }\n\n if ((_d = config === null || config === void 0 ? void 0 : config.context) === null || _d === void 0 ? void 0 : _d.translationLocale) {\n locale = config.context.translationLocale;\n api.send('action', {\n type: seamly_utils_1.actionTypes.setTranslation,\n body: {\n enabled: true,\n locale\n }\n });\n }\n\n dispatch((0, actions_2.setLocale)(locale));\n return {\n initialState: undefined,\n locale,\n config\n };\n }\n } catch (e) {\n if (e instanceof seamly_session_expired_error_1.default) {\n const err = new seamly_session_expired_error_1.default();\n return rejectWithValue({\n name: err.name,\n message: err.message,\n originalEvent: err.originalEvent,\n originalError: err.originalError,\n action: err.action\n });\n }\n\n const err = new seamly_unavailable_error_1.default();\n return rejectWithValue({\n name: err.name,\n message: err.message,\n langKey: err.langKey\n });\n }\n}));\nexports.resetApp = (0, toolkit_1.createAsyncThunk)('resetApp', (_, {\n dispatch,\n extra: {\n api\n }\n}) => __awaiter(void 0, void 0, void 0, function* () {\n yield api.disconnect();\n yield api.clearStore();\n dispatch((0, actions_1.resetConfig)());\n yield dispatch((0, actions_1.initializeConfig)());\n yield dispatch((0, exports.initializeApp)());\n dispatch((0, actions_3.initializeVisibility)());\n}));\n\n//# sourceURL=webpack://@seamly/web-ui/./src/javascripts/domains/app/actions.ts?");
|
|
205
205
|
|
|
206
206
|
/***/ }),
|
|
207
207
|
|
|
@@ -432,7 +432,7 @@ eval("\n\nvar __importDefault = this && this.__importDefault || function (mod) {
|
|
|
432
432
|
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
|
|
433
433
|
|
|
434
434
|
"use strict";
|
|
435
|
-
eval("\n\nvar _a;\n\nObject.defineProperty(exports, \"__esModule\", ({\n value: true\n}));\nexports.stopIdleDetachCountdownCounter = exports.showOption = exports.setUserSelectedOptions = exports.setUserSelectedOption = exports.setUserEntryType = exports.setUploadProgress = exports.setUploadError = exports.setUploadComplete = exports.setServiceEntryMetadata = exports.setServiceDataItem = exports.setSeamlyContainerElement = exports.setParticipant = exports.setLoadedImageEventIds = exports.setIsLoading = exports.setInitialState = exports.setHistory = exports.setHeaderTitle = exports.setHeaderSubTitle = exports.setFeatures = exports.setFeatureEnabledState = exports.setEventsRead = exports.setBlockAutoEntrySwitch = exports.setActiveService = exports.setActiveEntryType = exports.resetHistoryLoadedFlag = exports.registerUpload = exports.initResumeConversationPrompt = exports.initIdleDetachCountdown = exports.hideOption = exports.decrementIdleDetachCountdownCounter = exports.clearResumeConversationPrompt = exports.clearIdleDetachCountdown = exports.clearFeatures = exports.clearEvents = exports.clearAllUploads = exports.addEvent = exports.ackEvent = exports.storeSlice = exports.initialStoreState = exports.mergeHistory = exports.orderHistory = exports.isUnreadMessage = void 0;\n\nconst toolkit_1 = __webpack_require__(/*! @reduxjs/toolkit */ \"./node_modules/@reduxjs/toolkit/dist/redux-toolkit.esm.js\");\n\nconst actions_1 = __webpack_require__(/*! domains/app/actions */ \"./src/javascripts/domains/app/actions.ts\");\n\nconst actions_2 = __webpack_require__(/*! domains/config/actions */ \"./src/javascripts/domains/config/actions.ts\");\n\nconst id_1 = __webpack_require__(/*! lib/id */ \"./src/javascripts/lib/id.js\");\n\nconst general_utils_1 = __webpack_require__(/*! ui/utils/general-utils */ \"./src/javascripts/ui/utils/general-utils.js\");\n\nconst seamly_utils_1 = __webpack_require__(/*! ui/utils/seamly-utils */ \"./src/javascripts/ui/utils/seamly-utils.ts\");\n\nconst isUnreadMessage = ({\n type,\n payload\n}) => type === seamly_utils_1.eventTypes.message && !payload.fromClient || type === seamly_utils_1.eventTypes.info && payload.type === seamly_utils_1.payloadTypes.text;\n\nexports.isUnreadMessage = isUnreadMessage;\n\nconst orderHistory = events => {\n return events.sort(({\n payload: {\n occurredAt: occurredAtA\n }\n }, {\n payload: {\n occurredAt: occurredAtB\n }\n }) => occurredAtA - occurredAtB);\n};\n\nexports.orderHistory = orderHistory;\n\nconst mergeHistory = (stateEvents, historyEvents) => {\n const newStateEvents = stateEvents.filter(stateEvent => // Deduplicate the event streams, giving events in historyEvents\n // precedence so the server is able to push changes to events.\n !historyEvents.some(historyEvent => historyEvent.payload.id === stateEvent.payload.id));\n const newHistoryEvents = historyEvents.filter(historyEvent => // Remove all non displayable participant messages\n !(historyEvent.type === 'participant' && !historyEvent.payload.participant.introduction)) // Reverse is done here because the server sends the history in the order\n // newest to oldest. In the case of exactly the same occurredAt timestamps\n // these messages will be shown in the wrong order if not reversed. For\n // the normal merging logic there is no added effect.\n .reverse();\n return (0, exports.orderHistory)([...newHistoryEvents, ...newStateEvents]);\n};\n\nexports.mergeHistory = mergeHistory;\n\nconst participantReducer = (participantInfo, action) => {\n // TODO: a) Styleguide only! b) Should be removed after styleguide overhaul.\n if (!participantInfo) {\n return {\n participants: {},\n currentAgent: ''\n };\n }\n\n const {\n participants\n } = participantInfo || {\n participants: {}\n };\n const {\n id,\n avatar,\n name,\n introduction\n } = action.participant;\n const oldParticipant = participants[id];\n const newParticipants = Object.assign(Object.assign({}, participants), {\n [id]: oldParticipant ? Object.assign(Object.assign(Object.assign(Object.assign({}, oldParticipant), avatar ? {\n avatar\n } : {}), name ? {\n name\n } : {}), introduction ? {\n introduction\n } : {}) : action.participant\n });\n return Object.assign(Object.assign({}, participantInfo), {\n participants: newParticipants,\n currentAgent: participantInfo.currentAgent !== id && !action.fromClient ? id : participantInfo.currentAgent\n });\n};\n\nconst calculateNewEntryMeta = (entryMeta, channelEvent) => {\n const entry = channelEvent.type === 'message' ? channelEvent === null || channelEvent === void 0 ? void 0 : channelEvent.payload.entry : {};\n const {\n blockAutoEntrySwitch\n } = entryMeta;\n\n if (!entry) {\n return Object.assign(Object.assign({}, entryMeta), {\n optionsOverride: {}\n });\n }\n\n const {\n type,\n options\n } = entry;\n let newActive = entryMeta.active;\n\n if (!blockAutoEntrySwitch && type !== entryMeta.userSelected) {\n newActive = type;\n }\n\n return Object.assign(Object.assign({}, entryMeta), {\n active: newActive,\n optionsOverride: Object.assign(Object.assign({}, entryMeta.optionsOverride), {\n [type]: options || {}\n })\n });\n};\n\nexports.initialStoreState = {\n events: [],\n initialState: {\n userResponded: false\n },\n unreadEvents: 0,\n userHasResponded: false,\n loadedImageEventIds: [],\n isLoading: false,\n idleDetachCountdown: {\n hasCountdown: false,\n isActive: false,\n remaining: undefined,\n wasStopped: undefined,\n count: undefined,\n timer: undefined\n },\n resumeConversationPrompt: false,\n serviceInfo: {\n activeServiceSessionId: ''\n },\n participantInfo: {\n participants: {},\n currentAgent: ''\n },\n headerTitles: {\n title: null,\n subTitle: ''\n },\n historyLoaded: false,\n skiplinkTargetId: (0, id_1.randomId)(),\n optionsButtonId: (0, id_1.randomId)(),\n headerCollapseButtonId: (0, id_1.randomId)(),\n serviceData: {},\n options: {\n features: {},\n panelActive: false,\n optionActive: '',\n userSelectedOptions: {}\n },\n showFileUpload: false,\n currentUploads: [],\n entryMeta: {\n default: seamly_utils_1.entryTypes.text,\n active: seamly_utils_1.entryTypes.text,\n userSelected: null,\n blockAutoEntrySwitch: false,\n options: {},\n optionsOverride: {}\n },\n seamlyContainerElement: null\n};\nexports.storeSlice = (0, toolkit_1.createSlice)({\n name: 'store',\n initialState: exports.initialStoreState,\n reducers: {\n addEvent: (state, action) => {\n var _a, _b;\n\n const {\n type: eventType,\n payload\n } = action.payload;\n const accountHasUploads = state.options.features.hasOwnProperty(seamly_utils_1.featureKeys.uploads);\n let newOptions = Object.assign({}, state.options); // This enabled override of the service enabled value for uploads.\n // If a message is sent with entry of type upload it will temporarily\n // override service value and enable uploads.\n\n if (accountHasUploads && (eventType === seamly_utils_1.eventTypes.message || eventType === seamly_utils_1.eventTypes.participant) && !payload.fromClient) {\n const entryType = eventType === 'message' ? (_a = payload.entry) === null || _a === void 0 ? void 0 : _a.type : {};\n newOptions = Object.assign(Object.assign({}, newOptions), {\n features: Object.assign(Object.assign({}, newOptions.features), {\n uploads: Object.assign(Object.assign({}, (_b = newOptions.features) === null || _b === void 0 ? void 0 : _b.uploads), {\n enabledFromEntry: entryType === seamly_utils_1.entryTypes.upload\n })\n })\n });\n }\n\n const incrementUnread = (0, exports.isUnreadMessage)(action.payload); // We check for duplicated and ignore them as in some error of the websocket\n // a duplicate join can be active for a while until the server connection\n // times out.\n\n const eventExists = state.events.find(e => e.payload.id === payload.id);\n\n if (eventExists) {\n return;\n }\n\n const newEntryMeta = calculateNewEntryMeta(state.entryMeta, action.payload);\n state.entryMeta = !accountHasUploads && newEntryMeta.active === seamly_utils_1.entryTypes.upload ? Object.assign({}, state.entryMeta) : newEntryMeta;\n state.options = newOptions;\n\n if (incrementUnread) {\n state.unreadEvents += 1;\n action.payload.payload.messageStatus = payload.fromClient ? seamly_utils_1.readStates.read : seamly_utils_1.readStates.received;\n }\n\n action.payload.payload.key = (0, id_1.randomId)();\n state.events.push(action.payload);\n },\n ackEvent: (state, {\n payload\n }) => {\n // If any ACKs are sent without transactionID the conversation crashes.\n // Ensure that this edge case is handled gracefully.\n if (!payload.transactionId) {\n console.warn('ACK received without transaction ID.');\n return;\n }\n\n const matchedEvent = state.events.find(m => m.payload.transactionId === payload.transactionId);\n const {\n id,\n occurredAt\n } = payload;\n\n if (matchedEvent) {\n state.events = (0, exports.orderHistory)( //@ts-ignore\n state.events.map(m => m.payload.id === matchedEvent.payload.id ? Object.assign(Object.assign({}, m), {\n payload: Object.assign(Object.assign({}, m.payload), {\n id,\n occurredAt\n })\n }) : m));\n }\n },\n clearEvents: state => {\n state.unreadEvents = 0;\n state.loadedImageEventIds = [];\n state.events = [];\n },\n setEventsRead: (state, {\n payload\n }) => {\n state.unreadEvents = 0;\n state.events.forEach(event => {\n if (payload.indexOf(event.payload.id) !== -1) {\n event.payload = Object.assign(Object.assign({}, event.payload), event.payload.messageStatus === seamly_utils_1.readStates.received && {\n messageStatus: seamly_utils_1.readStates.read\n });\n }\n\n return event;\n });\n },\n setLoadedImageEventIds: (state, {\n payload\n }) => {\n state.loadedImageEventIds.push(payload);\n },\n setHistory: (state, {\n payload: {\n events: history,\n participants,\n activeServiceSessionId,\n activeServiceSettings = {},\n serviceData,\n resumeConversationPrompt\n }\n }) => {\n var _a;\n\n const events = (0, exports.mergeHistory)(state.events, history);\n const mergedParticipants = Object.assign(Object.assign({}, state.participantInfo.participants), participants);\n const lastParticipantEvent = events.slice().reverse().find(m => (m.type === 'message' || m.type === 'participant') && !m.payload.fromClient);\n let lastParticipantId = null;\n\n if (lastParticipantEvent) {\n if (lastParticipantEvent.type === 'message') {\n lastParticipantId = lastParticipantEvent.payload.participant;\n }\n\n if (lastParticipantEvent.type === 'participant') {\n lastParticipantId = lastParticipantEvent.payload.participant.id;\n }\n }\n\n const {\n entry\n } = activeServiceSettings;\n const {\n upload\n } = entry.options;\n const historyNewEntryMeta = calculateNewEntryMeta(Object.assign(Object.assign(Object.assign({}, state.entryMeta), entry), {\n active: entry.default || seamly_utils_1.payloadTypes.text,\n options: Object.assign({}, entry && entry.options ? entry.options : {})\n }), events[events.length - 1]);\n let newFeatures = Object.assign({}, state.options.features);\n const newFeaturesHasUpload = newFeatures.hasOwnProperty(seamly_utils_1.featureKeys.uploads); // Only set uploads if it was initialised by the account config.\n\n if (newFeaturesHasUpload && lastParticipantEvent.type === 'message') {\n const {\n payload: lastParticipantEventPayload\n } = lastParticipantEvent;\n const entryType = ((_a = lastParticipantEventPayload === null || lastParticipantEventPayload === void 0 ? void 0 : lastParticipantEventPayload.entry) === null || _a === void 0 ? void 0 : _a.type) || {};\n newFeatures = Object.assign(Object.assign({}, newFeatures), {\n uploads: {\n enabled: !!(upload && upload.enabled),\n enabledFromEntry: entryType === seamly_utils_1.entryTypes.upload\n }\n });\n }\n\n state.unreadEvents = events.filter(event => event.type === 'message' && event.payload.messageStatus === seamly_utils_1.readStates.received).length;\n state.events = events.filter(e => e.type !== 'participant' || !!e.payload.participant.introduction);\n state.participantInfo = Object.assign(Object.assign(Object.assign({}, state.participantInfo), lastParticipantId ? participantReducer(state.participantInfo, {\n participant: mergedParticipants[lastParticipantId]\n }) : {}), {\n participants: mergedParticipants\n });\n state.historyLoaded = true;\n state.serviceInfo = Object.assign(Object.assign({}, state.serviceInfo), {\n activeServiceSessionId\n });\n state.serviceData = serviceData || {};\n state.options = Object.assign(Object.assign({}, state.options), {\n features: newFeatures || {}\n });\n state.entryMeta = !newFeaturesHasUpload && historyNewEntryMeta.active === seamly_utils_1.entryTypes.upload ? Object.assign({}, state.entryMeta) : historyNewEntryMeta;\n state.resumeConversationPrompt = resumeConversationPrompt || false;\n\n if (lastParticipantId) {\n state.headerTitles.subTitle = mergedParticipants[lastParticipantId].name;\n }\n },\n resetHistoryLoadedFlag: state => {\n state.historyLoaded = false;\n },\n setIsLoading: (state, {\n payload\n }) => {\n state.isLoading = payload;\n },\n initIdleDetachCountdown: (state, {\n payload\n }) => {\n const {\n delaySeconds,\n delayTime\n } = payload;\n state.idleDetachCountdown = {\n hasCountdown: true,\n isActive: true,\n wasStopped: false,\n count: delaySeconds,\n remaining: delaySeconds,\n timer: delayTime\n };\n },\n decrementIdleDetachCountdownCounter: state => {\n const {\n idleDetachCountdown\n } = state;\n const {\n remaining: prevRemaining\n } = idleDetachCountdown;\n const remaining = prevRemaining - 1;\n state.idleDetachCountdown.remaining = remaining;\n state.idleDetachCountdown.timer = (0, general_utils_1.getTimeFromSeconds)(remaining);\n },\n stopIdleDetachCountdownCounter: state => {\n state.idleDetachCountdown.isActive = false;\n state.idleDetachCountdown.wasStopped = true;\n },\n clearIdleDetachCountdown: state => {\n state.idleDetachCountdown.hasCountdown = false;\n state.idleDetachCountdown.isActive = false;\n },\n initResumeConversationPrompt: state => {\n state.resumeConversationPrompt = true;\n },\n clearResumeConversationPrompt: state => {\n state.resumeConversationPrompt = false;\n },\n setParticipant: (state, {\n payload\n }) => {\n state.participantInfo = participantReducer(state.participantInfo, {\n participant: payload.participant,\n fromClient: payload.fromClient\n });\n },\n setActiveService: (state, {\n payload\n }) => {\n if (state.serviceInfo.activeServiceSessionId !== payload) {\n state.serviceInfo.activeServiceSessionId = payload;\n }\n },\n setHeaderTitle: (state, {\n payload\n }) => {\n state.headerTitles.title = payload;\n },\n setHeaderSubTitle: (state, {\n payload\n }) => {\n state.headerTitles.subTitle = payload;\n },\n setInitialState: (state, {\n payload\n }) => {\n state.initialState = payload.initialState;\n state.unreadEvents = exports.initialStoreState.unreadEvents;\n },\n setServiceDataItem: (state, {\n payload\n }) => {\n state.serviceData[payload.type] = payload;\n },\n setFeatures: (state, {\n payload\n }) => {\n if (!payload.features) {\n return;\n }\n\n state.options.features = payload.features;\n },\n setFeatureEnabledState: (state, {\n payload\n }) => {\n if (!state.options.features.hasOwnProperty(payload.key)) {\n return;\n }\n\n state.options.features[payload.key].enabled = payload.enabled;\n },\n clearFeatures: state => {\n // case CLEAR_FEATURES:\n state.options.features = {};\n },\n showOption: (state, {\n payload\n }) => {\n state.options.panelActive = true;\n state.options.optionActive = payload;\n },\n hideOption: state => {\n // case HIDE_OPTION:\n state.options.panelActive = false;\n state.options.optionActive = '';\n },\n setUserSelectedOptions: (state, {\n payload\n }) => {\n state.options.userSelectedOptions = payload;\n },\n setUserSelectedOption: (state, {\n payload\n }) => {\n const {\n option,\n value\n } = payload;\n state.options.userSelectedOptions[option] = value;\n },\n setBlockAutoEntrySwitch: (state, {\n payload\n }) => {\n state.entryMeta.blockAutoEntrySwitch = payload;\n },\n setServiceEntryMetadata: (state, {\n payload\n }) => {\n state.entryMeta.active = payload.default;\n state.entryMeta.options = payload.options || {};\n state.entryMeta.optionsOverride = {};\n },\n setActiveEntryType: (state, {\n payload\n }) => {\n state.entryMeta.active = payload;\n },\n setUserEntryType: (state, {\n payload\n }) => {\n state.entryMeta.userSelected = payload;\n },\n registerUpload: (state, {\n payload\n }) => {\n state.currentUploads.push({\n id: payload.fileId,\n name: payload.fileName,\n progress: 1,\n uploading: true,\n complete: false,\n error: '',\n uploadHandle: payload.uploadHandle\n });\n },\n setUploadProgress: (state, {\n payload\n }) => {\n state.currentUploads = state.currentUploads.map(fileUpload => {\n if (fileUpload.id === payload.fileId) {\n return Object.assign(Object.assign({}, fileUpload), {\n progress: payload.progress,\n uploading: payload.progress !== 100,\n uploadHandle: payload.progress === 100 ? null : fileUpload.uploadHandle\n });\n }\n\n return fileUpload;\n });\n },\n setUploadError: (state, {\n payload\n }) => {\n state.currentUploads = state.currentUploads.map(fileUpload => {\n if (fileUpload.id === payload.fileId) {\n return Object.assign(Object.assign({}, fileUpload), {\n error: payload.errorText,\n progress: 0,\n uploading: false,\n uploadHandle: null\n });\n }\n\n return fileUpload;\n });\n },\n setUploadComplete: (state, {\n payload\n }) => {\n state.currentUploads = state.currentUploads.map(fileUpload => {\n if (fileUpload.id === payload) {\n return Object.assign(Object.assign({}, fileUpload), {\n complete: true\n });\n }\n\n return fileUpload;\n });\n },\n clearAllUploads: state => {\n state.currentUploads = [];\n },\n setSeamlyContainerElement: (state, {\n payload\n }) => {\n state.seamlyContainerElement = payload;\n }\n },\n extraReducers: builder => {\n builder.addCase(actions_1.resetApp.pending, () => exports.initialStoreState).addCase(actions_2.initializeConfig.fulfilled, (state, {\n payload\n }) => {\n var _a;\n\n state.headerTitles.subTitle = (_a = payload.agentParticipant) === null || _a === void 0 ? void 0 : _a.name;\n if (!payload.features) return;\n state.options.features = payload.features;\n }).addCase(actions_1.initializeApp.fulfilled, (state, {\n payload\n }) => {\n if (!payload.initialState) return;\n state.initialState = payload.initialState;\n });\n }\n});\n_a = exports.storeSlice.actions, exports.ackEvent = _a.ackEvent, exports.addEvent = _a.addEvent, exports.clearAllUploads = _a.clearAllUploads, exports.clearEvents = _a.clearEvents, exports.clearFeatures = _a.clearFeatures, exports.clearIdleDetachCountdown = _a.clearIdleDetachCountdown, exports.clearResumeConversationPrompt = _a.clearResumeConversationPrompt, exports.decrementIdleDetachCountdownCounter = _a.decrementIdleDetachCountdownCounter, exports.hideOption = _a.hideOption, exports.initIdleDetachCountdown = _a.initIdleDetachCountdown, exports.initResumeConversationPrompt = _a.initResumeConversationPrompt, exports.registerUpload = _a.registerUpload, exports.resetHistoryLoadedFlag = _a.resetHistoryLoadedFlag, exports.setActiveEntryType = _a.setActiveEntryType, exports.setActiveService = _a.setActiveService, exports.setBlockAutoEntrySwitch = _a.setBlockAutoEntrySwitch, exports.setEventsRead = _a.setEventsRead, exports.setFeatureEnabledState = _a.setFeatureEnabledState, exports.setFeatures = _a.setFeatures, exports.setHeaderSubTitle = _a.setHeaderSubTitle, exports.setHeaderTitle = _a.setHeaderTitle, exports.setHistory = _a.setHistory, exports.setInitialState = _a.setInitialState, exports.setIsLoading = _a.setIsLoading, exports.setLoadedImageEventIds = _a.setLoadedImageEventIds, exports.setParticipant = _a.setParticipant, exports.setSeamlyContainerElement = _a.setSeamlyContainerElement, exports.setServiceDataItem = _a.setServiceDataItem, exports.setServiceEntryMetadata = _a.setServiceEntryMetadata, exports.setUploadComplete = _a.setUploadComplete, exports.setUploadError = _a.setUploadError, exports.setUploadProgress = _a.setUploadProgress, exports.setUserEntryType = _a.setUserEntryType, exports.setUserSelectedOption = _a.setUserSelectedOption, exports.setUserSelectedOptions = _a.setUserSelectedOptions, exports.showOption = _a.showOption, exports.stopIdleDetachCountdownCounter = _a.stopIdleDetachCountdownCounter;\nexports[\"default\"] = exports.storeSlice.reducer;\n\n//# sourceURL=webpack://@seamly/web-ui/./src/javascripts/domains/store/slice.ts?");
|
|
435
|
+
eval("\n\nvar _a;\n\nObject.defineProperty(exports, \"__esModule\", ({\n value: true\n}));\nexports.stopIdleDetachCountdownCounter = exports.showOption = exports.setUserSelectedOptions = exports.setUserSelectedOption = exports.setUserEntryType = exports.setUploadProgress = exports.setUploadError = exports.setUploadComplete = exports.setServiceEntryMetadata = exports.setServiceDataItem = exports.setSeamlyContainerElement = exports.setParticipant = exports.setLoadedImageEventIds = exports.setIsLoading = exports.setInitialState = exports.setHistory = exports.setHeaderTitle = exports.setHeaderSubTitle = exports.setFeatures = exports.setFeatureEnabledState = exports.setEventsRead = exports.setBlockAutoEntrySwitch = exports.setActiveService = exports.setActiveEntryType = exports.resetHistoryLoadedFlag = exports.registerUpload = exports.initResumeConversationPrompt = exports.initIdleDetachCountdown = exports.hideOption = exports.decrementIdleDetachCountdownCounter = exports.clearResumeConversationPrompt = exports.clearIdleDetachCountdown = exports.clearFeatures = exports.clearEvents = exports.clearAllUploads = exports.addEvent = exports.ackEvent = exports.storeSlice = exports.initialStoreState = exports.mergeHistory = exports.orderHistory = exports.isUnreadMessage = void 0;\n\nconst toolkit_1 = __webpack_require__(/*! @reduxjs/toolkit */ \"./node_modules/@reduxjs/toolkit/dist/redux-toolkit.esm.js\");\n\nconst actions_1 = __webpack_require__(/*! domains/app/actions */ \"./src/javascripts/domains/app/actions.ts\");\n\nconst actions_2 = __webpack_require__(/*! domains/config/actions */ \"./src/javascripts/domains/config/actions.ts\");\n\nconst id_1 = __webpack_require__(/*! lib/id */ \"./src/javascripts/lib/id.js\");\n\nconst general_utils_1 = __webpack_require__(/*! ui/utils/general-utils */ \"./src/javascripts/ui/utils/general-utils.js\");\n\nconst seamly_utils_1 = __webpack_require__(/*! ui/utils/seamly-utils */ \"./src/javascripts/ui/utils/seamly-utils.ts\");\n\nconst isUnreadMessage = ({\n type,\n payload\n}) => type === seamly_utils_1.eventTypes.message && !payload.fromClient || type === seamly_utils_1.eventTypes.info && payload.type === seamly_utils_1.payloadTypes.text;\n\nexports.isUnreadMessage = isUnreadMessage;\n\nconst orderHistory = events => {\n return events.sort(({\n payload: {\n occurredAt: occurredAtA\n }\n }, {\n payload: {\n occurredAt: occurredAtB\n }\n }) => occurredAtA - occurredAtB);\n};\n\nexports.orderHistory = orderHistory;\n\nconst mergeHistory = (stateEvents, historyEvents) => {\n const newStateEvents = stateEvents.filter(stateEvent => // Deduplicate the event streams, giving events in historyEvents\n // precedence so the server is able to push changes to events.\n !historyEvents.some(historyEvent => historyEvent.payload.id === stateEvent.payload.id));\n const newHistoryEvents = historyEvents.filter(historyEvent => // Remove all non displayable participant messages\n !(historyEvent.type === 'participant' && !historyEvent.payload.participant.introduction)) // Reverse is done here because the server sends the history in the order\n // newest to oldest. In the case of exactly the same occurredAt timestamps\n // these messages will be shown in the wrong order if not reversed. For\n // the normal merging logic there is no added effect.\n .reverse();\n return (0, exports.orderHistory)([...newHistoryEvents, ...newStateEvents]);\n};\n\nexports.mergeHistory = mergeHistory;\n\nconst participantReducer = (participantInfo, action) => {\n // TODO: a) Styleguide only! b) Should be removed after styleguide overhaul.\n if (!participantInfo) {\n return {\n participants: {},\n currentAgent: ''\n };\n }\n\n const {\n participants\n } = participantInfo || {\n participants: {}\n };\n const {\n id,\n avatar,\n name,\n introduction\n } = action.participant;\n const oldParticipant = participants[id];\n const newParticipants = Object.assign(Object.assign({}, participants), {\n [id]: oldParticipant ? Object.assign(Object.assign(Object.assign(Object.assign({}, oldParticipant), avatar ? {\n avatar\n } : {}), name ? {\n name\n } : {}), introduction ? {\n introduction\n } : {}) : action.participant\n });\n return Object.assign(Object.assign({}, participantInfo), {\n participants: newParticipants,\n currentAgent: participantInfo.currentAgent !== id && !action.fromClient ? id : participantInfo.currentAgent\n });\n};\n\nconst calculateNewEntryMeta = (entryMeta, channelEvent) => {\n const entry = channelEvent.type === 'message' ? channelEvent === null || channelEvent === void 0 ? void 0 : channelEvent.payload.entry : {};\n const {\n blockAutoEntrySwitch\n } = entryMeta;\n\n if (!entry) {\n return Object.assign(Object.assign({}, entryMeta), {\n optionsOverride: {}\n });\n }\n\n const {\n type,\n options\n } = entry;\n let newActive = entryMeta.active;\n\n if (!blockAutoEntrySwitch && type !== entryMeta.userSelected) {\n newActive = type;\n }\n\n return Object.assign(Object.assign({}, entryMeta), {\n active: newActive,\n optionsOverride: Object.assign(Object.assign({}, entryMeta.optionsOverride), {\n [type]: options || {}\n })\n });\n};\n\nexports.initialStoreState = {\n events: [],\n initialState: {\n userResponded: false\n },\n unreadEvents: 0,\n userHasResponded: false,\n loadedImageEventIds: [],\n isLoading: false,\n idleDetachCountdown: {\n hasCountdown: false,\n isActive: false,\n remaining: undefined,\n wasStopped: undefined,\n count: undefined,\n timer: undefined\n },\n resumeConversationPrompt: false,\n serviceInfo: {\n activeServiceSessionId: ''\n },\n participantInfo: {\n participants: {},\n currentAgent: ''\n },\n headerTitles: {\n title: null,\n subTitle: ''\n },\n historyLoaded: false,\n skiplinkTargetId: (0, id_1.randomId)(),\n optionsButtonId: (0, id_1.randomId)(),\n headerCollapseButtonId: (0, id_1.randomId)(),\n serviceData: {},\n options: {\n features: {},\n panelActive: false,\n optionActive: '',\n userSelectedOptions: {}\n },\n showFileUpload: false,\n currentUploads: [],\n entryMeta: {\n default: seamly_utils_1.entryTypes.text,\n active: seamly_utils_1.entryTypes.text,\n userSelected: null,\n blockAutoEntrySwitch: false,\n options: {},\n optionsOverride: {}\n },\n seamlyContainerElement: null\n};\nexports.storeSlice = (0, toolkit_1.createSlice)({\n name: 'store',\n initialState: exports.initialStoreState,\n reducers: {\n addEvent: (state, action) => {\n var _a, _b;\n\n const {\n type: eventType,\n payload\n } = action.payload;\n const accountHasUploads = state.options.features.hasOwnProperty(seamly_utils_1.featureKeys.uploads);\n let newOptions = Object.assign({}, state.options); // This enabled override of the service enabled value for uploads.\n // If a message is sent with entry of type upload it will temporarily\n // override service value and enable uploads.\n\n if (accountHasUploads && (eventType === seamly_utils_1.eventTypes.message || eventType === seamly_utils_1.eventTypes.participant) && !payload.fromClient) {\n const entryType = eventType === 'message' ? (_a = payload.entry) === null || _a === void 0 ? void 0 : _a.type : {};\n newOptions = Object.assign(Object.assign({}, newOptions), {\n features: Object.assign(Object.assign({}, newOptions.features), {\n uploads: Object.assign(Object.assign({}, (_b = newOptions.features) === null || _b === void 0 ? void 0 : _b.uploads), {\n enabledFromEntry: entryType === seamly_utils_1.entryTypes.upload\n })\n })\n });\n }\n\n const incrementUnread = (0, exports.isUnreadMessage)(action.payload); // We check for duplicated and ignore them as in some error of the websocket\n // a duplicate join can be active for a while until the server connection\n // times out.\n\n const eventExists = state.events.find(e => e.payload.id === payload.id);\n\n if (eventExists) {\n return;\n }\n\n const newEntryMeta = calculateNewEntryMeta(state.entryMeta, action.payload);\n state.entryMeta = !accountHasUploads && newEntryMeta.active === seamly_utils_1.entryTypes.upload ? Object.assign({}, state.entryMeta) : newEntryMeta;\n state.options = newOptions;\n\n if (incrementUnread) {\n state.unreadEvents += 1;\n action.payload.payload.messageStatus = payload.fromClient ? seamly_utils_1.readStates.read : seamly_utils_1.readStates.received;\n }\n\n action.payload.payload.key = (0, id_1.randomId)();\n state.events.push(action.payload);\n },\n ackEvent: (state, {\n payload\n }) => {\n // If any ACKs are sent without transactionID the conversation crashes.\n // Ensure that this edge case is handled gracefully.\n if (!payload.transactionId) {\n console.warn('ACK received without transaction ID.');\n return;\n }\n\n const matchedEvent = state.events.find(m => m.payload.transactionId === payload.transactionId);\n const {\n id,\n occurredAt\n } = payload;\n\n if (matchedEvent) {\n state.events = (0, exports.orderHistory)( //@ts-ignore\n state.events.map(m => m.payload.id === matchedEvent.payload.id ? Object.assign(Object.assign({}, m), {\n payload: Object.assign(Object.assign({}, m.payload), {\n id,\n occurredAt\n })\n }) : m));\n }\n },\n clearEvents: state => {\n state.unreadEvents = 0;\n state.loadedImageEventIds = [];\n state.events = [];\n },\n setEventsRead: (state, {\n payload\n }) => {\n state.unreadEvents = 0;\n state.events.forEach(event => {\n if (payload.indexOf(event.payload.id) !== -1) {\n event.payload = Object.assign(Object.assign({}, event.payload), event.payload.messageStatus === seamly_utils_1.readStates.received && {\n messageStatus: seamly_utils_1.readStates.read\n });\n }\n\n return event;\n });\n },\n setLoadedImageEventIds: (state, {\n payload\n }) => {\n state.loadedImageEventIds.push(payload);\n },\n setHistory: (state, {\n payload: {\n events: history,\n participants,\n activeServiceSessionId,\n activeServiceSettings = {},\n serviceData,\n resumeConversationPrompt\n }\n }) => {\n var _a;\n\n const events = (0, exports.mergeHistory)(state.events, history);\n const mergedParticipants = Object.assign(Object.assign({}, state.participantInfo.participants), participants);\n const lastParticipantEvent = events.slice().reverse().find(m => (m.type === 'message' || m.type === 'participant') && !m.payload.fromClient);\n let lastParticipantId = null;\n\n if (lastParticipantEvent) {\n if (lastParticipantEvent.type === 'message') {\n lastParticipantId = lastParticipantEvent.payload.participant;\n }\n\n if (lastParticipantEvent.type === 'participant') {\n lastParticipantId = lastParticipantEvent.payload.participant.id;\n }\n }\n\n const {\n entry\n } = activeServiceSettings;\n const {\n upload\n } = entry.options;\n const historyNewEntryMeta = calculateNewEntryMeta(Object.assign(Object.assign(Object.assign({}, state.entryMeta), entry), {\n active: entry.default || seamly_utils_1.payloadTypes.text,\n options: Object.assign({}, entry && entry.options ? entry.options : {})\n }), events[events.length - 1]);\n let newFeatures = Object.assign({}, state.options.features);\n const newFeaturesHasUpload = newFeatures.hasOwnProperty(seamly_utils_1.featureKeys.uploads); // Only set uploads if it was initialised by the account config.\n\n if (newFeaturesHasUpload && (lastParticipantEvent === null || lastParticipantEvent === void 0 ? void 0 : lastParticipantEvent.type) === 'message') {\n const {\n payload: lastParticipantEventPayload\n } = lastParticipantEvent;\n const entryType = ((_a = lastParticipantEventPayload === null || lastParticipantEventPayload === void 0 ? void 0 : lastParticipantEventPayload.entry) === null || _a === void 0 ? void 0 : _a.type) || {};\n newFeatures = Object.assign(Object.assign({}, newFeatures), {\n uploads: {\n enabled: !!(upload && upload.enabled),\n enabledFromEntry: entryType === seamly_utils_1.entryTypes.upload\n }\n });\n }\n\n state.unreadEvents = events.filter(event => event.type === 'message' && event.payload.messageStatus === seamly_utils_1.readStates.received).length;\n state.events = events.filter(e => e.type !== 'participant' || !!e.payload.participant.introduction);\n state.participantInfo = Object.assign(Object.assign(Object.assign({}, state.participantInfo), lastParticipantId ? participantReducer(state.participantInfo, {\n participant: mergedParticipants[lastParticipantId]\n }) : {}), {\n participants: mergedParticipants\n });\n state.historyLoaded = true;\n state.serviceInfo = Object.assign(Object.assign({}, state.serviceInfo), {\n activeServiceSessionId\n });\n state.serviceData = Object.assign(Object.assign({}, state.serviceData), serviceData);\n state.options = Object.assign(Object.assign({}, state.options), {\n features: newFeatures || {}\n });\n state.entryMeta = !newFeaturesHasUpload && historyNewEntryMeta.active === seamly_utils_1.entryTypes.upload ? Object.assign({}, state.entryMeta) : historyNewEntryMeta;\n state.resumeConversationPrompt = resumeConversationPrompt || false;\n\n if (lastParticipantId) {\n state.headerTitles.subTitle = mergedParticipants[lastParticipantId].name;\n }\n },\n resetHistoryLoadedFlag: state => {\n state.historyLoaded = false;\n },\n setIsLoading: (state, {\n payload\n }) => {\n state.isLoading = payload;\n },\n initIdleDetachCountdown: (state, {\n payload\n }) => {\n const {\n delaySeconds,\n delayTime\n } = payload;\n state.idleDetachCountdown = {\n hasCountdown: true,\n isActive: true,\n wasStopped: false,\n count: delaySeconds,\n remaining: delaySeconds,\n timer: delayTime\n };\n },\n decrementIdleDetachCountdownCounter: state => {\n const {\n idleDetachCountdown\n } = state;\n const {\n remaining: prevRemaining\n } = idleDetachCountdown;\n const remaining = prevRemaining - 1;\n state.idleDetachCountdown.remaining = remaining;\n state.idleDetachCountdown.timer = (0, general_utils_1.getTimeFromSeconds)(remaining);\n },\n stopIdleDetachCountdownCounter: state => {\n state.idleDetachCountdown.isActive = false;\n state.idleDetachCountdown.wasStopped = true;\n },\n clearIdleDetachCountdown: state => {\n state.idleDetachCountdown.hasCountdown = false;\n state.idleDetachCountdown.isActive = false;\n },\n initResumeConversationPrompt: state => {\n state.resumeConversationPrompt = true;\n },\n clearResumeConversationPrompt: state => {\n state.resumeConversationPrompt = false;\n },\n setParticipant: (state, {\n payload\n }) => {\n state.participantInfo = participantReducer(state.participantInfo, {\n participant: payload.participant,\n fromClient: payload.fromClient\n });\n },\n setActiveService: (state, {\n payload\n }) => {\n if (state.serviceInfo.activeServiceSessionId !== payload) {\n state.serviceInfo.activeServiceSessionId = payload;\n }\n },\n setHeaderTitle: (state, {\n payload\n }) => {\n state.headerTitles.title = payload;\n },\n setHeaderSubTitle: (state, {\n payload\n }) => {\n state.headerTitles.subTitle = payload;\n },\n setInitialState: (state, {\n payload\n }) => {\n state.initialState = payload.initialState;\n state.unreadEvents = exports.initialStoreState.unreadEvents;\n },\n setServiceDataItem: (state, {\n payload\n }) => {\n state.serviceData[payload.type] = payload;\n },\n setFeatures: (state, {\n payload\n }) => {\n if (!payload.features) {\n return;\n }\n\n state.options.features = payload.features;\n },\n setFeatureEnabledState: (state, {\n payload\n }) => {\n if (!state.options.features.hasOwnProperty(payload.key)) {\n return;\n }\n\n state.options.features[payload.key].enabled = payload.enabled;\n },\n clearFeatures: state => {\n // case CLEAR_FEATURES:\n state.options.features = {};\n },\n showOption: (state, {\n payload\n }) => {\n state.options.panelActive = true;\n state.options.optionActive = payload;\n },\n hideOption: state => {\n // case HIDE_OPTION:\n state.options.panelActive = false;\n state.options.optionActive = '';\n },\n setUserSelectedOptions: (state, {\n payload\n }) => {\n state.options.userSelectedOptions = payload;\n },\n setUserSelectedOption: (state, {\n payload\n }) => {\n const {\n option,\n value\n } = payload;\n state.options.userSelectedOptions[option] = value;\n },\n setBlockAutoEntrySwitch: (state, {\n payload\n }) => {\n state.entryMeta.blockAutoEntrySwitch = payload;\n },\n setServiceEntryMetadata: (state, {\n payload\n }) => {\n state.entryMeta.active = payload.default;\n state.entryMeta.options = payload.options || {};\n state.entryMeta.optionsOverride = {};\n },\n setActiveEntryType: (state, {\n payload\n }) => {\n state.entryMeta.active = payload;\n },\n setUserEntryType: (state, {\n payload\n }) => {\n state.entryMeta.userSelected = payload;\n },\n registerUpload: (state, {\n payload\n }) => {\n state.currentUploads.push({\n id: payload.fileId,\n name: payload.fileName,\n progress: 1,\n uploading: true,\n complete: false,\n error: '',\n uploadHandle: payload.uploadHandle\n });\n },\n setUploadProgress: (state, {\n payload\n }) => {\n state.currentUploads = state.currentUploads.map(fileUpload => {\n if (fileUpload.id === payload.fileId) {\n return Object.assign(Object.assign({}, fileUpload), {\n progress: payload.progress,\n uploading: payload.progress !== 100,\n uploadHandle: payload.progress === 100 ? null : fileUpload.uploadHandle\n });\n }\n\n return fileUpload;\n });\n },\n setUploadError: (state, {\n payload\n }) => {\n state.currentUploads = state.currentUploads.map(fileUpload => {\n if (fileUpload.id === payload.fileId) {\n return Object.assign(Object.assign({}, fileUpload), {\n error: payload.errorText,\n progress: 0,\n uploading: false,\n uploadHandle: null\n });\n }\n\n return fileUpload;\n });\n },\n setUploadComplete: (state, {\n payload\n }) => {\n state.currentUploads = state.currentUploads.map(fileUpload => {\n if (fileUpload.id === payload) {\n return Object.assign(Object.assign({}, fileUpload), {\n complete: true\n });\n }\n\n return fileUpload;\n });\n },\n clearAllUploads: state => {\n state.currentUploads = [];\n },\n setSeamlyContainerElement: (state, {\n payload\n }) => {\n state.seamlyContainerElement = payload;\n }\n },\n extraReducers: builder => {\n builder.addCase(actions_1.resetApp.pending, () => exports.initialStoreState).addCase(actions_2.initializeConfig.fulfilled, (state, {\n payload\n }) => {\n var _a;\n\n state.headerTitles.subTitle = (_a = payload.agentParticipant) === null || _a === void 0 ? void 0 : _a.name;\n if (!payload.features) return;\n state.options.features = payload.features;\n }).addCase(actions_1.initializeApp.fulfilled, (state, {\n payload\n }) => {\n if (!payload.initialState) return;\n state.initialState = payload.initialState;\n });\n }\n});\n_a = exports.storeSlice.actions, exports.ackEvent = _a.ackEvent, exports.addEvent = _a.addEvent, exports.clearAllUploads = _a.clearAllUploads, exports.clearEvents = _a.clearEvents, exports.clearFeatures = _a.clearFeatures, exports.clearIdleDetachCountdown = _a.clearIdleDetachCountdown, exports.clearResumeConversationPrompt = _a.clearResumeConversationPrompt, exports.decrementIdleDetachCountdownCounter = _a.decrementIdleDetachCountdownCounter, exports.hideOption = _a.hideOption, exports.initIdleDetachCountdown = _a.initIdleDetachCountdown, exports.initResumeConversationPrompt = _a.initResumeConversationPrompt, exports.registerUpload = _a.registerUpload, exports.resetHistoryLoadedFlag = _a.resetHistoryLoadedFlag, exports.setActiveEntryType = _a.setActiveEntryType, exports.setActiveService = _a.setActiveService, exports.setBlockAutoEntrySwitch = _a.setBlockAutoEntrySwitch, exports.setEventsRead = _a.setEventsRead, exports.setFeatureEnabledState = _a.setFeatureEnabledState, exports.setFeatures = _a.setFeatures, exports.setHeaderSubTitle = _a.setHeaderSubTitle, exports.setHeaderTitle = _a.setHeaderTitle, exports.setHistory = _a.setHistory, exports.setInitialState = _a.setInitialState, exports.setIsLoading = _a.setIsLoading, exports.setLoadedImageEventIds = _a.setLoadedImageEventIds, exports.setParticipant = _a.setParticipant, exports.setSeamlyContainerElement = _a.setSeamlyContainerElement, exports.setServiceDataItem = _a.setServiceDataItem, exports.setServiceEntryMetadata = _a.setServiceEntryMetadata, exports.setUploadComplete = _a.setUploadComplete, exports.setUploadError = _a.setUploadError, exports.setUploadProgress = _a.setUploadProgress, exports.setUserEntryType = _a.setUserEntryType, exports.setUserSelectedOption = _a.setUserSelectedOption, exports.setUserSelectedOptions = _a.setUserSelectedOptions, exports.showOption = _a.showOption, exports.stopIdleDetachCountdownCounter = _a.stopIdleDetachCountdownCounter;\nexports[\"default\"] = exports.storeSlice.reducer;\n\n//# sourceURL=webpack://@seamly/web-ui/./src/javascripts/domains/store/slice.ts?");
|
|
436
436
|
|
|
437
437
|
/***/ }),
|
|
438
438
|
|
|
@@ -465,7 +465,7 @@ eval("\n\nObject.defineProperty(exports, \"__esModule\", ({\n value: true\n}));
|
|
|
465
465
|
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
|
|
466
466
|
|
|
467
467
|
"use strict";
|
|
468
|
-
eval("\n\nvar _a;\n\nObject.defineProperty(exports, \"__esModule\", ({\n value: true\n}));\nexports.disableEventsTranslation = exports.enableEventsTranslation = exports.disableTranslation = exports.enableTranslation = exports.translationSlice = exports.translationsInitialState = void 0;\n\nconst toolkit_1 = __webpack_require__(/*! @reduxjs/toolkit */ \"./node_modules/@reduxjs/toolkit/dist/redux-toolkit.esm.js\");\n\nconst actions_1 = __webpack_require__(/*! domains/
|
|
468
|
+
eval("\n\nvar _a;\n\nObject.defineProperty(exports, \"__esModule\", ({\n value: true\n}));\nexports.disableEventsTranslation = exports.enableEventsTranslation = exports.disableTranslation = exports.enableTranslation = exports.translationSlice = exports.translationsInitialState = void 0;\n\nconst toolkit_1 = __webpack_require__(/*! @reduxjs/toolkit */ \"./node_modules/@reduxjs/toolkit/dist/redux-toolkit.esm.js\");\n\nconst actions_1 = __webpack_require__(/*! domains/config/actions */ \"./src/javascripts/domains/config/actions.ts\");\n\nconst slice_1 = __webpack_require__(/*! domains/store/slice */ \"./src/javascripts/domains/store/slice.ts\");\n\nexports.translationsInitialState = {\n isActive: false,\n currentLocale: undefined,\n isAvailable: false,\n languages: [],\n containerId: (0, toolkit_1.nanoid)(),\n translatedEventGroups: {}\n};\n\nconst getLastGroupId = (events, id) => {\n const eventGroup = [...events].reduce((acc, {\n payload\n }, _index, arr) => {\n var _a;\n\n if (acc[id]) {\n // Splice to break early (make the reducer think we are done)\n // This is needed to avoid events of other groups from being added to the array.\n // @ts-ignore\n if ((payload === null || payload === void 0 ? void 0 : payload.type) === 'divider' && ((_a = payload === null || payload === void 0 ? void 0 : payload.body) === null || _a === void 0 ? void 0 : _a.translationEnabled)) {\n arr.splice(0);\n return acc;\n }\n\n acc[id].push(payload.id);\n }\n\n if (payload.id === id) acc[id] = [];\n return acc;\n }, {});\n const [[groupId, eventIds]] = Object.entries(eventGroup);\n const lastGroupId = events //@ts-ignore\n .filter(event => {\n var _a;\n\n return ((_a = event.payload) === null || _a === void 0 ? void 0 : _a.type) === 'divider';\n }).map(event => event.payload.id).at(-1);\n return {\n lastGroupId,\n groupId,\n eventIds\n };\n};\n\nexports.translationSlice = (0, toolkit_1.createSlice)({\n name: 'translation',\n initialState: exports.translationsInitialState,\n reducers: {\n enableTranslation: (state, {\n payload\n }) => {\n state.isActive = true;\n state.currentLocale = payload;\n },\n disableTranslation: state => {\n state.isActive = false;\n state.currentLocale = undefined;\n },\n enableEventsTranslation: (state, {\n payload: {\n events,\n id\n }\n }) => {\n delete state.translatedEventGroups[id];\n const {\n lastGroupId\n } = getLastGroupId(events, id);\n state.lastGroupId = lastGroupId;\n },\n disableEventsTranslation: (state, {\n payload: {\n events,\n id\n }\n }) => {\n const {\n lastGroupId,\n groupId,\n eventIds\n } = getLastGroupId(events, id);\n state.lastGroupId = lastGroupId;\n state.translatedEventGroups[groupId] = eventIds;\n }\n },\n extraReducers: builder => {\n builder.addCase(actions_1.initializeConfig.fulfilled, (state, {\n payload\n }) => {\n var _a;\n\n const feature = (_a = payload === null || payload === void 0 ? void 0 : payload.features) === null || _a === void 0 ? void 0 : _a.translation;\n if (!feature) return;\n state.isAvailable = feature.enabled === true;\n state.languages = feature.languages;\n }).addCase(slice_1.addEvent, (state, {\n payload\n }) => {\n if (state.translatedEventGroups[state.lastGroupId]) {\n state.translatedEventGroups[state.lastGroupId].push(payload.payload.id);\n }\n });\n }\n});\n_a = exports.translationSlice.actions, exports.enableTranslation = _a.enableTranslation, exports.disableTranslation = _a.disableTranslation, exports.enableEventsTranslation = _a.enableEventsTranslation, exports.disableEventsTranslation = _a.disableEventsTranslation;\nexports[\"default\"] = exports.translationSlice.reducer;\n\n//# sourceURL=webpack://@seamly/web-ui/./src/javascripts/domains/translations/slice.ts?");
|
|
469
469
|
|
|
470
470
|
/***/ }),
|
|
471
471
|
|
|
@@ -630,7 +630,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
|
|
|
630
630
|
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
631
631
|
|
|
632
632
|
"use strict";
|
|
633
|
-
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"API\": () => (/* binding */ API)\n/* harmony export */ });\n/* harmony import */ var xstream__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! xstream */ \"./node_modules/xstream/index.js\");\n/* harmony import */ var xstream__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(xstream__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var superagent__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! superagent */ \"./node_modules/superagent/lib/client.js\");\n/* harmony import */ var superagent__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(superagent__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var config__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! config */ \"./src/javascripts/config.ts\");\n/* harmony import */ var lib_store_index__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! lib/store/index */ \"./src/javascripts/lib/store/index.js\");\n/* harmony import */ var lib_id__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! lib/id */ \"./src/javascripts/lib/id.js\");\n/* harmony import */ var lib_store_providers_session_storage__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! lib/store/providers/session-storage */ \"./src/javascripts/lib/store/providers/session-storage.js\");\n/* harmony import */ var lib_debug__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! lib/debug */ \"./src/javascripts/lib/debug.js\");\n/* harmony import */ var lib_debug__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(lib_debug__WEBPACK_IMPORTED_MODULE_6__);\n/* harmony import */ var ui_utils_general_utils__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ui/utils/general-utils */ \"./src/javascripts/ui/utils/general-utils.js\");\n/* harmony import */ var _producer__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./producer */ \"./src/javascripts/api/producer.js\");\n/* harmony import */ var _event_producer__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./event-producer */ \"./src/javascripts/api/event-producer.js\");\n/* harmony import */ var _errors_seamly_session_expired_error__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./errors/seamly-session-expired-error */ \"./src/javascripts/api/errors/seamly-session-expired-error.js\");\n/* harmony import */ var _errors_seamly_configuration_error__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./errors/seamly-configuration-error */ \"./src/javascripts/api/errors/seamly-configuration-error.js\");\n/* harmony import */ var _errors_seamly_general_error__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./errors/seamly-general-error */ \"./src/javascripts/api/errors/seamly-general-error.js\");\n/* harmony import */ var _errors_seamly_unauthorized_error__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./errors/seamly-unauthorized-error */ \"./src/javascripts/api/errors/seamly-unauthorized-error.js\");\nfunction ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nconst log = lib_debug__WEBPACK_IMPORTED_MODULE_6___default()('seamly');\nconst DOMAIN = 'api.seamly-app.com';\nconst TRANSLATIONS_VERSION = 1;\n\nfunction buildPayload(command, payload) {\n if (command !== 'message') {\n return payload;\n }\n\n const {\n type,\n body\n } = payload;\n let {\n transactionId\n } = payload;\n\n if (!transactionId) {\n transactionId = (0,lib_id__WEBPACK_IMPORTED_MODULE_4__.randomId)();\n }\n\n return {\n type,\n body,\n transactionId\n };\n}\n/**\n * Tries to get the time zone key directly from the operating system for those\n * environments that support the ECMAScript Internationalization API.\n *\n * Based on https://github.com/pellepim/jstimezonedetect/blob/master/jstz.main.js\n */\n\n\nfunction getTimeZone() {\n if (!Intl || typeof Intl === 'undefined' || typeof Intl.DateTimeFormat === 'undefined') {\n return null;\n }\n\n const format = Intl.DateTimeFormat();\n\n if (typeof format === 'undefined' || typeof format.resolvedOptions === 'undefined') {\n return null;\n }\n\n const timezone = format.resolvedOptions().timeZone; // Ensure we get a valid timezone\n\n if (timezone && (timezone.indexOf('/') > -1 || timezone === 'UTC')) {\n return timezone;\n } else {\n return null;\n }\n}\n\nclass API {\n /**\n * Creates an instance of API.\n * @param {Object} [config={}]\n * @param {string} config.key Api key\n * @param {string} config.domain Domain to connect to\n * @param {string} config.secure Connect securely\n * @param {string} config.externalId Unique visitor identifier (optional)\n * @param {boolean} config.sendEnvironment\n * @param {string} layoutMode\n * @param {string} namespace\n * @param {Object} [context={ channelName: undefined, variables: undefined, locale: undefined, topic: undefined, translationLocale: undefined }]\n * @param {string} context.channelName\n * @param {object} context.variables\n * @param {string} context.locale\n * @param {string} context.topic\n * @param {string} context.translationLocale\n * @memberof API\n */\n constructor({\n layoutMode,\n namespace,\n config = {},\n context = {}\n }) {\n this.store = (0,lib_store_index__WEBPACK_IMPORTED_MODULE_3__.objectStore)(`${namespace}.connection${context.locale ? `.${context.locale}` : ''}`, config.storageProvider || lib_store_providers_session_storage__WEBPACK_IMPORTED_MODULE_5__[\"default\"]);\n this.connectionInfo = {\n apiKey: config.key,\n domain: config.domain || DOMAIN,\n secure: config.secure !== false ? config.secure || true : false\n };\n this.config = {\n sendEnvironment: config.sendEnvironment ?? true,\n context: _objectSpread(_objectSpread({}, context), {}, {\n channelName: context.channelName || 'web'\n })\n };\n this.connected = false;\n this.configReady = false;\n this.externalId = config.externalId;\n this.layoutMode = layoutMode;\n this.userResponded = false;\n this.internalProducer = new _event_producer__WEBPACK_IMPORTED_MODULE_9__[\"default\"]('API');\n this.internal$ = xstream__WEBPACK_IMPORTED_MODULE_0___default().create(this.internalProducer).flatten();\n this.connection$ = this.internal$.filter(event => event.type === 'connection');\n this.connection$.subscribe({\n next: ({\n connected,\n ready\n }) => {\n this.connected = connected;\n this.ready = ready;\n }\n });\n this.URLS = {}; // We want to reconnect whenever the page is loaded from cache (bfcache).\n // Older browsers don't support 'pageshow' and 'bfcache' so this will be ignored and work as usual.\n\n window.addEventListener('pageshow', event => {\n if (event.persisted && this.connected) {\n this.connect();\n }\n });\n }\n\n getAccessToken() {\n return this.store.get('accessToken');\n }\n\n setAccessToken(accessToken) {\n this.store.set('accessToken', accessToken);\n }\n\n getConversationUrl() {\n return this.store.get('conversationUrl');\n }\n\n setConversationUrl(url) {\n this.store.set('conversationUrl', url);\n }\n\n hasConversation() {\n return !!this.getConversationUrl();\n }\n\n getChannelTopic() {\n // The `channelName` fallback is needed for seamless client upgrades.\n // TODO: Remove when all clients have been upgraded past v20.\n return this.store.get('channelTopic') || this.store.get('channelName');\n }\n\n setChannelTopic(topic) {\n this.store.set('channelTopic', topic);\n }\n\n getLocale = locale => locale || this.locale;\n\n clearStore() {\n this.store.delete('accessToken');\n this.store.delete('conversationUrl'); // TODO: Remove `channelName` when all clients have been upgraded past v20.\n\n this.store.delete('channelName');\n this.store.delete('channelTopic');\n }\n\n getUrlPrefix(protocol) {\n const realProtocol = this.connectionInfo.secure ? `${protocol}s` : protocol;\n return `${realProtocol}://${this.connectionInfo.domain}`;\n }\n\n updateUrls({\n _links: responseLinks\n }) {\n this.URLS = Object.entries(responseLinks).filter(([key]) => key !== 'self').reduce((urls, [key, {\n href\n }]) => {\n return _objectSpread(_objectSpread({}, urls), {}, {\n [key]: href\n });\n }, this.URLS);\n }\n\n async reset() {\n await this.disconnect();\n this.clearStore();\n return this.getConfig();\n }\n\n async disconnect() {\n if (this.conversationProducer) {\n await this.conversationProducer.disconnect();\n }\n\n this.connected = false;\n this.configReady = false;\n }\n\n async createConversation() {\n try {\n const request = superagent__WEBPACK_IMPORTED_MODULE_1___default().post(`${this.getUrlPrefix('http')}${this.URLS.conversations}`).set('Content-Type', 'application/json').query({\n v: config__WEBPACK_IMPORTED_MODULE_2__.apiVersion\n }) // withCredentials() is necessary to allow browsers to save received\n // cookies in CORS requests.\n .withCredentials().send({\n externalId: this.externalId || undefined\n });\n const {\n body\n } = await request;\n const {\n conversation\n } = body;\n\n const initialState = _objectSpread({}, conversation);\n\n delete initialState.accessToken;\n delete initialState.channelTopic;\n this.setAccessToken(conversation.accessToken);\n this.setChannelTopic(conversation.channelTopic);\n this.updateUrls(body);\n this.setConversationUrl(this.URLS.conversation);\n this.locale = conversation.translation?.locale;\n this.userResponded = conversation.userResponded;\n return initialState;\n } catch (error) {\n if (error.status >= 500) {\n throw new _errors_seamly_general_error__WEBPACK_IMPORTED_MODULE_12__[\"default\"](error);\n }\n\n throw error;\n }\n }\n\n getConfig() {\n return superagent__WEBPACK_IMPORTED_MODULE_1___default().post(`${this.getUrlPrefix('http')}/client/${this.connectionInfo.apiKey}/configs`).set('Content-Type', 'application/json').query({\n v: config__WEBPACK_IMPORTED_MODULE_2__.apiVersion\n }).send({\n context: _objectSpread(_objectSpread({}, this.config.context), {}, {\n environment: this.config.sendEnvironment === true ? this.getEnvironment() : this.config.sendEnvironment\n })\n }).then(({\n body\n }) => {\n this.updateUrls(body);\n this.configReady = true;\n return body.config;\n }).catch(error => {\n if (error.status === 404) {\n throw new _errors_seamly_configuration_error__WEBPACK_IMPORTED_MODULE_11__[\"default\"]();\n }\n\n if (error.status >= 500) {\n throw new _errors_seamly_general_error__WEBPACK_IMPORTED_MODULE_12__[\"default\"](error);\n }\n\n throw error;\n });\n }\n\n async getConversation() {\n if (!this.hasConversation()) {\n return null;\n }\n\n try {\n const {\n body\n } = await superagent__WEBPACK_IMPORTED_MODULE_1___default().get(`${this.getUrlPrefix('http')}${this.URLS.history}`).set('Authorization', `Bearer ${this.getAccessToken()}`).query({\n v: config__WEBPACK_IMPORTED_MODULE_2__.apiVersion\n });\n this.updateUrls(body);\n const {\n messages,\n participants,\n activeServiceSessionId,\n activeServiceSettings,\n serviceData,\n ui,\n translation\n } = body.history;\n return {\n events: messages.map(([type, msg]) => {\n return {\n type,\n payload: _objectSpread(_objectSpread({}, msg), {}, {\n type: type === 'participant' ? type : msg.type\n })\n };\n }),\n participants,\n activeServiceSessionId,\n activeServiceSettings,\n serviceData,\n resumeConversationPrompt: ui ? Boolean(ui.resumeConversationPrompt) : false,\n translation\n };\n } catch (error) {\n if (error.status === 401) {\n throw new _errors_seamly_unauthorized_error__WEBPACK_IMPORTED_MODULE_13__[\"default\"](error);\n }\n\n if (error.status === 404) {\n throw new _errors_seamly_session_expired_error__WEBPACK_IMPORTED_MODULE_10__[\"default\"](error);\n }\n\n if (error.status >= 500) {\n throw new _errors_seamly_general_error__WEBPACK_IMPORTED_MODULE_12__[\"default\"](error);\n }\n\n throw error;\n }\n }\n\n async connect() {\n this.connected = false;\n let conversationInitialState = null;\n\n if (!this.hasConversation()) {\n conversationInitialState = await this.createConversation();\n }\n\n this.conversationProducer = new _producer__WEBPACK_IMPORTED_MODULE_8__[\"default\"](`${this.getUrlPrefix('ws')}${this.URLS.socket}`, this.config.context.channelName, this.getChannelTopic(), this.getAccessToken());\n this.internalProducer.emit(xstream__WEBPACK_IMPORTED_MODULE_0___default().create(this.conversationProducer)); // Send environment\n\n if (this.config.sendEnvironment) {\n this.send('context', {\n environment: this.config.sendEnvironment === true ? this.getEnvironment() : this.config.sendEnvironment\n }, false);\n }\n\n return conversationInitialState;\n }\n\n uploadFile(file, progressCallback, successCallback, errorCallback) {\n const formData = new FormData();\n formData.append('upload', file);\n const req = superagent__WEBPACK_IMPORTED_MODULE_1___default().post(`${this.getUrlPrefix('http')}${this.URLS.uploads}`).set('Authorization', `Bearer ${this.getAccessToken()}`).send(formData);\n req.on('progress', function (e) {\n const {\n direction,\n percent\n } = e;\n\n if (direction === 'upload' && typeof progressCallback === 'function') {\n progressCallback(percent);\n }\n });\n req.then(uploadResponse => {\n if (successCallback) {\n successCallback(uploadResponse);\n }\n }).catch(err => {\n if (errorCallback) {\n errorCallback(err.response);\n } else {\n throw err;\n }\n });\n return req;\n }\n\n getConversationIntitialState() {\n return superagent__WEBPACK_IMPORTED_MODULE_1___default().get(`${this.getUrlPrefix('http')}${this.getConversationUrl()}`).set('Authorization', `Bearer ${this.getAccessToken()}`).query({\n v: config__WEBPACK_IMPORTED_MODULE_2__.apiVersion\n }).then(({\n body\n }) => {\n this.updateUrls(body);\n this.userResponded = body.conversation.userResponded;\n return (0,ui_utils_general_utils__WEBPACK_IMPORTED_MODULE_7__.omit)(body.conversation, ['accessToken', 'channelTopic']);\n }).catch(error => {\n if (error.status === 401) {\n throw new _errors_seamly_unauthorized_error__WEBPACK_IMPORTED_MODULE_13__[\"default\"](error);\n }\n\n if (error.status === 404) {\n throw new _errors_seamly_session_expired_error__WEBPACK_IMPORTED_MODULE_10__[\"default\"](error);\n }\n\n if (error.status >= 500) {\n throw new _errors_seamly_general_error__WEBPACK_IMPORTED_MODULE_12__[\"default\"](error);\n }\n\n throw error;\n });\n }\n\n async getTranslations(locale) {\n try {\n const url = `${this.getUrlPrefix('http')}${this.URLS.translations}`.replace('{version}', String(TRANSLATIONS_VERSION)).replace('{locale}', this.getLocale(locale));\n const request = superagent__WEBPACK_IMPORTED_MODULE_1___default().get(url);\n const {\n body\n } = await request;\n return body.translations;\n } catch (error) {\n if (error.status >= 500) {\n throw new _errors_seamly_general_error__WEBPACK_IMPORTED_MODULE_12__[\"default\"](error);\n }\n\n throw error;\n }\n }\n\n send(command, payload, waitForReady = true) {\n if (!this.connected || waitForReady && !this.ready) {\n // Wait for connection\n this.connection$.filter(e => waitForReady ? e.connected && e.ready : e.connected).take(1).subscribe({\n next: () => this.send(command, payload, waitForReady)\n });\n return;\n }\n\n log('[SEND]', command, payload);\n this.conversationProducer.push(command, buildPayload(command, payload), 10000);\n }\n\n sendContext(context = {}) {\n const {\n locale,\n variables\n } = context;\n const payload = {};\n\n if (locale) {\n if (typeof locale !== 'string') {\n throw new Error('Locale must be a string');\n }\n\n payload.locale = locale;\n }\n\n if (variables) {\n if (typeof variables !== 'object') {\n throw new Error('Variables must be an object');\n }\n\n payload.variables = variables;\n } // If we have empty context don't send context message\n\n\n if (Object.keys(payload).length === 0 && payload.constructor === Object) {\n return;\n }\n\n this.send('context', payload, false);\n }\n\n stream() {\n return this.internal$.filter(event => event.type !== 'connection');\n }\n\n getEnvironment() {\n return {\n clientName: \"@seamly/web-ui\",\n clientVariant: this.layoutMode,\n clientVersion: \"20.8.0-beta.1\",\n currentUrl: window.location.toString(),\n screenResolution: `${window.screen.width}x${window.screen.height}`,\n timezone: getTimeZone(),\n userAgent: navigator.userAgent\n };\n }\n\n}\n\n//# sourceURL=webpack://@seamly/web-ui/./src/javascripts/api/index.js?");
|
|
633
|
+
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"API\": () => (/* binding */ API)\n/* harmony export */ });\n/* harmony import */ var xstream__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! xstream */ \"./node_modules/xstream/index.js\");\n/* harmony import */ var xstream__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(xstream__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var superagent__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! superagent */ \"./node_modules/superagent/lib/client.js\");\n/* harmony import */ var superagent__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(superagent__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var config__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! config */ \"./src/javascripts/config.ts\");\n/* harmony import */ var lib_store_index__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! lib/store/index */ \"./src/javascripts/lib/store/index.js\");\n/* harmony import */ var lib_id__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! lib/id */ \"./src/javascripts/lib/id.js\");\n/* harmony import */ var lib_store_providers_session_storage__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! lib/store/providers/session-storage */ \"./src/javascripts/lib/store/providers/session-storage.js\");\n/* harmony import */ var lib_debug__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! lib/debug */ \"./src/javascripts/lib/debug.js\");\n/* harmony import */ var lib_debug__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(lib_debug__WEBPACK_IMPORTED_MODULE_6__);\n/* harmony import */ var ui_utils_general_utils__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ui/utils/general-utils */ \"./src/javascripts/ui/utils/general-utils.js\");\n/* harmony import */ var _producer__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./producer */ \"./src/javascripts/api/producer.js\");\n/* harmony import */ var _event_producer__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./event-producer */ \"./src/javascripts/api/event-producer.js\");\n/* harmony import */ var _errors_seamly_session_expired_error__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./errors/seamly-session-expired-error */ \"./src/javascripts/api/errors/seamly-session-expired-error.js\");\n/* harmony import */ var _errors_seamly_configuration_error__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./errors/seamly-configuration-error */ \"./src/javascripts/api/errors/seamly-configuration-error.js\");\n/* harmony import */ var _errors_seamly_general_error__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./errors/seamly-general-error */ \"./src/javascripts/api/errors/seamly-general-error.js\");\n/* harmony import */ var _errors_seamly_unauthorized_error__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./errors/seamly-unauthorized-error */ \"./src/javascripts/api/errors/seamly-unauthorized-error.js\");\nfunction ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }\n\nfunction _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nconst log = lib_debug__WEBPACK_IMPORTED_MODULE_6___default()('seamly');\nconst DOMAIN = 'api.seamly-app.com';\nconst TRANSLATIONS_VERSION = 1;\n\nfunction buildPayload(command, payload) {\n if (command !== 'message') {\n return payload;\n }\n\n const {\n type,\n body\n } = payload;\n let {\n transactionId\n } = payload;\n\n if (!transactionId) {\n transactionId = (0,lib_id__WEBPACK_IMPORTED_MODULE_4__.randomId)();\n }\n\n return {\n type,\n body,\n transactionId\n };\n}\n/**\n * Tries to get the time zone key directly from the operating system for those\n * environments that support the ECMAScript Internationalization API.\n *\n * Based on https://github.com/pellepim/jstimezonedetect/blob/master/jstz.main.js\n */\n\n\nfunction getTimeZone() {\n if (!Intl || typeof Intl === 'undefined' || typeof Intl.DateTimeFormat === 'undefined') {\n return null;\n }\n\n const format = Intl.DateTimeFormat();\n\n if (typeof format === 'undefined' || typeof format.resolvedOptions === 'undefined') {\n return null;\n }\n\n const timezone = format.resolvedOptions().timeZone; // Ensure we get a valid timezone\n\n if (timezone && (timezone.indexOf('/') > -1 || timezone === 'UTC')) {\n return timezone;\n } else {\n return null;\n }\n}\n\nclass API {\n /**\n * Creates an instance of API.\n * @param {Object} [config={}]\n * @param {string} config.key Api key\n * @param {string} config.domain Domain to connect to\n * @param {string} config.secure Connect securely\n * @param {string} config.externalId Unique visitor identifier (optional)\n * @param {boolean} config.sendEnvironment\n * @param {string} layoutMode\n * @param {string} namespace\n * @param {Object} [context={ channelName: undefined, variables: undefined, locale: undefined, topic: undefined, translationLocale: undefined }]\n * @param {string} context.channelName\n * @param {object} context.variables\n * @param {string} context.locale\n * @param {string} context.topic\n * @param {string} context.translationLocale\n * @memberof API\n */\n constructor({\n layoutMode,\n namespace,\n config = {},\n context = {}\n }) {\n this.store = (0,lib_store_index__WEBPACK_IMPORTED_MODULE_3__.objectStore)(`${namespace}.connection${context.locale ? `.${context.locale}` : ''}`, config.storageProvider || lib_store_providers_session_storage__WEBPACK_IMPORTED_MODULE_5__[\"default\"]);\n this.connectionInfo = {\n apiKey: config.key,\n domain: config.domain || DOMAIN,\n secure: config.secure !== false ? config.secure || true : false\n };\n this.config = {\n sendEnvironment: config.sendEnvironment ?? true,\n context: _objectSpread(_objectSpread({}, context), {}, {\n channelName: context.channelName || 'web'\n })\n };\n this.connected = false;\n this.configReady = false;\n this.externalId = config.externalId;\n this.layoutMode = layoutMode;\n this.userResponded = false;\n this.internalProducer = new _event_producer__WEBPACK_IMPORTED_MODULE_9__[\"default\"]('API');\n this.internal$ = xstream__WEBPACK_IMPORTED_MODULE_0___default().create(this.internalProducer).flatten();\n this.connection$ = this.internal$.filter(event => event.type === 'connection');\n this.connection$.subscribe({\n next: ({\n connected,\n ready\n }) => {\n this.connected = connected;\n this.ready = ready;\n }\n });\n this.URLS = {}; // We want to reconnect whenever the page is loaded from cache (bfcache).\n // Older browsers don't support 'pageshow' and 'bfcache' so this will be ignored and work as usual.\n\n window.addEventListener('pageshow', event => {\n if (event.persisted && this.connected) {\n this.connect();\n }\n });\n }\n\n getAccessToken() {\n return this.store.get('accessToken');\n }\n\n setAccessToken(accessToken) {\n this.store.set('accessToken', accessToken);\n }\n\n getConversationUrl() {\n return this.store.get('conversationUrl');\n }\n\n setConversationUrl(url) {\n this.store.set('conversationUrl', url);\n }\n\n hasConversation() {\n return !!this.getConversationUrl();\n }\n\n getChannelTopic() {\n // The `channelName` fallback is needed for seamless client upgrades.\n // TODO: Remove when all clients have been upgraded past v20.\n return this.store.get('channelTopic') || this.store.get('channelName');\n }\n\n setChannelTopic(topic) {\n this.store.set('channelTopic', topic);\n }\n\n getLocale = locale => locale || this.locale;\n\n clearStore() {\n this.store.delete('accessToken');\n this.store.delete('conversationUrl'); // TODO: Remove `channelName` when all clients have been upgraded past v20.\n\n this.store.delete('channelName');\n this.store.delete('channelTopic');\n }\n\n getUrlPrefix(protocol) {\n const realProtocol = this.connectionInfo.secure ? `${protocol}s` : protocol;\n return `${realProtocol}://${this.connectionInfo.domain}`;\n }\n\n updateUrls({\n _links: responseLinks\n }) {\n this.URLS = Object.entries(responseLinks).filter(([key]) => key !== 'self').reduce((urls, [key, {\n href\n }]) => {\n return _objectSpread(_objectSpread({}, urls), {}, {\n [key]: href\n });\n }, this.URLS);\n }\n\n async reset() {\n await this.disconnect();\n this.clearStore();\n return this.getConfig();\n }\n\n async disconnect() {\n if (this.conversationProducer) {\n await this.conversationProducer.disconnect();\n }\n\n this.connected = false;\n this.configReady = false;\n }\n\n async createConversation() {\n try {\n const request = superagent__WEBPACK_IMPORTED_MODULE_1___default().post(`${this.getUrlPrefix('http')}${this.URLS.conversations}`).set('Content-Type', 'application/json').query({\n v: config__WEBPACK_IMPORTED_MODULE_2__.apiVersion\n }) // withCredentials() is necessary to allow browsers to save received\n // cookies in CORS requests.\n .withCredentials().send({\n externalId: this.externalId || undefined\n });\n const {\n body\n } = await request;\n const {\n conversation\n } = body;\n\n const initialState = _objectSpread({}, conversation);\n\n delete initialState.accessToken;\n delete initialState.channelTopic;\n this.setAccessToken(conversation.accessToken);\n this.setChannelTopic(conversation.channelTopic);\n this.updateUrls(body);\n this.setConversationUrl(this.URLS.conversation);\n this.locale = conversation.translation?.locale;\n this.userResponded = conversation.userResponded;\n return initialState;\n } catch (error) {\n if (error.status >= 500) {\n throw new _errors_seamly_general_error__WEBPACK_IMPORTED_MODULE_12__[\"default\"](error);\n }\n\n throw error;\n }\n }\n\n getConfig() {\n return superagent__WEBPACK_IMPORTED_MODULE_1___default().post(`${this.getUrlPrefix('http')}/client/${this.connectionInfo.apiKey}/configs`).set('Content-Type', 'application/json').query({\n v: config__WEBPACK_IMPORTED_MODULE_2__.apiVersion\n }).send({\n context: _objectSpread(_objectSpread({}, this.config.context), {}, {\n environment: this.config.sendEnvironment === true ? this.getEnvironment() : this.config.sendEnvironment\n })\n }).then(({\n body\n }) => {\n this.updateUrls(body);\n this.configReady = true;\n return body.config;\n }).catch(error => {\n if (error.status === 404) {\n throw new _errors_seamly_configuration_error__WEBPACK_IMPORTED_MODULE_11__[\"default\"]();\n }\n\n if (error.status >= 500) {\n throw new _errors_seamly_general_error__WEBPACK_IMPORTED_MODULE_12__[\"default\"](error);\n }\n\n throw error;\n });\n }\n\n async getConversation() {\n if (!this.hasConversation()) {\n return null;\n }\n\n try {\n const {\n body\n } = await superagent__WEBPACK_IMPORTED_MODULE_1___default().get(`${this.getUrlPrefix('http')}${this.URLS.history}`).set('Authorization', `Bearer ${this.getAccessToken()}`).query({\n v: config__WEBPACK_IMPORTED_MODULE_2__.apiVersion\n });\n this.updateUrls(body);\n const {\n messages,\n participants,\n activeServiceSessionId,\n activeServiceSettings,\n serviceData,\n ui,\n translation\n } = body.history;\n return {\n events: messages.map(([type, msg]) => {\n return {\n type,\n payload: _objectSpread(_objectSpread({}, msg), {}, {\n type: type === 'participant' ? type : msg.type\n })\n };\n }),\n participants,\n activeServiceSessionId,\n activeServiceSettings,\n serviceData,\n resumeConversationPrompt: ui ? Boolean(ui.resumeConversationPrompt) : false,\n translation\n };\n } catch (error) {\n if (error.status === 401) {\n throw new _errors_seamly_unauthorized_error__WEBPACK_IMPORTED_MODULE_13__[\"default\"](error);\n }\n\n if (error.status === 404) {\n throw new _errors_seamly_session_expired_error__WEBPACK_IMPORTED_MODULE_10__[\"default\"](error);\n }\n\n if (error.status >= 500) {\n throw new _errors_seamly_general_error__WEBPACK_IMPORTED_MODULE_12__[\"default\"](error);\n }\n\n throw error;\n }\n }\n\n async connect() {\n this.connected = false;\n let conversationInitialState = null;\n\n if (!this.hasConversation()) {\n conversationInitialState = await this.createConversation();\n }\n\n this.conversationProducer = new _producer__WEBPACK_IMPORTED_MODULE_8__[\"default\"](`${this.getUrlPrefix('ws')}${this.URLS.socket}`, this.config.context.channelName, this.getChannelTopic(), this.getAccessToken());\n this.internalProducer.emit(xstream__WEBPACK_IMPORTED_MODULE_0___default().create(this.conversationProducer)); // Send environment\n\n if (this.config.sendEnvironment) {\n this.send('context', {\n environment: this.config.sendEnvironment === true ? this.getEnvironment() : this.config.sendEnvironment\n }, false);\n }\n\n return conversationInitialState;\n }\n\n uploadFile(file, progressCallback, successCallback, errorCallback) {\n const formData = new FormData();\n formData.append('upload', file);\n const req = superagent__WEBPACK_IMPORTED_MODULE_1___default().post(`${this.getUrlPrefix('http')}${this.URLS.uploads}`).set('Authorization', `Bearer ${this.getAccessToken()}`).send(formData);\n req.on('progress', function (e) {\n const {\n direction,\n percent\n } = e;\n\n if (direction === 'upload' && typeof progressCallback === 'function') {\n progressCallback(percent);\n }\n });\n req.then(uploadResponse => {\n if (successCallback) {\n successCallback(uploadResponse);\n }\n }).catch(err => {\n if (errorCallback) {\n errorCallback(err.response);\n } else {\n throw err;\n }\n });\n return req;\n }\n\n getConversationIntitialState() {\n return superagent__WEBPACK_IMPORTED_MODULE_1___default().get(`${this.getUrlPrefix('http')}${this.getConversationUrl()}`).set('Authorization', `Bearer ${this.getAccessToken()}`).query({\n v: config__WEBPACK_IMPORTED_MODULE_2__.apiVersion\n }).then(({\n body\n }) => {\n this.updateUrls(body);\n this.userResponded = body.conversation.userResponded;\n return (0,ui_utils_general_utils__WEBPACK_IMPORTED_MODULE_7__.omit)(body.conversation, ['accessToken', 'channelTopic']);\n }).catch(error => {\n if (error.status === 401) {\n throw new _errors_seamly_unauthorized_error__WEBPACK_IMPORTED_MODULE_13__[\"default\"](error);\n }\n\n if (error.status === 404) {\n throw new _errors_seamly_session_expired_error__WEBPACK_IMPORTED_MODULE_10__[\"default\"](error);\n }\n\n if (error.status >= 500) {\n throw new _errors_seamly_general_error__WEBPACK_IMPORTED_MODULE_12__[\"default\"](error);\n }\n\n throw error;\n });\n }\n\n async getTranslations(locale) {\n try {\n const url = `${this.getUrlPrefix('http')}${this.URLS.translations}`.replace('{version}', String(TRANSLATIONS_VERSION)).replace('{locale}', this.getLocale(locale));\n const request = superagent__WEBPACK_IMPORTED_MODULE_1___default().get(url);\n const {\n body\n } = await request;\n return body.translations;\n } catch (error) {\n if (error.status >= 500) {\n throw new _errors_seamly_general_error__WEBPACK_IMPORTED_MODULE_12__[\"default\"](error);\n }\n\n throw error;\n }\n }\n\n send(command, payload, waitForReady = true) {\n if (!this.connected || waitForReady && !this.ready) {\n // Wait for connection\n this.connection$.filter(e => waitForReady ? e.connected && e.ready : e.connected).take(1).subscribe({\n next: () => this.send(command, payload, waitForReady)\n });\n return;\n }\n\n log('[SEND]', command, payload);\n this.conversationProducer.push(command, buildPayload(command, payload), 10000);\n }\n\n sendContext(context = {}) {\n const {\n locale,\n variables\n } = context;\n const payload = {};\n\n if (locale) {\n if (typeof locale !== 'string') {\n throw new Error('Locale must be a string');\n }\n\n payload.locale = locale;\n }\n\n if (variables) {\n if (typeof variables !== 'object') {\n throw new Error('Variables must be an object');\n }\n\n payload.variables = variables;\n } // If we have empty context don't send context message\n\n\n if (Object.keys(payload).length === 0 && payload.constructor === Object) {\n return;\n }\n\n this.send('context', payload, false);\n }\n\n stream() {\n return this.internal$.filter(event => event.type !== 'connection');\n }\n\n getEnvironment() {\n return {\n clientName: \"@seamly/web-ui\",\n clientVariant: this.layoutMode,\n clientVersion: \"20.7.0\",\n currentUrl: window.location.toString(),\n screenResolution: `${window.screen.width}x${window.screen.height}`,\n timezone: getTimeZone(),\n userAgent: navigator.userAgent\n };\n }\n\n}\n\n//# sourceURL=webpack://@seamly/web-ui/./src/javascripts/api/index.js?");
|
|
634
634
|
|
|
635
635
|
/***/ }),
|
|
636
636
|
|
|
@@ -2037,7 +2037,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
|
|
|
2037
2037
|
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
2038
2038
|
|
|
2039
2039
|
"use strict";
|
|
2040
|
-
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var domains_i18n_hooks__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! domains/i18n/hooks */ \"./src/javascripts/domains/i18n/hooks.ts\");\n/* harmony import */ var domains_i18n_hooks__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(domains_i18n_hooks__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var domains_store_slice__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! domains/store/slice */ \"./src/javascripts/domains/store/slice.ts\");\n/* harmony import */ var domains_visibility_constants__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! domains/visibility/constants */ \"./src/javascripts/domains/visibility/constants.js\");\n/* harmony import */ var domains_visibility_hooks__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! domains/visibility/hooks */ \"./src/javascripts/domains/visibility/hooks.ts\");\n/* harmony import */ var domains_visibility_hooks__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(domains_visibility_hooks__WEBPACK_IMPORTED_MODULE_3__);\n/* harmony import */ var preact_hooks__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! preact/hooks */ \"preact/hooks\");\n/* harmony import */ var preact_hooks__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(preact_hooks__WEBPACK_IMPORTED_MODULE_4__);\n/* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! react-redux */ \"./node_modules/react-redux/es/index.js\");\n/* harmony import */ var _domains_visibility_selectors__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../../domains/visibility/selectors */ \"./src/javascripts/domains/visibility/selectors.ts\");\n/* harmony import */ var _live_region_hooks__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./live-region-hooks */ \"./src/javascripts/ui/hooks/live-region-hooks.js\");\n/* harmony import */ var _seamly_api_hooks__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./seamly-api-hooks */ \"./src/javascripts/ui/hooks/seamly-api-hooks.js\");\n/* harmony import */ var _seamly_state_hooks__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./seamly-state-hooks */ \"./src/javascripts/ui/hooks/seamly-state-hooks.js\");\n/* harmony import */ var _use_seamly_commands__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./use-seamly-commands */ \"./src/javascripts/ui/hooks/use-seamly-commands.js\");\n\n\n\n\n\n\n\n\n\n\n\n\nconst useSeamlyChat = () => {\n const {\n t\n } = (0,domains_i18n_hooks__WEBPACK_IMPORTED_MODULE_0__.useI18n)();\n const {\n isInline,\n isWindow\n } = (0,_seamly_state_hooks__WEBPACK_IMPORTED_MODULE_9__.useSeamlyLayoutMode)();\n const {\n isOpen,\n isVisible,\n setVisibility\n } = (0,domains_visibility_hooks__WEBPACK_IMPORTED_MODULE_3__.useVisibility)();\n const showInlineView = (0,react_redux__WEBPACK_IMPORTED_MODULE_5__.useSelector)(_domains_visibility_selectors__WEBPACK_IMPORTED_MODULE_6__.selectShowInlineView);\n const dispatch = (0,react_redux__WEBPACK_IMPORTED_MODULE_5__.useDispatch)();\n const
|
|
2040
|
+
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var domains_i18n_hooks__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! domains/i18n/hooks */ \"./src/javascripts/domains/i18n/hooks.ts\");\n/* harmony import */ var domains_i18n_hooks__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(domains_i18n_hooks__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var domains_store_slice__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! domains/store/slice */ \"./src/javascripts/domains/store/slice.ts\");\n/* harmony import */ var domains_visibility_constants__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! domains/visibility/constants */ \"./src/javascripts/domains/visibility/constants.js\");\n/* harmony import */ var domains_visibility_hooks__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! domains/visibility/hooks */ \"./src/javascripts/domains/visibility/hooks.ts\");\n/* harmony import */ var domains_visibility_hooks__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(domains_visibility_hooks__WEBPACK_IMPORTED_MODULE_3__);\n/* harmony import */ var preact_hooks__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! preact/hooks */ \"preact/hooks\");\n/* harmony import */ var preact_hooks__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(preact_hooks__WEBPACK_IMPORTED_MODULE_4__);\n/* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! react-redux */ \"./node_modules/react-redux/es/index.js\");\n/* harmony import */ var _domains_visibility_selectors__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../../domains/visibility/selectors */ \"./src/javascripts/domains/visibility/selectors.ts\");\n/* harmony import */ var _live_region_hooks__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./live-region-hooks */ \"./src/javascripts/ui/hooks/live-region-hooks.js\");\n/* harmony import */ var _seamly_api_hooks__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./seamly-api-hooks */ \"./src/javascripts/ui/hooks/seamly-api-hooks.js\");\n/* harmony import */ var _seamly_state_hooks__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./seamly-state-hooks */ \"./src/javascripts/ui/hooks/seamly-state-hooks.js\");\n/* harmony import */ var _use_seamly_commands__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./use-seamly-commands */ \"./src/javascripts/ui/hooks/use-seamly-commands.js\");\n\n\n\n\n\n\n\n\n\n\n\n\nconst useSeamlyChat = () => {\n const events = (0,_seamly_state_hooks__WEBPACK_IMPORTED_MODULE_9__.useEvents)();\n const {\n t\n } = (0,domains_i18n_hooks__WEBPACK_IMPORTED_MODULE_0__.useI18n)();\n const {\n isInline,\n isWindow\n } = (0,_seamly_state_hooks__WEBPACK_IMPORTED_MODULE_9__.useSeamlyLayoutMode)();\n const {\n isOpen,\n isVisible,\n setVisibility\n } = (0,domains_visibility_hooks__WEBPACK_IMPORTED_MODULE_3__.useVisibility)();\n const showInlineView = (0,react_redux__WEBPACK_IMPORTED_MODULE_5__.useSelector)(_domains_visibility_selectors__WEBPACK_IMPORTED_MODULE_6__.selectShowInlineView);\n const dispatch = (0,react_redux__WEBPACK_IMPORTED_MODULE_5__.useDispatch)();\n const spinnerTimeout = (0,preact_hooks__WEBPACK_IMPORTED_MODULE_4__.useRef)(null);\n const {\n start,\n connect,\n apiConfigReady,\n apiConnected\n } = (0,_use_seamly_commands__WEBPACK_IMPORTED_MODULE_10__[\"default\"])();\n const hasConversation = (0,_seamly_api_hooks__WEBPACK_IMPORTED_MODULE_8__.useSeamlyHasConversation)();\n const prevIsOpen = (0,preact_hooks__WEBPACK_IMPORTED_MODULE_4__.useRef)(null);\n const prevIsVisible = (0,preact_hooks__WEBPACK_IMPORTED_MODULE_4__.useRef)(null);\n const startCalled = (0,preact_hooks__WEBPACK_IMPORTED_MODULE_4__.useRef)(false);\n const {\n sendAssertive\n } = (0,_live_region_hooks__WEBPACK_IMPORTED_MODULE_7__.useLiveRegion)();\n (0,preact_hooks__WEBPACK_IMPORTED_MODULE_4__.useEffect)(() => {\n if (isVisible) {\n // Wait for the live containers to stabilise in the DOM before injecting\n // the message or some screen readers will swallow it.\n setTimeout(() => {\n sendAssertive(t('window.srTexts.onLoad'));\n }, 500);\n }\n }, [isVisible, sendAssertive, t]);\n (0,preact_hooks__WEBPACK_IMPORTED_MODULE_4__.useEffect)(() => {\n if (isVisible !== prevIsVisible.current) {\n prevIsOpen.current = isOpen;\n prevIsVisible.current = isVisible;\n return;\n }\n\n if (prevIsOpen.current !== null) {\n if (isOpen) {\n sendAssertive(t('window.srTexts.onOpen'));\n } else {\n sendAssertive(t('window.srTexts.onClose'));\n }\n }\n\n prevIsOpen.current = isOpen;\n prevIsVisible.current = isVisible;\n }, [isOpen, isVisible, sendAssertive, t]);\n (0,preact_hooks__WEBPACK_IMPORTED_MODULE_4__.useEffect)(() => {\n // This delays the start of the loading inidicator we set when we initialise\n // the application. This is done to only avoid BSOD on initial load if DCX is slow.\n spinnerTimeout.current = setTimeout(() => {\n dispatch((0,domains_store_slice__WEBPACK_IMPORTED_MODULE_1__.setIsLoading)(true));\n }, 500);\n return () => {\n clearTimeout(spinnerTimeout.current);\n };\n }, [dispatch]);\n (0,preact_hooks__WEBPACK_IMPORTED_MODULE_4__.useEffect)(() => {\n if (events.length) {\n spinnerTimeout.current = setTimeout(() => {\n dispatch((0,domains_store_slice__WEBPACK_IMPORTED_MODULE_1__.setIsLoading)(false));\n }, 5000);\n }\n\n return () => {\n clearTimeout(spinnerTimeout.current);\n };\n }, [events, dispatch]);\n (0,preact_hooks__WEBPACK_IMPORTED_MODULE_4__.useEffect)(() => {\n // This is needed to reset the ref to allow connect and start to happen again.\n // Mostly due to Interrupt situations and a reset being called.\n if (!apiConfigReady || !apiConnected) {\n startCalled.current = false;\n }\n }, [apiConfigReady, apiConnected]);\n const connectAndStart = (0,preact_hooks__WEBPACK_IMPORTED_MODULE_4__.useCallback)(async () => {\n // We don't connect if we are already connected to the api to avoid multiple in-flight connection processes.\n if (!apiConnected) {\n await connect();\n } // We only start a conversation when the chat interface is either 'open' or if using the inline view if it's 'open' or 'minimized'.\n\n\n if (isOpen || isVisible && isInline) {\n start();\n startCalled.current = true;\n }\n }, [apiConnected, connect, isInline, isOpen, isVisible, start]);\n (0,preact_hooks__WEBPACK_IMPORTED_MODULE_4__.useEffect)(() => {\n // We dont't connect or start when the apiConfig is not ready yet.\n // We also keep track of whether start has been called to avoid multiple in-flight connection processes.\n // We check if the window view is not open and no conversation is started yet.\n // Lastly we check if the inline view is not scrolled in to view.\n if (!apiConfigReady || startCalled.current || isWindow && !isOpen && !hasConversation() || isInline && !showInlineView) {\n return;\n }\n\n if (hasConversation() && isOpen) {\n // We deactivate the extra startup loading spinner when a conversation is available\n // We also stop setting the loading indicator in the first place to avoid a flash.\n clearTimeout(spinnerTimeout.current);\n dispatch((0,domains_store_slice__WEBPACK_IMPORTED_MODULE_1__.setIsLoading)(false));\n }\n\n connectAndStart();\n }, [apiConfigReady, connectAndStart, dispatch, hasConversation, isInline, isOpen, isWindow, showInlineView]);\n\n const openChat = () => {\n setVisibility(domains_visibility_constants__WEBPACK_IMPORTED_MODULE_2__.visibilityStates.open);\n };\n\n const closeChat = () => {\n setVisibility(domains_visibility_constants__WEBPACK_IMPORTED_MODULE_2__.visibilityStates.minimized);\n };\n\n return {\n openChat,\n closeChat\n };\n};\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (useSeamlyChat);\n\n//# sourceURL=webpack://@seamly/web-ui/./src/javascripts/ui/hooks/use-seamly-chat.js?");
|
|
2041
2041
|
|
|
2042
2042
|
/***/ }),
|
|
2043
2043
|
|