@capillarytech/creatives-library 9.0.37-alpha.0 → 9.0.37

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 (29) hide show
  1. package/package.json +1 -1
  2. package/translations/en.json +2 -2
  3. package/v2Components/AccessForbidden/index.js +3 -5
  4. package/v2Components/AccessForbidden/messages.js +2 -3
  5. package/v2Containers/App/constants.js +0 -5
  6. package/v2Containers/Assets/Gallery/_gallery.scss +0 -6
  7. package/v2Containers/Assets/Gallery/index.js +10 -34
  8. package/v2Containers/Cap/index.js +2 -5
  9. package/v2Containers/Cap/messages.js +0 -4
  10. package/v2Containers/Cap/tests/__snapshots__/index.test.js.snap +2 -2
  11. package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/content.test.js.snap +6 -6
  12. package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/index.test.js.snap +4 -4
  13. package/v2Containers/Line/Container/Wrapper/tests/__snapshots__/index.test.js.snap +32 -32
  14. package/v2Containers/Line/Container/tests/__snapshots__/index.test.js.snap +36 -36
  15. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +118 -118
  16. package/v2Containers/SmsTrai/Create/tests/__snapshots__/index.test.js.snap +8 -8
  17. package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +18 -18
  18. package/v2Containers/Templates/ChannelTypeIllustration.js +1 -10
  19. package/v2Containers/Templates/_templates.scss +0 -6
  20. package/v2Containers/Templates/index.js +100 -141
  21. package/v2Containers/Templates/tests/ChannelTypeIllustration.test.js +0 -7
  22. package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +120 -173
  23. package/v2Containers/TemplatesV2/index.js +5 -16
  24. package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +268 -268
  25. package/utils/permissions.js +0 -59
  26. package/utils/tests/permissions.test.js +0 -116
  27. package/v2Components/AccessForbidden/_accessForbidden.scss +0 -14
  28. package/v2Components/NoPermissionWrapper/_noPermissionWrapper.scss +0 -12
  29. package/v2Components/NoPermissionWrapper/index.js +0 -26
@@ -1,59 +0,0 @@
1
- import {
2
- CREATIVE_VIEW,
3
- CREATIVE_CREATE,
4
- CREATIVE_EDIT,
5
- CREATIVE_DELETE,
6
- CREATIVES_UI_VIEW,
7
- } from '../v2Containers/App/constants';
8
-
9
- export const PERMISSIONS = {
10
- CREATIVE_VIEW,
11
- CREATIVE_CREATE,
12
- CREATIVE_EDIT,
13
- CREATIVE_DELETE,
14
- };
15
-
16
- export const PERMISSION_IDS = {
17
- [CREATIVE_VIEW]: 1508,
18
- [CREATIVE_CREATE]: 1509,
19
- [CREATIVE_EDIT]: 1510,
20
- [CREATIVE_DELETE]: 1511,
21
- };
22
-
23
- /**
24
- * Mode-aware access resolver for the tri-modal Creatives app.
25
- * Standalone: the `cap` slice is passed as a prop by the connected container.
26
- * Library / MFE: the host passes a `cap` (or legacy `Global`) prop.
27
- * Reads the prop first, then falls back — mirrors TemplatesV2's existing
28
- * `cap.user || Global.user` resolution.
29
- */
30
- export const getUserAccess = (props = {}) => {
31
- const { cap = {}, Global = {} } = props;
32
- const user = (cap && cap.user) || (Global && Global.user) || {};
33
- const isLoaded = !!(
34
- user &&
35
- typeof user === 'object' &&
36
- Object.keys(user).length > 0
37
- );
38
- return {
39
- accessiblePermissions: (isLoaded && user.accessiblePermissions) || [],
40
- isLoaded,
41
- };
42
- };
43
-
44
- export const hasPermission = (userAccess, code) => {
45
- if (!userAccess) return false;
46
- const granted = userAccess.accessiblePermissions || [];
47
- const id = PERMISSION_IDS[code];
48
- return (
49
- granted.includes(code) ||
50
- granted.includes(id) ||
51
- granted.includes(String(id))
52
- );
53
- };
54
-
55
- // Zero-impact view gate: honour the new CREATIVE_VIEW OR the legacy CREATIVES_UI_VIEW.
56
- export const canViewCreatives = userAccess =>
57
- hasPermission(userAccess, CREATIVE_VIEW) ||
58
- (userAccess &&
59
- (userAccess.accessiblePermissions || []).includes(CREATIVES_UI_VIEW));
@@ -1,116 +0,0 @@
1
- /**
2
- * Test suite for RBAC permission helpers (app/utils/permissions.js).
3
- * Covers getUserAccess (loaded/unloaded, cap vs Global, missing perms),
4
- * hasPermission (null guard, code/id/string-id match, empty), and
5
- * canViewCreatives (new perm, legacy perm, null guard).
6
- */
7
- import {
8
- PERMISSIONS,
9
- PERMISSION_IDS,
10
- getUserAccess,
11
- hasPermission,
12
- canViewCreatives,
13
- } from '../permissions';
14
- import {
15
- CREATIVE_VIEW,
16
- CREATIVE_CREATE,
17
- CREATIVE_EDIT,
18
- CREATIVE_DELETE,
19
- CREATIVES_UI_VIEW,
20
- } from '../../v2Containers/App/constants';
21
-
22
- describe('permissions - exported maps', () => {
23
- it('exposes the four creative permission codes', () => {
24
- expect(PERMISSIONS).toEqual({
25
- CREATIVE_VIEW,
26
- CREATIVE_CREATE,
27
- CREATIVE_EDIT,
28
- CREATIVE_DELETE,
29
- });
30
- });
31
-
32
- it('maps each permission code to its id', () => {
33
- expect(PERMISSION_IDS[CREATIVE_VIEW]).toBe(1508);
34
- expect(PERMISSION_IDS[CREATIVE_CREATE]).toBe(1509);
35
- expect(PERMISSION_IDS[CREATIVE_EDIT]).toBe(1510);
36
- expect(PERMISSION_IDS[CREATIVE_DELETE]).toBe(1511);
37
- });
38
- });
39
-
40
- describe('getUserAccess', () => {
41
- it('returns unloaded access with empty perms when no props are passed', () => {
42
- expect(getUserAccess()).toEqual({ accessiblePermissions: [], isLoaded: false });
43
- });
44
-
45
- it('returns unloaded access for an empty props object', () => {
46
- expect(getUserAccess({})).toEqual({ accessiblePermissions: [], isLoaded: false });
47
- });
48
-
49
- it('reads accessiblePermissions from cap.user when loaded', () => {
50
- const result = getUserAccess({ cap: { user: { accessiblePermissions: [1508, 1509] } } });
51
- expect(result).toEqual({ accessiblePermissions: [1508, 1509], isLoaded: true });
52
- });
53
-
54
- it('falls back to Global.user when cap.user is absent', () => {
55
- const result = getUserAccess({ Global: { user: { accessiblePermissions: ['CREATIVE_VIEW'] } } });
56
- expect(result).toEqual({ accessiblePermissions: ['CREATIVE_VIEW'], isLoaded: true });
57
- });
58
-
59
- it('is not loaded when the user object is empty', () => {
60
- expect(getUserAccess({ cap: { user: {} } })).toEqual({ accessiblePermissions: [], isLoaded: false });
61
- });
62
-
63
- it('defaults accessiblePermissions to [] when a loaded user has none', () => {
64
- const result = getUserAccess({ cap: { user: { id: 42 } } });
65
- expect(result).toEqual({ accessiblePermissions: [], isLoaded: true });
66
- });
67
- });
68
-
69
- describe('hasPermission', () => {
70
- it('returns false when userAccess is null or undefined', () => {
71
- expect(hasPermission(null, CREATIVE_VIEW)).toBe(false);
72
- expect(hasPermission(undefined, CREATIVE_VIEW)).toBe(false);
73
- });
74
-
75
- it('returns false when accessiblePermissions is missing', () => {
76
- expect(hasPermission({}, CREATIVE_VIEW)).toBe(false);
77
- });
78
-
79
- it('matches by permission code', () => {
80
- expect(hasPermission({ accessiblePermissions: [CREATIVE_CREATE] }, CREATIVE_CREATE)).toBe(true);
81
- });
82
-
83
- it('matches by numeric permission id', () => {
84
- expect(hasPermission({ accessiblePermissions: [1509] }, CREATIVE_CREATE)).toBe(true);
85
- });
86
-
87
- it('matches by string permission id', () => {
88
- expect(hasPermission({ accessiblePermissions: ['1509'] }, CREATIVE_CREATE)).toBe(true);
89
- });
90
-
91
- it('returns false when the permission is not granted', () => {
92
- expect(hasPermission({ accessiblePermissions: [CREATIVE_VIEW] }, CREATIVE_DELETE)).toBe(false);
93
- expect(hasPermission({ accessiblePermissions: [] }, CREATIVE_VIEW)).toBe(false);
94
- });
95
- });
96
-
97
- describe('canViewCreatives', () => {
98
- it('allows when the new CREATIVE_VIEW permission is present', () => {
99
- expect(canViewCreatives({ accessiblePermissions: [CREATIVE_VIEW] })).toBe(true);
100
- expect(canViewCreatives({ accessiblePermissions: [1508] })).toBe(true);
101
- });
102
-
103
- it('allows via the legacy CREATIVES_UI_VIEW permission', () => {
104
- expect(canViewCreatives({ accessiblePermissions: [CREATIVES_UI_VIEW] })).toBe(true);
105
- });
106
-
107
- it('returns a falsy value when userAccess is null', () => {
108
- // short-circuits on `userAccess &&`, so returns null (falsy) rather than false
109
- expect(canViewCreatives(null)).toBeFalsy();
110
- });
111
-
112
- it('returns false when neither view permission is present', () => {
113
- expect(canViewCreatives({ accessiblePermissions: [CREATIVE_CREATE] })).toBe(false);
114
- expect(canViewCreatives({})).toBe(false);
115
- });
116
- });
@@ -1,14 +0,0 @@
1
- // Access-denied screen: rbac-lock icon + heading + subtext (matches the shared
2
- // "no access" screen used across Loyalty+ / Org Settings).
3
- .no-access-icon {
4
- font-size: 48px;
5
- color: #8c8c8c;
6
- }
7
- .no-access-title {
8
- margin-top: 16px;
9
- }
10
- .no-access-text {
11
- margin-top: 8px;
12
- color: #6b778c;
13
- max-width: 420px;
14
- }
@@ -1,12 +0,0 @@
1
- // Dim + block interaction for a control the user lacks permission for.
2
- // The wrapper keeps pointer events (so the CapTooltip still shows on hover) while the
3
- // inner control is dimmed and non-interactive.
4
- .rbac-no-permission {
5
- display: inline-block;
6
- cursor: not-allowed;
7
-
8
- > * {
9
- opacity: 0.4;
10
- pointer-events: none;
11
- }
12
- }
@@ -1,26 +0,0 @@
1
- import React from 'react';
2
- import { FormattedMessage } from 'react-intl';
3
- import CapTooltip from '@capillarytech/cap-ui-library/CapTooltip';
4
- import globalMessages from '../../v2Containers/Cap/messages';
5
- import './_noPermissionWrapper.scss';
6
-
7
- // Wraps a single control and, when the user is not `allowed`, dims it + blocks
8
- // interaction (via CSS) and shows a permission tooltip on hover. Uses CapTooltip
9
- // instead of hand-rolled positioning/portals.
10
- const NoPermissionWrapper = ({ allowed, children, message }) => {
11
- const child = React.Children.only(children);
12
-
13
- if (allowed || child.props.disabled) {
14
- return child;
15
- }
16
-
17
- return (
18
- <CapTooltip
19
- title={message || <FormattedMessage {...globalMessages.noPermissionAction} />}
20
- >
21
- <span className="rbac-no-permission">{child}</span>
22
- </CapTooltip>
23
- );
24
- };
25
-
26
- export default NoPermissionWrapper;