69
common/resources/client/channels/requests/use-channel-content.ts
Executable file
69
common/resources/client/channels/requests/use-channel-content.ts
Executable file
@@ -0,0 +1,69 @@
|
||||
import {hashKey, keepPreviousData, useQuery} from '@tanstack/react-query';
|
||||
import {apiClient} from '@common/http/query-client';
|
||||
import {Channel, ChannelContentItem} from '@common/channels/channel';
|
||||
import {
|
||||
channelEndpoint,
|
||||
channelQueryKey,
|
||||
} from '@common/channels/requests/use-channel';
|
||||
import {PaginatedBackendResponse} from '@common/http/backend-response/pagination-response';
|
||||
import {useRef} from 'react';
|
||||
import {useChannelQueryParams} from '@common/channels/use-channel-query-params';
|
||||
import {useSearchParams} from 'react-router-dom';
|
||||
|
||||
interface Response<T extends ChannelContentItem = ChannelContentItem>
|
||||
extends PaginatedBackendResponse<T> {}
|
||||
|
||||
interface Options {
|
||||
paginate?: boolean;
|
||||
}
|
||||
|
||||
export function useChannelContent<
|
||||
T extends ChannelContentItem = ChannelContentItem,
|
||||
>(
|
||||
channel: Channel<T>,
|
||||
params?: Record<string, string> | null,
|
||||
options?: Options,
|
||||
) {
|
||||
const [searchParams] = useSearchParams();
|
||||
const queryParams = useChannelQueryParams(channel, params);
|
||||
if (options?.paginate) {
|
||||
queryParams.page = searchParams.get('page') || '1';
|
||||
}
|
||||
const queryKey = channelQueryKey(channel.id, queryParams);
|
||||
const initialQueryKey = useRef(hashKey(queryKey)).current;
|
||||
|
||||
const query = useQuery({
|
||||
queryKey: channelQueryKey(channel.id, queryParams),
|
||||
queryFn: () => fetchChannelContent<T>(channel, queryParams),
|
||||
placeholderData: keepPreviousData,
|
||||
initialData: () => {
|
||||
if (hashKey(queryKey) === initialQueryKey) {
|
||||
return channel.content;
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
...query,
|
||||
queryKey,
|
||||
};
|
||||
}
|
||||
|
||||
function fetchChannelContent<T extends ChannelContentItem = ChannelContentItem>(
|
||||
channel: Channel<T>,
|
||||
params: any,
|
||||
) {
|
||||
return apiClient
|
||||
.get<Response<T>>(channelEndpoint(channel.id), {
|
||||
params: {
|
||||
...params,
|
||||
paginate:
|
||||
channel.config.paginationType === 'lengthAware'
|
||||
? 'lengthAware'
|
||||
: 'simple',
|
||||
returnContentOnly: 'true',
|
||||
},
|
||||
})
|
||||
.then(response => response.data.pagination);
|
||||
}
|
||||
68
common/resources/client/channels/requests/use-channel.ts
Executable file
68
common/resources/client/channels/requests/use-channel.ts
Executable file
@@ -0,0 +1,68 @@
|
||||
import {useQuery} from '@tanstack/react-query';
|
||||
import {apiClient} from '@common/http/query-client';
|
||||
import {BackendResponse} from '@common/http/backend-response/backend-response';
|
||||
import {useParams} from 'react-router-dom';
|
||||
import {Channel} from '@common/channels/channel';
|
||||
import {useChannelQueryParams} from '@common/channels/use-channel-query-params';
|
||||
import {isSsr} from '@common/utils/dom/is-ssr';
|
||||
import {getBootstrapData} from '@common/core/bootstrap-data/use-backend-bootstrap-data';
|
||||
|
||||
export interface GetChannelResponse extends BackendResponse {
|
||||
channel: Channel;
|
||||
}
|
||||
|
||||
export function useChannel(
|
||||
slugOrId: string | number | undefined,
|
||||
loader: 'channelPage' | 'editChannelPage' | 'editUserListPage',
|
||||
userParams?: Record<string, string | null>,
|
||||
) {
|
||||
const params = useParams();
|
||||
const channelId = slugOrId || params.slugOrId!;
|
||||
const queryParams = useChannelQueryParams(undefined, userParams);
|
||||
return useQuery({
|
||||
// only refetch when channel ID or restriction changes and not query params.
|
||||
// content will be re-fetched in channel content components
|
||||
// on SSR use query params as well, to avoid caching wrong data when query params change
|
||||
queryKey: isSsr()
|
||||
? channelQueryKey(channelId, queryParams)
|
||||
: channelQueryKey(channelId, {restriction: queryParams.restriction}),
|
||||
|
||||
queryFn: () => fetchChannel(channelId, {...queryParams, loader}),
|
||||
initialData: () => {
|
||||
// @ts-ignore
|
||||
const data = getBootstrapData().loaders?.[loader];
|
||||
const isSameChannel =
|
||||
data?.channel.id == channelId || data?.channel.slug == channelId;
|
||||
const isSameRestriction =
|
||||
!queryParams.restriction ||
|
||||
data?.channel.restriction?.name === queryParams.restriction;
|
||||
if (isSameChannel && isSameRestriction) {
|
||||
return data;
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function channelQueryKey(
|
||||
slugOrId: number | string,
|
||||
params?: Record<string, string | number | null>,
|
||||
) {
|
||||
const key: any[] = ['channel', `${slugOrId}`];
|
||||
if (params) {
|
||||
key.push(params);
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
export function channelEndpoint(slugOrId: number | string) {
|
||||
return `channel/${slugOrId}`;
|
||||
}
|
||||
|
||||
function fetchChannel(
|
||||
slugOrId: number | string,
|
||||
params: Record<string, string | number | undefined | null> = {},
|
||||
): Promise<GetChannelResponse> {
|
||||
return apiClient
|
||||
.get(channelEndpoint(slugOrId), {params})
|
||||
.then(response => response.data);
|
||||
}
|
||||
23
common/resources/client/channels/requests/use-infinite-channel-content.ts
Executable file
23
common/resources/client/channels/requests/use-infinite-channel-content.ts
Executable file
@@ -0,0 +1,23 @@
|
||||
import {useInfiniteData} from '@common/ui/infinite-scroll/use-infinite-data';
|
||||
import {Channel, ChannelContentItem} from '@common/channels/channel';
|
||||
import {
|
||||
channelEndpoint,
|
||||
channelQueryKey,
|
||||
} from '@common/channels/requests/use-channel';
|
||||
import {useChannelQueryParams} from '@common/channels/use-channel-query-params';
|
||||
|
||||
export function useInfiniteChannelContent<
|
||||
T extends ChannelContentItem = ChannelContentItem,
|
||||
>(channel: Channel<T>) {
|
||||
const queryParams = useChannelQueryParams(channel);
|
||||
return useInfiniteData<T>({
|
||||
willSortOrFilter: true,
|
||||
initialPage: channel.content,
|
||||
queryKey: channelQueryKey(channel.id),
|
||||
endpoint: channelEndpoint(channel.id),
|
||||
queryParams: {
|
||||
returnContentOnly: 'true',
|
||||
...queryParams,
|
||||
},
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user