Display image responses in SUSI.AI Android app

SUSI.AI Android app has many response functionalities ranging from giving simple ANSWER type responses to complex TABLE and MAP type responses. Although, even after all these useful response types there were some missing action types all related to media. SUSI.AI app was not capable of playing any kind of image responses.So, to do this the links received in the response were used to fetch the corresponding image stored in the link. Since, the app now has two build flavors corresponding to the F-Droid version and PlayStore version respectively it had to be considered that while adding the feature to display images any proprietary software was not included with the F-Droid version. The JSON response from the server whenever a query for was asked gave the link to the image.  For eg : on querying : “Image of cat “ the server gave the response as : Actions": [        {          "language": "en",          "type": "answer",          "expression": "https://pixabay.com/get/e830b1072ef5023ed1584d05fb1d4790e076e7d610ac104496f0c77ea0e9bcbf_640.jpg"        } So in the android app just like the usual answer type response a message was displayed with the link to the image present in the message. Catching IMAGE response : The image responses are of the type “answer” as seen in the server response above. So we a method had to be devised so that the responses which display the images are caught and displayed. In the file ChatFeedRecyclerAdapter.java a separate code to detect the IMAGE response was added as : private static final int IMAGE = 17; Next we must specify that what type of view that is to be used whenever an IMAGE response is encountered by the app. Since the action type is “answer” a specification was required to choose the type of the viewholder. Since the images are only displayed through the pixabay the URL of the images end with either “.jpg” or “.png”. So in the expression of the response if we check that it is a link and also it ends with either “.jpg” or “.png” it will be certain that the response given from the server is an image. The code to identify the view type : @Override public int getItemViewType(int position) {   ChatMessage item = getItem(position);   if (item.getId() == -404) return DOTS;   else if (item.getId() == -405) return NULL_HOLDER;   else if (item.isDate()) return DATE_VIEW;   else if (item.getContent().endsWith(".jpg") || item.getContent().endsWith(".png"))       return IMAGE; Inflating the layout of type IMAGE Now after determining that the response will be an image we have to inflate the layout of the viewholder to support images in the onCreateViewHolder() method . The layout  of the image response was inflated as follows : case IMAGE:   view = inflater.inflate(R.layout.image_holder, viewGroup, false);   return new ImageViewHolder(view, clickListener); Here ImageViewHolder is the view holder that is used for displaying the images , we will discuss it later in the post. Also now in the onBindViewHolder() method of the ChatFeedRecyclerAdapter.java file we have to specify the instance of the view holder if it was to support the image response. It was done as follows : else if (holder instanceof…

Continue ReadingDisplay image responses in SUSI.AI Android app

Adding Filters for Lists of Skills on the SUSI.AI Server

In this blog post, we will learn how to add filters to the API responsible for fetching the list of skills i.e. the endpoint - https://api.susi.ai/cms/getSkillList.json. The purpose of adding filters is to return a list of skills based on some parameters associated with the skill, that would be required to allow the user to get the desired response that s/he may be using to display it on the UI. Overview of the API API to fetch the list of skills - URL -  https://api.susi.ai/cms/getSkillList.json It takes 5 optional parameters - model - It is the name of the model that user is requesting group - It is the name of the group that user is requesting language - It is the name of the language that user is requesting skill - It is the name of the skill that user is requesting applyFilter - It has true/false values, depending whether filtering is required If the request URL contains the parameter applyFilter as true, in that case the other 2 compulsory parameters are - filter_name - ascending/descending, depending upon the type of sorting the user wants filter_type - lexicographical, rating, etc based on what basis the filtering is going to happen So, we will now look into adding a new filter_type to the API. Detailed explanation of the implementation We can add filters based on the key values of the Metadata object of individual skills. The Metadata object for each skill is similar to the following object - { "model": "general", "group": "Knowledge", "language": "en", "developer_privacy_policy": null, "descriptions": "A skill that returns the anagrams for a word", "image": "images/anagrams.jpg", "author": "vivek iyer", "author_url": "https://github.com/Remorax", "author_email": null, "skill_name": "Anagrams", "protected": false, "terms_of_use": null, "dynamic_content": true, "examples": ["Anagram for best"], "skill_rating": { "negative": "0", "positive": "0", "stars": { "one_star": 0, "four_star": 0, "five_star": 0, "total_star": 0, "three_star": 0, "avg_star": 0, "two_star": 0 }, "feedback_count": 0 }, "creationTime": "2017-12-17T14:32:15Z", "lastAccessTime": "2018-06-19T17:50:01Z", "lastModifiedTime": "2017-12-17T14:32:15Z" }   We will now add provision for URL parameter, filter_type=feedback in the API, which will filter the results based on the feedback_count key, which tells the number of feedback/comments a skill has received. In the serviceImpl method of the ListSkillService class, we can see a code snippet that handles the filtering part, It checks the filter_type parameter received in the URL on if-else block. The code snippet looks like this - if (filter_type.equals("date")) { . . } else if (filter_type.equals("lexicographical")) { . . } else if (filter_type.equals("rating")) { . . }   Similarly, we will need to add an else if condition with feedback_type=feedback and write the code block inside it. Here is the code for it, which is explained in detail. . . else if (filter_type.equals("feedback")) { if (filter_name.equals("ascending")) { Collections.sort(jsonValues, new Comparator<JSONObject>() { @Override public int compare(JSONObject a, JSONObject b) { Integer valA; Integer valB; int result=0; try { valA = a.getJSONObject("skill_rating").getInt("feedback_count"); valB = b.getJSONObject("skill_rating").getInt("feedback_count"); result = Integer.compare(valA, valB); } catch (JSONException e) { e.printStackTrace(); } return result; } }); } else { Collections.sort(jsonValues, new Comparator<JSONObject>() {…

Continue ReadingAdding Filters for Lists of Skills on the SUSI.AI Server

Implementing the List View of the Skill Cards

In this blog post, we are going to understand the implementation of the UI for the SUSI.AI skill card that is displayed on various routes of the SUSI Skill CMS Web-App. Now, there are two types of views of the views for the skill cards - List view and Grid view. We will learn to implement the List View in this blog. Final UI of the Skill Card Going through the implementation The UI has multiple components - The image thumbnail. The title and author section, Below that we have examples, ratings and the description section. Fetching the data The Skill Metadata for each skill is passed as props from the parent of the component, where this UI is implemented. This data object contains the various data points that are needed to display the UI. The key values used are - skill_name - Used in the Title of the Skill Card image - Used to display the thumbnail image of the skill model - used to create the link to the Skill Details page group - used to create the link to the Skill Details page language - used to create the link to the Skill Details page skill_tag - used to create the link to the Skill Details page examples - used to display the examples card. author - used to display the Author name skill_rating - Used to display the stars and the total number of ratings of the skill The following image shows the various areas, where the data is being used. Parsing the data and creating JSX Below is the code used to parse the data and achieving the UI, followed by the explanation. ….. loadSkillCards = () => { let cards = []; Object.keys(this.state.skills).forEach(el => { let skill = this.state.skills[el]; let skill_name = 'Name not available', examples = [], image = '', description = 'No description available', author_name = 'Author', average_rating = 0, total_rating = 0; if (skill.skill_name) skill_name = skill.skill_name.charAt(0).toUpperCase() + skill_name.slice(1); …. // Similarly parse, image, descriptions, author …. if (skill.examples) examples = skill.examples.slice(0, 2); // Select max 2 examples if (skill.skill_rating) { average_rating = parseFloat(skill.skill_rating.stars.avg_star); total_rating = parseInt(skill.skill_rating.stars.total_star, 10); } cards.push( <div style={styles.skillCard} key={el}> <div style={styles.imageContainer}> // Display the image, else default avatar compoennt CircleImage </div> <div style={styles.content}> <div style={styles.header}> // Add Link to the skill title <div style={styles.title}><span>{skill_name}</span></div> <div style={styles.authorName}><span>{author_name}</span></div> </div> <div style={styles.details}> <div style={styles.exampleSection}> {examples.map((eg, index) => { return ( <div key={index} style={styles.example}>&quot;{eg}&quot;</div>); })} </div> <div style={styles.textData}> <div style={styles.row}> <div style={styles.rating}> // Show the 5-star rating section </div> </div> <div style={styles.row}> // Insert the skill description </div> //Close the div tags ); }); this.setState({cards}); }; render() { . . return (<div style={styles.gridList}>{skillDisplay}</div>); } . .   An array of skills is passed as props and set in the state of the component in the constructor lifecycle method. The loadSkillCards() function is called in the didComponentMount lifecycle method, which is responsible for creating the JSX for all the Skill Cards. In this function, the map property of array is used, to…

Continue ReadingImplementing the List View of the Skill Cards

Individual skill usage subsections in SUSI Skill CMS

In SUSI.AI Skills CMS several interactive skill related statistics are displayed on the skill page for each skill which includes user ratings, ratings over time, user feedback and skill usage data displayed interactively. The skill usage section is further subdivided to get more insight into how the skill has been used and from where. Therefore we have three subsections which display Time wise skill usage, device wise usage, and country wise usage. All this data can help evaluate which devices are mostly using the skill or data like in which country the skill is more popular than others. So in this post, we mainly discuss the UI of how these sections are implemented. Implementation Adding a Card component to the skill page component at the bottom of the skill page component. <SkillUsageCard skill_usage={this.state.skill_usage} device_usage_data={this.state.device_usage_data} countryWiseSkillUsage={this.state.countryWiseSkillUsage} />   In the render function of the newly made component, we import the Paper component from material-ui and render it at the top to contain the subsections to give it a card-like UI. <div> <Paper className="margin-b-md margin-t-md"> ... </Paper> </div>   Create div for the time wise skill usage. Calculate total skill usage for displaying the total skill usage count and also it helps to decide whether we need to render the section or not. So if the total skill usage by time count is greater than zero then render the line chart for visual analysis and display the total skill usage count too. let totalSkillUsage = 0; if (this.props.skill_usage) { // eslint-disable-next-line totalSkillUsage = this.props.skill_usage.reduce((totalCount, day) => { if (day) { return totalCount + day.count; } return totalCount; }, 0); } <div className="time-chart"> <div> <ResponsiveContainer width={this.state.width} height={300}> <LineChart ... > <XAxis dataKey="date" padding={{ right: 20 }} /> <YAxis allowDecimals={false} /> <Tooltip wrapperStyle={{ height: '60px' }} /> <Legend /> <Line ... /> </LineChart> </ResponsiveContainer> </div> </div> <div className="total-hits"> <div className="large-text">{totalSkillUsage}</div> Hits this week </div>   Create div for the Device wise usage. Conditionally render it in case the device wise data is available in the props. <div className="device-usage"> <div className="sub-title">Device wise Usage</div> {this.props.device_usage_data && this.props.device_usage_data.length ? ( <div className="pie-chart"> <ResponsiveContainer width={600} height={350}> <PieChart> <Pie ... > {this.props.device_usage_data.map((entry, index) => ( <Cell key={index} fill={entry.color} /> ))} </Pie> <Legend wrapperStyle={{ position: 'relative' }} /> </PieChart> </ResponsiveContainer> </div> </div>   Create a div for the country wise usage. We get the country wise usage data from the props and then we plug in the data in the geo chart component and also display the data as a table on the side. In case no data comes in or is unavailable we do not render the component at all. <div> {countryWiseSkillUsage && countryWiseSkillUsage.length ? ( <div className="country-usage-container"> <div className="country-usage-graph"> <GeoChart data={countryWiseSkillUsage} /> </div> <div className="country-usage-list"> <Table> ... </div> </div> ) : ( <div className="unavailable-message"> Country wise usage distribution is not available. </div> )} </div>   This is how the three subsection in the skill usage component are implemented Resources React Chartkick, Package which provides GeoChart component: https://github.com/ankane/react-chartkick  Sabastian Eschweiler, Getting started with material-UI for React, https://medium.com/codingthesmartway-com-blog/getting-started-with-material-ui-for-react-material-design-for-react-364b2688b555

Continue ReadingIndividual skill usage subsections in SUSI Skill CMS

Server Side Implement of Usage Analytics of a Skill in SUSI.AI

Which skills are being used most frequently in SUSI.AI? And which are rarely used? Such statistics are needed to give proper responses from the most used skills. So when the user sends a query to SUSI, it searches for the best-suited skill to respond to that query. The usage count of that skill is incremented accordingly with the date. Storage of Skill Usage Data Create a skillUsage.json file to store the stats and make a JSONTray object for that in DAO.java file. Modify the SusiArguement.java file to check which skill is being currently used for the response and write the skill usage stats to skillUsage.json.The function updateUsageData takes the skillPath in parameter and splits it from slash character. Thus the model name, group name, language name and skill name can be obtained. Then it searches for the date in the JSON file. If it exists then its count value is increased by 1, else a new object is inserted in the JSON file that contains the date and the corresponding usage count. public void updateUsageData(String skillPath) { Boolean dateExists = false; for (int i = 0; i<usageData.length(); i++) { JSONObject dayUsage = usageData.getJSONObject(i); if (dayUsage.get("date").equals(today)){ dayUsage.put("count", dayUsage.getInt("count")+1+""); usageData.put(i,dayUsage); dateExists = true; break; } } } API to access the Skill Usage Data Create GetSkillUsageService.java file to return the usage stats stored in skillUsage.json. It runs at the endponit - /cms/getSkillUage.json and mining role required to access this API is anonymous. It simply reads the data stored in skillUsage.json file and returns it. JsonTray skillRating = DAO.skillUsage; JSONObject languageName = groupName.getJSONObject(language_name); if (languageName.has(skill_name)) { JSONArray skillUsage = languageName.getJSONArray(skill_name); result.put("skill_name", skill_name); result.put("skill_usage", skillUsage); result.put("accepted", true); result.put("message", "Skill usage fetched"); return new ServiceResponse(result); } Add the API file to skillUsage.json services = new Class[]{ ... //Skill usage data GetSkillUsageService.class ... } So now we know which skills are being used at what rate and make the required changes like server scaling, adding more accuracy to the feature etc. We can expand these stats to country wise or device wise usage distribution. Resources Javatpoint (how to get current date and time)  - https://www.javatpoint.com/java-get-current-date  

Continue ReadingServer Side Implement of Usage Analytics of a Skill in SUSI.AI

Adding a feature to delete skills from skill page for admins

SUSI Skill CMS has evolved drastically over the past few months with not only the introduction of skill metrics, skill analytics and powerful sorting features and interactive skill view types we needed the SUSI admins to be able to delete skills directly from the skills page and hence the skill can be deleted without visiting the admin service and then locating the skill and deleting it. This feature can be useful when a skill live on the system needs to be removed instantaneously for any reason like the API used by the skill going down or if it is a redundant skill or anything else. This feature was much needed for the admins and thus it was implemented. About the API An API is developed at the server so from the client we call this API to fetch data from the server and plug this data into the chart we wish to render. Endpoint : /cms/deleteSkill.json?access_token={access_token}&model={model}&group={group}&language={language}&skill={skill}   Parameters : Model Group Skill Language Feedback Access token (taken from the session of the logged in user) Sample API call : /cms/deleteSkill.json?access_token=ANecfA1GjP4Bkgv4PwjL0OAW4kODzW&model=general&group=Knowledge&language=en&skill=whois Displaying a button with delete icon on skill page The option to delete skill should be available at the skill page for each skill so we add a button with a delete icon for this in the group of edit skills and skill version buttons, clicking over this button will open up a confirmation dialog with two actions notable the delete/confirm button which deletes the skills and the cancel button which can be useful in case the user changes their mind. On clicking the delete button the request to delete the skill is sent to the server and thus the skill is deleted. Import some required components import Dialog from 'material-ui/Dialog'; import FlatButton from 'material-ui/FlatButton'; import Cookies from 'universal-cookie'; import $ from 'jquery';   Adding some variables to the component state which will help us decide when the delete skill dialog is to be shown. this.state = { ... showDeleteDialog: false, ... }   Display the delete skill button only when the user is logged in user has admin rights. { cookies.get(showAdmin) ? ( ... ): '' }   Adding some JSX to the component’s render function which includes a div in the skill page section and the Dialog component for the delete skill and some actions which in our case is the the confirmation to delete skill and to cancel the skill deletion in case the user changes their mind. Also a tooltip is shown which appears on hovering over the delete skill button. <div className="skillDeleteBtn"> <FloatingActionButton onClick={this.handleDeleteToggle} data-tip="Delete Skill" backgroundColor={colors.header} > <DeleteBtn /> </FloatingActionButton> <ReactTooltip effect="solid" place="bottom" /> <Dialog title="Delete Skill" actions={deleteDialogActions} modal={false} open={this.state.showDeleteDialog} onRequestClose={this.handleDeleteToggle} > <div> Are you sure about deleting{' '} <span style={{ fontWeight: 'bold' }}> {this.state.skill_name} </span>? </div> </Dialog> </div>   Clicking the delete skill button will change the state variable which decides whether the dialog is to be shown or not. handleDeleteToggle = () => { this.setState({ showDeleteDialog: !this.state.showDeleteDialog, }); };   Adding submit and…

Continue ReadingAdding a feature to delete skills from skill page for admins

Adding a feature to report skills in the CMS

A lot of interesting features were introduced in the SUSI.AI Skills CMS over the past few months but it lacked the functionality for users to be able to report skills which they find inappropriate or for any other reason. So an API was developed at the server to flag the skills as inappropriate and thus using this API endpoint an option was added at the skill page for each skill to mark the skill as inappropriate or report it. This data could be useful by admins to re-review the skills and see if something is wrong with it and it things seem out of place the skill can be removed or can be disabled. About the API An API is developed at the server so from the client we call this API to fetch data from the server and plug this data into the chart we wish to render. Endpoint : /cms/reportSkill.json?model={model}&group={group}&skill={skill}&feedback={feedback message}&access_token={access_token}   Parameters : Model Group Skill Language Feedback Access token (taken from the session of the logged in user) Sample API call : /cms/reportSkill.json?model=general&group=Knowledge&skill=Anime Suggestions&feedback=Not good&access_token=6O7cqoMbzlClxPwg1is31Tz5pjVwo3 Displaying option to report on skill page The option to report skill should be available at the skill page for each skill so we add a field in the skill details section to the skill page component which will only be visible to the logged in users and on clicking over this field we display a dialog with a text field, the user can enter the message or the reason for reporting the skill and then clicking on the submit button when the user is done writing or click on the cancel button in case the user changes their mind to report the skill. Once the message is submitted we run a function by passing in the feedback message which in turn hits the corresponding endpoint and posts the data on the server. Import some required components import Dialog from 'material-ui/Dialog'; import FlatButton from 'material-ui/FlatButton'; import TextField from 'material-ui/TextField';   Adding some variables to the component state which will help us decide when the report dialog is to be shown and the feedback message as the user types and some other relevant data. this.state = { ... skillTag: '', showReportDialog: false, feedbackMessage: '' ... }   Display the report feature only when the user is logged in. { cookies.get('loggedIn') ? ( ... ): '' }   Adding some jsx to the component’s render function which includes a div in the skill details section and the Dialog component for the report message and confirmation and the dialog contains a text field to take report message and some actions which in our case is the send report action and the cancel report action. <tr> <td>Report: </td> <td> <div style={{ color: '#108ee9', cursor: 'pointer' }} onClick={this.handleReportToggle} > Flag as inappropriate </div> </td> <Dialog title="Flag as inappropriate" actions={reportDialogActions} modal={false} open={this.state.showReportDialog} onRequestClose={this.handleReportToggle} > <TextField hintText="Leave a feedback message" floatingLabelText="Feedback message" multiLine floatingLabelFocusStyle={{ color: 'rgb(66, 133, 244)', }} underlineFocusStyle={{ borderColor: 'rgb(66, 133, 244)', }} fullWidth onChange={(event, val) =>…

Continue ReadingAdding a feature to report skills in the CMS

Add Info on Skill Usage Distribution for all Skills by an Author in SUSI.AI

SUSI Skill CMS has a dashboard option available at the /dashboard route which displays several data for the logged in user as the skills created by the user and the ratings the user has provided to all the skills, since we have a skill usage section available on all skill pages which depicts the skill usage count for the past week in a line chart. Skill creators didn’t have a functionality to see the skill usage distribution on their skills which can provide some useful insight like how some of the skills they created are performing in comparison to the others so I developed a ‘My Analytics’ section in the dashboard page and displayed the skill usage distribution in the form of pie chart among the skills created by the logged in users. About the API An API is developed at the server so from the client we call this API to fetch data from the server and plug this data into the chart we wish to render. Endpoint : /cms/getSkillsByAuthor.json?author_email={email}   Parameters : Email ID which is taken from the cookies since it is stored there once the user logs in. Sample API call : /cms/getSkillsByAuthor.json?author_email=anshu.av97@gmail.com Fetching the data for the component We first create a separate My Analytics component and require it in the dashboard and make an AJAX call to the appropriate endpoint inside a loadSkillsUsage function which is called inside the componentDidMount hook after which the server returns raw data in the form of JSON. We then pass the response into a saveUsageData function to parse the data for our use and save it to the application state. loadSKillsUsage = () => { let url = urls.API_URL + `/cms/getSkillsByAuthor.json?author_email=${cookies.get('emailId')}`; let self = this; $.ajax({ url: url, dataType: 'jsonp', jsonp: 'callback', crossDomain: true, success: function(data) { self.saveUsageData(data.author_skills || []); ... }, error: function(err) { ... }, }); };   Set the application state with the received data which the pie chart component will use as it’s data source. saveUsageData = data => { const skillUsage = data.map(skill => { let dataObject = {}; dataObject.skill_name = skill.skill_name; dataObject.usage_count = skill.usage_count || 0; return dataObject; }); this.setState({ skillUsage }); }; Implementing the UI We create a separate ‘My Analytics’ component which is imported into the dashboard component to make the code cleaner and manageable. So inside the My analytics component, we fetch the data from the server as depicted above and after that, we render the pie chart component after importing from the recharts library. Importing the pie chart components from the recharts library. import { Legend, PieChart, Pie, Sector, Cell, ResponsiveContainer } from 'recharts';   Rendering the pie chart component while supplying appropriate props most important of which is the data prop which will be used in the chart and that data is available in the application state as saved earlier. We also have other styling props and a function which is triggered when hovering over cells of the pie chart to represent the data of the hovered cell.…

Continue ReadingAdd Info on Skill Usage Distribution for all Skills by an Author in SUSI.AI

Implementing feature to filter skills by average customer review

SUSI Skill CMS showcases all the skills on the index page but lacks the functionality to refine skills according to average customer review which is a much-needed feature since some users may only want to try skills which have at least a minimum rating so they can know instantly which skills are performing well in comparison to others. Thus, we implement several star inputs on the sidebar to select skills which have ratings greater than or equal to the selected rating input. Implementing the UI Add a menu to the sidebar at the bottom of all categories and display ‘Refine by’ submenu text to denote the section. <Menu desktop={true} disableAutoFocus={true}> <Subheader style={{ fontWeight: 'bold' }}>Refine by</Subheader> <h4 style={{ marginLeft: '12px', marginBottom: '4px' }}> Avg. Customer Review </h4> ...   Display rating options to the user by displaying a list of Ratings component imported from react-ratings-declarative, these are to be displayed for all ratings say four stars and above, three stars and above and so on, i.e. <div style={styles.singleRating} onClick={() => this.handleRatingRefine(4)} > <Ratings rating={4} widgetRatedColors="#ffbb28" widgetDimensions="20px" widgetSpacings="0px" > <Ratings.Widget /> <Ratings.Widget /> <Ratings.Widget /> <Ratings.Widget /> <Ratings.Widget /> </Ratings> <div style={styles.ratingLabel} className={this.state.rating_refine === 4 ? 'bold' : ''} > & Up </div> </div>   We add some styling and attach an onClick listener on each rating component which will handle the refining of skills according to the rating clicked, the idea behind this is to save the rating for the clicked option to the component state and re-render the skill cards handleRatingRefine = rating => { this.setState( { rating_refine: rating, }, this.loadCards(), ); };   When the component state is successfully set loadCards function as a callback is called which re-renders the cards by applying filter over the skills which match the average rating criteria which we just set. if (self.state.rating_refine) { data.filteredData = data.filteredData.filter( skill => skill.skill_rating.stars.avg_star >= self.state.rating_refine, ); } Displaying a button to clear any refinements made Once the skills are refined a button is needed to clear any refinements made. Initially when no refinements are made the rating_refine in the state is set to null which indicates that no refinements are made so whenever the value of that state is no null we render a button to clear the refinements or set the rating_refine state to null. {this.state.rating_refine ? ( <div className="clear-button" style={styles.clearButton} onClick={() => this.handleRatingRefine(null)} > Clear </div> ) : ( '' )} Resources MDN Docs, ES6 array filter, https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter  Hassan, Displayed a simple rating view, https://medium.com/@hassanahmedkhan/simple-ratings-view-in-react-native-59a0ceb2d13f  João, Learn about javascript map, filter, reduce, https://medium.com/@joomiguelcunha/learn-map-filter-and-reduce-in-javascript-ea59009593c4 

Continue ReadingImplementing feature to filter skills by average customer review

Implementing My Rating Section on the SUSI.AI Skills Dashboard

SUSI Skill CMS provides the functionality to rate the skills, therefore users rate skills they use but there isn’t any place where they can see all the skills they rated, thus a ‘My Ratings’ section was implemented on the dashboard page to view these statistics. So to see what ratings they have given to skills they can just login to the cms and navigate to /dashboard and a my ratings components is visible there which lists all the ratings the user has provided in a nice tabular format. About the API An API endpoint is implemented on the server which fetches the skill data for skills the user has rated which includes the skill name, stars given and the timestamp. /cms/getProfileDetails.json?access_token=   So we pass the access token of the authenticated user and a JSON response is received which contains all the details as depicted below, this data is then parsed on the frontend and filled in a tabular form on the MyRatings section. { "rated_skills": [ {"amazon_shopping": { "stars": "1", "timestamp": "2018-06-10 13:05:32.295" }}, {"aboutsusi": { "stars": "2", "timestamp": "2018-06-10 13:26:26.222" }}, {"anagrams": { "stars": "3", "timestamp": "2018-06-10 13:25:31.195" }} ], "session": {"identity": { "type": "email", "name": "anshu.av97@gmail.com", "anonymous": false }}, "accepted": true, "message": "User ratings fetched." } Displaying the results on the web Make a MyRatings component and render it on the dashboard component Make an AJAX call to the API and save the returned data to the component state. First create a loadSkills function in componentDidMount which will be called just as the component is mounted to the DOM which will then fetch data from the server, extract the meaningful parts such as skill_name, skill_star and timestamp and push them to an array which in this case is ratingsData. While the data is being fetched we show a circular loader for better UX and once we receive the data we save it in the component state and turn loading to false which will replace the loading animation with the actual data. loadSkills = () => { let url; url = urls.API_URL + '/cms/getProfileDetails.json?access_token=' + cookies.get('loggedIn'); let self = this; let ratingsData = []; $.ajax({ url: url, jsonpCallback: 'pxcd', dataType: 'jsonp', jsonp: 'callback', crossDomain: true, success: function(data) { if (data.rated_skills) { for (let i of data.rated_skills) { let skill_name = Object.keys(i)[0]; ratingsData.push({ skill_name: skill_name, skill_star: i[skill_name].stars, rating_timestamp: i[skill_name].timestamp, }); } self.setState({ ratingsData, }); } self.setState({ loading: false, }); }, error: function(err) { self.setState({ loading: false, openSnackbar: true, msgSnackbar: "Error. Couldn't rating data.", }); }, }); };   Display a loading animation when the data is being fetched, we maintain a state in the component called loading which is initially true since we don’t have the data just as the component is rendered so after we receive the data we turn the loading state to false which will hide the circular loader and display the component with the data received. {this.state.loading ? ( <div className="center"> <CircularProgress size={62} color="#4285f5" /> <h4>Loading</h4> </div> ) : ( ... ) }   Add a…

Continue ReadingImplementing My Rating Section on the SUSI.AI Skills Dashboard