Sunday

An example of converting object to an array in javascript


const ingredients = {
 salad: 2,
 tomato: 1,
 cheese: 3,
 meat: 2
}

const transformedIngredients = Object.keys(ingredients)
  .map(iKey => {
     return [...Array(ingredients[iKey])].map((_, i) => {
       return iKey ;
   });
}); 

console.log(transformedIngredients.toString());
the output is: salad,salad,tomato,cheese,cheese,cheese,meat,meat

**Object.keys(ingredients) returns key list:   salad,tomato,cheese,meat
**Array(ingredients[iKey])   returns the value of the given key like salad. for instance,the output for salad: Array(2). so the second map loops 2 time and returns salad twice.

enable css loader >> unknown property 'localIdentName' error

versions >>  "css-loader":"3.4.2"

firstly looking: (in the project created by create-react-app which has been ejected)
{
  test: cssRegex,
  exclude: cssModuleRegex,
  use: getStyleLoaders({
 importLoaders: 1,
 sourceMap: isEnvProduction && shouldUseSourceMap,
  }),
  sideEffects: true,
},
I tried: (this one is the older config)
{
  test: cssRegex,
  exclude: cssModuleRegex,
  use: getStyleLoaders({
 importLoaders: 1,
 modules: true,
 localIdentName: "[name]__[local]___[hash:base64:5]",
 sourceMap: isEnvProduction && shouldUseSourceMap,
  }),
  sideEffects: true,
},
i got following error:
./src/index.css (./node_modules/css-loader/dist/cjs.js??ref--6-oneOf-3-1!./node_modules/postcss-loader/src??postcss!./src/index.css)
ValidationError: Invalid options object. CSS Loader has been initialized using an options object that does not match the API schema.
 - options has an unknown property 'localIdentName'. These properties are valid:
   object { url?, import?, modules?, sourceMap?, importLoaders?, localsConvention?, onlyLocals?, esModule? }

FIX:
 {
  test: cssRegex,
  exclude: cssModuleRegex,
  use: getStyleLoaders({
 importLoaders: 1,
 modules: {
   localIdentName: "[name]__[local]___[hash:base64:5]",
 }, 
 sourceMap: isEnvProduction && shouldUseSourceMap,
  }),
  sideEffects: true,
},

Saturday

How to copy given text to the clipboard in react with typescript


import React from 'react';
import { LightTooltip } from '../tooltip/lightTooltip';

interface IOwnProps {
  messageToBeCopied: string | null;
}

export default class CopyToClipboard extends React.Component<IOwnProps> {

  render() {
    const { messageToBeCopied, children } = this.props;
    let isCopySuccess = false;

    if (messageToBeCopied) {
      try {
        const textField = document.createElement('textarea');
        textField.innerText = messageToBeCopied;
        document.body.appendChild(textField);
        textField.select();

        isCopySuccess = document.execCommand('copy');
        textField.remove();

      } catch (e) {
        isCopySuccess = false;
      }

      return (
        <LightTooltip
          leaveDelay={1}
          leaveTouchDelay={1}
          title={isCopySuccess === false ? 'Failed to copy.' : 'Copied.'}
        >
          {children as React.ReactElement}
        </LightTooltip>
      );
    }

    return <>{children}</>;
  }
}

import { withStyles, Theme } from '@material-ui/core/styles';
import Tooltip from '@material-ui/core/Tooltip';

export  const LightTooltip = withStyles((theme: Theme) => ({
  tooltip: {
    backgroundColor: theme.palette.common.white,
    color: 'rgba(0, 0, 0, 0.87)',
    boxShadow: theme.shadows[1],
    fontSize: 12,
    fontFamily: 'Rubik-Regular',
  },
}))(Tooltip);

import React from 'react';
import CopyToClipboard from '../copyToClipboard/copyToClipboard';

interface IState {
  clipboardMessage: string | null;
}

class Example extends React.Component<null, IState> {
  constructor(props) {
    super(props);
    this.state = {
      clipboardMessage: null,
    };
  }

  setClipboardMessage() {
    const message = 'Message for copy to clipboard';

    this.setState({
      clipboardMessage: message,
    });
  }

  render() {
    return (
      <CopyToClipboard messageToBeCopied={this.state.clipboardMessage}>
        <a onClick={() => this.setClipboardMessage()}>Copy</a>
      </CopyToClipboard>
    );
  }
}

export default Example;
Example screenshot after clicking the text:

How to add fonts into react project

Define your font as follows in your app.scss/app.css :
(You can use your fonts as named in font-family.)
@font-face {
  font-family: 'Rubik-Regular';
  src: local('Rubik'), url(../static/font/Rubik/Rubik-Regular.ttf) format('truetype');
}

@font-face {
  font-family: 'Rubik-Medium';
  src: local('Rubik'), url(../static/font/Rubik/Rubik-Medium.ttf) format('truetype');
}

Add font files into src/static/font/..



















Convert currency code to symbol in react with typescript


import { currencyMap } from './currencyMap';

export default function  getSymbolFromCurrencyCode(currencyCode : string) {
  const code = currencyCode && currencyCode.toUpperCase();
  if (!currencyMap.hasOwnProperty(code)) {
    return currencyCode;
  }
  return currencyMap[code];
}

export const currencyMap = {
  'AED': 'د.إ',
  'AFN': '؋',
  'ALL': 'L',
  'AMD': '֏',
  'ANG': 'ƒ',
  'AOA': 'Kz',
  'ARS': '$',
  'AUD': '$',
  'AWG': 'ƒ',
  'AZN': '₼',
  'BAM': 'KM',
  'BBD': '$',
  'BDT': '৳',
  'BGN': 'лв',
  'BHD': '.د.ب',
  'BIF': 'FBu',
  'BMD': '$',
  'BND': '$',
  'BOB': '$b',
  'BRL': 'R$',
  'BSD': '$',
  'BTC': '฿',
  'BTN': 'Nu.',
  'BWP': 'P',
  'BYR': 'Br',
  'BYN': 'Br',
  'BZD': 'BZ$',
  'CAD': '$',
  'CDF': 'FC',
  'CHF': 'CHF',
  'CLP': '$',
  'CNY': '¥',
  'COP': '$',
  'CRC': '₡',
  'CUC': '$',
  'CUP': '₱',
  'CVE': '$',
  'CZK': 'Kč',
  'DJF': 'Fdj',
  'DKK': 'kr',
  'DOP': 'RD$',
  'DZD': 'دج',
  'EEK': 'kr',
  'EGP': '£',
  'ERN': 'Nfk',
  'ETB': 'Br',
  'ETH': 'Ξ',
  'EUR': '€',
  'FJD': '$',
  'FKP': '£',
  'GBP': '£',
  'GEL': '₾',
  'GGP': '£',
  'GHC': '₵',
  'GHS': 'GH₵',
  'GIP': '£',
  'GMD': 'D',
  'GNF': 'FG',
  'GTQ': 'Q',
  'GYD': '$',
  'HKD': '$',
  'HNL': 'L',
  'HRK': 'kn',
  'HTG': 'G',
  'HUF': 'Ft',
  'IDR': 'Rp',
  'ILS': '₪',
  'IMP': '£',
  'INR': '₹',
  'IQD': 'ع.د',
  'IRR': '﷼',
  'ISK': 'kr',
  'JEP': '£',
  'JMD': 'J$',
  'JOD': 'JD',
  'JPY': '¥',
  'KES': 'KSh',
  'KGS': 'лв',
  'KHR': '៛',
  'KMF': 'CF',
  'KPW': '₩',
  'KRW': '₩',
  'KWD': 'KD',
  'KYD': '$',
  'KZT': 'лв',
  'LAK': '₭',
  'LBP': '£',
  'LKR': '₨',
  'LRD': '$',
  'LSL': 'M',
  'LTC': 'Ł',
  'LTL': 'Lt',
  'LVL': 'Ls',
  'LYD': 'LD',
  'MAD': 'MAD',
  'MDL': 'lei',
  'MGA': 'Ar',
  'MKD': 'ден',
  'MMK': 'K',
  'MNT': '₮',
  'MOP': 'MOP$',
  'MRO': 'UM',
  'MRU': 'UM',
  'MUR': '₨',
  'MVR': 'Rf',
  'MWK': 'MK',
  'MXN': '$',
  'MYR': 'RM',
  'MZN': 'MT',
  'NAD': '$',
  'NGN': '₦',
  'NIO': 'C$',
  'NOK': 'kr',
  'NPR': '₨',
  'NZD': '$',
  'OMR': '﷼',
  'PAB': 'B/.',
  'PEN': 'S/.',
  'PGK': 'K',
  'PHP': '₱',
  'PKR': '₨',
  'PLN': 'zł',
  'PYG': 'Gs',
  'QAR': '﷼',
  'RMB': '¥',
  'RON': 'lei',
  'RSD': 'Дин.',
  'RUB': '₽',
  'RWF': 'R₣',
  'SAR': '﷼',
  'SBD': '$',
  'SCR': '₨',
  'SDG': 'ج.س.',
  'SEK': 'kr',
  'SGD': '$',
  'SHP': '£',
  'SLL': 'Le',
  'SOS': 'S',
  'SRD': '$',
  'SSP': '£',
  'STD': 'Db',
  'STN': 'Db',
  'SVC': '$',
  'SYP': '£',
  'SZL': 'E',
  'THB': '฿',
  'TJS': 'SM',
  'TMT': 'T',
  'TND': 'د.ت',
  'TOP': 'T$',
  'TRL': '₤',
  'TRY': '₺',
  'TL': '₺',
  'TTD': 'TT$',
  'TVD': '$',
  'TWD': 'NT$',
  'TZS': 'TSh',
  'UAH': '₴',
  'UGX': 'USh',
  'USD': '$',
  'UYU': '$U',
  'UZS': 'лв',
  'VEF': 'Bs',
  'VND': '₫',
  'VUV': 'VT',
  'WST': 'WS$',
  'XAF': 'FCFA',
  'XBT': 'Ƀ',
  'XCD': '$',
  'XOF': 'CFA',
  'XPF': '₣',
  'YER': '﷼',
  'ZAR': 'R',
  'ZWD': 'Z$',
}
Example:
import getSymbolFromCurrencyCode from '../commons/currencySymbol/currencySymbolMap';

...
getSymbolFromCurrencyCode('TRY');
...

Typescript index signature example


import Example1 from '../../components/……....';
import Example2 from '../../components/…....';


interface ExampleInfos {
  name: any;
  param1: string;
  param2?: boolean;
}


interface ExampleLayout {
  [key:string]: ExampleInfos;
}


export const exampleMap: ExampleLayout = {
  example1: {
    name: Example1,
    param1: 'medium',
  },
  example2: {
    name: Example2,
    param1: 'medium',
    param2: false,
  },
}


import { exampleMap } from './exampleMap';

...
 const myMap= exampleMap['example1'];
 const myComponent = myMap && myMap.name;
...

Monday

Exception handling in react with typescript

withRenderCtrl.tsx
import React from 'react';
import Loading from '../../commons/loading/loading';
import ErrorBoundary from '../../commons/error/errorBoundary';
import EmptyHint from '../../commons/empty/emptyHint';

export interface WithRenderCtrlProp {
  isDataReady: boolean;
  isLoading: boolean;
  customEmptyMessage?: string | null;
  errorMessage: string | null;
}

const withRenderCtrl = <P extends object>(Component: React.ComponentType<P>) =>
  class WithLoading extends React.Component<P & WithRenderCtrlProp> {
    render() {
      const { isDataReady, isLoading, errorMessage, customEmptyMessage, ...props } = this.props;

      if (isDataReady) return <Component {...props as P} />;
      if (errorMessage) return <ErrorBoundary errorMessage={errorMessage}/>;
      if (isLoading) return <Loading />;
      return <EmptyHint customMessage={customEmptyMessage}/>;
    }
  }

export default withRenderCtrl;
emptyHint.tsx
import React from 'react';

interface IProps {
  customMessage?: string | null;
}
 // custom message is not necessary, if it is not given then a common message will be shown
const EmptyHint = ({ customMessage = null }: IProps) => (
  <div>
    <div>{customMessage ? customMessage : 'common message for no data found '}</div>
  </div>
);

export default EmptyHint;
errorBoundary.tsx
import React from 'react';

interface IState {
  error: any;
  info: any;
}

interface IProps {
  errorMessage: any | null;
}

// also it has componentDidCatch method
class ErrorBoundary extends React.Component<IProps, IState> {
  constructor(props) {
    super(props);
    this.state = {
      error: null,
      info: null,
    };
  }

  componentDidCatch(error, info) {
    this.setState({
      error: error,
      info: info,
    });
  }

  render() {
    if (this.state.error || this.props.errorMessage) {
      return (
        <div>
          <h1>...... :( </h1>
            {this.state.error && this.state.error.toString()}
            {this.props.errorMessage && this.props.errorMessage.toString()}
        </div>
      );
    }
    return this.props.children;
  }
}

export default ErrorBoundary;
loading.tsx
import React from 'react';

const Loading = () => (
    <div>Wait for loading....</div>
);

export default Loading;
example:
import React from 'react';

// define props, states vs. ...

class Example extends React.PureComponent {

  // ...
  // when you calling your api, you should set loading, error props.
  async componentDidMount() {
    const { setMyData,  setLoader, setError } = this.props;

    setLoader(true);
    const myData = await getMyData()
      .catch((error) => {
        setError(error);
      });
    setLoader(false);

    setMyData(myData);
  }

  render(){
    const { myData, isLoading, error } = this.props;
    // usually your main component gets data, sets error & loading cases. It has callback methods vs.
    // The component named with Body includes html, css stuffs.
    // and you should define your body component as following. (with wraping our HOC named as withRenderCtrl)
    // export default withRenderCtrl(ExampleBody);
    return(
        <ExampleBody
          myData={myData}
          isLoading={isLoading}
          errorMessage={error}
          isDataReady={myData && !myData.isEmpty()}
          customEmptyMessage="my custom empty data >> this props is not necessary"
        />
    );
  }
}

export default Example;
References: https://github.com/kenneth1003/react-render-ctrl

React common api calls with axios (typescript)

Firstly, create a component called as "request.ts"
import axios from 'axios';
import I from 'immutable';

const apiURL = axios.create({
  baseURL: process.env.MY_API_URL, // example: localhost:8080/
});

const request = function (options) {

  const onSuccess = function (response) {
    const data = response.data;

    if (data.myErrorFromApiAsSuccessStatus) {
      return myStructureError(data.myErrorFromApiAsSuccessStatus);
    }
    return I.fromJS({ data });
  };

  const onError = function (error) {
    if (error.response && error.response.data && error.response.data.myErrorFromApiAsSuccessStatus) {
      return myStructureError(error.response.data.myErrorFromApiAsSuccessStatus);
    }

    console.log(`
      url: ${options.url}
      message:  ${error.message}
      stackTrace: ${error.stack}
    `);

    return Promise.reject(error.message);
  };

  function myStructureError(myErrorFromApiAsSuccessStatus) {
    const error = (`
      url: ${options.url}
      message: ${myErrorFromApiAsSuccessStatus.message}
    `);
    console.log(error);

    return Promise.reject(error);
  }

  return apiURL(options)
    .then(onSuccess)
    .catch(onError);
};

export default request;

Use request component in your api calls as following: (api.ts)
import request from '../request';

export const getMyData = async(mydata: string) => {
  return request({
    url:  '/my-data',
    method: 'POST',
    data: {
      mydata : mydata,
    },
  });
};

react - fusioncharts example with typescript (stackedcolumn2d)


import React from 'react';
import FusionCharts from 'fusioncharts';
import charts from 'fusioncharts/fusioncharts.charts';
import ReactFC from 'react-fusioncharts';

// add this line if you have licence:  FusionCharts.options['creditLabel'] = false;

charts(FusionCharts);

interface IOwnProps {
  myData: any;
}

type IProp = IOwnProps;

class StackedChart extends React.PureComponent<IProp> {
  constructor(props: IProp) {
    super(props);
    this.getToolText = this.getToolText.bind(this);
  }

  getToolText(label: string, customData: string) {
    return (
      `${label}` +
      ' | ' +
      `${customData}` +
      '<br/>' +
      '<div style="width:110px;color:red;margin-left:1px;margin-top:2px;"> ' +
        'Custom Tooltip' +
      '</div>'
    );
  }

  render() {
    // const { myData } = this.props;

    const dataSource = {
      chart: {
        theme: 'fusion',
        bgColor: '#FFFFFF',
        alternateHGridColor:'#FFFFFF',
        formatNumberScale: 1,
        numberPrefix: '$',
        numDivLines: 6,
        textOutline:0,

/*      decimalSeperator: ',',
        decimals: 0,
        forceDecimals: 0,
        yAxisValueDecimals: 0,*/

        divLineThickness: 1,
        divLineAlpha: 10,

        useRoundEdges: 0,
        usePlotGradientColor: 0,

        showSum: '1',
        showLegend: 1,
        showcanvasborder: 0,
        showPlotBorder: 0,

        baseFont:'Arial, "Helvetica Neue", Helvetica, sans-serif',
        baseFontSize: 14,
        baseFontColor: '#000000',

        labelFont:'Arial, "Helvetica Neue", Helvetica, sans-serif',
        labelFontSize: 14,
        labelFontColor: '#000000',

        valueFont:'Arial, "Helvetica Neue", Helvetica, sans-serif',
        valueFontSize: 14,
        valueFontColor: '#000000',

        outCnvBaseFont:'Arial, "Helvetica Neue", Helvetica, sans-serif',
        outCnvBaseFontSize: 14,
        outCnvBaseFontColor: '#000000',

        legendItemFont:'Arial, "Helvetica Neue", Helvetica, sans-serif',
        legendItemFontSize: 14,
        legendItemFontColor: '#000000',
        legendIconScale: 1,
        legendBorderThickness: 0,
        legendShadow: 0,

      },
      categories: [
        {
          category: [
            {
              label: 'Label1',
            },
            {
              label: 'Label2',
            },
            {
              label: 'Label3',
            },
            {
              label: 'Label4',
            },
          ],
        },
      ],
      dataset: [
        {
          seriesname: 'Serie 1',
          showValues: false,
          color: '#003f5ec',
          data: [
            {
              value: 1000,
              toolText: this.getToolText(
                '$label',
                'my custom text 1'
              ),
            },
            {
              value: 2000,
              toolText: this.getToolText(
                '$label',
                'my custom text 2'
              ),
            },
            {
              value: 50,
              toolText: this.getToolText(
                '$label',
                'my custom text 3'
              ),
            },
            {
              value: 3000,
              toolText: this.getToolText(
                '$label',
                'my custom text 4'
              ),
            },
          ],
        },
        {
          seriesname: 'Serie 2',
          showValues: false,
          color: '#ffe600',
          data: [
            {
              value: 4000,
              toolText: this.getToolText(
                '$label',
                'my custom text 5'
              ),
            },
            {
              value: 2000,
              toolText: this.getToolText(
                '$label',
                'my custom text 6'
              ),
            },
            {
              value: 800,
              toolText: this.getToolText(
                '$label',
                'my custom text 7'
              ),
            },
            {
              value: 6600,
              toolText: this.getToolText(
                '$label',
                'my custom text 8'
              ),
            },
          ],
        },
      ],
    }

    return (
      <div id="my-chart-container">
        <ReactFC
          type="stackedcolumn2d"
          width="100%"
          height="250"
          dataFormat="JSON"
          dataSource={dataSource}
        />
      </div>
    );
  }
}

export default StackedChart;