Skip to content

Commit

Permalink
Merge pull request #6712 from TheThingsNetwork/fix/remove-class-compo…
Browse files Browse the repository at this point in the history
…nents

Refactor some class components to functional
  • Loading branch information
PavelJankoski authored Nov 23, 2023
2 parents 83f0086 + 1ad3498 commit 8b1c55c
Show file tree
Hide file tree
Showing 21 changed files with 1,346 additions and 1,611 deletions.
19 changes: 7 additions & 12 deletions config/storybook/preview.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,27 +23,22 @@ import { createMemoryHistory } from 'history'
import messages from '@ttn-lw/locales/en.json'
import backendMessages from '@ttn-lw/locales/.backend/en.json'

import { EnvProvider } from '@ttn-lw/lib/components/env'

import '../../pkg/webui/styles/main.styl'
import 'focus-visible/dist/focus-visible'
import createStore from './store'
import Center from './center'
import env from './env'

const history = createMemoryHistory()
const store = createStore(history)

export const decorators = [
Story => (
<EnvProvider env={env}>
<Provider store={store}>
<IntlProvider key="key" messages={{ ...messages, ...backendMessages }} locale="en-US">
<ConnectedRouter history={history}>
<Center>{Story()}</Center>
</ConnectedRouter>
</IntlProvider>
</Provider>
</EnvProvider>
<Provider store={store}>
<IntlProvider key="key" messages={{ ...messages, ...backendMessages }} locale="en-US">
<ConnectedRouter history={history}>
<Center>{Story()}</Center>
</ConnectedRouter>
</IntlProvider>
</Provider>
),
]
116 changes: 20 additions & 96 deletions pkg/webui/components/breadcrumbs/context.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright © 2019 The Things Network Foundation, The Things Industries B.V.
// Copyright © 2023 The Things Network Foundation, The Things Industries B.V.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -12,114 +12,44 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import React, { useContext, useEffect } from 'react'
import bind from 'autobind-decorator'
import React, { useContext, useEffect, useState } from 'react'

import PropTypes from '@ttn-lw/lib/prop-types'

const BreadcrumbsContext = React.createContext()
const { Provider, Consumer } = BreadcrumbsContext

class BreadcrumbsProvider extends React.Component {
static propTypes = {
children: PropTypes.node.isRequired,
}

state = {
breadcrumbs: [],
}
const BreadcrumbsProvider = ({ children }) => {
const [breadcrumbs, setBreadcrumbs] = useState([])

@bind
add(id, breadcrumb) {
this.setState(prev => {
const index = prev.breadcrumbs.findIndex(({ id: breadcrumbId }) => breadcrumbId === id)
const add = (id, breadcrumb) => {
setBreadcrumbs(prev => {
const index = prev.findIndex(({ id: breadcrumbId }) => breadcrumbId === id)
if (index === -1) {
return {
breadcrumbs: [...prev.breadcrumbs, { id, breadcrumb }].sort((a, b) =>
a.id < b.id ? -1 : 1,
),
}
return [...prev, { id, breadcrumb }].sort((a, b) => (a.id < b.id ? -1 : 1))
}

// Replace breadcrumb with existing id.
return {
breadcrumbs: [
...prev.breadcrumbs.slice(0, index),
{ id, breadcrumb },
...prev.breadcrumbs.slice(index + 1),
],
}
return [...prev.slice(0, index), { id, breadcrumb }, ...prev.slice(index + 1)]
})
}

@bind
remove(id) {
this.setState(prev => ({
breadcrumbs: prev.breadcrumbs.filter(b => b.id !== id),
}))
const remove = id => {
setBreadcrumbs(prev => prev.filter(b => b.id !== id))
}

render() {
const { children } = this.props
const value = {
add: this.add,
remove: this.remove,
breadcrumbs: this.state.breadcrumbs.map(b => b.breadcrumb),
}

return <Provider value={value}>{children}</Provider>
const value = {
add,
remove,
breadcrumbs: breadcrumbs.map(b => b.breadcrumb),
}
}

const withBreadcrumb = (id, element) => Component => {
class BreadcrumbsConsumer extends React.Component {
static propTypes = {
add: PropTypes.func.isRequired,
breadcrumb: PropTypes.oneOfType([PropTypes.func, PropTypes.element]).isRequired,
remove: PropTypes.func.isRequired,
}

constructor(props) {
super(props)

this.add()
}

add() {
const { add, breadcrumb } = this.props

add(id, breadcrumb)
}

remove() {
const { remove } = this.props

remove(id)
}

componentWillUnmount() {
this.remove()
}

render() {
const { add, remove, breadcrumb, ...rest } = this.props

return <Component {...rest} />
}
}

const BreadcrumbsConsumerContainer = props => (
<Consumer>
{({ add, remove }) => (
<BreadcrumbsConsumer {...props} add={add} remove={remove} breadcrumb={element(props)} />
)}
</Consumer>
)

return BreadcrumbsConsumerContainer
return <Provider value={value}>{children}</Provider>
}

withBreadcrumb.displayName = 'withBreadcrumb'
BreadcrumbsProvider.propTypes = {
children: PropTypes.node.isRequired,
}

const useBreadcrumbs = (id, element) => {
const context = useContext(BreadcrumbsContext)
Expand All @@ -133,10 +63,4 @@ const useBreadcrumbs = (id, element) => {
}, [])
}

export {
Consumer as BreadcrumbsConsumer,
BreadcrumbsProvider,
withBreadcrumb,
BreadcrumbsContext,
useBreadcrumbs,
}
export { Consumer as BreadcrumbsConsumer, BreadcrumbsProvider, BreadcrumbsContext, useBreadcrumbs }
50 changes: 26 additions & 24 deletions pkg/webui/components/form/field/stories/shared.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright © 2021 The Things Network Foundation, The Things Industries B.V.
// Copyright © 2023 The Things Network Foundation, The Things Industries B.V.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -12,12 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.

/* eslint-disable react/prop-types */

import React from 'react'
import React, { useEffect, useRef } from 'react'
import { action } from '@storybook/addon-actions'

import Yup from '@ttn-lw/lib/yup'
import PropTypes from '@ttn-lw/lib/prop-types'

import Form from '../..'

Expand All @@ -38,28 +37,31 @@ const validationSchema = Yup.object().shape({
error: errorSchema,
})

class FieldsWrapperExample extends React.Component {
form = React.createRef()

componentDidMount() {
if (this.form.current) {
this.form.current.setFieldError('error', 'Something went wrong.')
this.form.current.setFieldTouched('error')
const FieldsWrapperExample = props => {
const formRef = useRef(null)
const { initialValues, children } = props
useEffect(() => {
if (formRef.current) {
formRef.current.setFieldError('error', 'Something went wrong.')
formRef.current.setFieldTouched('error')
}
}
}, [])

return (
<Form
onSubmit={handleSubmit}
initialValues={initialValues}
formikRef={formRef}
validationSchema={validationSchema}
>
{children}
</Form>
)
}

render() {
return (
<Form
onSubmit={handleSubmit}
initialValues={this.props.initialValues}
formikRef={this.form}
validationSchema={validationSchema}
>
{this.props.children}
</Form>
)
}
FieldsWrapperExample.propTypes = {
children: PropTypes.node.isRequired,
initialValues: PropTypes.shape({}).isRequired,
}

export { info, FieldsWrapperExample }
29 changes: 9 additions & 20 deletions pkg/webui/components/input/stories/shared.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,33 +14,22 @@

/* eslint-disable react/prop-types, import/prefer-default-export */

import React from 'react'
import bind from 'autobind-decorator'
import React, { useCallback, useState } from 'react'

import Input from '..'

class Example extends React.Component {
constructor(props) {
super(props)
const Example = props => {
const { value: initialValue, type, component: Component, ...rest } = props

this.state = {
value: props.value || '',
}
}
const [value, setValue] = useState(initialValue || '')

@bind
onChange(value) {
this.setState({ value })
}
const handleChangeInput = useCallback(newValue => {
setValue(newValue)
}, [])

render() {
const { type, component: Component, ...props } = this.props
const { value } = this.state
const InputComponent = Component || Input

const InputComponent = Component ? Component : Input

return <InputComponent {...props} type={type} onChange={this.onChange} value={value} />
}
return <InputComponent {...rest} type={type} onChange={handleChangeInput} value={value} />
}

export { Example }
Loading

0 comments on commit 8b1c55c

Please sign in to comment.