diff --git a/src/app/services/contact.js b/src/app/services/contact.js
index 102b7359..0be7a14b 100644
--- a/src/app/services/contact.js
+++ b/src/app/services/contact.js
@@ -1,38 +1,45 @@
-import { createApi } from "@reduxjs/toolkit/query/react";
-import baseQuery from "./base.query";
-import BASE_URL, { ContentTypes } from "../config";
-import { REHYDRATE } from "redux-persist";
+import { createApi } from '@reduxjs/toolkit/query/react';
+import baseQuery from './base.query';
+import BASE_URL, { ContentTypes } from '../config';
+import { REHYDRATE } from 'redux-persist';
export const contactApi = createApi({
- reducerPath: "contact",
- baseQuery,
- extractRehydrationInfo(action, { reducerPath }) {
- if (action.type === REHYDRATE) {
- return action.payload ? action.payload[reducerPath] : undefined;
- }
- },
- endpoints: (builder) => ({
- getContacts: builder.query({
- query: () => ({ url: `user` }),
- transformResponse: (data) => {
- return data.map((user) => {
- const avatar = `${BASE_URL}/resource/avatar?uid=${user.uid}`;
- user.avatar = avatar;
- return user;
- });
- },
- }),
- sendMsg: builder.mutation({
- query: ({ id, content, type = "text" }) => ({
- headers: {
- "content-type": ContentTypes[type],
- },
- url: `user/${id}/send`,
- method: "POST",
- body: content,
- }),
- }),
+ reducerPath: 'contact',
+ baseQuery,
+ extractRehydrationInfo(action, { reducerPath }) {
+ if (action.type === REHYDRATE) {
+ return action.payload ? action.payload[reducerPath] : undefined;
+ }
+ },
+ endpoints: (builder) => ({
+ getContacts: builder.query({
+ query: () => ({ url: `user` }),
+ transformResponse: (data) => {
+ return data.map((user) => {
+ const avatar = `${BASE_URL}/resource/avatar?uid=${user.uid}`;
+ user.avatar = avatar;
+ return user;
+ });
+ }
}),
+ register: builder.mutation({
+ query: (data) => ({
+ url: `user/register`,
+ method: 'POST',
+ body: data
+ })
+ }),
+ sendMsg: builder.mutation({
+ query: ({ id, content, type = 'text' }) => ({
+ headers: {
+ 'content-type': ContentTypes[type]
+ },
+ url: `user/${id}/send`,
+ method: 'POST',
+ body: content
+ })
+ })
+ })
});
-export const { useGetContactsQuery, useSendMsgMutation } = contactApi;
+export const { useGetContactsQuery, useSendMsgMutation, useRegisterMutation } = contactApi;
diff --git a/src/routes/index.js b/src/routes/index.js
index 407e76ef..90b4731e 100644
--- a/src/routes/index.js
+++ b/src/routes/index.js
@@ -1,70 +1,72 @@
// import { useState } from "react";
-import { Route, Routes, HashRouter } from "react-router-dom";
-import { Provider } from "react-redux";
+import { Route, Routes, HashRouter } from 'react-router-dom';
+import { Provider } from 'react-redux';
-import { persistStore } from "redux-persist";
-import { PersistGate } from "redux-persist/integration/react";
+import { persistStore } from 'redux-persist';
+import { PersistGate } from 'redux-persist/integration/react';
// import Welcome from './Welcome'
-import NotFoundPage from "./404";
-import LoginPage from "./login";
-import HomePage from "./home";
-import ChatPage from "./chat";
-import ContactsPage from "./contacts";
-import RequireAuth from "../common/component/RequireAuth";
+import NotFoundPage from './404';
+import LoginPage from './login';
+import HomePage from './home';
+import ChatPage from './chat';
+import ContactsPage from './contacts';
+import RequireAuth from '../common/component/RequireAuth';
-import store from "../app/store.with.persist";
+import store from '../app/store.with.persist';
+import InvitePage from './invite';
// import getStore from "../app/store";
const PageRoutes = () => {
- return (
-
-
- } />
-
-
-
- }
- >
- } />
-
- } />
- } />
- } />
-
-
- } />
- } />
-
-
- } />
-
-
- );
+ return (
+
+
+ } />
+ } />
+
+
+
+ }
+ >
+ } />
+
+ } />
+ } />
+ } />
+
+
+ } />
+ } />
+
+
+ } />
+
+
+ );
};
// const local_key = "AUTH_DATA";
export default function ReduxRoutes() {
- // const [authData, setAuthData] = useState(
- // JSON.parse(localStorage.getItem(local_key))
- // );
- // const updateAuthData = (data) => {
- // localStorage.setItem(local_key, JSON.stringify(data));
- // setAuthData(data);
- // };
- return (
-
-
-
-
- {/* {authData ? (
+ // const [authData, setAuthData] = useState(
+ // JSON.parse(localStorage.getItem(local_key))
+ // );
+ // const updateAuthData = (data) => {
+ // localStorage.setItem(local_key, JSON.stringify(data));
+ // setAuthData(data);
+ // };
+ return (
+
+
+
+
+ {/* {authData ? (
) : (
)} */}
-
- );
+
+ );
}
diff --git a/src/routes/invite/index.js b/src/routes/invite/index.js
new file mode 100644
index 00000000..a1ee6698
--- /dev/null
+++ b/src/routes/invite/index.js
@@ -0,0 +1,168 @@
+import { useState, useEffect } from 'react';
+import StyledWrapper from './styled';
+import { useNavigate } from 'react-router-dom';
+import toast from 'react-hot-toast';
+
+import { useRegisterMutation } from '../../app/services/contact';
+import { useCheckInviteTokenValidMutation } from '../../app/services/auth';
+
+export default function InvitePage() {
+ const [secondPwd, setSecondPwd] = useState('');
+ const [samePwd, setSamePwd] = useState(true);
+ const [token, setToken] = useState('');
+ const [valid, setValid] = useState(false);
+ // const [sp] = useSearchParams();
+ const navigateTo = useNavigate();
+ const [register, { data, isLoading, isSuccess, isError, error }] = useRegisterMutation();
+ const [checkToken, { data: isValid, isLoading: checkLoading, isSuccess: checkSuccess }] =
+ useCheckInviteTokenValidMutation();
+ useEffect(() => {
+ // console.log(search);
+ const query = new URLSearchParams(location.search);
+ setToken(query.get('token'));
+ }, []);
+ useEffect(() => {
+ if (token) {
+ checkToken(token);
+ }
+ }, [token]);
+ useEffect(() => {
+ if (checkSuccess) {
+ console.log({ isValid });
+ setValid(isValid);
+ } else {
+ setValid(false);
+ }
+ }, [checkSuccess, isValid]);
+
+ const [input, setInput] = useState({
+ name: '',
+ email: '',
+ password: ''
+ });
+
+ const handleReg = (evt) => {
+ evt.preventDefault();
+ if (!samePwd) {
+ toast.error('two passwords not same');
+ return;
+ }
+ console.log('wtf', input);
+ register({
+ ...input,
+ magic_token: token,
+ gender: 1
+ });
+ };
+ const handleInput = (evt) => {
+ const { type } = evt.target.dataset;
+ const { value } = evt.target;
+ console.log(type, value);
+ setInput((prev) => {
+ prev[type] = value;
+ return { ...prev };
+ });
+ };
+ const handleSecondPwdInput = (evt) => {
+ const { value } = evt.target;
+ setSecondPwd(value);
+ };
+ const handlePwdCheck = () => {
+ if (secondPwd) {
+ setSamePwd(secondPwd == input.password);
+ }
+ };
+ useEffect(() => {
+ if (!samePwd) {
+ toast.error('two passwords not same');
+ }
+ }, [samePwd]);
+
+ useEffect(() => {
+ if (isSuccess && data) {
+ // 去登录
+ toast.success('register success, login please');
+ setTimeout(() => {
+ navigateTo('/login');
+ }, 500);
+ } else if (isError) {
+ console.log('register failed', error);
+ switch (error.status) {
+ case 412:
+ toast.error('register failed: invalid token or expired');
+ break;
+ case 409: {
+ const tips = {
+ email_conflict: 'email conflict',
+ name_conflict: 'name conflict'
+ };
+ toast.error(`register failed: ${tips[error.data?.reason]}`);
+ break;
+ }
+ default:
+ toast.error('register failed');
+ break;
+ }
+ }
+ }, [data, isSuccess, isError, error]);
+
+ const { email, password, name } = input;
+ if (!token) return 'token not found';
+ if (checkLoading) return 'checking token valid';
+ if (!valid) return 'invite token expires or invalid';
+ return (
+
+
+
+

+
Sign Up to Rustchat
+
Please enter your details.
+
+
+
+
+ );
+}
diff --git a/src/routes/invite/styled.js b/src/routes/invite/styled.js
new file mode 100644
index 00000000..e31c9563
--- /dev/null
+++ b/src/routes/invite/styled.js
@@ -0,0 +1,75 @@
+import styled from 'styled-components';
+const StyledWrapper = styled.div`
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: 100vh;
+ .form {
+ padding: 36px 40px 32px 40px;
+ /* border: 1px solid #eee; */
+ box-shadow: 0px 4px 8px -2px rgba(16, 24, 40, 0.1), 0px 2px 4px -2px rgba(16, 24, 40, 0.06);
+ border-radius: 12px;
+ .tips {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ padding-bottom: 24px;
+ .logo {
+ width: 56px;
+ height: 56px;
+ margin-bottom: 28px;
+ }
+ .title {
+ font-weight: 600;
+ font-size: 24px;
+ line-height: 32px;
+ color: #101828;
+ margin-bottom: 8px;
+ }
+ }
+ .desc {
+ font-weight: normal;
+ font-size: 16px;
+ line-height: 24px;
+ color: #667085;
+ }
+ form {
+ display: flex;
+ flex-direction: column;
+ gap: 20px;
+ input {
+ width: 360px;
+ background: #ffffff;
+ border: 1px solid #d0d5dd;
+ box-shadow: 0px 1px 2px rgba(16, 24, 40, 0.05);
+ border-radius: 8px;
+ padding: 10px 14px;
+ font-weight: normal;
+ font-size: 16px;
+ line-height: 24px;
+ color: #667085;
+ }
+ }
+ .btn {
+ display: inline-block;
+ text-align: center;
+ width: 100%;
+ font-weight: 500;
+ font-size: 16px;
+ line-height: 24px;
+ color: #ffffff;
+ padding: 10px;
+ background: #1fe1f9;
+ border: 1px solid #1fe1f9;
+ box-shadow: 0px 1px 2px rgba(16, 24, 40, 0.05);
+ border-radius: 8px;
+ &.google {
+ color: #344054;
+ border-color: #d0d5dd;
+ background: none;
+ }
+ }
+ }
+`;
+
+export default StyledWrapper;