Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds sessions layout public event #68

Merged
merged 1 commit into from May 24, 2017

Conversation

dilpreetsio
Copy link
Member

  • I have read the Contribution & Best practices Guide.
  • My branch is up-to-date with the Upstream development branch.
  • The acceptance, integration, unit tests and linter pass locally with my changes
  • I have added tests that prove my fix is effective or that my feature works
  • I have added necessary documentation (if appropriate)

Short description of what this resolves:

Adds session layout in public events page
Added components

  • Session-filter
  • Session-list
  • Session-item

####Screenshot
screenshot from 2017-05-22 10-25-03

Fixes #63
@niranjan94 Please review.

@codecov
Copy link

codecov bot commented May 22, 2017

Codecov Report

Merging #68 into development will increase coverage by 0.17%.
The diff coverage is 77.77%.

Impacted file tree graph

@@               Coverage Diff               @@
##           development      #68      +/-   ##
===============================================
+ Coverage        58.83%   59.01%   +0.17%     
===============================================
  Files              129      133       +4     
  Lines              945      954       +9     
===============================================
+ Hits               556      563       +7     
- Misses             389      391       +2
Impacted Files Coverage Δ
app/components/public/session-list.js 100% <100%> (ø)
app/components/public/session-item.js 100% <100%> (ø)
app/components/public/session-filter.js 50% <50%> (ø)
app/controllers/public/sessions.js 80% <80%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update bb8eeb0...9c48c91. Read the comment docs.

@niranjan94 niranjan94 temporarily deployed to eventyay-frontend-pr-68 May 22, 2017 05:05 Inactive
@lunaticmonk
Copy link
Member

@geekyd Looks good, but I think it would look better if we increase some space between the "Talk" and the image.

Copy link
Member

@niranjan94 niranjan94 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few functional changes. UI review I'll do it once this is done.

const { Controller, computed } = Ember;

export default Controller.extend({
sessions: [{ shortAbstract: 'An introduction to the event', id: '1', title: 'Welcome to FOSSASIA', startAt: '10:35 AM / 17-03-2017', track: { color: 'green', fontColor: 'green', id: 0, name: 'Track 1' }, microlocation: { id: 0, name: 'Room 1' }, speakers: [{ shortBiography: 'Works for ORG 1', id: 0, city: 'Delhi', name: 'Arnold Singh', speakingExperience: 'GSOC 2015', organisation: 'ORG 1', longBiography: '', photo: { 'iconImageUrl': '' } }] },
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like I said in the issue, the startsAt and endsAt fields will be a js Date object. not a string.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@niranjan94 As we are going to use model for getting sessions, it would be better if we use parse the dates in the model.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The model's output is gonna be a js date object. (It will parse the API Response and give a js date output) ... And we shouldn't do the date -> string conversion in the model ... because the string date format we require might vary depending on where the session is being displayed in the UI.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like for example,

  • in this page we may want to display it in a more human readable form like March 23, 2017 05:30 PM
  • In the sessions table we'll display 23/03/2017 05:30 PM
  • In the form we may display in another way for it to work with the date picker.

We can't and shouldn't put all of this inside the model.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay got it!


const { Helper } = Ember;

export function underscoreText(params) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove this helper and use the underscore helper from ember-cli-string-helpers which is already a part of this project.

@@ -0,0 +1,5 @@
<div class="ui segment">
{{#each-in tracks as |track|}}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think tabs would look better. And when a user presses on a track, don't scroll to it. Instead filter the whole list to display only that track.

@dilpreetsio
Copy link
Member Author

dilpreetsio commented May 23, 2017

@niranjan94 Please review.
screenshot from 2017-05-23 11-07-22

Copy link
Member

@niranjan94 niranjan94 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Be reactive to data. Let computed properties do a lot of heavy lifting for you.

In your action based implementation, even if I'm on all tracks and keep pressing the all tab, the whole action will keep getting executed and hence the sessionsByTracks will keep getting computed.

But in the case of computed properties, unless the selected track changes, it'll not get recomputed. You can click on a button how many ever times you want.

And the next thing is, when you have an ID for any data object, never depend on it's name.

return keys(groupBy(orderBy(this.get('sessions'), 'startAt'), 'track.name'));
}),
actions: {
filterSession(element) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this action.

sessions: [{ shortAbstract: 'An introduction to the event', id: '1', title: 'Welcome to FOSSASIA', startAt: moment(new Date()).format('h:mm a / DD-MM-YYYY'), track: { color: 'green', fontColor: 'green', id: 0, name: 'Track 1' }, microlocation: { id: 2, name: 'Room 1' }, speakers: [{ shortBiography: 'Works for ORG 1', id: 0, city: 'Delhi', name: 'Arnold Singh', speakingExperience: 'GSOC 2015', organisation: 'ORG 1', longBiography: '', photo: { 'iconImageUrl': '' } }] },
{ shortAbstract: 'Welcome to open source', id: '2', title: 'Introduction to Open source', startAt: moment(new Date().setMinutes(10)).format('h:mm a / DD-MM-YYYY'), track: { color: 'red', fontColor: 'white', id: 0, name: 'Track 2' }, microlocation: { id: 3, name: 'Room 5' }, speakers: [{ shortBiography: '', id: 0, city: 'Delhi', name: 'Tux', speakingExperience: 'Speaker at the high conference', organisation: 'ORG 2', longBiography: '', photo: { 'iconImageUrl': '' } }] }
],
sessionsByTracks: computed('sessions.[]', function() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let this computed function depend on sessions.[] and selectedTrackId

You don't have to declare selectedTrackId anywhere. it is by default null. If it is null consider it to be all tracks. Else filter by that track id

@@ -1 +1,4 @@
{{outlet}}
<h2 class="ui header">Sessions</h2>
{{public/session-filter filterSession=(action 'filterSession') tracks=tracks}}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change to

{{public/session-filter selectedTrackId=selectedTrackId tracks=tracks}}

Note that you're passing in the selectedTrackId variable


actions: {
filter(element, event) {
this.set('selectedTrack', event.target.id);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change to

this.set('selectedTrackId', trackId);

selectedTrack: 'all',

actions: {
filter(element, event) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change to

filter(trackId = null) {

If no trackId is passed it is considered as null

@@ -0,0 +1,10 @@
<div class="ui secondary menu">
<a href="#" class="item {{if (eq selectedTrack 'all') 'active'}}" id="all" onclick={{action 'filter' 'All'}}>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change to

<a href="#" class="item {{unless selectedTrackId 'active'}}" {{action 'filter'}}>

Here if selectedTrackId is null it is considered to be all tracks.
And for action you don't have to specify onclick=
And note that we're not passing any argument to the action. hence trackId in the action will be null.

All
</a>
{{#each tracks as |track|}}
<a href="#" class="item {{if (eq selectedTrack (underscore track)) 'active'}}" id="{{underscore track}}" onclick={{action 'filter' track}}>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be changed to

<a href="#" class="item {{if (eq selectedTrackId track.id) 'active'}}" {{action 'filter' track.id}}>
{{track.name}}
</a>

@niranjan94
Copy link
Member

niranjan94 commented May 23, 2017

Now from anywhere in that page, all I have to do is change selectedTrackId and everything related to it will change.

@dilpreetsio
Copy link
Member Author

@niranjan94 Thank you for the detailed review and proposing a better solution. I have made the required changes. Please review it.

Copy link
Member

@niranjan94 niranjan94 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}
}),
tracks: computed('sessions.[]', function() {
var allTracks = mapValues(keyBy(orderBy(this.get('sessions'), 'startAt'), 'track.id'), function(v) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be better written as

chain(this.get('sessions'))
    .map('track')
    .uniqBy('id')
    .orderBy('name')
    .value()

chain is also a lodash method.

That way we don't have to order all the sessions before getting the tracks and we get all contents of the track object.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The output will be an array of track objects.

{ shortAbstract: 'Welcome to open source', id: '2', title: 'Introduction to Open source', startAt: moment(new Date().setMinutes(10)).format('h:mm a / DD-MM-YYYY'), track: { color: 'red', fontColor: 'white', id: 2, name: 'Track 2' }, microlocation: { id: 3, name: 'Room 5' }, speakers: [{ shortBiography: '', id: 0, city: 'Delhi', name: 'Tux', speakingExperience: 'Speaker at the high conference', organisation: 'ORG 2', longBiography: '', photo: { 'iconImageUrl': '' } }] }
],
sessionsByTracks: computed('sessions.[]', 'selectedTrackId', function() {
var allSessions = mapValues(groupBy(orderBy(this.get('sessions'), 'startAt'), 'track.id'), function(v) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be written as

Unfiltered:

chain(this.get('sessions'))
    .orderBy(['track.name', 'startAt'])
    .groupBy('track.name')
    .value();

Filtered:

chain(this.get('sessions'))
    .filter(['track.id', this.get('selectedTrackId')])
    .orderBy(['track.name', 'startAt'])
    .groupBy('track.name')
    .value();

Ordering and grouping are the operations that usually take up more time. So all filtering should be done before them so that they get as less data as possible.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will give an output like

{
    'Track name': []
}

Where [] is an array of sessions. You can use each-in in the template to loop through this and get both track name and the sessions.

const { Controller, computed } = Ember;

export default Controller.extend({
sessions: [{ shortAbstract: 'An introduction to the event', id: '1', title: 'Welcome to FOSSASIA', startAt: moment(new Date()).format('h:mm a / DD-MM-YYYY'), track: { color: 'green', fontColor: 'green', id: 1, name: 'Track 1' }, microlocation: { id: 2, name: 'Room 1' }, speakers: [{ shortBiography: 'Works for ORG 1', id: 0, city: 'Delhi', name: 'Arnold Singh', speakingExperience: 'GSOC 2015', organisation: 'ORG 1', longBiography: '', photo: { 'iconImageUrl': '' } }] },
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again ... like I said startAt and endAt will NOT be a string. It will be a date object. You need to use ember-moment template helpers to display it how you like.

@dilpreetsio
Copy link
Member Author

@niranjan94 Please review.

var allSessions = chain(this.get('sessions'))
.orderBy(['startAt', 'startAt'])
.groupBy('track.id')
.mapValues(function(v) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this needed ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you're anyway only using track name in the view.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a groupBy track.name should give you all the info you need+sessions

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm using the id to map the tracks and not the names anymore. That's the reason we are using this function to map the track id with the sessions.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're performing unnecessary operations here. With what I suggested here > #68 (comment) you can perform one operation less and yet achieve the same results.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For UI grouping, track name shouldn't be an issue.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We pass tracks to the filter component which stores selectedTrackId the id of the selected track. We need to update the session-filter according to this information, therefore I have used track id and not track name to populate and bind the sessions under a track id to the id in session-filter.

Now whenever selectedTrackId changes it filters the sessions of session-list according to the trackid.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@geekyd that's exactly what is being done here too #68 (comment) but with one less operation.

With one or two sessions, a single less operation isn't gonna matter. But with hundreds of session, a single operation, especially ones like mapValues matter a lot

],
sessionsByTracks: computed('sessions.[]', 'selectedTrackId', function() {
var allSessions = chain(this.get('sessions'))
.orderBy(['startAt', 'startAt'])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicate entry

@dilpreetsio
Copy link
Member Author

@niranjan94 Removed mapValues please check.

@@ -0,0 +1,8 @@
{{#each-in sessions as |id trackSession|}}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

call id as trackName

@@ -0,0 +1,8 @@
{{#each-in sessions as |id trackSession|}}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now. When it is filtered by a track, what is going to come here is an array and not an object. Please handle that too.

TL,DR;
The session-list component should be able to render both an array of sessions and an object (when it is grouped by track)

You can use the is-array helper available

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no need to handle this as output of both filter and unfiltered data is always going to be an object and not an array.
The format:
{ track1: Array, track2: Array ...}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Crap. Did not notice that groupBy in the filtered output. We should remove that. No point grouping by track when we are filtering by track.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And one more reason to have array support. If at in future we implement API calls for session filtering, we'll be getting sessions as array in the response.

@dilpreetsio
Copy link
Member Author

@niranjan94 Made the changes. Please review.

@niranjan94 niranjan94 temporarily deployed to eventyay-frontend-pr-68 May 23, 2017 18:22 Inactive
Copy link
Member

@niranjan94 niranjan94 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

{{/each}}
{{else}}
{{#each-in sessions as |track trackSession|}}
<h3 class="ui header" id="{{underscore track}}">{{track}}</h3>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ID can be removed

@@ -0,0 +1,15 @@
<div class="ui session-container">
{{#if (is-array sessions)}}
<h3 class="ui header" id="{{underscore track}}">{{track}}</h3>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ID can be removed

const { Component } = Ember;

export default Component.extend({
classNames: ['ui', 'accordion', 'segment']
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The accordion class can be removed here. This will fix the extra space on top.

screen shot 2017-05-23 at 11 59 49 pm

<div class="title">
<div class="ui">
<h4 class="ui header">{{session.title}}</h4>
<div class="ui row">Talk</div>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be the session type.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And add this as a subheader to your header for a better UI

<h4 class="ui header">
    {{session.title}}
    <div class="sub header">
        {{session.sessionType.name}}
    </div>
</h4>

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, increase from h4 to h3

</div>
<br>
<div class="ui grid">
<div class="column twelve wide">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let the speaker image, microlocation name and start time be in one row and the session shortAbstract in a different row. That would fix the sessionAbstract speaker image spacing issue

screen shot 2017-05-24 at 12 06 41 am

<div class="title">
<div class="ui">
<h4 class="ui header">{{session.title}}</h4>
<div class="ui row">Talk</div>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, increase from h4 to h3

@dilpreetsio
Copy link
Member Author

@niranjan94 Please review.

</div>
</div>
<div class="ui row">
<div class="session-description">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be a column inside the row. So put this inside a div with class column

@dilpreetsio
Copy link
Member Author

@niranjan94 Made the changes. Please review.

@niranjan94 niranjan94 temporarily deployed to eventyay-frontend-pr-68 May 24, 2017 04:50 Inactive
<div class="">{{moment-format session.startAt 'hh:mm a / DD-MM-YYYY'}} <i class="wait icon"></i></div>
</div>
</div>
<div class="ui row">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@geekyd

Looks like the row is out side the grid ?

Should be something like this.

<div class="ui grid">
    <div class="row">
        <!-- speaker pics and microlocation/time -->
    </div>
<div class="row">
    <div class="column">
        {{session.shortAbstract}}
    </div>
</div>

A row cannot exist outside a ui grid

@dilpreetsio
Copy link
Member Author

@niranjan94 Please review.

@niranjan94 niranjan94 merged commit b5f5a9e into fossasia:development May 24, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Implementing sessions layout for public events(UI)
3 participants