This commit is contained in:
2026-04-25 16:36:34 +08:00
commit db90e7579b
1876 changed files with 189777 additions and 0 deletions

View File

@@ -0,0 +1,24 @@
import { useEffect } from 'react';
import { fetchAvailableServices } from '../../model/common';
import { useAsyncFn } from '../useAsyncFn';
import { useMemoizedFn } from '../useMemoizedFn';
/**
* 用于监测服务是否可用的hooks
*/
export function useAvailableServices() {
const [{ loading, value: availableServices }, fetch] = useAsyncFn(() =>
fetchAvailableServices()
);
useEffect(() => {
fetch();
}, []);
const refetch = useMemoizedFn(async () => {
fetchAvailableServices.clearCache();
fetch();
});
return { loading, availableServices, refetch };
}

View File

@@ -0,0 +1,23 @@
import { sharedEvent, useSharedEventHandler } from '../../event';
import { useUserNotifyMute } from './useUserSettings';
/**
* 消息通知翻译
* 检查用户设置,接受已读消息并发送未静音消息
*
* 接收到消息事件{receiveMessage} -> 检查是否被静音 -> 没有静音,发送{receiveUnmutedMessage}事件
* -> 静音, 不做任何处理
*/
export function useMessageNotifyEventFilter() {
const { checkIsMuted } = useUserNotifyMute();
useSharedEventHandler('receiveMessage', (payload) => {
if (!payload) {
return;
}
if (!checkIsMuted(payload.converseId, payload.groupId)) {
sharedEvent.emit('receiveUnmutedMessage', payload);
}
});
}

View File

@@ -0,0 +1,19 @@
import { getCachedUserInfo } from '../../cache/cache';
import type { UserBaseInfo } from '../../model/user';
import { useAsync } from '../useAsync';
/**
* 用户信息
*/
export function useCachedUserInfo(
userId: string,
refetch = false
): UserBaseInfo | Record<string, never> {
const { value: userInfo = {} } = useAsync(async () => {
const users = getCachedUserInfo(userId, refetch);
return users;
}, [userId, refetch]);
return userInfo ?? {};
}

View File

@@ -0,0 +1,16 @@
import { getCachedUserInfo } from '../../cache/cache';
import type { UserBaseInfo } from '../../model/user';
import { useAsync } from '../useAsync';
/**
* 用户信息列表
*/
export function useUserInfoList(userIds: string[] = []): UserBaseInfo[] {
const { value: userInfoList = [] } = useAsync(async () => {
const users = await Promise.all(userIds.map((id) => getCachedUserInfo(id)));
return users;
}, [userIds.join(',')]);
return userInfoList;
}

View File

@@ -0,0 +1,110 @@
import { CacheKey } from '../../cache/cache';
import { useQuery, useQueryClient } from '../../cache/useCache';
import { sharedEvent } from '../../event';
import {
getUserSettings,
setUserSettings,
UserSettings,
} from '../../model/user';
import { useAsyncRequest } from '../useAsyncRequest';
import { useMemoizedFn } from '../useMemoizedFn';
import _without from 'lodash/without';
/**
* 用户设置hooks
*/
export function useUserSettings() {
const client = useQueryClient();
const { data: settings, isLoading } = useQuery(
[CacheKey.userSettings],
() => getUserSettings(),
{
staleTime: 10 * 60 * 1000, // 缓存10分钟
}
);
const [{ loading: saveLoading }, setSettings] = useAsyncRequest(
async (_settings: UserSettings) => {
client.setQueryData([CacheKey.userSettings], () => ({
...settings,
..._settings,
})); // 让配置能够立即生效, 防止依赖配置的行为出现跳变(如GroupNav)
const newSettings = await setUserSettings(_settings);
client.setQueryData([CacheKey.userSettings], () => newSettings);
sharedEvent.emit('userSettingsUpdate', newSettings);
},
[client]
);
return {
settings: settings ?? {},
setSettings,
loading: isLoading || saveLoading,
};
}
/**
* 单个用户设置
*/
export function useSingleUserSetting<K extends keyof UserSettings>(
name: K,
defaultValue?: UserSettings[K]
) {
const { settings, setSettings, loading } = useUserSettings();
return {
value: settings[name] ?? defaultValue,
setValue: async (newVal: UserSettings[K]) =>
setSettings({
[name]: newVal,
}),
loading,
};
}
/**
* 用户消息通知免打扰设置
*/
export function useUserNotifyMute() {
const { value: list = [], setValue: setList } = useSingleUserSetting(
'messageNotificationMuteList',
[]
);
const mute = useMemoizedFn((converseOrGroupId: string) => {
setList([...list, converseOrGroupId]);
});
const unmute = useMemoizedFn((converseOrGroupId: string) => {
setList(_without(list, converseOrGroupId));
});
const toggleMute = useMemoizedFn((converseOrGroupId) => {
if (list.includes(converseOrGroupId)) {
unmute(converseOrGroupId);
} else {
mute(converseOrGroupId);
}
});
/**
* 检查是否被静音
*/
const checkIsMuted = useMemoizedFn((panelId: string, groupId?: string) => {
if (groupId) {
return list.includes(panelId) || list.includes(groupId);
}
return list.includes(panelId);
});
return {
mutedList: list,
mute,
unmute,
toggleMute,
checkIsMuted,
};
}

View File

@@ -0,0 +1,10 @@
import { useUserInfoList } from './useUserInfoList';
/**
* 用户名列表
*/
export function useUsernames(userIds: string[]): string[] {
const userInfoList = useUserInfoList(userIds);
return userInfoList.map((info) => info.nickname);
}