[KnackSteem] - Backend Connection, Single Post View, Lazy Loading

in #utopian-io6 years ago

Weekend? What is that? I had some time to continue working on the Knacksteem frontend, so here is the PR for the next batch of commits:

Repository & Pull Request

https://github.com/knacksteem/knacksteem.org
https://github.com/knacksteem/knacksteem.org/pull/8

I believe the PR includes the commits from the last PR too (see PR comment). Sorry for that, i guess it´s just me being a n00b with PRs and squash merging :)

About knacksteem.org

"Do you have any talent? If yes! then KnackSteem is for you."
"Rewards people with talents, it can be any talent, anything you know how to do best is highly welcome on the platform."

Technology Stack

  • JavaScript ES6+ with Babel
  • React + Redux
  • Ant Design

Changes / New Features

A lot of things have been added, and apart from (probably) some minor bugfixing here and there all the basic user views are done now:

  • config.js for all the current and upcoming basic settings (Steem Connect scope array, for example).
  • Implement API handler/functions connecting frontend to backend.
  • Push new contributions not only to the blockchain, but to the backend too.
  • Load user articles from backend instead of using mock data.
  • Load articles by category from backend instead of using mock data.
  • Implement Lazy Loading for all article lists.
  • Single post view: show title, content, tags, ...
  • Convert timestamp to pretty human readable date.
  • Add some spinners/loaderes for article list and article detail page.
  • Update all npm packages, fix breaking changes of ESLint 5.x.

Details

services/api.js

There has been some old code in this file, copied from another one of my projects. I removed everything and implemented the POST and GET handlers from scratch. Every communication with the backend API goes through this file:

//set some default settings for axios to handle backend api correctly
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
axios.defaults.transformRequest = [(data, headers) => {
  let str = [];
  for(let p in data)
    if (data.hasOwnProperty(p) && data[p]) {
      str.push(`${encodeURIComponent(p)}=${encodeURIComponent(data[p])}`);
    }
  return str.join('&');
}];

//basic post request to backend api
export const apiPost = async (url, data) => {
  try {
    let response = await axios({
      method: 'post',
      url: (process.env.NODE_ENV === 'development') ? `http://localhost:3030/v1${url}` : `https://knacksteem.org/v1${url}`,
      data: data,
      responseType: 'json'
    });
    return response;
  } catch (error) {
    console.log(error);
    return false;
  }
};

...

actions/articles.js

New contributions will be added to the backend database now, right after successfully posting them to the blockchain:

//successfully posted to blockchain, now posting to backend with permalink and category
await apiPost('/posts/create', {
  author: store.user.username,
  permlink: newPermLink,
  access_token: store.user.accessToken,
  category: tags[1]
});



In case you are not familiar with async/await yet: Try it, it´s amazing! No more callback hell :)

containers/Home/index.js

There were some other parts to change for implementing Lazy Loading, but this is where the magic happens when the user scrolls to the bottom:

//scroll handler for lazy loading
onScroll = () => {
  const {dispatch, match, articles} = this.props;

  //if in loading process, don´t do anything
  if (articles.isBusy) {
    return;
  }
  //if user hits bottom, load next batch of items
  const scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
  if ((window.innerHeight + scrollTop) >= document.body.scrollHeight) {
    dispatch(getArticlesByCategory(match.params.category, articles.data.length));
  }
};



While new articles are loading, nothing happens when you scroll further. The rest is just checking if the user scrolled to the bottom, and dispatching the articles action with the current number of articles. That one will be used for the skip parameter of the backend.

What´s important here is that you should remove the event listener when the component gets unmounted - which means that we are hitting another route:

componentWillUnmount() {
  //remove scroll event again when hitting another route
  window.removeEventListener('scroll', this.onScroll);
}



I also had to change the articles reducer for this. If there is a skip parameter (in other words: if a scroll event happened), I don´t just replace the data array. Instead, I copy it with the spread operator:

case ARTICLES_GET:
  return {
    ...state,
    isBusy: false,
    data: action.skip ? [...state.data, ...action.payload] : action.payload //if lazy loading, combine arrays
  };



Earlier you would have used Array.concat for this. But with the power of Babel, we can use all the fancy new JavaScript stuff :)

containers/ArticleDetail/index.js

This one is completely new, it just had a static div with a text before. I am not using Redux for storing the article details, because right now I don´t need to access the data of a single article in any other component. Just using the component state instead:

getArticle = async () => {
  const {match} = this.props;
    try {
      let response = await apiGet(`/posts/${match.params.author}/${match.params.permlink}`);
      this.setState({
        data: response.data,
        isLoading: false
      });
    } catch (error) {
      console.log(error);
      this.setState({
        data: {},
        isLoading: false
    });
  }
};



The rest of the component is straightforward, I am not a big fan of using a plugin for everything, but with the help of react-markdown, turning the returned Markdown string into HTML was quite easy:

<ReactMarkdown source={data.body} />



It does not look very fancy right now, because the test entry is not that large:

knacksteem.png

Roadmap

  • View for moderators and mod functionality (review, ban, approve, ...).
  • Refactor stuff - I am always happy for suggestions if there is something you would improve in the code!
  • ...

How to contribute?

Talk to @knowledges (or me) :)

My GitHub Account: https://github.com/ateufel

Sort:  

KnackSteem has finally found a developer!

Well, they do have some other developers already, a bunch of experienced and funny people, judging from the discord channel :)

I remember @knowledges struggled for months to get developers for this project. Good to see it growing now.

Thanks for the contribution, @luschn! The speed at which you guys are developing is very impressive - keep it up!

Your contribution has been evaluated according to Utopian policies and guidelines, as well as a predefined set of questions pertaining to the category.

To view those questions and the relevant answers related to your post, click here.


Need help? Write a ticket on https://support.utopian.io/.
Chat with us on Discord.
[utopian-moderator]

Congratulations @luschn! You have completed the following achievement on Steemit and have been rewarded with new badge(s) :

Award for the number of upvotes

Click on the badge to view your Board of Honor.
If you no longer want to receive notifications, reply to this comment with the word STOP

To support your work, I also upvoted your post!

Do not miss the last post from @steemitboard:
SteemitBoard World Cup Contest - Belgium vs Japan


Participate in the SteemitBoard World Cup Contest!
Collect World Cup badges and win free SBD
Support the Gold Sponsors of the contest: @good-karma and @lukestokes


Do you like SteemitBoard's project? Then Vote for its witness and get one more award!

Hey @luschn
Thanks for contributing on Utopian.
We’re already looking forward to your next contribution!

Want to chat? Join us on Discord https://discord.gg/h52nFrV.

Vote for Utopian Witness!

Coin Marketplace

STEEM 0.33
TRX 0.11
JST 0.034
BTC 66407.27
ETH 3219.07
USDT 1.00
SBD 4.34