refactor: lots updates
This commit is contained in:
+11
-1
@@ -2,6 +2,7 @@ import { useState } from "react";
|
||||
import localforage from "localforage";
|
||||
import { useDispatch, batch } from "react-redux";
|
||||
import { fullfillReactionMessage } from "./slices/message.reaction";
|
||||
import { fullfillServer } from "./slices/server";
|
||||
import { fullfillMessage } from "./slices/message";
|
||||
import { fullfillChannelMsg } from "./slices/message.channel";
|
||||
import { fullfillUserMsg } from "./slices/message.user";
|
||||
@@ -38,6 +39,10 @@ const tables = [
|
||||
storeName: "footprint",
|
||||
description: "store user visit data",
|
||||
},
|
||||
{
|
||||
storeName: "server",
|
||||
description: "store server data",
|
||||
},
|
||||
// {
|
||||
// storeName: "message",
|
||||
// description: "store message with key-val full data",
|
||||
@@ -67,6 +72,7 @@ export const useRehydrate = () => {
|
||||
reactionMessage: {},
|
||||
message: { replying: {} },
|
||||
footprint: {},
|
||||
server: {},
|
||||
};
|
||||
const tables = Object.keys(window.CACHE);
|
||||
const results = await Promise.all(
|
||||
@@ -95,6 +101,9 @@ export const useRehydrate = () => {
|
||||
case "message":
|
||||
rehydrateData.message[key] = data;
|
||||
break;
|
||||
case "server":
|
||||
rehydrateData.server[key] = data;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
@@ -104,6 +113,7 @@ export const useRehydrate = () => {
|
||||
);
|
||||
batch(() => {
|
||||
dispatch(fullfillContacts(rehydrateData.contacts));
|
||||
dispatch(fullfillServer(rehydrateData.server));
|
||||
console.log("fullfill channels from indexedDB");
|
||||
dispatch(fullfillChannels(rehydrateData.channels));
|
||||
dispatch(fullfillChannelMsg(rehydrateData.channelMessage));
|
||||
@@ -114,7 +124,7 @@ export const useRehydrate = () => {
|
||||
});
|
||||
|
||||
setIterated(true);
|
||||
// console.log("iterate results", rehydrateData, results);
|
||||
console.log("iterate results", rehydrateData, results);
|
||||
};
|
||||
return { rehydrate, rehydrated: iterated };
|
||||
};
|
||||
|
||||
@@ -5,6 +5,8 @@ export const ContentTypes = {
|
||||
text: "text/plain",
|
||||
markdown: "text/markdown",
|
||||
image: "image/png",
|
||||
imageJPG: "image/jpeg",
|
||||
file: "rustchat/file",
|
||||
json: "application/json",
|
||||
};
|
||||
export const googleClientID =
|
||||
@@ -15,7 +17,9 @@ export const KEY_TOKEN = "RUSTCHAT_TOKEN";
|
||||
export const KEY_EXPIRE = "RUSTCHAT_TOKEN_EXPIRE";
|
||||
export const KEY_REFRESH_TOKEN = "RUSTCHAT_REFRESH_TOKEN";
|
||||
export const KEY_UID = "RUSTCHAT_CURR_UID";
|
||||
export const KEY_DEVICE_KEY = "RUSTCHAT_DEVICE_KEY";
|
||||
export const KEY_USERS_VERSION = "RUSTCHAT_USERS_VERSION";
|
||||
export const KEY_AFTER_MID = "RUSTCHAT_AFTER_MID";
|
||||
export const Emojis = ["👍", "❤️", "😄", "👀", "👎", "🎉", "🙁", "🚀"];
|
||||
|
||||
export default BASE_URL;
|
||||
|
||||
@@ -27,6 +27,16 @@ export default async function handler({ operation, data = {}, payload }) {
|
||||
await table.setItem("afterMid", afterMid);
|
||||
}
|
||||
break;
|
||||
case "updateReadChannels":
|
||||
{
|
||||
await table.setItem("readChannels", data.readChannels);
|
||||
}
|
||||
break;
|
||||
case "updateReadUsers":
|
||||
{
|
||||
await table.setItem("readUsers", data.readUsers);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
// import clearTable from "./clear.handler";
|
||||
import { updateOnline } from "../slices/ui";
|
||||
export default async function handler({ dispatch, operation }) {
|
||||
switch (operation) {
|
||||
case "offline":
|
||||
{
|
||||
dispatch(updateOnline(false));
|
||||
}
|
||||
break;
|
||||
case "online":
|
||||
{
|
||||
dispatch(updateOnline(true));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import clearTable from "./clear.handler";
|
||||
export default async function handler({ operation, payload }) {
|
||||
const table = window.CACHE["server"];
|
||||
if (operation.startsWith("reset")) {
|
||||
clearTable("server");
|
||||
return;
|
||||
}
|
||||
switch (operation) {
|
||||
case "updateInviteLink":
|
||||
{
|
||||
const data = payload;
|
||||
await table.setItem("inviteLink", data);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,15 @@
|
||||
import { createListenerMiddleware } from "@reduxjs/toolkit";
|
||||
import rtkqHandler from "./handler.rtkq";
|
||||
import channelsHandler from "./handler.channels";
|
||||
import contactsHandler from "./handler.contacts";
|
||||
import channelMsgHandler from "./handler.channel.msg";
|
||||
import dmMsgHandler from "./handler.dm.msg";
|
||||
import serverHandler from "./handler.server";
|
||||
import messageHandler from "./handler.message";
|
||||
import reactionHandler from "./handler.reaction";
|
||||
import footprintHandler from "./handler.footprint";
|
||||
const operations = [
|
||||
"__rtkq",
|
||||
"channels",
|
||||
"channelMessage",
|
||||
"contacts",
|
||||
@@ -24,23 +27,29 @@ const listenerMiddleware = createListenerMiddleware();
|
||||
listenerMiddleware.startListening({
|
||||
predicate: (action, currentState, previousState) => {
|
||||
const { type = "" } = action;
|
||||
console.log("operation", type);
|
||||
const [prefix] = type.split("/");
|
||||
console.log("operation", type, operations.includes(prefix));
|
||||
return operations.includes(prefix);
|
||||
// console.log("listener predicate", action, currentState, previousState);
|
||||
// return true;
|
||||
},
|
||||
effect: async (action, listenerApi) => {
|
||||
if (!window.CACHE) return;
|
||||
const { type = "", payload } = action;
|
||||
// const key = getCacheKey(type);
|
||||
// // console.log("listener effect", key, listenerApi.getState(), window.CACHE);
|
||||
// if (key && window.CACHE) {
|
||||
// await window.CACHE.setItem(key, listenerApi.getState()[key]);
|
||||
// }
|
||||
const [prefix, operation] = type.split("/");
|
||||
console.log("effect opt", action);
|
||||
if (!window.CACHE && prefix !== "__rtkq") return;
|
||||
|
||||
const state = listenerApi.getState()[prefix];
|
||||
switch (prefix) {
|
||||
case "__rtkq":
|
||||
{
|
||||
rtkqHandler({
|
||||
operation,
|
||||
payload,
|
||||
dispatch: listenerApi.dispatch,
|
||||
});
|
||||
}
|
||||
break;
|
||||
case "channels":
|
||||
{
|
||||
await channelsHandler({
|
||||
@@ -104,6 +113,15 @@ listenerMiddleware.startListening({
|
||||
});
|
||||
}
|
||||
break;
|
||||
case "server":
|
||||
{
|
||||
await serverHandler({
|
||||
operation,
|
||||
payload,
|
||||
data: state,
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -1,6 +1,15 @@
|
||||
import { createApi } from "@reduxjs/toolkit/query/react";
|
||||
import { nanoid } from "@reduxjs/toolkit";
|
||||
import baseQuery from "./base.query";
|
||||
import BASE_URL from "../config";
|
||||
import BASE_URL, { KEY_DEVICE_KEY } from "../config";
|
||||
const getDeviceId = () => {
|
||||
let d = localStorage.getItem(KEY_DEVICE_KEY);
|
||||
if (!d) {
|
||||
d = `web:${nanoid()}`;
|
||||
localStorage.setItem(KEY_DEVICE_KEY, d);
|
||||
}
|
||||
return d;
|
||||
};
|
||||
export const authApi = createApi({
|
||||
reducerPath: "authApi",
|
||||
baseQuery,
|
||||
@@ -9,7 +18,11 @@ export const authApi = createApi({
|
||||
query: (credentials) => ({
|
||||
url: "token/login",
|
||||
method: "POST",
|
||||
body: { credential: credentials, device: "web", device_token: "test" },
|
||||
body: {
|
||||
credential: credentials,
|
||||
device: getDeviceId(),
|
||||
device_token: "test",
|
||||
},
|
||||
}),
|
||||
transformResponse: (data) => {
|
||||
const { avatar_updated_at } = data.user;
|
||||
|
||||
@@ -5,6 +5,7 @@ import { updateToken, resetAuthData } from "../slices/auth.data";
|
||||
import BASE_URL, { tokenHeader } from "../config";
|
||||
const whiteList = [
|
||||
"login",
|
||||
"register",
|
||||
"checkInviteTokenValid",
|
||||
"getServer",
|
||||
"getOpenid",
|
||||
@@ -64,8 +65,13 @@ const baseQueryWithTokenCheck = async (args, api, extraOptions) => {
|
||||
result = await baseQuery(args, api, extraOptions);
|
||||
}
|
||||
if (result?.error) {
|
||||
console.log("api error", result.error.originalStatus, api.endpoint);
|
||||
console.log("api error", result.error, api.endpoint);
|
||||
switch (result.error.originalStatus || result.error.status) {
|
||||
case "FETCH_ERROR":
|
||||
{
|
||||
toast.error(`${api.endpoint}: Failed to fetch`);
|
||||
}
|
||||
break;
|
||||
case 404:
|
||||
{
|
||||
toast.error("Request Not Found");
|
||||
@@ -84,7 +90,7 @@ const baseQueryWithTokenCheck = async (args, api, extraOptions) => {
|
||||
location.href = "/#/login";
|
||||
// } else {
|
||||
toast.error("API Not Authenticated");
|
||||
return;
|
||||
// return;
|
||||
// }
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -61,6 +61,13 @@ export const channelApi = createApi({
|
||||
await onMessageSendStarted.call(this, param1, param2, "channel");
|
||||
},
|
||||
}),
|
||||
addMembers: builder.mutation({
|
||||
query: ({ id, members }) => ({
|
||||
url: `group/${id}/members/add`,
|
||||
method: "POST",
|
||||
body: members,
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -71,4 +78,5 @@ export const {
|
||||
useGetChannelsQuery,
|
||||
useCreateChannelMutation,
|
||||
useSendChannelMsgMutation,
|
||||
useAddMembersMutation,
|
||||
} = channelApi;
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import { createApi } from "@reduxjs/toolkit/query/react";
|
||||
import { batch } from "react-redux";
|
||||
|
||||
import { ContentTypes } from "../config";
|
||||
import { updateReadChannels, updateReadUsers } from "../slices/footprint";
|
||||
import { onMessageSendStarted } from "./handlers";
|
||||
|
||||
// import { updateMessage } from "../slices/message";
|
||||
@@ -48,6 +51,36 @@ export const messageApi = createApi({
|
||||
await onMessageSendStarted.call(this, param1, param2, param1.context);
|
||||
},
|
||||
}),
|
||||
readMessage: builder.mutation({
|
||||
query: (data) => ({
|
||||
url: `/user/read-index`,
|
||||
method: "POST",
|
||||
body: data,
|
||||
}),
|
||||
async onQueryStarted(data, { dispatch, getState, queryFulfilled }) {
|
||||
const { users = [], groups = [] } = data;
|
||||
const { readUsers, readChannels } = getState().footprint.readUsers;
|
||||
const prevUsers = users.map(({ uid }) => {
|
||||
return { uid, mid: readUsers[uid] };
|
||||
});
|
||||
const prevChannels = users.map(({ gid }) => {
|
||||
return { gid, mid: readChannels[gid] };
|
||||
});
|
||||
batch(() => {
|
||||
dispatch(updateReadChannels(groups));
|
||||
dispatch(updateReadUsers(users));
|
||||
});
|
||||
try {
|
||||
await queryFulfilled;
|
||||
} catch {
|
||||
// todo
|
||||
batch(() => {
|
||||
dispatch(updateReadChannels(prevChannels));
|
||||
dispatch(updateReadUsers(prevUsers));
|
||||
});
|
||||
}
|
||||
},
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -56,4 +89,5 @@ export const {
|
||||
useReactMessageMutation,
|
||||
useReplyMessageMutation,
|
||||
useLazyDeleteMessageQuery,
|
||||
useReadMessageMutation,
|
||||
} = messageApi;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { createApi } from "@reduxjs/toolkit/query/react";
|
||||
import BASE_URL from "../config";
|
||||
|
||||
import { updateInviteLink } from "../slices/server";
|
||||
import baseQuery from "./base.query";
|
||||
|
||||
export const serverApi = createApi({
|
||||
@@ -57,6 +57,29 @@ export const serverApi = createApi({
|
||||
body: data,
|
||||
}),
|
||||
}),
|
||||
createInviteLink: builder.query({
|
||||
query: (expired_in = 7 * 24 * 60 * 60) => ({
|
||||
headers: {
|
||||
"content-type": "text/plain",
|
||||
accept: "text/plain",
|
||||
},
|
||||
url: `/admin/user/create_invite_link?expired_in=${expired_in}`,
|
||||
responseHandler: (response) => response.text(),
|
||||
}),
|
||||
async onQueryStarted(expire, { dispatch, queryFulfilled, getState }) {
|
||||
const {
|
||||
expire: prevExp,
|
||||
link: prevLink,
|
||||
} = getState().server.inviteLink;
|
||||
try {
|
||||
const { data: link } = await queryFulfilled;
|
||||
console.log("link", link);
|
||||
dispatch(updateInviteLink({ expire, link }));
|
||||
} catch {
|
||||
dispatch(updateInviteLink({ expire: prevExp, link: prevLink }));
|
||||
}
|
||||
},
|
||||
}),
|
||||
updateServer: builder.mutation({
|
||||
query: (data) => ({
|
||||
url: `admin/system/organization`,
|
||||
@@ -79,4 +102,5 @@ export const {
|
||||
useLazyGetServerQuery,
|
||||
useUpdateServerMutation,
|
||||
useUpdateLogoMutation,
|
||||
useLazyCreateInviteLinkQuery,
|
||||
} = serverApi;
|
||||
|
||||
@@ -35,13 +35,14 @@ const handler = (data, dispatch, currState) => {
|
||||
dispatch(updateAfterMid(mid));
|
||||
break;
|
||||
}
|
||||
const { ready, loginUid } = currState;
|
||||
const { ready, loginUid, readUsers = {}, readChannels = {} } = currState;
|
||||
const to = typeof target.gid !== "undefined" ? "channel" : "user";
|
||||
const appendMessage = to == "user" ? addUserMsg : addChannelMsg;
|
||||
const self = from_uid == loginUid;
|
||||
// 此处有点绕
|
||||
const id = to == "user" ? (self ? target.uid : from_uid) : target.gid;
|
||||
|
||||
const readIndex = (to == "user" ? readUsers[id] : readChannels[id]) || 0;
|
||||
const read = self ? true : mid < readIndex ? true : false;
|
||||
switch (type) {
|
||||
case "normal":
|
||||
{
|
||||
@@ -50,7 +51,7 @@ const handler = (data, dispatch, currState) => {
|
||||
addMessage({
|
||||
mid,
|
||||
// 如果是自己发的消息,就是已读
|
||||
read: self,
|
||||
read,
|
||||
...common,
|
||||
})
|
||||
);
|
||||
@@ -70,7 +71,7 @@ const handler = (data, dispatch, currState) => {
|
||||
mid,
|
||||
reply_mid: detailMid,
|
||||
// 如果是自己发的消息,就是已读
|
||||
read: self,
|
||||
read,
|
||||
...common,
|
||||
})
|
||||
);
|
||||
|
||||
@@ -9,7 +9,11 @@ import {
|
||||
addChannel,
|
||||
removeChannel,
|
||||
} from "../../slices/channels";
|
||||
import { updateUsersVersion } from "../../slices/footprint";
|
||||
import {
|
||||
updateUsersVersion,
|
||||
updateReadChannels,
|
||||
updateReadUsers,
|
||||
} from "../../slices/footprint";
|
||||
import { updateUsersByLogs, updateUsersStatus } from "../../slices/contacts";
|
||||
import { resetAuthData } from "../../slices/auth.data";
|
||||
import baseQuery from "../base.query";
|
||||
@@ -58,6 +62,7 @@ export const streamingApi = createApi({
|
||||
const {
|
||||
ui: { ready },
|
||||
authData: { uid: loginUid },
|
||||
footprint: { readUsers, readChannels },
|
||||
} = getState();
|
||||
const data = JSON.parse(evt.data);
|
||||
const { type } = data;
|
||||
@@ -83,6 +88,18 @@ export const streamingApi = createApi({
|
||||
dispatch(updateUsersByLogs(logs));
|
||||
}
|
||||
break;
|
||||
case "user_settings":
|
||||
case "user_settings_changed":
|
||||
{
|
||||
console.log("users settings");
|
||||
const {
|
||||
read_index_users = [],
|
||||
read_index_groups = [],
|
||||
} = data;
|
||||
dispatch(updateReadChannels(read_index_groups));
|
||||
dispatch(updateReadUsers(read_index_users));
|
||||
}
|
||||
break;
|
||||
case "users_state":
|
||||
case "users_state_changed":
|
||||
{
|
||||
@@ -123,7 +140,12 @@ export const streamingApi = createApi({
|
||||
break;
|
||||
case "chat":
|
||||
{
|
||||
chatMessageHandler(data, dispatch, { ready, loginUid });
|
||||
chatMessageHandler(data, dispatch, {
|
||||
ready,
|
||||
loginUid,
|
||||
readUsers,
|
||||
readChannels,
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -132,8 +154,8 @@ export const streamingApi = createApi({
|
||||
break;
|
||||
}
|
||||
};
|
||||
streaming.onopen = () => {
|
||||
console.info("sse opened");
|
||||
streaming.onopen = (wtf) => {
|
||||
console.info("sse opened", wtf);
|
||||
};
|
||||
streaming.onerror = (err) => {
|
||||
switch (err.eventPhase) {
|
||||
@@ -148,6 +170,7 @@ export const streamingApi = createApi({
|
||||
break;
|
||||
|
||||
default:
|
||||
streaming.close();
|
||||
console.error("sse error error", err);
|
||||
// renewToken({ token, refreshToken });
|
||||
break;
|
||||
|
||||
@@ -6,6 +6,12 @@ const initialState = {
|
||||
expireTime: localStorage.getItem(KEY_EXPIRE) || new Date().getTime(),
|
||||
refreshToken: localStorage.getItem(KEY_REFRESH_TOKEN),
|
||||
};
|
||||
const emptyState = {
|
||||
uid: null,
|
||||
token: null,
|
||||
expireTime: new Date().getTime(),
|
||||
refreshToken: null,
|
||||
};
|
||||
const authDataSlice = createSlice({
|
||||
name: "authData",
|
||||
initialState,
|
||||
@@ -37,7 +43,7 @@ const authDataSlice = createSlice({
|
||||
localStorage.removeItem(KEY_TOKEN);
|
||||
localStorage.removeItem(KEY_REFRESH_TOKEN);
|
||||
localStorage.removeItem(KEY_UID);
|
||||
return initialState;
|
||||
return emptyState;
|
||||
},
|
||||
setUid(state, action) {
|
||||
const uid = action.payload;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { createSlice } from "@reduxjs/toolkit";
|
||||
import { getNonNullValues } from "../../common/utils";
|
||||
import BASE_URL from "../config";
|
||||
const initialState = {
|
||||
ids: [],
|
||||
byId: {},
|
||||
@@ -37,6 +38,11 @@ const contactsSlice = createSlice({
|
||||
if (state.byId[uid]) {
|
||||
Object.keys(vals).forEach((k) => {
|
||||
state.byId[uid][k] = vals[k];
|
||||
if (k == "avatar_updated_at") {
|
||||
state.byId[
|
||||
uid
|
||||
].avatar = `${BASE_URL}/resource/avatar?uid=${uid}&t=${vals[k]}`;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ import { createSlice } from "@reduxjs/toolkit";
|
||||
const initialState = {
|
||||
usersVersion: 0,
|
||||
afterMid: 0,
|
||||
readUsers: {},
|
||||
readChannels: {},
|
||||
};
|
||||
const footprintSlice = createSlice({
|
||||
name: "footprint",
|
||||
@@ -11,7 +13,13 @@ const footprintSlice = createSlice({
|
||||
return initialState;
|
||||
},
|
||||
fullfillFootprint(state, action) {
|
||||
return action.payload;
|
||||
const {
|
||||
usersVersion = 0,
|
||||
afterMid = 0,
|
||||
readUsers = {},
|
||||
readChannels = {},
|
||||
} = action.payload;
|
||||
return { usersVersion, afterMid, readUsers, readChannels };
|
||||
},
|
||||
updateUsersVersion(state, action) {
|
||||
const usersVersion = action.payload;
|
||||
@@ -21,6 +29,20 @@ const footprintSlice = createSlice({
|
||||
const afterMid = action.payload;
|
||||
state.afterMid = afterMid;
|
||||
},
|
||||
updateReadUsers(state, action) {
|
||||
const reads = action.payload || [];
|
||||
if (reads.length == 0) return;
|
||||
reads.forEach(({ uid, mid }) => {
|
||||
state.readUsers[uid] = mid;
|
||||
});
|
||||
},
|
||||
updateReadChannels(state, action) {
|
||||
const reads = action.payload || [];
|
||||
if (reads.length == 0) return;
|
||||
reads.forEach(({ gid, mid }) => {
|
||||
state.readChannels[gid] = mid;
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
export const {
|
||||
@@ -28,5 +50,7 @@ export const {
|
||||
fullfillFootprint,
|
||||
updateAfterMid,
|
||||
updateUsersVersion,
|
||||
updateReadChannels,
|
||||
updateReadUsers,
|
||||
} = footprintSlice.actions;
|
||||
export default footprintSlice.reducer;
|
||||
|
||||
@@ -15,9 +15,9 @@ const channelMsgSlice = createSlice({
|
||||
const { id, mid } = action.payload;
|
||||
if (state[id]) {
|
||||
if (state[id].findIndex((id) => id == mid) > -1) return;
|
||||
state[id].push(mid);
|
||||
state[id].push(+mid);
|
||||
} else {
|
||||
state[id] = [mid];
|
||||
state[id] = [+mid];
|
||||
}
|
||||
},
|
||||
removeChannelMsg(state, action) {
|
||||
|
||||
@@ -22,6 +22,10 @@ const reactionMessageSlice = createSlice({
|
||||
const idx = reactionUids.findIndex((id) => id == from_uid);
|
||||
if (idx > -1) {
|
||||
reactionUids.splice(idx, 1);
|
||||
if (reactionUids.length == 0) {
|
||||
// 没有表情了
|
||||
delete state[mid][reaction];
|
||||
}
|
||||
} else {
|
||||
reactionUids.push(from_uid);
|
||||
}
|
||||
|
||||
@@ -18,10 +18,10 @@ const userMsgSlice = createSlice({
|
||||
const { id, mid } = action.payload;
|
||||
if (state.byId[id]) {
|
||||
if (state.byId[id].findIndex((id) => id == mid) > -1) return;
|
||||
state.byId[id].push(mid);
|
||||
state.byId[id].push(+mid);
|
||||
} else {
|
||||
state.byId[id] = [mid];
|
||||
state.ids.push(id);
|
||||
state.byId[id] = [+mid];
|
||||
state.ids.push(+id);
|
||||
}
|
||||
},
|
||||
removeUserMsg(state, action) {
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
import { createSlice } from "@reduxjs/toolkit";
|
||||
const initialState = {
|
||||
inviteLink: {
|
||||
link: "",
|
||||
expire: 0,
|
||||
},
|
||||
};
|
||||
const serverSlice = createSlice({
|
||||
name: "server",
|
||||
initialState,
|
||||
reducers: {
|
||||
resetServer() {
|
||||
return initialState;
|
||||
},
|
||||
fullfillServer(state, action) {
|
||||
const {
|
||||
inviteLink = {
|
||||
link: "",
|
||||
expire: 0,
|
||||
},
|
||||
} = action.payload;
|
||||
return { inviteLink };
|
||||
},
|
||||
updateInviteLink(state, action) {
|
||||
const { link, expire = 7 * 24 * 60 * 60 } = action.payload;
|
||||
state.inviteLink = { link, expire };
|
||||
},
|
||||
},
|
||||
});
|
||||
export const {
|
||||
resetServer,
|
||||
fullfillServer,
|
||||
updateInviteLink,
|
||||
} = serverSlice.actions;
|
||||
export default serverSlice.reducer;
|
||||
@@ -1,6 +1,7 @@
|
||||
import { createSlice } from "@reduxjs/toolkit";
|
||||
|
||||
const initialState = {
|
||||
online: true,
|
||||
ready: false,
|
||||
menuExpand: true,
|
||||
setting: false,
|
||||
@@ -13,6 +14,9 @@ const uiSlice = createSlice({
|
||||
setReady(state) {
|
||||
state.ready = true;
|
||||
},
|
||||
updateOnline(state, action) {
|
||||
state.online = action.payload;
|
||||
},
|
||||
toggleMenuExpand(state) {
|
||||
state.menuExpand = !state.menuExpand;
|
||||
},
|
||||
@@ -28,6 +32,7 @@ const uiSlice = createSlice({
|
||||
});
|
||||
export const {
|
||||
setReady,
|
||||
updateOnline,
|
||||
toggleSetting,
|
||||
toggleMenuExpand,
|
||||
toggleChannelSetting,
|
||||
|
||||
+44
-1
@@ -3,6 +3,7 @@ import { setupListeners } from "@reduxjs/toolkit/query";
|
||||
import listenerMiddleware from "./listener.middleware";
|
||||
import authDataReducer from "./slices/auth.data";
|
||||
import footprintReducer from "./slices/footprint";
|
||||
import serverReducer from "./slices/server";
|
||||
import uiReducer from "./slices/ui";
|
||||
import channelsReducer from "./slices/channels";
|
||||
import contactsReducer from "./slices/contacts";
|
||||
@@ -21,6 +22,7 @@ const reducer = combineReducers({
|
||||
authData: authDataReducer,
|
||||
ui: uiReducer,
|
||||
footprint: footprintReducer,
|
||||
server: serverReducer,
|
||||
contacts: contactsReducer,
|
||||
channels: channelsReducer,
|
||||
reactionMessage: reactionMsgReducer,
|
||||
@@ -49,5 +51,46 @@ const store = configureStore({
|
||||
)
|
||||
.prepend(listenerMiddleware.middleware),
|
||||
});
|
||||
setupListeners(store.dispatch);
|
||||
let initialized = false;
|
||||
setupListeners(
|
||||
store.dispatch,
|
||||
(dispatch, { onOnline, onOffline, onFocus, onFocusLost }) => {
|
||||
const handleFocus = () => dispatch(onFocus());
|
||||
const handleFocusLost = () => dispatch(onFocusLost());
|
||||
const handleOnline = () => dispatch(onOnline());
|
||||
const handleOffline = () => dispatch(onOffline());
|
||||
const handleVisibilityChange = () => {
|
||||
if (window.document.visibilityState === "visible") {
|
||||
handleFocus();
|
||||
} else {
|
||||
handleFocusLost();
|
||||
}
|
||||
};
|
||||
|
||||
if (!initialized) {
|
||||
if (typeof window !== "undefined" && window.addEventListener) {
|
||||
// Handle focus events
|
||||
window.addEventListener(
|
||||
"visibilitychange",
|
||||
handleVisibilityChange,
|
||||
false
|
||||
);
|
||||
window.addEventListener("focus", handleFocus, false);
|
||||
|
||||
// Handle connection events
|
||||
window.addEventListener("online", handleOnline, false);
|
||||
window.addEventListener("offline", handleOffline, false);
|
||||
initialized = true;
|
||||
}
|
||||
}
|
||||
const unsubscribe = () => {
|
||||
window.removeEventListener("focus", handleFocus);
|
||||
window.removeEventListener("visibilitychange", handleVisibilityChange);
|
||||
window.removeEventListener("online", handleOnline);
|
||||
window.removeEventListener("offline", handleOffline);
|
||||
initialized = false;
|
||||
};
|
||||
return unsubscribe;
|
||||
}
|
||||
);
|
||||
export default store;
|
||||
|
||||
Reference in New Issue
Block a user