Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit f712186

Browse files
author
Germain Souquet
committed
Migrate StickerPicker to TypeScript
1 parent 9444995 commit f712186

File tree

1 file changed

+86
-76
lines changed

1 file changed

+86
-76
lines changed

src/components/views/rooms/Stickerpicker.js renamed to src/components/views/rooms/Stickerpicker.tsx

Lines changed: 86 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,25 @@ limitations under the License.
1515
*/
1616
import React from 'react';
1717
import classNames from 'classnames';
18+
import { Room } from 'matrix-js-sdk/src/models/room';
1819
import { _t, _td } from '../../../languageHandler';
1920
import AppTile from '../elements/AppTile';
2021
import { MatrixClientPeg } from '../../../MatrixClientPeg';
2122
import * as sdk from '../../../index';
2223
import dis from '../../../dispatcher/dispatcher';
2324
import AccessibleButton from '../elements/AccessibleButton';
24-
import WidgetUtils from '../../../utils/WidgetUtils';
25+
import WidgetUtils, { IWidgetEvent } from '../../../utils/WidgetUtils';
2526
import PersistedElement from "../elements/PersistedElement";
2627
import { IntegrationManagers } from "../../../integrations/IntegrationManagers";
2728
import SettingsStore from "../../../settings/SettingsStore";
28-
import { ContextMenu } from "../../structures/ContextMenu";
29+
import { ChevronFace, ContextMenu } from "../../structures/ContextMenu";
2930
import { WidgetType } from "../../../widgets/WidgetType";
3031
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
3132
import { Action } from "../../../dispatcher/actions";
3233
import { WidgetMessagingStore } from "../../../stores/widgets/WidgetMessagingStore";
3334
import { replaceableComponent } from "../../../utils/replaceableComponent";
35+
import { ActionPayload } from '../../../dispatcher/payloads';
36+
import ScalarAuthClient from '../../../ScalarAuthClient';
3437

3538
// This should be below the dialog level (4000), but above the rest of the UI (1000-2000).
3639
// We sit in a context menu, so this should be given to the context menu.
@@ -39,27 +42,35 @@ const STICKERPICKER_Z_INDEX = 3500;
3942
// Key to store the widget's AppTile under in PersistedElement
4043
const PERSISTED_ELEMENT_KEY = "stickerPicker";
4144

45+
interface IProps {
46+
room: Room;
47+
}
48+
49+
interface IState {
50+
showStickers: boolean;
51+
imError: string;
52+
stickerpickerX: number;
53+
stickerpickerY: number;
54+
stickerpickerChevronOffset?: number;
55+
stickerpickerWidget: IWidgetEvent;
56+
widgetId: string;
57+
}
58+
4259
@replaceableComponent("views.rooms.Stickerpicker")
43-
export default class Stickerpicker extends React.PureComponent {
60+
export default class Stickerpicker extends React.PureComponent<IProps, IState> {
4461
static currentWidget;
4562

46-
constructor(props) {
47-
super(props);
48-
this._onShowStickersClick = this._onShowStickersClick.bind(this);
49-
this._onHideStickersClick = this._onHideStickersClick.bind(this);
50-
this._launchManageIntegrations = this._launchManageIntegrations.bind(this);
51-
this._removeStickerpickerWidgets = this._removeStickerpickerWidgets.bind(this);
52-
this._updateWidget = this._updateWidget.bind(this);
53-
this._onWidgetAction = this._onWidgetAction.bind(this);
54-
this._onResize = this._onResize.bind(this);
55-
this._onFinished = this._onFinished.bind(this);
63+
private dispatcherRef: string;
5664

57-
this.popoverWidth = 300;
58-
this.popoverHeight = 300;
65+
private prevSentVisibility: boolean;
5966

60-
// This is loaded by _acquireScalarClient on an as-needed basis.
61-
this.scalarClient = null;
67+
private popoverWidth = 300;
68+
private popoverHeight = 300;
69+
// This is loaded by _acquireScalarClient on an as-needed basis.
70+
private scalarClient: ScalarAuthClient = null;
6271

72+
constructor(props: IProps) {
73+
super(props);
6374
this.state = {
6475
showStickers: false,
6576
imError: null,
@@ -70,7 +81,7 @@ export default class Stickerpicker extends React.PureComponent {
7081
};
7182
}
7283

73-
_acquireScalarClient() {
84+
private acquireScalarClient(): Promise<void | ScalarAuthClient> {
7485
if (this.scalarClient) return Promise.resolve(this.scalarClient);
7586
// TODO: Pick the right manager for the widget
7687
if (IntegrationManagers.sharedInstance().hasManager()) {
@@ -79,15 +90,15 @@ export default class Stickerpicker extends React.PureComponent {
7990
this.forceUpdate();
8091
return this.scalarClient;
8192
}).catch((e) => {
82-
this._imError(_td("Failed to connect to integration manager"), e);
93+
this.imError(_td("Failed to connect to integration manager"), e);
8394
});
8495
} else {
8596
IntegrationManagers.sharedInstance().openNoManagerDialog();
8697
}
8798
}
8899

89-
async _removeStickerpickerWidgets() {
90-
const scalarClient = await this._acquireScalarClient();
100+
private removeStickerpickerWidgets = async (): Promise<void> => {
101+
const scalarClient = await this.acquireScalarClient();
91102
console.log('Removing Stickerpicker widgets');
92103
if (this.state.widgetId) {
93104
if (scalarClient) {
@@ -109,44 +120,44 @@ export default class Stickerpicker extends React.PureComponent {
109120
}).catch((e) => {
110121
console.error('Failed to remove sticker picker widget', e);
111122
});
112-
}
123+
};
113124

114-
componentDidMount() {
125+
public componentDidMount(): void {
115126
// Close the sticker picker when the window resizes
116-
window.addEventListener('resize', this._onResize);
127+
window.addEventListener('resize', this.onResize);
117128

118-
this.dispatcherRef = dis.register(this._onWidgetAction);
129+
this.dispatcherRef = dis.register(this.onWidgetAction);
119130

120131
// Track updates to widget state in account data
121-
MatrixClientPeg.get().on('accountData', this._updateWidget);
132+
MatrixClientPeg.get().on('accountData', this.updateWidget);
122133

123134
// Initialise widget state from current account data
124-
this._updateWidget();
135+
this.updateWidget();
125136
}
126137

127-
componentWillUnmount() {
138+
public componentWillUnmount(): void {
128139
const client = MatrixClientPeg.get();
129-
if (client) client.removeListener('accountData', this._updateWidget);
140+
if (client) client.removeListener('accountData', this.updateWidget);
130141

131-
window.removeEventListener('resize', this._onResize);
142+
window.removeEventListener('resize', this.onResize);
132143
if (this.dispatcherRef) {
133144
dis.unregister(this.dispatcherRef);
134145
}
135146
}
136147

137-
componentDidUpdate(prevProps, prevState) {
138-
this._sendVisibilityToWidget(this.state.showStickers);
148+
public componentDidUpdate(prevProps: IProps, prevState: IState): void {
149+
this.sendVisibilityToWidget(this.state.showStickers);
139150
}
140151

141-
_imError(errorMsg, e) {
152+
private imError(errorMsg: string, e: Error): void {
142153
console.error(errorMsg, e);
143154
this.setState({
144155
showStickers: false,
145156
imError: _t(errorMsg),
146157
});
147158
}
148159

149-
_updateWidget() {
160+
private updateWidget = (): void => {
150161
const stickerpickerWidget = WidgetUtils.getStickerpickerWidgets()[0];
151162
if (!stickerpickerWidget) {
152163
Stickerpicker.currentWidget = null;
@@ -175,9 +186,9 @@ export default class Stickerpicker extends React.PureComponent {
175186
stickerpickerWidget,
176187
widgetId: stickerpickerWidget ? stickerpickerWidget.id : null,
177188
});
178-
}
189+
};
179190

180-
_onWidgetAction(payload) {
191+
private onWidgetAction = (payload: ActionPayload): void => {
181192
switch (payload.action) {
182193
case "user_widget_updated":
183194
this.forceUpdate();
@@ -191,11 +202,11 @@ export default class Stickerpicker extends React.PureComponent {
191202
this.setState({ showStickers: false });
192203
break;
193204
}
194-
}
205+
};
195206

196-
_defaultStickerpickerContent() {
207+
private defaultStickerpickerContent(): JSX.Element {
197208
return (
198-
<AccessibleButton onClick={this._launchManageIntegrations}
209+
<AccessibleButton onClick={this.launchManageIntegrations}
199210
className='mx_Stickers_contentPlaceholder'>
200211
<p>{ _t("You don't currently have any stickerpacks enabled") }</p>
201212
<p className='mx_Stickers_addLink'>{ _t("Add some now") }</p>
@@ -204,29 +215,29 @@ export default class Stickerpicker extends React.PureComponent {
204215
);
205216
}
206217

207-
_errorStickerpickerContent() {
218+
private errorStickerpickerContent(): JSX.Element {
208219
return (
209-
<div style={{ "text-align": "center" }} className="error">
220+
<div style={{ textAlign: "center" }} className="error">
210221
<p> { this.state.imError } </p>
211222
</div>
212223
);
213224
}
214225

215-
_sendVisibilityToWidget(visible) {
226+
private sendVisibilityToWidget(visible: boolean): void {
216227
if (!this.state.stickerpickerWidget) return;
217228
const messaging = WidgetMessagingStore.instance.getMessagingForId(this.state.stickerpickerWidget.id);
218-
if (messaging && visible !== this._prevSentVisibility) {
229+
if (messaging && visible !== this.prevSentVisibility) {
219230
messaging.updateVisibility(visible).catch(err => {
220231
console.error("Error updating widget visibility: ", err);
221232
});
222-
this._prevSentVisibility = visible;
233+
this.prevSentVisibility = visible;
223234
}
224235
}
225236

226-
_getStickerpickerContent() {
237+
public getStickerpickerContent(): JSX.Element {
227238
// Handle integration manager errors
228-
if (this.state._imError) {
229-
return this._errorStickerpickerContent();
239+
if (this.state.imError) {
240+
return this.errorStickerpickerContent();
230241
}
231242

232243
// Stickers
@@ -244,7 +255,7 @@ export default class Stickerpicker extends React.PureComponent {
244255
// Load stickerpack content
245256
if (stickerpickerWidget && stickerpickerWidget.content && stickerpickerWidget.content.url) {
246257
// Set default name
247-
stickerpickerWidget.content.name = stickerpickerWidget.name || _t("Stickerpack");
258+
stickerpickerWidget.content.name = stickerpickerWidget.content.name || _t("Stickerpack");
248259

249260
// FIXME: could this use the same code as other apps?
250261
const stickerApp = {
@@ -275,12 +286,12 @@ export default class Stickerpicker extends React.PureComponent {
275286
creatorUserId={stickerpickerWidget.sender || MatrixClientPeg.get().credentials.userId}
276287
waitForIframeLoad={true}
277288
showMenubar={true}
278-
onEditClick={this._launchManageIntegrations}
279-
onDeleteClick={this._removeStickerpickerWidgets}
289+
onEditClick={this.launchManageIntegrations}
290+
onDeleteClick={this.removeStickerpickerWidgets}
280291
showTitle={false}
281292
showCancel={false}
282293
showPopout={false}
283-
onMinimiseClick={this._onHideStickersClick}
294+
onMinimiseClick={this.onHideStickersClick}
284295
handleMinimisePointerEvents={true}
285296
userWidget={true}
286297
/>
@@ -290,7 +301,7 @@ export default class Stickerpicker extends React.PureComponent {
290301
);
291302
} else {
292303
// Default content to show if stickerpicker widget not added
293-
stickersContent = this._defaultStickerpickerContent();
304+
stickersContent = this.defaultStickerpickerContent();
294305
}
295306
return stickersContent;
296307
}
@@ -300,15 +311,15 @@ export default class Stickerpicker extends React.PureComponent {
300311
* Show the sticker picker overlay
301312
* If no stickerpacks have been added, show a link to the integration manager add sticker packs page.
302313
*/
303-
_onShowStickersClick(e) {
314+
private onShowStickersClick = (e: React.MouseEvent<HTMLElement>): void => {
304315
if (!SettingsStore.getValue("integrationProvisioning")) {
305316
// Intercept this case and spawn a warning.
306317
return IntegrationManagers.sharedInstance().showDisabledDialog();
307318
}
308319

309320
// XXX: Simplify by using a context menu that is positioned relative to the sticker picker button
310321

311-
const buttonRect = e.target.getBoundingClientRect();
322+
const buttonRect = e.currentTarget.getBoundingClientRect();
312323

313324
// The window X and Y offsets are to adjust position when zoomed in to page
314325
let x = buttonRect.right + window.pageXOffset - 41;
@@ -324,50 +335,50 @@ export default class Stickerpicker extends React.PureComponent {
324335
// Offset the chevron location, which is relative to the left of the context menu
325336
// (10 = offset when context menu would not be displayed off viewport)
326337
// (2 = context menu borders)
327-
const stickerPickerChevronOffset = Math.max(10, 2 + window.pageXOffset + buttonRect.left - x);
338+
const stickerpickerChevronOffset = Math.max(10, 2 + window.pageXOffset + buttonRect.left - x);
328339

329340
const y = (buttonRect.top + (buttonRect.height / 2) + window.pageYOffset) - 19;
330341

331342
this.setState({
332343
showStickers: true,
333-
stickerPickerX: x,
334-
stickerPickerY: y,
335-
stickerPickerChevronOffset,
344+
stickerpickerX: x,
345+
stickerpickerY: y,
346+
stickerpickerChevronOffset,
336347
});
337-
}
348+
};
338349

339350
/**
340351
* Trigger hiding of the sticker picker overlay
341352
* @param {Event} ev Event that triggered the function call
342353
*/
343-
_onHideStickersClick(ev) {
354+
private onHideStickersClick = (ev: React.MouseEvent): void => {
344355
if (this.state.showStickers) {
345356
this.setState({ showStickers: false });
346357
}
347-
}
358+
};
348359

349360
/**
350361
* Called when the window is resized
351362
*/
352-
_onResize() {
363+
private onResize = (): void => {
353364
if (this.state.showStickers) {
354365
this.setState({ showStickers: false });
355366
}
356-
}
367+
};
357368

358369
/**
359370
* The stickers picker was hidden
360371
*/
361-
_onFinished() {
372+
private onFinished = (): void => {
362373
if (this.state.showStickers) {
363374
this.setState({ showStickers: false });
364375
}
365-
}
376+
};
366377

367378
/**
368379
* Launch the integration manager on the stickers integration page
369380
*/
370-
_launchManageIntegrations = () => {
381+
private launchManageIntegrations = (): void => {
371382
// TODO: Open the right integration manager for the widget
372383
if (SettingsStore.getValue("feature_many_integration_managers")) {
373384
IntegrationManagers.sharedInstance().openAll(
@@ -384,7 +395,7 @@ export default class Stickerpicker extends React.PureComponent {
384395
}
385396
};
386397

387-
render() {
398+
public render(): JSX.Element {
388399
let stickerPicker;
389400
let stickersButton;
390401
const className = classNames(
@@ -400,26 +411,25 @@ export default class Stickerpicker extends React.PureComponent {
400411
id='stickersButton'
401412
key="controls_hide_stickers"
402413
className={className}
403-
onClick={this._onHideStickersClick}
404-
active={this.state.showStickers.toString()}
414+
onClick={this.onHideStickersClick}
405415
title={_t("Hide Stickers")}
406416
/>;
407417

408418
const GenericElementContextMenu = sdk.getComponent('context_menus.GenericElementContextMenu');
409419
stickerPicker = <ContextMenu
410-
chevronOffset={this.state.stickerPickerChevronOffset}
411-
chevronFace="bottom"
412-
left={this.state.stickerPickerX}
413-
top={this.state.stickerPickerY}
420+
chevronOffset={this.state.stickerpickerChevronOffset}
421+
chevronFace={ChevronFace.Bottom}
422+
left={this.state.stickerpickerX}
423+
top={this.state.stickerpickerY}
414424
menuWidth={this.popoverWidth}
415425
menuHeight={this.popoverHeight}
416-
onFinished={this._onFinished}
426+
onFinished={this.onFinished}
417427
menuPaddingTop={0}
418428
menuPaddingLeft={0}
419429
menuPaddingRight={0}
420430
zIndex={STICKERPICKER_Z_INDEX}
421431
>
422-
<GenericElementContextMenu element={this._getStickerpickerContent()} onResize={this._onFinished} />
432+
<GenericElementContextMenu element={this.getStickerpickerContent()} onResize={this.onFinished} />
423433
</ContextMenu>;
424434
} else {
425435
// Show show-stickers button
@@ -428,7 +438,7 @@ export default class Stickerpicker extends React.PureComponent {
428438
id='stickersButton'
429439
key="controls_show_stickers"
430440
className="mx_MessageComposer_button mx_MessageComposer_stickers"
431-
onClick={this._onShowStickersClick}
441+
onClick={this.onShowStickersClick}
432442
title={_t("Show Stickers")}
433443
/>;
434444
}

0 commit comments

Comments
 (0)