This commit is contained in:
2022-03-21 04:29:58 +08:00
parent b0ae509531
commit 78c3c92905
8 changed files with 303 additions and 112 deletions
+10 -6
View File
@@ -1,15 +1,19 @@
import { BrowserRouter, Route, Routes } from "react-router-dom";
import Home from "./pages/home";
import Dashboard from "./pages/dashboard";
import { Provider } from "react-redux";
import store from "./store";
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/dashboard" element={<Dashboard />} />
</Routes>
</BrowserRouter>
<Provider store={store}>
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/dashboard" element={<Dashboard />} />
</Routes>
</BrowserRouter>
</Provider>
);
}
+167 -41
View File
@@ -1,10 +1,49 @@
import { useState } from "react";
import { animated, useSpring } from "@react-spring/web";
import { AnimatePresence, motion } from "framer-motion";
import { useEffect, useState } from "react";
import { sendSignInCode, signIn } from "../../telegram/telegram";
import user, {
login,
setCodeHash,
useSelectCodeHash,
useSelectorIsLoggedIn,
} from "../../store/user";
import { useDispatch } from "react-redux";
import { Link } from "react-router-dom";
import { getMe } from "../../telegram/user";
export default function Home() {
let [hiddenDrawer, setHiddenDrawer] = useState(true);
let dispatch = useDispatch();
let handleHiddenDrawer = (e: MouseEvent) => {
if (!hiddenDrawer) {
console.log(e.target);
setHiddenDrawer(true);
}
};
useEffect(() => {
document.addEventListener("click", handleHiddenDrawer);
return () => document.removeEventListener("click", handleHiddenDrawer);
});
useEffect(() => {
let dcID = localStorage.getItem("defaultDcId");
console.log(dcID);
let authKey = localStorage.getItem(dcID + "authKey");
let serverSalt = localStorage.getItem(dcID + "serverSalt");
console.log("authKey = %s", authKey);
console.log("serverSalt = %s", serverSalt);
getMe()
.then((user) => {
dispatch(login(user));
})
.catch((e) => {
console.log(e);
});
}, []);
return (
<div className={""}>
<div className={"h-screen w-screen bg-amber-400"}>
<Logo />
<Menu
@@ -38,32 +77,58 @@ function Logo() {
}
function Menu(props: { onClickLogin: () => void }) {
let loggedIn = useSelectorIsLoggedIn();
return (
<ul
<motion.ul
initial={{
y: 20,
opacity: 0,
}}
animate={{
y: 0,
opacity: 1,
transition: { type: "tween", duration: 1, ease: "easeInOut" },
}}
className={
"absolute right-8 top-0 m-4 flex justify-end gap-4 rounded-xl bg-base-200 px-12 py-4 shadow"
"absolute right-8 top-0 m-4 flex justify-end gap-4 rounded-l bg-base-200 px-8 py-2 shadow"
}
>
<li
className={"cursor-pointer select-none text-base hover:text-base-300"}
className={
"cursor-pointer select-none p-2 text-base hover:bg-amber-400 hover:bg-opacity-50"
}
>
</li>
<li
className={"cursor-pointer select-none text-base hover:text-base-300"}
onClick={props.onClickLogin}
>
/
</li>
</ul>
{!loggedIn ? (
<li
className={
"cursor-pointer select-none p-2 text-base hover:text-gray-500"
}
onClick={props.onClickLogin}
>
/
</li>
) : (
<Link to={"dashboard"}>
<li
className={
"cursor-pointer select-none p-2 text-base hover:text-gray-500"
}
>
</li>
</Link>
)}
</motion.ul>
);
}
function FileButton(props: { openLogin: () => void }) {
return (
<div className={"btn-group absolute top-1/2 left-1/4"}>
<button className={"btn"}></button>
<button className={"btn"} onClick={props.openLogin}>
<button className={"btn rounded-l-full"}></button>
<button className={"btn rounded-r-full"} onClick={props.openLogin}>
</button>
</div>
@@ -71,39 +136,100 @@ function FileButton(props: { openLogin: () => void }) {
}
function Drawer(props: { hidden: boolean; setHidden: () => void }) {
const styles = useSpring({
opacity: !props.hidden ? 1 : 0,
visibility: !props.hidden ? "visible" : "hidden",
});
let width = window.innerWidth;
return (
<animated.div style={styles}>
<div className={"absolute right-0 z-0 h-screen w-screen"}>
<div
className={"absolute z-40 h-screen w-screen bg-gray-400 opacity-60"}
onClick={() => {
props.setHidden();
}}
></div>
<div
className={
"absolute right-0 z-50 h-screen w-1/3 origin-right bg-base-100"
}
>
<div className={"container mt-20 flex items-center justify-center"}>
<LoginContent />
</div>
<AnimatePresence>
{props.hidden ? (
""
) : (
<div className={"h-screen w-screen overflow-hidden"}>
<motion.div
initial={{ translateX: width / 2 }}
animate={{ translateX: 0 }}
exit={{ translateX: width / 2 }}
transition={{ type: "spring", bounce: 0.25 }}
>
<div
className={
"absolute right-0 z-50 flex h-screen w-1/2 origin-right justify-center bg-base-100"
}
onClick={(e) => {
e.nativeEvent.stopImmediatePropagation();
}}
>
<div
className={
"z-50 flex h-full w-3/4 flex-col items-center justify-center gap-8"
}
>
<LoginContent setHidden={props.setHidden} />
</div>
</div>
</motion.div>
</div>
</div>
</animated.div>
)}
</AnimatePresence>
);
}
function LoginContent() {
function LoginContent(props: { setHidden: () => void }) {
let [phone, setPhone] = useState("");
let [phoneCode, setPhoneCode] = useState("");
let codeHash = useSelectCodeHash();
const dispatch = useDispatch();
let handleSendCode = () => {
sendSignInCode(phone)
.then((hash) => {
dispatch(setCodeHash(hash));
})
.catch((e) => {
alert(e.error_message);
});
};
let handleLogin = () => {
signIn(phone, phoneCode, codeHash)
.then((e) => {
dispatch(login(e.user));
props.setHidden();
alert("登录成功");
})
.catch((e) => {
alert(e.error_message);
});
};
return (
<div className={"flex bg-base-100"}>
<label className={"label mr-5 text-base-content"}></label>
<input className={"input input-primary"} />
<div className={"flex flex-col gap-8 rounded-2xl border-2 p-16"}>
{codeHash === "" ? (
<>
<div className={"flex bg-base-100"}>
<label className={"label mr-5 text-base-content"}></label>
<input
className={"input input-primary"}
value={phone}
onChange={(e) => setPhone(e.target.value)}
/>
</div>
<button className={"btn self-end"} onClick={handleSendCode}>
</button>
</>
) : (
<div className={"flex flex-col gap-8"}>
<label className={"label mr-5 text-base-content"}></label>
<input
className={"input input-primary"}
value={phoneCode}
onChange={(e) => setPhoneCode(e.target.value)}
/>
<button className={"btn self-end"} onClick={handleLogin}>
</button>
</div>
)}
</div>
);
}
+11
View File
@@ -0,0 +1,11 @@
import { configureStore, getDefaultMiddleware } from "@reduxjs/toolkit";
import userReducer from "./store/user";
export default configureStore({
reducer: {
user: userReducer,
},
middleware: getDefaultMiddleware({
serializableCheck: false,
}),
});
+40
View File
@@ -0,0 +1,40 @@
import { createSlice } from "@reduxjs/toolkit";
import { useSelector } from "react-redux";
const User = createSlice({
name: "user",
initialState: {
codeHash: "",
isLoggedIn: false,
user: {},
},
reducers: {
login: (state, action) => {
state.isLoggedIn = true;
state.user = action.payload;
},
logout: (state) => {
state.isLoggedIn = false;
state.user = {};
},
setCodeHash: (state, action) => {
state.codeHash = action.payload;
},
},
});
export function useSelectorUser() {
return useSelector((state: any) => state.user.user);
}
export function useSelectorIsLoggedIn() {
return useSelector((state: any) => state.user.isLoggedIn);
}
export function useSelectCodeHash() {
return useSelector((state: any) => state.user.codeHash);
}
export const { login, logout, setCodeHash } = User.actions;
export default User.reducer;
+4 -4
View File
@@ -15,7 +15,7 @@ class TelegramHelper {
this.client = new Client({
api_id: appID,
api_hash: appHash,
test: false,
test: true,
});
} else {
let createTransport = function (dc: any, crypto: any) {
@@ -47,15 +47,15 @@ class TelegramHelper {
hideLog: boolean = false
): Promise<any> {
try {
!hideLog && console.log(`${method} req\n${params}`);
!hideLog && console.debug(`${method} req\n%o`, params);
options = {
...options,
};
let resp = await this.client.call(method, params, options);
!hideLog && console.log(`${method} resp\n${resp}`);
!hideLog && console.debug(`${method} resp\n%o`, resp);
return resp;
} catch (error) {
!hideLog && console.log(`${method} error:`, error);
!hideLog && console.debug(`${method} error\n%o`, error);
// @ts-ignore
const { error_code, error_message } = error;