UNPKG

@yext/chat-headless

Version:

A state manager library powered by Redux for Yext Chat integrations

140 lines (130 loc) 3.97 kB
import { createSlice, PayloadAction } from "@reduxjs/toolkit"; import { ConversationState } from "../models/slices/ConversationState"; import { Message, MessageNotes } from "@yext/chat-core"; const BASE_STATE_LOCAL_STORAGE_KEY = "yext_chat_state"; export const initialState: ConversationState = { messages: [], isLoading: false, canSendMessage: true, }; export function getStateLocalStorageKey( hostname: string, botId: string ): string { return `${BASE_STATE_LOCAL_STORAGE_KEY}__${hostname}__${botId}`; } /** * Loads the {@link ConversationState} from local storage. */ export const loadSessionState = (botId: string): ConversationState => { if (!localStorage) { console.warn( "Local storage is not available. State will not be persisted while navigating across pages." ); return initialState; } const hostname = window?.location?.hostname; if (!hostname) { console.warn( "Unable to get hostname of current page. State will not be persisted while navigating across pages." ); return initialState; } const savedState = localStorage.getItem( getStateLocalStorageKey(hostname, botId) ); if (savedState) { try { const parsedState: ConversationState = JSON.parse(savedState); if (parsedState.messages.length > 0) { const lastTimestamp = parsedState.messages[parsedState.messages.length - 1].timestamp; const currentDate = new Date(); const lastDate = new Date(lastTimestamp || 0); const diff = currentDate.getTime() - lastDate.getTime(); // If the last message was sent within the last day, we consider the session to be active if (diff < 24 * 60 * 60 * 1000) { return parsedState; } localStorage.removeItem(getStateLocalStorageKey(hostname, botId)); } } catch (e) { console.warn( "Unabled to load saved state: error parsing state. Starting with a fresh state." ); localStorage.removeItem(getStateLocalStorageKey(hostname, botId)); } } return initialState; }; export const saveSessionState = (botId: string, state: ConversationState) => { if (!localStorage) { console.warn( "Local storage is not available. State will not be persisted while navigating across pages." ); return initialState; } const hostname = window?.location?.hostname; if (!hostname) { console.warn( "Unable to get hostname of current page. State will not be persisted across page refreshes." ); return initialState; } localStorage.setItem( getStateLocalStorageKey(hostname, botId), JSON.stringify(state) ); }; /** * Registers with Redux the slice of {@link State} pertaining to the loading status * of Chat Headless. */ export const conversationSlice = createSlice({ name: "conversation", initialState, reducers: { setConversationId: ( state: ConversationState, action: PayloadAction<string | undefined> ) => { state.conversationId = action.payload; }, setMessages: ( state: ConversationState, action: PayloadAction<Message[]> ) => { state.messages = action.payload; }, addMessage: (state: ConversationState, action: PayloadAction<Message>) => { state.messages.push(action.payload); }, setMessageNotes: ( state: ConversationState, action: PayloadAction<MessageNotes> ) => { state.notes = action.payload; }, setIsLoading: ( state: ConversationState, action: PayloadAction<boolean> ) => { state.isLoading = action.payload; }, setCanSendMessage: ( state: ConversationState, action: PayloadAction<boolean> ) => { state.canSendMessage = action.payload; }, }, }); export const { setMessages, addMessage, setMessageNotes, setIsLoading, setConversationId, setCanSendMessage, } = conversationSlice.actions; export default conversationSlice.reducer;