Skip to content

Commit

Permalink
search page new list (#1498)
Browse files Browse the repository at this point in the history
  • Loading branch information
jdtoombs authored Feb 7, 2024
1 parent e871a89 commit 298e3ce
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 301 deletions.
36 changes: 28 additions & 8 deletions app/subscriber/src/components/content-list/ContentList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import { IContentSearchResult } from 'features/utils/interfaces';
import moment from 'moment';
import React from 'react';
import { FaPlayCircle } from 'react-icons/fa';
import { FaCopyright, FaEyeSlash } from 'react-icons/fa6';
import { FaCopyright, FaEyeSlash, FaSquareUpRight } from 'react-icons/fa6';
import { useNavigate } from 'react-router-dom';
import { useContent } from 'store/hooks';
import { Checkbox, Col, IContentModel, IFileReferenceModel, Row, Show } from 'tno-core';
import { useContent, useLookup } from 'store/hooks';
import { Checkbox, Col, IContentModel, IFileReferenceModel, Row, Settings, Show } from 'tno-core';

import { ContentListContext } from './ContentListContext';
import * as styled from './styled';
Expand All @@ -18,17 +18,24 @@ export interface IContentListProps {
onContentSelected: (content: IContentModel[]) => void;
/** array of selected content */
selected: IContentModel[];
/** prop to determine whether to style the content based on user settings */
styleOnSettings?: boolean;
/** determine whether to show date next to the sentiment icon */
showDate?: boolean;
}

export const ContentList: React.FC<IContentListProps> = ({
content,
onContentSelected,
selected,
styleOnSettings = false,
showDate = false,
}) => {
const navigate = useNavigate();
const { groupBy, viewOptions } = React.useContext(ContentListContext);
const grouped = groupContent(groupBy, content);
const [, { stream }] = useContent();
const [{ settings }] = useLookup();

const [activeFileReference, setActiveFileReference] = React.useState<IFileReferenceModel>();
const [activeStream, setActiveStream] = React.useState<{ source: string; id: number }>();
Expand All @@ -52,6 +59,10 @@ export const ContentList: React.FC<IContentListProps> = ({
}
}, [activeFileReference, stream, setActiveStream]);

const popOutIds = React.useMemo(() => {
return settings.find((setting) => setting.name === Settings.SearchPageResultsNewWindow)?.value;
}, [settings]);

return (
<styled.ContentList>
{Object.keys(grouped).map((group) => (
Expand Down Expand Up @@ -82,10 +93,23 @@ export const ContentList: React.FC<IContentListProps> = ({
}}
/>
{viewOptions.sentiment && determineToneIcon(item.tonePools[0])}
{viewOptions.date && (
{showDate && (
<div className="date">{moment(item.publishedOn).format('DD-MMM-YYYY')}</div>
)}
<button className="headline">{item.headline}</button>
<Show visible={viewOptions.section}>
{item.section && <div className="section">{item.section}</div>}
{item.page && <div className="page-number">{item.page}</div>}
</Show>
<Show visible={styleOnSettings && popOutIds?.includes(String(item.mediaTypeId))}>
<FaSquareUpRight
className={`new-tab ${!item.section && 'no-section'}`}
onClick={(e) => {
e.stopPropagation();
window.open(`/view/${item.id}`, '_blank');
}}
/>
</Show>
<Show
visible={
!!item.fileReferences.length &&
Expand All @@ -111,10 +135,6 @@ export const ContentList: React.FC<IContentListProps> = ({
}}
/>
</Show>
<Show visible={viewOptions.section}>
{item.section && <div className="section">{item.section}</div>}
{item.page && <div className="page-number">{item.page}</div>}
</Show>
</Row>
<Row>
{viewOptions.teaser && !!item.body && (
Expand Down
18 changes: 13 additions & 5 deletions app/subscriber/src/components/content-list/styled/ContentList.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import styled from 'styled-components';

export const ContentList = styled.div`
width: 100%;
.group-title {
border-bottom: 1px solid ${(props) => props.theme.css.border};
}
Expand Down Expand Up @@ -53,9 +52,6 @@ export const ContentList = styled.div`
justify-content: center;
font-size: 1.1rem;
}
.section {
margin-left: auto;
}
.section,
.page-number {
font-family: ${(props) => props.theme.css.fPrimary};
Expand All @@ -65,9 +61,20 @@ export const ContentList = styled.div`
margin-left: 0.25rem;
}
.new-tab {
height: 20px;
margin-left: 0.5rem;
width: 20px;
color: ${(props) => props.theme.css.btnBkPrimary};
&:hover {
cursor: pointer;
transform: scale(1.1);
}
}
.play-icon,
.eye-slash {
margin-left: auto;
margin-left: 0.5rem;
height: 20px;
width: 20px;
color: ${(props) => props.theme.css.btnBkPrimary};
Expand All @@ -89,6 +96,7 @@ export const ContentList = styled.div`
.headline {
background: none;
border: none;
margin-right: auto;
color: blue;
padding: 0;
cursor: pointer;
Expand Down
177 changes: 24 additions & 153 deletions app/subscriber/src/features/search-page/SearchPage.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,21 @@
import { MsearchMultisearchBody } from '@elastic/elasticsearch/lib/api/types';
import { BasicSearch } from 'components/basic-search';
import { ContentList } from 'components/content-list';
import { PageSection } from 'components/section';
import { Sentiment } from 'components/sentiment';
import { ContentListActionBar } from 'components/tool-bar';
import { useElastic } from 'features/my-searches/hooks';
import { IContentSearchResult } from 'features/utils/interfaces';
import React from 'react';
import { FaPlay, FaStop } from 'react-icons/fa';
import { FaBookmark } from 'react-icons/fa6';
import { useNavigate, useParams } from 'react-router-dom';
import { useParams } from 'react-router-dom';
import { toast } from 'react-toastify';
import { useContent, useFilters, useLookup } from 'store/hooks';
import { useProfileStore } from 'store/slices';
import {
Checkbox,
Col,
ContentTypeName,
IContentModel,
Loading,
Row,
Settings,
Show,
} from 'tno-core';
import { Col, IContentModel, Loading, Row, Show } from 'tno-core';

import { AdvancedSearch } from './components';
import { Player } from './player/Player';
import * as styled from './styled';
import { filterFormat, formatDate } from './utils';
import { filterFormat } from './utils';

export interface ISearchType {
showAdvanced?: boolean;
Expand All @@ -40,47 +30,18 @@ export const SearchPage: React.FC<ISearchType> = ({ showAdvanced }) => {
},
{ findContentWithElasticsearch, storeSearchFilter },
] = useContent();
const navigate = useNavigate();
const [{ frontPageImagesMediaTypeId, settings, isReady }] = useLookup();
const [{ frontPageImagesMediaTypeId }] = useLookup();
const genQuery = useElastic();
const [, { getFilter }] = useFilters();
const [{ filter: activeFilter }, { storeFilter }] = useProfileStore();

const [content, setContent] = React.useState<IContentModel[]>([]);
const [activeContent, setActiveContent] = React.useState<IContentModel | null>(null);
const [playerOpen, setPlayerOpen] = React.useState<boolean>(false);
const [content, setContent] = React.useState<IContentSearchResult[]>([]);
const [selected, setSelected] = React.useState<IContentModel[]>([]);
const [isLoading, setIsLoading] = React.useState(false);
const [showPage, setShowPage] = React.useState<string[]>([]);
const [showNewWindow, setShowNewWindow] = React.useState<string[]>([]);
const [hideSource, setHideSource] = React.useState<string[]>([]);
const [init, setInit] = React.useState(true); // React hooks are horrible...

const filterId = id ? parseInt(id) : 0;

React.useEffect(() => {
if (isReady) {
const showPageIds = settings.find(
(s) => s.name === Settings.SearchPageResultsShowPage,
)?.value;
if (showPageIds) {
setShowPage(showPageIds.split(','));
}
const showNewWindowIds = settings.find(
(s) => s.name === Settings.SearchPageResultsNewWindow,
)?.value;
if (showNewWindowIds) {
setShowNewWindow(showNewWindowIds.split(','));
}
const hideSourceIds = settings.find(
(s) => s.name === Settings.SearchPageResultsHideSource,
)?.value;
if (hideSourceIds) {
setHideSource(hideSourceIds.split(','));
}
}
}, [isReady, settings]);

React.useEffect(() => {
// Fetch the active filter if required.
if (filterId && init && activeFilter?.id !== filterId) {
Expand Down Expand Up @@ -114,6 +75,10 @@ export const SearchPage: React.FC<ISearchType> = ({ showAdvanced }) => {
[findContentWithElasticsearch],
);

const handleContentSelected = React.useCallback((content: IContentModel[]) => {
setSelected(content);
}, []);

React.useEffect(() => {
// Need to wait until front page images are in redux store before making a request.
if (frontPageImagesMediaTypeId) {
Expand Down Expand Up @@ -158,117 +123,23 @@ export const SearchPage: React.FC<ISearchType> = ({ showAdvanced }) => {
className="search"
/>
<Show visible={!!activeFilter}>
<div className="viewed-name padding-left">
<div className="viewed-name ">
<FaBookmark />
<div className="filter-name">{activeFilter?.name}</div>
</div>
</Show>
<Row className="search-contents">
<div className={playerOpen ? 'scroll minimized' : 'scroll'}>
<Col className={'search-items'}>
<Show visible={!content.length}>
<Row className="helper-text" justifyContent="center">
Please refine search criteria and click "search".
</Row>
</Show>

{content.map((item) => {
return (
<Row
key={item.id}
className="rows"
onClick={() => navigate(`/view/${item.id}`)}
>
<Col className="cols">
<Row>
<Col
className="checkBoxColumn"
alignItems="center"
onClick={(e) => e.stopPropagation()}
>
<Checkbox
onChange={(e) => {
if (e.target.checked) {
setSelected([...selected, item]);
} else {
setSelected(selected.filter((i) => i.id !== item.id));
}
}}
className="checkbox"
checked={selected.some((i) => i.id === item.id)}
/>
</Col>
<Col className="sentimentColumn">
<Sentiment
value={item.tonePools?.length ? item.tonePools[0].value : 0}
/>
</Col>
<Col className="dateColumn col-date">
<div className="date">{formatDate(item.publishedOn)}</div>
</Col>
<Col className="sourceColumn">
{item.contentType === ContentTypeName.AudioVideo &&
!hideSource.includes(`${item.mediaTypeId}`)
? item.series?.name
: item.source?.name}
</Col>
<Col className="headlineColumn">
<div className="headline">{item.headline}</div>
</Col>
{showPage.includes(`${item.mediaTypeId}`) && (
<Col className="linkColumn">{item.page}</Col>
)}
{showNewWindow.includes(`${item.mediaTypeId}`) && (
<Col className="linkColumn">
<div
className="new-window"
onClick={(e) => {
e.stopPropagation();
window.open(`/view/${item.id}`, '_blank');
}}
>
new window
</div>
</Col>
)}
<Show visible={!!item.fileReferences?.length}>
<Col className="mediaColumn">
<button
onClick={() => {
!playerOpen && setPlayerOpen(true);
item.fileReferences && setActiveContent(item);
}}
className={
playerOpen && activeContent?.id === item.id
? 'playing media-button'
: 'show media-button'
}
>
{playerOpen && activeContent?.id === item.id ? (
<Row>
<div>NOW PLAYING</div> <FaStop />
</Row>
) : (
<Row>
<div>PLAY MEDIA</div> <FaPlay />
</Row>
)}
</button>
</Col>
</Show>
</Row>
</Col>
</Row>
);
})}
</Col>
</div>
<Show visible={playerOpen}>
<Col className="player">
<Player setPlayerOpen={setPlayerOpen} content={activeContent} />
</Col>
</Show>
</Row>
<Show visible={!content.length}>
<Row className="helper-text" justifyContent="center">
Please refine search criteria and click "search".
</Row>
</Show>
<ContentList
onContentSelected={handleContentSelected}
content={content}
selected={selected}
showDate
styleOnSettings
/>
{isLoading && <Loading />}
</PageSection>
</Col>
Expand Down
Loading

0 comments on commit 298e3ce

Please sign in to comment.