feat: connect onboarding to APIs
This commit is contained in:
@@ -4,110 +4,106 @@ import dayjs from "dayjs";
|
|||||||
import { updateToken, resetAuthData } from "../slices/auth.data";
|
import { updateToken, resetAuthData } from "../slices/auth.data";
|
||||||
import BASE_URL, { tokenHeader } from "../config";
|
import BASE_URL, { tokenHeader } from "../config";
|
||||||
const whiteList = [
|
const whiteList = [
|
||||||
"login",
|
"login",
|
||||||
"register",
|
"register",
|
||||||
"sendMagicLink",
|
"sendMagicLink",
|
||||||
"checkInviteTokenValid",
|
"checkInviteTokenValid",
|
||||||
"getGoogleAuthConfig",
|
"getGoogleAuthConfig",
|
||||||
"getGithubAuthConfig",
|
"getGithubAuthConfig",
|
||||||
"getSMTPStatus",
|
"getSMTPStatus",
|
||||||
"getLoginConfig",
|
"getLoginConfig",
|
||||||
"getServerVersion",
|
"getServerVersion",
|
||||||
"getServer",
|
"getServer",
|
||||||
"getOpenid",
|
"getOpenid",
|
||||||
"getMetamaskNonce",
|
"getMetamaskNonce",
|
||||||
"renew",
|
"renew",
|
||||||
|
"getInitialized",
|
||||||
|
"createAdmin",
|
||||||
|
"updateLoginConfig"
|
||||||
];
|
];
|
||||||
const baseQuery = fetchBaseQuery({
|
const baseQuery = fetchBaseQuery({
|
||||||
baseUrl: BASE_URL,
|
baseUrl: BASE_URL,
|
||||||
prepareHeaders: (headers, { getState, endpoint }) => {
|
prepareHeaders: (headers, { getState, endpoint }) => {
|
||||||
console.log("req", endpoint);
|
console.log("req", endpoint);
|
||||||
const { token } = getState().authData;
|
const { token } = getState().authData;
|
||||||
if (token && !whiteList.includes(endpoint)) {
|
if (token && !whiteList.includes(endpoint)) {
|
||||||
headers.set(tokenHeader, token);
|
headers.set(tokenHeader, token);
|
||||||
}
|
}
|
||||||
return headers;
|
return headers;
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
let waitingForRenew = null;
|
let waitingForRenew = null;
|
||||||
const baseQueryWithTokenCheck = async (args, api, extraOptions) => {
|
const baseQueryWithTokenCheck = async (args, api, extraOptions) => {
|
||||||
if (waitingForRenew) {
|
if (waitingForRenew) {
|
||||||
await waitingForRenew;
|
await waitingForRenew;
|
||||||
}
|
}
|
||||||
// 先检查token是否过期,过期则renew
|
// 先检查token是否过期,过期则renew
|
||||||
const {
|
const { token, refreshToken, expireTime = new Date().getTime() } = api.getState().authData;
|
||||||
token,
|
let result = null;
|
||||||
refreshToken,
|
if (!whiteList.includes(api.endpoint) && dayjs().isAfter(new Date(expireTime - 20 * 1000))) {
|
||||||
expireTime = new Date().getTime(),
|
// 快过期了,renew
|
||||||
} = api.getState().authData;
|
waitingForRenew = baseQuery(
|
||||||
let result = null;
|
{
|
||||||
if (
|
url: "/token/renew",
|
||||||
!whiteList.includes(api.endpoint) &&
|
method: "POST",
|
||||||
dayjs().isAfter(new Date(expireTime - 20 * 1000))
|
body: {
|
||||||
) {
|
token,
|
||||||
// 快过期了,renew
|
refresh_token: refreshToken
|
||||||
waitingForRenew = baseQuery(
|
|
||||||
{
|
|
||||||
url: "/token/renew",
|
|
||||||
method: "POST",
|
|
||||||
body: {
|
|
||||||
token,
|
|
||||||
refresh_token: refreshToken,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
api,
|
|
||||||
extraOptions
|
|
||||||
);
|
|
||||||
result = await waitingForRenew;
|
|
||||||
waitingForRenew = null;
|
|
||||||
if (result.data) {
|
|
||||||
// store the new token
|
|
||||||
api.dispatch(updateToken(result.data));
|
|
||||||
// retry the initial query
|
|
||||||
result = await baseQuery(args, api, extraOptions);
|
|
||||||
}
|
}
|
||||||
} else {
|
},
|
||||||
result = await baseQuery(args, api, extraOptions);
|
api,
|
||||||
|
extraOptions
|
||||||
|
);
|
||||||
|
result = await waitingForRenew;
|
||||||
|
waitingForRenew = null;
|
||||||
|
if (result.data) {
|
||||||
|
// store the new token
|
||||||
|
api.dispatch(updateToken(result.data));
|
||||||
|
// retry the initial query
|
||||||
|
result = await baseQuery(args, api, extraOptions);
|
||||||
}
|
}
|
||||||
if (result?.error) {
|
} else {
|
||||||
console.log("api error", result.error, api.endpoint);
|
result = await baseQuery(args, api, extraOptions);
|
||||||
switch (result.error.originalStatus || result.error.status) {
|
}
|
||||||
case "FETCH_ERROR":
|
if (result?.error) {
|
||||||
{
|
console.log("api error", result.error, api.endpoint);
|
||||||
toast.error(`${api.endpoint}: Failed to fetch`);
|
switch (result.error.originalStatus || result.error.status) {
|
||||||
}
|
case "FETCH_ERROR":
|
||||||
break;
|
{
|
||||||
case 404:
|
toast.error(`${api.endpoint}: Failed to fetch`);
|
||||||
{
|
|
||||||
toast.error("Request Not Found");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 500:
|
|
||||||
{
|
|
||||||
toast.error(result.error.data || "server error");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 401:
|
|
||||||
{
|
|
||||||
if (api.endpoint !== "login") {
|
|
||||||
api.dispatch(resetAuthData());
|
|
||||||
location.href = "/#/login";
|
|
||||||
toast.error("API Not Authenticated");
|
|
||||||
}
|
|
||||||
// toast.error("token expired, please login again");
|
|
||||||
// } else {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 403:
|
|
||||||
toast.error("Request Not Allowed");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case 404:
|
||||||
|
{
|
||||||
|
toast.error("Request Not Found");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 500:
|
||||||
|
{
|
||||||
|
toast.error(result.error.data || "server error");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 401:
|
||||||
|
{
|
||||||
|
if (api.endpoint !== "login") {
|
||||||
|
api.dispatch(resetAuthData());
|
||||||
|
location.href = "/#/login";
|
||||||
|
toast.error("API Not Authenticated");
|
||||||
|
}
|
||||||
|
// toast.error("token expired, please login again");
|
||||||
|
// } else {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 403:
|
||||||
|
toast.error("Request Not Allowed");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return result;
|
}
|
||||||
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default baseQueryWithTokenCheck;
|
export default baseQueryWithTokenCheck;
|
||||||
|
|||||||
+210
-196
@@ -4,204 +4,218 @@ import { updateInfo } from "../slices/server";
|
|||||||
import baseQuery from "./base.query";
|
import baseQuery from "./base.query";
|
||||||
const defaultExpireDuration = 7 * 24 * 60 * 60;
|
const defaultExpireDuration = 7 * 24 * 60 * 60;
|
||||||
export const serverApi = createApi({
|
export const serverApi = createApi({
|
||||||
reducerPath: "serverApi",
|
reducerPath: "serverApi",
|
||||||
baseQuery,
|
baseQuery,
|
||||||
endpoints: (builder) => ({
|
endpoints: (builder) => ({
|
||||||
getServer: builder.query({
|
getServer: builder.query({
|
||||||
query: () => ({ url: `admin/system/organization` }),
|
query: () => ({ url: `admin/system/organization` }),
|
||||||
transformResponse: (data) => {
|
transformResponse: (data) => {
|
||||||
data.logo = `${BASE_URL}/resource/organization/logo?t=${new Date().getTime()}`;
|
data.logo = `${BASE_URL}/resource/organization/logo?t=${new Date().getTime()}`;
|
||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
async onQueryStarted(data, { dispatch, queryFulfilled }) {
|
async onQueryStarted(data, { dispatch, queryFulfilled }) {
|
||||||
try {
|
try {
|
||||||
const { data: server } = await queryFulfilled;
|
const { data: server } = await queryFulfilled;
|
||||||
dispatch(updateInfo(server));
|
dispatch(updateInfo(server));
|
||||||
} catch {
|
} catch {
|
||||||
console.log("get server info error");
|
console.log("get server info error");
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
}),
|
|
||||||
getThirdPartySecret: builder.query({
|
|
||||||
query: () => ({
|
|
||||||
// headers: {
|
|
||||||
// "content-type": "text/plain",
|
|
||||||
// accept: "text/plain",
|
|
||||||
// },
|
|
||||||
url: `/admin/system/third_party_secret`,
|
|
||||||
responseHandler: (response) => response.text(),
|
|
||||||
}),
|
|
||||||
keepUnusedDataFor: 0,
|
|
||||||
}),
|
|
||||||
updateThirdPartySecret: builder.mutation({
|
|
||||||
query: () => ({
|
|
||||||
url: `/admin/system/third_party_secret`,
|
|
||||||
method: "POST",
|
|
||||||
responseHandler: (response) => response.text(),
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
getMetrics: builder.query({
|
|
||||||
query: () => ({ url: `/admin/system/metrics` }),
|
|
||||||
}),
|
|
||||||
getServerVersion: builder.query({
|
|
||||||
query: () => ({
|
|
||||||
headers: {
|
|
||||||
// "content-type": "text/plain",
|
|
||||||
accept: "text/plain",
|
|
||||||
},
|
|
||||||
url: `/admin/system/version`,
|
|
||||||
responseHandler: (response) => response.text(),
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
getFirebaseConfig: builder.query({
|
|
||||||
query: () => ({ url: `admin/fcm/config` }),
|
|
||||||
}),
|
|
||||||
getGoogleAuthConfig: builder.query({
|
|
||||||
query: () => ({ url: `admin/google_auth/config` }),
|
|
||||||
}),
|
|
||||||
updateGoogleAuthConfig: builder.mutation({
|
|
||||||
query: (data) => ({
|
|
||||||
url: `admin/google_auth/config`,
|
|
||||||
method: "POST",
|
|
||||||
body: data,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
getGithubAuthConfig: builder.query({
|
|
||||||
query: () => ({ url: `admin/github_auth/config` }),
|
|
||||||
}),
|
|
||||||
updateGithubAuthConfig: builder.mutation({
|
|
||||||
query: (data) => ({
|
|
||||||
url: `admin/github_auth/config`,
|
|
||||||
method: "POST",
|
|
||||||
body: data,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
sendTestEmail: builder.mutation({
|
|
||||||
query: (data) => ({
|
|
||||||
url: `/admin/system/send_mail`,
|
|
||||||
method: "POST",
|
|
||||||
body: data,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
updateFirebaseConfig: builder.mutation({
|
|
||||||
query: (data) => ({
|
|
||||||
url: `admin/fcm/config`,
|
|
||||||
method: "POST",
|
|
||||||
body: data,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
getAgoraConfig: builder.query({
|
|
||||||
query: () => ({ url: `admin/agora/config` }),
|
|
||||||
}),
|
|
||||||
updateAgoraConfig: builder.mutation({
|
|
||||||
query: (data) => ({
|
|
||||||
url: `admin/agora/config`,
|
|
||||||
method: "POST",
|
|
||||||
body: data,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
getSMTPConfig: builder.query({
|
|
||||||
query: () => ({ url: `admin/smtp/config` }),
|
|
||||||
}),
|
|
||||||
getSMTPStatus: builder.query({
|
|
||||||
query: () => ({ url: `/admin/smtp/enabled` }),
|
|
||||||
}),
|
|
||||||
updateSMTPConfig: builder.mutation({
|
|
||||||
query: (data) => ({
|
|
||||||
url: `admin/smtp/config`,
|
|
||||||
method: "POST",
|
|
||||||
body: data,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
getLoginConfig: builder.query({
|
|
||||||
query: () => ({ url: `admin/login/config` }),
|
|
||||||
}),
|
|
||||||
updateLoginConfig: builder.mutation({
|
|
||||||
query: (data) => ({
|
|
||||||
url: `admin/login/config`,
|
|
||||||
method: "POST",
|
|
||||||
body: data,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
updateLogo: builder.mutation({
|
|
||||||
query: (data) => ({
|
|
||||||
headers: {
|
|
||||||
"content-type": "image/png",
|
|
||||||
},
|
|
||||||
url: `admin/system/organization/logo`,
|
|
||||||
method: "POST",
|
|
||||||
body: data,
|
|
||||||
}),
|
|
||||||
async onQueryStarted(data, { dispatch, queryFulfilled }) {
|
|
||||||
try {
|
|
||||||
await queryFulfilled;
|
|
||||||
dispatch(
|
|
||||||
updateInfo({
|
|
||||||
logo: `${BASE_URL}/resource/organization/logo?t=${new Date().getTime()}`,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
} catch {
|
|
||||||
console.log("update server logo error");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
createInviteLink: builder.query({
|
|
||||||
query: (expired_in = defaultExpireDuration) => ({
|
|
||||||
headers: {
|
|
||||||
"content-type": "text/plain",
|
|
||||||
accept: "text/plain",
|
|
||||||
},
|
|
||||||
url: `/admin/system/create_invite_link?expired_in=${expired_in}`,
|
|
||||||
responseHandler: (response) => response.text(),
|
|
||||||
}),
|
|
||||||
transformResponse: (link) => {
|
|
||||||
// 替换掉域名
|
|
||||||
const invite = new URL(link);
|
|
||||||
return `${location.origin}${invite.pathname}${invite.search}${invite.hash}`;
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
updateServer: builder.mutation({
|
|
||||||
query: (data) => ({
|
|
||||||
url: `admin/system/organization`,
|
|
||||||
method: "POST",
|
|
||||||
body: data,
|
|
||||||
}),
|
|
||||||
async onQueryStarted(data, { dispatch, queryFulfilled, getState }) {
|
|
||||||
const { name: prevName, description: prevDesc } = getState().server;
|
|
||||||
dispatch(updateInfo(data));
|
|
||||||
try {
|
|
||||||
await queryFulfilled;
|
|
||||||
} catch {
|
|
||||||
dispatch(updateInfo({ name: prevName, description: prevDesc }));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
}),
|
}),
|
||||||
|
getThirdPartySecret: builder.query({
|
||||||
|
query: () => ({
|
||||||
|
// headers: {
|
||||||
|
// "content-type": "text/plain",
|
||||||
|
// accept: "text/plain",
|
||||||
|
// },
|
||||||
|
url: `/admin/system/third_party_secret`,
|
||||||
|
responseHandler: (response) => response.text()
|
||||||
|
}),
|
||||||
|
keepUnusedDataFor: 0
|
||||||
|
}),
|
||||||
|
updateThirdPartySecret: builder.mutation({
|
||||||
|
query: () => ({
|
||||||
|
url: `/admin/system/third_party_secret`,
|
||||||
|
method: "POST",
|
||||||
|
responseHandler: (response) => response.text()
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
getMetrics: builder.query({
|
||||||
|
query: () => ({ url: `/admin/system/metrics` })
|
||||||
|
}),
|
||||||
|
getServerVersion: builder.query({
|
||||||
|
query: () => ({
|
||||||
|
headers: {
|
||||||
|
// "content-type": "text/plain",
|
||||||
|
accept: "text/plain"
|
||||||
|
},
|
||||||
|
url: `/admin/system/version`,
|
||||||
|
responseHandler: (response) => response.text()
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
getFirebaseConfig: builder.query({
|
||||||
|
query: () => ({ url: `admin/fcm/config` })
|
||||||
|
}),
|
||||||
|
getGoogleAuthConfig: builder.query({
|
||||||
|
query: () => ({ url: `admin/google_auth/config` })
|
||||||
|
}),
|
||||||
|
updateGoogleAuthConfig: builder.mutation({
|
||||||
|
query: (data) => ({
|
||||||
|
url: `admin/google_auth/config`,
|
||||||
|
method: "POST",
|
||||||
|
body: data
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
getGithubAuthConfig: builder.query({
|
||||||
|
query: () => ({ url: `admin/github_auth/config` })
|
||||||
|
}),
|
||||||
|
updateGithubAuthConfig: builder.mutation({
|
||||||
|
query: (data) => ({
|
||||||
|
url: `admin/github_auth/config`,
|
||||||
|
method: "POST",
|
||||||
|
body: data
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
sendTestEmail: builder.mutation({
|
||||||
|
query: (data) => ({
|
||||||
|
url: `/admin/system/send_mail`,
|
||||||
|
method: "POST",
|
||||||
|
body: data
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
updateFirebaseConfig: builder.mutation({
|
||||||
|
query: (data) => ({
|
||||||
|
url: `admin/fcm/config`,
|
||||||
|
method: "POST",
|
||||||
|
body: data
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
getAgoraConfig: builder.query({
|
||||||
|
query: () => ({ url: `admin/agora/config` })
|
||||||
|
}),
|
||||||
|
updateAgoraConfig: builder.mutation({
|
||||||
|
query: (data) => ({
|
||||||
|
url: `admin/agora/config`,
|
||||||
|
method: "POST",
|
||||||
|
body: data
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
getSMTPConfig: builder.query({
|
||||||
|
query: () => ({ url: `admin/smtp/config` })
|
||||||
|
}),
|
||||||
|
getSMTPStatus: builder.query({
|
||||||
|
query: () => ({ url: `/admin/smtp/enabled` })
|
||||||
|
}),
|
||||||
|
updateSMTPConfig: builder.mutation({
|
||||||
|
query: (data) => ({
|
||||||
|
url: `admin/smtp/config`,
|
||||||
|
method: "POST",
|
||||||
|
body: data
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
getLoginConfig: builder.query({
|
||||||
|
query: () => ({ url: `admin/login/config` })
|
||||||
|
}),
|
||||||
|
updateLoginConfig: builder.mutation({
|
||||||
|
query: (data) => ({
|
||||||
|
url: `admin/login/config`,
|
||||||
|
method: "POST",
|
||||||
|
body: data
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
updateLogo: builder.mutation({
|
||||||
|
query: (data) => ({
|
||||||
|
headers: {
|
||||||
|
"content-type": "image/png"
|
||||||
|
},
|
||||||
|
url: `admin/system/organization/logo`,
|
||||||
|
method: "POST",
|
||||||
|
body: data
|
||||||
|
}),
|
||||||
|
async onQueryStarted(data, { dispatch, queryFulfilled }) {
|
||||||
|
try {
|
||||||
|
await queryFulfilled;
|
||||||
|
dispatch(
|
||||||
|
updateInfo({
|
||||||
|
logo: `${BASE_URL}/resource/organization/logo?t=${new Date().getTime()}`
|
||||||
|
})
|
||||||
|
);
|
||||||
|
} catch {
|
||||||
|
console.log("update server logo error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
createInviteLink: builder.query({
|
||||||
|
query: (expired_in = defaultExpireDuration) => ({
|
||||||
|
headers: {
|
||||||
|
"content-type": "text/plain",
|
||||||
|
accept: "text/plain"
|
||||||
|
},
|
||||||
|
url: `/admin/system/create_invite_link?expired_in=${expired_in}`,
|
||||||
|
responseHandler: (response) => response.text()
|
||||||
|
}),
|
||||||
|
transformResponse: (link) => {
|
||||||
|
// 替换掉域名
|
||||||
|
const invite = new URL(link);
|
||||||
|
return `${location.origin}${invite.pathname}${invite.search}${invite.hash}`;
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
updateServer: builder.mutation({
|
||||||
|
query: (data) => ({
|
||||||
|
url: `admin/system/organization`,
|
||||||
|
method: "POST",
|
||||||
|
body: data
|
||||||
|
}),
|
||||||
|
async onQueryStarted(data, { dispatch, queryFulfilled, getState }) {
|
||||||
|
const { name: prevName, description: prevDesc } = getState().server;
|
||||||
|
dispatch(updateInfo(data));
|
||||||
|
try {
|
||||||
|
await queryFulfilled;
|
||||||
|
} catch {
|
||||||
|
dispatch(updateInfo({ name: prevName, description: prevDesc }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
createAdmin: builder.mutation({
|
||||||
|
query: (data) => ({
|
||||||
|
url: `/admin/system/createAdmin`,
|
||||||
|
method: "POST",
|
||||||
|
body: data
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
getInitialized: builder.query({
|
||||||
|
query: () => ({
|
||||||
|
url: `/admin/system/initialized`
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
export const {
|
export const {
|
||||||
useGetServerVersionQuery,
|
useGetServerVersionQuery,
|
||||||
useGetGithubAuthConfigQuery,
|
useGetGithubAuthConfigQuery,
|
||||||
useUpdateGithubAuthConfigMutation,
|
useUpdateGithubAuthConfigMutation,
|
||||||
useGetGoogleAuthConfigQuery,
|
useGetGoogleAuthConfigQuery,
|
||||||
useUpdateGoogleAuthConfigMutation,
|
useUpdateGoogleAuthConfigMutation,
|
||||||
useGetSMTPStatusQuery,
|
useGetSMTPStatusQuery,
|
||||||
useSendTestEmailMutation,
|
useSendTestEmailMutation,
|
||||||
useUpdateFirebaseConfigMutation,
|
useUpdateFirebaseConfigMutation,
|
||||||
useGetFirebaseConfigQuery,
|
useGetFirebaseConfigQuery,
|
||||||
useGetLoginConfigQuery,
|
useGetLoginConfigQuery,
|
||||||
useUpdateLoginConfigMutation,
|
useUpdateLoginConfigMutation,
|
||||||
useGetSMTPConfigQuery,
|
useGetSMTPConfigQuery,
|
||||||
useUpdateSMTPConfigMutation,
|
useUpdateSMTPConfigMutation,
|
||||||
useGetAgoraConfigQuery,
|
useGetAgoraConfigQuery,
|
||||||
useUpdateAgoraConfigMutation,
|
useUpdateAgoraConfigMutation,
|
||||||
useGetServerQuery,
|
useGetServerQuery,
|
||||||
useGetMetricsQuery,
|
useGetMetricsQuery,
|
||||||
useLazyGetServerQuery,
|
useLazyGetServerQuery,
|
||||||
useUpdateServerMutation,
|
useUpdateServerMutation,
|
||||||
useUpdateLogoMutation,
|
useUpdateLogoMutation,
|
||||||
useCreateInviteLinkQuery,
|
useCreateInviteLinkQuery,
|
||||||
useLazyCreateInviteLinkQuery,
|
useLazyCreateInviteLinkQuery,
|
||||||
useGetThirdPartySecretQuery,
|
useGetThirdPartySecretQuery,
|
||||||
useUpdateThirdPartySecretMutation,
|
useUpdateThirdPartySecretMutation,
|
||||||
|
useCreateAdminMutation,
|
||||||
|
useGetInitializedQuery
|
||||||
} = serverApi;
|
} = serverApi;
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import { Navigate } from "react-router-dom";
|
||||||
|
import { useGetInitializedQuery } from "../../app/services/server";
|
||||||
|
|
||||||
|
export default function RequireInitialized({ children, redirectTo = "/" }) {
|
||||||
|
const { data } = useGetInitializedQuery();
|
||||||
|
console.log("initialized?", data);
|
||||||
|
return data === false ? <Navigate to={redirectTo} replace /> : children;
|
||||||
|
}
|
||||||
+11
-6
@@ -24,6 +24,7 @@ import SettingChannelPage from "./settingChannel";
|
|||||||
import OnboardingPage from "./onboarding";
|
import OnboardingPage from "./onboarding";
|
||||||
import toast from "react-hot-toast";
|
import toast from "react-hot-toast";
|
||||||
import ResourceManagement from "./resources";
|
import ResourceManagement from "./resources";
|
||||||
|
import RequireInitialized from "../common/component/RequireInitialized";
|
||||||
|
|
||||||
const PageRoutes = () => {
|
const PageRoutes = () => {
|
||||||
const {
|
const {
|
||||||
@@ -49,9 +50,11 @@ const PageRoutes = () => {
|
|||||||
<Route
|
<Route
|
||||||
path="/login"
|
path="/login"
|
||||||
element={
|
element={
|
||||||
<RequireNoAuth>
|
<RequireInitialized>
|
||||||
<LoginPage />
|
<RequireNoAuth>
|
||||||
</RequireNoAuth>
|
<LoginPage />
|
||||||
|
</RequireNoAuth>
|
||||||
|
</RequireInitialized>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Route
|
<Route
|
||||||
@@ -89,9 +92,11 @@ const PageRoutes = () => {
|
|||||||
<Route
|
<Route
|
||||||
path="/"
|
path="/"
|
||||||
element={
|
element={
|
||||||
<RequireAuth>
|
<RequireInitialized>
|
||||||
<HomePage />
|
<RequireAuth>
|
||||||
</RequireAuth>
|
<HomePage />
|
||||||
|
</RequireAuth>
|
||||||
|
</RequireInitialized>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Route path="setting">
|
<Route path="setting">
|
||||||
|
|||||||
@@ -11,11 +11,7 @@ import StyledOnboardingPage from "./styled";
|
|||||||
export default function OnboardingPage() {
|
export default function OnboardingPage() {
|
||||||
const [step, setStep] = useState(0);
|
const [step, setStep] = useState(0);
|
||||||
const [data, setData] = useState({
|
const [data, setData] = useState({
|
||||||
spaceName: "",
|
spaceName: ""
|
||||||
adminEmail: "",
|
|
||||||
adminPassword: "",
|
|
||||||
adminPassword2: "",
|
|
||||||
inviteRule: null
|
|
||||||
});
|
});
|
||||||
const props = { step, setStep, data, setData };
|
const props = { step, setStep, data, setData };
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
|
import { useEffect, useState } from "react";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
|
import toast from "react-hot-toast";
|
||||||
import StyledInput from "../../../common/component/styled/Input";
|
import StyledInput from "../../../common/component/styled/Input";
|
||||||
import StyledButton from "../../../common/component/styled/Button";
|
import StyledButton from "../../../common/component/styled/Button";
|
||||||
import toast from "react-hot-toast";
|
import { useCreateAdminMutation } from "../../../app/services/server";
|
||||||
|
import { useLoginMutation } from "../../../app/services/auth";
|
||||||
|
|
||||||
const StyledAdminCredentialsStep = styled.div`
|
const StyledAdminCredentialsStep = styled.div`
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@@ -19,7 +22,34 @@ const StyledAdminCredentialsStep = styled.div`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export default function AdminCredentialsStep({ step, setStep, data, setData }) {
|
export default function AdminCredentialsStep({ step, setStep }) {
|
||||||
|
const [
|
||||||
|
createAdmin,
|
||||||
|
{ isLoading: isSignUpLoading, isSuccess: isSignUpSuccess, error: signUpError }
|
||||||
|
] = useCreateAdminMutation();
|
||||||
|
const [login, { isLoading: isLoginLoading, isSuccess: isLoginSuccess, error: loginError }] =
|
||||||
|
useLoginMutation();
|
||||||
|
|
||||||
|
const [email, setEmail] = useState("");
|
||||||
|
const [password, setPassword] = useState("");
|
||||||
|
const [confirm, setConfirm] = useState("");
|
||||||
|
|
||||||
|
// Display error
|
||||||
|
useEffect(() => {
|
||||||
|
if (signUpError === undefined) return;
|
||||||
|
toast.error(`Failed to sign up: ${signUpError.data}`);
|
||||||
|
}, [signUpError]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (loginError === undefined) return;
|
||||||
|
toast.error(`Login failed: ${loginError.data}`);
|
||||||
|
}, [loginError]);
|
||||||
|
|
||||||
|
// Increment `step` when both signing up and logging in have completed
|
||||||
|
useEffect(() => {
|
||||||
|
if (isSignUpSuccess && isLoginSuccess) setStep(step + 1);
|
||||||
|
}, [isSignUpSuccess, isLoginSuccess]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledAdminCredentialsStep>
|
<StyledAdminCredentialsStep>
|
||||||
<span className="primaryText">Now let’s set up your admin account</span>
|
<span className="primaryText">Now let’s set up your admin account</span>
|
||||||
@@ -27,56 +57,51 @@ export default function AdminCredentialsStep({ step, setStep, data, setData }) {
|
|||||||
<StyledInput
|
<StyledInput
|
||||||
className="input"
|
className="input"
|
||||||
placeholder="Enter your email"
|
placeholder="Enter your email"
|
||||||
value={data.adminEmail}
|
value={email}
|
||||||
onChange={(e) =>
|
onChange={(e) => setEmail(e.target.value)}
|
||||||
setData({
|
|
||||||
...data,
|
|
||||||
adminEmail: e.target.value
|
|
||||||
})
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
<StyledInput
|
<StyledInput
|
||||||
className="input"
|
className="input"
|
||||||
type="password"
|
type="password"
|
||||||
placeholder="Enter your password"
|
placeholder="Enter your password"
|
||||||
value={data.adminPassword}
|
value={password}
|
||||||
onChange={(e) =>
|
onChange={(e) => setPassword(e.target.value)}
|
||||||
setData({
|
|
||||||
...data,
|
|
||||||
adminPassword: e.target.value
|
|
||||||
})
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
<StyledInput
|
<StyledInput
|
||||||
className="input"
|
className="input"
|
||||||
type="password"
|
type="password"
|
||||||
placeholder="Confirm your password"
|
placeholder="Confirm your password"
|
||||||
value={data.adminPassword2}
|
value={confirm}
|
||||||
onChange={(e) =>
|
onChange={(e) => setConfirm(e.target.value)}
|
||||||
setData({
|
|
||||||
...data,
|
|
||||||
adminPassword2: e.target.value
|
|
||||||
})
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
<StyledButton
|
<StyledButton
|
||||||
className="button"
|
className="button"
|
||||||
onClick={() => {
|
onClick={async () => {
|
||||||
// Verification for admin credentials
|
// Verification for admin credentials
|
||||||
if (data.adminEmail === "") {
|
if (email === "") {
|
||||||
toast.error("Please enter admin email!");
|
toast.error("Please enter admin email!");
|
||||||
return;
|
return;
|
||||||
} else if (data.adminPassword === "") {
|
} else if (password === "") {
|
||||||
toast.error("Please enter admin password!");
|
toast.error("Please enter admin password!");
|
||||||
return;
|
return;
|
||||||
} else if (data.adminPassword !== data.adminPassword2) {
|
} else if (password !== confirm) {
|
||||||
toast.error("Two passwords do not match!");
|
toast.error("Two passwords do not match!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setStep(step + 1);
|
await createAdmin({
|
||||||
|
email,
|
||||||
|
name: "Admin",
|
||||||
|
password,
|
||||||
|
gender: 0
|
||||||
|
});
|
||||||
|
await login({
|
||||||
|
email,
|
||||||
|
password,
|
||||||
|
type: "password"
|
||||||
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Sign Up
|
{!(isSignUpLoading || isLoginLoading) ? "Sign Up" : "..."}
|
||||||
</StyledButton>
|
</StyledButton>
|
||||||
</StyledAdminCredentialsStep>
|
</StyledAdminCredentialsStep>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
|
import { useState, useEffect } from "react";
|
||||||
|
import toast from "react-hot-toast";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import StyledRadio from "../../../common/component/styled/Radio";
|
import StyledRadio from "../../../common/component/styled/Radio";
|
||||||
import StyledButton from "../../../common/component/styled/Button";
|
import StyledButton from "../../../common/component/styled/Button";
|
||||||
|
import { useGetLoginConfigQuery, useUpdateLoginConfigMutation } from "../../../app/services/server";
|
||||||
|
|
||||||
const StyledInviteRuleStep = styled.div`
|
const StyledInviteRuleStep = styled.div`
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@@ -14,22 +17,39 @@ const StyledInviteRuleStep = styled.div`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export default function InviteRuleStep({ step, setStep, data, setData }) {
|
export default function InviteRuleStep({ step, setStep }) {
|
||||||
|
const { data: loginConfig } = useGetLoginConfigQuery();
|
||||||
|
const [updateLoginConfig, { isSuccess, error }] = useUpdateLoginConfigMutation();
|
||||||
|
|
||||||
|
const [value, setValue] = useState(null);
|
||||||
|
|
||||||
|
// Display error
|
||||||
|
useEffect(() => {
|
||||||
|
if (error === undefined) return;
|
||||||
|
toast.error(`Failed to update invitation rule: ${error.data}`);
|
||||||
|
}, [error]);
|
||||||
|
|
||||||
|
// Increment `step` when updating has completed
|
||||||
|
useEffect(() => {
|
||||||
|
if (isSuccess) setStep(step + 1);
|
||||||
|
}, [isSuccess]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledInviteRuleStep>
|
<StyledInviteRuleStep>
|
||||||
<span className="primaryText">Last step: invite others!</span>
|
<span className="primaryText">Last step: invite others!</span>
|
||||||
<span className="secondaryText">Firstly, who can sign up to this server?</span>
|
<span className="secondaryText">Firstly, who can sign up to this server?</span>
|
||||||
<StyledRadio
|
<StyledRadio
|
||||||
options={["Everyone", "Invitation link only"]}
|
options={["Everyone", "Invitation link only"]}
|
||||||
value={data.inviteRule}
|
value={value}
|
||||||
onChange={(v) => {
|
onChange={(v) => {
|
||||||
setData({
|
setValue(v);
|
||||||
...data,
|
if (loginConfig !== undefined) {
|
||||||
inviteRule: v
|
const whoCanSignUp = ["EveryOne", "InvitationOnly"][v];
|
||||||
});
|
updateLoginConfig({
|
||||||
setTimeout(() => {
|
...loginConfig,
|
||||||
setStep(step + 1);
|
who_can_sign_up: whoCanSignUp
|
||||||
}, 750);
|
});
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<StyledButton className="button border_less ghost" onClick={() => setStep(step + 1)}>
|
<StyledButton className="button border_less ghost" onClick={() => setStep(step + 1)}>
|
||||||
|
|||||||
Reference in New Issue
Block a user