Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[READY] Search Page - Add new list view #1498

Merged
merged 1 commit into from
Feb 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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(
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implemented new window, need to re implement show page, currently just shows page number if one exists

(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">
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All this covered in ContentList

<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
Loading