125 lines
3.6 KiB
TypeScript
125 lines
3.6 KiB
TypeScript
import { useEffect } from 'react';
|
|
import { create } from 'zustand';
|
|
import { mutative } from 'zustand-mutative';
|
|
|
|
import { importEntities } from '@/actions/importer';
|
|
import { useClient } from '@/hooks/use-client';
|
|
import { useFeatures } from '@/hooks/use-features';
|
|
import { useLoggedIn } from '@/hooks/use-logged-in';
|
|
|
|
import type { store } from '@/store';
|
|
import type { PlApiClient, ShoutMessage as BaseShoutMessage } from 'pl-api';
|
|
|
|
let lazyStore: typeof store;
|
|
import('@/store').then(({ store }) => (lazyStore = store)).catch(() => {});
|
|
|
|
const minifyMessage = ({ author, ...message }: BaseShoutMessage) => ({
|
|
author_id: author.id,
|
|
...message,
|
|
});
|
|
|
|
type ShoutMessage = ReturnType<typeof minifyMessage>;
|
|
|
|
type State = {
|
|
socket: ReturnType<InstanceType<typeof PlApiClient>['shoutbox']['connect']> | null;
|
|
messages: Array<ShoutMessage>;
|
|
isLoading: boolean;
|
|
actions: {
|
|
setMessages: (messages: Array<BaseShoutMessage>) => void;
|
|
pushMessage: (message: BaseShoutMessage) => void;
|
|
setSocket: (socket: State['socket']) => void;
|
|
};
|
|
};
|
|
|
|
const useShoutboxStore = create<State>()(
|
|
mutative(
|
|
(set) => ({
|
|
socket: null,
|
|
messages: [],
|
|
isLoading: true,
|
|
actions: {
|
|
setMessages: (messages) => {
|
|
set((state: State) => {
|
|
lazyStore?.dispatch(
|
|
importEntities(
|
|
{ accounts: messages.map((msg) => msg.author) },
|
|
{ override: false },
|
|
) as any,
|
|
);
|
|
state.messages = messages.map(minifyMessage);
|
|
state.isLoading = false;
|
|
});
|
|
},
|
|
pushMessage: (message) => {
|
|
set((state: State) => {
|
|
lazyStore?.dispatch(importEntities({ accounts: [message.author] }) as any);
|
|
state.messages.push(minifyMessage(message));
|
|
});
|
|
},
|
|
setSocket: (socket) => {
|
|
set((state: State) => {
|
|
state.socket = socket;
|
|
});
|
|
},
|
|
},
|
|
}),
|
|
{
|
|
enableAutoFreeze: false,
|
|
},
|
|
),
|
|
);
|
|
|
|
const useShoutboxMessages = () => useShoutboxStore((state) => state.messages);
|
|
const useShoutboxIsLoading = () => useShoutboxStore((state) => state.isLoading);
|
|
const useShoutboxSocket = () => useShoutboxStore((state) => state.socket);
|
|
const useShoutboxActions = () => useShoutboxStore((state) => state.actions);
|
|
|
|
const useShoutboxSubscription = () => {
|
|
const client = useClient();
|
|
const { shoutbox: shoutboxAvailable } = useFeatures();
|
|
const { isLoggedIn } = useLoggedIn();
|
|
const shoutboxStore = useShoutboxActions();
|
|
|
|
useEffect(() => {
|
|
if (!(shoutboxAvailable && isLoggedIn)) return;
|
|
|
|
let socket: ReturnType<InstanceType<typeof PlApiClient>['shoutbox']['connect']>;
|
|
|
|
client.settings
|
|
.verifyCredentials()
|
|
.then((account) => {
|
|
if (account.__meta.pleroma?.chat_token) {
|
|
socket = client.shoutbox.connect(account.__meta.pleroma?.chat_token, {
|
|
onMessage: (message) => {
|
|
shoutboxStore.pushMessage(message);
|
|
},
|
|
onMessages: (messages) => {
|
|
shoutboxStore.setMessages(messages);
|
|
},
|
|
});
|
|
shoutboxStore.setSocket(socket);
|
|
}
|
|
})
|
|
.catch(() => {});
|
|
|
|
return () => {
|
|
socket?.close();
|
|
shoutboxStore.setSocket(null);
|
|
};
|
|
}, [shoutboxAvailable && isLoggedIn]);
|
|
};
|
|
|
|
const useCreateShoutboxMessage = () => {
|
|
const socket = useShoutboxSocket();
|
|
return { mutate: socket?.message };
|
|
};
|
|
|
|
export {
|
|
useShoutboxStore,
|
|
useShoutboxMessages,
|
|
useShoutboxIsLoading,
|
|
useShoutboxSubscription,
|
|
useCreateShoutboxMessage,
|
|
type ShoutMessage,
|
|
};
|