Skip to content

Commit 2437ca6

Browse files
Move to functional components (Part IV) (#2353)
* Use FC for EditingOverviewCard * Use FC for MissionCreator * Use FC for EditingWorkspaceSideContentDeploymentTab * Reformat code and comments * Use FC for SourceRecorderShareCell * Use FC for SourceRecorderSelectCell * Use FC for SideContentToneMatrix * Use FC for SideContentCanvasOutput * Fix incorrect memoization * Standardise Drawable export/imports * Use FC for BackwardArrowDrawable * Improve comment formatting * Add back memoization * Use FC for ArrowDrawable --------- Co-authored-by: Martin Henz <[email protected]>
1 parent eac74a9 commit 2437ca6

14 files changed

+360
-443
lines changed

src/commons/editingOverviewCard/EditingOverviewCard.tsx

+76-104
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {
1414
} from '@blueprintjs/core';
1515
import { IconNames } from '@blueprintjs/icons';
1616
import { ItemRenderer, Select } from '@blueprintjs/select';
17-
import * as React from 'react';
17+
import React, { useState } from 'react';
1818
import { NavLink } from 'react-router-dom';
1919
import Textarea from 'react-textarea-autosize';
2020

@@ -38,85 +38,57 @@ type StateProps = {
3838
assessmentTypes: AssessmentType[];
3939
};
4040

41-
type State = {
42-
editingOverviewField: string;
43-
fieldValue: any;
44-
showOptionsOverlay: boolean;
45-
};
46-
47-
export class EditingOverviewCard extends React.Component<EditingOverviewCardProps, State> {
48-
public constructor(props: EditingOverviewCardProps) {
49-
super(props);
50-
this.state = {
51-
editingOverviewField: '',
52-
fieldValue: '',
53-
showOptionsOverlay: false
54-
};
55-
}
56-
57-
public render() {
58-
return (
59-
<div>
60-
{this.optionsOverlay()}
61-
{this.makeEditingOverviewCard(this.props.overview)}
62-
</div>
63-
);
64-
}
41+
export const EditingOverviewCard: React.FC<EditingOverviewCardProps> = props => {
42+
const [editingOverviewField, setEditingOverviewField] = useState('');
43+
const [fieldValue, setFieldValue] = useState<any>('');
44+
const [showOptionsOverlay, setShowOptionsOverlay] = useState(false);
6545

66-
private saveEditOverview = (field: keyof AssessmentOverview) => (e: any) => {
46+
const saveEditOverview = (field: keyof AssessmentOverview) => (e: any) => {
6747
const overview = {
68-
...this.props.overview,
69-
[field]: this.state.fieldValue
48+
...props.overview,
49+
[field]: fieldValue
7050
};
71-
this.setState({
72-
editingOverviewField: '',
73-
fieldValue: ''
74-
});
51+
setEditingOverviewField('');
52+
setFieldValue('');
7553
storeLocalAssessmentOverview(overview);
76-
this.props.updateEditingOverview(overview);
54+
props.updateEditingOverview(overview);
7755
};
7856

79-
private handleEditOverview = () => (e: any) => {
80-
this.setState({
81-
fieldValue: e.target.value
82-
});
57+
const handleEditOverview = (e: any) => {
58+
setFieldValue(e.target.value);
8359
};
8460

85-
private toggleEditField = (field: keyof AssessmentOverview) => (e: any) => {
86-
if (this.state.editingOverviewField !== field) {
87-
this.setState({
88-
editingOverviewField: field,
89-
fieldValue: this.props.overview[field]
90-
});
61+
const toggleEditField = (field: keyof AssessmentOverview) => (e: any) => {
62+
if (editingOverviewField !== field) {
63+
setEditingOverviewField(field);
64+
setFieldValue(props.overview[field]);
9165
}
9266
};
9367

94-
private toggleOptionsOverlay = () => {
95-
this.setState({
96-
showOptionsOverlay: !this.state.showOptionsOverlay
97-
});
68+
const toggleOptionsOverlay = () => {
69+
setShowOptionsOverlay(!showOptionsOverlay);
9870
};
9971

100-
private handleExportXml = (e: any) => {
72+
const handleExportXml = (e: any) => {
10173
exportXml();
10274
};
10375

104-
private makeEditingOverviewTextarea = (field: keyof AssessmentOverview) => (
76+
const makeEditingOverviewTextarea = (field: keyof AssessmentOverview) => (
10577
<Textarea
10678
autoFocus={true}
10779
className={'editing-textarea'}
108-
onChange={this.handleEditOverview()}
109-
onBlur={this.saveEditOverview(field)}
110-
value={this.state.fieldValue}
80+
onChange={handleEditOverview}
81+
onBlur={saveEditOverview(field)}
82+
value={fieldValue}
11183
/>
11284
);
11385

114-
private makeEditingOverviewCard = (overview: AssessmentOverview) => (
86+
const makeEditingOverviewCard = (overview: AssessmentOverview) => (
11587
<div>
11688
<Card className="row listing" elevation={Elevation.ONE}>
117-
<div className="col-xs-3 listing-picture" onClick={this.toggleEditField('coverImage')}>
118-
{this.state.editingOverviewField === 'coverImage' ? (
119-
this.makeEditingOverviewTextarea('coverImage')
89+
<div className="col-xs-3 listing-picture" onClick={toggleEditField('coverImage')}>
90+
{editingOverviewField === 'coverImage' ? (
91+
makeEditingOverviewTextarea('coverImage')
12092
) : (
12193
<img
12294
alt="Assessment cover"
@@ -127,13 +99,13 @@ export class EditingOverviewCard extends React.Component<EditingOverviewCardProp
12799
</div>
128100

129101
<div className="col-xs-9 listing-text">
130-
{this.makeEditingOverviewCardTitle(overview, overview.title)}
102+
{makeEditingOverviewCardTitle(overview, overview.title)}
131103
<div className="row listing-xp">
132104
<H6> {`Max XP: ${overview.maxXp}`} </H6>
133105
</div>
134-
<div className="row listing-description" onClick={this.toggleEditField('shortSummary')}>
135-
{this.state.editingOverviewField === 'shortSummary' ? (
136-
this.makeEditingOverviewTextarea('shortSummary')
106+
<div className="row listing-description" onClick={toggleEditField('shortSummary')}>
107+
{editingOverviewField === 'shortSummary' ? (
108+
makeEditingOverviewTextarea('shortSummary')
137109
) : (
138110
<Markdown content={createPlaceholder(overview.shortSummary)} />
139111
)}
@@ -142,26 +114,24 @@ export class EditingOverviewCard extends React.Component<EditingOverviewCardProp
142114
<Text className="listing-due-date">
143115
<Icon className="listing-due-icon" iconSize={12} icon={IconNames.TIME} />
144116
<div className="date-container">Opens at:&nbsp;</div>
145-
<div className="date-container" onClick={this.toggleEditField('openAt')}>
146-
{this.state.editingOverviewField === 'openAt'
147-
? this.makeEditingOverviewTextarea('openAt')
117+
<div className="date-container" onClick={toggleEditField('openAt')}>
118+
{editingOverviewField === 'openAt'
119+
? makeEditingOverviewTextarea('openAt')
148120
: `${getPrettyDate(overview.openAt)}`}
149121
</div>
150122

151123
<div className="date-container">&nbsp;&nbsp;Due:&nbsp;</div>
152-
<div className="date-container" onClick={this.toggleEditField('closeAt')}>
153-
{this.state.editingOverviewField === 'closeAt'
154-
? this.makeEditingOverviewTextarea('closeAt')
124+
<div className="date-container" onClick={toggleEditField('closeAt')}>
125+
{editingOverviewField === 'closeAt'
126+
? makeEditingOverviewTextarea('closeAt')
155127
: `${getPrettyDate(overview.closeAt)}`}
156128
</div>
157129
</Text>
158-
<Button icon={IconNames.WRENCH} minimal={true} onClick={this.toggleOptionsOverlay}>
130+
<Button icon={IconNames.WRENCH} minimal={true} onClick={toggleOptionsOverlay}>
159131
Other Options
160132
</Button>
161133
<NavLink
162-
to={`${this.props.listingPath}/${overview.id.toString()}/${
163-
Constants.defaultQuestionId
164-
}`}
134+
to={`${props.listingPath}/${overview.id.toString()}/${Constants.defaultQuestionId}`}
165135
>
166136
<ControlButton label="Edit mission" icon={IconNames.EDIT} />
167137
</NavLink>
@@ -171,82 +141,77 @@ export class EditingOverviewCard extends React.Component<EditingOverviewCardProp
171141
</div>
172142
);
173143

174-
private makeEditingOverviewCardTitle = (overview: AssessmentOverview, title: string) => (
144+
const makeEditingOverviewCardTitle = (overview: AssessmentOverview, title: string) => (
175145
<div className="row listing-title">
176146
<Text ellipsize={true} className={'col-xs-10'}>
177-
<H4 onClick={this.toggleEditField('title')}>
178-
{this.state.editingOverviewField === 'title'
179-
? this.makeEditingOverviewTextarea('title')
147+
<H4 onClick={toggleEditField('title')}>
148+
{editingOverviewField === 'title'
149+
? makeEditingOverviewTextarea('title')
180150
: createPlaceholder(title)}
181151
</H4>
182152
</Text>
183-
<div className="col-xs-2">{this.makeExportButton(overview)}</div>
153+
<div className="col-xs-2">{makeExportButton(overview)}</div>
184154
</div>
185155
);
186156

187-
private makeExportButton = (overview: AssessmentOverview) => (
188-
<Button
189-
icon={IconNames.EXPORT}
190-
intent={Intent.DANGER}
191-
minimal={true}
192-
onClick={this.handleExportXml}
193-
>
157+
const makeExportButton = (overview: AssessmentOverview) => (
158+
<Button icon={IconNames.EXPORT} intent={Intent.DANGER} minimal={true} onClick={handleExportXml}>
194159
Save as XML
195160
</Button>
196161
);
197162

198-
private saveCategory = (i: AssessmentType, e: any) => {
163+
const saveCategory = (i: AssessmentType, e: any) => {
199164
const overview = {
200-
...this.props.overview,
165+
...props.overview,
201166
category: i
202167
};
203168
storeLocalAssessmentOverview(overview);
204-
this.props.updateEditingOverview(overview);
169+
props.updateEditingOverview(overview);
205170
};
206171

207-
private optionsOverlay = () => (
172+
const optionsOverlay = () => (
208173
<Dialog
209174
canOutsideClickClose={false}
210175
className="assessment-reset"
211176
icon={IconNames.WRENCH}
212177
isCloseButtonShown={true}
213-
isOpen={this.state.showOptionsOverlay}
214-
onClose={this.toggleOptionsOverlay}
178+
isOpen={showOptionsOverlay}
179+
onClose={toggleOptionsOverlay}
215180
title="Other options"
216181
>
217182
<div className={Classes.DIALOG_BODY}>
218183
<H3>Assessment Type</H3>
219-
{this.assessmentTypeSelect(this.props.overview.type, this.saveCategory)}
184+
{assessmentTypeSelect(props.overview.type, saveCategory)}
220185
<H3>Number</H3>
221-
<div onClick={this.toggleEditField('number')}>
222-
{this.state.editingOverviewField === 'number'
223-
? this.makeEditingOverviewTextarea('number')
224-
: createPlaceholder(this.props.overview.number || '')}
186+
<div onClick={toggleEditField('number')}>
187+
{editingOverviewField === 'number'
188+
? makeEditingOverviewTextarea('number')
189+
: createPlaceholder(props.overview.number || '')}
225190
</div>
226191
<H3>Story</H3>
227-
<div onClick={this.toggleEditField('story')}>
228-
{this.state.editingOverviewField === 'story'
229-
? this.makeEditingOverviewTextarea('story')
230-
: createPlaceholder(this.props.overview.story || '')}
192+
<div onClick={toggleEditField('story')}>
193+
{editingOverviewField === 'story'
194+
? makeEditingOverviewTextarea('story')
195+
: createPlaceholder(props.overview.story || '')}
231196
</div>
232197
<br />
233198
<H3>Filename</H3>
234-
<div onClick={this.toggleEditField('fileName')}>
235-
{this.state.editingOverviewField === 'fileName'
236-
? this.makeEditingOverviewTextarea('fileName')
237-
: createPlaceholder(this.props.overview.fileName || '')}
199+
<div onClick={toggleEditField('fileName')}>
200+
{editingOverviewField === 'fileName'
201+
? makeEditingOverviewTextarea('fileName')
202+
: createPlaceholder(props.overview.fileName || '')}
238203
</div>
239204
</div>
240205
</Dialog>
241206
);
242207

243-
private assessmentTypeSelect = (
208+
const assessmentTypeSelect = (
244209
assessmentType: AssessmentType,
245210
handleSelect = (i: AssessmentType, e?: React.SyntheticEvent<HTMLElement>) => {}
246211
) => (
247212
<AssessmentTypeSelectComponent
248213
className={Classes.MINIMAL}
249-
items={this.props.assessmentTypes}
214+
items={props.assessmentTypes}
250215
onItemSelect={handleSelect}
251216
itemRenderer={assessmentTypeRenderer}
252217
filterable={false}
@@ -258,7 +223,14 @@ export class EditingOverviewCard extends React.Component<EditingOverviewCardProp
258223
/>
259224
</AssessmentTypeSelectComponent>
260225
);
261-
}
226+
227+
return (
228+
<div>
229+
{optionsOverlay()}
230+
{makeEditingOverviewCard(props.overview)}
231+
</div>
232+
);
233+
};
262234

263235
const createPlaceholder = (str: string): string => {
264236
if (str.match('^(\n| )*$')) {

0 commit comments

Comments
 (0)