Skip to content

Commit

Permalink
feat(ui): add ClassRoom Timer (#1288)
Browse files Browse the repository at this point in the history
* feat(ui): add Countdown

* fix(eslint): format

* fix(component): use date-fns in Countdown

* fix(component): rename Countdown to Timer

* fix(component): useClockTick support duration
rename countdown to timer

* fix(component): adjust negated conditions

* fix(component): rename timer

* fix(component): remove timer in AppStoreButton

* fix(component): format code

* fix(component): rename timer

* fix(component): timer types

* Update packages/flat-components/src/components/ClassroomPage/Timer/index.tsx

Co-authored-by: Black-Hole <158blackhole@gmail.com>

* Update packages/flat-components/src/components/ClassroomPage/Timer/index.tsx

* fix(component): use NaN as initialize value to <Timer />

* rename

* fix(component): revert countdown code

* fix(component): revert countdown code

* refactor(component): use react schedule timing update

* refactor(component): fix timing

* refactor(component): format code

* refactor(component): format code

* fix(assets): style

* refactor(component): format code

Co-authored-by: Black-Hole <158blackhole@gmail.com>
  • Loading branch information
Matrixbirds and BlackHole1 committed Jan 17, 2022
1 parent e4d91b0 commit dbd49e9
Show file tree
Hide file tree
Showing 12 changed files with 177 additions and 16 deletions.
17 changes: 14 additions & 3 deletions desktop/renderer-app/src/pages/BigClassPage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@ import {
TopBarDivider,
LoadingPage,
CloudRecordBtn,
Timer,
} from "flat-components";
import { observer } from "mobx-react-lite";
import React, { useEffect, useRef, useState } from "react";
import { useParams } from "react-router-dom";
import { RoomPhase } from "white-web-sdk";
import { useTranslation } from "react-i18next";
import { AgoraCloudRecordBackgroundConfigItem } from "../../api-middleware/flatServer/agora";
import { RoomStatus, RoomType } from "../../api-middleware/flatServer/constants";
import { RoomStatus } from "../../api-middleware/flatServer/constants";
import { RtcChannelType } from "../../api-middleware/rtc";
import { ChatPanel } from "../../components/ChatPanel";
import { RoomStatusStoppedModal } from "../../components/ClassRoom/RoomStatusStoppedModal";
Expand Down Expand Up @@ -227,8 +228,18 @@ export const BigClassPage = observer<BigClassPageProps>(function BigClassPage()
return (
<>
<NetworkStatus networkQuality={classRoomStore.networkQuality} />
{!classRoomStore.isCreator && (
<RoomInfo roomStatus={classRoomStore.roomStatus} roomType={RoomType.BigClass} />
{classRoomStore.isCreator ? (
classRoomStore.roomInfo?.beginTime && (
<Timer
beginTime={classRoomStore.roomInfo.beginTime}
roomStatus={classRoomStore.roomStatus}
/>
)
) : (
<RoomInfo
roomStatus={classRoomStore.roomStatus}
roomType={classRoomStore.roomInfo?.roomType}
/>
)}
</>
);
Expand Down
17 changes: 14 additions & 3 deletions desktop/renderer-app/src/pages/OneToOnePage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
TopBarDivider,
LoadingPage,
CloudRecordBtn,
Timer,
} from "flat-components";

import InviteButton from "../../components/InviteButton";
Expand All @@ -26,7 +27,7 @@ import {
} from "../../components/ExitRoomConfirm";
import { Whiteboard } from "../../components/Whiteboard";
import { RoomStatusStoppedModal } from "../../components/ClassRoom/RoomStatusStoppedModal";
import { RoomStatus, RoomType } from "../../api-middleware/flatServer/constants";
import { RoomStatus } from "../../api-middleware/flatServer/constants";
import { RecordingConfig, useClassRoomStore } from "../../stores/class-room-store";
import { RtcChannelType } from "../../api-middleware/rtc";
import { useComputed } from "../../utils/mobx";
Expand Down Expand Up @@ -185,8 +186,18 @@ export const OneToOnePage = observer<OneToOnePageProps>(function OneToOnePage()
return (
<>
<NetworkStatus networkQuality={classRoomStore.networkQuality} />
{!classRoomStore.isCreator && (
<RoomInfo roomStatus={classRoomStore.roomStatus} roomType={RoomType.OneToOne} />
{classRoomStore.isCreator ? (
classRoomStore.roomInfo?.beginTime && (
<Timer
beginTime={classRoomStore.roomInfo.beginTime}
roomStatus={classRoomStore.roomStatus}
/>
)
) : (
<RoomInfo
roomStatus={classRoomStore.roomStatus}
roomType={classRoomStore.roomInfo?.roomType}
/>
)}
</>
);
Expand Down
10 changes: 9 additions & 1 deletion desktop/renderer-app/src/pages/SmallClassPage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
TopBarDivider,
LoadingPage,
CloudRecordBtn,
Timer,
} from "flat-components";

import InviteButton from "../../components/InviteButton";
Expand Down Expand Up @@ -223,7 +224,14 @@ export const SmallClassPage = observer<SmallClassPageProps>(function SmallClassP
return (
<>
<NetworkStatus networkQuality={classRoomStore.networkQuality} />
{!classRoomStore.isCreator && (
{classRoomStore.isCreator ? (
classRoomStore.roomInfo?.beginTime && (
<Timer
beginTime={classRoomStore.roomInfo.beginTime}
roomStatus={classRoomStore.roomStatus}
/>
)
) : (
<RoomInfo
roomStatus={classRoomStore.roomStatus}
roomType={classRoomStore.roomInfo?.roomType}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import "./style.less";

import React, { useState, useEffect, useMemo } from "react";
import { useTranslation } from "react-i18next";
import { useIsUnMounted } from "../../../utils/hooks";
import { RoomStatus } from "../../../types/room";
import { intervalToDuration } from "date-fns/fp";

export type TimerProps = {
roomStatus: RoomStatus;
beginTime: number;
};

const paddingHexCode = (number: number): string => {
return String(number).padStart(2, "0");
};

const useClockTick = (beginTime: number, roomStatus: RoomStatus): string => {
const [timestamp, updateTimestamp] = useState<number>(Date.now());
const unmounted = useIsUnMounted();

useEffect(() => {
let timer = NaN;

if (unmounted.current) {
return;
}

if (roomStatus === RoomStatus.Started) {
const startTimer = (): void => {
updateTimestamp(Math.floor(Date.now() / 1000) * 1000);
timer = window.requestAnimationFrame(startTimer);
};
startTimer();
}

return () => {
window.cancelAnimationFrame(timer);
};
}, [roomStatus, unmounted]);

return useMemo(() => {
const {
days = 0,
hours = 0,
minutes = 0,
seconds = 0,
} = intervalToDuration({
start: beginTime,
end: timestamp,
});

const minutesAndSeconds = `${paddingHexCode(minutes)}:${paddingHexCode(seconds)}`;
const dayHours = hours + days * 24;

return dayHours > 0
? `${paddingHexCode(dayHours)}:${minutesAndSeconds}`
: minutesAndSeconds;
}, [beginTime, timestamp]);
};

export const Timer: React.FC<TimerProps> = ({ roomStatus = RoomStatus.Paused, beginTime }) => {
const timing = useClockTick(beginTime, roomStatus);

const { t } = useTranslation();

return (
<span className="timer-bar">
<span className={`timer-${roomStatus}`}>{t("room-started")}</span>
<span>{timing}</span>
</span>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.timer-bar {
color: #7a7b7c;
font-size: 12px;
margin: 0 8px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Meta, Story } from "@storybook/react";
import React from "react";
import { RoomStatus } from "../../../types/room";
import { Timer, TimerProps } from ".";

const storyMeta: Meta = {
title: "ClassroomPage/Timer",
component: Timer,
};

export default storyMeta;

export const Overview: Story<TimerProps> = args => {
return <Timer {...args} />;
};

Overview.args = {
roomStatus: RoomStatus.Paused,
beginTime: Date.now(),
};
1 change: 1 addition & 0 deletions packages/flat-components/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ export * from "./components/RoomStatusElement";
export * from "./containers/CloudStorageContainer";
export * from "./components/DeviceTestPage";
export * from "./components/ClassroomPage/CloudRecordBtn";
export * from "./components/ClassroomPage/Timer";
3 changes: 2 additions & 1 deletion packages/flat-i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -390,5 +390,6 @@
"user-guide-button": "Check it out now",
"start-recording": "Start recording",
"stop-recording": "Stop recording",
"open-in-browser": "Open in Browser"
"open-in-browser": "Open in Browser",
"room-started": "Started:"
}
3 changes: 2 additions & 1 deletion packages/flat-i18n/locales/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -390,5 +390,6 @@
"user-guide-button": "立即查看",
"start-recording": "开始录制",
"stop-recording": "停止录制",
"open-in-browser": "请在浏览器中打开"
"open-in-browser": "请在浏览器中打开",
"room-started": "已上课:"
}
17 changes: 14 additions & 3 deletions web/flat-web/src/pages/BigClassPage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { message } from "antd";
import classNames from "classnames";
import {
CloudRecordBtn,
Timer,
LoadingPage,
NetworkStatus,
RoomInfo,
Expand All @@ -16,7 +17,7 @@ import { useParams } from "react-router-dom";
import { RoomPhase } from "white-web-sdk";
import { useTranslation } from "react-i18next";
import { AgoraCloudRecordBackgroundConfigItem } from "../../api-middleware/flatServer/agora";
import { RoomStatus, RoomType } from "../../api-middleware/flatServer/constants";
import { RoomStatus } from "../../api-middleware/flatServer/constants";
import { RtcChannelType } from "../../api-middleware/rtc/room";
import { ChatPanel } from "../../components/ChatPanel";
import { RoomStatusStoppedModal } from "../../components/ClassRoom/RoomStatusStoppedModal";
Expand Down Expand Up @@ -201,8 +202,18 @@ export const BigClassPage = observer<BigClassPageProps>(function BigClassPage()
return (
<>
<NetworkStatus networkQuality={classRoomStore.networkQuality} />
{!classRoomStore.isCreator && (
<RoomInfo roomStatus={classRoomStore.roomStatus} roomType={RoomType.BigClass} />
{classRoomStore.isCreator ? (
classRoomStore.roomInfo?.beginTime && (
<Timer
beginTime={classRoomStore.roomInfo.beginTime}
roomStatus={classRoomStore.roomStatus}
/>
)
) : (
<RoomInfo
roomStatus={classRoomStore.roomStatus}
roomType={classRoomStore.roomInfo?.roomType}
/>
)}
</>
);
Expand Down
17 changes: 14 additions & 3 deletions web/flat-web/src/pages/OneToOnePage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
TopBar,
TopBarDivider,
LoadingPage,
Timer,
CloudRecordBtn,
} from "flat-components";

Expand All @@ -26,7 +27,7 @@ import {
} from "../../components/ExitRoomConfirm";
import { Whiteboard } from "../../components/Whiteboard";
import { RoomStatusStoppedModal } from "../../components/ClassRoom/RoomStatusStoppedModal";
import { RoomStatus, RoomType } from "../../api-middleware/flatServer/constants";
import { RoomStatus } from "../../api-middleware/flatServer/constants";
import { RecordingConfig, useClassRoomStore } from "../../stores/class-room-store";
import { RtcChannelType } from "../../api-middleware/rtc/room";
import { useComputed } from "../../utils/mobx";
Expand Down Expand Up @@ -161,8 +162,18 @@ export const OneToOnePage = observer<OneToOnePageProps>(function OneToOnePage()
return (
<>
<NetworkStatus networkQuality={classRoomStore.networkQuality} />
{!classRoomStore.isCreator && (
<RoomInfo roomStatus={classRoomStore.roomStatus} roomType={RoomType.OneToOne} />
{classRoomStore.isCreator ? (
classRoomStore.roomInfo?.beginTime && (
<Timer
beginTime={classRoomStore.roomInfo.beginTime}
roomStatus={classRoomStore.roomStatus}
/>
)
) : (
<RoomInfo
roomStatus={classRoomStore.roomStatus}
roomType={classRoomStore.roomInfo?.roomType}
/>
)}
</>
);
Expand Down
10 changes: 9 additions & 1 deletion web/flat-web/src/pages/SmallClassPage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
TopBar,
TopBarDivider,
LoadingPage,
Timer,
CloudRecordBtn,
} from "flat-components";

Expand Down Expand Up @@ -204,7 +205,14 @@ export const SmallClassPage = observer<SmallClassPageProps>(function SmallClassP
return (
<>
<NetworkStatus networkQuality={classRoomStore.networkQuality} />
{!classRoomStore.isCreator && (
{classRoomStore.isCreator ? (
classRoomStore.roomInfo?.beginTime && (
<Timer
beginTime={classRoomStore.roomInfo.beginTime}
roomStatus={classRoomStore.roomStatus}
/>
)
) : (
<RoomInfo
roomStatus={classRoomStore.roomStatus}
roomType={classRoomStore.roomInfo?.roomType}
Expand Down

0 comments on commit dbd49e9

Please sign in to comment.