@capillarytech/creatives-library 7.17.30 → 7.17.31

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@capillarytech/creatives-library",
3
3
  "author": "meharaj",
4
- "version": "7.17.30",
4
+ "version": "7.17.31",
5
5
  "description": "Capillary creatives ui",
6
6
  "main": "./index.js",
7
7
  "module": "./index.es.js",
package/utils/common.js CHANGED
@@ -288,7 +288,8 @@ export const isTraiDLTEnable = (isFullMode, smsRegister) => {
288
288
  return isTraiDltFeature;
289
289
  };
290
290
 
291
- export const intlKeyGenerator = (value = "") => String(value).replace(/[^a-zA-Z0-9_]/g, "");
291
+
292
+ export const intlKeyGenerator = (value = "") => String(value).replace(/[^a-zA-Z0-9_]/g, "").toLowerCase();
292
293
 
293
294
  export const handleInjectedData = (data, scope) => {
294
295
  let tagType;
@@ -51,7 +51,7 @@ describe("handleInjectedData", () => {
51
51
  const result = handleInjectedData(data, "scope");
52
52
  const intlKey = intlKeyGenerator("scope");
53
53
  expect(intlKey).toEqual('scope');
54
- expect(result.tag1.name).toEqual(<FormattedMessage defaultMessage="Registration Fields" id="scope.RegistrationFields" values={{}} />);
54
+ expect(result.tag1.name).toEqual(<FormattedMessage defaultMessage="Registration Fields" id="scope.registrationfields" values={{}} />);
55
55
  });
56
56
 
57
57
  it("adds tagType for Registration custom fields", () => {
@@ -62,9 +62,10 @@ describe("handleInjectedData", () => {
62
62
  };
63
63
 
64
64
  const result = handleInjectedData(data, "scope");
65
-
65
+ const intlKey = intlKeyGenerator();
66
+ expect(intlKey).toEqual('');
66
67
  expect(result.tag1.name).toEqual(
67
- <FormattedMessage defaultMessage="Registration custom fields" id="scope.Registrationcustomfields_name.CustomTagMessage" values={{}} />
68
+ <FormattedMessage defaultMessage="Registration custom fields" id="scope.registrationcustomfields_name.CustomTagMessage" values={{}} />
68
69
  );
69
70
  });
70
71
 
@@ -78,7 +79,7 @@ describe("handleInjectedData", () => {
78
79
  const result = handleInjectedData(data, "scope");
79
80
 
80
81
  expect(result.tag1.name).toEqual(
81
- <FormattedMessage defaultMessage="Customer extended fields" id="scope.Customerextendedfields_name.ExtendedTagMessage" values={{}} />
82
+ <FormattedMessage defaultMessage="Customer extended fields" id="scope.customerextendedfields_name.ExtendedTagMessage" values={{}} />
82
83
  );
83
84
  });
84
85
  it("adds tagType for Customer extended fields fields", () => {
@@ -156,7 +157,7 @@ describe("handleInjectedData", () => {
156
157
  const result = handleInjectedData(data, "scope");
157
158
 
158
159
  expect(result.tag1.subtags.subtag1.desc).toEqual(
159
- <FormattedMessage defaultMessage="Enter your first name" id="scope.Enteryourfirstname" values={{}} />
160
+ <FormattedMessage defaultMessage="Enter your first name" id="scope.enteryourfirstname" values={{}} />
160
161
  );
161
162
  });
162
163
  it("replaces subtag name desc with intl key", () => {
@@ -174,7 +175,7 @@ describe("handleInjectedData", () => {
174
175
  const result = handleInjectedData(data, "scope");
175
176
 
176
177
  expect(result.tag1.subtags.subtag1.desc).toEqual(
177
- <FormattedMessage defaultMessage="Enter your first name" id="scope.Enteryourfirstname" values={{}} />
178
+ <FormattedMessage defaultMessage="Enter your first name" id="scope.enteryourfirstname" values={{}} />
178
179
  );
179
180
  });
180
181
  });
@@ -25,7 +25,7 @@ import {
25
25
  JAPANESE_HELP_TEXT,
26
26
  TAG_TRANSLATION_DOC,
27
27
  } from "../../containers/TagList/constants";
28
- import { HIDE_FOR_JP_LOCALE } from '../../v2Containers/App/constants';
28
+ import { JP_LOCALE_HIDE_FEATURE } from '../../v2Containers/App/constants';
29
29
  import { hidingDateTagsForJpLocale } from '../../v2Containers/TagList/utils';
30
30
 
31
31
 
@@ -175,7 +175,7 @@ class CapTagList extends React.Component { // eslint-disable-line react/prefer-s
175
175
  renderTags(tags, searchString = '') {
176
176
  const { disableRelatedTags, childTagsToDisable, parentTagstoDisable, showCardsRelatedTags } = this?.props?.disableTagsDetails;
177
177
  const { accessibleFeatures = [] } = this?.props?.currentOrgDetails || {};
178
- const hideDateTagsForJpLocale = accessibleFeatures.includes(HIDE_FOR_JP_LOCALE);
178
+ const hideDateTagsForJpLocale = accessibleFeatures.includes(JP_LOCALE_HIDE_FEATURE);
179
179
  const list = [];
180
180
  const loyaltyAttrDisableText = <FormattedMessage {...messages.loyaltyAttributeDisable} />;
181
181
  let clonedTags = _.cloneDeep(tags);
@@ -54,7 +54,7 @@ export const LINE = 'line';
54
54
  export const EMAIL = 'email';
55
55
  export const ASSETS = 'assets';
56
56
 
57
- export const HIDE_FOR_JP_LOCALE = 'HIDE_FOR_JP_LOCALE';
57
+ export const JP_LOCALE_HIDE_FEATURE = 'JP_LOCALE_HIDE_FEATURE';
58
58
 
59
59
  export const TRACK_EDIT_SMS = 'editSms';
60
60
  export const TRACK_EDIT_EMAIL = 'editEmail';
@@ -0,0 +1,20 @@
1
+ /*
2
+ *
3
+ * ChannelTemplates actions
4
+ *
5
+ */
6
+
7
+ import * as types from './constants';
8
+
9
+ export function defaultAction() {
10
+ return {
11
+ type: types.DEFAULT_ACTION,
12
+ };
13
+ }
14
+
15
+ export function getTemplates(channel) {
16
+ return {
17
+ type: types.GET_TEMPLATES_REQUEST,
18
+ channel,
19
+ };
20
+ }
@@ -0,0 +1,8 @@
1
+ /*
2
+ *
3
+ * ChannelTemplates constants
4
+ *
5
+ */
6
+
7
+ export const DEFAULT_ACTION = 'app/ChannelTemplates/DEFAULT_ACTION';
8
+
@@ -0,0 +1,47 @@
1
+ /*
2
+ *
3
+ * ChannelTemplates
4
+ *
5
+ */
6
+
7
+ import PropTypes from 'prop-types';
8
+
9
+ import React from 'react';
10
+ import { connect } from 'react-redux';
11
+ import { FormattedMessage } from 'react-intl';
12
+ import { bindActionCreators } from 'redux';
13
+ import { createStructuredSelector } from 'reselect';
14
+ import makeSelectChannelTemplates from './selectors';
15
+ import * as actions from './actions';
16
+ import messages from './messages';
17
+
18
+
19
+ export class ChannelTemplates extends React.Component { // eslint-disable-line react/prefer-stateless-function
20
+ componentDidMount() {
21
+ this.props.actions.getTemplates(this.props.channel);
22
+ }
23
+ render() {
24
+ return (
25
+ <CardGrid
26
+ cardDataList={[]}
27
+ />
28
+ );
29
+ }
30
+ }
31
+
32
+ ChannelTemplates.propTypes = {
33
+ actions: PropTypes.object.isRequired,
34
+ channel: PropTypes.string,
35
+ };
36
+
37
+ const mapStateToProps = createStructuredSelector({
38
+ ChannelTemplates: makeSelectChannelTemplates(),
39
+ });
40
+
41
+ function mapDispatchToProps(dispatch) {
42
+ return {
43
+ actions: bindActionCreators(actions, dispatch),
44
+ };
45
+ }
46
+
47
+ export default connect(mapStateToProps, mapDispatchToProps)(ChannelTemplates);
@@ -0,0 +1,13 @@
1
+ /*
2
+ * ChannelTemplates Messages
3
+ *
4
+ * This contains all the text for the ChannelTemplates component.
5
+ */
6
+ import { defineMessages } from 'react-intl';
7
+
8
+ export default defineMessages({
9
+ header: {
10
+ id: 'creatives.containersV2.ChannelTemplates.header',
11
+ defaultMessage: 'This is ChannelTemplates container !',
12
+ },
13
+ });
@@ -0,0 +1,34 @@
1
+ /*
2
+ *
3
+ * ChannelTemplates reducer
4
+ *
5
+ */
6
+
7
+ import { fromJS } from 'immutable';
8
+ import * as types from './constants';
9
+
10
+ const initialState = fromJS({
11
+ loadingTemplates: true,
12
+ smsTemplates: [],
13
+ emailTemplates: [],
14
+ wechatTemplates: [],
15
+ mobilepushTemplates: [],
16
+ });
17
+
18
+ function channelTemplatesReducer(state = initialState, action) {
19
+ const channelTemplates = `${action.channel}Templates`;
20
+ switch (action.type) {
21
+ case types.DEFAULT_ACTION:
22
+ return state;
23
+ case types.GET_TEMPLATES_REQUEST:
24
+ return state.set('loadingTemplates', true);
25
+ case types.GET_TEMPLATES_SUCESS:
26
+ return state.set('loadingTemplates', false).set(channelTemplates, action.templates);
27
+ case types.GET_TEMPLATES_FAILURE:
28
+ return state.set('loadingTemplates', false).set('error', action.error);
29
+ default:
30
+ return state;
31
+ }
32
+ }
33
+
34
+ export default channelTemplatesReducer;
@@ -0,0 +1,32 @@
1
+ import { take, takeLatest, call, put, cancel } from 'redux-saga/effects';
2
+ import { LOCATION_CHANGE } from 'react-router-redux';
3
+ import * as Api from '../../services/api';
4
+
5
+
6
+ import * as types from './constants';
7
+ // Individual exports for testing
8
+ export function* defaultSaga() {
9
+ // See example in v2Containers/HomePage/sagas.js
10
+ }
11
+ function* getTemplates(action) {
12
+ try {
13
+ const req = {
14
+ channel: action.channel,
15
+ queryParams: action.query,
16
+ };
17
+ const res = call(Api.getAllTemplates, req);
18
+ put({type: types.GET_TEMPLATES_SUCESS, templates: res.response, channel: action.channel});
19
+ } catch (error) {
20
+ put({type: types.GET_TEMPLATES_FAILURE, error});
21
+ }
22
+ }
23
+ function* getTemplatesWatcher() {
24
+ const watcher = yield takeLatest(types.GET_TEMPLATES_REQUEST, getTemplates);
25
+ yield take(LOCATION_CHANGE);
26
+ yield cancel(watcher);
27
+ }
28
+ // All sagas to be loaded
29
+ export default [
30
+ defaultSaga,
31
+ getTemplatesWatcher,
32
+ ];
@@ -0,0 +1,25 @@
1
+ import { createSelector } from 'reselect';
2
+
3
+ /**
4
+ * Direct selector to the channelTemplates state domain
5
+ */
6
+ const selectChannelTemplatesDomain = () => (state) => state.get('templates');
7
+
8
+ /**
9
+ * Other specific selectors
10
+ */
11
+
12
+
13
+ /**
14
+ * Default selector used by ChannelTemplates
15
+ */
16
+
17
+ const makeSelectChannelTemplates = () => createSelector(
18
+ selectChannelTemplatesDomain(),
19
+ (substate) => substate.toJS()
20
+ );
21
+
22
+ export default makeSelectChannelTemplates;
23
+ export {
24
+ selectChannelTemplatesDomain,
25
+ };
@@ -0,0 +1,82 @@
1
+ import { expectSaga } from "redux-saga-test-plan";
2
+ import { take, cancel, takeLatest } from "redux-saga/effects";
3
+ import * as matchers from "redux-saga-test-plan/matchers";
4
+ import { LOCATION_CHANGE } from "react-router-redux";
5
+ import { throwError } from "redux-saga-test-plan/providers";
6
+ import { createMockTask } from "redux-saga/utils";
7
+ import * as types from "../constants";
8
+ import { watchAiSuggestions, getAiSuggestions } from "../sagas";
9
+ import * as Api from "../../../../services/api";
10
+
11
+ describe("getAiSuggestions saga", () => {
12
+ it("Should handle valid response from api", () => {
13
+ const successCallback = () => {};
14
+ const failureCallback = () => {};
15
+ const action = {
16
+ type: types.GET_AI_SUGGESTIONS,
17
+ prompt: {},
18
+ successCallback,
19
+ failureCallback,
20
+ };
21
+ expectSaga(getAiSuggestions, action)
22
+ .provide([
23
+ [
24
+ matchers.call.fn(Api.getAiSuggestions),
25
+ {
26
+ success: true,
27
+ status: {
28
+ isError: false,
29
+ code: 200,
30
+ message: "success",
31
+ },
32
+ message: "Meta data fetched successfully",
33
+ response: {
34
+ "https://response.com": 1400,
35
+ },
36
+ },
37
+ ],
38
+ [matchers.call.fn(successCallback)],
39
+ ])
40
+ .run();
41
+ });
42
+
43
+ it("Should handles error thrown from api", () => {
44
+ const successCallback = () => {};
45
+ const failureCallback = () => {};
46
+ const action = {
47
+ type: types.GET_AI_SUGGESTIONS,
48
+ prompt: {},
49
+ successCallback,
50
+ failureCallback,
51
+ };
52
+ expectSaga(getAiSuggestions, action)
53
+ .provide([[matchers.call.fn(Api.getAiSuggestions), throwError()]])
54
+ .run();
55
+ });
56
+ });
57
+
58
+ describe("watchAiSuggestions saga", () => {
59
+ let generator = null;
60
+ beforeEach(() => {
61
+ generator = watchAiSuggestions();
62
+ });
63
+ it("Should handle valid response from api", () => {
64
+ const progress1 = generator.next();
65
+ const mockTask = takeLatest(types.GET_AI_SUGGESTIONS, getAiSuggestions);
66
+ expect(progress1.value).toEqual(mockTask);
67
+ const progress2 = generator.next();
68
+ expect(progress2.value).toEqual(take(LOCATION_CHANGE));
69
+ });
70
+
71
+ it("Should handle LOCATION_CHANGE action and cancel the watcher", () => {
72
+ generator = watchAiSuggestions();
73
+ const mockTask = createMockTask();
74
+
75
+ expect(generator.next().value).toEqual(
76
+ takeLatest(types.GET_AI_SUGGESTIONS, getAiSuggestions)
77
+ );
78
+ expect(generator.next(mockTask).value).toEqual(take(LOCATION_CHANGE));
79
+ expect(generator.next().value).toEqual(cancel(mockTask));
80
+ expect(generator.next().done).toEqual(true);
81
+ });
82
+ });
@@ -98,7 +98,7 @@ export class TagList extends React.Component { // eslint-disable-line react/pref
98
98
  //Form tags object with tag headers
99
99
  _.forEach(tagsList, (temp) => {
100
100
  const tag = temp.definition;
101
- const { locale : userLocale } = this.props.intl;
101
+ const { locale : userLocale } = this.props?.intl || {};
102
102
  if (!tag['tag-header']) {
103
103
  mainTags[tag.value] = {
104
104
  "name": tag?.label[userLocale] ? tag?.label[userLocale] : tag?.label?.en,
@@ -29,7 +29,7 @@ import FTP from '../FTP';
29
29
  import Gallery from '../Assets/Gallery';
30
30
  import withStyles from '../../hoc/withStyles';
31
31
  import styles, { CapTabStyle } from './TemplatesV2.style';
32
- import { CREATIVES_UI_VIEW, LOYALTY, WHATSAPP, RCS, LINE, EMAIL, ASSETS, HIDE_FOR_JP_LOCALE } from '../App/constants';
32
+ import { CREATIVES_UI_VIEW, LOYALTY, WHATSAPP, RCS, LINE, EMAIL, ASSETS, JP_LOCALE_HIDE_FEATURE } from '../App/constants';
33
33
  import AccessForbidden from '../../v2Components/AccessForbidden';
34
34
  import { getObjFromQueryParams } from '../../utils/v2common';
35
35
  import { selectCurrentOrgDetails } from "../../v2Containers/Cap/selectors";
@@ -119,8 +119,8 @@ export class TemplatesV2 extends React.Component { // eslint-disable-line react/
119
119
  const { accessibleFeatures = [] } = currentOrgDetails || {};
120
120
  // This data will be available when it will be accessed in library mode
121
121
  const { currentOrgDetails: { accessibleFeatures: libModeAccessibleFeatures = [] } = {} } = cap || {};
122
- const hideEngagementChannel = accessibleFeatures.includes(HIDE_FOR_JP_LOCALE) || libModeAccessibleFeatures.includes(HIDE_FOR_JP_LOCALE);
123
- // Show only line and email channel content with both channel tabs if the HIDE_FOR_JP_LOCALE feature is enabled;
122
+ const hideEngagementChannel = accessibleFeatures.includes(JP_LOCALE_HIDE_FEATURE) || libModeAccessibleFeatures.includes(JP_LOCALE_HIDE_FEATURE);
123
+ // Show only line and email channel content with both channel tabs if the JP_LOCALE_HIDE_FEATURE feature is enabled;
124
124
  filteredPanes = hideEngagementChannel ? filteredPanes?.filter((pane) => [EMAIL, LINE, ASSETS].includes(pane?.key) && pane) : filteredPanes;
125
125
  defaultChannel = hideEngagementChannel ? EMAIL : defaultChannel;
126
126
 
@@ -599,7 +599,7 @@ export const authData = {
599
599
  "ENABLE_PRODUCT_SUPPORT_VIDEOS",
600
600
  "ENABLE_RANDOM_COUPON_CODE",
601
601
  "HIDE_DEFAULT_EMAIL_TEMPLATES",
602
- "HIDE_FOR_JP_LOCALE",
602
+ "JP_LOCALE_HIDE_FEATURE",
603
603
  ],
604
604
  org_loyalty_v2_status: true,
605
605
  module_details: [
@@ -680,6 +680,6 @@ export const currentOrgDetails = {
680
680
  "JOURNEY_UI",
681
681
  "LOYALTY_PROMOTION_ENABLED",
682
682
  "HIDE_DEFAULT_EMAIL_TEMPLATES",
683
- "HIDE_FOR_JP_LOCALE",
683
+ "JP_LOCALE_HIDE_FEATURE",
684
684
  ],
685
685
  };