refactor: rename contact with user

This commit is contained in:
Tristan Yang
2022-07-04 16:12:23 +08:00
parent 6083040e2b
commit 101dbdb5ee
76 changed files with 319 additions and 286 deletions
+2 -2
View File
@@ -8,8 +8,8 @@ const tables = [
description: "store channel list"
},
{
storeName: "contacts",
description: "store contact list"
storeName: "users",
description: "store user list"
},
{
storeName: "messageDM",
+5 -5
View File
@@ -6,7 +6,7 @@ import { fullfillMessage } from "../slices/message";
import { fullfillChannelMsg } from "../slices/message.channel";
import { fullfillUserMsg } from "../slices/message.user";
import { fullfillChannels } from "../slices/channels";
import { fullfillContacts } from "../slices/contacts";
import { fullfillContacts } from "../slices/users";
import { fullfillFootprint } from "../slices/footprint";
import { fullfillFileMessage } from "../slices/message.file";
import { fullfillUI } from "../slices/ui";
@@ -17,7 +17,7 @@ const useRehydrate = () => {
const rehydrate = async () => {
const rehydrateData = {
channels: [],
contacts: [],
users: [],
fileMessage: {},
channelMessage: {},
userMessage: {},
@@ -38,9 +38,9 @@ const useRehydrate = () => {
rehydrateData.channels.push(data);
}
break;
case "contacts":
case "users":
if (data) {
rehydrateData.contacts.push(data);
rehydrateData.users.push(data);
}
break;
case "footprint":
@@ -75,7 +75,7 @@ const useRehydrate = () => {
})
);
batch(() => {
dispatch(fullfillContacts(rehydrateData.contacts));
dispatch(fullfillContacts(rehydrateData.users));
dispatch(fullfillServer(rehydrateData.server));
console.log("fullfill channels from indexedDB");
dispatch(fullfillChannels(rehydrateData.channels));
@@ -1,17 +1,17 @@
import clearTable from "./clear.handler";
export default async function handler({ operation, data, payload }) {
const table = window.CACHE["contacts"];
const table = window.CACHE["users"];
if (operation.startsWith("reset")) {
clearTable("contacts");
clearTable("users");
return;
}
switch (operation) {
case "fullfillContacts":
{
const contacts = payload;
const users = payload;
await Promise.all(
contacts.map(({ uid, ...rest }) => {
users.map(({ uid, ...rest }) => {
return table.setItem(uid + "", { uid, ...rest });
})
);
+4 -4
View File
@@ -1,7 +1,7 @@
import { createListenerMiddleware } from "@reduxjs/toolkit";
import rtkqHandler from "./handler.rtkq";
import channelsHandler from "./handler.channels";
import contactsHandler from "./handler.contacts";
import usersHandler from "./handler.users";
import channelMsgHandler from "./handler.channel.msg";
import dmMsgHandler from "./handler.dm.msg";
import serverHandler from "./handler.server";
@@ -15,7 +15,7 @@ const operations = [
"__rtkq",
"channels",
"channelMessage",
"contacts",
"users",
"userMessage",
"reactionMessage",
"fileMessage",
@@ -65,9 +65,9 @@ listenerMiddleware.startListening({
});
}
break;
case "contacts":
case "users":
{
await contactsHandler({
await usersHandler({
operation,
payload,
data: state
+2 -1
View File
@@ -3,6 +3,7 @@ import toast from "react-hot-toast";
import dayjs from "dayjs";
import { updateToken, resetAuthData } from "../slices/auth.data";
import BASE_URL, { tokenHeader } from "../config";
import { RootState } from "../store";
const whiteList = [
"login",
@@ -28,7 +29,7 @@ const baseQuery = fetchBaseQuery({
baseUrl: BASE_URL,
prepareHeaders: (headers, { getState, endpoint }) => {
console.log("req", endpoint);
const { token } = getState().authData;
const { token } = (getState() as RootState).authData;
if (token && !whiteList.includes(endpoint)) {
headers.set(tokenHeader, token);
}
+12 -11
View File
@@ -9,19 +9,20 @@ import { removeChannelSession } from "../slices/message.channel";
import { removeReactionMessage } from "../slices/message.reaction";
import { onMessageSendStarted } from "./handlers";
import handleChatMessage from "../../common/hook/useStreaming/chat.handler";
import { Channel, CreateChannelDTO } from "../../types/channel";
import { RootState } from "../store";
export const channelApi = createApi({
reducerPath: "channelApi",
baseQuery,
refetchOnFocus: true,
endpoints: (builder) => ({
getChannels: builder.query({
getChannels: builder.query<Channel[], void>({
query: () => ({ url: `group` })
}),
getChannel: builder.query({
getChannel: builder.query<Channel, number>({
query: (id) => ({ url: `group/${id}` })
}),
leaveChannel: builder.query({
leaveChannel: builder.query<void, number>({
query: (id) => ({ url: `group/${id}/leave` }),
async onQueryStarted(gid, { dispatch, queryFulfilled }) {
try {
@@ -32,7 +33,7 @@ export const channelApi = createApi({
}
}
}),
createChannel: builder.mutation({
createChannel: builder.mutation<number, CreateChannelDTO>({
query: (data) => ({
url: "group",
method: "POST",
@@ -66,7 +67,7 @@ export const channelApi = createApi({
const { data: messages } = await queryFulfilled;
if (messages?.length) {
messages.forEach((msg) => {
handleChatMessage(msg, dispatch, getState());
handleChatMessage(msg, dispatch, getState() as RootState);
});
}
}
@@ -80,15 +81,15 @@ export const channelApi = createApi({
url: gid
? `/group/create_reg_magic_link?expired_in=3600&max_times=1&gid=${gid}`
: `/group/create_reg_magic_link?expired_in=3600&max_times=1`,
responseHandler: (response) => response.text()
responseHandler: (response: Response) => response.text()
}),
transformResponse: (link) => {
transformResponse: (link: string) => {
// 替换掉域名
const invite = new URL(link);
return `${location.origin}${invite.pathname}${invite.search}${invite.hash}`;
}
}),
removeChannel: builder.query({
removeChannel: builder.query<void, number>({
query: (id) => ({
url: `group/${id}`,
method: "DELETE"
@@ -99,7 +100,7 @@ export const channelApi = createApi({
ui: {
remeberedNavs: { chat: remeberedPath }
}
} = getState();
} = getState() as RootState;
try {
await queryFulfilled;
// 删掉该channel下的所有消息&reaction
@@ -161,7 +162,7 @@ export const channelApi = createApi({
await queryFulfilled;
dispatch(
updateChannel({
id: gid,
gid,
icon: `${BASE_URL}/resource/group_avatar?gid=${gid}&t=${+new Date()}`
})
);
+24 -18
View File
@@ -11,7 +11,16 @@ import { onMessageSendStarted } from "./handlers";
import { normalizeArchiveData } from "../../common/utils";
// import { updateMessage } from "../slices/message";
import baseQuery from "./base.query";
import { OG } from "../../types/common";
type UploadFileResponse = {
path: string;
size: number;
hash: string;
image_properties: {
width: number;
height: number;
};
};
export const messageApi = createApi({
reducerPath: "messageApi",
baseQuery,
@@ -25,25 +34,22 @@ export const messageApi = createApi({
method: "PUT",
body: content
})
// async onQueryStarted({mid,content},{dispatch}){
// dispatch()
// }
}),
reactMessage: builder.mutation({
reactMessage: builder.mutation<number, { mid: number; action: string }>({
query: ({ mid, action }) => ({
url: `/message/${mid}/like`,
method: "PUT",
body: { action }
})
}),
deleteMessage: builder.query({
deleteMessage: builder.query<number, number>({
query: (mid) => ({
url: `/message/${mid}`,
method: "DELETE"
})
}),
prepareUploadFile: builder.mutation({
query: (meta = {}) => ({
prepareUploadFile: builder.mutation<string, { content_type: string; filename: string }>({
query: (meta = { content_type: "", filename: "" }) => ({
url: `/resource/file/prepare`,
method: "POST",
body: meta
@@ -56,21 +62,18 @@ export const messageApi = createApi({
body: { mid_list: mids }
})
}),
uploadFile: builder.mutation({
uploadFile: builder.mutation<UploadFileResponse | {}, FormData>({
query: (formData) => ({
// headers: {
// "content-type": ContentTypes.formData,
// },
url: `/resource/file/upload`,
method: "POST",
body: formData
}),
transformResponse: (data) => {
transformResponse: (data: UploadFileResponse | null) => {
console.log("upload file response", data);
return data ? data : {};
}
}),
getOGInfo: builder.query({
getOGInfo: builder.query<OG, string>({
query: (url) => ({
url: `/resource/open_graphic_parse?url=${encodeURIComponent(url)}`
})
@@ -80,14 +83,14 @@ export const messageApi = createApi({
url: `/resource/archive?file_path=${encodeURIComponent(file_path)}`
})
}),
pinMessage: builder.mutation({
pinMessage: builder.mutation<void, { gid: number; mid: number }>({
query: ({ gid, mid }) => ({
url: `/group/${gid}/pin`,
method: "POST",
body: { mid }
})
}),
unpinMessage: builder.mutation({
unpinMessage: builder.mutation<void, { gid: number; mid: number }>({
query: ({ gid, mid }) => ({
url: `/group/${gid}/unpin`,
method: "POST",
@@ -111,7 +114,7 @@ export const messageApi = createApi({
}
}
}),
removeFavorite: builder.query({
removeFavorite: builder.query<void, number>({
query: (id) => ({
url: `/favorite/${id}`,
method: "DELETE"
@@ -170,7 +173,10 @@ export const messageApi = createApi({
await onMessageSendStarted.call(this, param1, param2, param1.context);
}
}),
readMessage: builder.mutation({
readMessage: builder.mutation<
void,
{ users?: [{ uid: number; mid: number }]; groups?: [{ gid: number; mid: number }] }
>({
query: (data) => ({
url: `/user/read-index`,
method: "POST",
@@ -4,14 +4,14 @@ import { KEY_UID } from "../config";
import baseQuery from "./base.query";
import { resetAuthData } from "../slices/auth.data";
import { updateMute } from "../slices/footprint";
import { fullfillContacts } from "../slices/contacts";
import { fullfillContacts } from "../slices/users";
import BASE_URL, { ContentTypes } from "../config";
import { onMessageSendStarted } from "./handlers";
import handleChatMessage from "../../common/hook/useStreaming/chat.handler";
import { User } from "../../types/auth";
export const contactApi = createApi({
reducerPath: "contactApi",
export const userApi = createApi({
reducerPath: "userApi",
baseQuery,
endpoints: (builder) => ({
getContacts: builder.query({
@@ -30,21 +30,21 @@ export const contactApi = createApi({
async onQueryStarted(data, { dispatch, queryFulfilled }) {
const local_uid = localStorage.getItem(KEY_UID);
try {
const { data: contacts } = await queryFulfilled;
const matchedUser = contacts.find((c) => c.uid == local_uid);
console.log("wtf", contacts, matchedUser);
const { data: users } = await queryFulfilled;
const matchedUser = users.find((c) => c.uid == local_uid);
console.log("wtf", users, matchedUser);
if (!matchedUser) {
// 用户已注销或被禁用
console.log("no matched user, redirect to login");
dispatch(resetAuthData());
} else {
const markedContacts = contacts.map((u) => {
const markedContacts = users.map((u) => {
return u.uid == matchedUser.uid ? { ...u, online: true } : u;
});
dispatch(fullfillContacts(markedContacts));
}
} catch {
console.log("get contact list error");
console.log("get user list error");
}
}
}),
@@ -135,4 +135,4 @@ export const {
useGetContactsQuery,
useLazyGetContactsQuery,
useSendMsgMutation
} = contactApi;
} = userApi;
+2 -2
View File
@@ -18,7 +18,7 @@ export interface State {
draftMixedText: { [key: string]: any };
remeberedNavs: {
chat: null | string;
contact: null | string;
user: null | string;
};
}
@@ -39,7 +39,7 @@ const initialState: State = {
// todo: typo
remeberedNavs: {
chat: null,
contact: null
user: null
}
};
@@ -19,18 +19,18 @@ const initialState: State = {
byId: {}
};
const contactsSlice = createSlice({
name: "contacts",
const usersSlice = createSlice({
name: "users",
initialState,
reducers: {
resetContacts() {
return initialState;
},
fullfillContacts(state, action: PayloadAction<StoredUser[]>) {
const contacts = action.payload || [];
state.ids = contacts.map(({ uid }) => uid);
const users = action.payload || [];
state.ids = users.map(({ uid }) => uid);
state.byId = Object.fromEntries(
contacts.map((c) => {
users.map((c) => {
const { uid } = c;
return [uid, c];
})
@@ -100,5 +100,5 @@ const contactsSlice = createSlice({
});
export const { resetContacts, fullfillContacts, updateUsersByLogs, updateUsersStatus } =
contactsSlice.actions;
export default contactsSlice.reducer;
usersSlice.actions;
export default usersSlice.reducer;
+24 -24
View File
@@ -1,24 +1,24 @@
import { combineReducers, configureStore } from '@reduxjs/toolkit';
import { setupListeners } from '@reduxjs/toolkit/query';
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';
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';
import reactionMsgReducer from './slices/message.reaction';
import channelMsgReducer from './slices/message.channel';
import userMsgReducer from './slices/message.user';
import favoritesReducer from './slices/favorites';
import fileMsgReducer from './slices/message.file';
import messageReducer from './slices/message';
import { authApi } from './services/auth';
import { contactApi } from './services/contact';
import { channelApi } from './services/channel';
import { messageApi } from './services/message';
import { serverApi } from './services/server';
import { combineReducers, configureStore } from "@reduxjs/toolkit";
import { setupListeners } from "@reduxjs/toolkit/query";
import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux";
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 usersReducer from "./slices/users";
import reactionMsgReducer from "./slices/message.reaction";
import channelMsgReducer from "./slices/message.channel";
import userMsgReducer from "./slices/message.user";
import favoritesReducer from "./slices/favorites";
import fileMsgReducer from "./slices/message.file";
import messageReducer from "./slices/message";
import { authApi } from "./services/auth";
import { userApi } from "./services/user";
import { channelApi } from "./services/channel";
import { messageApi } from "./services/message";
import { serverApi } from "./services/server";
const reducer = combineReducers({
authData: authDataReducer,
@@ -26,7 +26,7 @@ const reducer = combineReducers({
footprint: footprintReducer,
server: serverReducer,
favorites: favoritesReducer,
contacts: contactsReducer,
users: usersReducer,
channels: channelsReducer,
reactionMessage: reactionMsgReducer,
userMessage: userMsgReducer,
@@ -35,7 +35,7 @@ const reducer = combineReducers({
message: messageReducer,
[authApi.reducerPath]: authApi.reducer,
[messageApi.reducerPath]: messageApi.reducer,
[contactApi.reducerPath]: contactApi.reducer,
[userApi.reducerPath]: userApi.reducer,
[channelApi.reducerPath]: channelApi.reducer,
[serverApi.reducerPath]: serverApi.reducer
});
@@ -46,7 +46,7 @@ const store = configureStore({
getDefaultMiddleware()
.concat(
authApi.middleware,
contactApi.middleware,
userApi.middleware,
channelApi.middleware,
serverApi.middleware,
messageApi.middleware

Before

Width:  |  Height:  |  Size: 669 B

After

Width:  |  Height:  |  Size: 669 B

+3 -3
View File
@@ -6,7 +6,7 @@ import IconInvite from "../../assets/icons/add.person.svg";
import IconMention from "../../assets/icons/mention.svg";
import ChannelIcon from "./ChannelIcon";
import ChannelModal from "./ChannelModal";
import ContactsModal from "./ContactsModal";
import ContactsModal from "./UsersModal";
import InviteModal from "./InviteModal";
const Styled = styled.ul`
@@ -47,7 +47,7 @@ export default function AddEntriesMenu() {
const [inviteModalVisible, setInviteModalVisible] = useState(false);
const [channelModalVisible, setChannelModalVisible] = useState(false);
const [contactsModalVisible, setContactsModalVisible] = useState(false);
const [usersModalVisible, setContactsModalVisible] = useState(false);
const toggleInviteModalVisible = () => {
setInviteModalVisible((prev) => {
if (!prev) {
@@ -96,7 +96,7 @@ export default function AddEntriesMenu() {
</li>
</Styled>
{channelModalVisible && <ChannelModal personal={isPrivate} closeModal={handleCloseModal} />}
{contactsModalVisible && <ContactsModal closeModal={toggleContactsModalVisible} />}
{usersModalVisible && <ContactsModal closeModal={toggleContactsModalVisible} />}
{inviteModalVisible && <InviteModal closeModal={toggleInviteModalVisible} />}
</>
);
+3 -3
View File
@@ -7,7 +7,7 @@ import IconChat from "../../assets/icons/placeholder.chat.svg";
import IconAsk from "../../assets/icons/placeholder.question.svg";
import IconInvite from "../../assets/icons/placeholder.invite.svg";
import IconDownload from "../../assets/icons/placeholder.download.svg";
import ContactsModal from "./ContactsModal";
import ContactsModal from "./UsersModal";
import { useAppSelector } from "../../app/store";
const Styled = styled.div`
@@ -75,7 +75,7 @@ const BlankPlaceholder: FC<Props> = ({ type = "chat" }) => {
const server = useAppSelector((store) => store.server);
const [inviteModalVisible, setInviteModalVisible] = useState(false);
const [createChannelVisible, setCreateChannelVisible] = useState(false);
const [contactListVisible, setContactListVisible] = useState(false);
const [userListVisible, setContactListVisible] = useState(false);
const toggleChannelModalVisible = () => {
setCreateChannelVisible((prev) => !prev);
};
@@ -121,7 +121,7 @@ const BlankPlaceholder: FC<Props> = ({ type = "chat" }) => {
{createChannelVisible && (
<ChannelModal personal={true} closeModal={toggleChannelModalVisible} />
)}
{contactListVisible && <ContactsModal closeModal={toggleContactListVisible} />}
{userListVisible && <ContactsModal closeModal={toggleContactListVisible} />}
{inviteModalVisible && <InviteModal closeModal={toggleInviteModalVisible} />}
</>
);
+1 -1
View File
@@ -58,7 +58,7 @@ const Channel: FC<Props> = ({ interactive = true, id, compact = false, avatarSiz
const { channel, totalMemberCount } = useAppSelector((store) => {
return {
channel: store.channels.byId[id],
totalMemberCount: store.contacts.ids.length
totalMemberCount: store.users.ids.length
};
});
+8 -8
View File
@@ -4,7 +4,7 @@ import { useNavigate } from "react-router-dom";
import Modal from "../Modal";
import Button from "../styled/Button";
import ChannelIcon from "../ChannelIcon";
import Contact from "../Contact";
import User from "../User";
import StyledWrapper from "./styled";
import StyledCheckbox from "../styled/Checkbox";
import StyledToggle from "../../component/styled/Toggle";
@@ -19,8 +19,8 @@ interface Props {
}
const ChannelModal: FC<Props> = ({ personal = false, closeModal }) => {
const { contactsData, loginUid } = useAppSelector((store) => {
return { contactsData: store.contacts.byId, loginUid: store.authData.user?.uid };
const { usersData, loginUid } = useAppSelector((store) => {
return { usersData: store.users.byId, loginUid: store.authData.user?.uid };
});
const navigateTo = useNavigate();
const [data, setData] = useState<CreateChannelDTO>({
@@ -30,7 +30,7 @@ const ChannelModal: FC<Props> = ({ personal = false, closeModal }) => {
is_public: !personal
});
const { contacts, input, updateInput } = useFilteredUsers();
const { users, input, updateInput } = useFilteredUsers();
const [createChannel, { isSuccess, isError, isLoading, data: newChannelId }] =
useCreateChannelMutation();
@@ -85,7 +85,7 @@ const ChannelModal: FC<Props> = ({ personal = false, closeModal }) => {
};
if (!loginUid) return null;
const loginUser = contactsData[Number(loginUid)];
const loginUser = usersData[Number(loginUid)];
if (!loginUser) return null;
const { name, members, is_public } = data;
@@ -101,9 +101,9 @@ const ChannelModal: FC<Props> = ({ personal = false, closeModal }) => {
placeholder="Type Username to search"
/>
</div>
{contacts && (
{users && (
<ul className="users">
{contacts.map((u) => {
{users.map((u) => {
const { uid } = u;
const checked = members ? members.includes(uid) : false;
return (
@@ -120,7 +120,7 @@ const ChannelModal: FC<Props> = ({ personal = false, closeModal }) => {
name="cb"
id="cb"
/>
<Contact uid={uid} interactive={false} />
<User uid={uid} interactive={false} />
</li>
);
})}
+1 -1
View File
@@ -84,7 +84,7 @@ const FileBox: FC<Props> = ({
from_uid,
content
}) => {
const fromUser = useAppSelector((store) => store.contacts.byId[from_uid]);
const fromUser = useAppSelector((store) => store.users.byId[from_uid]);
const icon = getFileIcon(file_type, name);
if (!content || !fromUser || !name) return null;
const previewContent = renderPreview({ file_type, content, name });
+1 -1
View File
@@ -60,7 +60,7 @@ const FileMessage: FC<Props> = ({
to
});
const { stopUploading, data, uploadFile, progress, isSuccess: uploadSuccess } = useUploadFile();
const fromUser = useAppSelector((store) => store.contacts.byId[from_uid]);
const fromUser = useAppSelector((store) => store.users.byId[from_uid]);
const { size, name, content_type } = properties ?? {};
useEffect(() => {
const handleUpSend = async ({
+6 -6
View File
@@ -4,7 +4,7 @@ import Modal from "../Modal";
import Button from "../styled/Button";
import Input from "../styled/Input";
import Channel from "../Channel";
import Contact from "../Contact";
import User from "../User";
// import Channel from "../Channel";
import Reply from "../Message/Reply";
import StyledWrapper from "./styled";
@@ -27,7 +27,7 @@ export default function ForwardModal({ mids, closeModal }) {
// input: channelInput,
updateInput: updateChannelInput
} = useFilteredChannels();
const { contacts, input, updateInput } = useFilteredUsers();
const { users, input, updateInput } = useFilteredUsers();
const toggleCheck = ({ currentTarget }: MouseEvent<HTMLLIElement>) => {
const { id, type = "user" } = currentTarget.dataset;
const ids = type == "user" ? selectedMembers : selectedChannels;
@@ -100,8 +100,8 @@ export default function ForwardModal({ mids, closeModal }) {
</li>
);
})}
{contacts &&
contacts.map((u) => {
{users &&
users.map((u) => {
const { uid } = u;
const checked = selectedMembers.includes(uid);
console.log({ checked });
@@ -114,7 +114,7 @@ export default function ForwardModal({ mids, closeModal }) {
onClick={toggleCheck}
>
<StyledCheckbox readOnly checked={checked} name="cb" id="cb" />
<Contact uid={uid} interactive={false} />
<User uid={uid} interactive={false} />
</li>
);
})}
@@ -142,7 +142,7 @@ export default function ForwardModal({ mids, closeModal }) {
{selectedMembers.map((uid) => {
return (
<li key={uid} className="item">
<Contact
<User
key={uid}
uid={uid}
interactive={false}
+1 -1
View File
@@ -56,7 +56,7 @@ const GithubLoginButton: FC<Props> = ({ type = "login", client_id }) => {
switch (error.status) {
case 410:
toast.error(
"No associated account found, please contact admin for an invitation link to join."
"No associated account found, please user admin for an invitation link to join."
);
break;
default:
+1 -1
View File
@@ -54,7 +54,7 @@ const GoogleLoginInner: FC<Props> = ({ type = "login", loaded, loadError }) => {
switch (error.status) {
case 410:
toast.error(
"No associated account found, please contact admin for an invitation link to join."
"No associated account found, please user admin for an invitation link to join."
);
break;
default:
@@ -3,7 +3,7 @@ import styled from "styled-components";
import toast from "react-hot-toast";
import Button from "../styled/Button";
import Input from "../styled/Input";
import Contact from "../Contact";
import User from "../User";
import StyledCheckbox from "../styled/Checkbox";
import { useAddMembersMutation } from "../../../app/services/channel";
import CloseIcon from "../../../assets/icons/close.svg";
@@ -105,10 +105,10 @@ interface Props {
const AddMembers: FC<Props> = ({ cid, closeModal }) => {
const [addMembers, { isLoading: isAdding, isSuccess }] = useAddMembersMutation();
const [selects, setSelects] = useState([]);
const { channel, contactData } = useAppSelector((store) => {
const { channel, userData } = useAppSelector((store) => {
return {
channel: store.channels.byId[cid],
contactData: store.contacts.byId
userData: store.users.byId
};
});
useEffect(() => {
@@ -121,7 +121,7 @@ const AddMembers: FC<Props> = ({ cid, closeModal }) => {
const handleAddMembers = () => {
addMembers({ id: cid, members: selects });
};
const { input, updateInput, contacts = [] } = useFilteredUsers();
const { input, updateInput, users = [] } = useFilteredUsers();
const toggleCheckMember = ({ currentTarget }: MouseEvent<SVGSVGElement | HTMLLIElement>) => {
const { uid } = currentTarget.dataset;
@@ -140,7 +140,7 @@ const AddMembers: FC<Props> = ({ cid, closeModal }) => {
if (!channel) return null;
const { members: uids } = channel;
const contactIds = contacts.map(({ uid }) => uid);
const userIds = users.map(({ uid }) => uid);
return (
<Styled>
@@ -150,7 +150,7 @@ const AddMembers: FC<Props> = ({ cid, closeModal }) => {
{selects.map((uid) => {
return (
<li className="select" key={uid}>
{contactData[uid].name}
{userData[uid].name}
<CloseIcon data-uid={uid} onClick={toggleCheckMember} className="close" />
</li>
);
@@ -166,7 +166,7 @@ const AddMembers: FC<Props> = ({ cid, closeModal }) => {
{/* )} */}
</div>
<ul className="users">
{contactIds.map((uid) => {
{userIds.map((uid) => {
const added = uids.includes(uid);
return (
<li
@@ -182,7 +182,7 @@ const AddMembers: FC<Props> = ({ cid, closeModal }) => {
name="cb"
id="cb"
/>
<Contact uid={uid} interactive={false} />
<User uid={uid} interactive={false} />
</li>
);
})}
@@ -6,7 +6,7 @@ import Modal from "../Modal";
import useLeaveChannel from "../../hook/useLeaveChannel";
import StyledModal from "../styled/Modal";
import Button from "../styled/Button";
import Contact from "../Contact";
import User from "../User";
const UserList = styled.ul`
display: flex;
@@ -97,7 +97,7 @@ const TransferOwnerModal: FC<Props> = ({ id, closeModal, withLeave = true }) =>
className={`user ${uid == id ? "selected" : ""}`}
onClick={handleSelectUser.bind(null, id)}
>
<Contact uid={id} interactive={false} />
<User uid={id} interactive={false} />
</li>
);
})}
+7 -7
View File
@@ -3,8 +3,8 @@ import styled from "styled-components";
import Tippy from "@tippyjs/react";
import { hideAll } from "tippy.js";
import toast from "react-hot-toast";
import { useUpdateContactMutation } from "../../app/services/contact";
import Contact from "./Contact";
import { useUpdateContactMutation } from "../../app/services/user";
import User from "./User";
import StyledMenu from "./styled/Menu";
import InviteLink from "./InviteLink";
import moreIcon from "../../assets/icons/more.svg?url";
@@ -119,9 +119,9 @@ interface Props {
cid?: number;
}
const ManageMembers: FC<Props> = ({ cid }) => {
const { contacts, channels, loginUser } = useAppSelector((store) => {
const { users, channels, loginUser } = useAppSelector((store) => {
return {
contacts: store.contacts,
users: store.users,
channels: store.channels,
loginUser: store.authData.user
};
@@ -141,7 +141,7 @@ const ManageMembers: FC<Props> = ({ cid }) => {
updateContact({ id: uid, is_admin: isAdmin });
};
const channel = channels.byId[cid] ?? null;
const uids = channel ? (channel.is_public ? contacts.ids : channel.members) : contacts.ids;
const uids = channel ? (channel.is_public ? users.ids : channel.members) : users.ids;
return (
<StyledWrapper>
@@ -154,7 +154,7 @@ const ManageMembers: FC<Props> = ({ cid }) => {
</div>
<ul className="members">
{uids.map((uid) => {
const { name, email, is_admin } = contacts.byId[uid];
const { name, email, is_admin } = users.byId[uid];
const owner = channel && channel.owner == uid;
const switchRoleVisible = loginUser.is_admin && loginUser.uid !== uid;
const dotsVisible = email || loginUser?.is_admin;
@@ -164,7 +164,7 @@ const ManageMembers: FC<Props> = ({ cid }) => {
return (
<li key={uid} className="member">
<div className="left">
<Contact compact uid={uid} interactive={false} />
<User compact uid={uid} interactive={false} />
<div className="info">
<span className="name">
{name} {owner && <IconOwner />}
+2 -2
View File
@@ -20,8 +20,8 @@ interface Props {
}
const Mention: FC<Props> = ({ uid, popover = true, cid, textOnly = false }) => {
const contactsData = useAppSelector((store) => store.contacts.byId);
const user = contactsData[uid];
const usersData = useAppSelector((store) => store.users.byId);
const user = usersData[uid];
if (!user) return null;
if (textOnly) return `@${user.name}`;
return (
@@ -10,12 +10,12 @@ interface Props {
}
const PreviewMessage: FC<Props> = ({ mid = 0 }) => {
const { msg, contactsData } = useAppSelector((store) => {
return { msg: store.message[mid], contactsData: store.contacts.byId };
const { msg, usersData } = useAppSelector((store) => {
return { msg: store.message[mid], usersData: store.users.byId };
});
if (!msg) return null;
const { from_uid, created_at, content_type, content, thumbnail, properties } = msg;
const { name, avatar } = contactsData[from_uid];
const { name, avatar } = usersData[from_uid];
return (
<StyledWrapper className={`preview`}>
<div className="avatar">
+2 -2
View File
@@ -106,9 +106,9 @@ const StyledDetails = styled.div`
}
`;
const ReactionDetails = ({ uids = [], emoji, index }) => {
const contactsData = useSelector((store) => store.contacts.byId);
const usersData = useSelector((store) => store.users.byId);
const names = uids.map((id) => {
return contactsData[id]?.name;
return usersData[id]?.name;
});
const emojiData = getEmojiDataFromNative(emoji, "apple", AppleEmojiData);
const prefixDesc =
+1 -1
View File
@@ -156,7 +156,7 @@ interface ReplyProps {
const Reply: FC<ReplyProps> = ({ mid, interactive = true }) => {
const { data, users } = useAppSelector((store) => {
return { data: store.message[mid], users: store.contacts.byId };
return { data: store.message[mid], users: store.users.byId };
});
const handleClick = (evt: MouseEvent<HTMLDivElement>) => {
const { mid } = evt.currentTarget.dataset;
+4 -7
View File
@@ -38,12 +38,12 @@ function Message({
const {
message = {},
reactionMessageData,
contactsData
usersData
} = useSelector((store) => {
return {
reactionMessageData: store.reactionMessage,
message: store.message[mid] || {},
contactsData: store.contacts.byId
usersData: store.users.byId
};
});
@@ -75,7 +75,7 @@ function Message({
}, [mid, read]);
const reactions = reactionMessageData[mid];
const currUser = contactsData[fromUid] || {};
const currUser = usersData[fromUid] || {};
// if (!message) return null;
let timePrefix = null;
const dayjsTime = dayjs(time);
@@ -115,10 +115,7 @@ function Message({
visible={contextMenuVisible}
hide={hideContextMenu}
>
<div
className="details"
data-pin-tip={`pinned by ${contactsData[pinInfo?.created_by]?.name}`}
>
<div className="details" data-pin-tip={`pinned by ${usersData[pinInfo?.created_by]?.name}`}>
<div className="up">
<span className="name">{currUser.name}</span>
<Tooltip
+5 -5
View File
@@ -30,7 +30,7 @@ import { ReactEditor } from "slate-react";
import useUploadFile from "../../hook/useUploadFile";
import Styled from "./styled";
import { CONFIG } from "./config";
import Contact from "../Contact";
import User from "../User";
export const TEXT_EDITOR_PREFIX = "_text_editor";
let components = createPlateUI({
@@ -50,7 +50,7 @@ const Plugins = ({
const [context, to] = id.split("_");
const { addStageFile } = useUploadFile({ context, id: to });
const enableMentions = members.length > 0;
const contactData = useSelector((store) => store.contacts.byId);
const userData = useSelector((store) => store.users.byId);
const [msgs, setMsgs] = useState([]);
const [cmdKey, setCmdKey] = useState(false);
const editableRef = useRef(null);
@@ -220,12 +220,12 @@ const Plugins = ({
onRenderItem={({ item }) => {
console.log("wtf", item);
if (!item || !item.data) return null;
return <Contact key={item.data.uid} uid={item.data.uid} interactive={false} />;
return <User key={item.data.uid} uid={item.data.uid} interactive={false} />;
}}
items={members.map((id) => {
const data = contactData[id];
const data = userData[id];
if (!data) {
// console.log("wtffe", id, contactData);
// console.log("wtffe", id, userData);
return { key: id };
}
const { uid, name, ...rest } = data;
+1 -1
View File
@@ -30,7 +30,7 @@ const Profile: FC<Props> = ({ uid, type = "embed", cid }) => {
const { data } = useAppSelector((store) => {
return {
data: store.contacts.byId[uid]
data: store.users.byId[uid]
};
});
+3 -3
View File
@@ -122,15 +122,15 @@ const renderContent = (data) => {
export default function Replying({ context, id, mid }) {
const { removeReplying } = useSendMessage({ to: id, context });
const { msg, contactsData } = useAppSelector((store) => {
return { contactsData: store.contacts.byId, msg: store.message[mid] };
const { msg, usersData } = useAppSelector((store) => {
return { usersData: store.users.byId, msg: store.message[mid] };
});
const removeReply = () => {
removeReplying();
};
if (!msg) return null;
const { from_uid } = msg;
const user = contactsData[from_uid];
const user = usersData[from_uid];
return (
<Styled className="reply">
<div className="prefix">
+4 -4
View File
@@ -39,13 +39,13 @@ function Send({
mode,
uploadFiles,
channelsData,
contactsData,
usersData,
uids
} = useAppSelector((store) => {
return {
channelsData: store.channels.byId,
uids: store.contacts.ids,
contactsData: store.contacts.byId,
uids: store.users.ids,
usersData: store.users.byId,
mode: store.ui.inputMode,
from_uid: store.authData.user?.uid,
replying_mid: store.message.replying[`${context}_${id}`],
@@ -127,7 +127,7 @@ function Send({
const toggleMarkdownFullscreen = () => {
setMarkdownFullscreen((prev) => !prev);
};
const name = context == "channel" ? channelsData[id]?.name : contactsData[id]?.name;
const name = context == "channel" ? channelsData[id]?.name : usersData[id]?.name;
const placeholder = `Send to ${ChatPrefixs[context]}${name} `;
const members =
context == "channel" ? (channelsData[id]?.is_public ? uids : channelsData[id]?.members) : [];
+1 -1
View File
@@ -56,7 +56,7 @@ export default function Server() {
const { pathname } = useLocation();
const { server, userCount } = useAppSelector((store) => {
return {
userCount: store.contacts.ids.length,
userCount: store.users.ids.length,
server: store.server
};
});
@@ -21,7 +21,7 @@ interface Props {
enableContextMenu?: boolean;
}
const Contact: FC<Props> = ({
const User: FC<Props> = ({
cid,
uid,
owner = false,
@@ -34,7 +34,7 @@ const Contact: FC<Props> = ({
}) => {
const navigate = useNavigate();
const { visible: contextMenuVisible, handleContextMenuEvent, hideContextMenu } = useContextMenu();
const curr = useAppSelector((store) => store.contacts.byId[uid]);
const curr = useAppSelector((store) => store.users.byId[uid]);
const handleDoubleClick = () => {
navigate(`/chat/dm/${uid}`);
};
@@ -73,4 +73,4 @@ const Contact: FC<Props> = ({
);
};
export default Contact;
export default User;
@@ -4,7 +4,7 @@ import { NavLink } from "react-router-dom";
import { useOutsideClick } from "rooks";
import useFilteredUsers from "../hook/useFilteredUsers";
import Contact from "./Contact";
import User from "./User";
import Modal from "./Modal";
const StyledWrapper = styled.div`
@@ -16,7 +16,6 @@ const StyledWrapper = styled.div`
box-shadow: 0 25px 50px rgba(31, 41, 55, 0.25);
border-radius: 8px;
transition: all 0.5s ease;
/* overflow-y: scroll; */
.search {
box-shadow: 0 1px 0 rgba(0, 0, 0, 0.1);
padding: 8px;
@@ -58,7 +57,7 @@ interface Props {
const ContactsModal: FC<Props> = ({ closeModal }) => {
const wrapperRef = useRef<HTMLDivElement>(null);
const { contacts, updateInput, input } = useFilteredUsers();
const { users, updateInput, input } = useFilteredUsers();
useOutsideClick(wrapperRef, closeModal);
const handleSearch = (evt: ChangeEvent<HTMLInputElement>) => {
@@ -71,14 +70,14 @@ const ContactsModal: FC<Props> = ({ closeModal }) => {
<div className="search">
<input value={input} onChange={handleSearch} placeholder="Type Username to search" />
</div>
{contacts && (
{users && (
<ul className="users">
{contacts.map((u) => {
{users.map((u) => {
const { uid } = u;
return (
<li key={uid} className="user">
<NavLink onClick={closeModal} to={`/chat/dm/${uid}`}>
<Contact uid={uid} interactive={false} />
<User uid={uid} interactive={false} />
</NavLink>
</li>
);
+4 -4
View File
@@ -4,7 +4,7 @@ import toast from "react-hot-toast";
import { useNavigate, useMatch } from "react-router-dom";
import { hideAll } from "tippy.js";
import { useRemoveMembersMutation } from "../../app/services/channel";
import { useLazyDeleteContactQuery } from "../../app/services/contact";
import { useLazyDeleteContactQuery } from "../../app/services/user";
import useConfig from "./useConfig";
import useCopy from "./useCopy";
import { useAppSelector } from "../../app/store";
@@ -15,14 +15,14 @@ interface Props {
const useContactOperation: FC<Props> = ({ uid, cid }) => {
const [passedUid, setPassedUid] = useState(undefined);
const { values: agoraConfig } = useConfig("agora");
const isUserDetailPath = useMatch(`/contacts/${uid}`);
const isUserDetailPath = useMatch(`/users/${uid}`);
const [removeUser, { isSuccess: removeUserSuccess }] = useLazyDeleteContactQuery();
const [removeInChannel, { isSuccess: removeSuccess }] = useRemoveMembersMutation();
const navigateTo = useNavigate();
const { copy } = useCopy();
const { user, channel, loginUser } = useAppSelector((store) => {
return {
user: store.contacts.byId[uid],
user: store.users.byId[uid],
channel: store.channels.byId[cid],
loginUser: store.authData.user
};
@@ -36,7 +36,7 @@ const useContactOperation: FC<Props> = ({ uid, cid }) => {
if (removeSuccess || removeUserSuccess) {
toast.success("Remove Successfully");
if (removeUserSuccess && isUserDetailPath) {
navigateTo(`/contacts`);
navigateTo(`/users`);
}
}
}, [removeSuccess, removeUserSuccess, isUserDetailPath]);
+4 -4
View File
@@ -3,16 +3,16 @@ import { useAppSelector } from "../../app/store";
export default function useFilteredUsers() {
const [input, setInput] = useState("");
const contacts = useAppSelector((store) => Object.values(store.contacts.byId));
const users = useAppSelector((store) => Object.values(store.users.byId));
const [filteredUsers, setFilteredUsers] = useState([]);
useEffect(() => {
if (!input) {
setFilteredUsers(contacts);
setFilteredUsers(users);
} else {
let str = ["", input.toLowerCase(), ""].join(".*");
let reg = new RegExp(str);
setFilteredUsers(
contacts.filter((c) => {
users.filter((c) => {
return reg.test(c.name.toLowerCase());
})
);
@@ -25,7 +25,7 @@ export default function useFilteredUsers() {
return {
input,
contacts: filteredUsers,
users: filteredUsers,
updateInput
};
}
+1 -1
View File
@@ -1,6 +1,6 @@
import { useState } from "react";
import { useSendChannelMsgMutation } from "../../app/services/channel";
import { useSendMsgMutation } from "../../app/services/contact";
import { useSendMsgMutation } from "../../app/services/user";
import { useCreateArchiveMutation } from "../../app/services/message";
export default function useForwardMessage() {
+1 -1
View File
@@ -1,7 +1,7 @@
import { useDispatch, batch } from "react-redux";
import { resetFootprint } from "../../app/slices/footprint";
import { resetChannels } from "../../app/slices/channels";
import { resetContacts } from "../../app/slices/contacts";
import { resetContacts } from "../../app/slices/users";
import { resetChannelMsg } from "../../app/slices/message.channel";
import { resetUserMsg } from "../../app/slices/message.user";
import { resetReactionMessage } from "../../app/slices/message.reaction";
+1 -1
View File
@@ -1,6 +1,6 @@
import { useEffect, useState, useRef } from "react";
import { useLazyGetHistoryMessagesQuery } from "../../app/services/channel";
import { useLazyGetHistoryMessagesQuery as useLazyGetDMHistoryMsg } from "../../app/services/contact";
import { useLazyGetHistoryMessagesQuery as useLazyGetDMHistoryMsg } from "../../app/services/user";
import { useAppSelector } from "../../app/store";
export interface PageInfo {
isFirst: boolean;
+6 -5
View File
@@ -1,9 +1,10 @@
import { useState, useEffect } from "react";
import { usePinMessageMutation, useUnpinMessageMutation } from "../../app/services/message";
import { useAppSelector } from "../../app/store";
import { PinnedMessage } from "../../types/channel";
export default function usePinMessage(cid: number) {
const [pins, setPins] = useState([]);
const [pins, setPins] = useState<PinnedMessage[]>([]);
const { channel, loginUser } = useAppSelector((store) => {
return {
channel: store.channels.byId[cid],
@@ -13,15 +14,15 @@ export default function usePinMessage(cid: number) {
const [pin, { isError, isLoading, isSuccess }] = usePinMessageMutation();
const [unpin, { isError: isUnpinError, isLoading: isUnpining, isSuccess: isUnpinSuccess }] =
useUnpinMessageMutation();
const pinMessage = (mid) => {
const pinMessage = (mid: number) => {
if (!mid || !cid) return;
pin({ mid, gid: +cid });
};
const unpinMessage = (mid) => {
const unpinMessage = (mid: number) => {
if (!mid || !cid) return;
unpin({ mid, gid: +cid });
};
const getPinInfo = (mid) => {
const getPinInfo = (mid: number) => {
if (!cid || !channel) return;
const pins = channel.pinned_messages;
if (!pins || pins.length == 0) return;
@@ -38,7 +39,7 @@ export default function usePinMessage(cid: number) {
getPinInfo,
channel,
pins,
canPin: loginUser.is_admin || channel?.owner == loginUser.uid,
canPin: loginUser?.is_admin || channel?.owner == loginUser?.uid,
pinMessage,
unpinMessage,
isError,
+1 -1
View File
@@ -1,7 +1,7 @@
import toast from "react-hot-toast";
import { removeReplyingMessage, addReplyingMessage } from "../../app/slices/message";
import { useSendChannelMsgMutation } from "../../app/services/channel";
import { useSendMsgMutation } from "../../app/services/contact";
import { useSendMsgMutation } from "../../app/services/user";
import { useReplyMessageMutation } from "../../app/services/message";
import { useAppDispatch, useAppSelector } from "../../app/store";
+1 -1
View File
@@ -18,7 +18,7 @@ import {
updateReadUsers,
updateMute
} from "../../../app/slices/footprint";
import { updateUsersByLogs, updateUsersStatus } from "../../../app/slices/contacts";
import { updateUsersByLogs, updateUsersStatus } from "../../../app/slices/users";
import { resetAuthData } from "../../../app/slices/auth.data";
import chatMessageHandler from "./chat.handler";
import store, { useAppDispatch, useAppSelector } from "../../../app/store";
+3 -6
View File
@@ -20,12 +20,9 @@ export default function useUploadFile(props: { context: string; id: string } | o
const canceledRef = useRef(false);
const sliceUploadedCountRef = useRef(0);
const totalSliceCountRef = useRef(1);
const [prepareUploadFile, { isLoading: isPreparing, isSuccess: isPrepared }] =
usePrepareUploadFileMutation();
const [
uploadFileFn,
{ isLoading: isUploading, isSuccess: isUploaded, isError: uploadFileError }
] = useUploadFileMutation();
const [prepareUploadFile, { isLoading: isPreparing }] = usePrepareUploadFileMutation();
const [uploadFileFn, { isLoading: isUploading, isError: uploadFileError }] =
useUploadFileMutation();
const uploadChunk = (data: { file_id: string; chunk: File; is_last: boolean }) => {
const { file_id, chunk, is_last } = data;
+4 -4
View File
@@ -11,7 +11,7 @@ import useMessageFeed from "../../../common/hook/useMessageFeed";
import useConfig from "../../../common/hook/useConfig";
import ChannelIcon from "../../../common/component/ChannelIcon";
import Tooltip from "../../../common/component/Tooltip";
import Contact from "../../../common/component/Contact";
import User from "../../../common/component/User";
import Layout from "../Layout";
import { renderMessageFragment } from "../utils";
import EditIcon from "../../../assets/icons/edit.svg";
@@ -66,7 +66,7 @@ export default function ChannelChat({ cid = "", dropFiles = [] }) {
footprint: store.footprint,
loginUser: store.authData.user,
// msgIds: store.channelMessage[cid] || [],
userIds: store.contacts.ids,
userIds: store.users.ids,
data: store.channels.byId[cid] || {},
messageData: store.message || {}
};
@@ -183,7 +183,7 @@ export default function ChannelChat({ cid = "", dropFiles = [] }) {
</div>
</StyledHeader>
}
contacts={
users={
membersVisible ? (
<>
<StyledContacts>
@@ -195,7 +195,7 @@ export default function ChannelChat({ cid = "", dropFiles = [] }) {
)}
{memberIds.map((uid) => {
return (
<Contact
<User
enableContextMenu={true}
cid={cid}
owner={owner == uid}
+1 -1
View File
@@ -11,7 +11,7 @@ import Tooltip from "../../../common/component/Tooltip";
import IconSetting from "../../../assets/icons/setting.svg";
import IconInvite from "../../../assets/icons/invite.from.channel.svg";
import { useReadMessageMutation } from "../../../app/services/message";
import { useUpdateMuteSettingMutation } from "../../../app/services/contact";
import { useUpdateMuteSettingMutation } from "../../../app/services/user";
import StyledLink from "./styled";
import ChannelIcon from "../../../common/component/ChannelIcon";
import { getUnreadCount } from "../utils";
+3 -3
View File
@@ -8,7 +8,7 @@ import FavIcon from "../../../assets/icons/bookmark.svg";
// import IconHeadphone from "../../../assets/icons/headphone.svg";
// import useChatScroll from "../../../common/hook/useChatScroll";
import { useReadMessageMutation } from "../../../app/services/message";
import Contact from "../../../common/component/Contact";
import User from "../../../common/component/User";
import Layout from "../Layout";
import { StyledHeader, StyledDMChat } from "./styled";
import LoadMore from "../LoadMore";
@@ -34,7 +34,7 @@ export default function DMChat({ uid = 0, dropFiles = [] }) {
selects: store.ui.selectMessages[`user_${uid}`],
loginUid: store.authData.user?.uid,
footprint: store.footprint,
currUser: store.contacts.byId[uid],
currUser: store.users.byId[uid],
messageData: store.message
};
});
@@ -81,7 +81,7 @@ export default function DMChat({ uid = 0, dropFiles = [] }) {
}
header={
<StyledHeader className="head">
<Contact interactive={false} uid={currUser.uid} />
<User interactive={false} uid={currUser.uid} />
</StyledHeader>
}
>
+3 -3
View File
@@ -14,7 +14,7 @@ import useContextMenu from "../../../common/hook/useContextMenu";
import ContextMenu from "../../../common/component/ContextMenu";
dayjs.extend(relativeTime);
import { renderPreviewMessage } from "../utils";
import Contact from "../../../common/component/Contact";
import User from "../../../common/component/User";
import { ContentTypes } from "../../../app/config";
const NavItem = ({ uid, mid, unreads, setFiles }) => {
const [previewMsg, setPreviewMsg] = useState(null);
@@ -24,7 +24,7 @@ const NavItem = ({ uid, mid, unreads, setFiles }) => {
const [updateReadIndex] = useReadMessageMutation();
const { currMsg, currUser } = useSelector((store) => {
return {
currUser: store.contacts.byId[uid],
currUser: store.users.byId[uid],
currMsg: store.message[mid]
};
});
@@ -107,7 +107,7 @@ const NavItem = ({ uid, mid, unreads, setFiles }) => {
to={`/chat/dm/${uid}`}
onContextMenu={handleContextMenuEvent}
>
<Contact compact interactive={false} className="avatar" uid={uid} />
<User compact interactive={false} className="avatar" uid={uid} />
<div className="details">
<div className="up">
<span className="name">{currUser.name}</span>
+1 -1
View File
@@ -13,7 +13,7 @@ const DMList: FC<Props> = ({ uids, setDropFiles }) => {
return {
loginUid: store.authData.user?.uid,
readUsers: store.footprint.readUsers,
contactData: store.contacts.byId,
userData: store.users.byId,
userMessage: store.userMessage.byId,
messageData: store.message
};
+6 -6
View File
@@ -13,7 +13,7 @@ interface Props {
children: ReactElement;
header: ReactElement;
aside: ReactElement | null;
contacts: ReactElement | null;
users: ReactElement | null;
dropFiles: [];
context: string;
to: number | null;
@@ -23,7 +23,7 @@ const Layout: FC<Props> = ({
children,
header,
aside = null,
contacts = null,
users = null,
dropFiles = [],
context = "channel",
to = null
@@ -31,11 +31,11 @@ const Layout: FC<Props> = ({
const { addStageFile } = useUploadFile({ context, id: to });
const messagesContainer = useRef<HTMLDivElement>(null);
const [previewImage, setPreviewImage] = useState(null);
const { selects, channelsData, contactsData } = useAppSelector((store) => {
const { selects, channelsData, usersData } = useAppSelector((store) => {
return {
selects: store.ui.selectMessages[`${context}_${to}`],
channelsData: store.channels.byId,
contactsData: store.contacts.byId
usersData: store.users.byId
};
});
const [{ isActive }, drop] = useDrop(
@@ -95,7 +95,7 @@ const Layout: FC<Props> = ({
);
}
}, []);
const name = context == "channel" ? channelsData[to]?.name : contactsData[to]?.name;
const name = context == "channel" ? channelsData[to]?.name : usersData[to]?.name;
return (
<>
@@ -110,7 +110,7 @@ const Layout: FC<Props> = ({
{selects && <Operations context={context} id={to} />}
</div>
</div>
{contacts && <div className="members">{contacts}</div>}
{users && <div className="members">{users}</div>}
{aside && <div className="aside">{aside}</div>}
</main>
<div className={`drag_tip ${isActive ? "visible animate__animated animate__fadeIn" : ""}`}>
+1 -1
View File
@@ -1,7 +1,7 @@
import Tippy from "@tippyjs/react";
import { useDispatch, useSelector } from "react-redux";
import { useNavigate, useLocation, useMatch } from "react-router-dom";
import { useUpdateMuteSettingMutation } from "../../../app/services/contact";
import { useUpdateMuteSettingMutation } from "../../../app/services/user";
import { useReadMessageMutation } from "../../../app/services/message";
import { removeUserSession } from "../../../app/slices/message.user";
import ContextMenu from "../../../common/component/ContextMenu";
+6 -6
View File
@@ -6,7 +6,7 @@ import { NativeTypes } from "react-dnd-html5-backend";
import relativeTime from "dayjs/plugin/relativeTime";
import ContextMenu from "./ContextMenu";
import getUnreadCount, { renderPreviewMessage } from "../utils";
import Contact from "../../../common/component/Contact";
import User from "../../../common/component/User";
import Avatar from "../../../common/component/Avatar";
import iconChannel from "../../../assets/icons/channel.svg?url";
import IconLock from "../../../assets/icons/lock.svg";
@@ -51,7 +51,7 @@ export default function Session({
const { visible: contextMenuVisible, handleContextMenuEvent, hideContextMenu } = useContextMenu();
const [data, setData] = useState(null);
const { messageData, contactData, channelData, readIndex, loginUid, mids, muted } = useSelector(
const { messageData, userData, channelData, readIndex, loginUid, mids, muted } = useSelector(
(store) => {
return {
mids: type == "user" ? store.userMessage.byId[id] : store.channelMessage[id],
@@ -59,7 +59,7 @@ export default function Session({
readIndex:
type == "user" ? store.footprint.readUsers[id] : store.footprint.readChannels[id],
messageData: store.message,
contactData: store.contacts.byId,
userData: store.users.byId,
channelData: store.channels.byId,
muted: type == "user" ? store.footprint.muteUsers[id] : store.footprint.muteChannels[id]
};
@@ -72,13 +72,13 @@ export default function Session({
};
useEffect(() => {
const tmp = type == "user" ? contactData[id] : channelData[id];
const tmp = type == "user" ? userData[id] : channelData[id];
if (!tmp) return;
const { name, icon, avatar, is_public = true } = tmp;
const session =
type == "user" ? { name, icon: avatar, mid, is_public } : { name, icon, mid, is_public };
setData(session);
}, [id, mid, type, contactData, channelData]);
}, [id, mid, type, userData, channelData]);
if (!data) return null;
const previewMsg = messageData[mid] || {};
const { name, icon, is_public } = data;
@@ -108,7 +108,7 @@ export default function Session({
>
<div className="icon">
{type == "user" ? (
<Contact avatarSize={40} compact interactive={false} className="avatar" uid={id} />
<User avatarSize={40} compact interactive={false} className="avatar" uid={id} />
) : (
<Avatar className="icon" type="channel" name={name} url={icon} />
// <img
+4 -4
View File
@@ -10,12 +10,12 @@ import AddIcon from "../../assets/icons/add.svg";
import BlankPlaceholder from "../../common/component/BlankPlaceholder";
import Server from "../../common/component/Server";
import Tooltip from "../../common/component/Tooltip";
// import Contact from "../../common/component/Contact";
// import User from "../../common/component/User";
// import CurrentUser from "../../common/component/CurrentUser";
import ChannelChat from "./ChannelChat";
import DMChat from "./DMChat";
import ChannelList from "./ChannelList";
import ContactsModal from "../../common/component/ContactsModal";
import ContactsModal from "../../common/component/UsersModal";
import ChannelModal from "../../common/component/ChannelModal";
import DMList from "./DMList";
@@ -28,7 +28,7 @@ export default function ChatPage() {
};
});
const [channelModalVisible, setChannelModalVisible] = useState(false);
const [contactsModalVisible, setContactsModalVisible] = useState(false);
const [usersModalVisible, setContactsModalVisible] = useState(false);
const { channel_id, user_id } = useParams();
const toggleContactsModalVisible = () => {
setContactsModalVisible((prev) => !prev);
@@ -49,7 +49,7 @@ export default function ChatPage() {
{channelModalVisible && (
<ChannelModal closeModal={toggleChannelModalVisible} personal={true} />
)}
{contactsModalVisible && <ContactsModal closeModal={toggleContactsModalVisible} />}
{usersModalVisible && <ContactsModal closeModal={toggleContactsModalVisible} />}
<StyledWrapper>
<div className="left">
<Server />
+3 -3
View File
@@ -9,12 +9,12 @@ import Server from "../../common/component/Server";
import CurrentUser from "../../common/component/CurrentUser";
import ChannelChat from "./ChannelChat";
import DMChat from "./DMChat";
import ContactsModal from "../../common/component/ContactsModal";
import ContactsModal from "../../common/component/UsersModal";
import ChannelModal from "../../common/component/ChannelModal";
import SessionList from "./SessionList";
export default function ChatPage() {
const [channelModalVisible, setChannelModalVisible] = useState(false);
const [contactsModalVisible, setContactsModalVisible] = useState(false);
const [usersModalVisible, setContactsModalVisible] = useState(false);
const { channel_id, user_id } = useParams();
const { sessionUids } = useSelector((store) => {
return {
@@ -38,7 +38,7 @@ export default function ChatPage() {
{channelModalVisible && (
<ChannelModal closeModal={toggleChannelModalVisible} personal={true} />
)}
{contactsModalVisible && <ContactsModal closeModal={toggleContactsModalVisible} />}
{usersModalVisible && <ContactsModal closeModal={toggleContactsModalVisible} />}
<StyledWrapper>
<div className="left">
<Server />
+3 -3
View File
@@ -1,6 +1,6 @@
import { useState } from "react";
// import { useUpdateChannelMutation } from "../../app/services/channel";
import { useUpdateMuteSettingMutation } from "../../app/services/contact";
import { useUpdateMuteSettingMutation } from "../../app/services/user";
import { useReadMessageMutation } from "../../app/services/message";
import { useAppSelector } from "../../app/store";
@@ -8,10 +8,10 @@ export default function useSession({ type, id }) {
const [inviteModalVisible, setInviteModalVisible] = useState(false);
const [muteChannel] = useUpdateMuteSettingMutation();
const [updateReadIndex] = useReadMessageMutation();
const { messageData, contactData, channelData } = useAppSelector((store) => {
const { messageData, userData, channelData } = useAppSelector((store) => {
return {
messageData: store.message,
contactData: store.contacts.byId,
userData: store.users.byId,
channelData: store.channels.byId
};
});
+1 -1
View File
@@ -44,7 +44,7 @@ function FavsPage() {
console.log("favs", store.favorites);
return {
favorites: store.favorites,
userData: store.contacts.byId,
userData: store.users.byId,
channelData: store.channels.byId
};
});
+1 -1
View File
@@ -24,7 +24,7 @@ interface Props {
const User: FC<Props> = ({ uid }) => {
const { pathname } = useLocation();
const user = useAppSelector((store) => store.contacts.byId[uid]);
const user = useAppSelector((store) => store.users.byId[uid]);
if (!user) return null;
return (
+4 -4
View File
@@ -13,7 +13,7 @@ import Notification from "../../common/component/Notification";
import Manifest from "../../common/component/Manifest";
import ChatIcon from "../../assets/icons/chat.svg";
import ContactIcon from "../../assets/icons/contact.svg";
import ContactIcon from "../../assets/icons/user.svg";
import FavIcon from "../../assets/icons/bookmark.svg";
import FolderIcon from "../../assets/icons/folder.svg";
import { useAppSelector } from "../../app/store";
@@ -27,7 +27,7 @@ export default function HomePage() {
loginUid,
ui: {
ready,
remeberedNavs: { chat: chatPath, contact: contactPath }
remeberedNavs: { chat: chatPath, user: userPath }
}
} = useAppSelector((store) => {
return {
@@ -52,7 +52,7 @@ export default function HomePage() {
}
// 有点绕
const chatNav = isChatHomePath ? "/chat" : chatPath || "/chat";
const contactNav = contactPath || "/contacts";
const userNav = userPath || "/users";
return (
<>
@@ -72,7 +72,7 @@ export default function HomePage() {
<ChatIcon />
</Tooltip>
</NavLink>
<NavLink className="link" to={contactNav}>
<NavLink className="link" to={userNav}>
<Tooltip tip="Members">
<ContactIcon />
</Tooltip>
+6 -11
View File
@@ -1,7 +1,7 @@
import { useEffect } from "react";
import initCache, { useRehydrate } from "../../app/cache";
import { useLazyGetFavoritesQuery } from "../../app/services/message";
import { useLazyGetContactsQuery } from "../../app/services/contact";
import { useLazyGetContactsQuery } from "../../app/services/user";
import { useLazyGetServerQuery } from "../../app/services/server";
import useStreaming from "../../common/hook/useStreaming";
import { useAppSelector } from "../../app/store";
@@ -27,12 +27,7 @@ export default function usePreload() {
] = useLazyGetFavoritesQuery();
const [
getContacts,
{
isLoading: contactsLoading,
isSuccess: contactsSuccess,
isError: contactsError,
data: contacts
}
{ isLoading: usersLoading, isSuccess: usersSuccess, isError: usersError, data: users }
] = useLazyGetContactsQuery();
const [
getServer,
@@ -61,11 +56,11 @@ export default function usePreload() {
}, [canStreaming]);
return {
loading: contactsLoading || serverLoading || favoritesLoading || !rehydrated,
error: contactsError && serverError && favoritesError,
success: contactsSuccess && serverSuccess && favoritesSuccess,
loading: usersLoading || serverLoading || favoritesLoading || !rehydrated,
error: usersError && serverError && favoritesError,
success: usersSuccess && serverSuccess && favoritesSuccess,
data: {
contacts,
users,
server,
favorites
}
+2 -2
View File
@@ -12,7 +12,7 @@ const SendMagicLinkPage = lazy(() => import("./sendMagicLink"));
const RegPage = lazy(() => import("./reg/Register"));
const LoginPage = lazy(() => import("./login"));
const OAuthPage = lazy(() => import("./oauth"));
const ContactsPage = lazy(() => import("./contacts"));
const ContactsPage = lazy(() => import("./users"));
const FavoritesPage = lazy(() => import("./favs"));
const OnboardingPage = lazy(() => import("./onboarding"));
const InvitePage = lazy(() => import("./invite"));
@@ -138,7 +138,7 @@ const PageRoutes = () => {
}
/>
</Route>
<Route path="contacts">
<Route path="users">
<Route
index
element={
+1 -1
View File
@@ -77,7 +77,7 @@ export default function LoginPage() {
break;
case 410:
toast.error(
"No associated account found, please contact admin for an invitation link to join."
"No associated account found, please user admin for an invitation link to join."
);
break;
default:
+4 -4
View File
@@ -58,11 +58,11 @@ export const Dates = {
};
export default function Date({ select = "", updateFilter }) {
// const { input, updateInput, contacts } = useFilteredUsers();
// const contacts=useSelector(store=>store.contacts);
// const { input, updateInput, users } = useFilteredUsers();
// const users=useSelector(store=>store.users);
// const uid=contacts.ids;
// const dataMap=contacts.byId;
// const uid=users.ids;
// const dataMap=users.byId;
const handleClick = (dur) => {
updateFilter({ date: dur });
};
+10 -10
View File
@@ -1,7 +1,7 @@
import styled from "styled-components";
import Search from "../Search";
import CheckSign from "../../../assets/icons/check.sign.svg";
import Contact from "../../../common/component/Contact";
import User from "../../../common/component/User";
import useFilteredUsers from "../../../common/hook/useFilteredUsers";
const Styled = styled.div`
@@ -28,7 +28,7 @@ const Styled = styled.div`
width: 100%;
display: flex;
flex-direction: column;
.contact {
.user {
position: relative;
cursor: pointer;
&.none {
@@ -49,11 +49,11 @@ const Styled = styled.div`
`;
export default function From({ select = "", updateFilter }) {
const { input, updateInput, contacts } = useFilteredUsers();
// const contacts=useSelector(store=>store.contacts);
const { input, updateInput, users } = useFilteredUsers();
// const users=useSelector(store=>store.users);
// const uid=contacts.ids;
// const dataMap=contacts.byId;
// const uid=users.ids;
// const dataMap=users.byId;
const handleClick = (uid) => {
updateFilter({ from: uid });
};
@@ -64,14 +64,14 @@ export default function From({ select = "", updateFilter }) {
<Search embed={true} value={input} updateSearchValue={updateInput} />
</div>
<ul className="list">
<li className="contact none" onClick={handleClick.bind(null, undefined)}>
<li className="user none" onClick={handleClick.bind(null, undefined)}>
Anyone
{!select && <CheckSign className="check" />}
</li>
{contacts.map(({ uid }) => {
{users.map(({ uid }) => {
return (
<li key={uid} className="contact" onClick={handleClick.bind(null, uid)}>
<Contact uid={uid} interactive={true} />
<li key={uid} className="user" onClick={handleClick.bind(null, uid)}>
<User uid={uid} interactive={true} />
{select == uid && <CheckSign className="check" />}
</li>
);
+4 -4
View File
@@ -78,11 +78,11 @@ export const FileTypes = {
}
};
export default function Type({ select = "", updateFilter }) {
// const { input, updateInput, contacts } = useFilteredUsers();
// const contacts=useSelector(store=>store.contacts);
// const { input, updateInput, users } = useFilteredUsers();
// const users=useSelector(store=>store.users);
// const uid=contacts.ids;
// const dataMap=contacts.byId;
// const uid=users.ids;
// const dataMap=users.byId;
const handleClick = (type) => {
updateFilter({ type });
};
+4 -4
View File
@@ -65,8 +65,8 @@ export default function Filter({ filter, updateFilter }) {
};
toggleFilterVisible(tmp);
};
const { contactMap, channelMap } = useAppSelector((store) => {
return { contactMap: store.contacts.byId, channelMap: store.channels.byId };
const { userMap, channelMap } = useAppSelector((store) => {
return { userMap: store.users.byId, channelMap: store.channels.byId };
});
const { from, channel, type, date } = filter;
@@ -91,9 +91,9 @@ export default function Filter({ filter, updateFilter }) {
onClick={toggleFilterVisible.bind(null, { from: true })}
>
{from && (
<Avatar className="avatar" name={contactMap[from].name} url={contactMap[from].avatar} />
<Avatar className="avatar" name={userMap[from].name} url={userMap[from].avatar} />
)}
<span className="txt">From {from && contactMap[from].name}</span>
<span className="txt">From {from && userMap[from].name}</span>
<ArrowDown className="arrow" />
</div>
</Tippy>
+1 -1
View File
@@ -1,7 +1,7 @@
import { useEffect, useState, MouseEvent } from "react";
import styled from "styled-components";
import toast from "react-hot-toast";
import { useUpdateAvatarMutation } from "../../app/services/contact";
import { useUpdateAvatarMutation } from "../../app/services/user";
import AvatarUploader from "../../common/component/AvatarUploader";
import ProfileBasicEditModal from "./ProfileBasicEditModal";
import UpdatePasswordModal from "./UpdatePasswordModal";
+1 -1
View File
@@ -2,7 +2,7 @@ import { ChangeEvent, FC, useEffect, useState } from "react";
import styled from "styled-components";
import toast from "react-hot-toast";
import Input from "../../common/component/styled/Input";
import { useUpdateInfoMutation } from "../../app/services/contact";
import { useUpdateInfoMutation } from "../../app/services/user";
import StyledModal from "../../common/component/styled/Modal";
import Button from "../../common/component/styled/Button";
import Modal from "../../common/component/Modal";
@@ -3,7 +3,7 @@ import { NavLink, useParams, useLocation } from "react-router-dom";
import { useDispatch, useSelector } from "react-redux";
import { updateRemeberedNavs } from "../../app/slices/ui";
import Search from "../../common/component/Search";
import Contact from "../../common/component/Contact";
import User from "../../common/component/User";
import Profile from "../../common/component/Profile";
import StyledWrapper from "./styled";
@@ -14,26 +14,26 @@ export default function ContactsPage() {
const { pathname } = useLocation();
const { user_id } = useParams();
const contactIds = useSelector((store) => store.contacts.ids);
const userIds = useSelector((store) => store.users.ids);
useEffect(() => {
dispatch(updateRemeberedNavs({ key: "contact" }));
dispatch(updateRemeberedNavs({ key: "user" }));
return () => {
dispatch(updateRemeberedNavs({ key: "contact", path: pathname }));
dispatch(updateRemeberedNavs({ key: "user", path: pathname }));
};
}, [pathname]);
console.log({ contactIds, user_id });
if (!contactIds) return null;
console.log({ userIds, user_id });
if (!userIds) return null;
return (
<StyledWrapper>
<div className="left">
<Search />
<div className="list">
<nav className="nav">
{contactIds.map((uid) => {
{userIds.map((uid) => {
return (
<NavLink key={uid} className="session" to={`/contacts/${uid}`}>
<Contact uid={uid} enableContextMenu={true} />
<NavLink key={uid} className="session" to={`/users/${uid}`}>
<User uid={uid} enableContextMenu={true} />
</NavLink>
);
})}
@@ -47,7 +47,7 @@ export default function ContactsPage() {
</div>
) : (
<div className="right placeholder">
<BlankPlaceholder type="contact" />
<BlankPlaceholder type="user" />
</div>
)}
</StyledWrapper>
+2 -5
View File
@@ -1,9 +1,8 @@
import { ContentType } from "./message";
export interface ChannelMember {}
export interface Message {}
export type ContentType = "text/plain" | "text/markdown" | "vocechat/file" | "vocechat/archive";
export interface PinnedMessage {
mid: number;
content: string;
@@ -17,10 +16,10 @@ export interface PinnedMessage {
export interface Channel {
gid: number;
// icon: string; // todo: check
owner: number;
name: string;
description: string;
icon?: string;
members: number[];
is_public: boolean;
avatar_updated_at: number;
@@ -37,8 +36,6 @@ export interface CreateChannelDTO {
export interface UpdateChannelDTO {
operation: "add_member" | "remove_member";
members?: number[];
// type = 'group_changed'
gid: number; // todo check
name?: string;
description?: string;
+36
View File
@@ -1,3 +1,39 @@
export interface EntityId {
id: number;
}
export interface OG {
type: string;
title: string;
url: string;
images: [
{
type?: string;
url: string;
secure_url?: string;
width?: number;
height?: number;
alt?: string;
}
];
audios: [
{
type?: string;
url: string;
secure_url?: string;
}
];
videos: [
{
type?: string;
url: string;
secure_url?: string;
width: number;
height: number;
}
];
favicon_url?: string;
description?: string;
locale?: string;
locale_alternate?: [];
site_name?: string;
}
+1
View File
@@ -0,0 +1 @@
export type ContentType = "text/plain" | "text/markdown" | "vocechat/file" | "vocechat/archive";
+3 -1
View File
@@ -1,5 +1,6 @@
import { User } from "./auth";
import { Channel, ContentType } from "./channel";
import { Channel } from "./channel";
import { ContentType } from "./message";
export interface ReadyEvent {
type: "ready";
@@ -75,6 +76,7 @@ export interface RelatedGroupsEvent {
}
export interface NormalMessage {
mid: number;
type: "normal";
properties: {};
content_type: ContentType;