diff --git a/assets/agenda/components/AgendaApp.tsx b/assets/agenda/components/AgendaApp.tsx index 17862b4ea..efa92d681 100644 --- a/assets/agenda/components/AgendaApp.tsx +++ b/assets/agenda/components/AgendaApp.tsx @@ -57,7 +57,6 @@ import BookmarkTabs from 'components/BookmarkTabs'; import {setActiveDate, setAgendaDropdownFilter} from 'local-store'; import {previewConfigSelector, detailsConfigSelector} from 'ui/selectors'; import {SearchResultsBar} from 'search/components/SearchResultsBar'; -import NewItemsIcon from 'search/components/NewItemsIcon'; const modals = { shareItem: ShareItemModal, @@ -268,17 +267,9 @@ class AgendaApp extends SearchBase { toggleFeaturedFilter={this.props.toggleFeaturedFilter} featuredFilter={this.props.featuredOnly} hasAgendaFeaturedItems={this.props.hasAgendaFeaturedItems} + newItems={this.props.newItems} + fetchItems={this.props.fetchItems} /> - {!(this.props.newItems || []).length ? null : ( -
-
- -
-
- )} { } render() { - return isMobilePhone() ? + return isTablet() ? this.renderMobile() : this.renderNonMobile(); } diff --git a/assets/agenda/components/AgendaListViewControls.tsx b/assets/agenda/components/AgendaListViewControls.tsx index 0e714cdb8..1e2333953 100644 --- a/assets/agenda/components/AgendaListViewControls.tsx +++ b/assets/agenda/components/AgendaListViewControls.tsx @@ -1,31 +1,54 @@ import React from 'react'; -import PropTypes from 'prop-types'; - import AgendaFeaturedStoriesToogle from './AgendaFeaturedStoriesToogle'; -import {DISPLAY_AGENDA_FEATURED_STORIES_ONLY} from 'utils'; +import {DISPLAY_AGENDA_FEATURED_STORIES_ONLY, isMobilePhoneScreen} from 'utils'; import ListViewOptions from 'components/ListViewOptions'; +import NewItemsIcon from 'search/components/NewItemsIcon'; +import {WithScreenSizeObserver} from '@sourcefabric/common'; +import {IAgendaItem, IEvent} from 'interfaces'; -function AgendaListViewControls({activeView, setView, hideFeaturedToggle, toggleFeaturedFilter, featuredFilter, hasAgendaFeaturedItems}: any) { - return ( -
-
- {!hideFeaturedToggle && hasAgendaFeaturedItems && DISPLAY_AGENDA_FEATURED_STORIES_ONLY && - - } - -
-
- ); +interface IProps { + activeView?: string; + hideFeaturedToggle?: boolean; + featuredFilter?: boolean; + hasAgendaFeaturedItems?: boolean; + newItems?: Array; + setView: (view: {type: string, label: string}) => void; + toggleFeaturedFilter: (event: IEvent) => void; + fetchItems: () => void; } +function AgendaListViewControls({activeView, setView, hideFeaturedToggle, toggleFeaturedFilter, featuredFilter, hasAgendaFeaturedItems, newItems, fetchItems}: IProps) { + const renderRefreshButton = (newItems || []).length > 0 && ( +
+ +
+ ); -AgendaListViewControls.propTypes = { - activeView: PropTypes.string, - setView: PropTypes.func.isRequired, - toggleFeaturedFilter: PropTypes.func.isRequired, - hideFeaturedToggle: PropTypes.bool, - featuredFilter: PropTypes.bool, - hasAgendaFeaturedItems: PropTypes.bool, -}; + return ( + + {(dimensions) => ( +
+ {isMobilePhoneScreen(dimensions.width) + ? renderRefreshButton + : ( + <> + {renderRefreshButton} +
+ {!hideFeaturedToggle && hasAgendaFeaturedItems && DISPLAY_AGENDA_FEATURED_STORIES_ONLY && + + } + +
+ + ) + } +
+ )} +
+ ); +} export default AgendaListViewControls; diff --git a/assets/agenda/index.ts b/assets/agenda/index.ts index ac408c81e..853a815b4 100644 --- a/assets/agenda/index.ts +++ b/assets/agenda/index.ts @@ -1,5 +1,5 @@ import {IAgendaState} from 'interfaces'; -import {createStore, getInitData, isMobilePhone, closeItemOnMobile} from 'utils'; +import {createStore, getInitData, isTablet, closeItemOnMobile} from 'utils'; import {initWebSocket} from 'websocket'; import agendaReducer from './reducers'; @@ -28,7 +28,7 @@ if (localStorage.getItem('view')) { window.onpopstate = function(event: any) { if (event.state) { closeItemOnMobile(store.dispatch, event.state, openItemDetails, previewItem); - if (!isMobilePhone()) { + if (!isTablet()) { store.dispatch(setState(event.state)); store.dispatch(fetchItems()); } diff --git a/assets/am-news/index.ts b/assets/am-news/index.ts index a0749737c..24f9c2bbe 100644 --- a/assets/am-news/index.ts +++ b/assets/am-news/index.ts @@ -1,6 +1,6 @@ import {get, startsWith} from 'lodash'; -import {createStore, getInitData, closeItemOnMobile, isMobilePhone} from '../utils'; +import {createStore, getInitData, closeItemOnMobile, isTablet} from '../utils'; import {initWebSocket} from 'websocket'; import {getReadItems} from 'local-store'; @@ -45,7 +45,7 @@ if (navigationId) { window.onpopstate = function(event: any) { if (event.state) { closeItemOnMobile(store.dispatch, event.state, openItemDetails, previewItem); - if (!isMobilePhone()) { + if (!isTablet()) { store.dispatch(setState(event.state)); } } diff --git a/assets/factcheck/index.ts b/assets/factcheck/index.ts index 09e97a69b..0059d7f47 100644 --- a/assets/factcheck/index.ts +++ b/assets/factcheck/index.ts @@ -1,4 +1,4 @@ -import {createStore, getInitData, closeItemOnMobile, isMobilePhone} from '../utils'; +import {createStore, getInitData, closeItemOnMobile, isTablet} from '../utils'; import {initWebSocket} from 'websocket'; import {getReadItems} from 'local-store'; @@ -33,7 +33,7 @@ store.dispatch(initParams(params)); window.onpopstate = function(event: any) { if (event.state) { closeItemOnMobile(store.dispatch, event.state, openItemDetails, previewItem); - if (!isMobilePhone()) { + if (!isTablet()) { store.dispatch(setState(event.state)); } } diff --git a/assets/home/components/HomeApp.tsx b/assets/home/components/HomeApp.tsx index 3a040329c..c1c534568 100644 --- a/assets/home/components/HomeApp.tsx +++ b/assets/home/components/HomeApp.tsx @@ -1,7 +1,7 @@ import React from 'react'; import {connect} from 'react-redux'; -import {gettext, isDisplayed, isMobilePhone} from 'utils'; +import {gettext, isDisplayed, isTablet} from 'utils'; import {getCard} from 'components/cards/utils'; import getItemActions from 'wire/item-actions'; import ItemDetails from 'wire/components/ItemDetails'; @@ -271,7 +271,7 @@ class HomeApp extends React.Component extends React.Component extends React.Component { window.onpopstate = function(event: any) { if (event.state) { closeItemOnMobile(store.dispatch, event.state, openItemDetails, previewItem); - if (!isMobilePhone()) { + if (!isTablet()) { store.dispatch(setState(event.state)); } } diff --git a/assets/media-releases/index.ts b/assets/media-releases/index.ts index daef6b5d6..6396dba46 100644 --- a/assets/media-releases/index.ts +++ b/assets/media-releases/index.ts @@ -1,4 +1,4 @@ -import {createStore, getInitData, closeItemOnMobile, isMobilePhone} from '../utils'; +import {createStore, getInitData, closeItemOnMobile, isTablet} from '../utils'; import {initWebSocket} from 'websocket'; import {render} from 'render-utils'; @@ -33,7 +33,7 @@ store.dispatch(initParams(params)); window.onpopstate = function(event: any) { if (event.state) { closeItemOnMobile(store.dispatch, event.state, openItemDetails, previewItem); - if (!isMobilePhone()) { + if (!isTablet()) { store.dispatch(setState(event.state)); } } diff --git a/assets/monitoring/index.ts b/assets/monitoring/index.ts index c4647deb4..37892b1fe 100644 --- a/assets/monitoring/index.ts +++ b/assets/monitoring/index.ts @@ -1,6 +1,6 @@ import {get, startsWith} from 'lodash'; -import {createStore, getInitData, closeItemOnMobile, isMobilePhone} from 'utils'; +import {createStore, getInitData, closeItemOnMobile, isTablet} from 'utils'; import {render} from 'render-utils'; import {initWebSocket} from 'websocket'; import {getReadItems} from 'local-store'; @@ -39,7 +39,7 @@ if (get(window.viewData, 'context', '') === 'monitoring') { window.onpopstate = function(event: any) { if (event.state) { closeItemOnMobile(store.dispatch, event.state, openItemDetails, previewItem); - if (!isMobilePhone()) { + if (!isTablet()) { store.dispatch(setState(event.state)); } } diff --git a/assets/search/components/NewItemsIcon.tsx b/assets/search/components/NewItemsIcon.tsx index 49ffeddad..8cdea420d 100644 --- a/assets/search/components/NewItemsIcon.tsx +++ b/assets/search/components/NewItemsIcon.tsx @@ -56,7 +56,7 @@ class NewItemsIcon extends React.Component { ref={(elem: any) => this.dom.tooltip = elem} title={gettext('refresh')} aria-label={gettext('refresh')} - className="button__reset-styles d-flex align-items-center ms-3" + className="button__reset-styles d-flex align-items-center" onClick={this.props.refresh} > diff --git a/assets/styles/navbar.scss b/assets/styles/navbar.scss index 509da2018..a324fc749 100644 --- a/assets/styles/navbar.scss +++ b/assets/styles/navbar.scss @@ -567,11 +567,3 @@ nav.search { } } } - -.navbar { - &.navbar--list-controls { - @include phone { - display: none; - } - } -} \ No newline at end of file diff --git a/assets/utils.tsx b/assets/utils.tsx index 00134ec84..54ccffb9d 100644 --- a/assets/utils.tsx +++ b/assets/utils.tsx @@ -561,10 +561,14 @@ export function isTouchDevice() { || navigator.maxTouchPoints > 0; // works on IE10/11 and Surface } -export function isMobilePhone() { +export function isTablet() { return isTouchDevice() && screen.width < 768; } +export function isMobilePhoneScreen(dimensions: number) { + return dimensions < 575; +} + /** * Checks if wire context * @returns {boolean} @@ -633,7 +637,7 @@ export function recordAction(item: any, action: any = 'open', section: any = 'wi } export function closeItemOnMobile(dispatch: any, state: any, openItemDetails: any, previewItem: any) { - if (isMobilePhone()) { + if (isTablet()) { dispatch(openItemDetails(null)); dispatch(previewItem(null)); } @@ -677,7 +681,7 @@ export function shouldShowListShortcutActionIcons(listConfig: any, isExtended: a mobile: false, }; - return isMobilePhone() ? + return isTablet() ? showActionIconsConfig.mobile : ( isExtended ? showActionIconsConfig.large : diff --git a/assets/wire/components/ListViewControls.tsx b/assets/wire/components/ListViewControls.tsx index 8e70ec3e4..a6639bc52 100644 --- a/assets/wire/components/ListViewControls.tsx +++ b/assets/wire/components/ListViewControls.tsx @@ -1,12 +1,27 @@ import React from 'react'; -import PropTypes from 'prop-types'; - import {noNavigationSelected} from 'search/utils'; - import NewsOnlyControl from './NewsOnlyControl'; import SearchAllVersionsControl from './SearchAllVersionsControl'; import ListViewOptions from '../../components/ListViewOptions'; import {ListSearchOptions} from './ListSearchOptions'; +import NewItemsIcon from 'search/components/NewItemsIcon'; +import {isMobilePhoneScreen} from 'utils'; +import {WithScreenSizeObserver} from '@sourcefabric/common'; +import {IArticle} from 'interfaces'; + +interface IProps { + activeView?: string; + newsOnly?: boolean; + activeNavigation?: Array; + hideNewsOnly?: boolean; + hideSearchAllVersions?: boolean; + searchAllVersions?: boolean; + newItems?: Array; + setView: (view: {type: string, label: string}) => void; + toggleSearchAllVersions?: () => void; + toggleNews?: () => void; + fetchItems: () => void; +} function ListViewControls({ activeView, @@ -18,51 +33,62 @@ function ListViewControls({ hideSearchAllVersions, searchAllVersions, toggleSearchAllVersions, -}: any) { - return( -
-
- {hideSearchAllVersions ? null : ( - - )} - {!hideNewsOnly && } - - - {(!noNavigationSelected(activeNavigation) || (hideSearchAllVersions && hideNewsOnly)) ? null : ( -
- -
- )} -
+ newItems, + fetchItems, +}: IProps) { + const renderRefreshButton = (newItems || []).length > 0 && ( +
+
); -} -ListViewControls.propTypes = { - activeView: PropTypes.string, - setView: PropTypes.func.isRequired, - newsOnly: PropTypes.bool, - toggleNews: PropTypes.func, - activeNavigation: PropTypes.arrayOf(PropTypes.string), - hideNewsOnly: PropTypes.bool, - hideSearchAllVersions: PropTypes.bool, - searchAllVersions: PropTypes.bool, - toggleSearchAllVersions: PropTypes.func, -}; + return ( + + {(dimensions) => ( +
+ {isMobilePhoneScreen(dimensions.width) + ? renderRefreshButton + : ( + <> + {renderRefreshButton} +
+ {hideSearchAllVersions ? null : ( + + )} + {!hideNewsOnly && } + + + {(!noNavigationSelected(activeNavigation) || (hideSearchAllVersions && hideNewsOnly)) ? null : ( +
+ +
+ )} +
+ + ) + } +
+ )} +
+ ); +} export default ListViewControls; diff --git a/assets/wire/components/WireApp.tsx b/assets/wire/components/WireApp.tsx index e386c59b2..68b3002d5 100644 --- a/assets/wire/components/WireApp.tsx +++ b/assets/wire/components/WireApp.tsx @@ -62,7 +62,6 @@ import { listConfigSelector, advancedSearchTabsConfigSelector, } from 'ui/selectors'; -import NewItemsIcon from 'search/components/NewItemsIcon'; const modals: any = { shareItem: ShareItemModal, @@ -238,17 +237,9 @@ class WireApp extends SearchBase { hideSearchAllVersions={!(this.props.context === 'wire' && DISPLAY_ALL_VERSIONS_TOGGLE)} searchAllVersions={this.props.searchAllVersions} toggleSearchAllVersions={this.props.toggleSearchAllVersions} + newItems={this.props.newItems} + fetchItems={this.props.fetchItems} /> - {!(this.props.newItems || []).length ? null : ( -
-
- -
-
- )}
{ const {companyId, userId} = e.detail; store.dispatch(fetchFoldersWire(companyId, userId)); -}); \ No newline at end of file +}); diff --git a/package-lock.json b/package-lock.json index a372d183e..6dc1bb1bd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1475,10 +1475,80 @@ "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==", "dev": true }, + "@sourcefabric/common": { + "version": "0.0.37", + "resolved": "https://registry.npmjs.org/@sourcefabric/common/-/common-0.0.37.tgz", + "integrity": "sha512-LVtXJ3AKpU1tMveVkr//XmewZcNSJJrOtgprXOjdgwolcWkqF0ElzZFVH1JJyoeMPFenvcS7OKIlNjPxz/8etw==", + "requires": { + "date-fns": "2.7.0", + "lodash": "4.17.19", + "primereact": "^6.0.2", + "react": "16.9.0", + "react-dom": "16.9.0", + "react-sortable-hoc": "^1.11.0" + }, + "dependencies": { + "date-fns": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.7.0.tgz", + "integrity": "sha512-wxYp2PGoUDN5ZEACc61aOtYFvSsJUylIvCjpjDOqM1UDaKIIuMJ9fAnMYFHV3TQaDpfTVxhwNK/GiCaHKuemTA==" + }, + "lodash": { + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==" + }, + "primereact": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/primereact/-/primereact-6.6.0.tgz", + "integrity": "sha512-onoowjhlOz9Kcjna1DYEKWTGjKah4MjqZchm9E3BkcWjeXoCLv3F5QnIo8eVF9q+xymEK/6Oh7zHlfCJYyWwDw==" + }, + "react": { + "version": "16.9.0", + "resolved": "https://registry.npmjs.org/react/-/react-16.9.0.tgz", + "integrity": "sha512-+7LQnFBwkiw+BobzOF6N//BdoNw0ouwmSJTEm9cglOOmsg/TMiFHZLe2sEoN5M7LgJTj9oHH0gxklfnQe66S1w==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2" + } + }, + "react-dom": { + "version": "16.9.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.9.0.tgz", + "integrity": "sha512-YFT2rxO9hM70ewk9jq0y6sQk8cL02xm4+IzYBz75CQGlClQQ1Bxq0nhHF6OtSbit+AIahujJgb/CPRibFkMNJQ==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2", + "scheduler": "^0.15.0" + } + }, + "react-sortable-hoc": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/react-sortable-hoc/-/react-sortable-hoc-1.11.0.tgz", + "integrity": "sha512-v1CDCvdfoR3zLGNp6qsBa4J1BWMEVH25+UKxF/RvQRh+mrB+emqtVHMgZ+WreUiKJoEaiwYoScaueIKhMVBHUg==", + "requires": { + "@babel/runtime": "^7.2.0", + "invariant": "^2.2.4", + "prop-types": "^15.5.7" + } + }, + "scheduler": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.15.0.tgz", + "integrity": "sha512-xAefmSfN6jqAa7Kuq7LIJY0bwAPG3xlCj0HMEBQk1lxYiDKZscY2xJ5U/61ZTrYbmNQbXa+gc7czPkVo11tnCg==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + } + } + }, "@superdesk/common": { - "version": "0.0.28", - "resolved": "https://registry.npmjs.org/@superdesk/common/-/common-0.0.28.tgz", - "integrity": "sha512-EhsYMm340r3FVrakH00lLvQbxVYYTzL61J5GXI3BI2xLN2dPI3N0AJEaMGqjbt0xUpUFxE3T08OtYvIC5koZvg==", + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@superdesk/common/-/common-0.0.29.tgz", + "integrity": "sha512-Fg/BlKxhkuxdVu6GtBk7SSSVdy67S+zUmB0Zun7atuswOzvM+ZDwlDFC8AIJKRG8Dqf3qRDO8JQhFKgB/M0kEg==", "requires": { "date-fns": "2.7.0", "lodash": "4.17.19", diff --git a/package.json b/package.json index 666cfa188..28660f086 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,8 @@ "@dnd-kit/core": "^6.0.8", "@dnd-kit/sortable": "^8.0.0", "@popperjs/core": "^2.11.4", - "@superdesk/common": "0.0.28", + "@sourcefabric/common": "0.0.37", + "@superdesk/common": "0.0.29", "@types/bootstrap": "^5.2.6", "@types/lodash": "^4.17.6", "@types/react": "^17.0.2", @@ -56,6 +57,7 @@ "redux-logger": "3.0.6", "redux-thunk": "2.4.2", "reselect": "3.0.1", + "sass": "~1.3.0", "sass-loader": "~10.5.2", "store": "2.0.12", "style-loader": "~2.0.0",