Skip to content

Commit

Permalink
feat(classroom): add user guide to the classroom (#1179)
Browse files Browse the repository at this point in the history
* feat(classroom): add user guide to the classroom

* chore(classroom): add comment to onUserGuide method
  • Loading branch information
Cheerego7 committed Dec 8, 2021
1 parent e9be221 commit f75c14e
Show file tree
Hide file tree
Showing 19 changed files with 147 additions and 5 deletions.
1 change: 1 addition & 0 deletions .commitlintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ module.exports = {
"github",
"style",
"room",
"classroom",
],
],
"scope-case": [2, "always", ["lower-case", "kebab-case"]],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ export interface JoinRoomResult {
uid: number;
token: string;
};
showGuide: boolean;
}

export function joinRoom(uuid: string): Promise<JoinRoomResult> {
Expand Down
3 changes: 3 additions & 0 deletions desktop/renderer-app/src/api-middleware/rtm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ export enum RTMessageType {
ChannelStatus = "ChannelStatus",
/** user login on other device */
REMOTE_LOGIN = "REMOTE_LOGIN",
/** display a user guide message info when first create the classroom */
UserGuide = "UserGuide",
}

export type RTMEvents = {
Expand Down Expand Up @@ -123,6 +125,7 @@ export type RTMEvents = {
};
};
[RTMessageType.REMOTE_LOGIN]: void;
[RTMessageType.UserGuide]: string;
};

export interface RTMessage<U extends keyof RTMEvents = keyof RTMEvents> {
Expand Down
1 change: 1 addition & 0 deletions desktop/renderer-app/src/components/ChatPanel/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export const ChatPanel = observer<ChatPanelProps>(function ChatPanel({
disableHandRaising={disableHandRaising}
isRaiseHand={classRoomStore.users.currentUser?.isRaiseHand}
unreadCount={classRoomStore.users.handRaisingJoiners.length || null}
openCloudStorage={() => classRoomStore.toggleCloudStoragePanel(true)}
/>
);
});
Expand Down
2 changes: 2 additions & 0 deletions desktop/renderer-app/src/pages/utils/join-room-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { RouteNameType, usePushHistory } from "../../utils/routes";
import { roomStore } from "../../stores/room-store";
import { RoomType } from "../../api-middleware/flatServer/constants";
import { errorTips } from "../../components/Tips/ErrorTips";
import { globalStore } from "../../stores/global-store";

export const joinRoomHandler = async (
roomUUID: string,
Expand All @@ -10,6 +11,7 @@ export const joinRoomHandler = async (
try {
const formatRoomUUID = roomUUID.replace(/\s+/g, "");
const data = await roomStore.joinRoom(formatRoomUUID);
globalStore.updateShowGuide(data.showGuide);
// @TODO make roomType a param
switch (data.roomType) {
case RoomType.BigClass: {
Expand Down
30 changes: 29 additions & 1 deletion desktop/renderer-app/src/stores/class-room-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,10 @@ import { i18n } from "i18next";
export type { User } from "./user-store";

export type RTMChannelMessage = RTMessage<
RTMessageType.ChannelMessage | RTMessageType.Notice | RTMessageType.BanText
| RTMessageType.ChannelMessage
| RTMessageType.Notice
| RTMessageType.BanText
| RTMessageType.UserGuide
>;

export type RecordingConfig = Required<
Expand Down Expand Up @@ -257,6 +260,10 @@ export class ClassRoomStore {
console.error(e);
this.updateCalling(false);
}

if (globalStore.isShowGuide) {
this.onUserGuide();
}
};

public toggleCloudStoragePanel = (visible: boolean): void => {
Expand Down Expand Up @@ -443,6 +450,27 @@ export class ClassRoomStore {
this.addMessage(RTMessageType.ChannelMessage, text, this.userUUID);
};

public onUserGuide = (): void => {
// this callback is triggered immediately after joinRTC
// network may be offline status, user rejoin or refresh classroom page
// then this callback will trigger again that push the guide message
// the user guide message always at the end
// so that for avoid multiple send message of the user guide
if (
this.messages.length > 0 &&
this.messages[this.messages.length - 1].type === RTMessageType.UserGuide
) {
return;
}
this.messages.push({
type: RTMessageType.UserGuide,
uuid: uuidv4(),
timestamp: Date.now(),
value: false,
userUUID: this.userUUID,
});
};

public onCancelAllHandRaising = (): void => {
if (this.isCreator) {
this.cancelAllHandRaising();
Expand Down
5 changes: 5 additions & 0 deletions desktop/renderer-app/src/stores/global-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export class GlobalStore {
*/
public checkNewVersionDate: number = new Date().getTime();
public isShowRecordHintTips = true;
public isShowGuide = false;
public userInfo: UserInfo | null = null;
public whiteboardRoomUUID: string | null = null;
public whiteboardRoomToken: string | null = null;
Expand Down Expand Up @@ -92,6 +93,10 @@ export class GlobalStore {
public isShareScreenUID = (uid: number): boolean => {
return this.rtcShareScreen?.uid === uid;
};

public updateShowGuide = (showGuide: boolean): void => {
this.isShowGuide = showGuide;
};
}

export const globalStore = new GlobalStore();
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ export interface ChatMessageProps {
messageUser?: { name: string };
message: ChatMsg;
onMount: () => void;
openCloudStorage?: () => void;
}

export const ChatMessage = observer<ChatMessageProps>(function ChatMessage({
userUUID,
messageUser,
message,
onMount,
openCloudStorage,
}) {
const { t } = useTranslation();
useEffect(() => {
Expand All @@ -43,6 +45,23 @@ export const ChatMessage = observer<ChatMessageProps>(function ChatMessage({
</div>
);
}
case ChatMsgType.UserGuide: {
return (
<div className="chat-message-line">
<div className="chat-message-user-guide-bubble">
<pre>
{t("user-guide-text")}
<span
className="chat-message-user-guide-btn"
onClick={openCloudStorage}
>
{t("user-guide-button")}
</span>
</pre>
</div>
</div>
);
}
default: {
break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,30 @@
user-select: none;
}
}

.chat-message-user-guide-bubble {
display: inline-block;
padding: 4px 12px;
border-radius: 4px;
font-size: 12px;
user-select: text;
background: #eef0f6;
color: #7a7b7c;

& > pre {
margin: 0;
padding: 0;
overflow: visible;
text-align: initial;
font-family: inherit;
white-space: normal;
word-break: break-all;
text-align: justify;
user-select: auto;
}
}

.chat-message-user-guide-btn {
color: #3381ff;
cursor: pointer;
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export interface ChatMessageListProps {
messages: ChatMsg[];
getUserByUUID: (uuid: string) => User | undefined;
loadMoreRows: InfiniteLoaderProps["loadMoreRows"];
openCloudStorage: () => void;
}

export const ChatMessageList = observer<ChatMessageListProps>(function ChatMessageList({
Expand All @@ -30,6 +31,7 @@ export const ChatMessageList = observer<ChatMessageListProps>(function ChatMessa
messages,
getUserByUUID,
loadMoreRows,
openCloudStorage,
}) {
const forceUpdate = useUpdate();

Expand Down Expand Up @@ -124,6 +126,7 @@ export const ChatMessageList = observer<ChatMessageListProps>(function ChatMessa
{() => (
<ChatMessage
onMount={measure}
openCloudStorage={openCloudStorage}
userUUID={userUUID}
messageUser={getUserByUUID(messages[index].userUUID)}
message={messages[index]}
Expand Down
1 change: 1 addition & 0 deletions packages/flat-components/src/components/ChatPanel/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export enum ChatMsgType {
Notice = "Notice",
BanText = "BanText",
ChannelMessage = "ChannelMessage",
UserGuide = "UserGuide",
}

export type ChatMsg = {
Expand Down
4 changes: 3 additions & 1 deletion packages/flat-i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -382,5 +382,7 @@
"device-test": "Devices Test",
"close-tip": "Close tip",
"device-test-option": "Device test option",
"turn-on-device-test": "Turn on device test when join the room"
"turn-on-device-test": "Turn on device test when join the room",
"user-guide-text": "Want to learn more about Flat?",
"user-guide-button": "Check it out now"
}
4 changes: 3 additions & 1 deletion packages/flat-i18n/locales/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -382,5 +382,7 @@
"device-test": "设备检测",
"close-tip": "不再提示",
"device-test-option": "设备检测选项",
"turn-on-device-test": "进入房间时检测"
"turn-on-device-test": "进入房间时检测",
"user-guide-text": "想了解更多 Flat 的使用技巧?",
"user-guide-button": "立即查看"
}
3 changes: 3 additions & 0 deletions web/flat-web/src/api-middleware/Rtm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ export enum RTMessageType {
ChannelStatus = "ChannelStatus",
/** user login on other device */
REMOTE_LOGIN = "REMOTE_LOGIN",
/** display a user guide message info when first create the classroom */
UserGuide = "UserGuide",
}

export type RTMEvents = {
Expand Down Expand Up @@ -123,6 +125,7 @@ export type RTMEvents = {
};
};
[RTMessageType.REMOTE_LOGIN]: void;
[RTMessageType.UserGuide]: string;
};

export interface RTMessage<U extends keyof RTMEvents = keyof RTMEvents> {
Expand Down
1 change: 1 addition & 0 deletions web/flat-web/src/api-middleware/flatServer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ export interface JoinRoomResult {
token: string;
};
rtmToken: string;
showGuide: boolean;
}

export function joinRoom(uuid: string): Promise<JoinRoomResult> {
Expand Down
1 change: 1 addition & 0 deletions web/flat-web/src/components/ChatPanel/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export const ChatPanel = observer<ChatPanelProps>(function ChatPanel({
disableHandRaising={disableHandRaising}
isRaiseHand={classRoomStore.users.currentUser?.isRaiseHand}
unreadCount={classRoomStore.users.handRaisingJoiners.length || null}
openCloudStorage={() => classRoomStore.toggleCloudStoragePanel(true)}
/>
);
});
Expand Down
2 changes: 2 additions & 0 deletions web/flat-web/src/pages/utils/join-room-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { generateRoutePath, RouteNameType, usePushHistory } from "../../utils/ro
import { roomStore } from "../../stores/room-store";
import { RoomType } from "../../api-middleware/flatServer/constants";
import { errorTips } from "../../components/Tips/ErrorTips";
import { globalStore } from "../../stores/GlobalStore";

export const joinRoomHandler = async (
roomUUID: string,
Expand All @@ -10,6 +11,7 @@ export const joinRoomHandler = async (
try {
const formatRoomUUID = roomUUID.replace(/\s+/g, "");
const data = await roomStore.joinRoom(formatRoomUUID);
globalStore.updateShowGuide(data.showGuide);
// try to work around chrome does not show permission popup after
// soft navigating. here we do a "hard" navigating instead.
// @TODO make roomType a param
Expand Down
5 changes: 5 additions & 0 deletions web/flat-web/src/stores/GlobalStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export class GlobalStore {
* Hide it permanently if user close the tooltip.
*/
public isShowRecordHintTips = true;
public isShowGuide = false;
public isTurnOffDeviceTest = false;
public userInfo: UserInfo | null = null;
public whiteboardRoomUUID: string | null = null;
Expand Down Expand Up @@ -93,6 +94,10 @@ export class GlobalStore {
public isShareScreenUID = (uid: UID): boolean => {
return this.rtcShareScreen?.uid === Number(uid);
};

public updateShowGuide = (showGuide: boolean): void => {
this.isShowGuide = showGuide;
};
}

export const globalStore = new GlobalStore();
39 changes: 37 additions & 2 deletions web/flat-web/src/stores/class-room-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@ import { WhiteboardStore } from "./whiteboard-store";
export type { User } from "./user-store";

export type RTMChannelMessage = RTMessage<
RTMessageType.ChannelMessage | RTMessageType.Notice | RTMessageType.BanText
| RTMessageType.ChannelMessage
| RTMessageType.Notice
| RTMessageType.BanText
| RTMessageType.UserGuide
>;

export type RecordingConfig = Required<
Expand Down Expand Up @@ -256,6 +259,10 @@ export class ClassRoomStore {
console.error(e);
this.updateCalling(false);
}

if (globalStore.isShowGuide) {
this.onUserGuide();
}
};

public leaveRTC = (): void => {
Expand Down Expand Up @@ -435,6 +442,27 @@ export class ClassRoomStore {
this.addMessage(RTMessageType.ChannelMessage, text, this.userUUID);
};

public onUserGuide = (): void => {
// this callback is triggered immediately after joinRTC
// network may be offline status, user rejoin or refresh classroom page
// then this callback will trigger again that push the guide message
// the user guide message always at the end
// so that for avoid multiple send message of the user guide
if (
this.messages.length > 0 &&
this.messages[this.messages.length - 1].type === RTMessageType.UserGuide
) {
return;
}
this.messages.push({
type: RTMessageType.UserGuide,
uuid: uuidv4(),
timestamp: Date.now(),
value: false,
userUUID: this.userUUID,
});
};

public onCancelAllHandRaising = (): void => {
if (this.isCreator) {
this.cancelAllHandRaising();
Expand Down Expand Up @@ -1037,7 +1065,14 @@ export function useClassRoomStore({
i18n,
}: ClassRoomStoreConfig): ClassRoomStore {
const [classRoomStore] = useState(
() => new ClassRoomStore({ roomUUID, ownerUUID, recordingConfig, classMode, i18n }),
() =>
new ClassRoomStore({
roomUUID,
ownerUUID,
recordingConfig,
classMode,
i18n,
}),
);

const pushHistory = usePushHistory();
Expand Down

0 comments on commit f75c14e

Please sign in to comment.