153 lines
4.1 KiB
TypeScript
153 lines
4.1 KiB
TypeScript
import { FetchState, TicketMessage } from "@frontend/kitui";
|
||
import { create } from "zustand";
|
||
import { createJSONStorage, devtools, persist } from "zustand/middleware";
|
||
import { useUserStore } from "./user";
|
||
import { produce } from "immer";
|
||
|
||
type SessionData = {
|
||
ticketId: string;
|
||
sessionId: string;
|
||
};
|
||
interface AuthData {
|
||
sessionData: SessionData | null;
|
||
isMessageSending: boolean;
|
||
messages: TicketMessage[];
|
||
apiPage: number;
|
||
messagesPerPage: number;
|
||
lastMessageId: string | undefined;
|
||
isPreventAutoscroll: boolean;
|
||
unauthTicketMessageFetchState: FetchState;
|
||
}
|
||
interface TicketStore {
|
||
unauthData: AuthData;
|
||
authData: AuthData;
|
||
}
|
||
const initAuthData = {
|
||
sessionData: null,
|
||
isMessageSending: false,
|
||
messages: [],
|
||
apiPage: 0,
|
||
messagesPerPage: 10,
|
||
lastMessageId: undefined,
|
||
isPreventAutoscroll: false,
|
||
unauthTicketMessageFetchState: "idle" as FetchState,
|
||
};
|
||
const initState = {
|
||
unauthData: initAuthData,
|
||
authData: initAuthData,
|
||
};
|
||
|
||
export const useTicketStore = create<TicketStore>()(
|
||
persist(
|
||
devtools((set, get) => initState, {
|
||
name: "Unauth tickets",
|
||
}),
|
||
{
|
||
version: 0,
|
||
name: "unauth-ticket",
|
||
storage: createJSONStorage(() => localStorage),
|
||
},
|
||
),
|
||
);
|
||
|
||
export const cleanAuthTicketData = () => {
|
||
useTicketStore.setState({ authData: initAuthData });
|
||
};
|
||
|
||
export const setTicketData = (sessionData: SessionData) =>
|
||
updateTicket((ticket) => {
|
||
ticket.sessionData = sessionData;
|
||
});
|
||
|
||
export const setIsMessageSending = (
|
||
isMessageSending: AuthData["isMessageSending"],
|
||
) =>
|
||
updateTicket((ticket) => {
|
||
ticket.isMessageSending = isMessageSending;
|
||
});
|
||
|
||
export const addOrUpdateUnauthMessages = (receivedMessages: TicketMessage[]) =>
|
||
updateTicket((ticket) => {
|
||
const filtered = filterMessageUncompleteness(receivedMessages);
|
||
console.log(filtered);
|
||
if (filtered.length === 0) return;
|
||
|
||
const messageIdToMessageMap: { [messageId: string]: TicketMessage } = {};
|
||
|
||
[...ticket.messages, ...filtered].forEach(
|
||
(message) => (messageIdToMessageMap[message.id] = message),
|
||
);
|
||
|
||
const sortedMessages = Object.values(messageIdToMessageMap).sort(
|
||
sortMessagesByTime,
|
||
);
|
||
|
||
ticket.messages = sortedMessages;
|
||
ticket.lastMessageId = sortedMessages.at(-1)?.id;
|
||
});
|
||
|
||
export const incrementUnauthMessageApiPage = () =>
|
||
updateTicket((ticket) => {
|
||
ticket.apiPage++;
|
||
});
|
||
|
||
export const setUnauthIsPreventAutoscroll = (isPreventAutoscroll: boolean) =>
|
||
updateTicket((ticket) => {
|
||
ticket.isPreventAutoscroll = isPreventAutoscroll;
|
||
});
|
||
|
||
export const setUnauthTicketMessageFetchState = (
|
||
unauthTicketMessageFetchState: FetchState,
|
||
) =>
|
||
updateTicket((ticket) => {
|
||
ticket.unauthTicketMessageFetchState = unauthTicketMessageFetchState;
|
||
});
|
||
|
||
function sortMessagesByTime(ticket1: TicketMessage, ticket2: TicketMessage) {
|
||
const date1 = new Date(ticket1.created_at).getTime();
|
||
const date2 = new Date(ticket2.created_at).getTime();
|
||
return date1 - date2;
|
||
}
|
||
|
||
function filterMessageUncompleteness(messages: TicketMessage[]) {
|
||
return messages.filter(
|
||
(message) =>
|
||
"id" in message &&
|
||
"ticket_id" in message &&
|
||
"user_id" in message &&
|
||
"session_id" in message &&
|
||
"message" in message &&
|
||
"files" in message &&
|
||
"shown" in message &&
|
||
"request_screenshot" in message &&
|
||
"created_at" in message &&
|
||
((message.files !== null && message.files.length > 0) ||
|
||
message.message.length > 0),
|
||
);
|
||
}
|
||
|
||
export const updateTicket = <T extends AuthData>(
|
||
recipe: (ticket: AuthData) => void,
|
||
) =>
|
||
setProducedState(
|
||
(state) => {
|
||
//В зависимости от авторизованности вызывается изменение разных объектов
|
||
if (Boolean(useUserStore.getState().userId)) {
|
||
recipe(state.authData);
|
||
} else {
|
||
recipe(state.unauthData);
|
||
}
|
||
},
|
||
{
|
||
type: "updateTicket",
|
||
recipe,
|
||
},
|
||
);
|
||
|
||
function setProducedState<A extends string | { type: unknown }>(
|
||
recipe: (state: TicketStore) => void,
|
||
action?: A,
|
||
) {
|
||
useTicketStore.setState((state) => produce(state, recipe), false, action);
|
||
}
|