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,30 @@
import React from 'react';
import PropTypes from 'prop-types';
import { translate } from 'react-i18next';
import { Col } from 'reactstrap';
export class InfoField extends React.Component {
static propTypes = {
t: PropTypes.func.isRequired,
label: PropTypes.string,
labelValue: PropTypes.string,
children: PropTypes.oneOfType([PropTypes.string, PropTypes.element])
};
render() {
const { t, label, children, labelValue } = this.props;
return (
<li className="row">
<Col sm="4">
<p className="mb-1">{labelValue || t(label)}</p>
</Col>
<Col sm="8">
<p className="mb-1">{children}</p>
</Col>
</li>
);
}
}
export default translate(['tabsContent'], { wait: true })(InfoField);
@@ -0,0 +1,143 @@
import React from 'react';
import PropTypes from 'prop-types';
import { translate } from 'react-i18next';
import PopupLayout from '../../../../common/Popups/PopupLayout';
import InfoField from './InfoField';
import {
capOnlyFirstLetter,
getTitle,
notNullAndUnd
} from '../../../../../common/helper';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faCheckCircle } from '@fortawesome/free-solid-svg-icons';
class SourceIndexInfoPopup extends React.Component {
static propTypes = {
source: PropTypes.object.isRequired,
hideSourceInfoPopup: PropTypes.func.isRequired,
t: PropTypes.func.isRequired
};
render() {
let { t, source, hideSourceInfoPopup } = this.props;
/*
const loc = cl(
source.city,
source.state,
source.country && t(`common:country.${source.country}`)
)
.split(' ')
.join(', '); */
/*
source = {
...source,
tags: ['Lorem', 'ipsum', 'dolor', 'ipsum', 'dolor', 'ipsum', 'dolor'],
verified: true,
followers: 3333,
following: 33,
favorites: 333,
title: 'Title',
url: 'URL',
type: 'Type',
subType: 'Sub Type',
lang: 'en',
location: 'Washington, DC',
country: 'US',
spam_probability: '20%',
likes: 3
}; */
return (
<PopupLayout
className="source-info-popup"
title="sourceIndexTab.sourceInfoPopupTitle"
showFooter={false}
onHide={hideSourceInfoPopup}
>
<ul className="container">
<InfoField label="sourceIndexTab.titleLabel">
<a href={source.url} target="_blank" rel="noopener noreferrer">
{getTitle(source.title)}
</a>
</InfoField>
{source.url && (
<InfoField label="sourceIndexTab.homeUrl">{source.url}</InfoField>
)}
{source.type && (
<InfoField label="sourceIndexTab.mediaType">
{capOnlyFirstLetter(source.type)}
</InfoField>
)}
{source.subType && (
<InfoField labelValue="Sub Type">
{capOnlyFirstLetter(source.subType)}
</InfoField>
)}
{source.verified && (
<InfoField labelValue="Verified">
<FontAwesomeIcon
title="Source Verified"
className="text-primary"
icon={faCheckCircle}
/>
</InfoField>
)}
{source.lang && (
<InfoField label="sourceIndexTab.lang">
{t(`common:language.${source.lang}`, '-')}
</InfoField>
)}
{source.location && (
<InfoField labelValue="Location">{source.location}</InfoField>
)}
{source.country && (
<InfoField label="sourceIndexTab.country">
{t(`common:country.${source.country}`)}
</InfoField>
)}
{notNullAndUnd(source.followers) && (
<InfoField labelValue="Followers">{source.followers}</InfoField>
)}
{notNullAndUnd(source.following) && (
<InfoField labelValue="Following">{source.following}</InfoField>
)}
{notNullAndUnd(source.favorites) && (
<InfoField labelValue="Favorites">{source.favorites}</InfoField>
)}
{notNullAndUnd(source.likes) && (
<InfoField labelValue="Likes">{source.likes}</InfoField>
)}
{source.tags && source.tags.length > 0 && (
<InfoField labelValue="Tags">{source.tags.join(', ')}</InfoField>
)}
{source.spam_probability && (
<InfoField labelValue="Spam Probability">
{source.spam_probability}
</InfoField>
)}
{source.source_profiles && (
<InfoField labelValue="Source profiles">
{source.source_profiles.join(', ')}
</InfoField>
)}
</ul>
</PopupLayout>
);
}
}
export default translate(['tabsContent'], { wait: true })(SourceIndexInfoPopup);
@@ -0,0 +1,186 @@
import React from 'react'
import PropTypes from 'prop-types'
import { translate } from 'react-i18next'
import SourceIndexTable from './SourceIndexTable'
import SourceIndexUpdatePopup from './SourceIndexUpdatePopup'
import FiltersTable from '../../../../common/FiltersTable/FiltersTable'
import { withRouter } from 'react-router-dom'
import reduxConnect from '../../../../../redux/utils/connect'
import { compose } from 'redux'
import { Button, ButtonGroup, Input, InputGroup, InputGroupAddon } from 'reactstrap'
import { setDocumentData } from '../../../../../common/helper'
class SourceIndexSubTab extends React.Component {
static propTypes = {
sourcesState: PropTypes.object.isRequired,
actions: PropTypes.object.isRequired,
t: PropTypes.func.isRequired
};
componentDidMount() {
setDocumentData('title', 'Source Index | Search')
}
componentWillUnmount() {
setDocumentData('title')
}
_sourceIndexesState = () => this.props.sourcesState.sourceIndexesState;
_sourceLists = () => this.props.sourcesState.sourceListsState.data;
loadSourceIndexes = (params) => {
this.props.actions.getSourceIndexes(params || null)
};
onSearchSources = () => {
this.loadSourceIndexes()
};
onEnterSearchInput = (e) => {
if (e.keyCode === 13) this.loadSourceIndexes()
};
onChangeSearchInput = (e) => {
this.props.actions.setSourceIndexSearchQuery(e.target.value)
};
onFetchData = (params) => {
this.loadSourceIndexes(params)
};
showAddToListPopup = () => {
const { actions } = this.props
const sourceIndexesState = this._sourceIndexesState()
if (sourceIndexesState.selectedIds.length === 0) {
actions.addAlert({
type: 'notice',
transKey: 'noListsSelected',
id: 'noListsSelected'
})
return false
}
actions.toggleAddSourceToListPopup()
};
onSelectFilter = (groupName, filterValue) => {
this.props.actions.selectSourcesFilter(groupName, filterValue)
};
onClearFilters = (groupName) => {
this.props.actions.clearSourcesFilters(groupName)
};
onClearAllFilters = () => {
this.props.actions.clearAllSourcesFilters()
};
onMoreFilters = (groupName) => {
this.props.actions.loadMoreSourcesFilters(groupName)
};
onLessFilters = (groupName) => {
this.props.actions.loadLessSourcesFilters(groupName)
};
render () {
const { t, actions } = this.props
const sourceIndexesState = this._sourceIndexesState()
const sourceLists = this._sourceLists()
const {
searchQuery,
selectedIds,
chosenListsToAddSources,
chosenSourceToUpdate,
advancedFilters
} = sourceIndexesState
return (
<div className="mb-3">
<InputGroup className="mb-3">
<Input
type="text"
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>
<ButtonGroup className="mb-3">
<Button
onClick={this.showAddToListPopup}
color="secondary"
>
<i className="fa fa-plus fa-1px for-small mr-1"> </i>{" "}
{t('sourceIndexTab.addToSourceListsBtn')}
</Button>
</ButtonGroup>
<div className="search-content">
<SourceIndexTable
tableState={sourceIndexesState}
type="sourceIndexesState"
onFetch={this.onFetchData}
actions={actions}
/>
<FiltersTable
filters={advancedFilters.all}
pages={advancedFilters.pages}
selectedFilters={advancedFilters.selected}
clearPending={advancedFilters.pending}
callbacks={{
selectFilter: this.onSelectFilter,
clearFilters: this.onClearFilters,
clearAllFilters: this.onClearAllFilters,
moreFilters: this.onMoreFilters,
lessFilters: this.onLessFilters,
refine: this.onSearchSources
}}
/>
</div>
{sourceIndexesState.isAddPopupVisible && (
<SourceIndexUpdatePopup
type="add"
sourceLists={sourceLists}
chosenLists={chosenListsToAddSources}
chosenSourceIndexes={selectedIds}
actions={actions}
/>
)}
{sourceIndexesState.isUpdatePopupVisible && (
<SourceIndexUpdatePopup
type="update"
sourceLists={sourceLists}
chosenLists={chosenSourceToUpdate.listIds}
chosenSourceIndexes={[chosenSourceToUpdate.id]}
updateItemTitle={chosenSourceToUpdate.title}
actions={actions}
/>
)}
</div>
)
}
}
const applyDecorators = compose(
withRouter,
reduxConnect('sourcesState', ['appState', 'sourcesState']),
translate(['tabsContent'], { wait: true })
)
export default applyDecorators(SourceIndexSubTab)
@@ -0,0 +1,195 @@
import React from 'react'
import PropTypes from 'prop-types'
import { translate, Interpolate } from 'react-i18next'
import Table from '../../../../common/Table/Table'
import CheckboxCell from '../../../../common/Table/CheckboxCell'
import SortableTh from '../../../../common/Table/SortableTh'
import SourceIndexInfoPopup from './SourceIndexInfoPopup'
import { Button } from 'reactstrap'
import { getTitle } from '../../../../../common/helper'
export class SourceIndexTable extends React.Component {
static propTypes = {
t: PropTypes.func.isRequired,
tableState: PropTypes.object.isRequired,
type: PropTypes.string.isRequired,
onFetch: PropTypes.func.isRequired,
onDeleteIndex: PropTypes.func,
actions: PropTypes.object.isRequired
};
onFetch = (page, pageSize, sorted) => {
const { tableState, onFetch } = this.props
const params = {
page: page + 1,
limit: pageSize,
query: tableState.searchQuery
}
if (sorted.length) {
const sortedField = sorted[0]
const sort = {
field: sortedField.id,
direction: sortedField.desc ? 'desc' : 'asc'
}
params['sort'] = sort
}
onFetch(params)
};
selectAllAction = (event) => {
const { actions } = this.props
actions.toggleAllSourceIndexes()
};
selectRowAction = (itemId) => {
const { actions } = this.props
actions.toggleSourceIndex(itemId) // TODO
};
showUpdateSourcePopup = (source) => (e) => {
e.preventDefault()
this.props.actions.showUpdateSourcePopup(source)
};
deleteSourceIndex = (source) => (e) => {
e.preventDefault()
this.props.onDeleteIndex(source)
};
toggleInfoPopup = (source) => () => {
const { type, actions } = this.props
actions.toggleInfoSourcePopup(type, source)
};
getColumns = () => {
const {t, type, tableState} = this.props
let columns = [
{
id: 'selectCheckbox',
accessor: '',
sortable: false,
width: 45,
className: 'cw-center-cell',
headerClassName: 'cw-center-cell',
Header: () => {
return (
<CheckboxCell
checked={tableState.isAllSelected}
onChange={this.selectAllAction}
/>
)
},
Cell: ({original}) => {
const isSelected = tableState.selectedIds.includes(original.id)
return (
<CheckboxCell
id={original.id}
checked={isSelected}
onChange={this.selectRowAction}
/>
)
}
}, {
Header: <SortableTh title='sourceIndexTab.name' />,
accessor: 'name',
Cell: ({original}) => {
return (
<Button
color="link"
className="btn-anchor"
title="Click to see details"
onClick={this.toggleInfoPopup(original)}
>
{getTitle(original.title)}
</Button>
)
}
}, {
id: 'mediaType',
Header: <SortableTh title='sourceIndexTab.mediaType' />,
accessor: item => t(`searchTab.sourceTypes.${item.type}`)
}, {
id: 'country',
Header: <SortableTh title='sourceIndexTab.country' />,
accessor: item => {
return item.country ? t(`common:country.${item.country}`) : ''
}
}, {
id: 'action',
Header: t('sourceIndexTab.action'),
sortable: false,
Cell: ({original}) => {
return (
<Button
outline
color="info"
className="border-0"
size="sm"
onClick={this.showUpdateSourcePopup(original)}
>
<Interpolate
i18nKey='sourceIndexTab.actionBtn'
listsCount={original.listIds.length}
/>
</Button>
)
}
}, {
id: 'deleteAction',
Header: t('sourceIndexTab.action'),
sortable: false,
Cell: ({original}) => {
return (
<Button
outline
size="sm"
color="secondary"
className="border-0"
onClick={this.deleteSourceIndex(original)}
>
{t('sourceListsTab.delete')}
</Button>
)
}
}
]
const sourceIndexCols = ['selectCheckbox', 'name', 'mediaType', 'country', 'action']
const sourceOfListCols = ['name', 'mediaType', 'country', 'deleteAction']
let cols = type === 'sourceIndexesState' ? sourceIndexCols : sourceOfListCols
return columns.filter(col => cols.includes(col.id) || cols.includes(col.accessor))
};
render () {
const {tableState} = this.props
const columns = this.getColumns()
const infoPopup = tableState.infoPopup
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}
/>
{infoPopup.visible && infoPopup.item &&
<SourceIndexInfoPopup
source={infoPopup.item}
hideSourceInfoPopup={this.toggleInfoPopup(null)}
/>
}
</div>
)
}
}
export default translate(['tabsContent'], { wait: true })(SourceIndexTable)
@@ -0,0 +1,106 @@
import React from 'react'
import PropTypes from 'prop-types'
import { translate, Interpolate } from 'react-i18next'
import PopupLayout from '../../../../common/Popups/PopupLayout'
import { CustomInput } from 'reactstrap'
import { getTitle } from '../../../../../common/helper'
export class SourceIndexUpdatePopup extends React.Component {
static propTypes = {
type: PropTypes.string.isRequired,
sourceLists: PropTypes.array.isRequired,
chosenLists: PropTypes.array.isRequired,
chosenSourceIndexes: PropTypes.array.isRequired,
updateItemTitle: PropTypes.string,
actions: PropTypes.object.isRequired,
t: PropTypes.func.isRequired
};
componentWillMount = () => {
const { sourceLists, actions } = this.props
if (sourceLists.length === 0) {
actions.getMainSourceLists({page: 1, limit: 50})
}
};
onChoseList = (e) => {
const { type, chosenLists, actions } = this.props
const isChecked = e.target.checked
const listId = parseInt(e.target.dataset.listId)
const lists = isChecked ? chosenLists.concat(listId) : chosenLists.filter((id) => listId !== id)
const action = type === 'add' ? actions.setChosenListsToAddSources : actions.setChosenListsToUpdateSources
action(lists)
};
onSubmit = () => {
const { actions, chosenSourceIndexes, chosenLists, type } = this.props
actions.addSourcesToList({
sources: chosenSourceIndexes,
sourceLists: chosenLists
}, type === 'add')
};
getBodyTitle () {
const { t, type, updateItemTitle } = this.props
if (type === 'add') {
return <p className="mb-3">{t('sourceListsTab.popup.addToListDesc')}</p>
}
else {
return (
<p className="mb-3">
<Interpolate
i18nKey='sourceListsTab.popup.updateListDesc'
name={getTitle(updateItemTitle)}
/>
</p>
)
}
}
render () {
const { type, sourceLists, chosenLists, actions } = this.props
const isAdd = type === 'add'
const title = isAdd ? 'addToListTitle' : 'updateListTitle'
const submitText = isAdd ? 'addBtn' : 'saveBtn'
const hideAction = isAdd ? actions.toggleAddSourceToListPopup : actions.hideUpdateSourcePopup
return (
<PopupLayout
title={`sourceListsTab.popup.${title}`}
submitText={`sourceListsTab.popup.${submitText}`}
onHide={hideAction}
onSubmit={this.onSubmit}
>
<div>
{this.getBodyTitle()}
{sourceLists.length > 0 &&
<ul className="row">
{sourceLists.map((list, i) => {
const isListChosen = chosenLists.includes(list.id)
return (
<li key={i} className="col-md-4 col-sm-6 mb-2">
<CustomInput
type="checkbox"
id={'sourceListCheck-' + i}
className="d-flex"
data-list-id={list.id}
checked={isListChosen}
onChange={this.onChoseList}
label={list.name}
/>
</li>
)
})}
</ul>
}
</div>
</PopupLayout>
)
}
}
export default translate(['tabsContent', 'common'], { wait: true })(SourceIndexUpdatePopup)