diff --git a/src/components/BanksLink.jsx b/src/components/BanksLink.jsx deleted file mode 100644 index 2455ae27be..0000000000 --- a/src/components/BanksLink.jsx +++ /dev/null @@ -1,47 +0,0 @@ -import React from 'react' - -import AppLinker from 'cozy-ui/transpiled/react/AppLinker' -import Icon from 'cozy-ui/transpiled/react/Icon' -import styles from 'styles/konnectorSuccess.styl' -import OpenwithIcon from 'cozy-ui/transpiled/react/Icons/Openwith' - -import { useI18n } from 'cozy-ui/transpiled/react' -import { useClient } from 'cozy-client' -import Intents from 'cozy-interapp' - -const BanksLink = ({ banksUrl }) => { - const { t } = useI18n() - const client = useClient() - const intents = new Intents({ client }) - return banksUrl ? ( - - {({ href, onClick, name }) => ( - - - {t('account.success.banksLinkText', { - appName: name - })} - - )} - - ) : ( - - intents.redirect('io.cozy.apps', { slug: 'banks' }, url => { - window.top.location.href = url - }) - } - > - - {t('account.success.banksLinkText')} - - ) -} - -export default BanksLink diff --git a/src/components/KonnectorErrors.jsx b/src/components/KonnectorErrors.jsx deleted file mode 100644 index 2d7afcc9f9..0000000000 --- a/src/components/KonnectorErrors.jsx +++ /dev/null @@ -1,209 +0,0 @@ -import PropTypes from 'prop-types' -import React from 'react' -import flow from 'lodash/flow' -import keyBy from 'lodash/keyBy' -import { connect } from 'react-redux' -import { useClient, models } from 'cozy-client' -import { useNavigate } from 'react-router-dom' - -import AppIcon from 'cozy-ui/transpiled/react/AppIcon' -import Button from 'cozy-ui/transpiled/react/deprecated/Button' -import CrossButton from 'cozy-ui/transpiled/react/Icons/Cross' -import Divider from 'cozy-ui/transpiled/react/Divider' -import Icon from 'cozy-ui/transpiled/react/Icon' -import IconButton from 'cozy-ui/transpiled/react/IconButton' -import Infos from 'cozy-ui/transpiled/react/deprecated/Infos' -import InfosCarrousel from 'cozy-ui/transpiled/react/deprecated/InfosCarrousel' -import Typography from 'cozy-ui/transpiled/react/Typography' -import useBreakpoints from 'cozy-ui/transpiled/react/hooks/useBreakpoints' -import { Media, Bd } from 'cozy-ui/transpiled/react/deprecated/Media' -import { getErrorLocaleBound, KonnectorJobError } from 'cozy-harvest-lib' -import { useI18n } from 'cozy-ui/transpiled/react/I18n' - -import { - getAccountsWithErrors, - getInstalledKonnectors, - getTriggersInError -} from 'reducers/index' -import ReactMarkdownWrapper from 'components/ReactMarkdownWrapper' -import homeConfig from 'config/home.json' - -const { - triggers: { triggers: triggersModel, triggerStates: triggerStatesModel }, - accounts: accountsModel -} = models - -const muteTrigger = async (client, trigger, accountsById) => { - const accountId = triggersModel.getAccountId(trigger) - const initialAccount = accountsById[accountId] - const errorType = triggerStatesModel.getLastErrorType(trigger) - const account = accountsModel.muteError(initialAccount, errorType) - - await client.save(account) -} - -const getKonnectorSlug = konnector => konnector.slug - -// TODO, use directly Infos prop dismissAction when -// https://github.com/cozy/cozy-ui/pull/1724 is merged -// Here we need the aria-label for tests, and IconButton for style -const InfosDismissButton = ({ onClick }) => { - const { t } = useI18n() - return ( - - - - ) -} - -const dismissButtonStyle = { - position: 'absolute', - top: '0.5rem', - right: '0.5rem' -} - -const KonnectorError = ({ - trigger, - triggerErrors, - index, - konnectorsBySlug, - accountsById -}) => { - const client = useClient() - const { t, lang } = useI18n() - const { isMobile } = useBreakpoints() - const errorType = triggerStatesModel.getLastErrorType(trigger) - const konnError = new KonnectorJobError(errorType) - const konnectorSlug = triggersModel.getKonnector(trigger) - const konnectorAccount = triggersModel.getAccountId(trigger) - const konnector = konnectorsBySlug[konnectorSlug] - const navigate = useNavigate() - - const errorTitle = getErrorLocaleBound(konnError, konnector, lang, 'title') - - const errorDescription = getErrorLocaleBound( - konnError, - konnector, - lang, - 'description' - ) - - const handleDismiss = () => { - muteTrigger(client, trigger, accountsById) - } - - return ( - - - - - - - {konnector.name} - - - {triggerErrors.length > 1 - ? `(${index + 1}/${triggerErrors.length}) ` - : null} - {errorTitle} - - - - - - - - - > - } - action={ - - navigate(`/connected/${konnectorSlug}/accounts/${konnectorAccount}`) - } - /> - } - /> - ) -} - -export const KonnectorErrors = ({ - triggersInError, - accountsWithErrors, - installedKonnectors -}) => { - const accountsWithErrorsById = keyBy(accountsWithErrors, '_id') - const installedKonnectorsBySlug = keyBy(installedKonnectors, getKonnectorSlug) - const nonMutedTriggerErrors = triggersInError.filter(trigger => { - const errorType = triggerStatesModel.getLastErrorType(trigger) - const accountId = triggersModel.getAccountId(trigger) - const account = accountsWithErrorsById[accountId] - const konnectorSlug = triggersModel.getKonnector(trigger) - const hasInstalledKonnector = - installedKonnectors && - installedKonnectors.some(({ slug }) => slug === konnectorSlug) - - return ( - homeConfig.displayedErrorTypes.includes(errorType) && - hasInstalledKonnector && - account && - !triggersModel.isLatestErrorMuted(trigger, account) - ) - }) - - return nonMutedTriggerErrors.length > 0 ? ( - - - {nonMutedTriggerErrors.map((trigger, index) => ( - - ))} - - - ) : ( - - ) -} - -KonnectorErrors.propTypes = { - accountsWithErrors: PropTypes.array.isRequired, - installedKonnectors: PropTypes.arrayOf(PropTypes.object.isRequired), - triggersInError: PropTypes.array.isRequired -} - -const mapStateToProps = state => { - return { - accountsWithErrors: getAccountsWithErrors(state), - installedKonnectors: getInstalledKonnectors(state), - triggersInError: getTriggersInError(state) - } -} - -export default flow(connect(mapStateToProps))(KonnectorErrors) diff --git a/src/components/KonnectorErrors.spec.jsx b/src/components/KonnectorErrors.spec.jsx deleted file mode 100644 index 37da816a79..0000000000 --- a/src/components/KonnectorErrors.spec.jsx +++ /dev/null @@ -1,263 +0,0 @@ -import React from 'react' -import MockDate from 'mockdate' -import { KonnectorErrors } from './KonnectorErrors' -import AppLike from 'test/AppLike' -import { render, fireEvent } from '@testing-library/react' - -jest.mock('cozy-ui/transpiled/react/AppIcon', () => () => null) - -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useNavigate: () => jest.fn() -})) - -describe('KonnectorErrors', () => { - const MOCKED_DATE = '2020-01-08T09:49:23.589Z' - beforeAll(() => { - MockDate.set(MOCKED_DATE) - }) - - afterAll(() => { - jest.restoreAllMocks() - MockDate.reset() - }) - - const mockClient = { - save: jest.fn() - } - - const DEFAULT_INSTALLED_KONNECTORS = [ - { slug: 'test', name: 'Test Konnector' } - ] - - const setup = ({ - triggersInError = [], - accountsWithErrors = [], - installedKonnectors = DEFAULT_INSTALLED_KONNECTORS - } = {}) => { - const root = render( - - - - ) - return { root } - } - - it('should render divider when there are no errors', () => { - const { root } = setup() - expect(root.container).toMatchSnapshot() - }) - - it('should render divider when there are errors but no installed konnector', () => { - const triggersInError = [ - { - _id: '2', - worker: 'konnector', - current_state: { - last_error: 'MUTED_ERROR', - last_success: '2019-10-01T00:48:01.404911778Z' - }, - message: { - konnector: 'test', - account: '456' - } - } - ] - const { root } = setup({ triggersInError }) - - expect(root.container).toMatchSnapshot() - }) - - it('should render divider when all errors are muted', () => { - const triggersInError = [ - { - _id: '2', - worker: 'konnector', - current_state: { - last_error: 'MUTED_ERROR', - last_success: '2019-10-01T00:48:01.404911778Z' - }, - message: { - konnector: 'test', - account: '456' - } - } - ] - const accountsWithErrors = [ - { - _id: '456', - mutedErrors: [ - { - type: 'MUTED_ERROR', - mutedAt: '2019-12-01T00:48:01.404911778Z' - } - ] - } - ] - const installedKonnectors = [{ slug: 'test', name: 'Test Konnector' }] - - const { root } = setup({ - triggersInError, - accountsWithErrors, - installedKonnectors - }) - - expect(root.container).toMatchSnapshot() - }) - - it('should render active errors', async () => { - const triggersInError = [ - { - _id: '1', - worker: 'konnector', - current_state: { - last_error: 'LOGIN_FAILED' - }, - message: { - konnector: 'test', - account: '123' - } - }, - { - _id: '2', - worker: 'konnector', - current_state: { - last_error: 'LOGIN_FAILED.NEEDS_SECRET', // this one is muted - last_success: '2019-10-01T00:48:01.404911778Z' - }, - message: { - konnector: 'test', - account: '456' - } - }, - { - _id: '3', - worker: 'konnector', - current_state: { - last_error: 'USER_ACTION_NEEDED' - }, - message: { - konnector: 'test', - account: '123' - } - }, - { - _id: '4', - worker: 'konnector', - current_state: { - last_error: 'VENDOR_DOWN' // This type of error is not displayed - }, - message: { - konnector: 'test', - account: '123' - } - } - ] - const accountsWithErrors = [ - { _id: '123', mutedErrors: [] }, - { - _id: '456', - mutedErrors: [ - { - type: 'LOGIN_FAILED.NEEDS_SECRET', - mutedAt: '2019-12-01T00:48:01.404911778Z' - } - ] - } - ] - const installedKonnectors = [{ slug: 'test', name: 'Test Konnector' }] - const { root } = setup({ - triggersInError, - accountsWithErrors, - installedKonnectors - }) - - expect( - root.getByText('(1/2) Incorrect or expired credentials') - ).toBeTruthy() - - const dismissButton = root.getByLabelText('Mute error') - await fireEvent.click(dismissButton) - - expect(mockClient.save).toHaveBeenCalledWith({ - _id: '123', - mutedErrors: [{ mutedAt: MOCKED_DATE, type: 'LOGIN_FAILED' }] - }) - }) - - it('should hide errors when the konnector or account is missing', () => { - const triggersInError = [ - { - _id: '1', - worker: 'konnector', - current_state: { - last_error: 'LOGIN_FAILED' - }, - message: { - konnector: 'uninstalled', - account: '123' - } - }, - { - _id: '2', - worker: 'konnector', - current_state: { - last_error: 'LOGIN_FAILED' - }, - message: { - konnector: 'uninstalled', - account: 'no-account' - } - } - ] - const accountsWithErrors = [{ _id: '123', mutedErrors: [] }] - const installedKonnectors = [] - const { root } = setup({ - triggersInError, - accountsWithErrors, - installedKonnectors - }) - expect(root.container).toMatchSnapshot() - }) - - it('should not show slide indicator with only one slide', () => { - const triggersInError = [ - { - _id: '1', - worker: 'konnector', - current_state: { - last_error: 'LOGIN_FAILED' - }, - message: { - konnector: 'test', - account: '123' - } - } - ] - const accountsWithErrors = [ - { _id: '123', mutedErrors: [] }, - { - _id: '456', - mutedErrors: [ - { - type: 'LOGIN_FAILED.NEEDS_SECRET', - mutedAt: '2019-12-01T00:48:01.404911778Z' - } - ] - } - ] - const installedKonnectors = [{ slug: 'test', name: 'Test Konnector' }] - const { root } = setup({ - triggersInError, - accountsWithErrors, - installedKonnectors - }) - - // 1/1 is not displayed - expect(root.getByText('Incorrect or expired credentials')) - }) -}) diff --git a/src/components/KonnectorHeaderIcon.jsx b/src/components/KonnectorHeaderIcon.jsx deleted file mode 100644 index fd5d1ae512..0000000000 --- a/src/components/KonnectorHeaderIcon.jsx +++ /dev/null @@ -1,35 +0,0 @@ -import React, { Component } from 'react' -import { translate } from 'cozy-ui/transpiled/react/I18n' -import PropTypes from 'prop-types' -import AppIcon from 'cozy-ui/transpiled/react/AppIcon' - -import styles from 'styles/konnectorHeaderIcon.styl' - -export class KonnectorHeaderIcon extends Component { - render() { - const { center, konnector, t } = this.props - return ( - - - - ) - } -} - -KonnectorHeaderIcon.propTypes = { - center: PropTypes.bool, - konnector: PropTypes.object.isRequired, - t: PropTypes.func.isRequired -} - -export default translate()(KonnectorHeaderIcon) diff --git a/src/components/KonnectorInstall.jsx b/src/components/KonnectorInstall.jsx deleted file mode 100644 index 00b953d616..0000000000 --- a/src/components/KonnectorInstall.jsx +++ /dev/null @@ -1,99 +0,0 @@ -import React, { Component } from 'react' -import { connect } from 'react-redux' - -import { IntentTriggerManager } from 'cozy-harvest-lib' -import { translate } from 'cozy-ui/transpiled/react/I18n' - -import KonnectorSuccess from 'components/KonnectorSuccess' -import { getKonnector } from 'ducks/konnectors' -import styles from 'styles/konnectorInstall.styl' - -const vaultUnlockFormProps = { useAllAvailableSpace: true } - -export class KonnectorInstall extends Component { - constructor(props) { - super(props) - this.state = { - trigger: null, - success: false - } - this.handleLoginSuccess = this.handleLoginSuccess.bind(this) - this.handleSuccess = this.handleSuccess.bind(this) - } - - handleLoginSuccess(trigger) { - this.setState({ - trigger, - success: true - }) - - this.props.onLoginSuccess(trigger) - } - - handleSuccess(trigger) { - this.setState({ - trigger, - success: true - }) - - this.props.onSuccess(trigger) - } - - render() { - console.log('KonnectorInstall') - - const { - account, - konnector, - legacySuccess, - onDone, - successMessage, - successMessages, - successButtonLabel, - t, - onCancel - } = this.props - - const { trigger, success } = this.state - console.log('success', success) - console.log('legacySuccess', legacySuccess) - if (success || legacySuccess) { - return ( - - ) - } - return ( - - - - {t('account.config.title', { name: konnector.name })} - - - - - ) - } -} - -const mapStateToProps = (state, ownProps) => ({ - konnector: getKonnector(state.cozy, ownProps.connector.slug) -}) - -export default translate()(connect(mapStateToProps)(KonnectorInstall)) diff --git a/src/components/KonnectorMaintenance.jsx b/src/components/KonnectorMaintenance.jsx deleted file mode 100644 index 2dcbd7d5f7..0000000000 --- a/src/components/KonnectorMaintenance.jsx +++ /dev/null @@ -1,31 +0,0 @@ -import React from 'react' - -import ReactMarkdownWrapper from 'components/ReactMarkdownWrapper' - -import styles from 'styles/konnectorMaintenance.styl' -import { useI18n } from 'cozy-ui/transpiled/react' - -const KonnectorMaintenance = ({ maintenance, lang, konnectorName }) => { - const { t } = useI18n() - - return ( - - - - - {t('maintenance.service')} - - - {t('maintenance.problem', { konnectorName })} - - - {t('maintenance.title')} - - - ) -} - -export default KonnectorMaintenance diff --git a/src/components/KonnectorSuccess.jsx b/src/components/KonnectorSuccess.jsx deleted file mode 100644 index 1b281eabad..0000000000 --- a/src/components/KonnectorSuccess.jsx +++ /dev/null @@ -1,153 +0,0 @@ -import classNames from 'classnames' -import has from 'lodash/has' -import sortBy from 'lodash/sortBy' -import React, { Component } from 'react' -import PropTypes from 'prop-types' - -import Button from 'cozy-ui/transpiled/react/deprecated/Button' -import { translate } from 'cozy-ui/transpiled/react/I18n' - -import styles from 'styles/konnectorSuccess.styl' -import DescriptionContent from 'components/DescriptionContent' -import TriggerFolderLink from 'components/TriggerFolderLink' -import BanksLink from 'components/BanksLink' -import connectingIllu from 'assets/images/connecting-data-in-progress.svg' - -const SuccessImage = () => ( - - - -) - -const SuccessLinks = ({ children }) => ( - - {children} - -) - -const DriveLink = translate()(({ folderId, t }) => ( - -)) - -const SuccessFooter = translate()(({ children }) => ( - - {children} - -)) - -export class KonnectorSuccess extends Component { - componentDidMount() { - if (typeof this.props.handleConnectionSuccess === 'function') { - this.props.handleConnectionSuccess() - } - } - - render() { - const { account, error, title, messages } = this.props - const relatedApps = sortBy( - Object.values(KonnectorSuccess.apps).filter(app => - app.predicate(this.props) - ), - app => -app.priority - ) - - const hasLinks = relatedApps.length > 0 - - return ( - account && ( - - {!error && } - - {hasLinks && ( - - {relatedApps.map((app, i) => - // Should always pass context, since it's used for customisation - app.successLink(this.props, this.context, i) - )} - - )} - - - - {relatedApps.length > 0 - ? // Should always pass context, since it's used for customisation - relatedApps[0].footerLink(this.props, this.context) - : null} - - - ) - ) - } -} - -KonnectorSuccess.apps = { - drive: { - priority: 1, - // eslint-disable-next-line react/display-name - predicate: props => { - const trigger = props.trigger - const res = has(trigger, 'message.folder_to_save') - return res - }, - // eslint-disable-next-line react/display-name - successLink: (props, context, i) => { - return ( - - ) - }, - // eslint-disable-next-line react/display-name - footerLink: props => { - const { t, onDone, account, successButtonLabel } = props - return ( - { - event.preventDefault() - onDone(account) - }} - /> - ) - } - }, - - banks: { - priority: 0, - // eslint-disable-next-line react/display-name - predicate: props => { - const connector = props.connector - return ( - Array.isArray(connector.data_types) && - connector.data_types.includes('bankAccounts') - ) - }, - // eslint-disable-next-line react/display-name - successLink: (props, context, i) => { - return - }, - footerLink: () => null - } -} - -KonnectorSuccess.contextTypes = { - store: PropTypes.object -} - -KonnectorSuccess.propTypes = { - account: PropTypes.object.isRequired, - error: PropTypes.string, - title: PropTypes.string.isRequired, - messages: PropTypes.arrayOf(PropTypes.string), - onDone: PropTypes.func.isRequired, - successButtonLabel: PropTypes.string, - trigger: PropTypes.object.isRequired -} - -export { SuccessImage, SuccessLinks, BanksLink, DriveLink } - -export default translate()(KonnectorSuccess) diff --git a/src/components/KonnectorSuccess.spec.jsx b/src/components/KonnectorSuccess.spec.jsx deleted file mode 100644 index eca978fbd4..0000000000 --- a/src/components/KonnectorSuccess.spec.jsx +++ /dev/null @@ -1,81 +0,0 @@ -import React from 'react' -import { render, screen } from '@testing-library/react' - -import AppLike from 'test/AppLike' -import KonnectorSuccess from './KonnectorSuccess' - -// @TODO: some pretty ugly mocks here because the app uses different react-redux versions -jest.mock('react-redux/lib/utils/Subscription', () => ({ - createSubscription: () => ({ - trySubscribe: () => jest.fn(), - tryUnsubscribe: () => jest.fn(), - notifyNestedSubs: () => jest.fn() - }) -})) - -jest.mock( - 'cozy-client/node_modules/react-redux/lib/utils/Subscription', - () => ({ - __esModule: true, - default: () => ({ - trySubscribe: () => jest.fn(), - tryUnsubscribe: () => jest.fn() - }) - }) -) - -describe('KonnectorSuccess', () => { - let trigger, connector - const fakeStore = { - banksUrl: 'https://example-banks.mycozy.cloud', - getState: () => ({}), - subscribe: () => ({}), - dispatch: () => ({}) - } - const setup = () => { - render( - - {}} - connector={connector} - trigger={trigger} - /> - - ) - } - - beforeEach(() => { - connector = {} - trigger = { message: {} } - }) - - it('should not show drive if trigger has no folder_to_save', () => { - setup() - expect( - screen.queryByText('Open the folder in Cozy Drive') - ).not.toBeInTheDocument() - }) - - it('should show drive if trigger has a folder_to_save', async () => { - trigger.message.folder_to_save = 'deadbeef' - setup() - expect( - await screen.findByText('Open the folder in Cozy Drive') - ).toBeInTheDocument() - }) - - it('should show banks if connector has datatypes with bankAccounts', async () => { - connector.data_types = ['bankAccounts'] - setup() - expect( - screen.queryByText('Open the folder in Cozy Drive') - ).not.toBeInTheDocument() - expect( - await screen.findByText('See my accounts in Cozy Banks') - ).toBeInTheDocument() - }) -}) diff --git a/src/components/Services.jsx b/src/components/Services.jsx index a402cd9ef1..063f4241b0 100644 --- a/src/components/Services.jsx +++ b/src/components/Services.jsx @@ -5,7 +5,6 @@ import { useClient, useAppsInMaintenance, useQuery } from 'cozy-client' import keyBy from 'lodash/keyBy' import has from 'lodash/has' -import KonnectorErrors from 'components/KonnectorErrors' import AddServiceTile from 'components/AddServiceTile' import KonnectorTile from 'components/KonnectorTile' import CandidateCategoryTile from 'components/CandidateCategoryTile' @@ -79,7 +78,6 @@ export const Services = () => { return ( - {installedKonnectors.map(konnector => ( { - this.setState({ isSuccess: true }) - } - - render() { - console.log('CREATE ACCOUNT INTENT ???') - const { konnector, onCancel, onTerminate } = this.props - const { isSuccess } = this.state - console.log('isSuccess', isSuccess) - return ( - - {!isSuccess && } - {konnector && ( - onCancel()} - onSuccess={onTerminate} - handleConnectionSuccess={this.handleConnectionSuccess} - /> - )} - - ) - } -} - -CreateAccountIntent.contextTypes = { - store: PropTypes.object -} - -export default CreateAccountIntent diff --git a/src/components/services/CreateAccountService.jsx b/src/components/services/CreateAccountService.jsx deleted file mode 100644 index 1c3e3ce771..0000000000 --- a/src/components/services/CreateAccountService.jsx +++ /dev/null @@ -1,65 +0,0 @@ -import React from 'react' -import { connect } from 'react-redux' - -import { translate } from 'cozy-ui/transpiled/react/I18n' - -import AccountConnection from 'containers/AccountConnection' -import { - endConnectionCreation, - startConnectionCreation -} from 'ducks/connections' -import { - getCreatedConnectionAccount, - getTriggerByKonnectorAndAccount -} from 'reducers/index' - -class CreateAccountService extends React.Component { - constructor(props, context) { - super(props, context) - this.props.startCreation(this.props.konnector) - } - - onSuccess = account => { - this.props.endCreation() - this.props.onSuccess(account) - } - - render() { - const { t } = this.props - console.log('CREATE ACCOUNT SERVICE') - return ( - - - - ) - } -} - -const mapStateToProps = (state, ownProps) => { - // infos from route parameters - const { konnector } = ownProps - const createdAccount = getCreatedConnectionAccount(state) - const trigger = getTriggerByKonnectorAndAccount( - state, - konnector, - createdAccount - ) - return { - createdAccount, - trigger - } -} - -const mapDispatchToProps = (dispatch, ownProps) => ({ - startCreation: () => dispatch(startConnectionCreation(ownProps.konnector)), - endCreation: () => dispatch(endConnectionCreation()) -}) - -export default connect( - mapStateToProps, - mapDispatchToProps -)(translate()(CreateAccountService)) diff --git a/src/containers/AccountConnection.jsx b/src/containers/AccountConnection.jsx deleted file mode 100644 index 14ca47dcf2..0000000000 --- a/src/containers/AccountConnection.jsx +++ /dev/null @@ -1,165 +0,0 @@ -import PropTypes from 'prop-types' -import React, { Component } from 'react' -import { connect } from 'react-redux' - -import { translate } from 'cozy-ui/transpiled/react/I18n' - -import KonnectorInstall from 'components/KonnectorInstall' -import KonnectorMaintenance from 'components/KonnectorMaintenance' -import UpdateMessage from 'components/Banners/UpdateMessage' -import styles from 'styles/accountConnection.styl' -import { isKonnectorUpdateNeededError } from 'lib/konnectors' -import { - enqueueConnection, - getConnectionError, - isConnectionConnected, - isConnectionEnqueued -} from 'ducks/connections' - -class AccountConnection extends Component { - constructor(props, context) { - super(props, context) - this.store = context.store - - this.state = { - isFetching: false, - maintenance: props.maintenance && props.maintenance[props.konnector.slug] - } - - this.handleLoginSuccess = this.handleLoginSuccess.bind(this) - this.handleError = this.handleError.bind(this) - this.handleDeleteSuccess = this.handleDeleteSuccess.bind(this) - } - - componentDidMount() { - if (this.props.error) this.handleError({ message: this.props.error }) - } - - componentDidUpdate(prevProps) { - const { success, queued } = this.props - const { connectionError } = this.state - - const succeed = !prevProps.success && success - const loginSucceed = !prevProps.queued && queued - - if (succeed || loginSucceed) { - // we reset the error in case of persisted errors - if (succeed && connectionError) this.setState({ connectionError: null }) - this.props.handleConnectionSuccess() - } - } - - handleLoginSuccess(trigger) { - const { enqueueConnection, handleConnectionSuccess } = this.props - handleConnectionSuccess() - enqueueConnection(trigger) - } - - handleDeleteSuccess() { - this.setState({ - submitting: false - }) - - this.props.handleDeleteSuccess() - } - - handleError(error) { - // eslint-disable-next-line no-console - console.error(error) - - this.setState({ - submitting: false, - connectionError: error.message - }) - } - - buildSuccessMessages(konnector) { - const { t } = this.props - const messages = [ - t('account.message.success.connect', { - name: konnector.name - }) - ] - - if ( - konnector.additionnalSuccessMessage && - konnector.additionnalSuccessMessage.message - ) { - messages.push(t(konnector.additionnalSuccessMessage.message)) - } - - return messages - } - - render() { - const { - createdAccount, - error, - handleConnectionSuccess, - konnector, - lang, - onCancel, - onDone, - queued, - success, - successButtonLabel, - t - } = this.props - const { connectionError, oAuthError, maintenance } = this.state - const successMessages = - success || queued ? this.buildSuccessMessages(konnector) : [] - const konnectorError = error || oAuthError || connectionError - return ( - - {!!konnector.available_version && ( - - )} - {maintenance ? ( - - ) : ( - - )} - - ) - } -} - -AccountConnection.contextTypes = { - store: PropTypes.object -} - -const mapStateToProps = (state, ownProps) => ({ - error: getConnectionError(state.connections, ownProps.trigger), - queued: isConnectionEnqueued(state.connections, ownProps.trigger), - success: isConnectionConnected(state.connections, ownProps.trigger) -}) - -const mapDispatchToProps = dispatch => { - return { - enqueueConnection: trigger => dispatch(enqueueConnection(trigger)) - } -} - -export default connect( - mapStateToProps, - mapDispatchToProps -)(translate()(AccountConnection)) diff --git a/src/ducks/accounts/index.js b/src/ducks/accounts/index.js deleted file mode 100644 index 02bd5bb7f9..0000000000 --- a/src/ducks/accounts/index.js +++ /dev/null @@ -1,22 +0,0 @@ -export const DOCTYPE = 'io.cozy.accounts' - -// selectors -export const getAccount = (state, id) => { - if (!state.documents || !state.documents[DOCTYPE]) { - return null - } - - return state.documents[DOCTYPE][id] -} - -export const getIds = state => - // state.collection is bugged, it does not update correctly id list on - // RECEIVE_DATA - // (state.collections && - // state.collections[accountCollectionKey] && - // state.collections[accountCollectionKey].ids) || - // [] - (state.documents && - state.documents[DOCTYPE] && - Object.keys(state.documents[DOCTYPE])) || - [] diff --git a/src/ducks/connections/index.js b/src/ducks/connections/index.js deleted file mode 100644 index 9bd87e91a3..0000000000 --- a/src/ducks/connections/index.js +++ /dev/null @@ -1,380 +0,0 @@ -import { combineReducers } from 'redux' -import omit from 'lodash/omit' -import get from 'lodash/get' -import { buildKonnectorError } from 'lib/konnectors' - -// constant -const ACCOUNT_DOCTYPE = 'io.cozy.accounts' -const TRIGGERS_DOCTYPE = 'io.cozy.triggers' -const JOBS_DOCTYPE = 'io.cozy.jobs' - -export const ENQUEUE_CONNECTION = 'ENQUEUE_CONNECTION' -export const LAUNCH_TRIGGER = 'LAUNCH_TRIGGER' -export const PURGE_QUEUE = 'PURGE_QUEUE' -export const RECEIVE_DATA = 'RECEIVE_DATA' -export const RECEIVE_NEW_DOCUMENT = 'RECEIVE_NEW_DOCUMENT' -export const RECEIVE_DELETED_DOCUMENT = 'RECEIVE_DELETED_DOCUMENT' -export const UPDATE_CONNECTION_RUNNING_STATUS = - 'UPDATE_CONNECTION_RUNNING_STATUS' -export const UPDATE_CONNECTION_ERROR = 'UPDATE_CONNECTION_ERROR' -export const START_CONNECTION_CREATION = 'START_CONNECTION_CREATION' -export const END_CONNECTION_CREATION = 'END_CONNECTION_CREATION' - -// Helpers -const getTriggerKonnectorSlug = trigger => - (trigger && trigger.message && trigger.message.konnector) || null - -export const isKonnectorTrigger = doc => - doc._type === TRIGGERS_DOCTYPE && !!doc.message && !!doc.message.konnector - -export const isKonnectorJob = doc => - doc._type === JOBS_DOCTYPE && - (doc.worker === 'konnector' || doc.worker === 'client') - -// reducers -const reducer = (state = {}, action) => { - switch (action.type) { - case ENQUEUE_CONNECTION: - case UPDATE_CONNECTION_ERROR: - case UPDATE_CONNECTION_RUNNING_STATUS: - case LAUNCH_TRIGGER: - // Ignore the action if trigger does not have an id - // This is possible that an enqueue connection is dispatched - // with a trigger without _id, this is because for banking - // konnectors, the LOGIN_SUCCESS action is dispatched before - // the trigger has been created, thus a fake trigger is created - if (!action.trigger || !action.trigger._id) { - return state - } - if (!action.trigger.message || !action.trigger.message.konnector) { - return state - } - return { - ...state, - [getTriggerKonnectorSlug(action.trigger)]: konnectorReducer( - state[getTriggerKonnectorSlug(action.trigger)], - action - ) - } - - case RECEIVE_DATA: - case RECEIVE_NEW_DOCUMENT: - if ( - !action.response || - !action.response.data || - !action.response.data.length - ) { - return state - } - - return action.response.data.reduce((newState, doc) => { - const isTrigger = isKonnectorTrigger(doc) - const isJob = isKonnectorJob(doc) - // Ignore non triggers or non jobs - if (!isTrigger && !isJob) return newState - const konnectorSlug = doc.message.konnector - const triggerId = (isTrigger && doc._id) || (isJob && doc.trigger_id) - if (!triggerId) return newState - - const account = isTrigger && !!doc.message && doc.message.account - - const currentStatus = - (isTrigger && doc.current_state && doc.current_state.status) || - (isJob && doc.state) - - const error = - (isTrigger && - !!doc.current_state && - doc.current_state.status !== 'done' && - !!doc.current_state.last_error && - buildKonnectorError(doc.current_state.last_error)) || - (isJob && !!doc.error && buildKonnectorError(doc.error)) || - null - - const lastSyncDate = - (isTrigger && - !!doc.current_state && - doc.current_state.last_execution) || - (isJob && doc.queued_at) - const existingTriggers = get( - newState, - [konnectorSlug, 'triggers', 'data'], - [] - ) - let rawTriggers = existingTriggers - - if (isTrigger) { - rawTriggers = existingTriggers.filter(({ _id }) => _id !== doc._id) - rawTriggers.push(doc) - } - return { - ...newState, - [konnectorSlug]: { - triggers: { - ...get(newState, [konnectorSlug, 'triggers'], []), - data: rawTriggers, - [triggerId]: { - ...get(newState, [konnectorSlug, 'triggers', triggerId], {}), - account: - account || - get(newState, [ - konnectorSlug, - 'triggers', - triggerId, - 'account' - ]), - error, - hasError: !!error || currentStatus === 'errored', - isRunning: ['queued', 'running'].includes(currentStatus), - isConnected: !error && currentStatus === 'done', - lastSyncDate: lastSyncDate - } - } - } - } - }, state) - - case PURGE_QUEUE: - case RECEIVE_DELETED_DOCUMENT: - return Object.keys(state).reduce((konnectors, slug) => { - return { - ...konnectors, - [slug]: konnectorReducer(state[slug], action) - } - }, state) - - default: - return state - } -} - -const creation = (state = null, action) => { - switch (action.type) { - case RECEIVE_DATA: - case RECEIVE_NEW_DOCUMENT: { - if (!state) return null - if ( - !action.response || - !action.response.data || - action.response.data.length !== 1 - ) { - return state - } - - const doc = action.response.data[0] - const isAccount = doc._type === ACCOUNT_DOCTYPE - - if (isAccount) - return { - ...state, - account: doc._id - } - - const isTrigger = isKonnectorTrigger(doc) - if (isTrigger) - return { - ...state, - trigger: doc._id - } - - return state - } - case START_CONNECTION_CREATION: - // Store all data related to the creation of a new connection in then - // property `creation` - // While a new connection is being configured, new trigger and account - // are store here - return {} - case END_CONNECTION_CREATION: - return null - default: - return state - } -} - -export default combineReducers({ - creation, - konnectors: reducer -}) - -// sub(?) reducers -const konnectorReducer = (state = {}, action) => { - switch (action.type) { - case ENQUEUE_CONNECTION: - case LAUNCH_TRIGGER: - case RECEIVE_DATA: - case RECEIVE_NEW_DOCUMENT: - case RECEIVE_DELETED_DOCUMENT: - case PURGE_QUEUE: - // We assume that document being a trigger has already been validated. - return { - ...state, - triggers: triggersReducer(state.triggers, action) - } - default: - return state - } -} - -const triggersReducer = (state = {}, action) => { - switch (action.type) { - case ENQUEUE_CONNECTION: - return { - ...state, - [action.trigger._id]: { - ...state[action.trigger._id], - isEnqueued: true - } - } - case LAUNCH_TRIGGER: - return { - ...state, - [action.trigger._id]: { - ...state[action.trigger._id], - account: action.trigger.message.account, - isRunning: true - } - } - case PURGE_QUEUE: - return state - ? Object.keys(state).reduce((newState, triggerId) => { - return { - ...newState, - [triggerId]: { - ...newState[triggerId], - isEnqueued: false - } - } - }, state) - : state - case RECEIVE_DELETED_DOCUMENT: { - const { data } = action.response - const { _id, _type } = data[0] - if (_type === TRIGGERS_DOCTYPE) { - return omit(state, _id) - } else return state - } - default: - return state - } -} - -// action creators sync -export const enqueueConnection = trigger => ({ - type: ENQUEUE_CONNECTION, - trigger -}) - -export const purgeQueue = () => ({ - type: PURGE_QUEUE -}) - -export const updateConnectionError = (konnector, account, error) => ({ - type: UPDATE_CONNECTION_ERROR, - konnector, - account, - error -}) - -export const startConnectionCreation = konnector => ({ - type: START_CONNECTION_CREATION, - konnector -}) - -export const endConnectionCreation = () => ({ - type: END_CONNECTION_CREATION -}) - -// selectors -export const getConnectionsByKonnector = ( - state, - konnectorSlug, - validAccounts = [], - validKonnectors = [] -) => { - const konnectorIsValid = - !validKonnectors.length || validKonnectors.includes(konnectorSlug) - const konnectorHasConnections = - state.konnectors[konnectorSlug] && - Object.keys(state.konnectors[konnectorSlug].triggers).length - if (!konnectorIsValid || !konnectorHasConnections) return [] - - return Object.values(state.konnectors[konnectorSlug].triggers).filter( - trigger => validAccounts.includes(trigger.account) - ) -} - -// Map the trigger status to a status compatible with queue -const getTriggerQueueStatus = trigger => { - if (trigger.isRunning) return 'ongoing' - if (trigger.hasError) return 'error' - if (trigger.isConnected) return 'done' - return 'pending' -} - -export const getQueue = (state, konnectors) => - // state is state.connections - state.konnectors - ? Object.keys(state.konnectors).reduce( - (queuedConnections, konnectorSlug) => { - const triggers = state.konnectors[konnectorSlug].triggers - if (!triggers) return queuedConnections - const konnector = konnectors[konnectorSlug] - return queuedConnections.concat( - Object.keys(triggers).reduce((queuedTriggers, triggerId) => { - if (triggers[triggerId].isEnqueued) { - const label = konnector.name - const status = getTriggerQueueStatus(triggers[triggerId]) - return queuedTriggers.concat({ - konnector, - label, - status, - triggerId - }) - } - - return queuedTriggers - }, []) - ) - }, - [] - ) - : [] - -export const getConnectionError = (state, trigger) => - getTriggerState(state, trigger).error - -export const getCreatedAccount = state => - !!state.creation && state.creation.account - -export const getTriggerIdByKonnectorAndAccount = ( - state, - konnector, - account, - validAccounts = [] -) => - !!konnector && - !!account && - validAccounts.includes(account._id) && - !!state.konnectors[konnector.slug] && - Object.keys(state.konnectors[konnector.slug].triggers).find( - triggerId => - state.konnectors[konnector.slug].triggers[triggerId].account === - account._id - ) - -// get trigger from state, in state.konnectors[konnectorSlug].triggers[triggerId] -const getTriggerState = (state, trigger) => { - const konnectorSlug = getTriggerKonnectorSlug(trigger) - if (!konnectorSlug || !state.konnectors || !state.konnectors[konnectorSlug]) - return false - const triggers = state.konnectors[konnectorSlug].triggers - if (!triggers) return false - return (!!triggers && !!triggers[trigger._id] && triggers[trigger._id]) || {} -} - -export const isConnectionConnected = (state, trigger) => - getTriggerState(state, trigger).isConnected - -export const isConnectionEnqueued = (state, trigger) => - getTriggerState(state, trigger).isEnqueued diff --git a/src/ducks/connections/test/__snapshots__/connections.spec.js.snap b/src/ducks/connections/test/__snapshots__/connections.spec.js.snap deleted file mode 100644 index 10bea51dd8..0000000000 --- a/src/ducks/connections/test/__snapshots__/connections.spec.js.snap +++ /dev/null @@ -1,57 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Connections Duck Action creators enqueueConnection marks trigger as queued 1`] = ` -Object { - "creation": null, - "konnectors": Object { - "testprovider": Object { - "triggers": Object { - "trigger-1": Object { - "isEnqueued": true, - }, - }, - }, - }, -} -`; - -exports[`Connections Duck Action creators enqueueConnection should ignore when trigger has no _id 1`] = ` -Object { - "creation": null, - "konnectors": Object { - "testprovider": Object {}, - }, -} -`; - -exports[`Connections Duck Action creators purgeQueue marks all accounts as not queued 1`] = ` -Object { - "anotherprovider": Object { - "768ccdaa9d7b11e7869aae88b1c12d46": Object { - "isEnqueued": false, - }, - }, - "testprovider": Object { - "17375ac5a59e4d6585fc7d1e1c75ec74": Object { - "isEnqueued": false, - }, - "63c670ea9d7b11e7b5888c88b1c12d46": Object { - "isEnqueued": false, - }, - }, -} -`; - -exports[`Connections Duck Selectors getConnectionsByKonnector returns expected connections 1`] = ` -Array [ - Object { - "account": "81a548fca81455ec2c2644dd55008b52", - "error": "LOGIN_FAILED", - "hasError": true, - "isConnected": false, - "isRunning": false, - }, -] -`; - -exports[`Connections Duck Selectors getQueue returns one queued connection per queued account 1`] = `Array []`; diff --git a/src/ducks/connections/test/connections.spec.js b/src/ducks/connections/test/connections.spec.js deleted file mode 100644 index 60dc7c1d29..0000000000 --- a/src/ducks/connections/test/connections.spec.js +++ /dev/null @@ -1,392 +0,0 @@ -/* eslint-env jest */ -import get from 'lodash/get' - -import connections, { - enqueueConnection, - getConnectionsByKonnector, - getQueue, - purgeQueue, - RECEIVE_DATA -} from '../' - -describe('Connections Duck', () => { - describe('Reducer', () => { - describe('Receiving data', () => { - it('should ignore actions without data', () => { - const initialState = { creation: null, konnectors: {} } - - expect( - connections(initialState, { - type: RECEIVE_DATA - }) - ).toEqual(initialState) - expect( - connections(initialState, { - type: RECEIVE_DATA, - response: { - data: { yo: 1 } - } - }) - ).toEqual(initialState) - expect( - connections(initialState, { - type: RECEIVE_DATA, - response: { - data: [] - } - }) - ).toEqual(initialState) - }) - - it('should add a new trigger', () => { - const initialState = { creation: null, konnectors: {} } - const data = [ - { - _id: 'trigger-id', - _type: 'io.cozy.triggers', - message: { - konnector: 'my-kon', - account: 'account 1' - }, - current_state: { - status: 'done', - last_error: null, - last_execution: '2019-01-01' - } - } - ] - const newState = connections(initialState, { - type: RECEIVE_DATA, - response: { - data - } - }) - - expect(Object.keys(newState.konnectors).length).toEqual(1) - const triggerState = get( - newState, - 'konnectors.my-kon.triggers.trigger-id' - ) - expect(triggerState).toBeDefined() - expect(triggerState.account).toBe('account 1') - expect(triggerState.hasError).toBe(false) - expect(triggerState.isRunning).toBe(false) - expect(triggerState.lastSyncDate).toBe('2019-01-01') - }) - - it('should add a new job', () => { - const initialState = { creation: null, konnectors: {} } - const data = [ - { - _id: 'job-id', - _type: 'io.cozy.jobs', - worker: 'konnector', - trigger_id: 'job-trigger-id', - state: 'done', - error: null, - queued_at: '2019-01-01', - message: { - konnector: 'my-kon' - } - } - ] - const newState = connections(initialState, { - type: RECEIVE_DATA, - response: { - data - } - }) - - expect(Object.keys(newState.konnectors).length).toEqual(1) - const triggerState = get( - newState, - 'konnectors.my-kon.triggers.job-trigger-id' - ) - expect(triggerState).toBeDefined() - expect(triggerState.account).toBe(undefined) - expect(triggerState.hasError).toBe(false) - expect(triggerState.isRunning).toBe(false) - expect(triggerState.lastSyncDate).toBe('2019-01-01') - }) - }) - - describe('full trigger informations', () => { - it('should add a new trigger', () => { - const initialState = { creation: null, konnectors: {} } - const data = [ - { - _id: 'trigger-id', - _type: 'io.cozy.triggers', - message: { - konnector: 'my-kon', - account: 'account 1' - }, - current_state: { - status: 'done', - last_error: null, - last_execution: '2019-01-01' - } - } - ] - const newState = connections(initialState, { - type: RECEIVE_DATA, - response: { - data - } - }) - - expect(get(newState, 'konnectors.my-kon.triggers.data')).toEqual(data) - }) - - it('should keep the latest version of a trigger', () => { - const initialState = { - creation: null, - konnectors: { - 'my-kon': { - triggers: { - data: [ - { - _id: 'trigger-id', - _type: 'io.cozy.triggers', - message: { - konnector: 'my-kon', - account: 'account 1' - }, - current_state: { - status: 'done', - last_error: null, - last_execution: '2019-01-01' - } - } - ] - } - } - } - } - - const newConnectorData = { - _id: 'trigger-id', - _type: 'io.cozy.triggers', - message: { - konnector: 'my-kon', - account: 'account 1' - }, - current_state: { - status: 'done', - last_error: null, - last_execution: '2019-02-01' - } - } - - const newState = connections(initialState, { - type: RECEIVE_DATA, - response: { - data: [newConnectorData] - } - }) - - const triggerState = get(newState, 'konnectors.my-kon.triggers.data') - expect(triggerState.length).toEqual(1) - expect(triggerState[0]).toEqual(newConnectorData) - }) - - it('should not add jobs to the list', () => { - const initialState = { - creation: null, - konnectors: { - 'my-kon': { - triggers: { - data: [ - { - _id: 'trigger-id', - _type: 'io.cozy.triggers', - message: { - konnector: 'my-kon', - account: 'account 1' - }, - current_state: { - status: 'done', - last_error: null, - last_execution: '2019-01-01' - } - } - ] - } - } - } - } - - const newConnectorData = { - _id: 'job-id', - _type: 'io.cozy.jobs', - worker: 'konnector', - trigger_id: 'trigger-id', - state: 'done', - error: null, - queued_at: '2019-02-01', - message: { - konnector: 'my-kon' - } - } - - const newState = connections(initialState, { - type: RECEIVE_DATA, - response: { - data: [newConnectorData] - } - }) - - const triggerState = get(newState, 'konnectors.my-kon.triggers.data') - expect(triggerState.length).toEqual(1) - expect(triggerState[0].current_state).toBeDefined() - }) - }) - }) - - describe('Action creators', () => { - describe('enqueueConnection', () => { - it('marks trigger as queued', () => { - const state = { - konnectors: { - testprovider: {} - } - } - const konnector = { slug: 'testprovider' } - const account = { _id: '17375ac5a59e4d6585fc7d1e1c75ec74' } - const trigger = { - _id: 'trigger-1', - message: { - account: account._id, - konnector: konnector.slug - } - } - - const result = connections(state, enqueueConnection(trigger)) - - expect(result).toMatchSnapshot() - }) - - it('should ignore when trigger has no _id', () => { - const state = { - konnectors: { - testprovider: {} - } - } - const konnector = { slug: 'testprovider' } - const account = { _id: '17375ac5a59e4d6585fc7d1e1c75ec74' } - - // This is possible that an enqueue connection is dispatched - // with a trigger without _id, this is because for banking - // konnectors, the LOGIN_SUCCESS action is dispatched before - // the trigger has been created, thus a fake trigger is - // created. - const trigger = { - message: { - account: account._id, - konnector: konnector.slug - } - } - - const result = connections(state, enqueueConnection(trigger)) - - expect(result).toMatchSnapshot() - }) - }) - - describe('purgeQueue', () => { - it.skip('marks all accounts as not queued', () => { - const state = { - testprovider: { - '17375ac5a59e4d6585fc7d1e1c75ec74': {}, - '63c670ea9d7b11e7b5888c88b1c12d46': { - isEnqueued: true - } - }, - anotherprovider: { - '768ccdaa9d7b11e7869aae88b1c12d46': { - isEnqueued: true - } - } - } - - const result = connections(state, purgeQueue()) - - expect(result).toMatchSnapshot() - }) - }) - }) - - describe('Selectors', () => { - describe('getConnectionsByKonnector', () => { - it('returns expected connections', () => { - const state = { - konnectors: { - provider: { - triggers: { - '81a548fca81455ec2c2644dd55009990': { - account: '81a548fca81455ec2c2644dd55008b52', - error: 'LOGIN_FAILED', - hasError: true, - isConnected: false, - isRunning: false - }, - '63c670ea9d7b11e7b5888c88b1c12d46': { - account: '17375ac5a59e4d6585fc7d1e1c75ec74', - error: null, - hasError: false, - isConnected: true, - isRunning: true - } - } - } - } - } - - const validKonnectors = ['provider'] - const validAccounts = ['81a548fca81455ec2c2644dd55008b52'] - - expect( - getConnectionsByKonnector( - state, - 'provider', - validAccounts, - validKonnectors - ) - ).toMatchSnapshot() - }) - }) - - describe('getQueue', () => { - it('returns one queued connection per queued account', () => { - const state = { - data: { - testprovider: { - '17375ac5a59e4d6585fc7d1e1c75ec74': {}, - '63c670ea9d7b11e7b5888c88b1c12d46': { - isRunning: true, - isEnqueued: true - }, - '768ccdaa9d7b11e7869aae88b1c12d46': { - isEnqueued: true, - error: { - message: 'test error' - } - } - } - } - } - - const konnectors = { - testprovider: { - name: 'Test Provider', - slug: 'testprovider' - } - } - - const result = getQueue(state, konnectors) - - expect(result).toMatchSnapshot() - }) - }) - }) -}) diff --git a/src/ducks/jobs/index.js b/src/ducks/jobs/index.js deleted file mode 100644 index 01bd71e49c..0000000000 --- a/src/ducks/jobs/index.js +++ /dev/null @@ -1,8 +0,0 @@ -// CRUD - -export const fetchKonnectorJobs = () => {} - -// selectors - -export const isJobRunning = (state, job) => - !!job && ['queued', 'running'].includes(job.state) diff --git a/src/ducks/jobs/test/__snapshots__/jobs.spec.js.snap b/src/ducks/jobs/test/__snapshots__/jobs.spec.js.snap deleted file mode 100644 index 8489d6ce42..0000000000 --- a/src/ducks/jobs/test/__snapshots__/jobs.spec.js.snap +++ /dev/null @@ -1,7 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Jobs Duck isJobRunning returns true for error job 1`] = `false`; - -exports[`Jobs Duck isJobRunning returns true for queued job 1`] = `true`; - -exports[`Jobs Duck isJobRunning returns true for running job 1`] = `true`; diff --git a/src/ducks/jobs/test/jobs.spec.js b/src/ducks/jobs/test/jobs.spec.js deleted file mode 100644 index f8acf63fd4..0000000000 --- a/src/ducks/jobs/test/jobs.spec.js +++ /dev/null @@ -1,18 +0,0 @@ -/* eslint-env jest */ - -import { isJobRunning } from '../' - -describe('Jobs Duck', () => { - describe('isJobRunning', () => { - ;['queued', 'running'].forEach(state => { - it(`returns true for ${state} job`, () => { - expect(isJobRunning({}, { state: state })).toMatchSnapshot() - }) - }) - ;[('done', 'error')].forEach(state => { - it(`returns true for ${state} job`, () => { - expect(isJobRunning({}, { state: state })).toMatchSnapshot() - }) - }) - }) -}) diff --git a/src/lib/HomeStore.js b/src/lib/HomeStore.js index 18b31ef57d..8bfbe2cfe5 100644 --- a/src/lib/HomeStore.js +++ b/src/lib/HomeStore.js @@ -1,5 +1,3 @@ -import { isKonnectorJob } from 'ducks/connections' - import Intents from 'cozy-interapp' import { Q } from 'cozy-client' diff --git a/src/reducers/index.js b/src/reducers/index.js index b4c4de5fb8..f592739066 100644 --- a/src/reducers/index.js +++ b/src/reducers/index.js @@ -1,50 +1,21 @@ import { combineReducers } from 'redux' import get from 'lodash/get' -import * as fromAccounts from 'ducks/accounts' -import * as fromKonnectors from 'ducks/konnectors' -import connections, * as fromConnections from 'ducks/connections' - +const isKonnectorTrigger = doc => + doc._type === 'io.cozy.triggers' && !!doc.message && !!doc.message.konnector export default cozyClient => combineReducers({ - connections, cozy: cozyClient.reducer() }) // selectors -export const getInstalledKonnectors = state => - fromKonnectors.getInstalledKonnectors(state.cozy) - -export const getConnectionsByKonnector = (state, konnectorSlug) => - fromConnections.getConnectionsByKonnector( - state.connections, - konnectorSlug, - fromAccounts.getIds(state.cozy), - fromKonnectors.getSlugs(state.cozy) - ) - -export const getCreatedConnectionAccount = state => - fromAccounts.getAccount( - state.cozy, - fromConnections.getCreatedAccount(state.connections) - ) - -export const getTriggerByKonnectorAndAccount = (state, konnector, account) => { - const triggerId = fromConnections.getTriggerIdByKonnectorAndAccount( - state.connections, - konnector, - account, - fromAccounts.getIds(state.cozy) - ) - return fromTriggers.getTrigger(state.cozy, triggerId) -} export const getTriggersByKonnector = (state, konnectorSlug) => { const triggersInState = state.cozy.documents['io.cozy.triggers'] || {} const triggers = Object.keys(triggersInState).reduce((acc, key) => { const document = state.cozy.documents['io.cozy.triggers'][key] if ( - fromConnections.isKonnectorTrigger(document) && + isKonnectorTrigger(document) && get(document, 'message.konnector') === konnectorSlug ) { acc.push(document) diff --git a/src/styles/accountConnection.styl b/src/styles/accountConnection.styl deleted file mode 100644 index 8428d8c01f..0000000000 --- a/src/styles/accountConnection.styl +++ /dev/null @@ -1,29 +0,0 @@ -@require 'tools/mixins.styl' - -:local // @stylint ignore - h3 - font-size rem(24) - line-height 1.5em - margin .667em 0 - - h4 - font-size rem(20) - line-height 1.5em - margin 1em 0 - - p - font-size rem(16) - line-height rem(24) - - .col-account-connection - display flex - flex-direction column - justify-content center - width 100% - - @media (max-width: rem(400)) - h4 - font-size rem(18) - - p - font-size rem(14) diff --git a/src/styles/accountLoginForm.styl b/src/styles/accountLoginForm.styl deleted file mode 100644 index 803cf13b2e..0000000000 --- a/src/styles/accountLoginForm.styl +++ /dev/null @@ -1,50 +0,0 @@ -@require 'tools/mixins.styl' -@require 'settings/palette.styl' - -:local // @stylint ignore - .coz-form-controls, .coz-form-controls-success - margin rem(32) 0 rem(8) - display flex - flex-wrap wrap - .coz-btn - // Used to position progress bar - flex 1 0 auto - width 100% - - &:first-of-type - margin-left 0 - - &:last-of-type - margin-right 0 - - .coz-form-controls-success - margin-top rem(16) - - .col-btn--regular - margin 0 - font-size rem(16) - height rem(48) - width 100% - - .col-account-form-success-buttons - margin auto - - button - width 100% - - .account-form-login - .col-account-form-advanced-button - font-family Lato, sans-serif - cursor pointer - margin 1rem 0 0 - font-size .8em - border 0 - color var(--dodgerBlue) - background-color var(--white) - text-transform uppercase - font-weight 700 - padding .125rem // Magic number to align button with form fields - - .account-form-fieldset - padding 0 - border 0 diff --git a/src/styles/konnectorHeaderIcon.styl b/src/styles/konnectorHeaderIcon.styl deleted file mode 100644 index e37d223cce..0000000000 --- a/src/styles/konnectorHeaderIcon.styl +++ /dev/null @@ -1,17 +0,0 @@ -:local // @stylint ignore - .col-konnector-header-icon-wrapper - .col-konnector-header-icon-wrapper--center - height 3.5rem - display flex - - .col-konnector-header-icon - height 2rem - - .col-konnector-header-icon--center - height 3.5rem - - img - width auto - - .col-konnector-header-icon-wrapper--center - justify-content center diff --git a/src/styles/konnectorInstall.styl b/src/styles/konnectorInstall.styl deleted file mode 100644 index 84756209ca..0000000000 --- a/src/styles/konnectorInstall.styl +++ /dev/null @@ -1,36 +0,0 @@ -@require 'tools/mixins.styl' -@require 'settings/breakpoints.styl' -@require 'settings/palette.styl' - -:local // @stylint ignore - .col-account-connection-content - padding 0 2rem - - +tiny-screen() - padding 0 - - .col-account-connection-fetching - padding 0 0 2em - position relative - > div - position relative // override default Spinner absolute position - transform translateX(-50%) translateY(0) - - .col-account-connection-security - display flex - align-items top - margin-bottom .5rem - margin-top 1.5rem - - .col-account-connection-security svg - max-height rem(24) - max-width rem(24) - float left - margin-right rem(8) - - .col-account-connection-editor - text-align center - color var(--coolGrey) - margin-top 0 - margin-bottom 0 - font-size .9em diff --git a/src/styles/konnectorMaintenance.styl b/src/styles/konnectorMaintenance.styl deleted file mode 100644 index c185277978..0000000000 --- a/src/styles/konnectorMaintenance.styl +++ /dev/null @@ -1,17 +0,0 @@ -@require 'settings/palette.styl' - -:local // @stylint ignore - .maintenance-intro - text-align center - color var(--pomegranate) - margin 1rem auto - - .maintenance-service - font-size 1.125rem - - .maintenance-icon - width 6.25rem - height 6.25rem - margin 0 auto - background embedurl('../assets/icons/icon-maintenance.svg') 0 no-repeat - diff --git a/src/styles/konnectorSuccess.styl b/src/styles/konnectorSuccess.styl deleted file mode 100644 index 1019110b25..0000000000 --- a/src/styles/konnectorSuccess.styl +++ /dev/null @@ -1,23 +0,0 @@ -@require './accountLoginForm' - -.col-account-success - text-align center - -.col-account-success-links - display flex - align-items center - flex-direction column - -.col-account-success-link - position relative - margin-top 1rem - display flex - align-items center - color var(--dodgerBlue) - text-decoration none - font-weight bold - cursor pointer - -.col-account-success-illu - height rem(112) - width rem(120)
- {t('maintenance.problem', { konnectorName })} -
- {children} -