瀏覽代碼

feat(visitors) add info dialog (#14926)

factor2
Mihaela Dumitru 1 年之前
父節點
當前提交
94b6808ec6
沒有連結到貢獻者的電子郵件帳戶。

+ 7
- 0
lang/main.json 查看文件

263
         "Remove": "Remove",
263
         "Remove": "Remove",
264
         "Share": "Share",
264
         "Share": "Share",
265
         "Submit": "Submit",
265
         "Submit": "Submit",
266
+        "Understood": "Understood",
266
         "WaitForHostMsg": "The conference has not yet started because no moderators have yet arrived. If you'd like to become a moderator please log-in. Otherwise, please wait.",
267
         "WaitForHostMsg": "The conference has not yet started because no moderators have yet arrived. If you'd like to become a moderator please log-in. Otherwise, please wait.",
267
         "WaitForHostNoAuthMsg": "The conference has not yet started because no moderators have yet arrived. Please wait.",
268
         "WaitForHostNoAuthMsg": "The conference has not yet started because no moderators have yet arrived. Please wait.",
268
         "WaitingForHostButton": "Wait for moderator",
269
         "WaitingForHostButton": "Wait for moderator",
1492
     },
1493
     },
1493
     "visitors": {
1494
     "visitors": {
1494
         "chatIndicator": "(visitor)",
1495
         "chatIndicator": "(visitor)",
1496
+        "joinMeeting": {
1497
+            "description": "You're currently an observer in this conference.",
1498
+            "raiseHand": "Raise your hand",
1499
+            "title": "Joining meeting",
1500
+            "wishToSpeak": "If you wish to speak, please raise your hand below and wait for the moderator's approval."
1501
+        },
1495
         "labelTooltip": "Number of visitors: {{count}}",
1502
         "labelTooltip": "Number of visitors: {{count}}",
1496
         "notification": {
1503
         "notification": {
1497
             "demoteDescription": "Sent here by {{actor}}, raise your hand to participate",
1504
             "demoteDescription": "Sent here by {{actor}}, raise your hand to participate",

+ 2
- 5
react/features/base/ui/components/web/Dialog.tsx 查看文件

111
     }, [ onCancel ]);
111
     }, [ onCancel ]);
112
 
112
 
113
     const submit = useCallback(() => {
113
     const submit = useCallback(() => {
114
-        if (onSubmit && (
115
-            (document.activeElement && !operatesWithEnterKey(document.activeElement))
116
-            || !document.activeElement
117
-        )) {
114
+        if ((document.activeElement && !operatesWithEnterKey(document.activeElement)) || !document.activeElement) {
118
             !disableAutoHideOnSubmit && dispatch(hideDialog());
115
             !disableAutoHideOnSubmit && dispatch(hideDialog());
119
-            onSubmit();
116
+            onSubmit?.();
120
         }
117
         }
121
     }, [ onSubmit ]);
118
     }, [ onSubmit ]);
122
 
119
 

+ 31
- 1
react/features/reactions/components/native/RaiseHandButton.tsx 查看文件

40
      */
40
      */
41
     _raisedHand: boolean;
41
     _raisedHand: boolean;
42
 
42
 
43
+    /**
44
+     * Whether or not the click is disabled.
45
+     */
46
+    disableClick?: boolean;
47
+
43
     /**
48
     /**
44
      * Used to close the overflow menu after raise hand is clicked.
49
      * Used to close the overflow menu after raise hand is clicked.
45
      */
50
      */
75
      * @returns {void}
80
      * @returns {void}
76
      */
81
      */
77
     _onClick() {
82
     _onClick() {
83
+        const { disableClick, onCancel } = this.props;
84
+
85
+        if (disableClick) {
86
+            return;
87
+        }
88
+
78
         this._toggleRaisedHand();
89
         this._toggleRaisedHand();
79
-        this.props.onCancel();
90
+        onCancel();
80
     }
91
     }
81
 
92
 
82
     /**
93
     /**
159
     };
170
     };
160
 }
171
 }
161
 
172
 
173
+/**
174
+ * Maps part of the Redux state to the props of this component.
175
+ *
176
+ * @param {Object} state - The Redux state.
177
+ * @private
178
+ * @returns {IProps}
179
+ */
180
+function _standaloneMapStateToProps(state: IReduxState) {
181
+    const _enabled = getFeatureFlag(state, RAISE_HAND_ENABLED, true);
182
+
183
+    return {
184
+        _enabled
185
+    };
186
+}
187
+
188
+const StandaloneRaiseHandButton = translate(connect(_standaloneMapStateToProps)(RaiseHandButton));
189
+
190
+export { StandaloneRaiseHandButton };
191
+
162
 export default translate(connect(_mapStateToProps)(RaiseHandButton));
192
 export default translate(connect(_mapStateToProps)(RaiseHandButton));

+ 18
- 2
react/features/reactions/components/web/RaiseHandButton.ts 查看文件

2
 
2
 
3
 import { createToolbarEvent } from '../../../analytics/AnalyticsEvents';
3
 import { createToolbarEvent } from '../../../analytics/AnalyticsEvents';
4
 import { sendAnalytics } from '../../../analytics/functions';
4
 import { sendAnalytics } from '../../../analytics/functions';
5
-import { IReduxState } from '../../../app/types';
5
+import { IReduxState, IStore } from '../../../app/types';
6
 import { translate } from '../../../base/i18n/functions';
6
 import { translate } from '../../../base/i18n/functions';
7
 import { IconRaiseHand } from '../../../base/icons/svg';
7
 import { IconRaiseHand } from '../../../base/icons/svg';
8
 import { raiseHand } from '../../../base/participants/actions';
8
 import { raiseHand } from '../../../base/participants/actions';
15
  */
15
  */
16
 interface IProps extends AbstractButtonProps {
16
 interface IProps extends AbstractButtonProps {
17
 
17
 
18
+    /**
19
+     * Whether or not the click is disabled.
20
+     */
21
+    disableClick?: boolean;
22
+
23
+    /**
24
+     * Redux dispatch function.
25
+     */
26
+    dispatch: IStore['dispatch'];
27
+
18
     /**
28
     /**
19
      * Whether or not the hand is raised.
29
      * Whether or not the hand is raised.
20
      */
30
      */
51
      * @returns {void}
61
      * @returns {void}
52
      */
62
      */
53
     _handleClick() {
63
     _handleClick() {
54
-        const { dispatch, raisedHand } = this.props;
64
+        const { disableClick, dispatch, raisedHand } = this.props;
65
+
66
+        if (disableClick) {
67
+            return;
68
+        }
55
 
69
 
56
         sendAnalytics(createToolbarEvent(
70
         sendAnalytics(createToolbarEvent(
57
             'raise.hand',
71
             'raise.hand',
76
     };
90
     };
77
 };
91
 };
78
 
92
 
93
+export { RaiseHandButton };
94
+
79
 export default translate(connect(mapStateToProps)(RaiseHandButton));
95
 export default translate(connect(mapStateToProps)(RaiseHandButton));

+ 1
- 0
react/features/visitors/components/index.native.ts 查看文件

1
+export { default as JoinMeetingDialog } from './native/JoinMeetingDialog';

+ 1
- 0
react/features/visitors/components/index.web.ts 查看文件

1
+export { default as JoinMeetingDialog } from './web/JoinMeetingDialog';

+ 40
- 0
react/features/visitors/components/native/JoinMeetingDialog.tsx 查看文件

1
+import React, { useCallback, useState } from 'react';
2
+import { useTranslation } from 'react-i18next';
3
+import { View, ViewStyle } from 'react-native';
4
+import Dialog from 'react-native-dialog';
5
+
6
+import { StandaloneRaiseHandButton as RaiseHandButton } from '../../../reactions/components/native/RaiseHandButton';
7
+import styles from '../../components/native/styles';
8
+
9
+/**
10
+ * Component that renders the join meeting dialog for visitors.
11
+ *
12
+ * @returns {JSX.Element}
13
+ */
14
+export default function JoinMeetingDialog() {
15
+    const { t } = useTranslation();
16
+    const [ visible, setVisible ] = useState(true);
17
+
18
+    const closeDialog = useCallback(() => {
19
+        setVisible(false);
20
+    }, []);
21
+
22
+    return (
23
+        <Dialog.Container
24
+            coverScreen = { false }
25
+            visible = { visible }>
26
+            <Dialog.Title>{ t('visitors.joinMeeting.title') }</Dialog.Title>
27
+            <Dialog.Description>
28
+                { t('visitors.joinMeeting.description') }
29
+                <View style = { styles.raiseHandButton as ViewStyle }>
30
+                    {/* @ts-ignore */}
31
+                    <RaiseHandButton disableClick = { true } />
32
+                </View>
33
+            </Dialog.Description>
34
+            <Dialog.Description>{t('visitors.joinMeeting.wishToSpeak')}</Dialog.Description>
35
+            <Dialog.Button
36
+                label = { t('dialog.Understood') }
37
+                onPress = { closeDialog } />
38
+        </Dialog.Container>
39
+    );
40
+}

+ 12
- 0
react/features/visitors/components/native/styles.ts 查看文件

1
+/**
2
+ * The styles of the feature visitors.
3
+ */
4
+export default {
5
+
6
+    raiseHandButton: {
7
+        display: 'flex',
8
+        alignItems: 'center',
9
+        justifyContent: 'center',
10
+        width: '100%'
11
+    }
12
+};

+ 75
- 0
react/features/visitors/components/web/JoinMeetingDialog.tsx 查看文件

1
+import { noop } from 'lodash';
2
+import React from 'react';
3
+import { useTranslation } from 'react-i18next';
4
+import { makeStyles } from 'tss-react/mui';
5
+
6
+import { IconArrowUp } from '../../../base/icons/svg';
7
+import ToolboxButtonWithPopup from '../../../base/toolbox/components/web/ToolboxButtonWithPopup';
8
+import Dialog from '../../../base/ui/components/web/Dialog';
9
+import { RaiseHandButton } from '../../../reactions/components/web/RaiseHandButton';
10
+
11
+const useStyles = makeStyles()(theme => {
12
+    return {
13
+        raiseHand: {
14
+            alignItems: 'center',
15
+            display: 'flex',
16
+            flexDirection: 'column',
17
+            marginTop: theme.spacing(3),
18
+            marginBottom: theme.spacing(3),
19
+            pointerEvents: 'none'
20
+        },
21
+        raiseHandTooltip: {
22
+            border: '1px solid #444',
23
+            borderRadius: theme.shape.borderRadius,
24
+            paddingBottom: theme.spacing(1),
25
+            paddingTop: theme.spacing(1),
26
+            paddingLeft: theme.spacing(2),
27
+            paddingRight: theme.spacing(2)
28
+        },
29
+        raiseHandButton: {
30
+            display: 'inline-block',
31
+            marginTop: theme.spacing(2),
32
+            marginBottom: theme.spacing(2),
33
+            position: 'relative'
34
+        }
35
+    };
36
+});
37
+
38
+/**
39
+ * Component that renders the join meeting dialog for visitors.
40
+ *
41
+ * @returns {JSX.Element}
42
+ */
43
+export default function JoinMeetingDialog() {
44
+    const { t } = useTranslation();
45
+    const { classes } = useStyles();
46
+
47
+    return (
48
+        <Dialog
49
+            cancel = {{ hidden: true }}
50
+            ok = {{ translationKey: 'dialog.Understood' }}
51
+            titleKey = 'visitors.joinMeeting.title'>
52
+            <div className = 'join-meeting-dialog'>
53
+                <p>{t('visitors.joinMeeting.description')}</p>
54
+                <div className = { classes.raiseHand }>
55
+                    <p className = { classes.raiseHandTooltip }>{t('visitors.joinMeeting.raiseHand')}</p>
56
+                    <div className = { classes.raiseHandButton }>
57
+                        <ToolboxButtonWithPopup
58
+                            icon = { IconArrowUp }
59
+                            iconDisabled = { false }
60
+                            onPopoverClose = { noop }
61
+                            onPopoverOpen = { noop }
62
+                            popoverContent = { null }
63
+                            visible = { false }>
64
+                            {/* @ts-ignore */}
65
+                            <RaiseHandButton
66
+                                disableClick = { true }
67
+                                raisedHand = { true } />
68
+                        </ToolboxButtonWithPopup>
69
+                    </div>
70
+                </div>
71
+                <p>{t('visitors.joinMeeting.wishToSpeak')}</p>
72
+            </div>
73
+        </Dialog>
74
+    );
75
+}

+ 4
- 0
react/features/visitors/middleware.ts 查看文件

13
 import { CONNECTION_FAILED } from '../base/connection/actionTypes';
13
 import { CONNECTION_FAILED } from '../base/connection/actionTypes';
14
 import { connect, setPreferVisitor } from '../base/connection/actions';
14
 import { connect, setPreferVisitor } from '../base/connection/actions';
15
 import { disconnect } from '../base/connection/actions.any';
15
 import { disconnect } from '../base/connection/actions.any';
16
+import { openDialog } from '../base/dialog/actions';
16
 import { JitsiConferenceEvents, JitsiConnectionErrors } from '../base/lib-jitsi-meet';
17
 import { JitsiConferenceEvents, JitsiConnectionErrors } from '../base/lib-jitsi-meet';
17
 import { PARTICIPANT_UPDATED } from '../base/participants/actionTypes';
18
 import { PARTICIPANT_UPDATED } from '../base/participants/actionTypes';
18
 import { raiseHand } from '../base/participants/actions';
19
 import { raiseHand } from '../base/participants/actions';
48
     updateVisitorsCount,
49
     updateVisitorsCount,
49
     updateVisitorsInQueueCount
50
     updateVisitorsInQueueCount
50
 } from './actions';
51
 } from './actions';
52
+import { JoinMeetingDialog } from './components';
51
 import { getPromotionRequests, getVisitorsCount, getVisitorsInQueueCount } from './functions';
53
 import { getPromotionRequests, getVisitorsCount, getVisitorsInQueueCount } from './functions';
52
 import logger from './logger';
54
 import logger from './logger';
53
 import { WebsocketClient } from './websocket-client';
55
 import { WebsocketClient } from './websocket-client';
70
         const { conference } = action;
72
         const { conference } = action;
71
 
73
 
72
         if (getState()['features/visitors'].iAmVisitor) {
74
         if (getState()['features/visitors'].iAmVisitor) {
75
+            dispatch(openDialog(JoinMeetingDialog));
76
+
73
             const { demoteActorDisplayName } = getState()['features/visitors'];
77
             const { demoteActorDisplayName } = getState()['features/visitors'];
74
 
78
 
75
             dispatch(setVisitorDemoteActor(undefined));
79
             dispatch(setVisitorDemoteActor(undefined));

Loading…
取消
儲存