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,50 @@
1
+ const SET_CONTENT = 'SET_CONTENT'
2
+ const UNSET_CONTENT = 'UNSET_CONTENT'
3
+
4
+ const getLastItemInMap = map => Array.from(map)[map.size - 1]
5
+
6
+ // action creator
7
+ export const setContent = (location, content, id) => ({
8
+ type: SET_CONTENT,
9
+ location,
10
+ content,
11
+ id
12
+ })
13
+ export const unsetContent = (location, id) => ({
14
+ type: UNSET_CONTENT,
15
+ location,
16
+ id
17
+ })
18
+
19
+ // reducer
20
+ export const getDefaultState = () => ({
21
+ left: new Map(),
22
+ center: new Map(),
23
+ right: new Map(),
24
+ search: new Map()
25
+ })
26
+
27
+ export const reducer = (state = getDefaultState(), action) => {
28
+ if (!action.location || typeof action.id === undefined) return state
29
+ switch (action.type) {
30
+ case SET_CONTENT: {
31
+ const currentState = state[action.location]
32
+ currentState.set(action.id, action.content)
33
+ return { ...state, [action.location]: currentState }
34
+ }
35
+ case UNSET_CONTENT: {
36
+ const currentState = state[action.location]
37
+ if (!currentState.get(action.id)) {
38
+ return state
39
+ }
40
+ currentState.delete(action.id)
41
+ return { ...state, [action.location]: currentState }
42
+ }
43
+ default:
44
+ return state
45
+ }
46
+ }
47
+
48
+ // selectors
49
+ export const getContent = (state, location) =>
50
+ getLastItemInMap(state[location]) && getLastItemInMap(state[location])[1]
@@ -0,0 +1,86 @@
1
+ import stack from 'lib/stack'
2
+ import CLAUDY_ACTIONS from 'config/claudyActions.json'
3
+ import { LOG_OUT } from 'lib/reducers/settings'
4
+ import flag from 'cozy-flags'
5
+
6
+ const FETCH_CONTEXT = 'FETCH_CONTEXT'
7
+ const FETCH_CONTEXT_SUCCESS = 'FETCH_CONTEXT_SUCCESS'
8
+ const RECEIVE_NO_CONTEXT = 'RECEIVE_NO_CONTEXT'
9
+
10
+ // selectors
11
+ export const getHelpLink = state => {
12
+ return state.helpLink
13
+ }
14
+
15
+ export const getClaudyActions = state => {
16
+ return state.claudyActions
17
+ }
18
+ export const shouldEnableClaudy = state => {
19
+ const claudyActions = getClaudyActions(state)
20
+ return !!claudyActions && !!claudyActions.length
21
+ }
22
+
23
+ // actions
24
+ export const fetchContext = () => async (dispatch, getState) => {
25
+ dispatch({ type: FETCH_CONTEXT })
26
+ if (getState().context.contextNotExist) {
27
+ return dispatch({ type: FETCH_CONTEXT_SUCCESS, context: null })
28
+ }
29
+ try {
30
+ const context = await stack.get.context()
31
+ return dispatch({ type: FETCH_CONTEXT_SUCCESS, context })
32
+ } catch (error) {
33
+ if (error.status && error.status === 404) {
34
+ dispatch({ type: RECEIVE_NO_CONTEXT })
35
+ }
36
+ // eslint-disable-next-line no-console
37
+ console.warn('Cannot get Cozy context')
38
+ return null
39
+ }
40
+ }
41
+
42
+ // reducers
43
+ const defaultState = {
44
+ claudyActions: [],
45
+ contextNotExist: false,
46
+ helpLink: null,
47
+ isFetching: false
48
+ }
49
+
50
+ const reducer = (state = defaultState, action) => {
51
+ switch (action.type) {
52
+ case FETCH_CONTEXT:
53
+ return { ...state, isFetching: true }
54
+ case FETCH_CONTEXT_SUCCESS: {
55
+ const attr =
56
+ action.context && action.context.data && action.context.data.attributes
57
+ const contextActions = flag('bar.claudy.force-all-actions')
58
+ ? Object.keys(CLAUDY_ACTIONS)
59
+ : attr && attr['claudy_actions']
60
+ // get an arrays of action
61
+ const claudyActions = contextActions
62
+ .map(slug => {
63
+ if (CLAUDY_ACTIONS.hasOwnProperty(slug)) {
64
+ // adding also the action slug
65
+ return Object.assign({}, CLAUDY_ACTIONS[slug], { slug })
66
+ }
67
+ })
68
+ .filter(action => action)
69
+ return {
70
+ ...state,
71
+ helpLink: (attr && attr['help_link']) || null,
72
+ claudyActions,
73
+ isFetching: false,
74
+ contextNotExist: false
75
+ }
76
+ }
77
+ case RECEIVE_NO_CONTEXT:
78
+ return { ...state, contextNotExist: true }
79
+ case LOG_OUT:
80
+ return defaultState
81
+ default:
82
+ return state
83
+ }
84
+ }
85
+
86
+ export default reducer
@@ -0,0 +1,73 @@
1
+ import { combineReducers } from 'redux'
2
+ import * as content from 'lib/reducers/content'
3
+ import * as locale from 'lib/reducers/locale'
4
+ import * as theme from 'lib/reducers/theme'
5
+ import * as unserializable from 'lib/reducers/unserializable'
6
+ import appsReducer, * as apps from 'lib/reducers/apps'
7
+ import settingsReducer, * as settings from 'lib/reducers/settings'
8
+ import contextReducer, * as context from 'lib/reducers/context'
9
+
10
+ const proxy = (attr, method) => {
11
+ return (state, ...args) => {
12
+ return method(state[attr], ...args)
13
+ }
14
+ }
15
+
16
+ const setContent = content.setContent
17
+ const unsetContent = content.unsetContent
18
+ const setLocale = locale.setLocale
19
+ const setTheme = theme.setTheme
20
+ const setWebviewContext = unserializable.setWebviewContext
21
+ const fetchApps = apps.fetchApps
22
+ const setInfos = apps.setInfos
23
+ const fetchSettingsData = settings.fetchSettingsData
24
+ const logOut = settings.logOut
25
+ const fetchContext = context.fetchContext
26
+ export {
27
+ setContent,
28
+ unsetContent,
29
+ setLocale,
30
+ setTheme,
31
+ setWebviewContext,
32
+ fetchApps,
33
+ setInfos,
34
+ fetchSettingsData,
35
+ logOut,
36
+ fetchContext
37
+ }
38
+
39
+ export const getContent = proxy('content', content.getContent)
40
+ export const getLocale = proxy('locale', locale.getLocale)
41
+ export const getTheme = proxy('theme', theme.getTheme)
42
+ export const getApps = proxy('apps', apps.getApps)
43
+ export const getHomeApp = proxy('apps', apps.getHomeApp)
44
+ export const isFetchingApps = proxy('apps', apps.isFetchingApps)
45
+ export const isCurrentApp = proxy('apps', apps.isCurrentApp)
46
+ export const hasFetched = proxy('apps', apps.hasFetched)
47
+ export const getStorageData = proxy('settings', settings.getStorageData)
48
+ export const getSettingsAppURL = proxy('settings', settings.getSettingsAppURL)
49
+ export const isSettingsBusy = proxy('settings', settings.isSettingsBusy)
50
+ export const isFetchingSettings = proxy('settings', settings.isFetchingSettings)
51
+ export const getHelpLink = proxy('context', context.getHelpLink)
52
+ export const getClaudyActions = proxy('context', context.getClaudyActions)
53
+ export const shouldEnableClaudy = proxy('context', context.shouldEnableClaudy)
54
+ export const getWebviewContext = proxy(
55
+ 'unserializable',
56
+ unserializable.getWebviewContext
57
+ )
58
+
59
+ // realtime handlers
60
+ export const onRealtimeCreate = apps.receiveApp
61
+ export const onRealtimeDelete = apps.deleteApp
62
+
63
+ export const reducers = {
64
+ apps: appsReducer,
65
+ content: content.reducer,
66
+ context: contextReducer,
67
+ locale: locale.reducer,
68
+ settings: settingsReducer,
69
+ theme: theme.reducer,
70
+ unserializable: unserializable.reducer
71
+ }
72
+
73
+ export default combineReducers(reducers)
@@ -0,0 +1,22 @@
1
+ export const SET_LOCALE = 'SET_LOCALE'
2
+
3
+ // action creator
4
+ export const setLocale = lang => ({
5
+ type: SET_LOCALE,
6
+ lang
7
+ })
8
+
9
+ const getDefaultLang = () => {
10
+ return document.documentElement.getAttribute('lang') || 'en'
11
+ }
12
+
13
+ export const reducer = (state = getDefaultLang(), action) => {
14
+ if (action.type === SET_LOCALE) {
15
+ return action.lang
16
+ } else {
17
+ return state
18
+ }
19
+ }
20
+
21
+ // selector
22
+ export const getLocale = state => state
@@ -0,0 +1,111 @@
1
+ import stack from 'lib/stack'
2
+
3
+ const FETCH_SETTINGS = 'FETCH_SETTINGS'
4
+ const FETCH_SETTINGS_BUSY = 'FETCH_SETTINGS_BUSY'
5
+ const FETCH_SETTINGS_SUCCESS = 'FETCH_SETTINGS_SUCCESS'
6
+ const RECEIVE_NO_CONTEXT = 'RECEIVE_NO_CONTEXT'
7
+ const RECEIVE_STORAGE = 'RECEIVE_STORAGE'
8
+ const RECEIVE_SETTINGS_URL = 'RECEIVE_SETTINGS_URL'
9
+
10
+ export const LOG_OUT = 'LOG_OUT'
11
+
12
+ const BUSY_DELAY = 450
13
+
14
+ // selectors
15
+ export const getStorageData = state => {
16
+ return state.storageData
17
+ }
18
+ export const getSettingsAppURL = state => {
19
+ return state.settingsAppURL
20
+ }
21
+ export const isSettingsBusy = state => {
22
+ return state.isBusy
23
+ }
24
+ export const isFetchingSettings = state => {
25
+ return state.isFetching
26
+ }
27
+
28
+ // actions
29
+ const fetchStorageData = () => async dispatch => {
30
+ try {
31
+ const storageData = await stack.get.storageData()
32
+ return dispatch({ type: RECEIVE_STORAGE, storageData })
33
+ } catch (e) {
34
+ // eslint-disable-next-line no-console
35
+ console.warn && console.warn('Cannot get Cozy storage informations')
36
+ return null
37
+ }
38
+ }
39
+
40
+ const fetchSettingsAppURL = () => async (dispatch, getState) => {
41
+ // If the `settings` app is available, it will used to add the links 'Profile' and 'Connected Devices'
42
+ if (getState().settings.settingsAppURL) {
43
+ return dispatch({
44
+ type: RECEIVE_SETTINGS_URL,
45
+ settingsAppURL: getState().settings.settingsAppURL
46
+ })
47
+ }
48
+ try {
49
+ const settingsAppURL = await stack.get.settingsAppURL()
50
+ return dispatch({ type: RECEIVE_SETTINGS_URL, settingsAppURL })
51
+ } catch (e) {
52
+ // eslint-disable-next-line no-console
53
+ console.warn('Settings app is unavailable, settings links are disabled')
54
+ return null
55
+ }
56
+ }
57
+
58
+ export const fetchSettingsData = (displayBusy = true) => async dispatch => {
59
+ dispatch({ type: FETCH_SETTINGS })
60
+ // put the busy status after BUSY_DELAY secs
61
+ const busySpinner = setTimeout(() => {
62
+ // we do not display the busy status in the drawer
63
+ if (displayBusy) dispatch({ type: FETCH_SETTINGS_BUSY })
64
+ }, BUSY_DELAY)
65
+ await dispatch(fetchStorageData())
66
+ await dispatch(fetchSettingsAppURL())
67
+ clearTimeout(busySpinner)
68
+ dispatch({ type: FETCH_SETTINGS_SUCCESS })
69
+ }
70
+
71
+ export const logOut = () => async dispatch => {
72
+ dispatch({ type: LOG_OUT })
73
+ try {
74
+ await stack.logout()
75
+ } catch (e) {
76
+ // eslint-disable-next-line no-console
77
+ console.warn('Error while logging out in the cozy-bar', e)
78
+ }
79
+ }
80
+
81
+ // reducers
82
+ const defaultState = {
83
+ contextNotExist: false,
84
+ isFetching: false,
85
+ isBusy: false,
86
+ settingsAppURL: null,
87
+ storageData: null
88
+ }
89
+
90
+ const reducer = (state = defaultState, action) => {
91
+ switch (action.type) {
92
+ case FETCH_SETTINGS:
93
+ return { ...state, isFetching: true }
94
+ case FETCH_SETTINGS_BUSY:
95
+ return { ...state, isBusy: true }
96
+ case FETCH_SETTINGS_SUCCESS:
97
+ return { ...state, isFetching: false, isBusy: false }
98
+ case RECEIVE_NO_CONTEXT:
99
+ return { ...state, contextNotExist: true }
100
+ case RECEIVE_STORAGE:
101
+ return { ...state, storageData: action.storageData }
102
+ case RECEIVE_SETTINGS_URL:
103
+ return { ...state, settingsAppURL: action.settingsAppURL }
104
+ case LOG_OUT:
105
+ return defaultState
106
+ default:
107
+ return state
108
+ }
109
+ }
110
+
111
+ export default reducer
@@ -0,0 +1,48 @@
1
+ const SET_THEME = 'SET_THEME'
2
+ const DEFAULT_THEME = 'default'
3
+ const PRIMARY_THEME = 'primary'
4
+ const THEMES = [DEFAULT_THEME, PRIMARY_THEME]
5
+ const EMPTY_OVERRIDES = {}
6
+
7
+ // Theme state is { name, overrides }
8
+ // where both have the form described in `setTheme`
9
+ const DEFAULT_STATE = { name: DEFAULT_THEME, overrides: EMPTY_OVERRIDES }
10
+
11
+ /**
12
+ * Change the cozy-bar theme
13
+ *
14
+ * Today, the value 'primary' will change the background color
15
+ * of the bar in the mobile view. It will then use the
16
+ * `--primaryColor` CSS variable and the `--primaryContrastTextColor`
17
+ * for the text.
18
+ *
19
+ * @function
20
+ * @param {String} name - either 'default' or 'primary'
21
+ * @param {Object} overrides - overrides of default values for the theme
22
+ * default to an empty object (no overrides)
23
+ * It will only overrides the values for the
24
+ * 'primary' specific theme/view
25
+ * @param {Object} overrides.primaryColor - the background color
26
+ * @param {Object} overrides.primaryContrastTextColor - the text color
27
+ * @returns {Object} action `{ type: SET_THEME, theme: {name, overrides} }
28
+ */
29
+ export const setTheme = (name, overrides = EMPTY_OVERRIDES) => ({
30
+ type: SET_THEME,
31
+ theme: { name, overrides }
32
+ })
33
+
34
+ export const getDefaultTheme = () => DEFAULT_STATE
35
+
36
+ export const reducer = (state = getDefaultTheme(), action) => {
37
+ if (action.type === SET_THEME) {
38
+ if (THEMES.includes(action.theme.name)) {
39
+ return action.theme
40
+ }
41
+ return { ...action.theme, name: DEFAULT_THEME }
42
+ } else {
43
+ return state
44
+ }
45
+ }
46
+
47
+ // selector
48
+ export const getTheme = state => state
@@ -0,0 +1,26 @@
1
+ const SET_WEBVIEW_CONTEXT = 'SET_WEBVIEW_CONTEXT'
2
+
3
+ // selectors
4
+ export const getWebviewContext = state => {
5
+ return state.webviewContext
6
+ }
7
+
8
+ // actions
9
+ export const setWebviewContext = payload => ({
10
+ type: SET_WEBVIEW_CONTEXT,
11
+ payload
12
+ })
13
+
14
+ // reducers
15
+ const defaultState = {
16
+ webviewContext: undefined
17
+ }
18
+
19
+ export const reducer = (state = defaultState, action) => {
20
+ switch (action.type) {
21
+ case SET_WEBVIEW_CONTEXT:
22
+ return { ...state, webviewContext: action.payload }
23
+ default:
24
+ return state
25
+ }
26
+ }