Skip to content
Draft
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
10 changes: 5 additions & 5 deletions apps/client/src/common/context/EntryActionsContext.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { PropsWithChildren, createContext, useContext } from 'react';

import { useEntryActions } from '../hooks/useEntryAction';
import { useEntryActions, useScopedEntryActions } from '../hooks/useEntryAction';
import { useRundownSelectionContext } from './RundownSelectionContext';

type EntryActionsContextValue = ReturnType<typeof useEntryActions>;
const EntryActionsContext = createContext<EntryActionsContextValue | null>(null);

interface EntryActionsProviderProps extends PropsWithChildren {
actions: EntryActionsContextValue;
}
export function EntryActionsProvider({ children }: PropsWithChildren) {
const { effectiveRundownId } = useRundownSelectionContext();
const actions = useScopedEntryActions(effectiveRundownId);

export function EntryActionsProvider({ children, actions }: EntryActionsProviderProps) {
return <EntryActionsContext.Provider value={actions}>{children}</EntryActionsContext.Provider>;
}

Expand Down
72 changes: 72 additions & 0 deletions apps/client/src/common/context/RundownSelectionContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { Maybe, ProjectRundown } from 'ontime-types';
import {
PropsWithChildren,
createContext,
startTransition,
useCallback,
useContext,
useEffect,
useMemo,
useState,
} from 'react';

import { useProjectRundowns } from '../hooks-query/useProjectRundowns';

export type RundownScopeValue = {
loadedRundownId: string;
selectedRundownId: Maybe<string>;
isLoadedRundown: boolean;
effectiveRundownId: string;
selectRundownId: (val: Maybe<string>) => void;
rundowns: ProjectRundown[];
};

const RundownScopeContext = createContext<RundownScopeValue | null>(null);

export function RundownSelectionContextProvider({ children }: PropsWithChildren) {
'use memo';
const { data } = useProjectRundowns();
const { loaded, rundowns } = data;
const [selectedRundownId, setSelectedRundownId] = useState<Maybe<string>>(null);

const selectRundownId = useCallback(
(rundownId: Maybe<string>) => {
startTransition(() => {
if (rundowns.find((entry) => entry.id === rundownId)) setSelectedRundownId(rundownId);
else setSelectedRundownId(null);
});
},
[rundowns],
);

const effectiveRundownId = selectedRundownId ? selectedRundownId : loaded;
const isLoadedRundown = effectiveRundownId === loaded;

useEffect(() => {
if (!rundowns.find((entry) => entry.id === effectiveRundownId)) setSelectedRundownId(null);
}, [rundowns, effectiveRundownId]);

const value = useMemo(
(): RundownScopeValue => ({
loadedRundownId: loaded,
isLoadedRundown,
selectedRundownId,
effectiveRundownId,
selectRundownId,
rundowns,
}),
[loaded, isLoadedRundown, selectedRundownId, effectiveRundownId, selectRundownId, rundowns],
);

return <RundownScopeContext.Provider value={value}>{children}</RundownScopeContext.Provider>;
}

export function useRundownSelectionContext() {
const context = useContext(RundownScopeContext);

if (!context) {
throw new Error('useRundownScopeSelection requires a RundownSelectionContextProvider');
}

return context;
}
64 changes: 64 additions & 0 deletions apps/client/src/common/hooks-query/useContextRundown.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { useMemo } from 'react';

import { useRundownSelectionContext } from '../context/RundownSelectionContext';
import { useSelectedEventId } from '../hooks/useSocket';
import { getFlatRundownMetadata, getRundownMetadata } from '../utils/rundownMetadata';
import { useRundown } from './useRundown';

export function useContextRundownEditModal() {
'use memo';
const { effectiveRundownId } = useRundownSelectionContext();
const { data: rundown } = useRundown(effectiveRundownId);
return { rundown };
}

export function useContextRundownCueRenumberModal() {
'use memo';
const { effectiveRundownId } = useRundownSelectionContext();
const { data } = useRundown(effectiveRundownId);
const { flatOrder } = data;
return { flatOrder };
}

export function useContextRundownList() {
'use memo';
const { effectiveRundownId, isLoadedRundown } = useRundownSelectionContext();
const loadedEventId = useSelectedEventId();
const effectiveSelectedEventId = isLoadedRundown ? loadedEventId : null;
const { data: rundown, status } = useRundown(effectiveRundownId);
const rundownMetadata = useMemo(
() => getRundownMetadata(rundown, effectiveSelectedEventId),
[effectiveSelectedEventId, rundown],
);

return useMemo(
() => ({
rundown,
rundownMetadata,
status,
isLoadedRundown,
}),
[rundown, rundownMetadata, status, isLoadedRundown],
);
}

export function useContextRundownTable() {
'use memo';
const { effectiveRundownId, isLoadedRundown } = useRundownSelectionContext();
const loadedEventId = useSelectedEventId();
const effectiveSelectedEventId = isLoadedRundown ? loadedEventId : null;
const { data: rundown, status } = useRundown(effectiveRundownId);
const flatRundown = useMemo(
() => getFlatRundownMetadata(rundown, effectiveSelectedEventId),
[effectiveSelectedEventId, rundown],
);

return useMemo(
() => ({
flatRundown,
status,
loadedEventId,
}),
[flatRundown, status, loadedEventId],
);
}
107 changes: 47 additions & 60 deletions apps/client/src/common/hooks-query/useRundown.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { useQuery, useQueryClient } from '@tanstack/react-query';
import { EntryId, OntimeEntry, Rundown } from 'ontime-types';
import { useEffect, useMemo } from 'react';
import { useQuery } from '@tanstack/react-query';
import { EntryId, Maybe, OntimeEntry, Rundown } from 'ontime-types';
import { useMemo } from 'react';

import { queryRefetchIntervalSlow } from '../../ontimeConfig';
import { CURRENT_RUNDOWN_QUERY_KEY, getRundownQueryKey } from '../api/constants';
import { fetchCurrentRundown, fetchRundown } from '../api/rundown';
import { getRundownQueryKey } from '../api/constants';
import { fetchRundown } from '../api/rundown';
import { useSelectedEventId } from '../hooks/useSocket';
import { ExtendedEntry, getFlatRundownMetadata, getRundownMetadata } from '../utils/rundownMetadata';
import { useProjectRundowns } from './useProjectRundowns';
Expand All @@ -20,52 +20,49 @@ const cachedRundownPlaceholder: Rundown = {
};

/**
* Normalised rundown data for the currently loaded rundown.
*
* Bootstraps via the `/current` alias so the first paint is a single round-trip,
* independent of the project rundown list. Once the loaded id is known, the
* query key swaps to the id-keyed cache that is shared with `useRundownById`.
* Provides access to a specific rundown by ID.
* When rundownId is not provided the loaded rundown is provided
*/
export default function useRundown() {
const queryClient = useQueryClient();
export function useRundown(rundownId: Maybe<string>) {
'use memo';

const {
data: { loaded: loadedRundownId },
} = useProjectRundowns();

const effectiveRundownId = rundownId ? rundownId : loadedRundownId;
const isLoadedRundown = rundownId === loadedRundownId;

const { data, status, isError, refetch, isFetching } = useQuery<Rundown>({
queryKey: loadedRundownId ? getRundownQueryKey(loadedRundownId) : CURRENT_RUNDOWN_QUERY_KEY,
queryFn: ({ signal }) => fetchCurrentRundown({ signal }),
queryKey: getRundownQueryKey(effectiveRundownId),
queryFn: ({ signal }) => fetchRundown(effectiveRundownId, { signal }),
placeholderData: (previousData, _previousQuery) => previousData,
refetchInterval: queryRefetchIntervalSlow,
});

// Seed the id-keyed cache when fetching via the bootstrap alias
useEffect(() => {
if (!data || loadedRundownId) return;
queryClient.setQueryData(getRundownQueryKey(data.id), data);
}, [data, loadedRundownId, queryClient]);

// Once we have the ID, drop the temporary current cache
useEffect(() => {
if (!loadedRundownId) return;
queryClient.removeQueries({ queryKey: CURRENT_RUNDOWN_QUERY_KEY, exact: true });
}, [loadedRundownId, queryClient]);

return { data: data ?? cachedRundownPlaceholder, status, isError, refetch, isFetching };
return { data: data ?? cachedRundownPlaceholder, status, isError, refetch, isFetching, isLoadedRundown };
}

export function useRundownWithMetadata() {
const { data, status } = useRundown();
/**
* @deprecated
*/
export function useRundownWithMetadata(rundownId: Maybe<string>) {
'use memo';

const { data, status, isLoadedRundown } = useRundown(rundownId);
const selectedEventId = useSelectedEventId();
const rundownMetadata = useMemo(() => getRundownMetadata(data, selectedEventId), [data, selectedEventId]);
const effectiveSelectedEventId = isLoadedRundown ? selectedEventId : null;
const rundownMetadata = getRundownMetadata(data, effectiveSelectedEventId);
return { data, status, rundownMetadata };
}

/**
* Provides access to a flat rundown
* built from the order and rundown fields
* @deprecated
*/
export function useFlatRundown() {
const { data, status } = useRundown();
export function useFlatRundown(rundownId: Maybe<string>) {
const { data, status } = useRundown(rundownId);

const flatRundown = useMemo(() => {
if (data.revision === -1) {
Expand All @@ -77,11 +74,13 @@ export function useFlatRundown() {
return { data: flatRundown, rundownId: data.id, status };
}

export function useFlatRundownWithMetadata() {
const { data, status } = useRundown();
const selectedEventId = useSelectedEventId();
export function useFlatRundownWithMetadata(rundownId: Maybe<string>) {
'use memo';

const rundownWithMetadata = useMemo(() => getFlatRundownMetadata(data, selectedEventId), [data, selectedEventId]);
const { data, status, isLoadedRundown } = useRundown(rundownId);
const selectedEventId = useSelectedEventId();
const effectiveSelectedEventId = isLoadedRundown ? selectedEventId : null;
const rundownWithMetadata = getFlatRundownMetadata(data, effectiveSelectedEventId);
return { data: rundownWithMetadata, status };
}

Expand All @@ -91,9 +90,10 @@ export function useFlatRundownWithMetadata() {
* Callers MUST memoize the callback with useCallback to prevent
* re-filtering on every render.
*
* @deprecated
*/
export function usePartialRundown(cb: (event: ExtendedEntry<OntimeEntry>) => boolean) {
const { data, status } = useFlatRundownWithMetadata();
export function usePartialRundown(rundownId: Maybe<string>, cb: (event: ExtendedEntry<OntimeEntry>) => boolean) {
const { data, status } = useFlatRundownWithMetadata(rundownId);
const filteredData = useMemo(() => {
return data.filter(cb);
}, [data, cb]);
Expand All @@ -103,37 +103,24 @@ export function usePartialRundown(cb: (event: ExtendedEntry<OntimeEntry>) => boo

/**
* Hook to get a specific entry by ID from the rundown
* @deprecated
*/
export function useEntry(entryId: EntryId | null): OntimeEntry | null {
const { data: rundown } = useRundown();
export function useEntry(rundownId: Maybe<string>, entryId: EntryId | null): OntimeEntry | null {
const { data: rundown } = useRundown(rundownId);

if (entryId === null) return null;
return rundown.entries[entryId] ?? null;
}

export function useRundownAuxData() {
const { data, status } = useRundown();
/**
*
* @deprecated
*/
export function useRundownAuxData(rundownId: Maybe<string>) {
const { data, status } = useRundown(rundownId);
const filteredData = useMemo(() => {
const { title, id } = data;
return { title, id };
}, [data]);
return { data: filteredData, status };
}

/**
* Provides access to a specific rundown by ID.
* When rundownId is null/undefined the query is disabled and returns the placeholder.
*/
export function useRundownById(rundownId: string | null | undefined) {
const enabled = Boolean(rundownId);

const { data, status, isError, refetch, isFetching } = useQuery<Rundown>({
queryKey: getRundownQueryKey(rundownId ?? ''),
queryFn: ({ signal }) => fetchRundown(rundownId!, { signal }),
enabled,
placeholderData: (previousData, _previousQuery) => previousData,
refetchInterval: queryRefetchIntervalSlow,
});

return { data: data ?? cachedRundownPlaceholder, status, isError, refetch, isFetching };
}
54 changes: 0 additions & 54 deletions apps/client/src/common/hooks-query/useScopedRundown.ts

This file was deleted.

Loading
Loading