@@ -22,6 +22,8 @@ import dis from '../../dispatcher';
22
22
import { sanitizedHtmlNode } from '../../HtmlUtils' ;
23
23
import { _t } from '../../languageHandler' ;
24
24
import AccessibleButton from '../views/elements/AccessibleButton' ;
25
+ import Modal from '../../Modal' ;
26
+ import classnames from 'classnames' ;
25
27
26
28
const RoomSummaryType = PropTypes . shape ( {
27
29
room_id : PropTypes . string . isRequired ,
@@ -179,10 +181,13 @@ export default React.createClass({
179
181
summary : null ,
180
182
error : null ,
181
183
editing : false ,
184
+ saving : false ,
185
+ uploadingAvatar : false ,
182
186
} ;
183
187
} ,
184
188
185
189
componentWillMount : function ( ) {
190
+ this . _changeAvatarComponent = null ;
186
191
this . _loadGroupFromServer ( this . props . groupId ) ;
187
192
} ,
188
193
@@ -211,8 +216,83 @@ export default React.createClass({
211
216
} ) ;
212
217
} ,
213
218
214
- _onSettingsClick : function ( ) {
215
- this . setState ( { editing : true } ) ;
219
+ _onEditClick : function ( ) {
220
+ this . setState ( {
221
+ editing : true ,
222
+ profileForm : Object . assign ( { } , this . state . summary . profile ) ,
223
+ } ) ;
224
+ } ,
225
+
226
+ _onCancelClick : function ( ) {
227
+ this . setState ( {
228
+ editing : false ,
229
+ profileForm : null ,
230
+ } ) ;
231
+ } ,
232
+
233
+ _onNameChange : function ( e ) {
234
+ const newProfileForm = Object . assign ( this . state . profileForm , { name : e . target . value } ) ;
235
+ this . setState ( {
236
+ profileForm : newProfileForm ,
237
+ } ) ;
238
+ } ,
239
+
240
+ _onShortDescChange : function ( e ) {
241
+ const newProfileForm = Object . assign ( this . state . profileForm , { short_description : e . target . value } ) ;
242
+ this . setState ( {
243
+ profileForm : newProfileForm ,
244
+ } ) ;
245
+ } ,
246
+
247
+ _onLongDescChange : function ( e ) {
248
+ const newProfileForm = Object . assign ( this . state . profileForm , { long_description : e . target . value } ) ;
249
+ this . setState ( {
250
+ profileForm : newProfileForm ,
251
+ } ) ;
252
+ } ,
253
+
254
+ _onAvatarSelected : function ( ev ) {
255
+ const file = ev . target . files [ 0 ] ;
256
+ if ( ! file ) return ;
257
+
258
+ this . setState ( { uploadingAvatar : true } ) ;
259
+ MatrixClientPeg . get ( ) . uploadContent ( file ) . then ( ( url ) => {
260
+ const newProfileForm = Object . assign ( this . state . profileForm , { avatar_url : url } ) ;
261
+ this . setState ( {
262
+ uploadingAvatar : false ,
263
+ profileForm : newProfileForm ,
264
+ } ) ;
265
+ } ) . catch ( ( e ) => {
266
+ this . setState ( { uploadingAvatar : false } ) ;
267
+ const ErrorDialog = sdk . getComponent ( "dialogs.ErrorDialog" ) ;
268
+ console . error ( "Failed to upload avatar image" , e ) ;
269
+ Modal . createDialog ( ErrorDialog , {
270
+ title : _t ( 'Error' ) ,
271
+ description : _t ( 'Failed to upload image' ) ,
272
+ } ) ;
273
+ } ) . done ( ) ;
274
+ } ,
275
+
276
+ _onSaveClick : function ( ) {
277
+ this . setState ( { saving : true } ) ;
278
+ MatrixClientPeg . get ( ) . setGroupProfile ( this . props . groupId , this . state . profileForm ) . then ( ( result ) => {
279
+ this . setState ( {
280
+ saving : false ,
281
+ editing : false ,
282
+ summary : null ,
283
+ } ) ;
284
+ this . _loadGroupFromServer ( this . props . groupId ) ;
285
+ } ) . catch ( ( e ) => {
286
+ this . setState ( {
287
+ saving : false ,
288
+ } ) ;
289
+ const ErrorDialog = sdk . getComponent ( "dialogs.ErrorDialog" ) ;
290
+ console . error ( "Failed to save group profile" , e ) ;
291
+ Modal . createDialog ( ErrorDialog , {
292
+ title : _t ( 'Error' ) ,
293
+ description : _t ( 'Failed to update group' ) ,
294
+ } ) ;
295
+ } ) . done ( ) ;
216
296
} ,
217
297
218
298
_getFeaturedRoomsNode ( ) {
@@ -296,60 +376,129 @@ export default React.createClass({
296
376
const Loader = sdk . getComponent ( "elements.Spinner" ) ;
297
377
const TintableSvg = sdk . getComponent ( "elements.TintableSvg" ) ;
298
378
299
- if ( this . state . summary === null && this . state . error === null ) {
379
+ if ( this . state . summary === null && this . state . error === null || this . state . saving ) {
300
380
return < Loader /> ;
301
- } else if ( this . state . editing ) {
302
- return < div /> ;
303
381
} else if ( this . state . summary ) {
304
382
const summary = this . state . summary ;
305
- let description = null ;
306
- if ( summary . profile && summary . profile . long_description ) {
307
- description = sanitizedHtmlNode ( summary . profile . long_description ) ;
308
- }
309
-
310
- const roomBody = < div >
311
- < div className = "mx_GroupView_groupDesc" > { description } </ div >
312
- { this . _getFeaturedRoomsNode ( ) }
313
- { this . _getFeaturedUsersNode ( ) }
314
- </ div > ;
315
383
384
+ let avatarNode ;
316
385
let nameNode ;
317
- if ( summary . profile && summary . profile . name ) {
318
- nameNode = < div className = "mx_RoomHeader_name" >
319
- < span > { summary . profile . name } </ span >
320
- < span className = "mx_GroupView_header_groupid" >
321
- ({ this . props . groupId } )
322
- </ span >
386
+ let shortDescNode ;
387
+ let rightButtons ;
388
+ let roomBody ;
389
+ const headerClasses = {
390
+ mx_GroupView_header : true ,
391
+ } ;
392
+ if ( this . state . editing ) {
393
+ let avatarImage ;
394
+ if ( this . state . uploadingAvatar ) {
395
+ avatarImage = < Loader /> ;
396
+ } else {
397
+ const GroupAvatar = sdk . getComponent ( 'avatars.GroupAvatar' ) ;
398
+ avatarImage = < GroupAvatar groupId = { this . props . groupId }
399
+ groupAvatarUrl = { this . state . profileForm . avatar_url }
400
+ width = { 48 } height = { 48 } resizeMethod = 'crop'
401
+ /> ;
402
+ }
403
+
404
+ avatarNode = (
405
+ < div className = "mx_GroupView_avatarPicker" >
406
+ < label htmlFor = "avatarInput" className = "mx_GroupView_avatarPicker_label" >
407
+ { avatarImage }
408
+ </ label >
409
+ < div className = "mx_GroupView_avatarPicker_edit" >
410
+ < label htmlFor = "avatarInput" className = "mx_GroupView_avatarPicker_label" >
411
+ < img src = "img/camera.svg"
412
+ alt = { _t ( "Upload avatar" ) } title = { _t ( "Upload avatar" ) }
413
+ width = "17" height = "15" />
414
+ </ label >
415
+ < input id = "avatarInput" className = "mx_GroupView_uploadInput" type = "file" onChange = { this . _onAvatarSelected } />
416
+ </ div >
417
+ </ div >
418
+ ) ;
419
+ nameNode = < input type = "text"
420
+ value = { this . state . profileForm . name }
421
+ onChange = { this . _onNameChange }
422
+ placeholder = { _t ( 'Group Name' ) }
423
+ tabIndex = "1"
424
+ /> ;
425
+ shortDescNode = < input type = "text"
426
+ value = { this . state . profileForm . short_description }
427
+ onChange = { this . _onShortDescChange }
428
+ placeholder = { _t ( 'Description' ) }
429
+ tabIndex = "2"
430
+ /> ;
431
+ rightButtons = < span >
432
+ < AccessibleButton className = "mx_GroupView_saveButton mx_RoomHeader_textButton" onClick = { this . _onSaveClick } >
433
+ { _t ( 'Save' ) }
434
+ </ AccessibleButton >
435
+ < AccessibleButton className = 'mx_GroupView_cancelButton' onClick = { this . _onCancelClick } >
436
+ < img src = "img/cancel.svg" className = 'mx_filterFlipColor'
437
+ width = "18" height = "18" alt = { _t ( "Cancel" ) } />
438
+ </ AccessibleButton >
439
+ </ span > ;
440
+ roomBody = < div >
441
+ < textarea className = "mx_GroupView_editLongDesc" value = { this . state . profileForm . long_description }
442
+ onChange = { this . _onLongDescChange }
443
+ tabIndex = "3"
444
+ />
323
445
</ div > ;
324
446
} else {
325
- nameNode = < div className = "mx_RoomHeader_name" >
326
- < span > { this . props . groupId } </ span >
447
+ const groupAvatarUrl = summary . profile ? summary . profile . avatar_url : null ;
448
+ avatarNode = < GroupAvatar
449
+ groupId = { this . props . groupId }
450
+ groupAvatarUrl = { groupAvatarUrl }
451
+ width = { 48 } height = { 48 }
452
+ /> ;
453
+ if ( summary . profile && summary . profile . name ) {
454
+ nameNode = < div >
455
+ < span > { summary . profile . name } </ span >
456
+ < span className = "mx_GroupView_header_groupid" >
457
+ ({ this . props . groupId } )
458
+ </ span >
459
+ </ div > ;
460
+ } else {
461
+ nameNode = < span > { this . props . groupId } </ span > ;
462
+ }
463
+ shortDescNode = < span > { summary . profile . short_description } </ span > ;
464
+
465
+ let description = null ;
466
+ if ( summary . profile && summary . profile . long_description ) {
467
+ description = sanitizedHtmlNode ( summary . profile . long_description ) ;
468
+ }
469
+ roomBody = < div >
470
+ < div className = "mx_GroupView_groupDesc" > { description } </ div >
471
+ { this . _getFeaturedRoomsNode ( ) }
472
+ { this . _getFeaturedUsersNode ( ) }
327
473
</ div > ;
474
+ // disabled until editing works
475
+ rightButtons = < AccessibleButton className = "mx_GroupHeader_button"
476
+ onClick = { this . _onEditClick } title = { _t ( "Edit Group" ) }
477
+ >
478
+ < TintableSvg src = "img/icons-settings-room.svg" width = "16" height = "16" />
479
+ </ AccessibleButton > ;
480
+
481
+ headerClasses . mx_GroupView_header_view = true ;
328
482
}
329
483
330
- const groupAvatarUrl = summary . profile ? summary . profile . avatar_url : null ;
331
-
332
- // settings button is display: none until settings is wired up
333
484
return (
334
485
< div className = "mx_GroupView" >
335
- < div className = "mx_RoomHeader" >
336
- < div className = "mx_RoomHeader_wrapper" >
337
- < div className = "mx_RoomHeader_avatar" >
338
- < GroupAvatar
339
- groupId = { this . props . groupId }
340
- groupAvatarUrl = { groupAvatarUrl }
341
- width = { 48 } height = { 48 }
342
- />
486
+ < div className = { classnames ( headerClasses ) } >
487
+ < div className = "mx_GroupView_header_leftCol" >
488
+ < div className = "mx_GroupView_header_avatar" >
489
+ { avatarNode }
343
490
</ div >
344
- < div className = "mx_RoomHeader_info" >
345
- { nameNode }
346
- < div className = "mx_RoomHeader_topic" >
347
- { summary . profile . short_description }
491
+ < div className = "mx_GroupView_header_info" >
492
+ < div className = "mx_GroupView_header_name" >
493
+ { nameNode }
494
+ </ div >
495
+ < div className = "mx_GroupView_header_shortDesc" >
496
+ { shortDescNode }
348
497
</ div >
349
498
</ div >
350
- < AccessibleButton className = "mx_RoomHeader_button" onClick = { this . _onSettingsClick } title = { _t ( "Settings" ) } style = { { display : 'none' } } >
351
- < TintableSvg src = "img/icons-settings-room.svg" width = "16" height = "16" / >
352
- </ AccessibleButton >
499
+ </ div >
500
+ < div className = "mx_GroupView_header_rightCol" >
501
+ { rightButtons }
353
502
</ div >
354
503
</ div >
355
504
{ roomBody }
0 commit comments