Files
tubearchivist/frontend/src/pages/Search.tsx
Merlin 83bb7f678b DRAFT: Add Tubearchivist Frontend React dev docker setup (#768)
* Add development docker-compose file

* Add /new/ path in nginx conf

* Add frontend production setup

* Fix lint

* Refac move prod docker compose into non suffixed file

* Fix run.sh fileendings on windows

* Fix docker file naming consistancies

* Add frontend dev setup

* Add docker compose dev command

* Refac remove docker network

* Fix potential error causes

* Chore update react-router-dom

* Add redirect to login after logout

* Refac allow basic auth for session login in api

* Fix loginresponsetype optional property

* Refac move isAdmin check into page Base

* Refac use node lts for dev container

* Refac remove old setup in readme

* Refac move getisAdmin into loader and rename

* Refac remove manual csrf cookie handing from actions and loader

* Fix post requiring csrf header & cookie

* Fix remove empty files

* Refac revert dockerfile changes

* Refac revert gitatrributes changes

* Refac revert docker changes

* Refac revert nginx changes

* Refac revert docker change

* Refac move frontend into frontend folder

* Add production steps to dockerfile

* Refac implement endpoint renaming

* Refac remove frontend dockerfile

* Add credentials include for dev env

* Fix allow cors with credentials for dev environment

* Fix images in dev mode

* Add credentials for dev mode to all loader and actions, except signin

* Revert cors config

* Revert cors config

* Fix nginx not serving /youtube/

* Fix video url missing api

* Fix media url missing api

* Add application settings page

* Add continue vids

* Add csrf to delete requests

* Refac use api/video endpoint with filter to home, channel, playlist pages

* Add channel nav request

* Add channel playlists

* Fix filterbar for playlist in channel

* Add playlist_nav to video page

* Add downloads aggs

* Refac remove basic auth

* Fix credentials include in signin

* Refac user config to user me config

* Add ApiToken get
2024-08-11 00:53:50 +07:00

171 lines
5.6 KiB
TypeScript

import { useLoaderData, useSearchParams } from 'react-router-dom';
import { UserMeType } from '../api/actions/updateUserConfig';
import { useEffect, useState } from 'react';
import { VideoType, ViewLayoutType } from './Home';
import loadSearch from '../api/loader/loadSearch';
import { PlaylistType } from './Playlist';
import { ChannelType } from './Channels';
import VideoList from '../components/VideoList';
import ChannelList from '../components/ChannelList';
import PlaylistList from '../components/PlaylistList';
import SubtitleList from '../components/SubtitleList';
import { ViewStyles } from '../configuration/constants/ViewStyle';
import EmbeddableVideoPlayer from '../components/EmbeddableVideoPlayer';
import { Helmet } from 'react-helmet';
import SearchExampleQueries from '../components/SearchExampleQueries';
const EmptySearchResponse: SearchResultsType = {
results: {
video_results: [],
channel_results: [],
playlist_results: [],
fulltext_results: [],
},
queryType: 'simple',
};
type SearchResultType = {
video_results: VideoType[];
channel_results: ChannelType[];
playlist_results: PlaylistType[];
fulltext_results: [];
};
type SearchResultsType = {
results: SearchResultType;
queryType: string;
};
type SearchLoaderDataType = {
userConfig: UserMeType;
};
const Search = () => {
const { userConfig } = useLoaderData() as SearchLoaderDataType;
const [searchParams] = useSearchParams();
const videoId = searchParams.get('videoId');
const userMeConfig = userConfig.config;
const view = (userMeConfig.view_style_home || ViewStyles.grid) as ViewLayoutType;
const gridItems = userMeConfig.grid_items || 3;
const [searchQuery, setSearchQuery] = useState('');
const [searchResults, setSearchResults] = useState<SearchResultsType>();
const [refresh, setRefresh] = useState(false);
const videoList = searchResults?.results.video_results;
const channelList = searchResults?.results.channel_results;
const playlistList = searchResults?.results.playlist_results;
const fulltextList = searchResults?.results.fulltext_results;
const queryType = searchResults?.queryType;
const showEmbeddedVideo = videoId !== null;
const hasSearchQuery = searchQuery.length > 0;
const hasVideos = Number(videoList?.length) > 0;
const hasChannels = Number(channelList?.length) > 0;
const hasPlaylist = Number(playlistList?.length) > 0;
const hasFulltext = Number(fulltextList?.length) > 0;
const isSimpleQuery = queryType === 'simple';
const isVideoQuery = queryType === 'video' || isSimpleQuery;
const isChannelQuery = queryType === 'channel' || isSimpleQuery;
const isPlaylistQuery = queryType === 'playlist' || isSimpleQuery;
const isFullTextQuery = queryType === 'full' || isSimpleQuery;
const isGridView = view === ViewStyles.grid;
const gridView = isGridView ? `boxed-${gridItems}` : '';
const gridViewGrid = isGridView ? `grid-${gridItems}` : '';
useEffect(() => {
(async () => {
if (!hasSearchQuery) {
setSearchResults(EmptySearchResponse);
return;
}
const searchResults = await loadSearch(searchQuery);
setSearchResults(searchResults);
setRefresh(false);
})();
}, [searchQuery, refresh, hasSearchQuery]);
return (
<>
<Helmet>
<title>TubeArchivist</title>
</Helmet>
{showEmbeddedVideo && <EmbeddableVideoPlayer videoId={videoId} />}
<div className={`boxed-content ${gridView}`}>
<div className="title-bar">
<h1>Search your Archive</h1>
</div>
<div className="multi-search-box">
<div>
<input
type="text"
name="searchInput"
autoComplete="off"
value={searchQuery}
onChange={event => {
setSearchQuery(event.target.value);
}}
/>
</div>
</div>
<div id="multi-search-results">
{hasSearchQuery && isVideoQuery && (
<div className="multi-search-result">
<h2>Video Results</h2>
<div id="video-results" className={`video-list ${view} ${gridViewGrid}`}>
<VideoList videoList={videoList} viewLayout={view} refreshVideoList={setRefresh} />
</div>
</div>
)}
{hasSearchQuery && isChannelQuery && (
<div className="multi-search-result">
<h2>Channel Results</h2>
<div id="channel-results" className={`channel-list ${view} ${gridViewGrid}`}>
<ChannelList
channelList={channelList}
viewLayout={view}
refreshChannelList={setRefresh}
/>
</div>
</div>
)}
{hasSearchQuery && isPlaylistQuery && (
<div className="multi-search-result">
<h2>Playlist Results</h2>
<div id="playlist-results" className={`playlist-list ${view} ${gridViewGrid}`}>
<PlaylistList
playlistList={playlistList}
viewLayout={view}
setRefresh={setRefresh}
/>
</div>
</div>
)}
{hasSearchQuery && isFullTextQuery && (
<div className="multi-search-result">
<h2>Fulltext Results</h2>
<div id="fulltext-results" className="video-list list">
<SubtitleList subtitleList={fulltextList} />
</div>
</div>
)}
</div>
{!hasVideos && !hasChannels && !hasPlaylist && !hasFulltext && <SearchExampleQueries />}
</div>
</>
);
};
export default Search;