import React, { useState } from 'react' import { useLocation, useHistory, Match, Redirect } from 'react-router-dom' import { useDidMount, useDidUpdate } from 'react-hooks-lib' import SVG from 'react-inlinesvg' import _isEmpty from 'lodash/isEmpty' import _cloneDeep from 'lodash/cloneDeep' import _some from 'lodash/some' import { ApiInterface } from 'types' import { Input, Button } from 'ui' import { ExploreApiBreadcrumbs } from 'components' import * as S from './styled' type Param = { isOptional: boolean name: string type: string } type Method = { description?: string isSigned: boolean isSubscription: boolean isConstant?: boolean params: Param[] pubsub?: string[] type: string } type ParamFormatted = Param & { value: string } type FuncResult = { message: string level: string } type Props = { api: ApiInterface match: Match } const Method = ({ api, match }: Props) => { const location = useLocation() const history = useHistory() const { category, subcategory, method } = match.params const [data, setData] = useState<Method>() const [paramInputs, setParamInputs] = useState<ParamFormatted[]>([]) const [funcResult, setFuncResult] = useState<FuncResult>({ message: 'Fill out the required params and click the "Run test" button.', level: 'info' }) const requirements = [ { key: 'isSigned', name: 'signed' }, { key: 'isSubscription', name: 'a subscription' } ] useDidMount(() => { if (api.description[category]?.categories[subcategory]?.methods[method]) { setData(api.description[category].categories[subcategory].methods[method]) } }) useDidUpdate(() => { if (data && !_isEmpty(data)) { const paramsFormatted: ParamFormatted[] = data.params.map((o: Param) => ({ ...o, value: '' })) setParamInputs(paramsFormatted) if (data.isSigned || data.isSubscription) { setFuncResult({ message: "This function can't be tested.", level: 'error' }) } } }, [data]) const handleInputChange = ( e: React.ChangeEvent<HTMLInputElement>, idx: number ) => { if (paramInputs) { const paramsFormatted = _cloneDeep(paramInputs) paramsFormatted[idx].value = e.target.value setParamInputs(paramsFormatted) } } const handleRunTest = () => { if (_some(paramInputs, o => !o.isOptional && !o.value)) { setFuncResult({ message: 'You have to fill out all the required params!', level: 'error' }) } else { const params = paramInputs.map(o => o.value) const fn = api.promise[category][subcategory][method] if (data && !data.isConstant) { fn(...params) .then(res => { setFuncResult({ message: JSON.stringify(res), level: 'result' }) }) .catch(err => { setFuncResult({ message: JSON.stringify(err.message), level: 'error' }) }) } else { setFuncResult({ message: JSON.stringify(fn), level: 'result' }) } } } const handleReset = () => { setFuncResult({ message: 'Fill out the required params and click the "Run test" button.', level: 'info' }) } return category === 'consts' ? ( <Redirect to="/explore-api" /> ) : data ? ( <S.Wrapper> <S.Title> <S.CategoryName> <div> <strong> {method}( {data.params && ( <> <span> {data.params.map(o => o.name).join(', ')} </span> </> )} ) </strong> {data.description && <div>{data.description}</div>} </div> <div> {location?.state?.search && ( <Button fluid theme="outline" text="< Back to search" onClick={() => history.push({ pathname: `/search/${location.state.search}`, state: { routeName: 'Search' } }) } /> )} </div> </S.CategoryName> <ExploreApiBreadcrumbs match={match} /> </S.Title> {_isEmpty(data) ? ( <S.Empty>There's nothing in here 🤔</S.Empty> ) : ( <S.Content> <div> <S.Header>Can be tested?</S.Header> {requirements.map((item, idx) => ( <S.Requirement key={`requirement-${idx}`} isOk={!data[item.key]}> <SVG src={data[item.key] ? '/icons/close.svg' : '/icons/check.svg'} > <img src={ data[item.key] ? '/icons/close.svg' : '/icons/check.svg' } alt={data[item.key] ? 'not testable' : 'is testable'} /> </SVG> {data[item.key] ? `Is ${item.name}` : `Is not ${item.name}`} </S.Requirement> ))} </div> <div> <S.Header>Return type</S.Header> {data.type && <S.ReturnType>{data.type}</S.ReturnType>} </div> <S.Params> <S.Header>Params</S.Header> {_isEmpty(paramInputs) ? ( <S.NoParams> This function doesn't have any params. </S.NoParams> ) : ( paramInputs && paramInputs.map((item, idx) => ( <div key={`paramInput-${idx}`}> <S.ParamName isOptional={item.isOptional}> <strong>{item.name}:</strong> {` ${item.type}`} <span>{item.isOptional ? 'Optional' : 'Required!'}</span> </S.ParamName> {!data.isSigned && !data.isSubscription && ( <Input fluid value={item.value} onChange={e => handleInputChange(e, idx)} /> )} </div> )) )} <Button fluid disabled={data.isSigned || data.isSubscription} text={ data.isSigned || data.isSubscription ? 'Test unavailable' : 'Run test' } onClick={handleRunTest} style={{ marginTop: '8px' }} /> </S.Params> <div> <S.Header>Test result</S.Header> <S.FuncResult fluid padding="16px 24px" level={funcResult.level}> <button onClick={handleReset}>RESET</button> {funcResult.message} </S.FuncResult> </div> </S.Content> )} </S.Wrapper> ) : null } export default Method