master
icechen 2022-03-01 20:22:44 +08:00
parent 473d3e55c7
commit be3da0a45d
12 changed files with 306 additions and 55 deletions

View File

@ -94,6 +94,6 @@ body {
} }
.receiveInputClose { .receiveInputClose {
position: absolute; position: absolute !important;
right: 20px; right: 20px;
} }

View File

@ -15,23 +15,24 @@ function CountriesInput(props: {
let [countriesList, setCountriesList] = useState([] as Country[]); let [countriesList, setCountriesList] = useState([] as Country[]);
useEffect(() => { useEffect(() => {
Telegram.call("help.getCountriesList").then((result: any) => { Telegram.call("help.getCountriesList", undefined, undefined, true).then(
console.log("country:", result); (result: any) => {
let resp: Country[] = []; let resp: Country[] = [];
result.countries.map((country: any) => { result.countries.map((country: any) => {
resp.push({ resp.push({
default_name: country.default_name, default_name: country.default_name,
country_code: country.country_codes[0].country_code, country_code: country.country_codes[0].country_code,
// patterns: // patterns:
// country.country_codes[0]?.patterns.length > 0 // country.country_codes[0]?.patterns.length > 0
// ? country.country_codes[0]?.patterns[0] // ? country.country_codes[0]?.patterns[0]
// : "", // : "",
iso2: country.iso2, iso2: country.iso2,
});
return true;
}); });
return true; setCountriesList(resp);
}); }
setCountriesList(resp); );
});
}, []); }, []);
return ( return (

7
src/global.d.ts vendored
View File

@ -1,2 +1,9 @@
declare module "mtproton/envs/browser"; declare module "mtproton/envs/browser";
declare module "mtproton/src/utils/common"; declare module "mtproton/src/utils/common";
declare module "mtproton/src/index";
declare module "mtproton/envs/browser/sha1";
declare module "mtproton/envs/browser/sha256";
declare module "mtproton/envs/browser/pbkdf2";
declare module "mtproton/envs/browser/transport";
declare module "mtproton/envs/browser/get-random-bytes";
declare module "mtproton/envs/browser/get-local-storage";

View File

@ -4,15 +4,19 @@ import reportWebVitals from "./reportWebVitals";
import Dashboard from "./pages/dashboard"; import Dashboard from "./pages/dashboard";
import { BrowserRouter, Routes, Route } from "react-router-dom"; import { BrowserRouter, Routes, Route } from "react-router-dom";
import Home from "./pages/home"; import Home from "./pages/home";
import { Provider } from "react-redux";
import store from "./store";
ReactDOM.render( ReactDOM.render(
<React.StrictMode> <React.StrictMode>
<BrowserRouter> <Provider store={store}>
<Routes> <BrowserRouter>
<Route path="/" element={<Home />} /> <Routes>
<Route path="/dashboard" element={<Dashboard />} /> <Route path="/" element={<Home />} />
</Routes> <Route path="/dashboard" element={<Dashboard />} />
</BrowserRouter> </Routes>
</BrowserRouter>
</Provider>
</React.StrictMode>, </React.StrictMode>,
document.getElementById("root") document.getElementById("root")
); );

View File

@ -1,6 +1,31 @@
import style from "./style.module.css"; import style from "./style.module.css";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import React, { useState } from "react";
import {
Divider,
IconButton,
Menu,
MenuItem,
Paper,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
} from "@mui/material";
import MoreHorizIcon from "@mui/icons-material/MoreHoriz";
enum ContentType {
File,
Share,
SafeBox,
Recycled,
}
function Login() { function Login() {
let [type, setType] = useState(ContentType.File);
return ( return (
<div <div
style={{ style={{
@ -11,17 +36,100 @@ function Login() {
}} }}
> >
<div className={style.menu}> <div className={style.menu}>
<li></li> <li onClick={() => setType(ContentType.File)}></li>
<li></li> <li onClick={() => setType(ContentType.Share)}></li>
<li></li> <li onClick={() => setType(ContentType.SafeBox)}></li>
<li></li> <li onClick={() => setType(ContentType.Recycled)}></li>
<Link to={`/`}> <Link to={`/`}>
<div className={style.logo}>LOGO</div> <div className={style.logo}>LOGO</div>
</Link> </Link>
</div> </div>
<div></div> <div className={style.content}>
{type === ContentType.File && <File />}
{type === ContentType.Share && <Share />}
{type === ContentType.SafeBox && <SafeBox />}
{type === ContentType.Recycled && <Recycled />}
</div>
</div> </div>
); );
} }
function File() {
let [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
const open = Boolean(anchorEl);
let handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
setAnchorEl(event.currentTarget);
};
let handleClose = () => {
setAnchorEl(null);
};
return (
<div
style={{
display: "flex",
alignItems: "center",
height: "100%",
width: "100%",
}}
>
<Paper sx={{ padding: "100px", width: "100%" }}>
<TableContainer sx={{ backgroundColor: "#f2f2f2" }}>
<Table aria-label={"文件列表"}>
<TableHead>
<TableRow>
<TableCell sx={{ width: "70%" }}></TableCell>
<TableCell></TableCell>
<TableCell></TableCell>
</TableRow>
</TableHead>
<TableBody>
<TableRow>
<TableCell sx={{ position: "relative" }}>
xxx
<IconButton
sx={{ position: "absolute", right: 20 }}
onClick={handleClick}
>
<MoreHorizIcon />
</IconButton>
</TableCell>
<TableCell>2020-01-01 12:12:12</TableCell>
<TableCell>128MB</TableCell>
</TableRow>
</TableBody>
</Table>
</TableContainer>
</Paper>
<Menu
open={open}
id="basic-menu"
anchorEl={anchorEl}
onClose={handleClose}
>
<MenuItem onClick={handleClose}></MenuItem>
<MenuItem onClick={handleClose}></MenuItem>
<Divider />
<MenuItem onClick={handleClose}></MenuItem>
<MenuItem onClick={handleClose}></MenuItem>
<MenuItem onClick={handleClose}></MenuItem>
<MenuItem onClick={handleClose}></MenuItem>
<MenuItem onClick={handleClose}></MenuItem>
</Menu>
</div>
);
}
function Share() {
return <div></div>;
}
function SafeBox() {
return <div></div>;
}
function Recycled() {
return <div></div>;
}
export default Login; export default Login;

View File

@ -32,3 +32,10 @@
font-size: 48px; font-size: 48px;
cursor: pointer; cursor: pointer;
} }
.content {
display: flex;
flex-direction: column;
width: 100%;
height: 100vh;
}

View File

@ -5,24 +5,33 @@ import style from "./style.module.css";
import { Box, Drawer } from "@mui/material"; import { Box, Drawer } from "@mui/material";
import { HomeMenu } from "../../component/homeMenu"; import { HomeMenu } from "../../component/homeMenu";
import { HomeSignIn } from "../../component/homeSignIn"; import { HomeSignIn } from "../../component/homeSignIn";
import { useDispatch } from "react-redux";
import { useSelectorIsLoggedIn, useSelectorUser } from "../../store/user";
import { login } from "../../store/user";
function Home() { function Home() {
let [isSignIn, setIsSignIn] = useState(false); // let [isSignIn, setIsSignIn] = useState(false);
const dispatch = useDispatch();
let isSignIn = useSelectorIsLoggedIn();
let [isOpenSignIn, setIsOpenSignIn] = useState(false); let [isOpenSignIn, setIsOpenSignIn] = useState(false);
let user = useSelectorUser();
useEffect(function () { useEffect(
getMe() function () {
.then(function (user) { getMe()
// 已登录 .then(function (user) {
setIsSignIn(true); // 已登录
}) dispatch(login(user));
.catch(function (error) { })
if (error.code === 401) { .catch(function (error) {
// Unauthorized if (error.code === 401) {
} // Unauthorized
console.log(error); }
}); console.log(error);
}, []); });
},
[dispatch]
);
return ( return (
<div className={style.box}> <div className={style.box}>
@ -34,7 +43,6 @@ function Home() {
}} }}
/> />
</div> </div>
<HomeMenu <HomeMenu
className={style.homeMenu} className={style.homeMenu}
isSignIn={isSignIn} isSignIn={isSignIn}
@ -42,7 +50,7 @@ function Home() {
setIsOpenSignIn(true); setIsOpenSignIn(true);
}} }}
/> />
{user.user && <div>{user.user.username}</div>}
<Drawer <Drawer
anchor={"right"} anchor={"right"}
open={isOpenSignIn && !isSignIn} open={isOpenSignIn && !isSignIn}

21
src/storage.ts 100644
View File

@ -0,0 +1,21 @@
function getLocalStorage() {
return {
set(key: string, value: string) {
return window.localStorage.setItem(key, value);
},
get(key: string) {
return window.localStorage.getItem(key);
},
setObject(key: string, value: any) {
return window.localStorage.setItem(key, JSON.stringify(value));
},
getObject(key: string) {
return JSON.parse(window.localStorage.getItem(key)?.toString() || "{}");
},
};
}
export default getLocalStorage;

View File

@ -1,7 +1,8 @@
import { configureStore } from "@reduxjs/toolkit"; import { configureStore } from "@reduxjs/toolkit";
import userReducer from "./store/user";
export default configureStore({ export default configureStore({
reducer: { reducer: {
user: (state) => {}, user: userReducer,
}, },
}); });

View File

@ -0,0 +1,29 @@
import { createSlice } from "@reduxjs/toolkit";
import { useSelector } from "react-redux";
import storage from "../storage";
const FileList = createSlice({
name: "fileList",
initialState: {
fileList: [],
},
reducers: {
updateOfStorage: (state) => {
state.fileList = storage().getObject("fileList");
},
addFileOfStorage: (state, action) => {
// @ts-ignore
state.fileList.push(action.payload);
storage().setObject("fileList", state.fileList);
},
},
});
export function useSelectorFileList() {
return useSelector((state: any) => state.fileList);
}
export const { updateOfStorage } = FileList.actions;
export default FileList.reducer;

32
src/store/user.ts 100644
View File

@ -0,0 +1,32 @@
import { createSlice } from "@reduxjs/toolkit";
import { useSelector } from "react-redux";
const User = createSlice({
name: "user",
initialState: {
isLoggedIn: false,
user: {},
},
reducers: {
login: (state, action) => {
state.isLoggedIn = true;
state.user = action.payload;
},
logout: (state) => {
state.isLoggedIn = false;
state.user = {};
},
},
});
export function useSelectorUser() {
return useSelector((state: any) => state.user.user);
}
export function useSelectorIsLoggedIn() {
return useSelector((state: any) => state.user.isLoggedIn);
}
export const { login, logout } = User.actions;
export default User.reducer;

View File

@ -1,26 +1,59 @@
import Client from "mtproton/envs/browser"; import Client from "mtproton/envs/browser";
import { rand_id } from "../utils/rand"; import { rand_id } from "../utils/rand";
import { obj } from "../utils/log"; import { obj } from "../utils/log";
import makeMTProto from "mtproton/src/index";
import SHA1 from "mtproton/envs/browser/sha1";
import SHA256 from "mtproton/envs/browser/sha256";
import PBKDF2 from "mtproton/envs/browser/pbkdf2";
import Transport from "mtproton/envs/browser/transport";
import getRandomBytes from "mtproton/envs/browser/get-random-bytes";
import getLocalStorage from "mtproton/envs/browser/get-local-storage";
class TelegramHelper { class TelegramHelper {
private client: any; private client: any;
constructor(appID: number, appHash: string) { constructor(appID: number, appHash: string, custom: boolean = false) {
this.client = new Client({ if (custom) {
api_id: appID, this.client = new Client({
api_hash: appHash, api_id: appID,
test: true, api_hash: appHash,
}); test: true,
});
} else {
let createTransport = function (dc: any, crypto: any) {
return new Transport(dc, crypto);
};
const MTProto = makeMTProto({
SHA1,
SHA256,
PBKDF2,
getRandomBytes,
getLocalStorage,
createTransport,
});
this.client = new MTProto({
api_id: appID,
api_hash: appHash,
test: true,
});
}
this.client.setDefaultDc(1); this.client.setDefaultDc(1);
} }
async call(method: string, params?: object, options?: object): Promise<any> { async call(
method: string,
params?: object,
options?: object,
hideLog: boolean = false
): Promise<any> {
try { try {
console.dir(`${method} req\n${obj(params)}`); !hideLog && console.dir(`${method} req\n${obj(params)}`);
let resp = await this.client.call(method, params, options); let resp = await this.client.call(method, params, options);
console.dir(`${method} resp\n${obj(resp)}`); !hideLog && console.dir(`${method} resp\n${obj(resp)}`);
return resp; return resp;
} catch (error) { } catch (error) {
console.log(`${method} error:`, error); !hideLog && console.log(`${method} error:`, error);
// @ts-ignore // @ts-ignore
const { error_code, error_message } = error; const { error_code, error_message } = error;