184 lines
4.9 KiB
TypeScript
184 lines
4.9 KiB
TypeScript
import { FetchState, Ticket, TicketMessage } from "@frontend/kitui";
|
||
import { create } from "zustand";
|
||
import { devtools, persist, createJSONStorage } 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 {
|
||
ticketCount: number;
|
||
tickets: Ticket[];
|
||
apiPage: number;
|
||
ticketsPerPage: number;
|
||
ticketsFetchState: FetchState;
|
||
authData: AuthData;
|
||
unauthData: AuthData;
|
||
}
|
||
|
||
const initAuthData = {
|
||
sessionData: null,
|
||
isMessageSending: false,
|
||
messages: [],
|
||
apiPage: 0,
|
||
messagesPerPage: 10,
|
||
lastMessageId: undefined,
|
||
isPreventAutoscroll: false,
|
||
unauthTicketMessageFetchState: "idle" as FetchState,
|
||
};
|
||
|
||
const initialState: TicketStore = {
|
||
ticketCount: 0,
|
||
tickets: [],
|
||
apiPage: 0,
|
||
ticketsPerPage: 10,
|
||
ticketsFetchState: "idle",
|
||
authData: initAuthData,
|
||
unauthData: initAuthData,
|
||
};
|
||
|
||
export const useTicketStore = create<TicketStore>()(
|
||
persist(
|
||
devtools((set, get) => initialState, {
|
||
name: "Unauth tickets",
|
||
}),
|
||
{
|
||
version: 0,
|
||
name: "unauth-ticket",
|
||
storage: createJSONStorage(() => localStorage),
|
||
}
|
||
)
|
||
);
|
||
|
||
export const setTicketCount = (ticketCount: number) =>
|
||
useTicketStore.setState({ ticketCount });
|
||
|
||
export const setTicketApiPage = (apiPage: number) =>
|
||
useTicketStore.setState({ apiPage: apiPage });
|
||
|
||
export const updateTickets = (receivedTickets: Ticket[]) => {
|
||
const state = useTicketStore.getState();
|
||
const ticketIdToTicketMap: { [ticketId: string]: Ticket } = {};
|
||
|
||
[...state.tickets, ...receivedTickets].forEach(
|
||
(ticket) => (ticketIdToTicketMap[ticket.id] = ticket)
|
||
);
|
||
|
||
useTicketStore.setState({ tickets: Object.values(ticketIdToTicketMap) });
|
||
};
|
||
|
||
export const clearTickets = () => useTicketStore.setState({ ...initialState });
|
||
|
||
export const setTicketsFetchState = (ticketsFetchState: FetchState) =>
|
||
useTicketStore.setState({ ticketsFetchState });
|
||
|
||
export const setTicketData = (sessionData: SessionData) =>
|
||
updateTicket((ticket) => {
|
||
ticket.sessionData = sessionData;
|
||
});
|
||
|
||
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);
|
||
}
|
||
|
||
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)
|
||
);
|
||
}
|
||
|
||
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;
|
||
}
|
||
|
||
export const addOrUpdateUnauthMessages = (receivedMessages: TicketMessage[]) =>
|
||
updateTicket((ticket) => {
|
||
const filtered = filterMessageUncompleteness(receivedMessages);
|
||
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 setUnauthTicketMessageFetchState = (
|
||
unauthTicketMessageFetchState: FetchState
|
||
) =>
|
||
updateTicket((ticket) => {
|
||
ticket.unauthTicketMessageFetchState = unauthTicketMessageFetchState;
|
||
});
|
||
|
||
export const setUnauthIsPreventAutoscroll = (isPreventAutoscroll: boolean) =>
|
||
updateTicket((ticket) => {
|
||
ticket.isPreventAutoscroll = isPreventAutoscroll;
|
||
});
|
||
|
||
export const incrementUnauthMessage = () =>
|
||
updateTicket((ticket) => {
|
||
ticket.apiPage++;
|
||
});
|
||
|
||
export const setIsMessageSending = (
|
||
isMessageSending: AuthData["isMessageSending"]
|
||
) => {
|
||
updateTicket((ticket) => {
|
||
ticket.isMessageSending = isMessageSending;
|
||
});
|
||
};
|