Skip to content

Commit

Permalink
Zoom: make user interface prettier, add React
Browse files Browse the repository at this point in the history
  • Loading branch information
pferreir committed Oct 15, 2024
1 parent 449feb1 commit f60f836
Show file tree
Hide file tree
Showing 19 changed files with 340 additions and 134 deletions.
4 changes: 2 additions & 2 deletions vc_dummy/indico_vc_dummy/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,11 @@ class DummyPlugin(VCPluginMixin, IndicoPlugin):

@property
def logo_url(self):
return url_for_plugin(self.name + '.static', filename='images/dummy_logo.png')
return url_for_plugin(self.name + '.static', filename='images/dummy_logo.svg')

@property
def icon_url(self):
return url_for_plugin(self.name + '.static', filename='images/dummy_icon.png')
return url_for_plugin(self.name + '.static', filename='images/dummy_icon.svg')

def get_blueprints(self):
return IndicoPluginBlueprint('vc_dummy', __name__)
Expand Down
Binary file not shown.
1 change: 1 addition & 0 deletions vc_dummy/indico_vc_dummy/static/images/dummy_icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
1 change: 1 addition & 0 deletions vc_dummy/indico_vc_dummy/static/images/dummy_logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions vc_zoom/indico_vc_zoom/client/JoinButton.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// This file is part of the Indico plugins.
// Copyright (C) 2020 - 2024 CERN and ENEA
//
// The Indico plugins are free software; you can redistribute
// them and/or modify them under the terms of the MIT License;
// see the LICENSE file for more details.

.button-label:global(.ui.image.label) {
> img {
margin: 0;
height: 1.5em !important;
}
}
150 changes: 150 additions & 0 deletions vc_zoom/indico_vc_zoom/client/JoinButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
// This file is part of the Indico plugins.
// Copyright (C) 2020 - 2024 CERN and ENEA

// The Indico plugins are free software; you can redistribute
// them and/or modify them under the terms of the MIT License;
// see the LICENSE file for more details.

import staticURL from 'indico-url:plugin_vc_zoom.static';

import React, {useState} from 'react';
import {Button, ButtonGroup, Confirm, Icon, Label, Popup, SemanticICONS} from 'semantic-ui-react';

import {Translate} from 'indico/react/i18n';
import {handleAxiosError, indicoAxios} from 'indico/utils/axios';

import './JoinButton.module.scss';

interface OptionsButtonProps {
url: string;
onMadeAltHost: () => void;
}

/** A dropdown button which shows additional actions, such as the possibility to take over as meeting co-host */
function OptionsButton({url, onMadeAltHost}: OptionsButtonProps) {
const [isConfirmOpen, setConfirmOpen] = useState(false);
const [state, setState] = useState('idle');

async function makeAlternativeHost() {
setConfirmOpen(false);
try {
setState('submitting');
await indicoAxios.post(url);
setState('success');
} catch (error) {
handleAxiosError(error);
}
window.setTimeout(() => {
onMadeAltHost();
setState('idle');
}, 3000);
}

const trigger = (
<Button
disabled={state !== 'idle'}
title={Translate.string('Actions you can perform on your Zoom meeting')}
color={state === 'success' ? 'green' : undefined}
loading={state === 'submitting'}
size="mini"
icon={state !== 'submitting'}
>
{
{
idle: <Icon fitted name="cog" />,
submitting: null,
success: <Icon fitted name="checkmark" />,
}[state]
}
</Button>
);

return (
<>
<Popup trigger={trigger} hoverable on="click">
<Button
size="mini"
title={Translate.string('You will become an alternative host of this Zoom meeting')}
onClick={() => setConfirmOpen(true)}
>
<Icon name="star" />
<Translate>Make me alternative host</Translate>
</Button>
</Popup>
<Confirm
header={Translate.string('Make me an alternative host')}
content={Translate.string('Are you sure you want to be added as an alternative host?')}
open={isConfirmOpen}
onConfirm={makeAlternativeHost}
onCancel={() => setConfirmOpen(false)}
/>
</>
);
}

interface JoinButtonProps {
classes: string;
href: string;
target: string;
icon: SemanticICONS;
caption: string;
description: string;
altHostUrl: string;
meetingTitle: string | undefined;
meetingDataHtml: string | undefined;
}

/** The join button, which can optionally include an alternative host URL (creates menu) as well as a pop-up */
export default function JoinButton({
classes,
href,
target,
icon,
caption,
description,
altHostUrl = '',
meetingTitle,
meetingDataHtml,
}: JoinButtonProps) {
const [isAltHost, setAltHost] = useState(!altHostUrl);

let buttons = (
<>
<Button size="mini" title={description} className={classes} href={href} target={target}>
<Icon name={icon} />
{caption}
</Button>
{!isAltHost ? (
<OptionsButton
url={altHostUrl}
onMadeAltHost={() => {
setAltHost(true);
}}
/>
) : null}
</>
);

const labeledButton = (
<Button as="div" labelPosition="left" size="mini">
<Label as="a" size="mini" image title="Zoom" pointing="right" styleName="button-label">
<img src={staticURL({filename: 'images/zoom_icon.svg'})} />
</Label>
</Button>
);

buttons = meetingDataHtml ? (
<>
<Popup hoverable trigger={labeledButton}>
<h4>{meetingTitle}</h4>
{/* the HTML data is generated server-side from the Zoom API output and should be in a sanitized state */}
<div dangerouslySetInnerHTML={{__html: meetingDataHtml}} />
</Popup>
{buttons}
</>
) : (
buttons
);

return <ButtonGroup size="mini">{buttons}</ButtonGroup>;
}
46 changes: 46 additions & 0 deletions vc_zoom/indico_vc_zoom/client/ind_vc_zoom_join_button.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// This file is part of the Indico plugins.
// Copyright (C) 2020 - 2024 CERN and ENEA
//
// The Indico plugins are free software; you can redistribute
// them and/or modify them under the terms of the MIT License;
// see the LICENSE file for more details.

import React from 'react';
import ReactDOM from 'react-dom';

import JoinButton from './JoinButton';

import './ind_vc_zoom_join_button.scss';

/** Custom element wrapper for a React-managed JoinButton */
customElements.define(
'ind-vc-zoom-join-button',
class extends HTMLElement {
connectedCallback() {
const classes = this.getAttribute('classes');
const href = this.getAttribute('href');
const target = this.getAttribute('target');
const icon = this.getAttribute('icon');
const caption = this.getAttribute('caption');
const description = this.getAttribute('description');
const altHostUrl = this.getAttribute('alt-host-url');
const meetingTitle = this.getAttribute('meeting-title');
const meetingDataHtml = this.getAttribute('meeting-data-html');

ReactDOM.render(
<JoinButton
classes={classes}
href={href}
target={target}
icon={icon}
caption={caption}
description={description}
altHostUrl={altHostUrl}
meetingTitle={meetingTitle}
meetingDataHtml={meetingDataHtml}
/>,
this
);
}
}
);
12 changes: 12 additions & 0 deletions vc_zoom/indico_vc_zoom/client/ind_vc_zoom_join_button.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// This file is part of the Indico plugins.
// Copyright (C) 2020 - 2024 CERN and ENEA
//
// The Indico plugins are free software; you can redistribute
// them and/or modify them under the terms of the MIT License;
// see the LICENSE file for more details.

ind-vc-zoom-join-button {
display: flex;
gap: 0.2em;
margin-right: 0.2em;
}
32 changes: 1 addition & 31 deletions vc_zoom/indico_vc_zoom/client/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,4 @@
// them and/or modify them under the terms of the MIT License;
// see the LICENSE file for more details.

/* global confirmPrompt:false, $T:false */

import {handleAxiosError, indicoAxios} from 'indico/utils/axios';

const $t = $T.domain('vc_zoom');

document.addEventListener('DOMContentLoaded', async () => {
$('.vc-toolbar').dropdown({
positioning: {
level1: {my: 'right top', at: 'right bottom', offset: '0px 0px'},
},
});

document.querySelectorAll('.vc-toolbar .action-make-host').forEach(elem => {
elem.addEventListener('click', () => {
confirmPrompt(
$t.gettext('Are you sure you want to be added as an alternative host?'),
$t.gettext('Make me an alternative host')
).then(async () => {
const killProgress = IndicoUI.Dialogs.Util.progress();
try {
await indicoAxios.post(elem.dataset.href);
window.location.reload();
} catch (error) {
handleAxiosError(error);
killProgress();
}
});
});
});
});
import './ind_vc_zoom_join_button';
8 changes: 6 additions & 2 deletions vc_zoom/indico_vc_zoom/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,14 +163,18 @@ def init(self):
self.inject_bundle('main.js', WPVCEventPage)
self.inject_bundle('main.js', WPVCManageEvent)
self.inject_bundle('main.js', WPConferenceDisplay)
self.inject_bundle('main.css', WPSimpleEventDisplay)
self.inject_bundle('main.css', WPVCEventPage)
self.inject_bundle('main.css', WPVCManageEvent)
self.inject_bundle('main.css', WPConferenceDisplay)

@property
def logo_url(self):
return url_for_plugin(self.name + '.static', filename='images/zoom_logo.png')
return url_for_plugin(self.name + '.static', filename='images/zoom_logo.svg')

@property
def icon_url(self):
return url_for_plugin(self.name + '.static', filename='images/zoom_logo.png')
return url_for_plugin(self.name + '.static', filename='images/zoom_icon.svg')

def create_form(self, event, existing_vc_room=None, existing_event_vc_room=None):
"""Override the default room form creation mechanism."""
Expand Down
1 change: 1 addition & 0 deletions vc_zoom/indico_vc_zoom/static/images/zoom_icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed vc_zoom/indico_vc_zoom/static/images/zoom_logo.png
Binary file not shown.
Loading

0 comments on commit f60f836

Please sign in to comment.