cozy-bar 0.0.0-development

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 (103) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +174 -0
  3. package/dist/cozy-bar.min.js +77 -0
  4. package/dist/cozy-bar.min.js.map +1 -0
  5. package/package.json +165 -0
  6. package/src/assets/icons/16/icon-storage-16.svg +3 -0
  7. package/src/assets/icons/24/icon-arrow-left.svg +3 -0
  8. package/src/assets/icons/32/icon-claudy.svg +1 -0
  9. package/src/assets/icons/apps/icon-collect.svg +25 -0
  10. package/src/assets/icons/apps/icon-drive.svg +17 -0
  11. package/src/assets/icons/apps/icon-market-soon.svg +25 -0
  12. package/src/assets/icons/apps/icon-photos.svg +19 -0
  13. package/src/assets/icons/apps/icon-soon.svg +21 -0
  14. package/src/assets/icons/apps/icon-store.svg +19 -0
  15. package/src/assets/icons/claudyActions/icon-bills.svg +6 -0
  16. package/src/assets/icons/claudyActions/icon-laptop.svg +7 -0
  17. package/src/assets/icons/claudyActions/icon-phone.svg +8 -0
  18. package/src/assets/icons/claudyActions/icon-question-mark.svg +6 -0
  19. package/src/assets/icons/comingsoon/icon-bank.svg +12 -0
  20. package/src/assets/icons/comingsoon/icon-sante.svg +12 -0
  21. package/src/assets/icons/comingsoon/icon-store.svg +6 -0
  22. package/src/assets/icons/icon-cozy.svg +3 -0
  23. package/src/assets/icons/icon-shield.svg +3 -0
  24. package/src/assets/icons/spinner.svg +4 -0
  25. package/src/assets/sprites/icon-apps.svg +1 -0
  26. package/src/assets/sprites/icon-cozy-home.svg +16 -0
  27. package/src/components/Apps/AppItem.jsx +117 -0
  28. package/src/components/Apps/AppItemPlaceholder.jsx +12 -0
  29. package/src/components/Apps/AppNavButtons.jsx +94 -0
  30. package/src/components/Apps/AppsContent.jsx +91 -0
  31. package/src/components/Apps/ButtonCozyHome.jsx +30 -0
  32. package/src/components/Apps/ButtonCozyHome.spec.jsx +53 -0
  33. package/src/components/Apps/IconCozyHome.jsx +38 -0
  34. package/src/components/Apps/index.jsx +72 -0
  35. package/src/components/Banner.jsx +41 -0
  36. package/src/components/Bar.jsx +295 -0
  37. package/src/components/Bar.spec.jsx +133 -0
  38. package/src/components/Claudy.jsx +81 -0
  39. package/src/components/ClaudyIcon.jsx +18 -0
  40. package/src/components/Drawer.jsx +227 -0
  41. package/src/components/Drawer.spec.jsx +98 -0
  42. package/src/components/SearchBar.jsx +358 -0
  43. package/src/components/Settings/SettingsContent.jsx +163 -0
  44. package/src/components/Settings/StorageData.jsx +29 -0
  45. package/src/components/Settings/helper.js +8 -0
  46. package/src/components/Settings/index.jsx +220 -0
  47. package/src/components/StorageIcon.jsx +16 -0
  48. package/src/components/SupportModal.jsx +59 -0
  49. package/src/components/__snapshots__/Bar.spec.jsx.snap +302 -0
  50. package/src/config/claudyActions.json +20 -0
  51. package/src/config/persistWhitelist.json +4 -0
  52. package/src/dom.js +80 -0
  53. package/src/index.jsx +242 -0
  54. package/src/index.spec.jsx +34 -0
  55. package/src/lib/api/helpers.js +13 -0
  56. package/src/lib/api/index.jsx +145 -0
  57. package/src/lib/exceptions.js +89 -0
  58. package/src/lib/expiringMemoize.js +13 -0
  59. package/src/lib/icon.js +77 -0
  60. package/src/lib/intents.js +16 -0
  61. package/src/lib/logger.js +11 -0
  62. package/src/lib/middlewares/appsI18n.js +57 -0
  63. package/src/lib/realtime.js +43 -0
  64. package/src/lib/reducers/apps.js +175 -0
  65. package/src/lib/reducers/apps.spec.js +59 -0
  66. package/src/lib/reducers/content.js +50 -0
  67. package/src/lib/reducers/context.js +86 -0
  68. package/src/lib/reducers/index.js +73 -0
  69. package/src/lib/reducers/locale.js +22 -0
  70. package/src/lib/reducers/settings.js +111 -0
  71. package/src/lib/reducers/theme.js +48 -0
  72. package/src/lib/reducers/unserializable.js +26 -0
  73. package/src/lib/stack-client.js +401 -0
  74. package/src/lib/stack.js +79 -0
  75. package/src/lib/store/index.js +44 -0
  76. package/src/locales/de.json +57 -0
  77. package/src/locales/en.json +57 -0
  78. package/src/locales/es.json +57 -0
  79. package/src/locales/fr.json +57 -0
  80. package/src/locales/it.json +57 -0
  81. package/src/locales/ja.json +57 -0
  82. package/src/locales/nl_NL.json +57 -0
  83. package/src/locales/pl.json +57 -0
  84. package/src/locales/ru.json +57 -0
  85. package/src/locales/sq.json +57 -0
  86. package/src/locales/zh_CN.json +57 -0
  87. package/src/proptypes/index.js +10 -0
  88. package/src/queries/index.js +16 -0
  89. package/src/styles/apps.css +248 -0
  90. package/src/styles/banner.css +64 -0
  91. package/src/styles/bar.css +106 -0
  92. package/src/styles/base.css +21 -0
  93. package/src/styles/claudy.css +98 -0
  94. package/src/styles/drawer.css +126 -0
  95. package/src/styles/index.styl +33 -0
  96. package/src/styles/indicators.css +58 -0
  97. package/src/styles/nav.css +81 -0
  98. package/src/styles/navigation_item.css +34 -0
  99. package/src/styles/searchbar.css +156 -0
  100. package/src/styles/settings.css +34 -0
  101. package/src/styles/storage.css +22 -0
  102. package/src/styles/supportModal.css +20 -0
  103. package/src/styles/theme.styl +25 -0
@@ -0,0 +1,94 @@
1
+ import React, { Component } from 'react'
2
+ import { connect } from 'react-redux'
3
+
4
+ import BottomIcon from 'cozy-ui/react/Icons/Bottom'
5
+ import Icon from 'cozy-ui/react/Icon'
6
+ import TopIcon from 'cozy-ui/react/Icons/Top'
7
+ import { translate } from 'cozy-ui/react/I18n'
8
+
9
+ import { ButtonCozyHome } from 'components/Apps/ButtonCozyHome'
10
+ import { getHomeApp } from 'lib/reducers'
11
+ import { isFetchingApps } from 'lib/reducers'
12
+
13
+ class AppNavButton extends Component {
14
+ render() {
15
+ const {
16
+ homeApp,
17
+ handleClick,
18
+ appName,
19
+ appNamePrefix,
20
+ appSlug,
21
+ iconPath,
22
+ isFetchingApps,
23
+ isPublic,
24
+ opened,
25
+ t
26
+ } = this.props
27
+
28
+ const isHomeApp = homeApp && homeApp.isCurrentApp
29
+
30
+ if (!isPublic && isFetchingApps) {
31
+ return (
32
+ <div className="coz-nav-apps-btns --loading">
33
+ <div className="coz-nav-apps-btns-home coz-loading-placeholder" />
34
+ <div className="coz-nav-apps-btns-main coz-loading-placeholder" />
35
+ </div>
36
+ )
37
+ }
38
+
39
+ const displayName =
40
+ !isHomeApp && appNamePrefix
41
+ ? [
42
+ t(`${appSlug}.name_prefix`, {
43
+ _: appNamePrefix
44
+ }),
45
+ t(`${appSlug}.name`, {
46
+ _: appName
47
+ })
48
+ ].join(' ')
49
+ : t(`${appSlug}.name`, { _: appName })
50
+
51
+ const homeHref = !isPublic && homeApp && homeApp.href
52
+
53
+ return (
54
+ <div className={`coz-nav-apps-btns${isHomeApp ? ' --currentHome' : ''}`}>
55
+ <ButtonCozyHome homeHref={homeHref} />
56
+
57
+ {!isHomeApp && <span className="coz-nav-apps-btns-sep" />}
58
+
59
+ <button
60
+ type="button"
61
+ onClick={isPublic ? null : handleClick}
62
+ className="coz-nav-apps-btns-main"
63
+ aria-controls="coz-nav-pop--apps"
64
+ data-tutorial="apps"
65
+ disabled={isPublic}
66
+ >
67
+ {!isHomeApp && (
68
+ <img className="coz-bar-hide-sm" src={iconPath} width="28" alt="" />
69
+ )}
70
+ <span className="coz-nav-app-name">{displayName}</span>
71
+ {!isPublic && (
72
+ <Icon
73
+ icon={opened ? TopIcon : BottomIcon}
74
+ color="#95999d"
75
+ size="12"
76
+ />
77
+ )}
78
+ </button>
79
+ </div>
80
+ )
81
+ }
82
+ }
83
+
84
+ const mapStateToProps = state => ({
85
+ homeApp: getHomeApp(state),
86
+ isFetchingApps: isFetchingApps(state)
87
+ })
88
+
89
+ const mapDispatchToProps = () => ({})
90
+
91
+ export default connect(
92
+ mapStateToProps,
93
+ mapDispatchToProps
94
+ )(translate()(AppNavButton))
@@ -0,0 +1,91 @@
1
+ import React, { Component } from 'react'
2
+ import { connect } from 'react-redux'
3
+ import Proptypes from 'prop-types'
4
+
5
+ import { translate } from 'cozy-ui/react/I18n'
6
+ import Icon from 'cozy-ui/transpiled/react/Icon'
7
+ import CloudIcon from 'cozy-ui/transpiled/react/Icons/Cloud'
8
+
9
+ import withBreakpoints from 'cozy-ui/react/helpers/withBreakpoints'
10
+ import { getApps, getHomeApp, isFetchingApps } from 'lib/reducers'
11
+
12
+ import AppItem from 'components/Apps/AppItem'
13
+ import AppItemPlaceholder from 'components/Apps/AppItemPlaceholder'
14
+
15
+ const sorter = fn => (itemA, itemB) => fn(itemA) > fn(itemB)
16
+
17
+ export class AppsContent extends Component {
18
+ constructor(props, context) {
19
+ super(props, context)
20
+ this.translateApp = translateApp(this.props.t)
21
+ }
22
+
23
+ render() {
24
+ const {
25
+ t,
26
+ apps,
27
+ breakpoints,
28
+ homeApp,
29
+ isFetchingApps,
30
+ onAppSwitch
31
+ } = this.props
32
+ const { isMobile } = breakpoints
33
+ const isHomeApp = homeApp && homeApp.isCurrentApp
34
+ const homeSlug = homeApp && homeApp.slug
35
+
36
+ if (!isFetchingApps && (!apps || !apps.length)) {
37
+ return <p className="coz-nav--error coz-nav-group">{t('no_apps')}</p>
38
+ }
39
+
40
+ return (
41
+ <div className="coz-nav-pop-content">
42
+ <ul className="coz-nav-group">
43
+ {isMobile && homeApp && (
44
+ <AppItem app={homeApp} useHomeIcon onAppSwitch={onAppSwitch} />
45
+ )}
46
+ {isFetchingApps
47
+ ? new Array(3)
48
+ .fill({})
49
+ .map((nothing, index) => <AppItemPlaceholder key={index} />)
50
+ : apps
51
+ .filter(app => app.slug !== homeSlug)
52
+ .sort(sorter(this.translateApp))
53
+ .map((app, index) => (
54
+ <AppItem app={app} key={index} onAppSwitch={onAppSwitch} />
55
+ ))}
56
+ </ul>
57
+ {homeApp && !isMobile && !isHomeApp && (
58
+ <a role="menuitem" href={homeApp.href} className="coz-apps-home-btn">
59
+ <Icon icon={CloudIcon} />
60
+ {t('menu.home')}
61
+ </a>
62
+ )}
63
+ </div>
64
+ )
65
+ }
66
+ }
67
+ AppsContent.propTypes = {
68
+ homeApp: Proptypes.shape({
69
+ isCurrentApp: Proptypes.bool,
70
+ slug: Proptypes.string
71
+ }),
72
+ apps: Proptypes.array,
73
+ isFetchingApps: Proptypes.bool.isRequired
74
+ }
75
+ const translateApp = t => app => {
76
+ const namePrefix = app.namePrefix
77
+ ? t(`${app.slug}.namePrefix`, { _: app.namePrefix })
78
+ : null
79
+ const name = t(`${app.slug}.name`, { _: app.name })
80
+ return namePrefix ? `${namePrefix} ${name}` : `${name}`
81
+ }
82
+
83
+ const mapStateToProps = state => ({
84
+ apps: getApps(state),
85
+ homeApp: getHomeApp(state),
86
+ isFetchingApps: isFetchingApps(state)
87
+ })
88
+
89
+ export default connect(mapStateToProps)(
90
+ translate()(withBreakpoints()(AppsContent))
91
+ )
@@ -0,0 +1,30 @@
1
+ import React from 'react'
2
+
3
+ import IconCozyHome from './IconCozyHome'
4
+
5
+ export const ButtonCozyHome = ({ webviewContext, homeHref }) => {
6
+ if (webviewContext)
7
+ return (
8
+ <button
9
+ onClick={() => {
10
+ webviewContext.call('backToHome')
11
+ }}
12
+ className="coz-nav-apps-btns-home --flagship"
13
+ >
14
+ <IconCozyHome className="coz-nav-apps-btns-home-svg" />
15
+ </button>
16
+ )
17
+
18
+ if (homeHref)
19
+ return (
20
+ <a href={homeHref} className="coz-nav-apps-btns-home">
21
+ <IconCozyHome className="coz-nav-apps-btns-home-svg" />
22
+ </a>
23
+ )
24
+
25
+ return (
26
+ <span className="coz-nav-apps-btns-home">
27
+ <IconCozyHome className="coz-nav-apps-btns-home-svg" />
28
+ </span>
29
+ )
30
+ }
@@ -0,0 +1,53 @@
1
+ import React from 'react'
2
+ import { shallow } from 'enzyme'
3
+
4
+ import { ButtonCozyHome } from 'components/Apps/ButtonCozyHome'
5
+
6
+ const homeHref = 'foo'
7
+ const expectedCall = 'backToHome'
8
+ const webviewContext = {
9
+ call: jest.fn()
10
+ }
11
+
12
+ describe('ButtonCozyHome', () => {
13
+ it('should render a span with no props', () => {
14
+ const render = shallow(<ButtonCozyHome />)
15
+ const element = render.getElement()
16
+
17
+ expect(element.type).toBe('span')
18
+ })
19
+
20
+ it('should render an anchor with correct href when homeHref', () => {
21
+ const render = shallow(<ButtonCozyHome homeHref={homeHref} />)
22
+ const element = render.getElement()
23
+
24
+ expect(element.type).toBe('a')
25
+ expect(element.props.href).toBe(homeHref)
26
+ })
27
+
28
+ it('should render a button when webviewContext', () => {
29
+ const render = shallow(<ButtonCozyHome webviewContext={webviewContext} />)
30
+ const element = render.getElement()
31
+
32
+ expect(element.type).toBe('button')
33
+ })
34
+
35
+ it('should give priority to button if both webviewContext and homeHref are present', () => {
36
+ const render = shallow(
37
+ <ButtonCozyHome homeHref={homeHref} webviewContext={webviewContext} />
38
+ )
39
+ const element = render.getElement()
40
+
41
+ expect(element.type).toBe('button')
42
+ })
43
+
44
+ it('should call the correct context method on click', () => {
45
+ const render = shallow(
46
+ <ButtonCozyHome homeHref={homeHref} webviewContext={webviewContext} />
47
+ )
48
+
49
+ render.simulate('click')
50
+
51
+ expect(webviewContext.call).toBeCalledWith(expectedCall)
52
+ })
53
+ })
@@ -0,0 +1,38 @@
1
+ import React, { PureComponent } from 'react'
2
+
3
+ import AppIcon from 'cozy-ui/react/AppIcon'
4
+
5
+ import stack from 'lib/stack'
6
+
7
+ /* Generated with node_modules/.bin/svgr src/assets/sprites/icon-cozy-home.svg */
8
+ function SvgIconCozyHome(props) {
9
+ return (
10
+ <svg width={32} height={32} {...props}>
11
+ <g fill="none" fillRule="evenodd">
12
+ <circle fill="#297EF2" fillRule="nonzero" cx={16} cy={16} r={16} />
13
+ <path
14
+ d="M19.314 17.561a.555.555 0 01-.82.12 4.044 4.044 0 01-2.499.862 4.04 4.04 0 01-2.494-.86.557.557 0 01-.815-.12.547.547 0 01.156-.748c.214-.14.229-.421.229-.424a.555.555 0 01.176-.385.504.504 0 01.386-.145.544.544 0 01.528.553c0 .004 0 .153-.054.36a2.954 2.954 0 003.784-.008 1.765 1.765 0 01-.053-.344.546.546 0 01.536-.561h.01c.294 0 .538.237.545.532 0 0 .015.282.227.422a.544.544 0 01.158.746m2.322-6.369a5.94 5.94 0 00-1.69-3.506A5.651 5.651 0 0015.916 6a5.648 5.648 0 00-4.029 1.687 5.936 5.936 0 00-1.691 3.524 5.677 5.677 0 00-3.433 1.737 5.966 5.966 0 00-1.643 4.137C5.12 20.347 7.704 23 10.882 23h10.236c3.176 0 5.762-2.653 5.762-5.915 0-3.083-2.31-5.623-5.244-5.893"
15
+ fill="#FFF"
16
+ />
17
+ </g>
18
+ </svg>
19
+ )
20
+ }
21
+
22
+ class IconCozyHome extends PureComponent {
23
+ render() {
24
+ const { className } = this.props
25
+ const fetchIcon = () =>
26
+ `${stack.get.cozyURL()}/assets/images/icon-cozy-home.svg`
27
+
28
+ return (
29
+ <AppIcon
30
+ fetchIcon={fetchIcon}
31
+ fallbackIcon={SvgIconCozyHome}
32
+ className={className}
33
+ />
34
+ )
35
+ }
36
+ }
37
+
38
+ export default IconCozyHome
@@ -0,0 +1,72 @@
1
+ import React, { Component } from 'react'
2
+
3
+ import AppsContent from 'components/Apps/AppsContent'
4
+ import AppNavButtons from 'components/Apps/AppNavButtons'
5
+
6
+ class Apps extends Component {
7
+ constructor(props) {
8
+ super(props)
9
+ this.state = {
10
+ opened: false
11
+ }
12
+ }
13
+
14
+ componentDidMount() {
15
+ document.body.addEventListener('click', this.onClickOutside)
16
+ this.modalContainer = document.getElementById('cozy-bar-modal-dom-place')
17
+ }
18
+
19
+ componentWillUnmount() {
20
+ document.body.removeEventListener('click', this.onClickOutside)
21
+ }
22
+
23
+ onClickOutside = event => {
24
+ if (this.state.opened) {
25
+ // if it's not a cozy-bar nav popup, close the opened popup
26
+ if (
27
+ !this.rootRef.contains(event.target) &&
28
+ !this.modalContainer.contains(event.target)
29
+ ) {
30
+ this.setState({ opened: false })
31
+ event.stopPropagation()
32
+ }
33
+ }
34
+ }
35
+
36
+ toggleMenu = () => {
37
+ this.setState({ opened: !this.state.opened })
38
+ }
39
+
40
+ // data-tutorial attribute allows to be targeted in an application tutorial
41
+ render() {
42
+ const { appName, appNamePrefix, appSlug, iconPath, isPublic } = this.props
43
+ const { opened } = this.state
44
+ return (
45
+ <nav
46
+ className="coz-nav coz-nav-apps"
47
+ ref={ref => {
48
+ this.rootRef = ref
49
+ }}
50
+ >
51
+ <AppNavButtons
52
+ appName={appName}
53
+ appNamePrefix={appNamePrefix}
54
+ appSlug={appSlug}
55
+ iconPath={iconPath}
56
+ handleClick={this.toggleMenu}
57
+ opened={opened}
58
+ isPublic={isPublic}
59
+ />
60
+ <div
61
+ className="coz-nav-pop coz-nav-pop--apps"
62
+ id="coz-nav-pop--apps"
63
+ aria-hidden={!opened}
64
+ >
65
+ <AppsContent />
66
+ </div>
67
+ </nav>
68
+ )
69
+ }
70
+ }
71
+
72
+ export default Apps
@@ -0,0 +1,41 @@
1
+ import React, { Component } from 'react'
2
+ import { ButtonLink } from 'cozy-ui/react/Button'
3
+ import { translate } from 'cozy-ui/react/I18n'
4
+
5
+ class Banner extends Component {
6
+ constructor(props) {
7
+ super(props)
8
+ this.state = { unmounted: true }
9
+ this.animate = this.animate.bind(this)
10
+ }
11
+
12
+ animate() {
13
+ // To animate we have to use a setTimeout to
14
+ // force a CSS class update and trigger CSS animation
15
+ return setTimeout(() => {
16
+ this.setState(() => ({ unmounted: false }))
17
+ }, 100)
18
+ }
19
+
20
+ componentDidMount() {
21
+ this.animate()
22
+ }
23
+
24
+ render() {
25
+ const { t, code, links } = this.props
26
+ const { unmounted } = this.state
27
+ return (
28
+ <div className={`coz-bar-banner${unmounted ? ' unmounted' : ''}`}>
29
+ <p>{t(`banner.${code}.description`)}</p>
30
+ <ButtonLink
31
+ className="coz-bar-banner-button"
32
+ size="tiny"
33
+ href={links}
34
+ label={t(`banner.${code}.CTA`)}
35
+ />
36
+ </div>
37
+ )
38
+ }
39
+ }
40
+
41
+ export default translate()(Banner)