at the end of the day, it was inevitable

This commit is contained in:
Mo Elzubeir
2022-12-09 08:36:26 -06:00
commit 1218570914
1768 changed files with 887087 additions and 0 deletions
@@ -0,0 +1,101 @@
import React from 'react'
import PropTypes from 'prop-types'
import { translate } from 'react-i18next'
import SourceListsAddPopup from './SourceListsAddPopup'
import SourceListsDeletePopup from './SourceListsDeletePopup'
import SourceListsRenamePopup from './SourceListsRenamePopup'
import SourceListsClonePopup from './SourceListsClonePopup'
import SourceListsTable from './SourceListsTable'
import { Button, CustomInput } from 'reactstrap'
export class SourceLists extends React.Component {
static propTypes = {
sourceListsState: PropTypes.object.isRequired,
actions: PropTypes.object.isRequired,
t: PropTypes.func.isRequired
}
onGlobalOnlyClick = () => {
const { actions, sourceListsState } = this.props
actions.toggleOnlyGlobal()
const params = {
page: sourceListsState.page,
limit: sourceListsState.limit,
onlyShared: !sourceListsState.onlyGlobal,
sort: {
field: sourceListsState.sortByField,
direction: sourceListsState.sortDirection
}
}
actions.getMainSourceLists(params)
}
render() {
const { t, sourceListsState, actions } = this.props
const {
isAddListPopupVisible,
isDeletePopupVisible,
isRenameListPopupVisible,
isCloneListPopupVisible,
listToEdit
} = sourceListsState
return (
<div className="source-lists-tab">
<div className="d-flex justify-content-between align-items-end flex-wrap-reverse flex-sm-nowrap">
<CustomInput
id="show-global"
type="checkbox"
className="d-flex mb-3"
checked={sourceListsState.onlyGlobal}
onChange={this.onGlobalOnlyClick}
label={t('sourceListsTab.showGlobalCheck')}
/>
<Button
color="primary"
className="btn-icon mb-3"
onClick={actions.toggleAddListPopup}
>
<i className="lnr lnr-plus-circle btn-icon-wrapper" />
{t('sourceListsTab.addListBtn')}
</Button>
</div>
<SourceListsTable tableState={sourceListsState} actions={actions} />
{isAddListPopupVisible && (
<SourceListsAddPopup
toggleAddListPopup={actions.toggleAddListPopup}
addSourceList={actions.addSourceList}
/>
)}
{isDeletePopupVisible && (
<SourceListsDeletePopup
listToEdit={listToEdit}
toggleDeleteListPopup={actions.toggleDeleteListPopup}
deleteSourceList={actions.deleteSourceList}
/>
)}
{isRenameListPopupVisible && (
<SourceListsRenamePopup
listToEdit={listToEdit}
toggleRenameListPopup={actions.toggleRenameListPopup}
renameSourceList={actions.renameSourceList}
/>
)}
{isCloneListPopupVisible && (
<SourceListsClonePopup
listToEdit={listToEdit}
toggleCloneListPopup={actions.toggleCloneListPopup}
cloneSourceList={actions.cloneSourceList}
/>
)}
</div>
)
}
}
export default translate(['tabsContent'], { wait: true })(SourceLists)
@@ -0,0 +1,55 @@
import React from 'react'
import PropTypes from 'prop-types'
import { translate } from 'react-i18next'
import PopupLayout from '../../../../common/Popups/PopupLayout'
import { FormGroup, Input, Label } from 'reactstrap'
export class SourceListsAddPopup extends React.Component {
static propTypes = {
toggleAddListPopup: PropTypes.func.isRequired,
addSourceList: PropTypes.func.isRequired,
t: PropTypes.func.isRequired
}
state = {
name: ''
}
onSubmit = () => {
const { addSourceList } = this.props
addSourceList(this.state.name)
}
handleChange = (e) => {
const { value } = e.target
this.setState({ name: value })
}
render() {
const { toggleAddListPopup, t } = this.props
return (
<PopupLayout
title="Add a List"
submitText="Submit"
onHide={toggleAddListPopup}
onSubmit={this.onSubmit}
>
<div>
<FormGroup>
<Label>{t('sourceListsTab.popup.enterListName')}</Label>
<Input
type="text"
value={this.state.name}
onChange={this.handleChange}
/>
</FormGroup>
</div>
</PopupLayout>
)
}
}
export default translate(['tabsContent', 'common'], { wait: true })(
SourceListsAddPopup
)
@@ -0,0 +1,65 @@
import React from 'react'
import PropTypes from 'prop-types'
import { translate } from 'react-i18next'
import PopupLayout from '../../../../common/Popups/PopupLayout'
import { FormGroup, Input, Label } from 'reactstrap'
export class SourceListsClonePopup extends React.Component {
static propTypes = {
listToEdit: PropTypes.func.isRequired,
toggleCloneListPopup: PropTypes.func.isRequired,
cloneSourceList: PropTypes.func.isRequired,
t: PropTypes.func.isRequired
}
constructor(props) {
super(props)
this.state = {
name:
props.listToEdit && props.listToEdit.name
? `${props.listToEdit.name} (copy)`
: ''
}
}
handleChange = (e) => {
const { value } = e.target
this.setState({
name: value
})
}
onSubmit = () => {
const { listToEdit, cloneSourceList } = this.props
cloneSourceList({
id: listToEdit.id,
name: this.state.name
})
}
render() {
const { toggleCloneListPopup, t } = this.props
return (
<PopupLayout
title="Clone"
submitText="sourceListsTab.popup.cloneListSubmitBtn"
onHide={toggleCloneListPopup}
onSubmit={this.onSubmit}
>
<FormGroup>
<Label>{t('sourceListsTab.popup.renameListTitle')}</Label>
<Input
type="text"
value={this.state.name}
onChange={this.handleChange}
/>
</FormGroup>
</PopupLayout>
)
}
}
export default translate(['tabsContent', 'common'], { wait: true })(
SourceListsClonePopup
)
@@ -0,0 +1,42 @@
import React from 'react'
import PropTypes from 'prop-types'
import { translate, Interpolate } from 'react-i18next'
import PopupLayout from '../../../../common/Popups/PopupLayout'
import { getTitle } from '../../../../../common/helper';
export class SourceListsDeletePopup extends React.Component {
static propTypes = {
listToEdit: PropTypes.func.isRequired,
toggleDeleteListPopup: PropTypes.func.isRequired,
deleteSourceList: PropTypes.func.isRequired,
t: PropTypes.func.isRequired
};
onSubmit = () => {
const { listToEdit, deleteSourceList } = this.props
deleteSourceList(listToEdit)
};
render () {
const { listToEdit, toggleDeleteListPopup } = this.props
const value = listToEdit.name || listToEdit.title || ''
return (
<PopupLayout
title='sourceListsTab.popup.deleteListTitle'
submitText='Delete'
onHide={toggleDeleteListPopup}
onSubmit={this.onSubmit}
submitColor="danger"
>
<Interpolate
i18nKey='sourceListsTab.popup.deleteListDesc'
name={getTitle(value)}
/>
</PopupLayout>
)
}
}
export default translate(['tabsContent', 'common'], { wait: true })(SourceListsDeletePopup)
@@ -0,0 +1,64 @@
import React from 'react'
import PropTypes from 'prop-types'
import { translate } from 'react-i18next'
import PopupLayout from '../../../../common/Popups/PopupLayout'
import { FormGroup, Input, Label } from 'reactstrap'
export class SourceListsRenamePopup extends React.Component {
static propTypes = {
listToEdit: PropTypes.func.isRequired,
toggleRenameListPopup: PropTypes.func.isRequired,
renameSourceList: PropTypes.func.isRequired,
t: PropTypes.func.isRequired
}
constructor(props) {
super(props)
this.state = {
name: (props.listToEdit && props.listToEdit.name) || ''
}
}
handleChange = (e) => {
const { value } = e.target
this.setState({
name: value
})
}
onSubmit = () => {
const { listToEdit, renameSourceList } = this.props
const data = {
id: listToEdit.id,
name: this.state.name
}
renameSourceList(data, listToEdit.name)
}
render() {
const { toggleRenameListPopup, t } = this.props
return (
<PopupLayout
title="Rename"
submitText="sourceListsTab.popup.renameListSubmitBtn"
onHide={toggleRenameListPopup}
onSubmit={this.onSubmit}
>
<FormGroup>
<Label>{t('sourceListsTab.popup.renameListTitle')}</Label>
<Input
type="text"
value={this.state.name}
onChange={this.handleChange}
/>
</FormGroup>
</PopupLayout>
)
}
}
export default translate(['tabsContent', 'common'], { wait: true })(
SourceListsRenamePopup
)
@@ -0,0 +1,51 @@
import React, { Fragment } from 'react'
import PropTypes from 'prop-types'
import SourceLists from './SourceLists'
import SourcesOfList from './SourcesOfList'
import { withRouter } from 'react-router-dom'
import reduxConnect from '../../../../../redux/utils/connect'
import { compose } from 'redux'
import { setDocumentData } from '../../../../../common/helper'
class SourceListsSubTab extends React.Component {
static propTypes = {
sourcesState: PropTypes.object.isRequired,
actions: PropTypes.object.isRequired
}
componentDidMount() {
setDocumentData('title', 'Source Lists | Search')
}
componentWillUnmount() {
setDocumentData('title')
}
render() {
const { sourcesState, actions } = this.props
const { sourcesOfListState, sourceListsState } = sourcesState
const sourcesOfListVisible = sourcesOfListState.isSourcesOfListVisible
return (
<Fragment>
{!sourcesOfListVisible && (
<SourceLists sourceListsState={sourceListsState} actions={actions} />
)}
{sourcesOfListVisible && (
<SourcesOfList
sourcesOfListState={sourcesOfListState}
actions={actions}
/>
)}
</Fragment>
)
}
}
const applyDecorators = compose(
withRouter,
reduxConnect('sourcesState', ['appState', 'sourcesState'])
)
export default applyDecorators(SourceListsSubTab)
@@ -0,0 +1,256 @@
import React from 'react'
import PropTypes from 'prop-types'
import { translate } from 'react-i18next'
import moment from 'moment'
import Table from '../../../../common/Table/Table'
import SortableTh from '../../../../common/Table/SortableTh'
import { Button } from 'reactstrap'
export class SourceListsTable extends React.Component {
static propTypes = {
t: PropTypes.func.isRequired,
tableState: PropTypes.object.isRequired,
actions: PropTypes.object.isRequired
}
onFetch = (page, pageSize, sorted) => {
const { actions, tableState } = this.props
const params = {
page: page + 1,
limit: pageSize,
onlyShared: tableState.onlyGlobal
}
if (sorted.length) {
const sortedField = sorted[0]
const sort = {
field: sortedField.id,
direction: sortedField.desc ? 'desc' : 'asc'
}
params['sort'] = sort
}
actions.getMainSourceLists(params)
}
showDeleteListPopup = (item) => () => {
this.props.actions.toggleDeleteListPopup(item)
}
showRenameListPopup = (item) => () => {
this.props.actions.toggleRenameListPopup(item)
}
showCloneListPopup = (item) => () => {
this.props.actions.toggleCloneListPopup(item)
}
showSourcesOfList = (item) => () => {
this.props.actions.showSourcesOfList(item)
}
onShareList = (id) => () => {
this.props.actions.shareSourceList(id)
}
onUnshareList = (id) => () => {
this.props.actions.unshareSourceList(id)
}
getColumns() {
const { t } = this.props
let columns = [
{
Header: <SortableTh title="sourceListsTab.tableLabels.name" />,
accessor: 'name',
Cell: ({ original }) => {
return (
<a
href="#"
onClick={this.showSourcesOfList(original)}
>
{original.name}
</a>
)
}
},
{
id: 'sources',
Header: <SortableTh title="sourceListsTab.tableLabels.sources" />,
accessor: (item) => item.sourceNumber
},
{
id: 'createdBy',
Header: <SortableTh title="sourceListsTab.tableLabels.createdBy" />,
accessor: (item) => `${item.user.firstName} ${item.user.lastName}`
},
{
id: 'lastUpdated',
Header: <SortableTh title="sourceListsTab.tableLabels.lastUpdated" />,
accessor: (item) =>
item.updatedAt && moment(item.updatedAt).format('Do MMM YYYY')
},
{
id: 'lastUpdatedBy',
Header: <SortableTh title="sourceListsTab.tableLabels.lastUpdatedBy" />,
accessor: (item) =>
item.updatedBy &&
`${item.updatedBy.firstName} ${item.updatedBy.lastName}`
},
{
id: 'action',
Header: t('sourceIndexTab.action'),
// sortable: false,
minWidth: 220,
Cell: ({ original }) => {
return (
// <UncontrolledButtonDropdown>
// <DropdownToggle
// // caret
// // className="btn-icon btn-icon-only btn btn-link"
// color="link"
// >
// <i className="lnr-menu-circle btn-icon-wrapper" />
// </DropdownToggle>
// <DropdownMenu>
// <h2>Hello</h2>
// {/* <DropdownItem onClick={this.onUnshareList(original.id)}>
// <i className="dropdown-icon lnr-inbox"> </i>
// <span>{t("sourceListsTab.unshare")}</span>
// </DropdownItem>
// <DropdownItem onClick={this.onShareList(original.id)}>
// <i className="dropdown-icon lnr-file-empty"> </i>
// <span>{t("sourceListsTab.share")}</span>
// </DropdownItem>
// <DropdownItem onClick={this.showRenameListPopup(original)}>
// <i className="dropdown-icon lnr-book"> </i>
// <span>{t("sourceListsTab.rename")}</span>
// </DropdownItem>
// <DropdownItem onClick={this.showCloneListPopup(original)}>
// <i className="dropdown-icon lnr-picture"> </i>
// <span>{t("sourceListsTab.clone")}</span>
// </DropdownItem>
// <DropdownItem onClick={this.showDeleteListPopup(original)}>
// <i className="dropdown-icon lnr-picture"> </i>
// <span>{t("sourceListsTab.delete")}</span>
// </DropdownItem> */}
// </DropdownMenu>
// </UncontrolledButtonDropdown>
// <div className="d-block w-100 text-center">
// <UncontrolledButtonDropdown>
// <DropdownToggle
// caret
// className="btn-icon btn-icon-only btn btn-link"
// color="link"
// >
// <i className="lnr-menu-circle btn-icon-wrapper" />
// </DropdownToggle>
// <DropdownMenu className="rm-pointers dropdown-menu-hover-link">
// <DropdownItem onClick={this.onUnshareList(original.id)}>
// <i className="dropdown-icon lnr-inbox"> </i>
// <span>{t("sourceListsTab.unshare")}</span>
// </DropdownItem>
// <DropdownItem onClick={this.onShareList(original.id)}>
// <i className="dropdown-icon lnr-file-empty"> </i>
// <span>{t("sourceListsTab.share")}</span>
// </DropdownItem>
// <DropdownItem onClick={this.showRenameListPopup(original)}>
// <i className="dropdown-icon lnr-book"> </i>
// <span>{t("sourceListsTab.rename")}</span>
// </DropdownItem>
// <DropdownItem onClick={this.showCloneListPopup(original)}>
// <i className="dropdown-icon lnr-picture"> </i>
// <span>{t("sourceListsTab.clone")}</span>
// </DropdownItem>
// <DropdownItem onClick={this.showDeleteListPopup(original)}>
// <i className="dropdown-icon lnr-picture"> </i>
// <span>{t("sourceListsTab.delete")}</span>
// </DropdownItem>
// </DropdownMenu>
// </UncontrolledButtonDropdown>
// </div>
<div>
<Button
outline
size="sm"
color="info"
className="border-0"
onClick={
original.shared
? this.onUnshareList(original.id)
: this.onShareList(original.id)
}
>
{original.shared
? t('sourceListsTab.unshare')
: t('sourceListsTab.share')}
</Button>
<Button
outline
size="sm"
color="info"
className="border-0"
onClick={this.showRenameListPopup(original)}
>
{t('sourceListsTab.rename')}
</Button>
<Button
outline
size="sm"
color="info"
className="border-0"
onClick={this.showCloneListPopup(original)}
>
{t('sourceListsTab.clone')}
</Button>
<Button
outline
size="sm"
color="secondary"
className="border-0"
onClick={this.showDeleteListPopup(original)}
>
{t('sourceListsTab.delete')}
</Button>
</div>
)
}
}
]
const cols = [
'name',
'sources',
'createdBy',
'lastUpdated',
'lastUpdatedBy',
'action'
]
return columns.filter(
(col) => cols.includes(col.id) || cols.includes(col.accessor)
)
}
render() {
const { tableState } = this.props
const columns = this.getColumns()
return (
<div className="sources-table">
<Table
columns={columns}
data={tableState.data}
totalCount={tableState.totalCount}
showTotalCount
limit={tableState.limit}
page={tableState.page}
isLoading={tableState.isLoading}
onFetchData={this.onFetch}
/>
</div>
)
}
}
export default translate(['tabsContent'], { wait: true })(SourceListsTable)
@@ -0,0 +1,111 @@
import React from 'react'
import PropTypes from 'prop-types'
import { translate } from 'react-i18next'
import SourceIndexTable from '../SourceIndexSubTab/SourceIndexTable'
import SourceListsDeletePopup from './SourceListsDeletePopup'
import { Button, Input, InputGroup, InputGroupAddon } from 'reactstrap'
export class SourcesOfList extends React.Component {
static propTypes = {
sourcesOfListState: PropTypes.object.isRequired,
actions: PropTypes.object.isRequired,
t: PropTypes.func.isRequired
};
componentWillMount = () => {
this.searchSources('')
};
searchSources = (query) => {
const { actions, sourcesOfListState } = this.props
actions.getSourcesOfList(sourcesOfListState.visibleList.id, {
query: query,
page: sourcesOfListState.page,
limit: sourcesOfListState.limit
})
};
onSearchSources = () => {
const query = this.props.sourcesOfListState.searchQuery
this.searchSources(query)
};
onEnterSearchInput = (e) => {
if (e.keyCode === 13) this.onSearchSources()
};
onChangeSearchInput = (e) => {
const val = e.target.value
this.props.actions.setSourcesOfListSearchQuery(val)
};
onFetchData = (params) => {
const { sourcesOfListState, actions } = this.props
actions.getSourcesOfList(sourcesOfListState.visibleList.id, params)
};
onDeleteIndex = (source) => {
const { sourcesOfListState, actions } = this.props
const listId = sourcesOfListState.visibleList.id
actions.updateListSources({
id: source.id,
sourceLists: source.listIds.filter(id => id !== listId)
})
};
render () {
const { t, sourcesOfListState, actions } = this.props
const { searchQuery, visibleList, isDeletePopupVisible, listToEdit } = sourcesOfListState
return (
<div>
<Button className="btn-wide mb-3" size="sm" color="info" onClick={actions.hideSourcesOfList}>
<i className="lnr lnr-chevron-left"> </i>
</Button>
<div className="mb-3">
<p className="text-primary text-uppercase font-weight-bold mb-2">{visibleList.name} ({visibleList.sourceNumber})</p>
<InputGroup>
<Input
id="source-index-search"
placeholder={t('sourceIndexTab.mainInputPlaceholder')}
value={searchQuery}
onChange={this.onChangeSearchInput}
onKeyUp={this.onEnterSearchInput}
/>
<InputGroupAddon addonType="append">
<Button
color="primary"
className="btn-icon btn-icon-only"
onClick={this.onSearchSources}
>
<i className="lnr-magnifier btn-icon-wrapper"></i>
</Button>
</InputGroupAddon>
</InputGroup>
</div>
<SourceIndexTable
tableState={sourcesOfListState}
type='sourcesOfListState'
onFetch={this.onFetchData}
onDeleteIndex={actions.toggleDeleteListIndexPopup}
actions={actions}
/>
{isDeletePopupVisible &&
<SourceListsDeletePopup
listToEdit={listToEdit}
toggleDeleteListPopup={actions.toggleDeleteListIndexPopup}
deleteSourceList={this.onDeleteIndex}
/>
}
</div>
)
}
}
export default translate(['tabsContent'], { wait: true })(SourcesOfList)