@capillarytech/creatives-library 7.17.211 → 7.17.212
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/containers/App/index.js +52 -0
- package/entry.js +2 -0
- package/hoc/withReactRouterV3Compatibility.js +66 -0
- package/initialReducer.js +34 -0
- package/mfe-exposed-components.js +8 -0
- package/package.json +1 -1
- package/utils/checkStore.js +21 -0
- package/utils/customAuthWrapper.js +62 -0
- package/utils/customConnectedAuthWrapper.js +26 -0
- package/utils/history.js +8 -0
- package/utils/injectReducer.js +2 -0
- package/utils/injectSaga.js +2 -0
- package/v2Components/FormBuilder/index.js +1 -1
- package/v2Components/NavigationBar/saga.js +18 -0
- package/v2Components/RenderRoute/RenderRoute.js +11 -0
- package/v2Components/RenderRoute/index.js +1 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* App.js
|
|
4
|
+
*
|
|
5
|
+
* This component is the skeleton around the actual pages, and should only
|
|
6
|
+
* contain code that should be seen on all pages. (e.g. navigation bar)
|
|
7
|
+
*
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import React, { useEffect } from 'react'; // eslint-disable-line no-unused-vars
|
|
11
|
+
import { Switch } from 'react-router';
|
|
12
|
+
import { ConnectedRouter } from 'connected-react-router/immutable';
|
|
13
|
+
import history from 'utils/history';
|
|
14
|
+
|
|
15
|
+
import Cap from '../Cap';
|
|
16
|
+
import CapV2 from '../../v2Containers/Cap';
|
|
17
|
+
import Login from '../Login';
|
|
18
|
+
import NotFoundPage from '../NotFoundPage';
|
|
19
|
+
|
|
20
|
+
import GlobalStyle from '../../global-styles';
|
|
21
|
+
import config from '../../config/app';
|
|
22
|
+
import withReactRouterV3Compatibility from '../../hoc/withReactRouterV3Compatibility';
|
|
23
|
+
import RenderRoute from '../../v2Components/RenderRoute';
|
|
24
|
+
import { updateCharCount } from '../../utils/smsCharCountV2';
|
|
25
|
+
|
|
26
|
+
const loginUrl =
|
|
27
|
+
process.env.NODE_ENV === 'production'
|
|
28
|
+
? `${config.production.login_url}`
|
|
29
|
+
: `${config.development.login_url}`;
|
|
30
|
+
|
|
31
|
+
// const Protected = userIsAuthenticatedRedir(Cap);
|
|
32
|
+
const v3CompatibleCap = withReactRouterV3Compatibility(Cap);
|
|
33
|
+
const v3CompatibleCapV2 = withReactRouterV3Compatibility(CapV2);
|
|
34
|
+
|
|
35
|
+
export default function App() {
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
updateCharCount("", false);
|
|
38
|
+
});
|
|
39
|
+
return (
|
|
40
|
+
<div>
|
|
41
|
+
<ConnectedRouter history={history}>
|
|
42
|
+
<Switch>
|
|
43
|
+
<RenderRoute exact path={loginUrl} component={Login} />
|
|
44
|
+
<RenderRoute path="/v2" component={v3CompatibleCapV2} key="/v2" />
|
|
45
|
+
<RenderRoute path="/" component={v3CompatibleCap} key="/" />
|
|
46
|
+
<RenderRoute component={NotFoundPage} />
|
|
47
|
+
</Switch>
|
|
48
|
+
</ConnectedRouter>
|
|
49
|
+
<GlobalStyle />
|
|
50
|
+
</div>
|
|
51
|
+
);
|
|
52
|
+
}
|
package/entry.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import { compose } from 'redux';
|
|
4
|
+
import { withRouter } from 'react-router-dom';
|
|
5
|
+
import componentRoutes from '../routes';
|
|
6
|
+
|
|
7
|
+
function findRoute(routes, path) {
|
|
8
|
+
let match;
|
|
9
|
+
for (let i = 0; i < routes.length; i++) {
|
|
10
|
+
const route = routes[i];
|
|
11
|
+
if (route?.path === path) {
|
|
12
|
+
match = route;
|
|
13
|
+
break;
|
|
14
|
+
}
|
|
15
|
+
if (route?.routes) {
|
|
16
|
+
match = findRoute(route.routes, path);
|
|
17
|
+
if (match) {
|
|
18
|
+
break;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return match;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function getParamsObject(params = []) {
|
|
26
|
+
const paramsObject = {};
|
|
27
|
+
params.forEach((value, key) => {
|
|
28
|
+
if (paramsObject[key]) {
|
|
29
|
+
// If the key already exists, convert the value to an array (to handle multiple values for the same key)
|
|
30
|
+
paramsObject[key] = Array.isArray(paramsObject[key])
|
|
31
|
+
? [...paramsObject[key], value]
|
|
32
|
+
: [paramsObject[key], value];
|
|
33
|
+
} else {
|
|
34
|
+
paramsObject[key] = value;
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
return paramsObject;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function withReactRouterV3Compatibility(Component) {
|
|
41
|
+
const EnhancedComponent = (props) => {
|
|
42
|
+
const { history = {}, location = {}, match = {} } = props;
|
|
43
|
+
const matchedRoute = findRoute(componentRoutes, match.path);
|
|
44
|
+
const newProps = {
|
|
45
|
+
...props,
|
|
46
|
+
router: history,
|
|
47
|
+
params: match.params,
|
|
48
|
+
route: matchedRoute,
|
|
49
|
+
location: {
|
|
50
|
+
...location,
|
|
51
|
+
query: getParamsObject(new URLSearchParams(location.search)),
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
return <Component {...newProps} />;
|
|
55
|
+
};
|
|
56
|
+
EnhancedComponent.propTypes = {
|
|
57
|
+
router: PropTypes.object,
|
|
58
|
+
params: PropTypes.object,
|
|
59
|
+
route: PropTypes.object,
|
|
60
|
+
};
|
|
61
|
+
return compose(
|
|
62
|
+
withRouter,
|
|
63
|
+
)(EnhancedComponent);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export default withReactRouterV3Compatibility;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import languageProviderReducer from 'v2Containers/LanguageProvider/reducer';
|
|
2
|
+
import beeEditorReducer from 'v2Containers/BeeEditor/reducer';
|
|
3
|
+
import CapFacebookPreviewReducer from 'v2Containers/CapFacebookPreview/reducer';
|
|
4
|
+
|
|
5
|
+
import capReducer from 'containers/Cap/reducer';
|
|
6
|
+
import appReducer from 'containers/App/reducer';
|
|
7
|
+
import createSmsReducer from 'containers/Sms/Create/reducer';
|
|
8
|
+
import editSmsReducer from 'containers/Sms/Edit/reducer';
|
|
9
|
+
import templateReducer from 'containers/Templates/reducer';
|
|
10
|
+
import tagsReducer from 'containers/TagList/reducer';
|
|
11
|
+
import emailReducer from 'containers/Email/reducer';
|
|
12
|
+
import ebillReducer from 'containers/Ebill/reducer';
|
|
13
|
+
import ftpReducer from 'v2Containers/FTP/reducer';
|
|
14
|
+
import galleryReducer from './v2Containers/Assets/Gallery/reducer';
|
|
15
|
+
import CapCollapsibleLeftNavigationReducer from '@capillarytech/cap-ui-library/CapCollapsibleLeftNavigation/reducer';
|
|
16
|
+
import { AIRA_REDUCER_DOMAIN, askAiraReducer } from '@capillarytech/cap-ui-library/CapAskAira';
|
|
17
|
+
|
|
18
|
+
export const initialReducer = {
|
|
19
|
+
language: languageProviderReducer,
|
|
20
|
+
cap: capReducer,
|
|
21
|
+
app: appReducer,
|
|
22
|
+
create: createSmsReducer,
|
|
23
|
+
edit: editSmsReducer,
|
|
24
|
+
templates: templateReducer,
|
|
25
|
+
tagList: tagsReducer,
|
|
26
|
+
email: emailReducer,
|
|
27
|
+
ebill: ebillReducer,
|
|
28
|
+
beeEditor: beeEditorReducer,
|
|
29
|
+
facebookPreview: CapFacebookPreviewReducer,
|
|
30
|
+
FTP: ftpReducer,
|
|
31
|
+
[AIRA_REDUCER_DOMAIN]: askAiraReducer,
|
|
32
|
+
gallery: galleryReducer,
|
|
33
|
+
navigationConfig: CapCollapsibleLeftNavigationReducer,
|
|
34
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// This file is used to expose the components of the MFE to the host application
|
|
2
|
+
// Contents of this file are used in webpack config's ModuleFederationPlugin.
|
|
3
|
+
//
|
|
4
|
+
module.exports = {
|
|
5
|
+
// which exposes
|
|
6
|
+
// ADD MFE COMPONENT YOU WANT TO EXPORT example:
|
|
7
|
+
// './Home': './app/components/pages/Home',
|
|
8
|
+
};
|
package/package.json
CHANGED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { conformsTo, isFunction, isObject } from 'lodash';
|
|
2
|
+
import invariant from 'invariant';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Validate the shape of redux store
|
|
6
|
+
*/
|
|
7
|
+
export default function checkStore(store) {
|
|
8
|
+
const shape = {
|
|
9
|
+
dispatch: isFunction,
|
|
10
|
+
subscribe: isFunction,
|
|
11
|
+
getState: isFunction,
|
|
12
|
+
replaceReducer: isFunction,
|
|
13
|
+
runSaga: isFunction,
|
|
14
|
+
injectedReducers: isObject,
|
|
15
|
+
injectedSagas: isObject,
|
|
16
|
+
};
|
|
17
|
+
invariant(
|
|
18
|
+
conformsTo(store, shape),
|
|
19
|
+
'(app/utils...) injectors: Expected a valid redux store',
|
|
20
|
+
);
|
|
21
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/* eslint-disable no-unused-vars */
|
|
2
|
+
/* eslint-disable react/no-multi-comp */
|
|
3
|
+
/* eslint-disable react/prefer-stateless-function */
|
|
4
|
+
import React, { Component } from 'react';
|
|
5
|
+
import PropTypes from 'prop-types';
|
|
6
|
+
import hoistStatics from 'hoist-non-react-statics';
|
|
7
|
+
|
|
8
|
+
const AuthenticatingComponentWithRef = React.forwardRef((props, ref) => (
|
|
9
|
+
<div ref={ref} />
|
|
10
|
+
));
|
|
11
|
+
const FailureComponentWithRef = React.forwardRef((props, ref) => (
|
|
12
|
+
<div ref={ref} />
|
|
13
|
+
));
|
|
14
|
+
const defaults = {
|
|
15
|
+
AuthenticatingComponent: AuthenticatingComponentWithRef, // dont render anything while authenticating
|
|
16
|
+
FailureComponent: FailureComponentWithRef, // dont render anything on failure of the predicate
|
|
17
|
+
wrapperDisplayName: 'AuthWrapper',
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export default args => {
|
|
21
|
+
const { AuthenticatingComponent, FailureComponent, wrapperDisplayName } = {
|
|
22
|
+
...defaults,
|
|
23
|
+
...args,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
// Wraps the component that needs the auth enforcement
|
|
27
|
+
return function wrapComponent(DecoratedComponent) {
|
|
28
|
+
const displayName =
|
|
29
|
+
DecoratedComponent.displayName || DecoratedComponent.name || 'Component';
|
|
30
|
+
|
|
31
|
+
class UserAuthWrapper extends Component {
|
|
32
|
+
static displayName = `${wrapperDisplayName}(${displayName})`;
|
|
33
|
+
|
|
34
|
+
static propTypes = {
|
|
35
|
+
isAuthenticated: PropTypes.bool,
|
|
36
|
+
isAuthenticating: PropTypes.bool,
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
static defaultProps = {
|
|
40
|
+
isAuthenticating: false,
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
render() {
|
|
44
|
+
const { isAuthenticated, isAuthenticating, forwardedRef } = this.props;
|
|
45
|
+
if (isAuthenticated) {
|
|
46
|
+
return <DecoratedComponent {...this.props} ref={forwardedRef} />;
|
|
47
|
+
}
|
|
48
|
+
if (isAuthenticating) {
|
|
49
|
+
return <AuthenticatingComponent {...this.props} ref={forwardedRef} />;
|
|
50
|
+
}
|
|
51
|
+
return <FailureComponent {...this.props} ref={forwardedRef} />;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** forwardRef from HOC to the Wrapped Component */
|
|
56
|
+
const UserAuthWrapperWithRef = React.forwardRef((props, ref) => (
|
|
57
|
+
<UserAuthWrapper {...props} forwardedRef={ref} />
|
|
58
|
+
));
|
|
59
|
+
|
|
60
|
+
return hoistStatics(UserAuthWrapperWithRef, DecoratedComponent);
|
|
61
|
+
};
|
|
62
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { connect } from 'react-redux';
|
|
2
|
+
|
|
3
|
+
import authWrapper from './customAuthWrapper';
|
|
4
|
+
|
|
5
|
+
const connectedDefaults = {
|
|
6
|
+
authenticatingSelector: () => false,
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export default args => {
|
|
10
|
+
const { authenticatedSelector, authenticatingSelector } = {
|
|
11
|
+
...connectedDefaults,
|
|
12
|
+
...args,
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
/** Passed withRef option set to true for forwarding Ref to Wrapped Component */
|
|
16
|
+
return DecoratedComponent =>
|
|
17
|
+
connect(
|
|
18
|
+
(state, ownProps) => ({
|
|
19
|
+
isAuthenticated: authenticatedSelector(state, ownProps),
|
|
20
|
+
isAuthenticating: authenticatingSelector(state, ownProps),
|
|
21
|
+
}),
|
|
22
|
+
null,
|
|
23
|
+
null,
|
|
24
|
+
{ withRef: true },
|
|
25
|
+
)(authWrapper(args)(DecoratedComponent));
|
|
26
|
+
};
|
package/utils/history.js
ADDED
|
@@ -134,7 +134,7 @@ class FormBuilder extends React.Component { // eslint-disable-line react/prefer-
|
|
|
134
134
|
this.handleSetRadioValue = this.handleSetRadioValue.bind(this);
|
|
135
135
|
this.formElements = [];
|
|
136
136
|
// Check if the liquid flow feature is supported and the channel is in the supported list.
|
|
137
|
-
this.liquidFlow =
|
|
137
|
+
this.liquidFlow = LIQUID_SUPPORTED_CHANNELS.includes(props?.schema?.channel?.toUpperCase()) && hasLiquidSupportFeature();
|
|
138
138
|
}
|
|
139
139
|
|
|
140
140
|
componentWillMount() {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { all } from 'redux-saga/effects';
|
|
2
|
+
import CapCollapsibleLeftNavigationSagas from '@capillarytech/cap-ui-library/CapCollapsibleLeftNavigation/saga';
|
|
3
|
+
import { analyticsBotSaga } from '@capillarytech/cap-ui-library/CapAskAira';
|
|
4
|
+
|
|
5
|
+
export default [
|
|
6
|
+
{
|
|
7
|
+
key: 'navigation',
|
|
8
|
+
saga: function* navigationConfigSaga() {
|
|
9
|
+
yield all(CapCollapsibleLeftNavigationSagas.map(saga => saga.call()));
|
|
10
|
+
},
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
key: 'analyticsBotSaga',
|
|
14
|
+
saga: function* analyticsBotSagaFn() {
|
|
15
|
+
yield all(analyticsBotSaga.map(saga => saga.call()));
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
];
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Route } from 'react-router-dom';
|
|
3
|
+
|
|
4
|
+
const RenderRoute = ({ Component: ComponentToRender, ...rest }) => (
|
|
5
|
+
<Route
|
|
6
|
+
{...rest}
|
|
7
|
+
render={props => <ComponentToRender {...props} />}
|
|
8
|
+
/>
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
export default RenderRoute;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './RenderRoute';
|