trezy/firebase-system-update

View on GitHub
src/components/GithubExplorer.js

Summary

Maintainability
C
7 hrs
Test Coverage
// Module imports
import {
    useCallback,
    useEffect,
    useState,
} from 'react'
import PropTypes from 'prop-types'





// Local imports
import { Button } from 'components/Form/Button'
import { FontAwesomeIcon } from 'components/FontAwesomeIcon'
import { useAppContext } from 'contexts/AppContext'
import * as Github from 'helpers/github'





function GithubExplorer(props) {
    const {
        onSelect,
        projectID,
        title,
    } = props
    const {
        data: { projects },
    } = useAppContext()

    const project = projects[projectID]

    const [currentPath, setCurrentPath] = useState('')
    const [directoryListing, setDirectoryListing] = useState(null)

    const back = useCallback(() => {
        setCurrentPath(previousState => {
            const pathArray = previousState.split('/')
            return pathArray.slice(0, pathArray.length - 1).join('/')
        })
    }, [setCurrentPath])

    const getDirectoryToList = useCallback(() => {
        if (!currentPath) {
            return directoryListing
        }

        const pathArray = currentPath.split('/')

        return pathArray.reduce((accumulator, pathSegment) => {
            if (accumulator.currentPath) {
                accumulator.currentPath += `/${pathSegment}`
            } else {
                accumulator.currentPath = pathSegment
            }

            accumulator.currentDirectory = accumulator.currentDirectory.find(item => {
                return item.path === accumulator.currentPath
            }).contents

            return accumulator
        }, {
            currentDirectory: directoryListing,
            currentPath: '',
        }).currentDirectory
    }, [
        currentPath,
        directoryListing,
    ])

    const go = useCallback(path => {
        setCurrentPath(path)
    }, [setCurrentPath])

    const mapDirectoryListing = useCallback(item => {
        if (item.type === 'dir') {
            return (
                <Button
                    className="panel-block"
                    isStyled={false}
                    key={item.sha}
                    onClick={() => go(item.path)}>
                    <span className="panel-icon">
                        <FontAwesomeIcon
                            fixedWidth
                            icon="folder" />
                    </span>

                    {item.name}
                </Button>
            )
        }

        return (
            <div
                className="panel-block"
                key={item.sha}>
                <span className="panel-icon">
                    <FontAwesomeIcon
                        fixedWidth
                        icon="file" />
                </span>

                {item.name}

                <div className="panel-block-right">
                    <Button
                        className="is-small"
                        onClick={() => onSelect(item.path)}>
                        Select
                    </Button>
                </div>
            </div>
        )
    }, [])

    const sortDirectoryListing = useCallback((a, b) => {
        if (a.type === b.type) {
            return 0
        }

        if (a.type === 'dir') {
            return -1
        }

        return 1
    }, [])

    useEffect(async () => {
        const repoContents = await Github.getRepoContentsAtPath(project.link.org, project.link.repo, currentPath)
        const repoContentsJSON = await repoContents.json()
        console.log({
            repoContentsJSON,
        })
        setDirectoryListing(previousState => {
            if (!currentPath) {
                return repoContentsJSON.sort(sortDirectoryListing)
            }

            const newState = [...previousState]

            const parentDirectoryIndex = newState.findIndex(item => item.path === currentPath)
            const parentDirectory = { ...newState[parentDirectoryIndex] }

            parentDirectory.contents = repoContentsJSON
            newState[parentDirectoryIndex] = parentDirectory

            return newState
        })
    }, [currentPath])

    const directoryToList = getDirectoryToList()

    return (
        <div className="is-relative panel">
            <div className="is-sticky panel-heading">
                {title}
            </div>

            {!directoryListing && (
                <div className="panel-block">
                    {'Loading repo contents...'}
                </div>
            )}

            {(directoryListing && currentPath) && (
                <Button
                    className="panel-block"
                    isStyled={false}
                    onClick={back}>
                    <span className="panel-icon">
                        <FontAwesomeIcon
                            fixedWidth
                            icon="chevron-left" />
                    </span>
                    {'..'}
                </Button>
            )}

            {directoryToList && directoryToList.map(mapDirectoryListing)}
        </div>
    )
}

GithubExplorer.defaultProps = {
    title: 'Github Explorer!',
}

GithubExplorer.propTypes = {
    onSelect: PropTypes.func.isRequired,
    projectID: PropTypes.string.isRequired,
    title: PropTypes.string,
}





export { GithubExplorer }