From 5ef4a08ab29514004c3b0d45c2a27dccafb06940 Mon Sep 17 00:00:00 2001 From: "phong.nguyen.nam" Date: Tue, 25 Feb 2025 17:33:08 +0700 Subject: [PATCH 1/5] updated --- apps/chat/src/app/pages/main/index.tsx | 104 ++++++++++-------- .../MarkdownFormatText/ModalUnknowChannel.tsx | 19 ++-- .../ModalListClans/SidebarLogoItem.tsx | 1 + libs/store/src/lib/clans/clans.slice.ts | 1 + libs/store/src/lib/errors/errors.listener.ts | 8 +- libs/store/src/lib/toasts/toasts.slice.ts | 17 ++- 6 files changed, 92 insertions(+), 58 deletions(-) diff --git a/apps/chat/src/app/pages/main/index.tsx b/apps/chat/src/app/pages/main/index.tsx index 275f9e2ed2..f0bec4ad12 100644 --- a/apps/chat/src/app/pages/main/index.tsx +++ b/apps/chat/src/app/pages/main/index.tsx @@ -277,55 +277,73 @@ function MyApp() { dispatch(e2eeActions.setOpenModalE2ee(false)); }; // show toast error - const toastErrorStatus = useSelector(selectToastErrorStatus); - const [openUnknown, closeUnknown] = useModal(() => { - return ; - }, []); + // Lấy danh sách lỗi từ Redux + const toastError = useSelector(selectToastErrorStatus); + + // State quản lý danh sách modal lỗi đang mở + const [openErrors, setOpenErrors] = useState<{ id: number; message: string }[]>([]); + + // Khi có lỗi mới, thêm vào danh sách openErrors useEffect(() => { - if (toastErrorStatus) { - openUnknown(); - } else { - closeUnknown(); + if (toastError.errors.length > 0) { + setOpenErrors((prev) => [ + ...prev, + ...toastError.errors.map((err, index) => ({ + id: Date.now() + index, + message: err.message + })) + ]); } - }, [toastErrorStatus]); + }, [toastError.errors]); + + // Hàm đóng modal theo ID + const closeError = (id: number) => { + setOpenErrors((prev) => prev.filter((err) => err.id !== id)); + }; + return ( -
- {previewMode && } - {openPopupForward && } - - + <> + {openErrors.map((error) => ( + closeError(error.id)} /> + ))}
- -
+ {previewMode && } + {openPopupForward && } + + +
+ +
- {isPlayRingTone && - !!dataCall && - !isInCall && - directId !== dataCall?.channel_id && - dataCall?.data_type === WebrtcSignalingType.WEBRTC_SDP_OFFER && ( - - )} - - - {openModalE2ee && !hasKeyE2ee && } - {openModalAttachment && } - {isShowFirstJoinPopup && setIsShowFirstJoinPopup(false)} />} - {isShowPopupQuickMess && } -
+ {isPlayRingTone && + !!dataCall && + !isInCall && + directId !== dataCall?.channel_id && + dataCall?.data_type === WebrtcSignalingType.WEBRTC_SDP_OFFER && ( + + )} + + + {openModalE2ee && !hasKeyE2ee && } + {openModalAttachment && } + {isShowFirstJoinPopup && setIsShowFirstJoinPopup(false)} />} + {isShowPopupQuickMess && } + + ); } diff --git a/libs/components/src/lib/components/MarkdownFormatText/ModalUnknowChannel.tsx b/libs/components/src/lib/components/MarkdownFormatText/ModalUnknowChannel.tsx index 509b380f91..a949c04fb9 100644 --- a/libs/components/src/lib/components/MarkdownFormatText/ModalUnknowChannel.tsx +++ b/libs/components/src/lib/components/MarkdownFormatText/ModalUnknowChannel.tsx @@ -1,5 +1,5 @@ import { FRIEND_PAGE_LINK, toChannelPage, toMembersPage } from '@mezon/core'; -import { RootState, getStoreAsync, selectCurrentClanId, selectWelcomeChannelByClanId, toastActions } from '@mezon/store'; +import { RootState, getStoreAsync, selectCurrentClanId, selectWelcomeChannelByClanId } from '@mezon/store'; import { Icons } from '@mezon/ui'; import { useDispatch } from 'react-redux'; import { useNavigate } from 'react-router-dom'; @@ -7,19 +7,20 @@ import { useNavigate } from 'react-router-dom'; type ModalUnknowChannelProps = { onClose: () => void; isError?: boolean; + errMessage?: string; }; function ModalUnknowChannel(props: ModalUnknowChannelProps) { const dispatch = useDispatch(); - const { onClose, isError = false } = props; + const { onClose, isError = false, errMessage } = props; const navigate = useNavigate(); - const resetErrorToastStatus = () => { - dispatch(toastActions.setErrorToastStatus(false)); - }; + // const resetErrorToastStatus = () => { + // dispatch(toastActions.setToastError({ isActive: false, message: '' })); + // }; const directToWelcomeChannel = async () => { - resetErrorToastStatus(); + // resetErrorToastStatus(); const store = await getStoreAsync(); const currentClanId = selectCurrentClanId(store.getState() as RootState); @@ -40,7 +41,7 @@ function ModalUnknowChannel(props: ModalUnknowChannelProps) { const onCloseAndReset = () => { onClose(); if (isError) { - resetErrorToastStatus(); + // resetErrorToastStatus(); } }; @@ -52,7 +53,9 @@ function ModalUnknowChannel(props: ModalUnknowChannelProps) {
{isError ? ( -

Oops! Something Went Wrong

+

+ {errMessage ? errMessage : 'Oops! Something Went Wrong'} +

) : ( <>

You don't have access to this link.

diff --git a/libs/components/src/lib/components/ModalListClans/SidebarLogoItem.tsx b/libs/components/src/lib/components/ModalListClans/SidebarLogoItem.tsx index 834173879a..f014dda24a 100644 --- a/libs/components/src/lib/components/ModalListClans/SidebarLogoItem.tsx +++ b/libs/components/src/lib/components/ModalListClans/SidebarLogoItem.tsx @@ -51,6 +51,7 @@ const SidebarLogoItem = () => { openRightClickModal(); }; const handleClickToJoinClan = () => { + console.log('handleClickToJoinClan'); dispatch(clansActions.joinClan({ clanId: '0' })); }; const { quantityPendingRequest } = useFriends(); diff --git a/libs/store/src/lib/clans/clans.slice.ts b/libs/store/src/lib/clans/clans.slice.ts index 1f7c584cca..be59c02502 100644 --- a/libs/store/src/lib/clans/clans.slice.ts +++ b/libs/store/src/lib/clans/clans.slice.ts @@ -290,6 +290,7 @@ interface JoinClanPayload { clanId: string; } export const joinClan = createAsyncThunk('direct/joinClan', async ({ clanId }, thunkAPI) => { + console.log('joinClan', clanId); try { const mezon = await ensureSocket(getMezonCtx(thunkAPI)); await mezon.socketRef.current?.joinClanChat(clanId); diff --git a/libs/store/src/lib/errors/errors.listener.ts b/libs/store/src/lib/errors/errors.listener.ts index 6a9abbb643..417f823b88 100644 --- a/libs/store/src/lib/errors/errors.listener.ts +++ b/libs/store/src/lib/errors/errors.listener.ts @@ -123,8 +123,14 @@ errorListenerMiddleware.startListening({ if (!toast) { return; } + console.log('toast: ', toast); if (toast.type === 'error') { - listenerApi.dispatch(toastActions.setErrorToastStatus(true)); + listenerApi.dispatch( + toastActions.setToastError({ + status: true, + message: toast.message as string + }) + ); } } }); diff --git a/libs/store/src/lib/toasts/toasts.slice.ts b/libs/store/src/lib/toasts/toasts.slice.ts index 61d4a3c5d7..c0938f42f7 100644 --- a/libs/store/src/lib/toasts/toasts.slice.ts +++ b/libs/store/src/lib/toasts/toasts.slice.ts @@ -9,7 +9,7 @@ const toastsAdapter = createEntityAdapter(); const initialState = { ...toastsAdapter.getInitialState(), - toastErrorStatus: false + toastError: { status: false, errors: [] as { message: string }[] } }; const addToast = createAsyncThunk( 'toasts/addToast', @@ -62,19 +62,24 @@ export const toastsSlice = createSlice({ clearToasts: (state) => { toastsAdapter.removeAll(state); }, - setErrorToastStatus: (state, action: PayloadAction) => { - state.toastErrorStatus = action.payload; + setToastError: (state, action: PayloadAction<{ status: boolean; message: string }>) => { + state.toastError.status = action.payload.status; + if (action.payload.status) { + state.toastError.errors.push({ message: action.payload.message }); + } else { + state.toastError.errors = []; + } } } }); -export const { addOneToast, removeToast, clearToasts, setErrorToastStatus } = toastsSlice.actions; +export const { addOneToast, removeToast, clearToasts, setToastError } = toastsSlice.actions; export const toastActions = { addToast, removeToast, clearToasts, - setErrorToastStatus + setToastError }; // Create selectors using the adapter's getSelectors method @@ -83,6 +88,6 @@ export const { selectAll: selectToasts, selectById: selectToastById } = toastsAd ); export const selectToastErrorStatus = createSelector( [(state: { toasts: typeof initialState }) => state.toasts], - (toastsState) => toastsState.toastErrorStatus + (toastsState) => toastsState.toastError ); export const toastsReducer = toastsSlice.reducer; From 676e520a35872f3778afea506a6b8e55e8ada29f Mon Sep 17 00:00:00 2001 From: thanhlong1203 Date: Tue, 25 Feb 2025 17:51:15 +0700 Subject: [PATCH 2/5] fix bug hide footer settings when joining mezon meet --- apps/chat/src/app/pages/channel/ChannelVoice.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/chat/src/app/pages/channel/ChannelVoice.tsx b/apps/chat/src/app/pages/channel/ChannelVoice.tsx index 020e82d64d..e6a5c450fe 100644 --- a/apps/chat/src/app/pages/channel/ChannelVoice.tsx +++ b/apps/chat/src/app/pages/channel/ChannelVoice.tsx @@ -9,6 +9,7 @@ import { handleParticipantMeetState, selectCurrentChannel, selectCurrentClan, + selectIsShowSettingFooter, selectShowCamera, selectShowMicrophone, selectVoiceFullScreen, @@ -128,9 +129,11 @@ const ChannelVoice = memo( const isShow = isJoined && voiceInfo?.clanId === currentChannel?.clan_id && voiceInfo?.channelId === currentChannel?.channel_id; + const isShowSettingFooter = useSelector(selectIsShowSettingFooter); + return (
{tokenRef.current === '' || !serverUrl ? ( From 69eac8471eb0f8c1752065ecc65ddd563c6ff89a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Qu=E1=BB=91c=20Vinh=203?= Date: Wed, 26 Feb 2025 11:03:09 +0700 Subject: [PATCH 3/5] update input send token --- .../lib/components/FooterProfile/index.tsx | 21 +++++++++++++------ .../StatusProfile/ModalSendToken.tsx | 11 ++++++---- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/libs/components/src/lib/components/FooterProfile/index.tsx b/libs/components/src/lib/components/FooterProfile/index.tsx index dca65a5988..2d2e14084d 100644 --- a/libs/components/src/lib/components/FooterProfile/index.tsx +++ b/libs/components/src/lib/components/FooterProfile/index.tsx @@ -58,7 +58,13 @@ function FooterProfile({ name, status, avatar, userId, isDM }: FooterProfileProp const [userSearchError, setUserSearchError] = useState(null); const [resetTimerStatus, setResetTimerStatus] = useState(0); const [noClearStatus, setNoClearStatus] = useState(false); - const [isInputDisabled, setIsInputDisabled] = useState(false); + const [sendTokenInputsState, setSendTokenInputsState] = useState<{ + isSendTokenInputDisabled: boolean; + isUserSelectionDisabled: boolean; + }>({ + isSendTokenInputDisabled: false, + isUserSelectionDisabled: false + }); const { createDirectMessageWithUser } = useDirect(); const { sendInviteMessage } = useSendInviteMessage(); @@ -100,7 +106,7 @@ function FooterProfile({ name, status, avatar, userId, isDM }: FooterProfileProp setNote('send token'); setUserSearchError(''); setError(''); - setIsInputDisabled(false); + setSendTokenInputsState({ isSendTokenInputDisabled: false, isUserSelectionDisabled: false }); dispatch(giveCoffeeActions.setShowModalSendToken(false)); }; @@ -133,7 +139,7 @@ function FooterProfile({ name, status, avatar, userId, isDM }: FooterProfileProp const tokenEvent: ApiTokenSentEvent = { sender_id: myProfile.userId as string, sender_name: myProfile?.userProfile?.user?.username as string, - receiver_id: infoSendToken?.receiver_id ?? userId, + receiver_id: userId, amount: token, note: note, extra_attribute: infoSendToken?.extra_attribute ?? extraAttribute @@ -142,7 +148,7 @@ function FooterProfile({ name, status, avatar, userId, isDM }: FooterProfileProp try { await dispatch(giveCoffeeActions.sendToken(tokenEvent)).unwrap(); dispatch(giveCoffeeActions.setSendTokenEvent({ tokenEvent: tokenEvent, status: TOKEN_SUCCESS_STATUS })); - await sendNotificationMessage(infoSendToken?.receiver_id ?? userId, token, note ?? ''); + await sendNotificationMessage(userId, token, note ?? ''); } catch (err) { dispatch(giveCoffeeActions.setSendTokenEvent({ tokenEvent: tokenEvent, status: TOKEN_FAILED_STATUS })); } @@ -180,7 +186,10 @@ function FooterProfile({ name, status, avatar, userId, isDM }: FooterProfileProp setSelectedUserId(infoSendToken.receiver_id ?? ''); setNote(infoSendToken.note ?? 'send token'); setExtraAttribute(infoSendToken.extra_attribute ?? ''); - setIsInputDisabled(infoSendToken.amount !== 0); + setSendTokenInputsState({ + isSendTokenInputDisabled: infoSendToken.amount !== 0, + isUserSelectionDisabled: infoSendToken.receiver_id !== '' + }); const timer = setTimeout(() => { handleClosePopup(); }, 10000); @@ -260,7 +269,7 @@ function FooterProfile({ name, status, avatar, userId, isDM }: FooterProfileProp userSearchError={userSearchError} userId={myProfile.userId as string} note={note} - isInputDisabled={isInputDisabled} + sendTokenInputsState={sendTokenInputsState} /> )} diff --git a/libs/components/src/lib/components/ModalUserProfile/StatusProfile/ModalSendToken.tsx b/libs/components/src/lib/components/ModalUserProfile/StatusProfile/ModalSendToken.tsx index 00b4d56f6a..f80eeeedbc 100644 --- a/libs/components/src/lib/components/ModalUserProfile/StatusProfile/ModalSendToken.tsx +++ b/libs/components/src/lib/components/ModalUserProfile/StatusProfile/ModalSendToken.tsx @@ -21,7 +21,10 @@ type ModalSendTokenProps = { userId: string; selectedUserId: string; note: string; - isInputDisabled: boolean; + sendTokenInputsState: { + isSendTokenInputDisabled: boolean; + isUserSelectionDisabled: boolean; + }; }; const ModalSendToken = ({ @@ -37,7 +40,7 @@ const ModalSendToken = ({ userId, selectedUserId, note, - isInputDisabled + sendTokenInputsState }: ModalSendTokenProps) => { const usersClan = useSelector(selectAllUserClans); const dmGroupChatList = useSelector(selectAllDirectMessages); @@ -160,7 +163,7 @@ const ModalSendToken = ({ value={searchTerm} onClick={() => setIsDropdownOpen(true)} onChange={handleChangeSearchTerm} - disabled={isInputDisabled} + disabled={sendTokenInputsState.isUserSelectionDisabled} /> {isDropdownOpen && (
{error &&

{error}

}
From 0c327a75dd7c389294c267b3a33910b6d4d5dd38 Mon Sep 17 00:00:00 2001 From: "thai.phamquoc" <110405911+Cut666@users.noreply.github.com> Date: Wed, 26 Feb 2025 11:40:00 +0700 Subject: [PATCH 4/5] fix bug login QR --- libs/store/src/lib/auth/auth.slice.ts | 2 ++ libs/transport/src/lib/contexts/MezonContext.tsx | 2 ++ 2 files changed, 4 insertions(+) diff --git a/libs/store/src/lib/auth/auth.slice.ts b/libs/store/src/lib/auth/auth.slice.ts index 247f8dd3de..8a4360354b 100644 --- a/libs/store/src/lib/auth/auth.slice.ts +++ b/libs/store/src/lib/auth/auth.slice.ts @@ -2,6 +2,7 @@ import { LoadingStatus } from '@mezon/utils'; import { createAsyncThunk, createSelector, createSlice } from '@reduxjs/toolkit'; import { Session } from 'mezon-js'; import { ensureClientAsync, getMezonCtx, restoreLocalStorage } from '../helpers'; +import { clearAllMemoizedFunctions } from '../memoize'; export const AUTH_FEATURE_KEY = 'auth'; export interface AuthState { @@ -95,6 +96,7 @@ export const logOut = createAsyncThunk('auth/logOut', async (_, thunkAPI) => { const mezon = getMezonCtx(thunkAPI); await mezon?.logOutMezon(); thunkAPI.dispatch(authActions.setLogout()); + clearAllMemoizedFunctions(); restoreLocalStorage(['persist:auth', 'persist:apps', 'persist:categories']); }); diff --git a/libs/transport/src/lib/contexts/MezonContext.tsx b/libs/transport/src/lib/contexts/MezonContext.tsx index 847a7b7ac0..26498cb0a9 100644 --- a/libs/transport/src/lib/contexts/MezonContext.tsx +++ b/libs/transport/src/lib/contexts/MezonContext.tsx @@ -75,6 +75,8 @@ const MezonContextProvider: React.FC = ({ children, m throw new Error('Mezon client not initialized'); } const session = await clientRef.current.checkLoginRequest(LoginRequest); + const socket = await createSocket(); + socketRef.current = socket; return session; }, []); From ea05dc7ac7c3eaec668fedfbe5ac32766f8a94c2 Mon Sep 17 00:00:00 2001 From: "phong.nguyen.nam" Date: Wed, 26 Feb 2025 13:01:18 +0700 Subject: [PATCH 5/5] fixed --- apps/chat/src/app/pages/main/index.tsx | 30 ++----------- .../MarkdownFormatText/ModalUnknowChannel.tsx | 44 ++++++++++--------- libs/store/src/lib/clans/clans.slice.ts | 1 - libs/store/src/lib/errors/errors.listener.ts | 4 +- libs/store/src/lib/toasts/toasts.slice.ts | 32 ++++++++------ 5 files changed, 47 insertions(+), 64 deletions(-) diff --git a/apps/chat/src/app/pages/main/index.tsx b/apps/chat/src/app/pages/main/index.tsx index f0bec4ad12..f922b939ad 100644 --- a/apps/chat/src/app/pages/main/index.tsx +++ b/apps/chat/src/app/pages/main/index.tsx @@ -52,7 +52,7 @@ import { selectSignalingDataByUserId, selectStatusMenu, selectTheme, - selectToastErrorStatus, + selectToastErrors, useAppDispatch, useAppSelector } from '@mezon/store'; @@ -276,35 +276,13 @@ function MyApp() { const handleClose = () => { dispatch(e2eeActions.setOpenModalE2ee(false)); }; - // show toast error - // Lấy danh sách lỗi từ Redux - const toastError = useSelector(selectToastErrorStatus); - // State quản lý danh sách modal lỗi đang mở - const [openErrors, setOpenErrors] = useState<{ id: number; message: string }[]>([]); - - // Khi có lỗi mới, thêm vào danh sách openErrors - useEffect(() => { - if (toastError.errors.length > 0) { - setOpenErrors((prev) => [ - ...prev, - ...toastError.errors.map((err, index) => ({ - id: Date.now() + index, - message: err.message - })) - ]); - } - }, [toastError.errors]); - - // Hàm đóng modal theo ID - const closeError = (id: number) => { - setOpenErrors((prev) => prev.filter((err) => err.id !== id)); - }; + const toastError = useSelector(selectToastErrors); return ( <> - {openErrors.map((error) => ( - closeError(error.id)} /> + {toastError.map((error) => ( + ))}
void; + onClose?: () => void; isError?: boolean; errMessage?: string; + idErr?: string; }; function ModalUnknowChannel(props: ModalUnknowChannelProps) { const dispatch = useDispatch(); - const { onClose, isError = false, errMessage } = props; - const navigate = useNavigate(); - - // const resetErrorToastStatus = () => { - // dispatch(toastActions.setToastError({ isActive: false, message: '' })); - // }; + const { onClose, isError = false, errMessage, idErr } = props; + const { toClanPage, navigate } = useAppNavigation(); + const removeToastError = () => { + if (idErr) { + dispatch(toastActions.removeToastError(idErr)); + } + }; + const clearAllToastError = () => { + dispatch(toastActions.clearAllToastErrors()); + }; const directToWelcomeChannel = async () => { - // resetErrorToastStatus(); - + clearAllToastError(); const store = await getStoreAsync(); const currentClanId = selectCurrentClanId(store.getState() as RootState); - if (!currentClanId) { + if (!currentClanId || currentClanId === '0') { navigate(FRIEND_PAGE_LINK); return; } const welcomeChannelId = selectWelcomeChannelByClanId(store.getState(), currentClanId); if (welcomeChannelId) { + navigate(toClanPage(currentClanId)); navigate(toChannelPage(welcomeChannelId, currentClanId)); return; } - - navigate(toMembersPage(currentClanId)); }; const onCloseAndReset = () => { - onClose(); if (isError) { - // resetErrorToastStatus(); + removeToastError(); } + onClose?.(); }; return ( -
+
-
+
{isError ? ( -

+

{errMessage ? errMessage : 'Oops! Something Went Wrong'} -
+ ) : ( <>

You don't have access to this link.

diff --git a/libs/store/src/lib/clans/clans.slice.ts b/libs/store/src/lib/clans/clans.slice.ts index be59c02502..1f7c584cca 100644 --- a/libs/store/src/lib/clans/clans.slice.ts +++ b/libs/store/src/lib/clans/clans.slice.ts @@ -290,7 +290,6 @@ interface JoinClanPayload { clanId: string; } export const joinClan = createAsyncThunk('direct/joinClan', async ({ clanId }, thunkAPI) => { - console.log('joinClan', clanId); try { const mezon = await ensureSocket(getMezonCtx(thunkAPI)); await mezon.socketRef.current?.joinClanChat(clanId); diff --git a/libs/store/src/lib/errors/errors.listener.ts b/libs/store/src/lib/errors/errors.listener.ts index 417f823b88..e2671724d4 100644 --- a/libs/store/src/lib/errors/errors.listener.ts +++ b/libs/store/src/lib/errors/errors.listener.ts @@ -123,11 +123,9 @@ errorListenerMiddleware.startListening({ if (!toast) { return; } - console.log('toast: ', toast); if (toast.type === 'error') { listenerApi.dispatch( - toastActions.setToastError({ - status: true, + toastActions.addToastError({ message: toast.message as string }) ); diff --git a/libs/store/src/lib/toasts/toasts.slice.ts b/libs/store/src/lib/toasts/toasts.slice.ts index c0938f42f7..d17cd49e2e 100644 --- a/libs/store/src/lib/toasts/toasts.slice.ts +++ b/libs/store/src/lib/toasts/toasts.slice.ts @@ -9,7 +9,7 @@ const toastsAdapter = createEntityAdapter(); const initialState = { ...toastsAdapter.getInitialState(), - toastError: { status: false, errors: [] as { message: string }[] } + toastErrors: [] as { id: string; message: string }[] }; const addToast = createAsyncThunk( 'toasts/addToast', @@ -62,32 +62,38 @@ export const toastsSlice = createSlice({ clearToasts: (state) => { toastsAdapter.removeAll(state); }, - setToastError: (state, action: PayloadAction<{ status: boolean; message: string }>) => { - state.toastError.status = action.payload.status; - if (action.payload.status) { - state.toastError.errors.push({ message: action.payload.message }); - } else { - state.toastError.errors = []; + addToastError: (state, action: PayloadAction<{ message?: string }>) => { + const message = action.payload.message; + if (!message || state.toastErrors.find((error) => error.message === message)) { + return; } + const id = Date.now().toString(); + state.toastErrors.push({ id, message }); + }, + removeToastError: (state, action: PayloadAction) => { + state.toastErrors = state.toastErrors.filter((error) => error.id !== action.payload); + }, + clearAllToastErrors: (state) => { + state.toastErrors = []; } } }); -export const { addOneToast, removeToast, clearToasts, setToastError } = toastsSlice.actions; +export const { addOneToast, removeToast, clearToasts, addToastError, removeToastError, clearAllToastErrors } = toastsSlice.actions; export const toastActions = { addToast, removeToast, clearToasts, - setToastError + addToastError, + removeToastError, + clearAllToastErrors }; // Create selectors using the adapter's getSelectors method export const { selectAll: selectToasts, selectById: selectToastById } = toastsAdapter.getSelectors( (state: { toasts: typeof initialState }) => state.toasts ); -export const selectToastErrorStatus = createSelector( - [(state: { toasts: typeof initialState }) => state.toasts], - (toastsState) => toastsState.toastError -); +export const selectToastErrors = createSelector([(state: { toasts: typeof initialState }) => state.toasts], (toastsState) => toastsState.toastErrors); + export const toastsReducer = toastsSlice.reducer;