@capillarytech/creatives-library 7.14.38 → 7.14.41

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.
Files changed (37) hide show
  1. package/package.json +1 -1
  2. package/reducers.js +2 -0
  3. package/services/api.js +9 -1
  4. package/tests/integration/TemplateCreation/TemplateCreation.integration.test.js +420 -0
  5. package/tests/integration/TemplateCreation/api-response.js +1663 -0
  6. package/tests/integration/TemplateCreation/helper.js +23 -0
  7. package/tests/integration/TemplateCreation/mocks/initialState.js +428 -0
  8. package/tests/integration/TemplateCreation/msw-handler.js +48 -0
  9. package/v2Components/CapActionButton/index.js +1 -0
  10. package/v2Components/FormBuilder/index.js +28 -4
  11. package/v2Containers/Assets/Gallery/index.js +1 -1
  12. package/v2Containers/CreativesContainer/constants.js +2 -0
  13. package/v2Containers/CreativesContainer/selectors.js +2 -2
  14. package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +8 -0
  15. package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/content.test.js.snap +3 -0
  16. package/v2Containers/Line/Container/Text/index.js +3 -2
  17. package/v2Containers/Line/Container/Wrapper/tests/__snapshots__/index.test.js.snap +4 -0
  18. package/v2Containers/Line/Container/index.js +1 -1
  19. package/v2Containers/Rcs/index.js +3 -0
  20. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +250 -3
  21. package/v2Containers/Sms/Create/actions.js +9 -0
  22. package/v2Containers/Sms/Create/constants.js +2 -0
  23. package/v2Containers/Sms/Create/index.js +12 -0
  24. package/v2Containers/Sms/Create/sagas.js +19 -3
  25. package/v2Containers/Sms/Create/tests/sagas.test.js +82 -0
  26. package/v2Containers/Templates/index.js +26 -11
  27. package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +96 -80
  28. package/v2Containers/TemplatesV2/index.js +1 -1
  29. package/v2Containers/Viber/index.js +1 -0
  30. package/v2Containers/Whatsapp/constants.js +27 -8
  31. package/v2Containers/Whatsapp/index.js +14 -2
  32. package/v2Containers/Whatsapp/messages.js +21 -4
  33. package/v2Containers/Whatsapp/styles.scss +3 -0
  34. package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +180 -128
  35. package/v2Containers/Whatsapp/tests/utils.test.js +1 -1
  36. package/v2Containers/Whatsapp/utils.js +2 -1
  37. package/v2Containers/mockdata.js +5 -5
@@ -25,3 +25,12 @@ export function defaultAction() {
25
25
  type: types.DEFAULT_ACTION,
26
26
  };
27
27
  }
28
+
29
+ export function getAiSuggestions(prompt, successCallback, failureCallback) {
30
+ return {
31
+ type: types.GET_AI_SUGGESTIONS,
32
+ prompt,
33
+ successCallback,
34
+ failureCallback,
35
+ };
36
+ }
@@ -14,3 +14,5 @@ export const CREATE_TEMPLATE_FAILURE = 'app/v2Containers/Sms/Create/CREATE_TEMPL
14
14
  export const CLEAR_CREATE_RESPONSE_REQUEST = 'app/v2Containers/Sms/Create/CLEAR_CREATE_RESPONSE_REQUEST';
15
15
  export const CLEAR_CREATE_RESPONSE_SUCCESS = 'app/v2Containers/Sms/Create/CLEAR_CREATE_RESPONSE_SUCCESS';
16
16
  export const CLEAR_CREATE_RESPONSE_FAILURE = 'app/v2Containers/Sms/Create/CLEAR_CREATE_RESPONSE_FAILURE';
17
+
18
+ export const GET_AI_SUGGESTIONS = 'app/v2Containers/Sms/Create/GET_AI_SUGGESTIONS';
@@ -900,6 +900,17 @@ export class Create extends React.Component { // eslint-disable-line react/prefe
900
900
  stopValidation = () => {
901
901
  this.setState({startValidation: false});
902
902
  }
903
+
904
+ getAiSuggestions = (prompt) => {
905
+ return new Promise((resolve, reject) => {
906
+ this.props.actions.getAiSuggestions(prompt, (result) => {
907
+ resolve(result);
908
+ }, (error) => {
909
+ reject(error);
910
+ })
911
+ })
912
+ }
913
+
903
914
  saveFormData() {
904
915
  //Logic to save in db etc
905
916
  const formData = _.cloneDeep(this.state.formData);
@@ -989,6 +1000,7 @@ export class Create extends React.Component { // eslint-disable-line react/prefe
989
1000
  selectedOfferDetails={this.props.selectedOfferDetails}
990
1001
  onTestContentClicked={this.props.onTestContentClicked}
991
1002
  onPreviewContentClicked={this.props.onPreviewContentClicked}
1003
+ fetchAiSuggestions={this.getAiSuggestions}
992
1004
  />
993
1005
  </CapColumn>
994
1006
  </CapRow>
@@ -29,7 +29,23 @@ function* watchCreateTemplate() {
29
29
  yield cancel(watcher);
30
30
  }
31
31
 
32
+ export function* getAiSuggestions({ prompt, successCallback, failureCallback }) {
33
+ try {
34
+ const result = yield call(Api.getAiSuggestions, {prompt});
35
+ yield successCallback(result);
36
+ } catch (error) {
37
+ yield failureCallback(error);
38
+ }
39
+ }
40
+
41
+ export function* watchAiSuggestions() {
42
+ const watcher = yield takeLatest(
43
+ types.GET_AI_SUGGESTIONS,
44
+ getAiSuggestions
45
+ );
46
+ yield take(LOCATION_CHANGE);
47
+ yield cancel(watcher);
48
+ }
49
+
32
50
  // All sagas to be loaded
33
- export default [
34
- watchCreateTemplate,
35
- ];
51
+ export default [watchCreateTemplate, watchAiSuggestions];
@@ -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
+ });
@@ -95,7 +95,8 @@ import {
95
95
  TWILIO_CATEGORY_OPTIONS,
96
96
  KARIX_GUPSHUP_CATEGORY_OPTIONS,
97
97
  STATUS_OPTIONS,
98
- CATEGORY as WHATSAPP_CATEGORY,
98
+ CATEGORY,
99
+ WHATSAPP_CATEGORIES,
99
100
  STATUS as WHATSAPP_STATUS,
100
101
  WHATSAPP_STATUSES,
101
102
  HOST_TWILIO,
@@ -786,19 +787,33 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
786
787
  }
787
788
  return true;
788
789
  }
789
-
790
+ isCategoryMatching(category, selectedWhatsappCategory) {
791
+ const {utility, transactional, authentication, otp } = WHATSAPP_CATEGORIES;
792
+ if (selectedWhatsappCategory) {
793
+ switch (selectedWhatsappCategory) {
794
+ // older karix & gupshup category, supporting for older template filter in listing page
795
+ case utility: {
796
+ return [selectedWhatsappCategory, transactional].includes(category);
797
+ }
798
+ case authentication: {
799
+ return [selectedWhatsappCategory, otp].includes(category);
800
+ }
801
+ default:
802
+ return selectedWhatsappCategory === category;
803
+ }
804
+ }
805
+ return true;
806
+ }
790
807
  filterWhatsappTemplates = (templates) => {
791
808
  const { selectedWhatsappStatus, selectedWhatsappCategory } = this.state;
792
809
  return templates.filter((template) => {
793
- const { [WHATSAPP_CATEGORY]: category, [WHATSAPP_STATUS]: status } = template?.versions?.base?.content?.[WHATSAPP_LOWERCASE] || {};
810
+ const { [CATEGORY]: category, [WHATSAPP_STATUS]: status } = template?.versions?.base?.content?.[WHATSAPP_LOWERCASE] || {};
794
811
 
795
812
  // if status or category filter is applied, filter templates which match these filters
796
813
  return (
797
814
  this.isStatusMatching(status, selectedWhatsappStatus)
798
815
  ) && (
799
- selectedWhatsappCategory
800
- ? category === selectedWhatsappCategory
801
- : true
816
+ this.isCategoryMatching(category, selectedWhatsappCategory)
802
817
  );
803
818
  });
804
819
  }
@@ -855,8 +870,8 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
855
870
  />
856
871
  );
857
872
 
858
- getTemplateDataForGrid = ({templates=[], handlers, filterContent, channel, isLoading, loadingTip}) => {
859
- const currentChannel = channel.toUpperCase();
873
+ getTemplateDataForGrid = ({templates = [], handlers, filterContent, channel, isLoading, loadingTip}) => {
874
+ const currentChannel = channel.toUpperCase();
860
875
  const {channel: stateChannel} = this.state;
861
876
  const channelLowerCase = stateChannel.toLowerCase();
862
877
  let filteredTemplates = templates;
@@ -2358,7 +2373,7 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
2358
2373
  case WHATSAPP_STATUS:
2359
2374
  this.setState({ selectedWhatsappStatus: null });
2360
2375
  break;
2361
- case WHATSAPP_CATEGORY:
2376
+ case CATEGORY:
2362
2377
  this.setState({ selectedWhatsappCategory: null });
2363
2378
  break;
2364
2379
  default:
@@ -2384,7 +2399,7 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
2384
2399
  }
2385
2400
  {
2386
2401
  selectedWhatsappCategory ? (
2387
- <CapTag closable onClose={() => this.removeWhatsappFilter(WHATSAPP_CATEGORY)}>
2402
+ <CapTag closable onClose={() => this.removeWhatsappFilter(CATEGORY)}>
2388
2403
  {formatMessage(messages.category)}: {getWhatsappCategory(selectedWhatsappCategory, this.state.hostName)?.label || selectedWhatsappCategory}
2389
2404
  </CapTag>
2390
2405
  ) : null
@@ -2394,7 +2409,7 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
2394
2409
  <CapLink
2395
2410
  onClick={() => {
2396
2411
  this.removeWhatsappFilter(WHATSAPP_STATUS);
2397
- this.removeWhatsappFilter(WHATSAPP_CATEGORY);
2412
+ this.removeWhatsappFilter(CATEGORY);
2398
2413
  }}
2399
2414
  title={this.props.intl.formatMessage(messages.clearAll)}
2400
2415
  />