[KnackSteem] - Frontend with React/Redux and Ant Design

in #utopian-io6 years ago

I recently got asked to do some React programming for an Open Source project called "KnackSteem", and this is what I have done so far in my very first PR for the project:

Repository & Pull Request

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

Changes

  • Complete Cleanup and Reorganization of the project:
    • Remove SASS (pure CSS ftw!)
    • Add ESLint, Editorconfig and fix upcoming ESLint errors and warnings
    • Use Yarn instead of npm
    • Add License to the project
  • New Features
    • Base Layout with Ant Design
    • Dynamic Routing with react-router
    • Sidebar menu based on Ant Design: Logo, Categories, User contributions
    • Steem Connect login with callback redirection
    • Redux Actions/Reducers for user data and article data (global store)
    • Search Input - with JavaScript array.filter on client for now

Details

Screenshots with two states - logged out (only categories are visible) and logged in (right after logging in with Steem Connect)

default.png

logged_in.png

The code should be easy to understand for a React/Redux developer. Sometimes there was no need for a component state, so i switched to stateless functional components. For example:

components/ArticleListItem/index.js

const ArticleListItem = ({data}) => {
  return (
    <div className="ant-list-item">
      <Link to="/articles/permalink1">
        <div style={{width: 280, float: 'left', marginRight: 20}}><img src="http://placekitten.com/280/160" alt="Article"/></div>
        <h2 className="ant-list-item-meta-title">{data.title}</h2>
        <div className="ant-list-item-content">{data.description}</div>
      </Link>
      <ul className="ant-list-item-action">
        <li><IconText type="clock-circle-o" text="156" /><em className="ant-list-item-action-split" /></li>
        <li><IconText type="message" text="156" /><em className="ant-list-item-action-split" /></li>
        <li><IconText type="up-circle-o" text="2" /></li>
      </ul>
    </div>
  );
};



The dynamic routing in App.js is straightforward, i am reusing the Home component for three routes ("/" for all articles, "/mycontributions" for user articles, "/categories/:category" for all articles with a specific category):

App.js

const App = () => {
  return (
    <Layout>
      <Sidebar/>
      <Layout>
        <Header/>
        <Route exact path="/" component={Home} />
        <Route exact path="/callback" component={Callback} />
        <Route exact path="/mycontributions" component={Home} />
        <Route exact path="/categories/:category" component={Home} />
        <Route exact path="/articles/:article" component={ArticleDetail} />
      </Layout>
    </Layout>
  );
};

You can also see the base layout in the file, created with the Ant Design library.

There is one Redux Reducer for article storage and one for user data. Of course, using fancy stuff like the spread properties to copy the old state. This is how the article Reducer looks like:

reducers/articles.js

import {ARTICLES_REQUEST, ARTICLES_GET} from '../actions/types';

const initialState = {
  currentCategory: '',
  searchString: '',
  data: []
};

const articles = (state = initialState, action) => {
  switch (action.type) {
    case ARTICLES_REQUEST:
      return {
        ...state,
        currentCategory: action.category,
        data: []
      };
    case ARTICLES_GET:
      return {
        ...state,
        data: action.payload
      };
    default:
      return state;
  }
};

export default articles;



User Login happens with a login action that gets called right after logging in with Steem Connect. Steem Connect gets initialized and the user object gets loaded - thankfully, Steem Connect supports Promises (and async/await):

actions/user.js

export const userLogin = (accessToken) => {
  return async (dispatch) => {
    dispatch({
      type: types.USER_AUTH
    });

    let api = sc2.Initialize({
      app: 'knacksteem.app',
      callbackURL: 'http://localhost:3000/callback',
      accessToken: accessToken,
      scope: ['login', 'custom_json', 'claim_reward_balance', 'vote', 'comment']
    });
    let response = await api.me();

    dispatch({
      type: types.USER_GET,
      username: response.user,
      userObject: response,
      accessToken: accessToken
    });
  };
};

localhost:3000will be replaced with the domain later, of course :)

Searching is done client side right now, but that is just a temporary solution. Because not all articles will get loaded all the time (Paging will be included), Searching needs to happen on the server later. This is the temporary solution, searching in title and description/content of an article:

containers/Home/index.js

articlesData = articlesData.filter((elem) => {
        if (elem.title.toLowerCase().indexOf(searchString.toLowerCase()) !== -1) {
          return true;
        }
        if (elem.description.toLowerCase().indexOf(searchString.toLowerCase()) !== -1) {
          return true;
        }
        return false;
      });

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."

Thanx to @jaysermendez for grabbing this from the Discord Channel :)

  • Technology Stack

    • JavaScript ES6+ with Babel
    • React + Redux
  • Roadmap

    • Article detail page
    • View for moderators
    • Contribution page to create new contributions
    • Add some more comments to the code - it´s actually done, but not in the main repository yet. Don´t want to create a PR just for that :)
    • ...
  • How to contribute?
    Talk to @knowledges :)


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

Sort:  

Thank you for your contribution. A great contribution and would love to see more such contributions from you.

According to your Road-map "Add some more comments to the code - it´s actually done, but not in the main repository yet. Don´t want to create a PR just for that :)", though wouldn't it be better to add comments as you write the code i.e. the basic ones

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]

you are absolutely right, i am a bit lazy about that. although, it would save me some work to do it while programming...

Lazy 😂😂😂😂😂💁‍♂️💁‍♂️

Well, producing code is cool, commenting code is boring 😇

Hey @codingdefined
Here's a tip for your valuable feedback! @Utopian-io loves and incentivises informative comments.

Contributing on Utopian
Learn how to contribute on our website.

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

Vote for Utopian Witness!

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

Contributing on Utopian
Learn how to contribute on our website or by watching this tutorial on Youtube.

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

Vote for Utopian Witness!

Coin Marketplace

STEEM 0.18
TRX 0.16
JST 0.029
BTC 76491.95
ETH 2940.27
USDT 1.00
SBD 2.64