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.
- package/CHANGELOG.md +21 -0
- package/package.json +1 -1
- package/react/ActionsMenu/Actions/addToFavorites.js +66 -0
- package/react/ActionsMenu/Actions/download.js +42 -0
- package/react/ActionsMenu/Actions/index.js +3 -0
- package/react/ActionsMenu/Actions/locales/en.json +12 -0
- package/react/ActionsMenu/Actions/locales/fr.json +12 -0
- package/react/ActionsMenu/Actions/removeFromFavorites.js +66 -0
- package/react/AppLinker/Readme.md +3 -31
- package/react/AppLinker/__snapshots__/index.spec.jsx.snap +0 -12
- package/react/AppLinker/index.jsx +8 -144
- package/react/AppLinker/index.spec.jsx +1 -94
- package/react/AppLinker/native.config.js +0 -14
- package/transpiled/react/ActionsMenu/Actions/addToFavorites.js +144 -0
- package/transpiled/react/ActionsMenu/Actions/download.js +49 -0
- package/transpiled/react/ActionsMenu/Actions/index.js +3 -0
- package/transpiled/react/ActionsMenu/Actions/locales/withActionsLocales.js +24 -0
- package/transpiled/react/ActionsMenu/Actions/removeFromFavorites.js +144 -0
- package/transpiled/react/AppLinker/index.js +10 -179
- package/transpiled/react/AppLinker/native.config.js +0 -13
- package/react/AppLinker/__snapshots__/index.deprecated.spec.jsx.snap +0 -25
- package/react/AppLinker/expiringMemoize.js +0 -13
- package/react/AppLinker/index.deprecated.spec.jsx +0 -162
- package/transpiled/react/AppLinker/expiringMemoize.js +0 -17
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,24 @@
|
|
|
1
|
+
# [117.1.0](https://github.com/cozy/cozy-ui/compare/v117.0.0...v117.1.0) (2025-01-21)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* Add Download and Add/Remove favorites actions ([6e4bca4](https://github.com/cozy/cozy-ui/commit/6e4bca4))
|
|
7
|
+
|
|
8
|
+
# [117.0.0](https://github.com/cozy/cozy-ui/compare/v116.0.0...v117.0.0) (2025-01-13)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* Remove cordova stuff from AppLinker ([add9fbb](https://github.com/cozy/cozy-ui/commit/add9fbb))
|
|
14
|
+
* Remove deprecated slug prop from AppLinker ([a3d47e0](https://github.com/cozy/cozy-ui/commit/a3d47e0))
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### BREAKING CHANGES
|
|
18
|
+
|
|
19
|
+
* Use app={{ slug: 'drive' }} instead of slug='drive' as
|
|
20
|
+
AppLinker prop. Also, `name` is not passed anymore as render prop.
|
|
21
|
+
|
|
1
22
|
# [116.0.0](https://github.com/cozy/cozy-ui/compare/v115.1.0...v116.0.0) (2025-01-07)
|
|
2
23
|
|
|
3
24
|
|
package/package.json
CHANGED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import React, { forwardRef } from 'react'
|
|
2
|
+
|
|
3
|
+
import { splitFilename } from 'cozy-client/dist/models/file'
|
|
4
|
+
|
|
5
|
+
import { getActionsI18n } from './locales/withActionsLocales'
|
|
6
|
+
import Icon from '../../Icon'
|
|
7
|
+
import StarOutlineIcon from '../../Icons/StarOutline'
|
|
8
|
+
import ListItemIcon from '../../ListItemIcon'
|
|
9
|
+
import ListItemText from '../../ListItemText'
|
|
10
|
+
import ActionsMenuItem from '../ActionsMenuItem'
|
|
11
|
+
|
|
12
|
+
const makeComponent = (label, icon) => {
|
|
13
|
+
const Component = forwardRef((props, ref) => {
|
|
14
|
+
return (
|
|
15
|
+
<ActionsMenuItem {...props} ref={ref}>
|
|
16
|
+
<ListItemIcon>
|
|
17
|
+
<Icon icon={icon} />
|
|
18
|
+
</ListItemIcon>
|
|
19
|
+
<ListItemText primary={label} />
|
|
20
|
+
</ActionsMenuItem>
|
|
21
|
+
)
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
Component.displayName = 'addToFavorites'
|
|
25
|
+
|
|
26
|
+
return Component
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const addToFavorites = ({ showAlert }) => {
|
|
30
|
+
const { t } = getActionsI18n()
|
|
31
|
+
const icon = StarOutlineIcon
|
|
32
|
+
const label = t('favorites.add.label')
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
name: 'addToFavorites',
|
|
36
|
+
icon,
|
|
37
|
+
label,
|
|
38
|
+
displayCondition: docs =>
|
|
39
|
+
docs.length > 0 && docs.every(doc => !doc.cozyMetadata?.favorite),
|
|
40
|
+
Component: makeComponent(label, icon),
|
|
41
|
+
action: async (docs, { client }) => {
|
|
42
|
+
try {
|
|
43
|
+
for (const doc of docs) {
|
|
44
|
+
await client.save({
|
|
45
|
+
...doc,
|
|
46
|
+
cozyMetadata: {
|
|
47
|
+
...doc.cozyMetadata,
|
|
48
|
+
favorite: true
|
|
49
|
+
}
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const { filename } = splitFilename(docs[0])
|
|
54
|
+
showAlert({
|
|
55
|
+
message: t('favorites.add.success', {
|
|
56
|
+
filename,
|
|
57
|
+
smart_count: docs.length
|
|
58
|
+
}),
|
|
59
|
+
severity: 'success'
|
|
60
|
+
})
|
|
61
|
+
} catch (error) {
|
|
62
|
+
showAlert({ message: t('favorites.error'), severity: 'error' })
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import React, { forwardRef } from 'react'
|
|
2
|
+
|
|
3
|
+
import { downloadFile } from 'cozy-client/dist/models/file'
|
|
4
|
+
|
|
5
|
+
import { getActionsI18n } from './locales/withActionsLocales'
|
|
6
|
+
import Icon from '../../Icon'
|
|
7
|
+
import DownloadIcon from '../../Icons/Download'
|
|
8
|
+
import ListItemIcon from '../../ListItemIcon'
|
|
9
|
+
import ListItemText from '../../ListItemText'
|
|
10
|
+
import ActionsMenuItem from '../ActionsMenuItem'
|
|
11
|
+
|
|
12
|
+
const makeComponent = (label, icon) => {
|
|
13
|
+
const Component = forwardRef((props, ref) => {
|
|
14
|
+
return (
|
|
15
|
+
<ActionsMenuItem {...props} ref={ref}>
|
|
16
|
+
<ListItemIcon>
|
|
17
|
+
<Icon icon={icon} />
|
|
18
|
+
</ListItemIcon>
|
|
19
|
+
<ListItemText primary={label} />
|
|
20
|
+
</ActionsMenuItem>
|
|
21
|
+
)
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
Component.displayName = 'download'
|
|
25
|
+
|
|
26
|
+
return Component
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const download = ({ encryptedUrl }) => {
|
|
30
|
+
const { t } = getActionsI18n()
|
|
31
|
+
const icon = DownloadIcon
|
|
32
|
+
const label = t('download')
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
name: 'download',
|
|
36
|
+
icon,
|
|
37
|
+
label,
|
|
38
|
+
Component: makeComponent(label, icon),
|
|
39
|
+
action: (docs, { client, webviewIntent }) =>
|
|
40
|
+
downloadFile({ client, file: docs[0], url: encryptedUrl, webviewIntent })
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -5,6 +5,9 @@ export { smsTo } from './smsTo'
|
|
|
5
5
|
export { call } from './call'
|
|
6
6
|
export { emailTo } from './emailTo'
|
|
7
7
|
export { print } from './print'
|
|
8
|
+
export { download } from './download'
|
|
9
|
+
export { addToFavorites } from './addToFavorites'
|
|
10
|
+
export { removeFromFavorites } from './removeFromFavorites'
|
|
8
11
|
export { viewInContacts } from './viewInContacts'
|
|
9
12
|
export { viewInDrive } from './viewInDrive'
|
|
10
13
|
export { copyToClipboard } from './copyToClipboard'
|
|
@@ -5,6 +5,18 @@
|
|
|
5
5
|
"emailTo": "Send an email",
|
|
6
6
|
"smsTo": "Send a message",
|
|
7
7
|
"print": "Print",
|
|
8
|
+
"download": "Download",
|
|
9
|
+
"favorites": {
|
|
10
|
+
"add": {
|
|
11
|
+
"label": "Add to favorites",
|
|
12
|
+
"success": "%{filename} has been added to favorites |||| These items have been added to favorites"
|
|
13
|
+
},
|
|
14
|
+
"remove": {
|
|
15
|
+
"label": "Remove from favorites",
|
|
16
|
+
"success": "%{filename} has been removed from favorites |||| These items have been removed from favorites"
|
|
17
|
+
},
|
|
18
|
+
"error": "An error occurred, please try again."
|
|
19
|
+
},
|
|
8
20
|
"others": "Others",
|
|
9
21
|
"editAttribute": "Edit attribute",
|
|
10
22
|
"copyToClipboard": {
|
|
@@ -5,6 +5,18 @@
|
|
|
5
5
|
"emailTo": "Envoyer un e-mail",
|
|
6
6
|
"smsTo": "Envoyer un message",
|
|
7
7
|
"print": "Imprimer",
|
|
8
|
+
"download": "Télécharger",
|
|
9
|
+
"favorites": {
|
|
10
|
+
"add": {
|
|
11
|
+
"label": "Ajouter aux favoris",
|
|
12
|
+
"success": "%{filename} a été ajouté aux favoris |||| Ces éléments ont été ajoutés aux favoris"
|
|
13
|
+
},
|
|
14
|
+
"remove": {
|
|
15
|
+
"label": "Retirer des favoris",
|
|
16
|
+
"success": "%{filename} a été retiré des favoris |||| Ces éléments ont été retirés des favoris"
|
|
17
|
+
},
|
|
18
|
+
"error": "Une erreur est survenue, merci de réessayer."
|
|
19
|
+
},
|
|
8
20
|
"others": "Autres",
|
|
9
21
|
"editAttribute": "Editer l'attribut",
|
|
10
22
|
"copyToClipboard": {
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import React, { forwardRef } from 'react'
|
|
2
|
+
|
|
3
|
+
import { splitFilename } from 'cozy-client/dist/models/file'
|
|
4
|
+
|
|
5
|
+
import { getActionsI18n } from './locales/withActionsLocales'
|
|
6
|
+
import Icon from '../../Icon'
|
|
7
|
+
import StarIcon from '../../Icons/Star'
|
|
8
|
+
import ListItemIcon from '../../ListItemIcon'
|
|
9
|
+
import ListItemText from '../../ListItemText'
|
|
10
|
+
import ActionsMenuItem from '../ActionsMenuItem'
|
|
11
|
+
|
|
12
|
+
const makeComponent = (label, icon) => {
|
|
13
|
+
const Component = forwardRef((props, ref) => {
|
|
14
|
+
return (
|
|
15
|
+
<ActionsMenuItem {...props} ref={ref}>
|
|
16
|
+
<ListItemIcon>
|
|
17
|
+
<Icon icon={icon} />
|
|
18
|
+
</ListItemIcon>
|
|
19
|
+
<ListItemText primary={label} />
|
|
20
|
+
</ActionsMenuItem>
|
|
21
|
+
)
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
Component.displayName = 'removeFromFavorites'
|
|
25
|
+
|
|
26
|
+
return Component
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const removeFromFavorites = ({ showAlert }) => {
|
|
30
|
+
const { t } = getActionsI18n()
|
|
31
|
+
const icon = StarIcon
|
|
32
|
+
const label = t('favorites.remove.label')
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
name: 'removeFromFavorites',
|
|
36
|
+
icon,
|
|
37
|
+
label,
|
|
38
|
+
displayCondition: docs =>
|
|
39
|
+
docs.length > 0 && docs.every(doc => doc.cozyMetadata?.favorite),
|
|
40
|
+
Component: makeComponent(label, icon),
|
|
41
|
+
action: async (docs, { client }) => {
|
|
42
|
+
try {
|
|
43
|
+
for (const doc of docs) {
|
|
44
|
+
await client.save({
|
|
45
|
+
...doc,
|
|
46
|
+
cozyMetadata: {
|
|
47
|
+
...doc.cozyMetadata,
|
|
48
|
+
favorite: false
|
|
49
|
+
}
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const { filename } = splitFilename(docs[0])
|
|
54
|
+
showAlert({
|
|
55
|
+
message: t('favorites.success.remove', {
|
|
56
|
+
filename,
|
|
57
|
+
smart_count: docs.length
|
|
58
|
+
}),
|
|
59
|
+
severity: 'success'
|
|
60
|
+
})
|
|
61
|
+
} catch (error) {
|
|
62
|
+
showAlert({ message: t('favorites.error'), severity: 'error' })
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -1,15 +1,10 @@
|
|
|
1
1
|
Render-props component that provides onClick/href handler to
|
|
2
2
|
apply to an anchor that needs to open an app.
|
|
3
3
|
|
|
4
|
-
If the app is known to Cozy (for example Drive or Banks), and
|
|
5
|
-
the user has installed it on its device, the native app will
|
|
6
|
-
be opened.
|
|
7
|
-
|
|
8
4
|
The app's manifest can be set in the `app` prop. Then, in a
|
|
9
5
|
ReactNative environment, the AppLinker will be able to send
|
|
10
6
|
`openApp` message to the native environment with this `app`
|
|
11
|
-
data.
|
|
12
|
-
needed to open the native app ([more info](https://github.com/cozy/cozy-stack/blob/master/docs/apps.md#mobile))
|
|
7
|
+
data.
|
|
13
8
|
|
|
14
9
|
Handles several cases:
|
|
15
10
|
|
|
@@ -28,32 +23,9 @@ const app = {
|
|
|
28
23
|
};
|
|
29
24
|
|
|
30
25
|
<AppLinker app={app} href='http://dalailama-banks.mycozy.cloud'>{
|
|
31
|
-
({ onClick, href
|
|
32
|
-
<a href={href} onClick={onClick}>
|
|
33
|
-
Open { name }
|
|
34
|
-
</a>
|
|
35
|
-
)
|
|
36
|
-
}</AppLinker>
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
### Exemple with mobile data
|
|
40
|
-
|
|
41
|
-
```jsx
|
|
42
|
-
import AppLinker from 'cozy-ui/transpiled/react/AppLinker';
|
|
43
|
-
|
|
44
|
-
const app = {
|
|
45
|
-
slug: 'passwords',
|
|
46
|
-
mobile: {
|
|
47
|
-
schema: 'cozypass://',
|
|
48
|
-
id_playstore: 'io.cozy.pass',
|
|
49
|
-
id_appstore: 'cozy-pass/id1502262449'
|
|
50
|
-
}
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
<AppLinker app={app} href='http://dalailama-passwords.mycozy.cloud'>{
|
|
54
|
-
({ onClick, href, name }) => (
|
|
26
|
+
({ onClick, href }) => (
|
|
55
27
|
<a href={href} onClick={onClick}>
|
|
56
|
-
Open
|
|
28
|
+
Open
|
|
57
29
|
</a>
|
|
58
30
|
)
|
|
59
31
|
}</AppLinker>
|
|
@@ -1,16 +1,5 @@
|
|
|
1
1
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
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
3
|
exports[`app icon should render correctly 1`] = `
|
|
15
4
|
<div>
|
|
16
5
|
<div>
|
|
@@ -18,7 +7,6 @@ exports[`app icon should render correctly 1`] = `
|
|
|
18
7
|
href="https://fake.link"
|
|
19
8
|
>
|
|
20
9
|
Open
|
|
21
|
-
Cozy Drive
|
|
22
10
|
</a>
|
|
23
11
|
</div>
|
|
24
12
|
</div>
|
|
@@ -2,45 +2,25 @@ import PropTypes from 'prop-types'
|
|
|
2
2
|
import React from 'react'
|
|
3
3
|
|
|
4
4
|
import { withClient } from 'cozy-client'
|
|
5
|
-
import {
|
|
6
|
-
checkApp,
|
|
7
|
-
startApp,
|
|
8
|
-
isMobileApp,
|
|
9
|
-
isMobile,
|
|
10
|
-
openDeeplinkOrRedirect,
|
|
11
|
-
isAndroid,
|
|
12
|
-
isFlagshipApp
|
|
13
|
-
} from 'cozy-device-helper'
|
|
5
|
+
import { isFlagshipApp } from 'cozy-device-helper'
|
|
14
6
|
import { WebviewContext } from 'cozy-intent'
|
|
15
7
|
import logger from 'cozy-logger'
|
|
16
8
|
|
|
17
|
-
import expiringMemoize from './expiringMemoize'
|
|
18
9
|
import {
|
|
19
10
|
generateUniversalLink,
|
|
20
11
|
generateWebLink,
|
|
21
12
|
getUniversalLinkDomain
|
|
22
13
|
} from './native'
|
|
23
|
-
import { NATIVE_APP_INFOS } from './native.config'
|
|
24
|
-
|
|
25
|
-
const expirationDelay = 10 * 1000
|
|
26
|
-
const memoizedCheckApp = expiringMemoize(
|
|
27
|
-
appInfo => checkApp(appInfo).catch(() => false),
|
|
28
|
-
expirationDelay,
|
|
29
|
-
appInfo => appInfo.appId
|
|
30
|
-
)
|
|
31
14
|
|
|
32
15
|
export class AppLinker extends React.Component {
|
|
33
16
|
static contextType = WebviewContext
|
|
34
17
|
|
|
35
18
|
state = {
|
|
36
|
-
|
|
37
|
-
isFetchingAppInfo: false
|
|
19
|
+
imgRef: null
|
|
38
20
|
}
|
|
39
21
|
|
|
40
22
|
constructor(props) {
|
|
41
23
|
super(props)
|
|
42
|
-
|
|
43
|
-
this.imgRef = null
|
|
44
24
|
}
|
|
45
25
|
|
|
46
26
|
setImgRef = img => {
|
|
@@ -48,44 +28,14 @@ export class AppLinker extends React.Component {
|
|
|
48
28
|
this.setState({ imgRef: this.imgRef })
|
|
49
29
|
}
|
|
50
30
|
|
|
51
|
-
componentDidMount() {
|
|
52
|
-
if (isMobileApp()) {
|
|
53
|
-
this.checkAppAvailability()
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
async checkAppAvailability() {
|
|
58
|
-
const slug = AppLinker.getSlug(this.props)
|
|
59
|
-
const appInfo = NATIVE_APP_INFOS[slug]
|
|
60
|
-
if (appInfo) {
|
|
61
|
-
const nativeAppIsAvailable = Boolean(await memoizedCheckApp(appInfo))
|
|
62
|
-
this.setState({ nativeAppIsAvailable })
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
31
|
static getSlug(props) {
|
|
67
|
-
|
|
68
|
-
return props.app.slug
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return props.slug
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
static deprecateSlug(props) {
|
|
75
|
-
if (props.slug) {
|
|
76
|
-
console.warn(
|
|
77
|
-
`AppLinker's 'slug' prop is deprecated, please use 'app.slug' instead`
|
|
78
|
-
)
|
|
79
|
-
}
|
|
32
|
+
return props.app.slug
|
|
80
33
|
}
|
|
81
34
|
|
|
82
|
-
static getOnClickHref(props,
|
|
83
|
-
const { app, client
|
|
84
|
-
const slug = AppLinker.getSlug(props)
|
|
35
|
+
static getOnClickHref(props, context, imgRef) {
|
|
36
|
+
const { app, client } = props
|
|
85
37
|
let href = props.href
|
|
86
38
|
let onClick = null
|
|
87
|
-
const usingNativeApp = isMobileApp()
|
|
88
|
-
const appInfo = NATIVE_APP_INFOS[slug]
|
|
89
39
|
|
|
90
40
|
if (isFlagshipApp()) {
|
|
91
41
|
const { app: currentApp } = client
|
|
@@ -114,59 +64,11 @@ export class AppLinker extends React.Component {
|
|
|
114
64
|
}
|
|
115
65
|
}
|
|
116
66
|
|
|
117
|
-
if (usingNativeApp) {
|
|
118
|
-
if (nativeAppIsAvailable) {
|
|
119
|
-
// If we are on the native app and the other native app is available,
|
|
120
|
-
// we open the native app
|
|
121
|
-
onClick = AppLinker.openNativeFromNative.bind(this, props)
|
|
122
|
-
href = '#'
|
|
123
|
-
} else {
|
|
124
|
-
// If we are on a native app, but the other native app is not available
|
|
125
|
-
// we open the web link, this is done by the href prop. We still
|
|
126
|
-
// have to call the prop callback
|
|
127
|
-
onClick = AppLinker.openWeb.bind(this, props)
|
|
128
|
-
}
|
|
129
|
-
} else if (isMobile() && appInfo) {
|
|
130
|
-
// If we are on the "mobile web version", we try to open the native app
|
|
131
|
-
// if it exists with an universal links. If it fails, we redirect to the web
|
|
132
|
-
// version of the requested app
|
|
133
|
-
// Only on iOS ATM
|
|
134
|
-
if (isAndroid()) {
|
|
135
|
-
onClick = AppLinker.openNativeFromWeb.bind(this, props)
|
|
136
|
-
} else {
|
|
137
|
-
// Since generateUniversalLink can rise an error, let's catch it to not crash
|
|
138
|
-
// all the page.
|
|
139
|
-
try {
|
|
140
|
-
href = generateUniversalLink({ slug, nativePath, fallbackUrl: href })
|
|
141
|
-
} catch (err) {
|
|
142
|
-
console.error(err)
|
|
143
|
-
href = '#'
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
67
|
return {
|
|
149
68
|
href,
|
|
150
69
|
onClick
|
|
151
70
|
}
|
|
152
71
|
}
|
|
153
|
-
static openNativeFromWeb(props, ev) {
|
|
154
|
-
const { href, nativePath, onAppSwitch } = props
|
|
155
|
-
const slug = AppLinker.getSlug(props)
|
|
156
|
-
const appInfo = NATIVE_APP_INFOS[slug]
|
|
157
|
-
|
|
158
|
-
if (ev) {
|
|
159
|
-
ev.preventDefault()
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
AppLinker.onAppSwitch(onAppSwitch)
|
|
163
|
-
openDeeplinkOrRedirect(
|
|
164
|
-
appInfo.uri + (nativePath === '/' ? '' : nativePath),
|
|
165
|
-
function () {
|
|
166
|
-
window.location.href = href
|
|
167
|
-
}
|
|
168
|
-
)
|
|
169
|
-
}
|
|
170
72
|
|
|
171
73
|
static onAppSwitch(onAppSwitchFn) {
|
|
172
74
|
if (typeof onAppSwitchFn === 'function') {
|
|
@@ -174,38 +76,20 @@ export class AppLinker extends React.Component {
|
|
|
174
76
|
}
|
|
175
77
|
}
|
|
176
78
|
|
|
177
|
-
static openNativeFromNative(props, ev) {
|
|
178
|
-
const { onAppSwitch } = props
|
|
179
|
-
const slug = AppLinker.getSlug(props)
|
|
180
|
-
if (ev) {
|
|
181
|
-
ev.preventDefault()
|
|
182
|
-
}
|
|
183
|
-
const appInfo = NATIVE_APP_INFOS[slug]
|
|
184
|
-
AppLinker.onAppSwitch(onAppSwitch)
|
|
185
|
-
startApp(appInfo).catch(err => {
|
|
186
|
-
console.error('AppLinker: Could not open native app', err)
|
|
187
|
-
})
|
|
188
|
-
}
|
|
189
|
-
|
|
190
79
|
static openWeb(props) {
|
|
191
80
|
AppLinker.onAppSwitch(props.onAppSwitch)
|
|
192
81
|
}
|
|
193
82
|
|
|
194
83
|
render() {
|
|
195
84
|
const { children } = this.props
|
|
196
|
-
|
|
197
|
-
const slug = AppLinker.getSlug(this.props)
|
|
198
|
-
const { nativeAppIsAvailable } = this.state
|
|
199
|
-
const appInfo = NATIVE_APP_INFOS[slug]
|
|
85
|
+
|
|
200
86
|
const { href, onClick } = AppLinker.getOnClickHref(
|
|
201
87
|
this.props,
|
|
202
|
-
nativeAppIsAvailable,
|
|
203
88
|
this.context,
|
|
204
89
|
this.state.imgRef
|
|
205
90
|
)
|
|
206
91
|
|
|
207
92
|
return children({
|
|
208
|
-
...appInfo,
|
|
209
93
|
iconRef: this.setImgRef,
|
|
210
94
|
onClick: onClick,
|
|
211
95
|
href
|
|
@@ -213,38 +97,18 @@ export class AppLinker extends React.Component {
|
|
|
213
97
|
}
|
|
214
98
|
}
|
|
215
99
|
|
|
216
|
-
AppLinker.defaultProps = {
|
|
217
|
-
nativePath: '/'
|
|
218
|
-
}
|
|
219
100
|
AppLinker.propTypes = {
|
|
220
|
-
/** DEPRECATED: please use app.slug prop */
|
|
221
|
-
slug: PropTypes.string,
|
|
222
101
|
/*
|
|
223
102
|
Full web url : Used by default on desktop browser
|
|
224
103
|
Used as a fallback_uri on mobile web
|
|
225
104
|
*/
|
|
226
105
|
href: PropTypes.string,
|
|
227
|
-
/*
|
|
228
|
-
Path used for "native link"
|
|
229
|
-
*/
|
|
230
|
-
nativePath: PropTypes.string,
|
|
231
106
|
onAppSwitch: PropTypes.func,
|
|
232
107
|
app: PropTypes.shape({
|
|
233
108
|
// Slug of the app : drive / banks ...
|
|
234
|
-
slug: PropTypes.string.isRequired
|
|
235
|
-
// Information about mobile native app
|
|
236
|
-
mobile: PropTypes.shape({
|
|
237
|
-
schema: PropTypes.string,
|
|
238
|
-
id_playstore: PropTypes.string,
|
|
239
|
-
id_appstore: PropTypes.string
|
|
240
|
-
})
|
|
109
|
+
slug: PropTypes.string.isRequired
|
|
241
110
|
}).isRequired
|
|
242
111
|
}
|
|
243
112
|
|
|
244
113
|
export default withClient(AppLinker)
|
|
245
|
-
export {
|
|
246
|
-
NATIVE_APP_INFOS,
|
|
247
|
-
getUniversalLinkDomain,
|
|
248
|
-
generateWebLink,
|
|
249
|
-
generateUniversalLink
|
|
250
|
-
}
|
|
114
|
+
export { getUniversalLinkDomain, generateWebLink, generateUniversalLink }
|