Skip to content

Commit

Permalink
feat: general sourceList component and GlobalContext
Browse files Browse the repository at this point in the history
  • Loading branch information
LucasMaupin committed Sep 12, 2024
1 parent dd7913f commit 1c7e743
Show file tree
Hide file tree
Showing 14 changed files with 248 additions and 182 deletions.
5 changes: 4 additions & 1 deletion src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Toaster } from 'react-hot-toast';
import DefaultLayout from '../components/layout/DefaultLayout';
import './globals.css';
import GlobalContextProvider from '../contexts/GlobalContext';

export default async function RootLayout({
children
Expand All @@ -21,7 +22,9 @@ export default async function RootLayout({
}
}}
/>
<DefaultLayout>{children}</DefaultLayout>
<GlobalContextProvider>
<DefaultLayout>{children}</DefaultLayout>
</GlobalContextProvider>
</body>
</html>
);
Expand Down
116 changes: 44 additions & 72 deletions src/app/production/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { removeSetupItem } from '../../../hooks/items/removeSetupItem';
import { addSetupItem } from '../../../hooks/items/addSetupItem';
import HeaderNavigation from '../../../components/headerNavigation/HeaderNavigation';
import styles from './page.module.scss';
import FilterProvider from '../../../components/inventory/FilterContext';
import FilterProvider from '../../../contexts/FilterContext';
import { useGetPresets } from '../../../hooks/presets';
import { Preset } from '../../../interfaces/preset';
import SourceCards from '../../../components/sourceCards/SourceCards';
Expand All @@ -42,6 +42,7 @@ import { MonitoringButton } from '../../../components/button/MonitoringButton';
import { useGetMultiviewPreset } from '../../../hooks/multiviewPreset';
import { ISource } from '../../../hooks/useDragableItems';
import { useMultiviews } from '../../../hooks/multiviews';
import SourceList from '../../../components/sourceList/SourceList';

export default function ProductionConfiguration({ params }: PageProps) {
const t = useTranslate();
Expand Down Expand Up @@ -362,42 +363,32 @@ export default function ProductionConfiguration({ params }: PageProps) {
</li>
);
}
function getSourcesToDisplay(
filteredSources: Map<string, SourceWithId>
): React.ReactNode[] {
return Array.from(filteredSources.values()).map((source, index) => {
return (
<SourceListItem
key={`${source.ingest_source_name}-${index}`}
source={source}
disabled={selectedProductionItems?.includes(source._id.toString())}
action={(source: SourceWithId) => {
if (productionSetup && productionSetup.isActive) {
setSelectedSource(source);
setAddSourceModal(true);
} else if (productionSetup) {
const updatedSetup = addSetupItem(
{
_id: source._id.toString(),
label: source.ingest_source_name,
input_slot: getFirstEmptySlot()
},
productionSetup
);
if (!updatedSetup) return;
setProductionSetup(updatedSetup);
putProduction(updatedSetup._id.toString(), updatedSetup).then(
() => {
setAddSourceModal(false);
setSelectedSource(undefined);
}
);
}
}}
/>

const addSourceAction = (source: SourceWithId) => {
if (productionSetup && productionSetup.isActive) {
setSelectedSource(source);
setAddSourceModal(true);
} else if (productionSetup) {
const updatedSetup = addSetupItem(
{
_id: source._id.toString(),
label: source.ingest_source_name,
input_slot: getFirstEmptySlot()
},
productionSetup
);
});
}
if (!updatedSetup) return;
setProductionSetup(updatedSetup);
putProduction(updatedSetup._id.toString(), updatedSetup).then(() => {
setAddSourceModal(false);
setSelectedSource(undefined);
});
}
};

const isDisabledFunction = (source: SourceWithId): boolean => {
return selectedProductionItems?.includes(source._id.toString());
};

const getFirstEmptySlot = () => {
if (!productionSetup) throw 'no_production';
Expand Down Expand Up @@ -655,42 +646,23 @@ export default function ProductionConfiguration({ params }: PageProps) {
inventoryVisible ? 'min-w-[35%] ml-2 mt-2 max-h-[89vh]' : ''
}`}
>
<div className={`p-3 w-full bg-container rounded break-all h-full`}>
<div className="flex justify-end mb-2">
<button className="flex justify-end mb-2">
<IconX
className="w-5 h-5 text-brand"
onClick={() => setInventoryVisible(false)}
/>
</button>
</div>
<div className="mb-1">
<FilterProvider sources={sources}>
<FilterOptions
onFilteredSources={(filtered: Map<string, SourceWithId>) => {
setFilteredSources(new Map<string, SourceWithId>(filtered));
}}
/>
</FilterProvider>
</div>
<ul
className={`flex flex-col border-t border-gray-600 overflow-scroll h-full ${
!inventoryVisible && 'hidden'
} ${styles.no_scrollbar}`}
>
{getSourcesToDisplay(filteredSources)}
{addSourceModal && selectedSource && (
<AddSourceModal
name={selectedSource.name}
open={addSourceModal}
onAbort={handleAbortAddSource}
onConfirm={handleAddSource}
status={addSourceStatus}
loading={loadingCreateStream}
/>
)}
</ul>
</div>
<SourceList
sources={sources}
action={addSourceAction}
actionText={t('inventory_list.add')}
onClose={() => setInventoryVisible(false)}
isDisabledFunc={isDisabledFunction}
/>
{addSourceModal && selectedSource && (
<AddSourceModal
name={selectedSource.name}
open={addSourceModal}
onAbort={handleAbortAddSource}
onConfirm={handleAddSource}
status={addSourceStatus}
loading={loadingCreateStream}
/>
)}
</div>
<div className="flex flex-col h-fit w-full">
<div
Expand Down
2 changes: 1 addition & 1 deletion src/components/filter/FilterOptions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import SearchBar from './SearchBar';
import FilterDropdown from './FilterDropdown';
import { ClickAwayListener } from '@mui/base';
import { SourceWithId } from '../../interfaces/Source';
import { FilterContext } from '../inventory/FilterContext';
import { FilterContext } from '../../contexts/FilterContext';

type FilterOptionsProps = {
onFilteredSources: (sources: Map<string, SourceWithId>) => void;
Expand Down
20 changes: 18 additions & 2 deletions src/components/headerNavigation/HeaderNavigation.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,37 @@
'use client';

import Link from 'next/link';
import { useTranslate } from '../../i18n/useTranslate';
import { useContext } from 'react';
import { GlobalContext } from '../../contexts/GlobalContext';
import { IconRefresh } from '@tabler/icons-react';

export default function HeaderNavigation({
children
}: {
children: React.ReactNode;
}) {
const t = useTranslate();
const { incrementImageRefetchIndex } = useContext(GlobalContext);
return (
<div className="flex flex-row justify-between ">
<div className="m-2 rounded">
<div className="flex flex-row justify-between">
<div className="flex m-2 rounded align-center">
<Link
className="bg-button-bg hover:bg-button-hover-bg text-button-text font-bold py-2 px-4 rounded inline-flex items-center"
href={'/'}
>
<span>{t('homepage')}</span>
</Link>
<button
className="bg-button-bg hover:bg-button-hover-bg text-button-text font-bold py-2 px-4 rounded inline-flex items-center ml-2"
onClick={incrementImageRefetchIndex}
>
<IconRefresh
className="text-white mr-1"
onClick={incrementImageRefetchIndex}
/>
Refresh Images
</button>
</div>
{children}
</div>
Expand Down
21 changes: 11 additions & 10 deletions src/components/image/ImageComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import {
useState
} from 'react';
import Image from 'next/image';
import { FilterContext } from '../inventory/FilterContext';
import { IconExclamationCircle } from '@tabler/icons-react';
import { Loader } from '../loader/Loader';
import { GlobalContext } from '../../contexts/GlobalContext';

interface ImageComponentProps extends PropsWithChildren {
src: string;
Expand All @@ -18,28 +18,29 @@ interface ImageComponentProps extends PropsWithChildren {

const ImageComponent: React.FC<ImageComponentProps> = (props) => {
const { src, alt = 'Image', children } = props;
const { refetchIndex } = useContext(FilterContext);
const { imageRefetchIndex } = useContext(GlobalContext);
const [imgSrc, setImgSrc] = useState<string>();
const [loaded, setLoaded] = useState<boolean>(false);
const [loading, setLoading] = useState<boolean>(false);
const [error, setError] = useState<SyntheticEvent<HTMLImageElement, Event>>();
const timeout = useRef<ReturnType<typeof setTimeout>>();

const refetchImage = () => {
setImgSrc(`${src}?refetch=${refetchIndex}}`);
setImgSrc(`${src}?refetch=${imageRefetchIndex}}`);
setError(undefined);
setLoading(true);
clearTimeout(timeout.current);
timeout.current = setTimeout(() => setLoading(false), 500);
};

useEffect(() => {
refetchImage();
}, [src]);
}, [imageRefetchIndex]);

useEffect(() => {
refetchImage();
setError(undefined);
setLoading(true);
clearTimeout(timeout.current);
timeout.current = setTimeout(() => setLoading(false), 500);
}, [refetchIndex]);
setImgSrc(`${src}?refetch=${imageRefetchIndex}}`);
}, [src]);

useEffect(() => {
return () => {
Expand All @@ -48,7 +49,7 @@ const ImageComponent: React.FC<ImageComponentProps> = (props) => {
}, []);

return (
<div className="relative z-50 aspect-video min-w-full overflow-hidden border rounded-lg bg-zinc-700">
<div className="relative z-10 aspect-video min-w-full overflow-hidden border rounded-lg bg-zinc-700">
{((!imgSrc || error) && (
<IconExclamationCircle className="text-error fill-white w-full h-full" />
)) || (
Expand Down
95 changes: 19 additions & 76 deletions src/components/inventory/Inventory.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,18 @@

import { useEffect, useState } from 'react';
import { useSources } from '../../hooks/sources/useSources';
import FilterOptions from '../../components/filter/FilterOptions';
import SourceListItem from '../../components/sourceListItem/SourceListItem';
import { SourceWithId } from '../../interfaces/Source';
import EditView from './editView/EditView';
import FilterContext from './FilterContext';
import styles from './Inventory.module.scss';
import { IconRefresh } from '@tabler/icons-react';
import SourceList from '../sourceList/SourceList';
import { useTranslate } from '../../i18n/useTranslate';

export default function Inventory() {
const [updatedSource, setUpdatedSource] = useState<
SourceWithId | undefined
>();
const [sources] = useSources(updatedSource);
const [currentSource, setCurrentSource] = useState<SourceWithId | null>();
const [filteredSources, setFilteredSources] =
useState<Map<string, SourceWithId>>(sources);
const [refetchIndex, setRefetchIndex] = useState<number>(0);
const inventoryVisible = true;
const t = useTranslate();

useEffect(() => {
if (updatedSource && typeof updatedSource !== 'boolean') {
Expand All @@ -28,76 +22,25 @@ export default function Inventory() {
}, [updatedSource]);

const editSource = (source: SourceWithId) => {
setCurrentSource(() => source);
};

function getSourcesToDisplay(
filteredSources: Map<string, SourceWithId>
): React.ReactNode {
return Array.from(
filteredSources.size > 0 ? filteredSources.values() : sources.values()
).map((source, index) => {
return (
<SourceListItem
edit
key={`${source.ingest_source_name}-${index}`}
source={source}
disabled={false}
action={(source) => {
editSource(source);
}}
/>
);
});
}

const refetchImages = () => {
setRefetchIndex(refetchIndex + 1);
setCurrentSource(source);
};

return (
<FilterContext sources={sources} refetchIndex={refetchIndex}>
<div className="flex max-h-full min-h-[100%] flex-row">
<div
className={
inventoryVisible
? `${
styles.no_scrollbar
} min-w-fit overflow-hidden max-w-2xl transition-[width] ml-2 mt-2 max-h-[89vh]
${currentSource ? 'w-[30%]' : 'w-[50%]'}`
: 'hidden'
}
>
<div className="p-3 bg-container rounded break-all h-full">
<div className="flex justify-between mb-1">
<FilterOptions
onFilteredSources={(filtered: Map<string, SourceWithId>) =>
setFilteredSources(new Map<string, SourceWithId>(filtered))
}
/>
<IconRefresh
className="ml-2 text-white w-auto h-10 w-10 hover:cursor-pointer"
onClick={refetchImages}
/>
</div>
<ul
className={`flex flex-col border-t border-gray-600 overflow-scroll h-full ${styles.no_scrollbar}`}
>
{getSourcesToDisplay(filteredSources)}
</ul>
</div>
<div className="flex ">
<SourceList
sources={sources}
action={editSource}
actionText={t('inventory_list.edit')}
/>
{currentSource ? (
<div className={`p-3 ml-2 mt-2 bg-container rounded h-1/2 min-w-max`}>
<EditView
source={currentSource}
updateSource={(source) => setUpdatedSource(source)}
close={() => setCurrentSource(null)}
/>
</div>

{currentSource ? (
<div className={`p-3 ml-2 mt-2 bg-container rounded h-1/2 min-w-max`}>
<EditView
source={currentSource}
updateSource={(source) => setUpdatedSource(source)}
close={() => setCurrentSource(null)}
/>
</div>
) : null}
</div>
</FilterContext>
) : null}
</div>
);
}
2 changes: 1 addition & 1 deletion src/components/inventory/editView/GeneralSettings.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useContext } from 'react';
import { EditViewContext, IInput } from '../EditViewContext';
import { FilterContext } from '../FilterContext';
import { FilterContext } from '../../../contexts/FilterContext';
import { useTranslate } from '../../../i18n/useTranslate';
import SelectOptions from './SelectOptions';
import { getHertz } from '../../../utils/stream';
Expand Down
Loading

0 comments on commit 1c7e743

Please sign in to comment.