Skip to content

Commit

Permalink
Merge pull request #1243 from cozy/appicon-client
Browse files Browse the repository at this point in the history
feat: AppIcon doesn't require secure and domain props anymore
  • Loading branch information
y-lohse authored Nov 20, 2019
2 parents 2daad62 + 1c47cc3 commit 4ddc68b
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 42 deletions.
3 changes: 0 additions & 3 deletions react/AppIcon/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,6 @@ initialState = { fetchIcon: fetchIcon1 };
</div>
```

## `domain` and `secure` props
If the `fetchIcon` is missing, the `<AppIcon />` component needs the `domain` prop (litteraly the cozy domain) and the secure prop, to know which protocol use between `http` or `https`.

### Provide `fallbackIcon`

You can provide an `<Icon />` `icon` props to fallback when the AppIcon fetched is broken or the `fetchIcon` function errored.
Expand Down
42 changes: 27 additions & 15 deletions react/AppIcon/index.jsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import cx from 'classnames'
import { withClient } from 'cozy-client'
import styles from './styles.styl'

import Icon from '../Icon'
import Icon, { iconPropType } from '../Icon'
import palette from '../palette'
import { iconPropType } from '../Icon'

import { getPreloaded, preload } from './Preloader'
import { AppDoctype } from '../proptypes'
Expand All @@ -17,15 +17,28 @@ const FETCHING = 'fetching'
export class AppIcon extends Component {
constructor(props, context) {
super(props, context)
const { app, domain, secure } = props
const preloaded = getPreloaded(app, domain, secure)
this.state = {
error: null,
icon: preloaded,
status: preloaded ? DONE : FETCHING
}
this.isUnmounting = false
this.handleError = this.handleError.bind(this)

try {
const { app, client } = props
const cozyURL = new URL(client.getStackClient().uri)
// TODO: instead of storung domain and secure, pass down the client to the loaders (see https://github.com/cozy/cozy-ui/pull/1243#discussion_r348016827)
this.domain = cozyURL.host
this.secure = cozyURL.protocol === 'https:'

const preloaded = getPreloaded(app, this.domain, this.secure)
this.state = {
error: null,
icon: preloaded,
status: preloaded ? DONE : FETCHING
}
} catch (error) {
this.state = {
error,
status: ERRORED
}
}
}

componentWillUnmount() {
Expand All @@ -43,12 +56,12 @@ export class AppIcon extends Component {
}

async load() {
const { app, domain, fetchIcon, onReady, secure } = this.props
const { app, fetchIcon, onReady } = this.props
const loadFn = fetchIcon || preload
let loadedUrl
let loadError
try {
loadedUrl = await loadFn(app, domain, secure)
loadedUrl = await loadFn(app, this.domain, this.secure)
} catch (error) {
loadError = error
}
Expand Down Expand Up @@ -119,10 +132,9 @@ AppIcon.propTypes = {
fallbackIcon: iconPropType,
/** Custom implementation of how to fetch icon */
fetchIcon: PropTypes.func,
client: PropTypes.object.isRequired,
className: PropTypes.string,
domain: PropTypes.string,
onReady: PropTypes.func,
secure: PropTypes.bool
onReady: PropTypes.func
}

export default AppIcon
export default withClient(AppIcon)
36 changes: 19 additions & 17 deletions react/AppIcon/test/AppIcon.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@
import React from 'react'
import { shallow } from 'enzyme'

import AppIcon from '../'
import { AppIcon } from '../'

describe('AppIcon component', () => {
const app = {}
const domain = 'cozy.tools'
const secure = true

const mockClient = {
getStackClient: () => ({ uri: `https://${domain}` })
}

let successFetchIcon
let failureFetchIcon

Expand All @@ -31,12 +35,12 @@ describe('AppIcon component', () => {

it(`renders as loading`, () => {
const wrapper = shallow(
<AppIcon app={app} fetchIcon={successFetchIcon} secure={secure} />
<AppIcon app={app} fetchIcon={successFetchIcon} client={mockClient} />
)

const component = wrapper.getElement()
expect(component).toMatchSnapshot()
expect(successFetchIcon).toHaveBeenCalledWith(app, undefined, secure)
expect(successFetchIcon).toHaveBeenCalledWith(app, domain, secure)
expect(console.error).toHaveBeenCalledTimes(0)
})

Expand All @@ -45,15 +49,15 @@ describe('AppIcon component', () => {
<AppIcon
app={app}
fetchIcon={successFetchIcon}
client={mockClient}
onReady={() => {
wrapper.update()
const component = wrapper.getElement()
expect(component).toMatchSnapshot()
expect(successFetchIcon).toHaveBeenCalledWith(app, undefined, secure)
expect(successFetchIcon).toHaveBeenCalledWith(app, domain, secure)
expect(console.error).toHaveBeenCalledTimes(0)
done()
}}
secure={secure}
/>
)
})
Expand All @@ -63,15 +67,15 @@ describe('AppIcon component', () => {
<AppIcon
app={app}
fetchIcon={failureFetchIcon}
client={mockClient}
onReady={() => {
wrapper.update()
const component = wrapper.getElement()
expect(component).toMatchSnapshot()
expect(failureFetchIcon).toHaveBeenCalledWith(app, undefined, secure)
expect(failureFetchIcon).toHaveBeenCalledWith(app, domain, secure)
expect(console.error).toHaveBeenCalledTimes(0)
done()
}}
secure={secure}
/>
)
})
Expand All @@ -81,15 +85,15 @@ describe('AppIcon component', () => {
<AppIcon
app={app}
fetchIcon={failureFetchIcon}
client={mockClient}
onReady={() => {
wrapper.update()
const component = wrapper.getElement()
expect(component).toMatchSnapshot()
expect(failureFetchIcon).toHaveBeenCalledWith(app, undefined, secure)
expect(failureFetchIcon).toHaveBeenCalledWith(app, domain, secure)
expect(console.error).toHaveBeenCalledTimes(0)
done()
}}
secure={secure}
fallbackIcon="warning"
/>
)
Expand All @@ -113,36 +117,35 @@ describe('AppIcon component', () => {

it(`uses Preloader.preload when no fetchIcon method is provided`, async done => {
jest.mock('../Preloader')
const AppIcon = require('../').default
const AppIcon = require('../').AppIcon
const Preloader = require('../Preloader')
const wrapper = shallow(
<AppIcon
app={app}
client={mockClient}
onReady={() => {
wrapper.update()
const component = wrapper.getElement()
expect(component).toMatchSnapshot()
expect(Preloader.preload).toHaveBeenCalledWith(app, undefined, secure)
expect(Preloader.preload).toHaveBeenCalledWith(app, domain, secure)
expect(console.error).toHaveBeenCalledTimes(0)
done()
}}
secure={secure}
/>
)
})

it(`renders immediately when icon is alredy preloaded`, async done => {
jest.mock('../Preloader')
const AppIcon = require('../').default
const AppIcon = require('../').AppIcon
const Preloader = require('../Preloader')

shallow(
<AppIcon
app={app}
client={mockClient}
onReady={() => {
const wrapper = shallow(
<AppIcon app={app} domain={domain} secure={secure} />
)
const wrapper = shallow(<AppIcon app={app} client={mockClient} />)
const component = wrapper.getElement()
expect(component).toMatchSnapshot()
expect(Preloader.getPreloaded).toHaveBeenCalledWith(
Expand All @@ -153,7 +156,6 @@ describe('AppIcon component', () => {
expect(console.error).toHaveBeenCalledTimes(0)
done()
}}
secure={secure}
/>
)
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ exports[`SmallAppItem component should render correctly an app 1`] = `
<div
className="SmallAppItem__SmallAppItem-icon-wrapper___rQAvt"
>
<AppIcon
<withClient(AppIcon)
app={
Object {
"developer": Object {
Expand Down Expand Up @@ -55,7 +55,7 @@ exports[`SmallAppItem component should render correctly an app in maintenance 1`
<div
className="SmallAppItem__SmallAppItem-icon-wrapper___rQAvt"
>
<AppIcon
<withClient(AppIcon)
app={
Object {
"developer": Object {
Expand Down Expand Up @@ -110,7 +110,7 @@ exports[`SmallAppItem component should render correctly an app with iconToLoad (
<div
className="SmallAppItem__SmallAppItem-icon-wrapper___rQAvt"
>
<AppIcon
<withClient(AppIcon)
app={
Object {
"developer": Object {
Expand Down Expand Up @@ -163,7 +163,7 @@ exports[`SmallAppItem component should render correctly an app with iconToLoad i
<div
className="SmallAppItem__SmallAppItem-icon-wrapper___rQAvt"
>
<AppIcon
<withClient(AppIcon)
app={
Object {
"developer": Object {
Expand Down Expand Up @@ -216,7 +216,7 @@ exports[`SmallAppItem component should render correctly an app without developer
<div
className="SmallAppItem__SmallAppItem-icon-wrapper___rQAvt"
>
<AppIcon
<withClient(AppIcon)
app={
Object {
"editor": "cozy",
Expand Down Expand Up @@ -254,7 +254,7 @@ exports[`SmallAppItem component should render correctly an installed app 1`] = `
<div
className="SmallAppItem__SmallAppItem-icon-wrapper___rQAvt"
>
<AppIcon
<withClient(AppIcon)
app={
Object {
"developer": Object {
Expand Down Expand Up @@ -306,7 +306,7 @@ exports[`SmallAppItem component should render correctly an installed app without
<div
className="SmallAppItem__SmallAppItem-icon-wrapper___rQAvt"
>
<AppIcon
<withClient(AppIcon)
app={
Object {
"developer": Object {
Expand Down

0 comments on commit 4ddc68b

Please sign in to comment.