pl-hooks: Fixes, new hooks

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
marcin mikołajczak 2024-10-22 15:28:57 +02:00
parent e583d15d0d
commit 11a27f9504
15 changed files with 112 additions and 40 deletions

View file

@ -11,7 +11,7 @@ import FaviconService from 'pl-fe/utils/favicon-service';
FaviconService.initFaviconService();
const getNotifTotals = (state: RootState): number => {
const notifications = state.notifications.unread || 0;
const notifications = state.notifications.unread;
const reports = state.admin.openReports.count();
const approvals = state.admin.awaitingApproval.count();
return notifications + reports + approvals;

View file

@ -433,8 +433,8 @@ const EventHeader: React.FC<IEventHeader> = ({ status }) => {
id='event.participants'
defaultMessage='{count} {rawCount, plural, one {person} other {people}} going'
values={{
rawCount: event.participants_count || 0,
count: shortNumberFormat(event.participants_count || 0),
rawCount: event.participants_count,
count: shortNumberFormat(event.participants_count),
}}
/>
</span>

View file

@ -51,7 +51,7 @@ interface GetTextDirectionOpts {
}
/** Get the direction of the text. */
const getTextDirection = (text: string, { fallback = 'ltr', confidence }: GetTextDirectionOpts = {}): 'ltr' | 'rtl' => {
const getTextDirection = (text?: string, { fallback = 'ltr', confidence }: GetTextDirectionOpts = {}): 'ltr' | 'rtl' => {
if (!text) return fallback;
return isRtl(text, confidence) ? 'rtl' : 'ltr';
};

View file

@ -16,8 +16,8 @@ interface UseAccountOpts {
}
const useAccount = (accountId?: string, opts: UseAccountOpts = {}) => {
const queryClient = usePlHooksQueryClient();
const { client } = usePlHooksApiClient();
const queryClient = usePlHooksQueryClient();
const accountQuery = useQuery({
queryKey: ['accounts', 'entities', accountId],

View file

@ -7,8 +7,8 @@ import { importEntities } from 'pl-hooks/importer';
import { useAccount, type UseAccountOpts } from './useAccount';
const useAccountLookup = (acct?: string, opts: UseAccountOpts = {}) => {
const queryClient = usePlHooksQueryClient();
const { client } = usePlHooksApiClient();
const queryClient = usePlHooksQueryClient();
const { features } = client;
const accountIdQuery = useQuery({

View file

@ -4,8 +4,8 @@ import { usePlHooksApiClient } from 'pl-hooks/contexts/api-client';
import { usePlHooksQueryClient } from 'pl-hooks/contexts/query-client';
const useAccountRelationship = (accountId?: string) => {
const queryClient = usePlHooksQueryClient();
const { client } = usePlHooksApiClient();
const queryClient = usePlHooksQueryClient();
return useQuery({
queryKey: ['accounts', 'entities', accountId],

View file

@ -0,0 +1,21 @@
import { useQuery } from '@tanstack/react-query';
import { instanceSchema } from 'pl-api';
import * as v from 'valibot';
import { usePlHooksApiClient } from 'pl-hooks/contexts/api-client';
import { usePlHooksQueryClient } from 'pl-hooks/contexts/query-client';
const placeholderData = v.parse(instanceSchema, {});
const useInstance = () => {
const { client } = usePlHooksApiClient();
const queryClient = usePlHooksQueryClient();
return useQuery({
queryKey: ['instance'],
queryFn: client.instance.getInstance,
placeholderData,
}, queryClient);
};
export { useInstance };

View file

@ -0,0 +1,38 @@
import { useQuery } from '@tanstack/react-query';
import { usePlHooksApiClient } from 'pl-hooks/contexts/api-client';
import { usePlHooksQueryClient } from 'pl-hooks/contexts/query-client';
import { useInstance } from './useInstance';
const useTranslationLanguages = () => {
const { client } = usePlHooksApiClient();
const queryClient = usePlHooksQueryClient();
const { data: instance } = useInstance();
const {
allow_unauthenticated: allowUnauthenticated,
} = instance!.pleroma.metadata.translation;
const getTranslationLanguages = async () => {
const metadata = instance!.pleroma.metadata;
if (metadata.translation.source_languages?.length) {
return Object.fromEntries(metadata.translation.source_languages.map(source => [
source,
metadata.translation.target_languages!.filter(lang => lang !== source),
]));
}
return client.instance.getInstanceTranslationLanguages();
};
return useQuery({
queryKey: ['instance', 'translationLanguages'],
queryFn: getTranslationLanguages,
placeholderData: {},
enabled: allowUnauthenticated && client.features.translations,
}, queryClient);
};
export { useTranslationLanguages };

View file

@ -8,8 +8,8 @@ import type { PlApiClient } from 'pl-api';
type Timeline = 'home' | 'notifications';
const useMarker = (timeline: Timeline) => {
const queryClient = usePlHooksQueryClient();
const { client } = usePlHooksApiClient();
const queryClient = usePlHooksQueryClient();
return useQuery({
queryKey: ['markers', timeline],

View file

@ -1,13 +1,14 @@
import { useMutation } from '@tanstack/react-query';
import { usePlHooksApiClient } from 'pl-hooks/contexts/api-client';
import { queryClient } from 'pl-hooks/contexts/query-client';
import { usePlHooksQueryClient } from 'pl-hooks/contexts/query-client';
import type { Timeline } from './useMarkers';
import type { Marker } from 'pl-api';
const useUpdateMarkerMutation = (timeline: Timeline) => {
const { client } = usePlHooksApiClient();
const queryClient = usePlHooksQueryClient();
return useMutation({
mutationFn: (lastReadId: string) => client.timelines.saveMarkers({
@ -20,7 +21,7 @@ const useUpdateMarkerMutation = (timeline: Timeline) => {
...marker,
last_read_id: lastReadId,
}) : undefined),
});
}, queryClient);
};
export { useUpdateMarkerMutation };

View file

@ -25,8 +25,8 @@ const importNotification = (notification: NormalizedNotification) => {
};
const useNotification = (notificationId: string) => {
const queryClient = usePlHooksQueryClient();
const { client } = usePlHooksApiClient();
const queryClient = usePlHooksQueryClient();
const notificationQuery = useQuery({
queryKey: ['notifications', 'entities', notificationId],

View file

@ -1,4 +1,4 @@
import { useInfiniteQuery } from '@tanstack/react-query';
import { InfiniteData, useInfiniteQuery, UseInfiniteQueryResult } from '@tanstack/react-query';
import { usePlHooksApiClient } from 'pl-hooks/contexts/api-client';
import { queryClient, usePlHooksQueryClient } from 'pl-hooks/contexts/query-client';
@ -33,9 +33,13 @@ const importNotifications = (response: PaginatedResponse<BaseNotification>) => {
};
};
const useNotificationList = (params: UseNotificationParams) => {
const queryClient = usePlHooksQueryClient();
const useNotificationList = (params: UseNotificationParams): Omit<UseInfiniteQueryResult<InfiniteData<{
items: string[];
previous: (() => Promise<PaginatedResponse<BaseNotification>>) | null;
next: (() => Promise<PaginatedResponse<BaseNotification>>) | null;
}, unknown>, Error>, 'data'> & { data: string[] } => {
const { client } = usePlHooksApiClient();
const queryClient = usePlHooksQueryClient();
const notificationsQuery = useInfiniteQuery({
queryKey: getQueryKey(params),
@ -47,7 +51,7 @@ const useNotificationList = (params: UseNotificationParams) => {
getNextPageParam: (response) => response,
}, queryClient);
const data = flattenPages<string>(notificationsQuery.data) || [];
const data: string[] = flattenPages<string>(notificationsQuery.data) || [];
return {
...notificationsQuery,

View file

@ -1,13 +1,13 @@
import { useQuery } from '@tanstack/react-query';
import { useQueries, useQuery } from '@tanstack/react-query';
import { usePlHooksApiClient } from 'pl-hooks/contexts/api-client';
import { queryClient, usePlHooksQueryClient } from 'pl-hooks/contexts/query-client';
import { importEntities } from 'pl-hooks/importer';
import { useAccount } from 'pl-hooks/main';
import { type Account, normalizeAccount } from 'pl-hooks/normalizers/normalizeAccount';
import { normalizeStatus, type Status } from '../../normalizers/normalizeStatus';
import type { Account } from 'pl-hooks/normalizers/normalizeAccount';
// const toServerSideType = (columnType: string): Filter['context'][0] => {
// switch (columnType) {
// case 'home':
@ -101,11 +101,14 @@ const useStatus = (statusId?: string, opts: { language?: string } = {}) => {
const status = statusQuery.data;
queryClient.getQueriesData({ queryKey: ['test', ['t']] });
const accountsQuery = queryClient.getQueriesData<Account>({
queryKey: ['accounts', 'entities', status?.account_ids],
});
const accountsQuery = useQueries({
queries: status?.account_ids.map(accountId => ({
queryKey: ['accounts', 'entities', accountId],
queryFn: () => client.accounts.getAccount(accountId!)
.then(account => (importEntities({ accounts: [account] }, { withParents: false }), account))
.then(normalizeAccount),
})) || [],
}, queryClient);
let data: (Status & {
account: Account;
@ -115,8 +118,8 @@ const useStatus = (statusId?: string, opts: { language?: string } = {}) => {
if (status) {
data = {
...status,
account: accountsQuery[0][1]!,
accounts: accountsQuery.map(([_, account]) => account!).filter(Boolean),
account: accountsQuery[0].data!,
accounts: accountsQuery.map(({ data }) => data!).filter(Boolean),
// quote,
// reblog,
// poll

View file

@ -11,9 +11,9 @@ import type {
Status as BaseStatus,
} from 'pl-api';
const importAccount = (account: BaseAccount) => {
return queryClient.setQueryData<BaseAccount>(['accounts', 'entities', account.id], account);
};
const importAccount = (account: BaseAccount) => queryClient.setQueryData<BaseAccount>(
['accounts', 'entities', account.id], account,
);
const importGroup = (group: BaseGroup) => queryClient.setQueryData<BaseGroup>(
['groups', 'entities', group.id], group,
@ -33,8 +33,7 @@ const importRelationship = (relationship: BaseRelationship) => queryClient.setQu
);
const importStatus = (status: BaseStatus) => queryClient.setQueryData<Status>(
['statuses', 'entities', status.id],
_ => normalizeStatus(status),
['statuses', 'entities', status.id], normalizeStatus(status),
);
const isEmpty = (object: Record<string, any>) => !Object.values(object).some(value => value);
@ -56,23 +55,30 @@ const importEntities = (entities: {
const relationships: Record<string, BaseRelationship> = {};
const statuses: Record<string, BaseStatus> = {};
const processAccount = (account: BaseAccount) => {
const processAccount = (account: BaseAccount, withSelf = true) => {
if (withSelf) accounts[account.id] = account;
queryClient.setQueryData<string>(['accounts', 'byAcct', account.acct.toLocaleLowerCase()], account.id);
if (account.moved) processAccount(account.moved);
if (account.relationship) relationships[account.relationship.id] = account.relationship;
};
const processNotification = (notification: DeduplicatedNotification) => {
const processNotification = (notification: DeduplicatedNotification, withSelf = true) => {
if (withSelf) notifications[notification.id] = notification;
processAccount(notification.account);
if (notification.type === 'move') processAccount(notification.target);
if (['mention', 'status', 'reblog', 'favourite', 'poll', 'update', 'emoji_reaction', 'event_reminder', 'participation_accepted', 'participation_request'].includes(notification.type))
if (['mention', 'status', 'reblog', 'favourite', 'poll', 'update', 'emoji_reaction', 'event_reminder', 'participation_accepted', 'participation_request'].includes(notification.type)) {
// @ts-ignore
processStatus(notification.status);
}
};
const processStatus = (status: BaseStatus) => {
const processStatus = (status: BaseStatus, withSelf = true) => {
if (withSelf) statuses[status.id] = status;
if (status.account) {
processAccount(status.account);
}
@ -84,17 +90,14 @@ const importEntities = (entities: {
};
if (options.withParents) {
entities.accounts?.forEach(account => accounts[account.id] = account);
entities.groups?.forEach(group => groups[group.id] = group);
entities.notifications?.forEach(notification => notifications[notification.id] = notification);
entities.polls?.forEach(poll => polls[poll.id] = poll);
entities.relationships?.forEach(relationship => relationships[relationship.id] = relationship);
entities.statuses?.forEach(status => statuses[status.id] = status);
}
entities.accounts?.forEach((account) => processAccount(account));
entities.notifications?.forEach((notification) => processNotification(notification));
entities.statuses?.forEach((status) => processStatus(status));
entities.accounts?.forEach((account) => processAccount(account, options.withParents));
entities.notifications?.forEach((notification) => processNotification(notification, options.withParents));
entities.statuses?.forEach((status) => processStatus(status, options.withParents));
if (!isEmpty(accounts)) Object.values(accounts).forEach(importAccount);
if (!isEmpty(groups)) Object.values(groups).forEach(importGroup);

View file

@ -4,6 +4,8 @@ export * from './contexts/query-client';
export * from './hooks/accounts/useAccount';
export * from './hooks/accounts/useAccountLookup';
export * from './hooks/accounts/useAccountRelationship';
export * from './hooks/instance/useInstance';
export * from './hooks/instance/useTranslationLanguages';
export * from './hooks/markers/useMarkers';
export * from './hooks/markers/useUpdateMarkerMutation';
export * from './hooks/notifications/useNotification';