Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(error-tips): add error tips when server request failed #304

Merged
merged 3 commits into from
Feb 19, 2021
Merged
Show file tree
Hide file tree
Changes from all 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
61 changes: 23 additions & 38 deletions src/renderer-app/src/apiMiddleware/flatServer/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import Axios from "axios";
import { globalStore } from "../../stores/GlobalStore";
import { DocsType, FLAT_SERVER_VERSIONS, RoomDoc, RoomStatus, RoomType, Week } from "./constants";
import { DocsType, RoomDoc, RoomStatus, RoomType, Week } from "./constants";
import { post } from "./utils";

export interface CreateOrdinaryRoomPayload {
Expand Down Expand Up @@ -268,38 +266,38 @@ export function stopClass(roomUUID: string): Promise<StopClassResult> {
return post<StopClassPayload, StopClassResult>("room/update-status/stopped", { roomUUID });
}

export type CancelOrdinaryRoomResult = {};
type CancelOrdinaryRoomResult = {};

export interface CancelOrdinaryRoomPayload {
interface CancelOrdinaryRoomPayload {
roomUUID: string;
}

export function cancelOrdinaryRoom(roomUUID: string): Promise<CancelOrdinaryRoomResult> {
function cancelOrdinaryRoom(roomUUID: string): Promise<CancelOrdinaryRoomResult> {
return post<CancelOrdinaryRoomPayload, CancelOrdinaryRoomResult>("room/cancel/ordinary", {
roomUUID,
});
}

export type CancelPeriodicRoomResult = {};
type CancelPeriodicRoomResult = {};

export interface CancelPeriodicRoomPayload {
interface CancelPeriodicRoomPayload {
periodicUUID: string;
}

export function cancelPeriodicRoom(periodicUUID: string): Promise<CancelPeriodicRoomResult> {
function cancelPeriodicRoom(periodicUUID: string): Promise<CancelPeriodicRoomResult> {
return post<CancelPeriodicRoomPayload, CancelPeriodicRoomResult>("room/cancel/periodic", {
periodicUUID,
});
}

export type CancelPeriodicSubRoomResult = {};
type CancelPeriodicSubRoomResult = {};

export interface CancelPeriodicSubRoomPayload {
interface CancelPeriodicSubRoomPayload {
roomUUID: string;
periodicUUID: string;
}

export function cancelPeriodicSubRoom(
function cancelPeriodicSubRoom(
payload: CancelPeriodicSubRoomPayload,
): Promise<CancelPeriodicSubRoomResult> {
return post<CancelPeriodicSubRoomPayload, CancelPeriodicSubRoomResult>(
Expand All @@ -308,6 +306,18 @@ export function cancelPeriodicSubRoom(
);
}

type CancelHistoryRoomResult = {};

interface CancelHistoryRoomPayload {
roomUUID: string;
}

function cancelHistoryRoom(roomUUID: string): Promise<CancelHistoryRoomResult> {
return post<CancelHistoryRoomPayload, CancelHistoryRoomResult>("room/cancel/history", {
roomUUID,
});
}

export type CancelRoomResult = {};

export type CancelRoomPayload = {
Expand Down Expand Up @@ -344,18 +354,6 @@ export function cancelRoom({
return;
}

export type CancelHistoryRoomResult = {};

export interface CancelHistoryRoomPayload {
roomUUID: string;
}

export function cancelHistoryRoom(roomUUID: string): Promise<CancelHistoryRoomResult> {
return post<CancelHistoryRoomPayload, CancelHistoryRoomResult>("room/cancel/history", {
roomUUID,
});
}

export interface StartRecordRoomPayload {
roomUUID: string;
}
Expand Down Expand Up @@ -499,18 +497,5 @@ export interface LoginCheck {
}

export async function loginCheck(): Promise<LoginCheck> {
const Authorization = globalStore.wechat?.token;
if (!Authorization) {
throw new Error("not login");
}
const { data } = await Axios.post<LoginCheck>(
`${FLAT_SERVER_VERSIONS.V1HTTPS}/login`,
undefined,
{
headers: {
Authorization: "Bearer " + Authorization,
},
},
);
return data;
return await post<{}, LoginCheck>("/login", {});
}
19 changes: 10 additions & 9 deletions src/renderer-app/src/apiMiddleware/flatServer/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import Axios, { AxiosRequestConfig } from "axios";
import { globalStore } from "../../stores/GlobalStore";
import { FLAT_SERVER_VERSIONS, Status } from "./constants";
import { ServerRequestError } from "../../utils/error/ServerRequestError";
import { RequestErrorCode } from "../../constants/ErrorCode";

export type FlatServerResponse<T> =
| {
Expand All @@ -9,7 +11,7 @@ export type FlatServerResponse<T> =
}
| {
status: Status.Failed;
code: number;
code: RequestErrorCode;
};

export async function post<Payload, Result>(
Expand All @@ -22,23 +24,22 @@ export async function post<Payload, Result>(
};

const Authorization = globalStore.wechat?.token;
if (Authorization) {
config.headers = {
Authorization: "Bearer " + Authorization,
};
} else {
throw new Error("not login");
if (!Authorization) {
throw new ServerRequestError(RequestErrorCode.NeedLoginAgain);
}

config.headers = {
Authorization: "Bearer " + Authorization,
};

const { data: res } = await Axios.post<FlatServerResponse<Result>>(
`${FLAT_SERVER_VERSIONS.V1HTTPS}/${action}`,
payload,
config,
);

if (res.status !== Status.Success) {
// @TODO handle fetcher error
throw new Error(`Flat server error code ${res.code} for location "${action}".`);
throw new ServerRequestError(res.code);
}

return res.data;
Expand Down
3 changes: 2 additions & 1 deletion src/renderer-app/src/components/Modal/InviteModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { RoomItem } from "../../stores/RoomStore";
import { GlobalStoreContext, RoomStoreContext } from "../StoreProvider";
import { clipboard } from "electron";
import { getWeekNames } from "../WeekRateSelector";
import { errorTips } from "../Tips/ErrorTips";

const completeTimeFormat = format("yyyy-MM-dd HH:mm");
const onlySuffixTimeFormat = format("HH:mm");
Expand All @@ -29,7 +30,7 @@ export const InviteModal = observer<InviteModalProps>(function InviteModal({

useEffect(() => {
if (periodicUUID) {
void roomStore.syncPeriodicRoomInfo(periodicUUID);
roomStore.syncPeriodicRoomInfo(periodicUUID).catch(errorTips);
}
}, [periodicUUID, roomStore]);

Expand Down
2 changes: 2 additions & 0 deletions src/renderer-app/src/components/Modal/RemoveRoomModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { observer } from "mobx-react-lite";
import { Button, Checkbox, message, Modal } from "antd";
import React, { useState } from "react";
import { roomStore } from "../../stores/RoomStore";
import { errorTips } from "../Tips/ErrorTips";

interface RemoveRoomModalProps {
cancelModalVisible: boolean;
Expand Down Expand Up @@ -98,6 +99,7 @@ export const RemoveRoomModal = observer<RemoveRoomModalProps>(function RemoveRoo
message.success(content);
} catch (e) {
console.error(e);
errorTips(e);
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import React, { useState } from "react";
import { RoomItem, roomStore } from "../../stores/RoomStore";
import { RemoveHistoryRoomModal } from "../Modal/RemoveHistoryRoomModal";
import { useSafePromise } from "../../utils/hooks/lifecycle";
import { errorTips } from "../Tips/ErrorTips";

interface DeleteRoomHistoryItemProps extends MenuItemProps {
room: RoomItem | undefined;
Expand Down Expand Up @@ -33,6 +34,7 @@ export const DeleteRoomHistoryItem = observer<DeleteRoomHistoryItemProps>(
setShowRemoveHistoryRoomModal(false);
} catch (e) {
console.error(e);
errorTips(e);
} finally {
setLoading(false);
}
Expand Down
15 changes: 15 additions & 0 deletions src/renderer-app/src/components/Tips/ErrorTips.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { message } from "antd";
import { ServerRequestError } from "../../utils/error/ServerRequestError";
import { NODE_ENV } from "../../constants/Process";

export const errorTips = (e: Error): void => {
if (NODE_ENV === "development") {
console.error(e);
}

if (e instanceof ServerRequestError) {
void message.error(e.errorMessage);
} else {
void message.error(e.message);
}
};
53 changes: 53 additions & 0 deletions src/renderer-app/src/constants/ErrorCode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// see: https://github.com/netless-io/flat-server/blob/main/src/ErrorCode.ts
export enum RequestErrorCode {
ParamsCheckFailed = 100000,
ServerFail,
CurrentProcessFailed,
NotPermission,
NeedLoginAgain,
UnsupportedPlatform,
JWTSignFailed,

RoomNotFound = 200000,
RoomIsEnded,
RoomIsRunning,
RoomNotIsRunning,
RoomNotIsEnded,
RoomNotIsIdle,

PeriodicNotFound = 300000,
PeriodicIsEnded,
PeriodicSubRoomHasRunning,

UserNotFound = 400000,

RecordNotFound = 500000,
}

export const RequestErrorMessage = {
// request parameter error
[RequestErrorCode.ParamsCheckFailed]: "参数错误",
// this error may occur in high concurrency situations, the request should be retried
[RequestErrorCode.ServerFail]: "请求失败",
// server operation failed, possibly due to database failure or other reasons
[RequestErrorCode.CurrentProcessFailed]: "请求出错",
[RequestErrorCode.NotPermission]: "没有权限操作",
[RequestErrorCode.NeedLoginAgain]: "凭证已过期,请重新登录",
[RequestErrorCode.UnsupportedPlatform]: "不支持的登录平台",
[RequestErrorCode.JWTSignFailed]: "认证信息校验失败,请重新登录",

[RequestErrorCode.RoomNotFound]: "房间不存在",
[RequestErrorCode.RoomIsEnded]: "房间已结束",
[RequestErrorCode.RoomIsRunning]: "房间正在进行中",
[RequestErrorCode.RoomNotIsRunning]: "房间不在进行中",
[RequestErrorCode.RoomNotIsEnded]: "房间还未结束",
[RequestErrorCode.RoomNotIsIdle]: "房间还未开始",

[RequestErrorCode.PeriodicNotFound]: "周期性房间不存在",
[RequestErrorCode.PeriodicIsEnded]: "周期性房间已结束",
[RequestErrorCode.PeriodicSubRoomHasRunning]: "周期性子房间不存在",

[RequestErrorCode.UserNotFound]: "用户不存在",

[RequestErrorCode.RecordNotFound]: "回放不存在",
};
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { RoomStoreContext } from "../../../components/StoreProvider";
import { RoomItem } from "../../../stores/RoomStore";
import { RouteNameType, usePushHistory } from "../../../utils/routes";
import { MainRoomListItem } from "./MainRoomListItem";
import { errorTips } from "../../../components/Tips/ErrorTips";
import { joinRoomHandler } from "../../utils/joinRoomHandler";

export interface MainRoomListProps {
listRoomsType: ListRoomsType;
Expand All @@ -31,7 +33,7 @@ export const MainRoomList = observer<MainRoomListProps>(function MainRoomList({
setRoomUUIDs(roomUUIDs);
}
})
.catch(console.warn);
.catch(errorTips);
}

refreshRooms();
Expand Down Expand Up @@ -85,7 +87,7 @@ export const MainRoomList = observer<MainRoomListProps>(function MainRoomList({
showDivider={shouldShowDivider}
room={room}
isHistoryList={isHistoryList}
onJoinRoom={joinRoom}
onJoinRoom={roomUUID => joinRoomHandler(roomUUID, pushHistory)}
onReplayRoom={replayRoom}
onRemoveRoom={() => forceRefreshRooms(e => ~e)}
/>
Expand All @@ -95,28 +97,6 @@ export const MainRoomList = observer<MainRoomListProps>(function MainRoomList({
</>
);

async function joinRoom(roomUUID: string): Promise<void> {
const data = await roomStore.joinRoom(roomUUID);
// @TODO make roomType a param
switch (data.roomType) {
case RoomType.BigClass: {
pushHistory(RouteNameType.BigClassPage, data);
break;
}
case RoomType.SmallClass: {
pushHistory(RouteNameType.SmallClassPage, data);
break;
}
case RoomType.OneToOne: {
pushHistory(RouteNameType.OneToOnePage, data);
break;
}
default: {
console.error(new Error("failed to join room: incorrect room type"));
}
}
}

function replayRoom(config: { roomUUID: string; ownerUUID: string; roomType: RoomType }): void {
pushHistory(RouteNameType.ReplayPage, config);
}
Expand Down
29 changes: 4 additions & 25 deletions src/renderer-app/src/pages/HomePage/MainRoomMenu/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ import "./MainRoomMenu.less";
import React, { FC, useContext } from "react";
import { RoomType } from "../../../apiMiddleware/flatServer/constants";
import { RoomStoreContext } from "../../../components/StoreProvider";
import { RouteNameType, usePushHistory } from "../../../utils/routes";
import { usePushHistory } from "../../../utils/routes";
import { CreateRoomBox } from "./CreateRoomBox";
import { JoinRoomBox } from "./JoinRoomBox";
import { ScheduleRoomBox } from "./ScheduleRoomBox";
import { joinRoomHandler } from "../../utils/joinRoomHandler";

export interface MainRoomMenuProps {}

Expand All @@ -16,7 +17,7 @@ export const MainRoomMenu: FC = () => {

return (
<div className="main-room-menu-container">
<JoinRoomBox onJoinRoom={joinRoom} />
<JoinRoomBox onJoinRoom={roomUUID => joinRoomHandler(roomUUID, pushHistory)} />
<CreateRoomBox onCreateRoom={createOrdinaryRoom} />
<ScheduleRoomBox />
</div>
Expand All @@ -29,29 +30,7 @@ export const MainRoomMenu: FC = () => {
beginTime: Date.now(),
// TODO docs:[]
});
await joinRoom(roomUUID);
}

async function joinRoom(roomUUID: string): Promise<void> {
const data = await roomStore.joinRoom(roomUUID);
// @TODO make roomType a param
switch (data.roomType) {
case RoomType.BigClass: {
pushHistory(RouteNameType.BigClassPage, data);
break;
}
case RoomType.SmallClass: {
pushHistory(RouteNameType.SmallClassPage, data);
break;
}
case RoomType.OneToOne: {
pushHistory(RouteNameType.OneToOnePage, data);
break;
}
default: {
console.error(new Error("failed to join room: incorrect room type"));
}
}
await joinRoomHandler(roomUUID, pushHistory);
}
};

Expand Down
Loading