feat: settings & solid login

This commit is contained in:
zerosoul
2022-02-27 12:30:14 +08:00
parent 0394c99292
commit f7634a59cd
35 changed files with 1552 additions and 246 deletions
+7 -6
View File
@@ -1,13 +1,14 @@
// const BASE_URL = `${location.origin}/api`;
const BASE_URL = `https://rustchat.com:3000/api`;
const BASE_URL = `https://privoce.rustchat.com/api`;
// const BASE_URL = `https://rustchat.net/api`;
export const ContentTypes = {
text: 'text/plain',
image: 'image/png',
json: 'application/json'
text: "text/plain",
image: "image/png",
json: "application/json",
};
export const googleClientID =
'418687074928-naojba82n9ktf0rkvnqoor4nhr54ql1b.apps.googleusercontent.com';
"418687074928-naojba82n9ktf0rkvnqoor4nhr54ql1b.apps.googleusercontent.com";
// "840319286941-6ds7lbvk55eq8mjortf68cb2ll65lprt.apps.googleusercontent.com";
export const tokenHeader = 'X-API-Key';
export const tokenHeader = "X-API-Key";
export default BASE_URL;
+64 -50
View File
@@ -1,56 +1,70 @@
import { createApi } from '@reduxjs/toolkit/query/react';
import baseQuery from './base.query';
import BASE_URL from '../config';
import { createApi } from "@reduxjs/toolkit/query/react";
import baseQuery from "./base.query";
import BASE_URL from "../config";
export const authApi = createApi({
reducerPath: 'auth',
baseQuery,
endpoints: (builder) => ({
login: builder.mutation({
query: (credentials) => ({
url: 'token/login',
method: 'POST',
body: { credential: credentials, device: 'web', device_token: 'test' }
}),
transformResponse: (data) => {
const { avatar_updated_at } = data.user;
data.user.avatar =
avatar_updated_at == 0 ? '' : `${BASE_URL}/resource/avatar?uid=${data.user.uid}`;
return data;
}
reducerPath: "auth",
baseQuery,
endpoints: (builder) => ({
login: builder.mutation({
query: (credentials) => ({
url: "token/login",
method: "POST",
body: { credential: credentials, device: "web", device_token: "test" },
}),
transformResponse: (data) => {
const { avatar_updated_at } = data.user;
data.user.avatar =
avatar_updated_at == 0
? ""
: `${BASE_URL}/resource/avatar?uid=${data.user.uid}&t=${avatar_updated_at}`;
return data;
},
}),
// 更新token
renew: builder.mutation({
query: ({ token, refreshToken }) => ({
url: "/token/renew",
method: "POST",
body: {
token,
refresh_token: refreshToken,
},
}),
}),
// 获取openid
getOpenid: builder.mutation({
query: ({ issuer_url }) => ({
url: "/token/openid/authorize",
method: "POST",
body: {
issuer_url,
},
}),
}),
checkInviteTokenValid: builder.mutation({
query: (token) => ({
url: "user/check_invite_magic_token",
method: "POST",
body: { magic_token: token },
}),
}),
getMetamaskNonce: builder.query({
query: (address) => ({
url: `/token/metamask/nonce?public_address=${address}`,
}),
}),
logout: builder.query({
query: () => ({ url: `token/logout` }),
}),
}),
// 更新token
renew: builder.mutation({
query: ({ token, refreshToken }) => ({
url: '/token/renew',
method: 'POST',
body: {
token,
refresh_token: refreshToken
}
})
}),
checkInviteTokenValid: builder.mutation({
query: (token) => ({
url: 'user/check_invite_magic_token',
method: 'POST',
body: { magic_token: token }
})
}),
getMetamaskNonce: builder.query({
query: (address) => ({
url: `/token/metamask/nonce?public_address=${address}`
})
}),
logout: builder.query({
query: () => ({ url: `token/logout` })
})
})
});
export const {
useRenewMutation,
useLazyGetMetamaskNonceQuery,
useLoginMutation,
useLazyLogoutQuery,
useCheckInviteTokenValidMutation
useGetOpenidMutation,
useRenewMutation,
useLazyGetMetamaskNonceQuery,
useLoginMutation,
useLazyLogoutQuery,
useCheckInviteTokenValidMutation,
} = authApi;
+26
View File
@@ -4,6 +4,7 @@ import toast from "react-hot-toast";
import baseQuery from "./base.query";
import { ContentTypes } from "../config";
import { addChannelMsg } from "../slices/message.channel";
import { updateChannel } from "../slices/channels";
import {
addPendingMessage,
removePendingMessage,
@@ -21,6 +22,9 @@ export const channelApi = createApi({
getChannels: builder.query({
query: () => ({ url: `group` }),
}),
getChannel: builder.query({
query: (id) => ({ url: `group/${id}` }),
}),
createChannel: builder.mutation({
query: (data) => ({
url: "group",
@@ -28,6 +32,26 @@ export const channelApi = createApi({
body: data,
}),
}),
updateChannel: builder.mutation({
query: ({ id, ...data }) => ({
url: `group/${id}`,
method: "PUT",
body: data,
}),
async onQueryStarted(
{ id, name, description },
{ dispatch, queryFulfilled }
) {
// id: who send to ,from_uid: who sent
const patchResult = dispatch(updateChannel({ id, name, description }));
try {
await queryFulfilled;
} catch {
console.log("channel update failed");
patchResult.undo();
}
},
}),
removeChannel: builder.query({
query: (id) => ({
url: `group/${id}`,
@@ -78,6 +102,8 @@ export const channelApi = createApi({
});
export const {
useGetChannelQuery,
useUpdateChannelMutation,
useLazyRemoveChannelQuery,
useGetChannelsQuery,
useCreateChannelMutation,
+35 -1
View File
@@ -5,6 +5,7 @@ import toast from "react-hot-toast";
import baseQuery from "./base.query";
import BASE_URL, { ContentTypes } from "../config";
import { addUserMsg } from "../slices/message.user";
import { removeContact } from "../slices/contacts";
import {
addPendingMessage,
removePendingMessage,
@@ -26,12 +27,42 @@ export const contactApi = createApi({
const avatar =
user.avatar_updated_at == 0
? ""
: `${BASE_URL}/resource/avatar?uid=${user.uid}`;
: `${BASE_URL}/resource/avatar?uid=${user.uid}&t=${user.avatar_updated_at}`;
user.avatar = avatar;
return user;
});
},
}),
deleteContact: builder.query({
query: (uid) => ({ url: `/admin/user/${uid}`, method: "DELETE" }),
async onQueryStarted(uid, { dispatch, queryFulfilled }) {
// id: who send to ,from_uid: who sent
const patchResult = dispatch(removeContact(uid));
try {
await queryFulfilled;
} catch {
console.log("channel update failed");
patchResult.undo();
}
},
}),
updateAvatar: builder.mutation({
query: (data) => ({
headers: {
"content-type": "image/png",
},
url: `user/avatar`,
method: "POST",
body: data,
}),
}),
updateInfo: builder.mutation({
query: (data) => ({
url: `user`,
method: "PUT",
body: data,
}),
}),
register: builder.mutation({
query: (data) => ({
url: `user/register`,
@@ -80,6 +111,9 @@ export const contactApi = createApi({
});
export const {
useLazyDeleteContactQuery,
useUpdateInfoMutation,
useUpdateAvatarMutation,
useGetContactsQuery,
useSendMsgMutation,
useRegisterMutation,
+22 -1
View File
@@ -20,7 +20,28 @@ export const serverApi = createApi({
return data;
},
}),
updateLogo: builder.mutation({
query: (data) => ({
headers: {
"content-type": "image/png",
},
url: `admin/system/organization/logo`,
method: "POST",
body: data,
}),
}),
updateServer: builder.mutation({
query: (data) => ({
url: `admin/system/organization`,
method: "PUT",
body: data,
}),
}),
}),
});
export const { useGetServerQuery } = serverApi;
export const {
useGetServerQuery,
useUpdateServerMutation,
useUpdateLogoMutation,
} = serverApi;
+66 -42
View File
@@ -1,48 +1,72 @@
import { createSlice } from '@reduxjs/toolkit';
import { createSlice } from "@reduxjs/toolkit";
import BASE_URL from "../config";
import { getNonNullValues } from "../../common/utils";
const initialState = {
user: null,
usersVersion: null,
afterMid: null,
token: null,
refreshToken: null
user: null,
usersVersion: null,
afterMid: null,
token: null,
refreshToken: null,
};
const authDataSlice = createSlice({
name: 'authData',
initialState,
reducers: {
setAuthData(state, action) {
const { user, token, refresh_token } = action.payload;
state.user = user;
state.token = token;
state.refreshToken = refresh_token;
name: "authData",
initialState,
reducers: {
setAuthData(state, action) {
const { user, token, refresh_token } = action.payload;
state.user = user;
state.token = token;
state.refreshToken = refresh_token;
},
updateLoginedUserByLogs(state, action) {
const logs = action.payload;
logs.forEach(({ action, uid, ...rest }) => {
switch (action) {
case "update":
{
const vals = getNonNullValues(rest);
console.log("update vals", vals);
if (Object.keys(vals).includes("avatar_updated_at")) {
vals.avatar = `${BASE_URL}/resource/avatar?uid=${uid}&t=${vals.avatar_updated_at}`;
}
state.user = { ...state.user, ...vals };
}
break;
default:
break;
}
});
},
clearAuthData(state) {
console.log("clear auth data");
state.user = null;
state.token = null;
state.refreshToken = null;
},
updateToken(state, action) {
const { token, refresh_token } = action.payload;
console.log("refresh token");
state.token = token;
state.refreshToken = refresh_token;
},
setUsersVersion(state, action) {
const { version } = action.payload;
state.usersVersion = version;
},
setAfterMid(state, action) {
const { mid } = action.payload;
state.afterMid = mid;
},
},
clearAuthData(state) {
console.log('clear auth data');
state.user = null;
state.token = null;
state.refreshToken = null;
// 清掉本地缓存auth data
// localStorage.removeItem("AUTH_DATA");
// state.afterMid = null;
// state.usersVersion = null;
},
updateToken(state, action) {
const { token, refresh_token } = action.payload;
console.log('refresh token');
state.token = token;
state.refreshToken = refresh_token;
},
setUsersVersion(state, action) {
const { version } = action.payload;
state.usersVersion = version;
},
setAfterMid(state, action) {
const { mid } = action.payload;
state.afterMid = mid;
}
}
});
export const { updateToken, setAuthData, clearAuthData, setUsersVersion, setAfterMid } =
authDataSlice.actions;
export const {
updateToken,
setAuthData,
clearAuthData,
setUsersVersion,
setAfterMid,
updateLoginedUserByLogs,
} = authDataSlice.actions;
export default authDataSlice.reducer;
+14 -1
View File
@@ -14,6 +14,14 @@ const channelsSlice = createSlice({
})
);
},
updateChannel(state, action) {
// console.log("set channels store", action);
const { id, name, description } = action.payload;
const oObj = state[id];
const newObj = { ...oObj, name, description };
state[id] = newObj;
},
addChannel(state, action) {
// console.log("set channels store", action);
const ch = action.payload;
@@ -32,5 +40,10 @@ const channelsSlice = createSlice({
// },
},
});
export const { setChannels, addChannel, deleteChannel } = channelsSlice.actions;
export const {
setChannels,
addChannel,
deleteChannel,
updateChannel,
} = channelsSlice.actions;
export default channelsSlice.reducer;
+48 -1
View File
@@ -1,4 +1,5 @@
import { createSlice } from "@reduxjs/toolkit";
import { getNonNullValues } from "../../common/utils";
const initialState = [];
const contactsSlice = createSlice({
name: `contacts`,
@@ -9,6 +10,47 @@ const contactsSlice = createSlice({
const contacts = action.payload || [];
return contacts;
},
removeContact(state, action) {
const uid = action.payload;
return state.filter((c) => c.uid != uid);
},
updateUsersByLogs(state, action) {
const changeLogs = action.payload;
changeLogs.forEach(({ action, uid, ...rest }) => {
switch (action) {
case "update":
{
const vals = getNonNullValues(rest);
console.log("update vals", vals);
const curr = state.find(({ uid: id }) => id == uid);
if (curr) {
Object.keys(vals).forEach((k) => {
curr[k] = vals[k];
});
}
}
break;
case "create":
{
state.push({ uid, ...rest });
}
break;
case "delete":
{
const idx = state.findIndex((o) => {
return o.uid == uid;
});
if (idx > -1) {
state.splice(idx, 1);
}
}
break;
default:
break;
}
});
},
updateUsersStatus(state, action) {
const onlines = action.payload;
onlines.forEach((item) => {
@@ -22,5 +64,10 @@ const contactsSlice = createSlice({
},
},
});
export const { setContacts, updateUsersStatus } = contactsSlice.actions;
export const {
setContacts,
removeContact,
updateUsersByLogs,
updateUsersStatus,
} = contactsSlice.actions;
export default contactsSlice.reducer;
-5
View File
@@ -3,7 +3,6 @@ import { createSlice } from "@reduxjs/toolkit";
const initialState = {
menuExpand: true,
setting: false,
profileSetting: false,
channelSetting: null,
};
const uiSlice = createSlice({
@@ -16,9 +15,6 @@ const uiSlice = createSlice({
toggleSetting(state) {
state.setting = !state.setting;
},
toggleProfileSetting(state) {
state.profileSetting = !state.profileSetting;
},
toggleChannelSetting(state, action) {
console.log("toggle channel setting payload", action);
const id = action.payload;
@@ -29,7 +25,6 @@ const uiSlice = createSlice({
export const {
toggleSetting,
toggleMenuExpand,
toggleProfileSetting,
toggleChannelSetting,
} = uiSlice.actions;
export default uiSlice.reducer;