Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,6 @@ export enum Status {
AuthFailed,
}

export enum Sex {
Man = "Man",
Woman = "Woman",
}

export enum FileConvertStep {
None = "None",
Converting = "Converting",
Expand Down
25 changes: 16 additions & 9 deletions desktop/renderer-app/src/api-middleware/flatServer/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Region } from "flat-components";
import { RoomStatus, RoomType, Sex, Week } from "./constants";
import { RoomStatus, RoomType, Week } from "./constants";
import { post, postNotAuth } from "./utils";

export interface CreateOrdinaryRoomPayload {
Expand Down Expand Up @@ -451,22 +451,18 @@ export async function updatePeriodicSubRoom(payload: UpdatePeriodicSubRoomPayloa
);
}

export interface LoginCheckPayload {
type: "web" | "mobile";
}
export interface LoginCheckPayload {}

export interface LoginCheckResult {
name: string;
sex: Sex;
avatar: string;
token: string;
userUUID: string;
hasPhone: boolean;
}

export async function loginCheck(): Promise<LoginCheckResult> {
return await post<LoginCheckPayload, LoginCheckResult>("login", {
type: "web",
});
return await post<LoginCheckPayload, LoginCheckResult>("login", {});
}

export interface setAuthUUIDPayload {
Expand All @@ -489,7 +485,6 @@ export interface LoginProcessPayload {

export interface LoginProcessResult {
name: string;
sex: Sex;
avatar: string;
userUUID: string;
token: string;
Expand Down Expand Up @@ -557,3 +552,15 @@ export async function bindingPhone(phone: string, code: number): Promise<Binding
code,
});
}

export interface RenamePayload {
name: string;
}

export type RenameResult = {};

export async function rename(name: string): Promise<RenameResult> {
return await post<RenamePayload, RenameResult>("user/rename", {
name,
});
}
200 changes: 99 additions & 101 deletions desktop/renderer-app/src/components/MainPageLayoutContainer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
SVGLogout,
WindowsSystemBtnItem,
} from "flat-components";
import { observer } from "mobx-react-lite";
import { useTranslation } from "react-i18next";
import { routeConfig, RouteNameType } from "../../route-config";
import { GlobalStoreContext } from "../StoreProvider";
Expand All @@ -34,119 +35,116 @@ export interface MainPageLayoutContainerProps {
onRouteChange?: MainPageLayoutProps["onClick"];
}

export const MainPageLayoutContainer: React.FC<MainPageLayoutContainerProps> = ({
subMenu,
children,
activeKeys,
onRouteChange,
}) => {
const { t } = useTranslation();
const sideMenu = [
{
key: routeConfig[RouteNameType.HomePage].path,
title: "home",
route: routeConfig[RouteNameType.HomePage].path,
icon: (active: boolean): React.ReactNode => {
return active ? <SVGHomeFilled /> : <SVGHomeOutlined />;
export const MainPageLayoutContainer = observer<MainPageLayoutContainerProps>(
function MainPageLayoutContainer({ subMenu, children, activeKeys, onRouteChange }) {
const { t } = useTranslation();
const sideMenu = [
{
key: routeConfig[RouteNameType.HomePage].path,
title: "home",
route: routeConfig[RouteNameType.HomePage].path,
icon: (active: boolean): React.ReactNode => {
return active ? <SVGHomeFilled /> : <SVGHomeOutlined />;
},
},
},
{
key: routeConfig[RouteNameType.CloudStoragePage].path,
title: "cloudStorage",
route: routeConfig[RouteNameType.CloudStoragePage].path,
icon: (active: boolean): React.ReactNode => {
return active ? <SVGCloudFilled /> : <SVGCloudOutlined />;
{
key: routeConfig[RouteNameType.CloudStoragePage].path,
title: "cloudStorage",
route: routeConfig[RouteNameType.CloudStoragePage].path,
icon: (active: boolean): React.ReactNode => {
return active ? <SVGCloudFilled /> : <SVGCloudOutlined />;
},
},
},
];
];

const sideMenuFooter = [
{
key: "deviceCheck",
title: "deviceCheck",
route: routeConfig[RouteNameType.SystemCheckPage].path,
icon: (active: boolean): React.ReactNode => {
return active ? <SVGTestFilled /> : <SVGTest />;
const sideMenuFooter = [
{
key: "deviceCheck",
title: "deviceCheck",
route: routeConfig[RouteNameType.SystemCheckPage].path,
icon: (active: boolean): React.ReactNode => {
return active ? <SVGTestFilled /> : <SVGTest />;
},
},
},
];
];

const popMenu = [
{
key: routeConfig[RouteNameType.GeneralSettingPage].path,
icon: (): React.ReactNode => <SVGSetting />,
title: t("settings"),
route: routeConfig[RouteNameType.GeneralSettingPage].path,
},
{
key: "feedback",
icon: (): React.ReactNode => <SVGFeedback />,
title: t("feedback"),
route: "https://github.com/netless-io/flat/issues",
},
{
key: "logout",
icon: (): React.ReactNode => <SVGLogout />,
title: <span className="logout-title">{t("logout")}</span>,
route: routeConfig[RouteNameType.LoginPage].path,
},
];
const popMenu = [
{
key: routeConfig[RouteNameType.GeneralSettingPage].path,
icon: (): React.ReactNode => <SVGSetting />,
title: t("settings"),
route: routeConfig[RouteNameType.GeneralSettingPage].path,
},
{
key: "feedback",
icon: (): React.ReactNode => <SVGFeedback />,
title: t("feedback"),
route: "https://github.com/netless-io/flat/issues",
},
{
key: "logout",
icon: (): React.ReactNode => <SVGLogout />,
title: <span className="logout-title">{t("logout")}</span>,
route: routeConfig[RouteNameType.LoginPage].path,
},
];

const location = useLocation();
const location = useLocation();

activeKeys ??= [location.pathname];
activeKeys ??= [location.pathname];

const history = useHistory();
const history = useHistory();

const globalStore = useContext(GlobalStoreContext);
const globalStore = useContext(GlobalStoreContext);

const onMenuItemClick = (mainPageLayoutItem: MainPageLayoutItem): void => {
if (mainPageLayoutItem.key === "logout") {
globalStore.logout();
}
const onMenuItemClick = (mainPageLayoutItem: MainPageLayoutItem): void => {
if (mainPageLayoutItem.key === "logout") {
globalStore.logout();
}

if (mainPageLayoutItem.route.startsWith("/")) {
onRouteChange
? onRouteChange(mainPageLayoutItem)
: history.push(mainPageLayoutItem.route);
} else {
void shell.openExternal(mainPageLayoutItem.route);
}
};
if (mainPageLayoutItem.route.startsWith("/")) {
onRouteChange
? onRouteChange(mainPageLayoutItem)
: history.push(mainPageLayoutItem.route);
} else {
void shell.openExternal(mainPageLayoutItem.route);
}
};

const topBarMenu = [
{
key: "github",
icon: <SVGGithub />,
route: "https://github.com/netless-io/flat/",
},
];
const topBarMenu = [
{
key: "github",
icon: <SVGGithub />,
route: "https://github.com/netless-io/flat/",
},
];

const onClickTopBarMenu = (mainPageTopBarMenuItem: MainPageTopBarMenuItem): void => {
void shell.openExternal(mainPageTopBarMenuItem.route);
};
const onClickTopBarMenu = (mainPageTopBarMenuItem: MainPageTopBarMenuItem): void => {
void shell.openExternal(mainPageTopBarMenuItem.route);
};

const onClickWindowsSystemBtn = (winSystemBtn: WindowsSystemBtnItem): void => {
ipcAsyncByMainWindow("set-win-status", { windowStatus: winSystemBtn });
};
const onClickWindowsSystemBtn = (winSystemBtn: WindowsSystemBtnItem): void => {
ipcAsyncByMainWindow("set-win-status", { windowStatus: winSystemBtn });
};

return (
<MainPageLayout
activeKeys={activeKeys}
avatarSrc={globalStore.userInfo?.avatar ?? ""}
generateAvatar={generateAvatar}
isWin={runtime.isWin}
popMenu={popMenu}
sideMenu={sideMenu}
sideMenuFooter={sideMenuFooter}
subMenu={subMenu}
topBarMenu={topBarMenu}
userName={globalStore.userInfo?.name ?? ""}
onClick={onMenuItemClick}
onClickTopBarMenu={onClickTopBarMenu}
onClickWindowsSystemBtn={onClickWindowsSystemBtn}
>
{children}
</MainPageLayout>
);
};
return (
<MainPageLayout
activeKeys={activeKeys}
avatarSrc={globalStore.userInfo?.avatar ?? ""}
generateAvatar={generateAvatar}
isWin={runtime.isWin}
popMenu={popMenu}
sideMenu={sideMenu}
sideMenuFooter={sideMenuFooter}
subMenu={subMenu}
topBarMenu={topBarMenu}
userName={globalStore.userInfo?.name ?? ""}
onClick={onMenuItemClick}
onClickTopBarMenu={onClickTopBarMenu}
onClickWindowsSystemBtn={onClickWindowsSystemBtn}
>
{children}
</MainPageLayout>
);
},
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React, { useCallback, useState } from "react";
import { Button } from "antd";
import { useTranslation } from "react-i18next";
import { useSafePromise } from "../../../utils/hooks/lifecycle";

export interface ConfirmButtonsProps {
onConfirm: () => Promise<void>;
}

export const ConfirmButtons: React.FC<ConfirmButtonsProps> = ({ onConfirm }) => {
const sp = useSafePromise();
const { t } = useTranslation();
const [loading, setLoading] = useState(false);
const [phase, setPhase] = useState<"idle" | "confirm">("idle");

const confirm = useCallback(async () => {
setLoading(true);
await sp(onConfirm());
setLoading(false);
setPhase("idle");
}, [onConfirm, sp]);

if (phase === "idle") {
return (
<Button type="link" onClick={() => setPhase("confirm")}>
{t("modify")}
</Button>
);
} else {
return (
<>
<Button disabled={loading} loading={loading} type="primary" onClick={confirm}>
{t("confirm")}
</Button>
<Button onClick={() => setPhase("idle")}>{t("cancel")}</Button>
</>
);
}
};
Original file line number Diff line number Diff line change
@@ -1,22 +1,42 @@
import "./style.less";

import { Checkbox, Radio, RadioChangeEvent } from "antd";
import React, { useContext, useEffect, useState } from "react";
import { Checkbox, Input, Radio, RadioChangeEvent } from "antd";
import { UserSettingLayoutContainer } from "../UserSettingLayoutContainer";
import { ipcSyncByApp, ipcAsyncByApp } from "../../../utils/ipc";
import { useTranslation } from "react-i18next";
import { AppearancePicker, FlatPrefersColorScheme } from "flat-components";
import { ConfigStoreContext } from "../../../components/StoreProvider";
import { ConfigStoreContext, GlobalStoreContext } from "../../../components/StoreProvider";
import { useSafePromise } from "../../../utils/hooks/lifecycle";
import { loginCheck, rename } from "../../../api-middleware/flatServer";
import { ConfirmButtons } from "./ConfirmButtons";

enum SelectLanguage {
Chinese,
English,
}

export const GeneralSettingPage = (): React.ReactElement => {
const sp = useSafePromise();
const { t, i18n } = useTranslation();
const [openAtLogin, setOpenAtLogin] = useState(false);
const configStore = useContext(ConfigStoreContext);
const globalStore = useContext(GlobalStoreContext);

const [name, setName] = useState(globalStore.userName || "");
const [isRenaming, setRenaming] = useState(false);

async function changeUserName(): Promise<void> {
if (name !== globalStore.userName) {
setRenaming(true);
await sp(rename(name));
setRenaming(false);
// Refresh user info in global store.
const result = await sp(loginCheck());
globalStore.updateUserInfo(result);
globalStore.updateLastLoginCheck(Date.now());
}
}

useEffect(() => {
ipcSyncByApp("get-open-at-login")
Expand Down Expand Up @@ -55,6 +75,17 @@ export const GeneralSettingPage = (): React.ReactElement => {
</span>
</Checkbox>
</div>
<div className="general-setting-user-profile">
<span>{t("user-profile")}</span>
<Input
disabled={isRenaming}
id="username"
spellCheck={false}
value={name}
onChange={ev => setName(ev.currentTarget.value)}
/>
<ConfirmButtons onConfirm={changeUserName} />
</div>
<div className="general-setting-select-language">
<span>{t("language-settings")}</span>
<Radio.Group
Expand Down
Loading