Implementing User-name Update Functionality

The Badgeyay  Ember JS frontend has many features like Login and Sign up features and Login with OAuth and the most important, the badge generation feature is also up and running. Now the next important thing from User perspective is that there should be a settings panel where user can see its account details like username, Email & password and he should be able to change them if he want to.

I have implemented the setting panel in Badgeyay where user can see his account details. In this blog, I will be discussing how I implemented Update Username functionality in my Pull Request so that the User can change his username at any point of time.

Let’s get started and understand it step by step.

Step 1:

Generate User account component with help of ember cli.

$ ember g component user-component/user-account

 

Step 2:

Make changes in Handlebar of User Account. We will be using semantic UI form for making the changes in Handlebars.

// user-account.hbs

<h2 class="ui dividing header">Account</h2>
<form class="ui form" {{action 'updateUserName' on="submit"}}>
    
class="ui field"> Username
class="ui fields">
class="ten wide field"> {{input type="text" id="profileName" name=profileName value=user.username}}
</div> </div>
class="ui field"> Email
class="ui fields">
class="ten wide disabled field"> {{input type="email" name=email value=user.email}}
</div> </div> <button type="submit" class="ui basic orange button" tabindex="0" >Save Changes</button> </form>

 

We have used action on submitting the Form for changing and updating the username in Database and Firebase.

Step 3:

We will now define the action in user component JS file. We will also add the validations in Form so that empty form cannot be submitted to the server.

import Component from '@ember/component';
export default Component.extend({
  init() {
    this._super(...arguments);
  },
  actions: {
    updateUserName() {
      let profileName = this.get('profileName');
      this.get('sendUserName')(profileName);
    }
  },
  didRender() {
    this.$('.ui.form')
      .form({
        inline : true,
        delay  : false,
        fields : {
          username: {
            identifier : 'profileName',
            rules      : [
              {
                type   : 'empty',
                prompt : 'Please enter a valid username'
              }
            ]
          }
        }
      });
}});

 

Step 4:

We will now configure the controller to customize the action that we have defined above.

…….
export default Controller.extend({
  routing : service('-routing'),
  notify  : service('notify'),
  uid     : '',
  actions : {
…………...
   updateUserName(profileName) {
      const _this = this;
      const user = this.get('store').peekAll('user');
      user.forEach(user_ => {
        _this.set('uid', user_.get('id'));
      });
      _this.get('user').save();
      _this.get('notify').success('Username Successfully Updated!');
    }
  }
});

 

Step 5:

We have configured the frontend for sending the details to backend. Now, we have to edit the endpoint so that if username is change in params, It should change the username and send the response with the updated username.

api/controllers/registerUser.py
…………...
   if 'username' in data.keys():
        user.username = data['username']
        update_firebase_username(user.id, user.username)
        user.save_to_db()

 

Now, I am done with doing all the changes in backend API and Frontend.

Step 6:

Now run the Frontend & Backend to see the implemented changes.

User Account Panel

Now, we are done with implementation of Update Username Functionality.

Resources:

  1. Ember Docs –  Link
  2. Badgeyay Repository – Link
  3. Issue Link – Link
  4. Pull Request Link – Link
  5. Semantic UI –  LInk
Continue ReadingImplementing User-name Update Functionality

Implementing Pagination for listing Badges

Badgeyay project is divided into two parts i.e front-end with Ember JS and back-end with REST-API programmed in Python.

Badgeyay comes with many features for customising the process of generation of Badges. Badgeyay also keeps record of all the badges generated by user and also gives option to directly download the previously generated badges.
All the badges appear on single page which creates problem when a user has generated lot of badges and all the badges listed on single page.

To resolve this issue and make Badgeyay more user friendly I have implemented pagination in listing badges so that if there are more number of badges, user can see the badges listed in multiple pages in my Pull Request.

To implement this, I have used actions and made the changes accordingly.

Let’s get started and understand it step by step.

Step 1:

We will use semantic icons in handlebars for changing pages.

Step 2:

I will add action for changing page to next and previous page.

// components/user-component/my-badges.js 

import Component from '@ember/component';
import Ember from 'ember';
const { inject } = Ember;
export default Component.extend({
  queryParams : ['page'],
  page        : 1,
  notify      : inject.service('notify'),
  actions     : {
    nextPage() {  // Action for Next Page
      let filter = {};
      if (this.page > 1) {
        filter.page = this.page + 1;
        this.get('store').query('my-badges', filter)
          .then(records => {
            if (records.length > 0) {
              this.set('my-badges', records);
              this.set('page', this.page + 1);
            } else {
              this.notify.error('No More Badges found');
            }
          })
          .catch(err => {
            this.get('notify').error('Please try again!');
          });
      } else {
        this.notify.error('No More Badges Found');
      }
    },
    prevPage() {  // Action for Previous Page
      let filter = {};
      if (this.page - 1 > 0) {
        filter.page = this.page - 1;
        this.get('store').query('my-badges', filter)
          .then(records => {
            this.set('my-badges', records);
            this.set('page', this.page - 1);
          })
          .catch(err => {
            this.get('notify').error('Please try again!');
          });
      } else {
        this.notify.error('No More Badges Found');
      }
    }
  }
});

 

Step 3:

Now, We have to make the query for all badges generated by a user on opening the my-badges route in Frontend.

import Route from '@ember/routing/route';

import Ember from 'ember';

const { set } = Ember;

export default Route.extend({
  beforeModel(transition) {
    this._super(...arguments);
  },

  model(params) {
    let filter = {};
    this.set('params', params);
    filter.state = 'all';
    filter.page = params.page;
    return this.get('store').query('my-badges', filter);
  }
});

 

I have implemented the pagination feature for listing all badges by the user.

 

Step 4:

Now run the server to see the implemented changes by following command.

My Badges Route with Pagination Feature:

Now we are done with implementing the pagination feature for listing all badges by the user.

Resources:

  1. Ember Docs –  Link
  2. Badgeyay Repository – Link
  3. Issue Link – Link
  4. Semantic UI –  LInk

 

Continue ReadingImplementing Pagination for listing Badges

Customizing Ember CLI Notify for Badgeyay

Badgeyay project is divided into two parts i.e front-end with Ember JS and back-end with REST-API programmed in Python.

Badgeyay comes with many features for customising the process of generation of Badges. It gives freedom to user to choose Input Badge data which is to be printed on the individual badges, choosing the badge size, applying custom background to the badges and then optional features of font customization helps to generate cool badges.You have to just click on create badges and the generated badge with download link appear at bottom of form. But a problem arises with the generated badges link that after logout/login or generation of new badges just after creating badges one time, the link of the previously created badges is still there which is a bit confusing, as user might think the previous link to be the new link and press on that in order to download and find the old badges downloaded.

To resolve this issue, I have used the power of Ember notify library and customized it to show the generated badges link and disappear after a specified time in my Pull Request and after that user can always see his previously generated badges in My Badges route.

Let’s get started and understand it.

  • Customizing Notify library and making the changes in the send Badge data function to show the generated badge link just after the completion of badge generation process.

import Controller from '@ember/controller';
import { inject as service } from '@ember/service';   

export default Controller.extend({
....
routing : service('-routing'),
notify : service('notify'), // importing Notify service
.....
sendBadge(badgeData) {
      const _this = this;
      let badgeRecord = _this.get('store').createRecord('badge', badgeData);
      badgeRecord.save()
        .then(record => {
          _this.set('badgeGenerated', true);
          _this.set('genBadge', record);
          var notify = _this.get('notify');
          var link   = record.download_link; // Assigning download link to a variable 
          var message = notify.success(  // Configuring the message of notify service
            { html:   // Adding the html in notify message
            '
Badge generated successfully.
'
+ '<p>Visit this<b>' + '<a href=' + link + '> Link </a></b> to download badge.</p>', closeAfter: 10000 }); // Specifying the time of closing the message }) .catch(err => { _this.get('notify').error('Unable to generate badge'); }); },

 

I have implemented the customized notify function to show the badge generation link for a specific time.

  • Now run the server to see the implemented changes by following command.

$ ember serve

 

  • Ember Notify service showing the generated Badges link:

Now, I am done with the implementation of customised notify function to show the badge generation link for a specific time of 10 seconds.

Resources:

  1. Ember Docs –  Link
  2. Ember Notify Docs – Link
Continue ReadingCustomizing Ember CLI Notify for Badgeyay

Implementing User Input guide and using Semantic-UI Tables

Badgeyay project is divided into two parts i.e front-end with Ember JS and back-end with REST-API programmed in Python.

Badgeyay comes with many features for customising the process of generation of Badges. It gives freedom to user to choose Input Badge data which is to be printed on the individual badges, choosing the badge size, applying custom background to the badges and then optional features of font customization helps to generate cool badges. If a helper is not there for the directions to use these features then these features may be difficult to use for a user.

To resolve this issue and make Badgeyay more user friendly I have implemented a User Guide to help user to go through the User Manual before generating Badges in my Pull Request.

To implement user guide, I have used Semantic UI tables to give examples for CSV format and used other components for Manual format.

Let’s get started and understand it step by step.

Step 1:

Create User Guide component with Ember CLI.

$ ember g  component  user-component/user-guide

 

Step 2:

Now, We will use Semantic UI while editing Handlebars.

class="user-guide">
class="ui center aligned huge header">User-Input Guide
class="ui center aligned small header"> Please check what is the "Correct Format"?
class="ui segments">
class="ui segment">
class="ui raised segment">
class="ui header"> class="file excel icon">
class="content"> CSV Format
</div> </div>
class="ui bulleted list">
class="item">The CSV must be uploaded with 5 columns of data.
class="item">Five comma (',') seperated values should be present in the CSV
class="item">See Example Below
<table class="ui celled structured table"> <thead> <tr> <th rowspan="2">First Name</th> <th rowspan="2">Last Name</th> <th rowspan="2">Position</th> <th rowspan="2">Organisation/Project</th> <th rowspan="2">Social Handle</th> </tr> </thead> <tbody> <tr> <td>Deepjyoti</td> <td>Mondal</td> <td>Mentor</td> <td>FOSSASIA</td> <td>@djmgit</td> </tr> <tr> <td>Yash</td> <td>Ladha</td> <td>Developer</td> <td>Badgeyay</td> <td>@yashladha</td> </tr> <tr> <td>Manish</td> <td>Devgan</td> <td>Developer</td> <td>Badgeyay</td> <td>@gabru-md</td> </tr> <tr> <td>Parth</td> <td>Shandilya</td> <td>Developer</td> <td>Badgeyay</td> <td>@ParthS007</td> </tr> </tbody> </table> </div> </div>
class="ui segment">
class="ui raised segment">
class="ui header"> class="edit icon">
class="content"> Manual Data Format
</div> </div>
class="ui bulleted list">
class="item">Format for Manual data is same as CSV's data
class="item">Five comma (',') seperated values on each line is the correct format
class="item">See Example below
class="ui segment">

Deepjyoti,Mondal,Mentor,FOSSASIA,@djmgit

Yash,Ladha,Developer,FOSSASIA,@yashladha

Manish,Devgan,Developer,FOSSASIA,@gabru-md

Parth,Shandilya,Developer,FOSSASIA,@ParthS007

</div> </div> </div> </div>

 

Step 3:

Link it with Create Badges as a tooltip in the first accordian of create badges route.

<a class="ui icon orange button guide" href="{{href-to 'user-guide'}}" data-tooltip="User Input Guide" data-position="right center"><i class="info icon"></i></a>

 

I have implemented the user guide for the user to go through the User Manual before generating Badges.

Step 4::

Now run the server to see the implemented changes by following command.

$ ember serve

 

User Guide Component

Tooltip present in the create badges form.

Now, we are done implementing a User Guide to help user to go through the User Manual before generating Badges.

Resources:

  1. Ember Docs –  Link
  2. Badgeyay Repository – Link
  3. Issue Link – Link
  4. Semantic UI –  LInk
Continue ReadingImplementing User Input guide and using Semantic-UI Tables

Implement Table Sorting In Badgeyay

In this blog post I am going to explain about implementation of inplace table sorting in badgeyay. This is not about just adding the sortable class as described in the semantic docs, but the data inside the table has different characteristics and needs to be sorted in a different manner. Not like the traditional way of comparing strings as it will not be suitable for dates. For creating a custom comparison function for sorting, either we can implement a custom comparator using JQuery or we can use the data values for comparison. The latter option is more preferable as it can be extended  to different columns in the table.

Procedure

  1. Adding the sortable class in the table, which needs to be sorted.
<table class=“ui sortable table”>

  . . .

</table>

 

  1. We need to enable a javascript function when DOM completely gets loaded.
<script type=“text/javascript”>
 $(‘table’).tablesort();
</script>

 

  1. After this we need to create a template helper to return us the time stamp from the UTC formatted DateTime string. The value that will be returned by the helper will be used as the data value for the column entries.
import { helper } from ‘@ember/component/helper’;

export function extractTimeStamp(date) {
return Math.floor((new Date(date)).getTime() / 100);
}

export default helper(extractTimeStamp);

 

  1. The value that will be returned by the helper will be used as data value for comparison by table sorter.
<td data-sort-value={{extract-time-stamp user.created_at}}>{{sanitizeDate user.created_at}}</td>

 

  1. Now we need that certain columns do not sort, as there is no need. Such columns are photoURL, actions etc. These columns should be ignored by the sorter for sorting, so we will add a class to avoid sorting of these columns.
<th class=“no-sort”>User Photo</th>

Resources

  • Semantic UI table class – Link
  • Data sorting in the table API – Link
  • Pull Request for the same – Link
  • Template helper guide ember – Link
Continue ReadingImplement Table Sorting In Badgeyay

Implementing Access Codes in Open Event Frontend

The Open-Event-Frontend allows the event organiser to create access codes for his or her event.  Access codes can be used to password protect hidden tickets reserved for sponsors, members of the press and media. This blog post explains how we have integrated access codes creation in the frontend utilising the various features of Ember JS and Semantic UI.

Create Access code component

We will be creating a separate component for creating access code. To create it we will use the following command:

ember g component forms/events/view/create-access-code

This will create the following files:

  1. components/forms/events/view/create-access-code.js
  2. templates/components/forms/events/view/create-access-code.hbs
  3. tests/integration/components/forms/events/view/create-access-code-test.js

Create-access-code.hbs

This file includes the handlebar syntax to design the front end of the access code component. The whole template is nested inside the Semantic UI’s form class. Some of the helpers used are as follows:

  • Ember Input Helper: It has been used extensively throughout the template in order to take input from the event organizer. For e.g.:
{{input type=‘text’ name=‘access_code’ value=data.code}}
  • Semantic Radio Button: The semantic radio button has been used in order to allow the organizer to select the state of the access-code. He/She can choose if the access-code is active or inactive.

<div class="grouped inline fields">
    <label class="required">{{t 'Status'}}</label>
    <div class="field">
      {{ui-radio current=data.isActive name='status' label='Active' value='true' onChange=(action (mut data.isActive))}}
    </div>
    <div class="field">
      {{ui-radio name='status' label='Inactive' value='false' current=data.isActive onChange=(action (mut data.isActive))}}
    </div>
  </div>
  • Date Time Picker: The organizer can set the validity of the access code as well. We have used date-picker and time-picker components which were already created in the project. They have been used in the following way:

<div class="fields">
        <div class="wide field {{if device.isMobile 'sixteen' 'five'}}">
          <label>{{t 'Valid from'}}</label>
          {{widgets/forms/date-picker id='start_date' value=data.validFromDate rangePosition='start'}}
          <div class="ui hidden divider"></div>
          {{widgets/forms/time-picker id='start_time' value=data.validFromTime rangePosition='start'}}
        </div>
        <div class="wide field {{if device.isMobile 'sixteen' 'five'}}">
          <label>{{t 'Expires on'}}</label>
          {{widgets/forms/date-picker id='end_date' value=data.validTillDate rangePosition='end'}}
          <div class="ui hidden divider"></div>
          {{widgets/forms/time-picker id='end_time' value=data.validTillTime rangePosition='end'}}
        </div>
      </div>

Create-access-code.js

We use this file as the core of the component and handle the following use cases:

  1. Validation of the input. We show warning if something is wrong.
  2. Actions used by the various elements of the templates.
  3. Providing the link for the access-code.
  4. Saving the access-code.

accessCode : '',
  accessUrl  : computed('data.code', function() {
    const params = this.get('router._router.currentState.routerJsState.params');
    this.set('data.accessUrl', location.origin + this.get('router').urlFor('public', params['events.view'].event_id, { queryParams: { access_code: this.get('data.code') } })) ;
    return this.get('data.accessUrl');
  }),
  actions: {
    toggleAllSelection(allTicketTypesChecked) {
      this.set('allTicketTypesChecked', allTicketTypesChecked);
      if (allTicketTypesChecked) {
        this.set('data.tickets', this.get('data.event.tickets').slice());
      }
    },
    updateTicketSelections(newSelection) {
      if (newSelection.length === this.get('data.event.tickets').length) {
        this.set('allTicketTypesChecked', true);
      } else {
        this.set('allTicketTypesChecked', false);
      }
    },
    submit(data) {
      this.onValid(() => {
        data.save()
          .then(() => {
            this.get('notify').success(this.get('l10n').t('Access code has been successfully created.'));
            this.get('router').transitionTo('events.view.tickets.access-codes');
          })
          .catch(() => {
            this.get('notify').error(this.get('l10n').t('An unexpected error has occurred. Access code cannot be created.'));
          });
      });
    }
  }

Create-access-code-test.js

We can specify the tests in order to test the compatibility of the component here. For now, we will just write a simple test which checks if the component is rendered or not.

import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';

module('Unit | Controller | events/view/tickets/access codes/create', function(hooks) {
  setupTest(hooks);


  test('it exists', function(assert) {
    let controller = this.owner.lookup('controller:events/view/tickets/access-codes/create');
    assert.ok(controller);
  });
});

Now that we are done, setting up our component, we just need to add it in our application. We can achieve that using the following:

{{forms/events/view/create-access-code data=model}}

The model passed to the component is fetched from the create-access-code.js file.

References

Continue ReadingImplementing Access Codes in Open Event Frontend

Filtering and Session API Integration on Admin User Route Open Event Frontend

This blog article will illustrate how the Session API has been integrated into the admin users route  Open Event Frontend, as well as how it’s now possible to filter active and deleted users using the new filters implemented.

To make the sessions buttons on the users table functional a new sub route is added to the app’s user route as follows:

this.route('users', function() {
     this.route('view', { path: '/:user_id' }, function() {
       this.route('sessions', function() {
         this.route('list', { path: '/:session_status' });
       });
     });
     this.route('list', { path: '/:users_status' });

The newly added route further contains a dynamic sub route called list. This nested route fulfills the requirement of filtering the various sessions of a given user according to their states. Interestingly, the routes admin/users/view and admin/users/list are both dynamic and expect a parameter after /users/ hence, the app cannot distinguish between them on it’s own, thus explicit handling of the dynamic parameter of the routes was implemented, differentiating them on the basis of the route’s state as follows:

beforeModel(transition) {
this._super(...arguments);
const userState = transition.params[transition.targetName].users_status;
if (!['all', 'deleted', 'active'].includes(userState)) {
this.replaceWith('admin.users.view', userState);
}
}

Thus if the dynamic portion of the route doesn’t contain the parameters all, deleted or active, then it must be referring to a user’s sessions and the route needs to be replaced with the desired sessions route accordingly. Also, the template admin/users.hbs needs to be changed to display the navigation bar  only when required. It is efficiently handled by an IF condition as follows:

{{#if (and (not-includes session.currentRouteName ‘admin.users.user’) (not-includes session.currentRouteName ‘admin.users.view.sessions.list’))}}

The server is queried to fetch the sessions of a given user by making use of the hasMany relationship a user has with his sessions. They are loaded in the route admin/users/view/sessions/list.js

model() {
const userDetails = this.modelFor('admin.users.view');
return this.store.findRecord('user', userDetails.id, {
include: 'sessions'
});

After fetching the the sessions from the server, the existing session-card  component is reused in the route’s template to display the sessions.

{{#if model.sessions}}
{{#each model.sessions as |session|}}
{{session-card session=session}}

{{/each}}
{{else}}

{{t ‘No session proposals found for the events’}}

{{/if}}
</div>
</div>

Also, in the admin/users route the filtering of deleted users was not functional. Thus  the property deleted-at of the users model which stores the timestamp of the deletion of a user was utilised. deleted-at is null for a user which is active. Hence the active and deleted users can be filtered as :

if (params.users_status === 'active') {
filterOptions = [
{
name : 'deleted-at',
op : 'eq',
val  : null
}
];
} else if (params.users_status === 'deleted') {
filterOptions = [
{
name : 'deleted-at',
op : 'ne',
val  : null
}
];
}
return this.get('store').query('user', {
get_trashed  : true,
filter       : filterOptions,
'page[size]' : 10
});

It’s important to pass the get_trashed parameter as true in the query as the the deleted user records are actually soft deleted records and will be fetched only when explicitly queried for.

Resources

Continue ReadingFiltering and Session API Integration on Admin User Route Open Event Frontend

Implementing Event Image Size and Speaker Image Size APIs in Open Event Frontend

This blog article will illustrate how the Image Sizes APIs concerning event and speaker images are integrated in  Open Event Frontend, which allows for dynamic configurations of storing speaker and event images. The primary end points of Open Event API with which we are concerned with for fetching the event and speaker image sizes are

GET /v1/event-image-sizes

And

GET /v1/speaker-image-sizes

These endpoints are accessible only to a user with has administrator privileges as the customisation of image sizes is possible only on the admin dashboard. The image sizes are independent in regards to relationships and don’t have any related fields.

The model for the admin image settings route is defined as follows:

export default ModelBase.extend(CustomPrimaryKeyMixin, {
 thumbnailSizeQuality     : attr('number'),
 type                     : attr('string'),
 smallSizeWidthHeight     : attr('number'),
 smallSizeQuality         : attr('number'),
 iconSizeQuality          : attr('number'),
 iconSizeWidthHeight      : attr('number'),
 thumbnailSizeWidthHeight : attr('number')
});

The form which allows user to select image sizes, is in a separate component, and initially both the speaker and event image sizes are passed onto the component as a part of the entire model, so they can be separated later as per the requirement.

{{forms/admin/settings/images-form image=model save=’saveImages’ isLoading=isLoading}}

Most of the fields specify the units in which the numerical input concerning the image dimensions will be interpreted by the server and standard min and max validations are applied to the fields to ensure genuine and legitimate values can pass through the frontend.

<h3 class=”ui header”>{{t ‘Large Size’}}</h3>


{{input type=’number’ name=’large_width’ value=image.eventImageSize.fullWidth min=1}}

{{input type=’number’ name=’large_height’ value=image.eventImageSize.fullHeight min=1}}

{{input type=’number’ name=’large_quality’ value=image.eventImageSize.fullQuality min=1}}

</div>

{{ui-checkbox label=(t ‘Standard aspect ratio is 13:5. Tick to maintain aspect ratio.’) class=’checkbox’ name=’large_ratio’ checked=image.eventImageSize.fullAspect onChange=(action (mut image.eventImageSize.fullAspect))}}

{{t ‘Standard Size of the available area is 1300px X 500px’}}
<p>{{t ‘Found in :’}}</p>

{{t ‘Background Header Image in Public Event Page’}}

</div>

Furthermore, to ensure a user does not accidentally change the values inside the form, an action is triggered while transitioning away from the route which rollbacks any unsaved changes to the image sizes.

actions: {
willTransition() {
this.get('controller.model').forEach(image => {
image.rollbackAttributes();
});
}
}

Resources

Continue ReadingImplementing Event Image Size and Speaker Image Size APIs in Open Event Frontend

Creating the View Route for Users in Open Event Frontend

This blog article will describe how the users view user route is created in Open Event Frontend, which allows the admin to view a user whenever view action button in the user table is clicked.

The primary end point of Open Event API with which we are concerned with for fetching the the users details is

GET /v1/users/{user_id}

The complete user information on the view route is displayed, which includes the name, email, details about the user. All these are the attributes of the model user. Thus the model for the route is defined as follows:

model(params) {
return this.store.findRecord('user', params.session_id);

The view route is located at app/admin/users/<user_id> and the parent route, app/users has another sub route within it called list. The list route shows all, active, deleted users. This list has a column of action buttons.

This list can only be accessed by the admin. Whenever the view button in the Actions column is clicked the admin gets redirected to the view users route.

actions: {
    moveToUserDetails(id) {
      this.transitionToRoute('admin.users.view', id);
    }
}

The user profile form is:

{{widgets/forms/image-upload
imageUrl=user.avatarUrl
needsCropper=true
label=(t ‘User Image’)
id=’user_image’
icon=’photo’
hint=(t ‘Select User Image’)
maxSizeInKb=10000
aspectRatio=(array 1 1)
helpText=(t ‘We recommend using at least a 1000x1000px (1:1 ratio) image’)}}


{{input type=’text’ id=’name’ value=user.firstName}}

{{input type=’text’ id=’last_name’ value=user.lastName}}

{{widgets/forms/rich-text-editor id=’details’ value=user.details}}

The view route shows the following information about the user: Name, Family name, Email, Image of the user, Details of the user. Thus the admin can view all the users registered in the application.

Resources

Continue ReadingCreating the View Route for Users in Open Event Frontend

Adding Sessions and Events Statistics in the Admin Dashboard in Open Event Frontend

This blog article will illustrate how the admin statistics API for events and sessions is integrated and how the values of different types of sessions and events is added to the admin dashboard in   Open Event Frontend.

The primary end point of Open Event API with which we are concerned with for fetching the statistics are

GET /v1/admin/statistics/events

GET /v1/admin/statistics/events

import Route from '@ember/routing/route';

export default Route.extend({
 async model() {
   return {
     events: await this.get('store').queryRecord('admin-statistics-event', {
       filter: {
         name : 'id',
         op   : 'eq',
         val  : 1
       }
     })
sessions: await this.get('store').queryRecord('admin-statistics-session', {
       filter: {
         name : 'id',
         op   : 'eq',
         val  : 1
       }
     })
   };
 }
});

The route file helps to fetch the total count of each type of session and event through the queries written in the code. queryRecord is used instead of query because a single record is expected to be returned by the API. The view route is /admin.

The model needs to extend the base model class and all the attributes of the model will be number since the all the data obtained via these models from the API will be numerical statistics.

For Events:

import attr from 'ember-data/attr';
import ModelBase from 'open-event-frontend/models/base';export default ModelBase.extend({
draft     : attr('number'),
published : attr('number'),
past      : attr('number')
});

For Sessions:

import attr from 'ember-data/attr';
import ModelBase from 'open-event-frontend/models/base';export default ModelBase.extend({
confirmed : attr('number'),
accepted  : attr('number'),
submitted : attr('number'),
draft     : attr('number'),
rejected  : attr('number'),
pending   : attr('number')
});

Once we retrieve the values of the attributes from the queries written in the route file we display the values of pending, rejected, accepted sessions and published, draft, past events.

class="label"> {{t 'Accepted'}}
class="value">
class="ui teal label"> {{model.sessions.accepted}}
</div> </div>
class="ui small statistic">
class="label"> {{t 'Draft'}}
class="value">
class="ui yellow label"> {{model.sessions.pending}}
</div> </div>
class="ui small statistic">
class="label"> {{t 'Rejected'}}
class="value">
class="ui red label"> {{model.sessions.rejected}}

Resources

Continue ReadingAdding Sessions and Events Statistics in the Admin Dashboard in Open Event Frontend