cozy-ui 116.0.0 → 117.1.0

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.
@@ -1,4 +1,3 @@
1
- import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
2
1
  import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
3
2
  import _createClass from "@babel/runtime/helpers/createClass";
4
3
  import _assertThisInitialized from "@babel/runtime/helpers/assertThisInitialized";
@@ -11,8 +10,6 @@ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (O
11
10
 
12
11
  function _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; }
13
12
 
14
- import _regeneratorRuntime from "@babel/runtime/regenerator";
15
-
16
13
  function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
17
14
 
18
15
  function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
@@ -20,20 +17,10 @@ function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Re
20
17
  import PropTypes from 'prop-types';
21
18
  import React from 'react';
22
19
  import { withClient } from 'cozy-client';
23
- import { checkApp, startApp, isMobileApp, isMobile, openDeeplinkOrRedirect, isAndroid, isFlagshipApp } from 'cozy-device-helper';
20
+ import { isFlagshipApp } from 'cozy-device-helper';
24
21
  import { WebviewContext } from 'cozy-intent';
25
22
  import logger from 'cozy-logger';
26
- import expiringMemoize from "cozy-ui/transpiled/react/AppLinker/expiringMemoize";
27
23
  import { generateUniversalLink, generateWebLink, getUniversalLinkDomain } from "cozy-ui/transpiled/react/AppLinker/native";
28
- import { NATIVE_APP_INFOS } from "cozy-ui/transpiled/react/AppLinker/native.config";
29
- var expirationDelay = 10 * 1000;
30
- var memoizedCheckApp = expiringMemoize(function (appInfo) {
31
- return checkApp(appInfo).catch(function () {
32
- return false;
33
- });
34
- }, expirationDelay, function (appInfo) {
35
- return appInfo.appId;
36
- });
37
24
  export var AppLinker = /*#__PURE__*/function (_React$Component) {
38
25
  _inherits(AppLinker, _React$Component);
39
26
 
@@ -47,8 +34,7 @@ export var AppLinker = /*#__PURE__*/function (_React$Component) {
47
34
  _this = _super.call(this, props);
48
35
 
49
36
  _defineProperty(_assertThisInitialized(_this), "state", {
50
- nativeAppIsAvailable: null,
51
- isFetchingAppInfo: false
37
+ imgRef: null
52
38
  });
53
39
 
54
40
  _defineProperty(_assertThisInitialized(_this), "setImgRef", function (img) {
@@ -59,105 +45,36 @@ export var AppLinker = /*#__PURE__*/function (_React$Component) {
59
45
  });
60
46
  });
61
47
 
62
- _this.imgRef = null;
63
48
  return _this;
64
49
  }
65
50
 
66
51
  _createClass(AppLinker, [{
67
- key: "componentDidMount",
68
- value: function componentDidMount() {
69
- if (isMobileApp()) {
70
- this.checkAppAvailability();
71
- }
72
- }
73
- }, {
74
- key: "checkAppAvailability",
75
- value: function () {
76
- var _checkAppAvailability = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
77
- var slug, appInfo, nativeAppIsAvailable;
78
- return _regeneratorRuntime.wrap(function _callee$(_context) {
79
- while (1) {
80
- switch (_context.prev = _context.next) {
81
- case 0:
82
- slug = AppLinker.getSlug(this.props);
83
- appInfo = NATIVE_APP_INFOS[slug];
84
-
85
- if (!appInfo) {
86
- _context.next = 9;
87
- break;
88
- }
89
-
90
- _context.t0 = Boolean;
91
- _context.next = 6;
92
- return memoizedCheckApp(appInfo);
93
-
94
- case 6:
95
- _context.t1 = _context.sent;
96
- nativeAppIsAvailable = (0, _context.t0)(_context.t1);
97
- this.setState({
98
- nativeAppIsAvailable: nativeAppIsAvailable
99
- });
100
-
101
- case 9:
102
- case "end":
103
- return _context.stop();
104
- }
105
- }
106
- }, _callee, this);
107
- }));
108
-
109
- function checkAppAvailability() {
110
- return _checkAppAvailability.apply(this, arguments);
111
- }
112
-
113
- return checkAppAvailability;
114
- }()
115
- }, {
116
52
  key: "render",
117
53
  value: function render() {
118
54
  var children = this.props.children;
119
- AppLinker.deprecateSlug(this.props);
120
- var slug = AppLinker.getSlug(this.props);
121
- var nativeAppIsAvailable = this.state.nativeAppIsAvailable;
122
- var appInfo = NATIVE_APP_INFOS[slug];
123
55
 
124
- var _AppLinker$getOnClick = AppLinker.getOnClickHref(this.props, nativeAppIsAvailable, this.context, this.state.imgRef),
56
+ var _AppLinker$getOnClick = AppLinker.getOnClickHref(this.props, this.context, this.state.imgRef),
125
57
  href = _AppLinker$getOnClick.href,
126
58
  onClick = _AppLinker$getOnClick.onClick;
127
59
 
128
- return children(_objectSpread(_objectSpread({}, appInfo), {}, {
60
+ return children({
129
61
  iconRef: this.setImgRef,
130
62
  onClick: onClick,
131
63
  href: href
132
- }));
64
+ });
133
65
  }
134
66
  }], [{
135
67
  key: "getSlug",
136
68
  value: function getSlug(props) {
137
- if (props.app && props.app.slug) {
138
- return props.app.slug;
139
- }
140
-
141
- return props.slug;
142
- }
143
- }, {
144
- key: "deprecateSlug",
145
- value: function deprecateSlug(props) {
146
- if (props.slug) {
147
- console.warn("AppLinker's 'slug' prop is deprecated, please use 'app.slug' instead");
148
- }
69
+ return props.app.slug;
149
70
  }
150
71
  }, {
151
72
  key: "getOnClickHref",
152
- value: function getOnClickHref(props, nativeAppIsAvailable, context, imgRef) {
73
+ value: function getOnClickHref(props, context, imgRef) {
153
74
  var app = props.app,
154
- client = props.client,
155
- nativePath = props.nativePath;
156
- var slug = AppLinker.getSlug(props);
75
+ client = props.client;
157
76
  var href = props.href;
158
77
  var onClick = null;
159
- var usingNativeApp = isMobileApp();
160
- var appInfo = NATIVE_APP_INFOS[slug];
161
78
 
162
79
  if (isFlagshipApp()) {
163
80
  var _ref = client ? client.getInstanceOptions() : undefined,
@@ -175,64 +92,11 @@ export var AppLinker = /*#__PURE__*/function (_React$Component) {
175
92
  }
176
93
  }
177
94
 
178
- if (usingNativeApp) {
179
- if (nativeAppIsAvailable) {
180
- // If we are on the native app and the other native app is available,
181
- // we open the native app
182
- onClick = AppLinker.openNativeFromNative.bind(this, props);
183
- href = '#';
184
- } else {
185
- // If we are on a native app, but the other native app is not available
186
- // we open the web link, this is done by the href prop. We still
187
- // have to call the prop callback
188
- onClick = AppLinker.openWeb.bind(this, props);
189
- }
190
- } else if (isMobile() && appInfo) {
191
- // If we are on the "mobile web version", we try to open the native app
192
- // if it exists with an universal links. If it fails, we redirect to the web
193
- // version of the requested app
194
- // Only on iOS ATM
195
- if (isAndroid()) {
196
- onClick = AppLinker.openNativeFromWeb.bind(this, props);
197
- } else {
198
- // Since generateUniversalLink can rise an error, let's catch it to not crash
199
- // all the page.
200
- try {
201
- href = generateUniversalLink({
202
- slug: slug,
203
- nativePath: nativePath,
204
- fallbackUrl: href
205
- });
206
- } catch (err) {
207
- console.error(err);
208
- href = '#';
209
- }
210
- }
211
- }
212
-
213
95
  return {
214
96
  href: href,
215
97
  onClick: onClick
216
98
  };
217
99
  }
218
- }, {
219
- key: "openNativeFromWeb",
220
- value: function openNativeFromWeb(props, ev) {
221
- var href = props.href,
222
- nativePath = props.nativePath,
223
- onAppSwitch = props.onAppSwitch;
224
- var slug = AppLinker.getSlug(props);
225
- var appInfo = NATIVE_APP_INFOS[slug];
226
-
227
- if (ev) {
228
- ev.preventDefault();
229
- }
230
-
231
- AppLinker.onAppSwitch(onAppSwitch);
232
- openDeeplinkOrRedirect(appInfo.uri + (nativePath === '/' ? '' : nativePath), function () {
233
- window.location.href = href;
234
- });
235
- }
236
100
  }, {
237
101
  key: "onAppSwitch",
238
102
  value: function onAppSwitch(onAppSwitchFn) {
@@ -240,22 +104,6 @@ export var AppLinker = /*#__PURE__*/function (_React$Component) {
240
104
  onAppSwitchFn();
241
105
  }
242
106
  }
243
- }, {
244
- key: "openNativeFromNative",
245
- value: function openNativeFromNative(props, ev) {
246
- var onAppSwitch = props.onAppSwitch;
247
- var slug = AppLinker.getSlug(props);
248
-
249
- if (ev) {
250
- ev.preventDefault();
251
- }
252
-
253
- var appInfo = NATIVE_APP_INFOS[slug];
254
- AppLinker.onAppSwitch(onAppSwitch);
255
- startApp(appInfo).catch(function (err) {
256
- console.error('AppLinker: Could not open native app', err);
257
- });
258
- }
259
107
  }, {
260
108
  key: "openWeb",
261
109
  value: function openWeb(props) {
@@ -268,34 +116,17 @@ export var AppLinker = /*#__PURE__*/function (_React$Component) {
268
116
 
269
117
  _defineProperty(AppLinker, "contextType", WebviewContext);
270
118
 
271
- AppLinker.defaultProps = {
272
- nativePath: '/'
273
- };
274
119
  AppLinker.propTypes = {
275
- /** DEPRECATED: please use app.slug prop */
276
- slug: PropTypes.string,
277
-
278
120
  /*
279
121
  Full web url : Used by default on desktop browser
280
122
  Used as a fallback_uri on mobile web
281
123
  */
282
124
  href: PropTypes.string,
283
-
284
- /*
285
- Path used for "native link"
286
- */
287
- nativePath: PropTypes.string,
288
125
  onAppSwitch: PropTypes.func,
289
126
  app: PropTypes.shape({
290
127
  // Slug of the app : drive / banks ...
291
- slug: PropTypes.string.isRequired,
292
- // Information about mobile native app
293
- mobile: PropTypes.shape({
294
- schema: PropTypes.string,
295
- id_playstore: PropTypes.string,
296
- id_appstore: PropTypes.string
297
- })
128
+ slug: PropTypes.string.isRequired
298
129
  }).isRequired
299
130
  };
300
131
  export default withClient(AppLinker);
301
- export { NATIVE_APP_INFOS, getUniversalLinkDomain, generateWebLink, generateUniversalLink };
132
+ export { getUniversalLinkDomain, generateWebLink, generateUniversalLink };
@@ -1,14 +1 @@
1
- import { isAndroidApp } from 'cozy-device-helper';
2
- export var NATIVE_APP_INFOS = {
3
- drive: {
4
- appId: 'io.cozy.drive.mobile',
5
- uri: 'cozydrive://',
6
- name: 'Cozy Drive'
7
- },
8
- banks: {
9
- appId: isAndroidApp() ? 'io.cozy.banks.mobile' : 'io.cozy.banks',
10
- uri: 'cozybanks://',
11
- name: 'Cozy Banks'
12
- }
13
- };
14
1
  export var UNIVERSAL_LINK_URL = 'https://links.mycozy.cloud';
@@ -1,25 +0,0 @@
1
- // Jest Snapshot v1, https://goo.gl/fbAQLP
2
-
3
- exports[`app icon should not crash if no href 1`] = `
4
- <div>
5
- <div>
6
- <a>
7
- Open
8
- Cozy Drive
9
- </a>
10
- </div>
11
- </div>
12
- `;
13
-
14
- exports[`app icon should render correctly 1`] = `
15
- <div>
16
- <div>
17
- <a
18
- href="https://fake.link"
19
- >
20
- Open
21
- Cozy Drive
22
- </a>
23
- </div>
24
- </div>
25
- `;
@@ -1,13 +0,0 @@
1
- export default function (fn, duration, keyFn) {
2
- const memo = {}
3
- return arg => {
4
- const key = keyFn(arg)
5
- const memoInfo = memo[key]
6
- const uptodate =
7
- memoInfo && memoInfo.result && memoInfo.date - Date.now() < duration
8
- if (!uptodate) {
9
- memo[key] = { result: fn(arg), date: Date.now() }
10
- }
11
- return memo[key].result
12
- }
13
- }
@@ -1,162 +0,0 @@
1
- /**
2
- * Those tests are here to test previous AppLinker implementation base on
3
- * `slug` prop.
4
- * Now that AppLinkers implements `app` prop and uses `app.slug`, the old
5
- * `slug` prop is deprecated
6
- * Those tests should be kept until `slug` prop is completely removed
7
- */
8
-
9
- import { render } from '@testing-library/react'
10
- import userEvent from '@testing-library/user-event'
11
- import React from 'react'
12
-
13
- import {
14
- isMobileApp,
15
- isMobile,
16
- openDeeplinkOrRedirect,
17
- startApp,
18
- isAndroid,
19
- checkApp
20
- } from 'cozy-device-helper'
21
-
22
- import AppLinker from '.'
23
- import { generateUniversalLink } from './native'
24
- jest.useFakeTimers()
25
-
26
- const setup = ({ app, onAppSwitch }) => {
27
- return {
28
- user: userEvent.setup({ delay: null }),
29
- ...render(
30
- <AppLinker
31
- onAppSwitch={onAppSwitch}
32
- slug={app.slug}
33
- href="https://fake.link"
34
- >
35
- {({ onClick, href, name }) => (
36
- <div>
37
- <a href={href} onClick={onClick}>
38
- Open {name}
39
- </a>
40
- </div>
41
- )}
42
- </AppLinker>
43
- )
44
- }
45
- }
46
-
47
- jest.mock('./native', () => ({
48
- ...jest.requireActual('./native'),
49
- generateUniversalLink: jest.fn()
50
- }))
51
-
52
- jest.mock('cozy-device-helper', () => ({
53
- ...jest.requireActual('cozy-device-helper'),
54
- isMobileApp: jest.fn(),
55
- isMobile: jest.fn(),
56
- openDeeplinkOrRedirect: jest.fn(),
57
- startApp: jest.fn().mockResolvedValue(),
58
- isAndroid: jest.fn(),
59
- checkApp: jest.fn()
60
- }))
61
-
62
- const app = {
63
- slug: 'drive',
64
- name: 'Drive'
65
- }
66
-
67
- describe('app icon', () => {
68
- let spyConsoleError, spyConsoleWarn, appSwitchMock
69
-
70
- beforeEach(() => {
71
- isMobileApp.mockReturnValue(false)
72
- spyConsoleError = jest.spyOn(console, 'error')
73
- spyConsoleError.mockImplementation(() => {})
74
- spyConsoleWarn = jest.spyOn(console, 'warn')
75
- spyConsoleWarn.mockImplementation(() => {})
76
- isMobileApp.mockReturnValue(false)
77
- isMobile.mockReturnValue(false)
78
- isAndroid.mockReturnValue(false)
79
- appSwitchMock = jest.fn()
80
- })
81
-
82
- afterEach(() => {
83
- spyConsoleError.mockRestore()
84
- spyConsoleWarn.mockRestore()
85
- jest.restoreAllMocks()
86
- })
87
-
88
- it('should render correctly', () => {
89
- const { container } = setup({ app })
90
- expect(container).toMatchSnapshot()
91
- })
92
-
93
- it('should work for web -> web', async () => {
94
- isMobileApp.mockReturnValue(false)
95
- const { container, user } = setup({ app, onAppSwitch: appSwitchMock })
96
- const link = container.querySelector('a')
97
- await user.click(link)
98
- expect(appSwitchMock).not.toHaveBeenCalled()
99
- expect(startApp).not.toHaveBeenCalled()
100
- })
101
-
102
- it('should work for native -> native', async () => {
103
- isMobileApp.mockReturnValue(true)
104
- checkApp.mockResolvedValue(true)
105
- const { container, user } = setup({ app, onAppSwitch: appSwitchMock })
106
- const link = container.querySelector('a')
107
- await user.click(link)
108
-
109
- expect(startApp).toHaveBeenCalledWith({
110
- appId: 'io.cozy.drive.mobile',
111
- name: 'Cozy Drive',
112
- uri: 'cozydrive://'
113
- })
114
- expect(appSwitchMock).toHaveBeenCalled()
115
- })
116
-
117
- it('should work for web -> native for Android (custom schema)', async () => {
118
- isMobile.mockReturnValue(true)
119
- isAndroid.mockResolvedValue(true)
120
- const { container, user } = setup({ app, onAppSwitch: appSwitchMock })
121
- const link = container.querySelector('a')
122
- await user.click(link)
123
- expect(openDeeplinkOrRedirect).toHaveBeenCalledWith(
124
- 'cozydrive://',
125
- expect.any(Function)
126
- )
127
- expect(appSwitchMock).toHaveBeenCalled()
128
- })
129
-
130
- it('should work for web -> native for iOS (universal link)', async () => {
131
- isMobile.mockReturnValue(true)
132
- const { container, user } = setup({ app, onAppSwitch: appSwitchMock })
133
- const link = container.querySelector('a')
134
- await user.click(link)
135
-
136
- expect(generateUniversalLink).toHaveBeenCalled()
137
- })
138
-
139
- it('should work for native -> web', async () => {
140
- isMobileApp.mockReturnValue(true)
141
- const { container, user } = setup({ app, onAppSwitch: appSwitchMock })
142
- const link = container.querySelector('a')
143
- await user.click(link)
144
- expect(appSwitchMock).toHaveBeenCalled()
145
- })
146
-
147
- it('should not crash if no href', () => {
148
- isMobileApp.mockReturnValue(true)
149
- const { container } = render(
150
- <AppLinker onAppSwitch={appSwitchMock} slug={app.slug}>
151
- {({ onClick, href, name }) => (
152
- <div>
153
- <a href={href} onClick={onClick}>
154
- Open {name}
155
- </a>
156
- </div>
157
- )}
158
- </AppLinker>
159
- )
160
- expect(container).toMatchSnapshot()
161
- })
162
- })
@@ -1,17 +0,0 @@
1
- export default function (fn, duration, keyFn) {
2
- var memo = {};
3
- return function (arg) {
4
- var key = keyFn(arg);
5
- var memoInfo = memo[key];
6
- var uptodate = memoInfo && memoInfo.result && memoInfo.date - Date.now() < duration;
7
-
8
- if (!uptodate) {
9
- memo[key] = {
10
- result: fn(arg),
11
- date: Date.now()
12
- };
13
- }
14
-
15
- return memo[key].result;
16
- };
17
- }