├── .editorconfig ├── .github └── workflows │ └── npm-deploy.yml ├── .gitignore ├── LICENSE ├── README.md ├── package-lock.json ├── package.json ├── src ├── index.ts └── lib │ ├── branch │ ├── useBranch.ts │ └── useBranches.ts │ ├── release │ ├── useLatestRelease.ts │ └── useTaggedRelease.ts │ ├── repository │ ├── useCollaborators.ts │ └── useForks.ts │ ├── useRepos.ts │ └── useUser.ts └── tsconfig.json /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | charset = utf-8 3 | end_of_line = lf 4 | indent_size = 2 5 | indent_style = space 6 | insert_final_newline = true 7 | root = true 8 | trim_trailing_whitespace = true 9 | -------------------------------------------------------------------------------- /.github/workflows/npm-deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy to NPM 2 | 3 | on: 4 | push: 5 | branches: 6 | - releases/* 7 | 8 | jobs: 9 | publish: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@master 13 | - uses: actions/setup-node@v1 14 | with: 15 | node-version: '11.x' 16 | - name: Setup NPM 17 | run: echo '//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}'>.npmrc 18 | - name: Install NPM packages 19 | run: npm install 20 | - name: build 21 | run: npm run build 22 | - name: publish 23 | run: npm publish 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.log 3 | dist 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018-present Dominik Biedebach 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # `@d2k/react-github` 2 | 3 | > React hooks for Github API integrations 4 | 5 | > You'll need to install `react`, `react-dom`, etc at `^16.8.4` 6 | 7 | ## Links 8 | 9 | * [Open Demo](https://d2k-react-github.netlify.com/) 10 | * [Documentation](https://github.com/bdbch/react-github/wiki) 11 | 12 | ## Install 13 | 14 | ```sh 15 | npm i @d2k/react-github --save 16 | ``` 17 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@d2k/react-github", 3 | "version": "1.2.10", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@types/prop-types": { 8 | "version": "15.7.1", 9 | "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.1.tgz", 10 | "integrity": "sha512-CFzn9idOEpHrgdw8JsoTkaDDyRWk1jrzIV8djzcgpq0y9tG4B4lFT+Nxh52DVpDXV+n4+NPNv7M1Dj5uMp6XFg==", 11 | "dev": true 12 | }, 13 | "@types/react": { 14 | "version": "16.8.23", 15 | "resolved": "https://registry.npmjs.org/@types/react/-/react-16.8.23.tgz", 16 | "integrity": "sha512-abkEOIeljniUN9qB5onp++g0EY38h7atnDHxwKUFz1r3VH1+yG1OKi2sNPTyObL40goBmfKFpdii2lEzwLX1cA==", 17 | "dev": true, 18 | "requires": { 19 | "@types/prop-types": "*", 20 | "csstype": "^2.2.0" 21 | } 22 | }, 23 | "csstype": { 24 | "version": "2.6.6", 25 | "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.6.tgz", 26 | "integrity": "sha512-RpFbQGUE74iyPgvr46U9t1xoQBM8T4BL8SxrN66Le2xYAPSaDJJKeztV3awugusb3g3G9iL8StmkBBXhcbbXhg==", 27 | "dev": true 28 | }, 29 | "js-tokens": { 30 | "version": "4.0.0", 31 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 32 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", 33 | "dev": true 34 | }, 35 | "loose-envify": { 36 | "version": "1.4.0", 37 | "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", 38 | "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", 39 | "dev": true, 40 | "requires": { 41 | "js-tokens": "^3.0.0 || ^4.0.0" 42 | } 43 | }, 44 | "object-assign": { 45 | "version": "4.1.1", 46 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 47 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", 48 | "dev": true 49 | }, 50 | "prop-types": { 51 | "version": "15.7.2", 52 | "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", 53 | "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", 54 | "dev": true, 55 | "requires": { 56 | "loose-envify": "^1.4.0", 57 | "object-assign": "^4.1.1", 58 | "react-is": "^16.8.1" 59 | } 60 | }, 61 | "react": { 62 | "version": "16.8.6", 63 | "resolved": "https://registry.npmjs.org/react/-/react-16.8.6.tgz", 64 | "integrity": "sha512-pC0uMkhLaHm11ZSJULfOBqV4tIZkx87ZLvbbQYunNixAAvjnC+snJCg0XQXn9VIsttVsbZP/H/ewzgsd5fxKXw==", 65 | "dev": true, 66 | "requires": { 67 | "loose-envify": "^1.1.0", 68 | "object-assign": "^4.1.1", 69 | "prop-types": "^15.6.2", 70 | "scheduler": "^0.13.6" 71 | } 72 | }, 73 | "react-dom": { 74 | "version": "16.8.6", 75 | "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.8.6.tgz", 76 | "integrity": "sha512-1nL7PIq9LTL3fthPqwkvr2zY7phIPjYrT0jp4HjyEQrEROnw4dG41VVwi/wfoCneoleqrNX7iAD+pXebJZwrwA==", 77 | "dev": true, 78 | "requires": { 79 | "loose-envify": "^1.1.0", 80 | "object-assign": "^4.1.1", 81 | "prop-types": "^15.6.2", 82 | "scheduler": "^0.13.6" 83 | } 84 | }, 85 | "react-is": { 86 | "version": "16.8.6", 87 | "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.6.tgz", 88 | "integrity": "sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA==", 89 | "dev": true 90 | }, 91 | "scheduler": { 92 | "version": "0.13.6", 93 | "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.13.6.tgz", 94 | "integrity": "sha512-IWnObHt413ucAYKsD9J1QShUKkbKLQQHdxRyw73sw4FN26iWr3DY/H34xGPe4nmL1DwXyWmSWmMrA9TfQbE/XQ==", 95 | "dev": true, 96 | "requires": { 97 | "loose-envify": "^1.1.0", 98 | "object-assign": "^4.1.1" 99 | } 100 | }, 101 | "typescript": { 102 | "version": "3.5.3", 103 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.3.tgz", 104 | "integrity": "sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==", 105 | "dev": true 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@d2k/react-github", 3 | "version": "1.2.10", 4 | "description": "React hooks for Github API", 5 | "main": "./dist/index.js", 6 | "types": "./dist/index.d.ts", 7 | "repository": "https://github.com/bdbch/react-github", 8 | "author": "@d2k", 9 | "license": "MIT", 10 | "publishConfig": { 11 | "access": "public" 12 | }, 13 | "files": [ 14 | "dist/**/*.*" 15 | ], 16 | "keywords": [ 17 | "react", 18 | "hooks", 19 | "github" 20 | ], 21 | "scripts": { 22 | "prepublish": "npm run build", 23 | "start": "tsc --watch", 24 | "build": "npm run clean && tsc", 25 | "clean": "rm -rf ./dist" 26 | }, 27 | "devDependencies": { 28 | "@types/react": "^16.8.23", 29 | "react": "^16.8.4", 30 | "react-dom": "^16.8.4", 31 | "typescript": "^3.5.3" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import useBranch from "./lib/branch/useBranch"; 2 | import useBranches from "./lib/branch/useBranches"; 3 | import useLatestRelease from "./lib/release/useLatestRelease"; 4 | import useTaggedRelease from "./lib/release/useTaggedRelease"; 5 | import useCollaborators from "./lib/repository/useCollaborators"; 6 | import useForks from "./lib/repository/useForks"; 7 | import useRepos from "./lib/useRepos"; 8 | import useUser from "./lib/useUser"; 9 | 10 | export interface IGithubRepoPermissions { 11 | admin: boolean; 12 | push: boolean; 13 | pull: boolean; 14 | } 15 | 16 | export interface IGithubLicense { 17 | key: string; 18 | name: string; 19 | spdx_id: string; 20 | url: string; 21 | node_id: string; 22 | } 23 | 24 | export interface IGithubOrganization { 25 | login: string; 26 | id: number; 27 | node_id: string; 28 | avatar_url: string; 29 | gravatar_id: string; 30 | url: string; 31 | html_url: string; 32 | followers_url: string; 33 | following_url: string; 34 | gists_url: string; 35 | starred_url: string; 36 | subscriptions_url: string; 37 | organizations_url: string; 38 | repos_url: string; 39 | events_url: string; 40 | received_events_url: string; 41 | type: string; 42 | site_admin: boolean; 43 | } 44 | 45 | export interface IGithubBaseUser { 46 | login: string; 47 | id: number; 48 | node_id: string; 49 | avatar_url: string; 50 | gravatar_id: string; 51 | url: string; 52 | html_url: string; 53 | followers_url: string; 54 | following_url: string; 55 | gists_url: string; 56 | starred_url: string; 57 | subscriptions_url: string; 58 | organizations_url: string; 59 | repos_url: string; 60 | events_url: string; 61 | received_events_url: string; 62 | type: "User"; 63 | site_admin: boolean; 64 | } 65 | 66 | export interface IGithubUser extends IGithubBaseUser { 67 | name: string; 68 | company: string; 69 | blog: string; 70 | location: string; 71 | email: string; 72 | hireable: boolean; 73 | bio: string; 74 | public_repos: number; 75 | public_gists: number; 76 | followers: number; 77 | following: number; 78 | created_at: string; 79 | updated_at: string; 80 | } 81 | 82 | export interface IGithubRepo { 83 | id: number; 84 | node_id: string; 85 | name: string; 86 | full_name: string; 87 | owner: IGithubBaseUser; 88 | private: boolean; 89 | html_url: string; 90 | description: string; 91 | fork: boolean; 92 | url: string; 93 | archive_url: string; 94 | assignees_url: string; 95 | blobs_url: string; 96 | branches_url: string; 97 | collaborators_url: string; 98 | comments_url: string; 99 | commits_url: string; 100 | compare_url: string; 101 | contents_url: string; 102 | contributors_url: string; 103 | deployments_url: string; 104 | downloads_url: string; 105 | events_url: string; 106 | forks_url: string; 107 | git_commits_url: string; 108 | git_refs_url: string; 109 | git_tags_url: string; 110 | git_url: string; 111 | issue_comment_url: string; 112 | issue_events_url: string; 113 | issues_url: string; 114 | keys_url: string; 115 | labels_url: string; 116 | languages_url: string; 117 | merges_url: string; 118 | milestones_url: string; 119 | notifications_url: string; 120 | pulls_url: string; 121 | releases_url: string; 122 | ssh_url: string; 123 | stargazers_url: string; 124 | statuses_url: string; 125 | subscribers_url: string; 126 | subscription_url: string; 127 | tags_url: string; 128 | teams_url: string; 129 | trees_url: string; 130 | clone_url: string; 131 | mirror_url: string; 132 | hooks_url: string; 133 | svn_url: string; 134 | homepage: string; 135 | language?: string; 136 | forks_count: number; 137 | stargazers_count: number; 138 | watchers_count: number; 139 | size: number; 140 | default_branch: string; 141 | open_issues_count: number; 142 | is_template: boolean; 143 | topics: string[]; 144 | has_issues: boolean; 145 | has_projects: boolean; 146 | has_wiki: boolean; 147 | has_pages: boolean; 148 | has_downloads: boolean; 149 | archived: boolean; 150 | disabled: boolean; 151 | pushed_at: string; 152 | created_at: string; 153 | updated_at: string; 154 | permissions: IGithubRepoPermissions; 155 | allow_rebase_merge: boolean; 156 | template_repository?: string; 157 | allow_squash_merge: boolean; 158 | allow_merge_commit: boolean; 159 | subscribers_count: number; 160 | network_count: number; 161 | license: IGithubLicense; 162 | organization?: IGithubOrganization; 163 | parent?: IGithubRepo; 164 | } 165 | 166 | export interface IUserResponse { 167 | user?: IGithubUser; 168 | loading: boolean; 169 | error?: string; 170 | } 171 | 172 | export interface IReposResponse { 173 | repos?: IGithubRepo[]; 174 | loading: boolean; 175 | error?: string; 176 | } 177 | 178 | export interface IBranchResponse { 179 | branch?: any; 180 | loading: boolean; 181 | error?: string; 182 | } 183 | 184 | export interface IBranchesResponse { 185 | branches?: any[]; 186 | loading: boolean; 187 | error?: string; 188 | } 189 | 190 | export interface IReleaseResponse { 191 | release?: any; 192 | loading: boolean; 193 | error?: string; 194 | } 195 | 196 | export interface ICollaboratorsResponse { 197 | collaborators?: any[]; 198 | loading: boolean; 199 | error?: string; 200 | } 201 | 202 | export interface IForksResponse { 203 | forks?: any[]; 204 | loading: boolean; 205 | error?: string; 206 | } 207 | 208 | export { 209 | useRepos, 210 | useUser, 211 | useBranches, 212 | useBranch, 213 | useLatestRelease, 214 | useTaggedRelease, 215 | useForks, 216 | useCollaborators 217 | }; 218 | 219 | export default { 220 | useRepos, 221 | useUser, 222 | useBranches, 223 | useBranch, 224 | useLatestRelease, 225 | useTaggedRelease, 226 | useForks, 227 | useCollaborators 228 | }; 229 | -------------------------------------------------------------------------------- /src/lib/branch/useBranch.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | 3 | import { IBranchResponse } from "../.."; 4 | 5 | export default function useBranch( 6 | owner: string, 7 | repo: string, 8 | branchName: string 9 | ): IBranchResponse { 10 | const [branch, setBranch] = useState(); 11 | const [loading, setLoading] = useState(false); 12 | const [error, setError] = useState(); 13 | 14 | if (!owner || !repo || !branchName) return { branch, loading, error }; 15 | 16 | useEffect(() => { 17 | if ( 18 | repo && 19 | repo.length > 0 && 20 | owner && 21 | owner.length && 22 | branchName && 23 | branchName.length > 0 24 | ) { 25 | setLoading(true); 26 | setError(undefined); 27 | fetch( 28 | `https://api.github.com/repos/${owner}/${repo}/branches/${branchName}` 29 | ) 30 | .then(res => res.json()) 31 | .then(data => { 32 | setLoading(false); 33 | setBranch(data); 34 | setError(undefined); 35 | }) 36 | .catch(e => { 37 | setLoading(false); 38 | setBranch(null); 39 | setError(e); 40 | }); 41 | } 42 | }, [owner, repo, branchName]); 43 | 44 | return { 45 | branch, 46 | loading, 47 | error 48 | }; 49 | } 50 | -------------------------------------------------------------------------------- /src/lib/branch/useBranches.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | 3 | import { IBranchesResponse } from "../.."; 4 | 5 | export default function useBranches( 6 | owner: string, 7 | repo: string 8 | ): IBranchesResponse { 9 | const [branches, setBranches] = useState([]); 10 | const [loading, setLoading] = useState(false); 11 | const [error, setError] = useState(); 12 | 13 | if (!owner || !repo) return { branches, loading, error }; 14 | 15 | useEffect(() => { 16 | if (repo && repo.length > 0 && owner && owner.length) { 17 | setLoading(true); 18 | setError(undefined); 19 | fetch(`https://api.github.com/repos/${owner}/${repo}/branches`) 20 | .then(res => res.json()) 21 | .then(data => { 22 | setLoading(false); 23 | setBranches(data); 24 | setError(undefined); 25 | }) 26 | .catch(e => { 27 | setLoading(false); 28 | setBranches([]); 29 | setError(e); 30 | }); 31 | } 32 | }, [owner, repo]); 33 | 34 | return { 35 | branches, 36 | loading, 37 | error 38 | }; 39 | } 40 | -------------------------------------------------------------------------------- /src/lib/release/useLatestRelease.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | 3 | import { IReleaseResponse } from "../.."; 4 | 5 | export default function useLatestRelease( 6 | owner: string, 7 | repo: string 8 | ): IReleaseResponse { 9 | const [release, setRelease] = useState(); 10 | const [loading, setLoading] = useState(false); 11 | const [error, setError] = useState(); 12 | 13 | if (!owner || !repo) return { release, loading, error }; 14 | 15 | useEffect(() => { 16 | if (owner && owner.length > 0 && repo && repo.length > 0) { 17 | setError(undefined); 18 | setLoading(true); 19 | 20 | fetch(`https://api.github.com/repos/${owner}/${repo}/releases/latest`) 21 | .then(res => res.json()) 22 | .then(data => { 23 | setLoading(false); 24 | setRelease(data); 25 | }) 26 | .catch(e => { 27 | setLoading(false); 28 | setRelease(null); 29 | setError(e); 30 | }); 31 | } 32 | }, [owner, repo]); 33 | 34 | return { 35 | release, 36 | loading, 37 | error 38 | }; 39 | } 40 | -------------------------------------------------------------------------------- /src/lib/release/useTaggedRelease.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | 3 | import { IReleaseResponse } from "../.."; 4 | 5 | export default function useTaggedRelease( 6 | owner: string, 7 | repo: string, 8 | tag: string 9 | ): IReleaseResponse { 10 | const [release, setRelease] = useState(); 11 | const [loading, setLoading] = useState(false); 12 | const [error, setError] = useState(); 13 | 14 | if (!owner || !repo || !tag) return { release, loading, error }; 15 | 16 | useEffect(() => { 17 | if ( 18 | owner && 19 | owner.length > 0 && 20 | repo && 21 | repo.length > 0 && 22 | tag && 23 | tag.length > 0 24 | ) { 25 | setError(undefined); 26 | setLoading(true); 27 | 28 | fetch( 29 | `https://api.github.com/repos/${owner}/${repo}/releases/tags/${tag}` 30 | ) 31 | .then(res => res.json()) 32 | .then(data => { 33 | setLoading(false); 34 | setRelease(data); 35 | }) 36 | .catch(e => { 37 | setLoading(false); 38 | setRelease(null); 39 | setError(e); 40 | }); 41 | } 42 | }, [owner, repo]); 43 | 44 | return { 45 | release, 46 | loading, 47 | error 48 | }; 49 | } 50 | -------------------------------------------------------------------------------- /src/lib/repository/useCollaborators.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | 3 | import { ICollaboratorsResponse } from "../.."; 4 | 5 | export default function useCollaborators( 6 | owner: string, 7 | repo: string 8 | ): ICollaboratorsResponse { 9 | const [collaborators, setCollaborators] = useState([]); 10 | const [loading, setLoading] = useState(false); 11 | const [error, setError] = useState(); 12 | 13 | if (!owner || !repo) return { collaborators, loading, error }; 14 | 15 | useEffect(() => { 16 | if (repo && repo.length > 0 && owner && owner.length) { 17 | setLoading(true); 18 | setError(undefined); 19 | fetch(`https://api.github.com/repos/${owner}/${repo}/collaborators`) 20 | .then(res => res.json()) 21 | .then(data => { 22 | setLoading(false); 23 | setCollaborators(data); 24 | setError(undefined); 25 | }) 26 | .catch(e => { 27 | setLoading(false); 28 | setCollaborators([]); 29 | setError(e); 30 | }); 31 | } 32 | }, [owner, repo]); 33 | 34 | return { 35 | collaborators, 36 | loading, 37 | error 38 | }; 39 | } 40 | -------------------------------------------------------------------------------- /src/lib/repository/useForks.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | 3 | import { IForksResponse } from "../.."; 4 | 5 | export default function useForks(owner: string, repo: string): IForksResponse { 6 | const [forks, setForks] = useState([]); 7 | const [loading, setLoading] = useState(false); 8 | const [error, setError] = useState(); 9 | 10 | useEffect(() => { 11 | if (repo && repo.length > 0 && owner && owner.length) { 12 | setLoading(true); 13 | setError(undefined); 14 | fetch(`https://api.github.com/repos/${owner}/${repo}/forks`) 15 | .then(res => res.json()) 16 | .then(data => { 17 | setLoading(false); 18 | setForks(data); 19 | setError(undefined); 20 | }) 21 | .catch(e => { 22 | setLoading(false); 23 | setForks([]); 24 | setError(e); 25 | }); 26 | } 27 | }, [owner, repo]); 28 | 29 | return { 30 | forks, 31 | loading, 32 | error 33 | }; 34 | } 35 | -------------------------------------------------------------------------------- /src/lib/useRepos.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | 3 | import { IGithubRepo, IReposResponse } from ".."; 4 | 5 | export default function useRepos(githubUserName: string): IReposResponse { 6 | const [repos, setRepos] = useState([]); 7 | const [loading, setLoading] = useState(false); 8 | const [error, setError] = useState(); 9 | 10 | if (!githubUserName) return { repos, loading, error }; 11 | 12 | useEffect(() => { 13 | setLoading(true); 14 | fetch(`https://api.github.com/users/${githubUserName}/repos`) 15 | .then(res => res.json()) 16 | .then(data => { 17 | setLoading(false); 18 | setRepos(data); 19 | }) 20 | .catch(err => { 21 | setRepos([]); 22 | setError(err); 23 | }); 24 | }, [githubUserName]); 25 | 26 | return { 27 | repos, 28 | loading, 29 | error 30 | }; 31 | } 32 | -------------------------------------------------------------------------------- /src/lib/useUser.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | 3 | import { IGithubUser, IUserResponse } from ".."; 4 | 5 | export default function useUser(githubUserName: string): IUserResponse { 6 | const [user, setUser] = useState(); 7 | const [loading, setLoading] = useState(false); 8 | const [error, setError] = useState(); 9 | 10 | if (!githubUserName) return { user, loading, error }; 11 | 12 | useEffect(() => { 13 | setLoading(true); 14 | fetch(`https://api.github.com/users/${githubUserName}`) 15 | .then(res => res.json()) 16 | .then(data => { 17 | setLoading(false); 18 | setUser(data); 19 | }) 20 | .catch(err => { 21 | setUser(undefined); 22 | setError(err); 23 | }); 24 | }, [githubUserName]); 25 | 26 | return { 27 | user, 28 | loading, 29 | error 30 | }; 31 | } 32 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Basic Options */ 4 | // "incremental": true, /* Enable incremental compilation */ 5 | "target": "es5", 6 | /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */ 7 | "module": "commonjs", 8 | /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ 9 | "lib": ["dom", "es2015"], 10 | /* Specify library files to be included in the compilation. */ 11 | "allowJs": false, 12 | /* Allow javascript files to be compiled. */ 13 | "checkJs": false, 14 | /* Report errors in .js files. */ 15 | "jsx": "react", 16 | /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 17 | "declaration": true, 18 | /* Generates corresponding '.d.ts' file. */ 19 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 20 | // "sourceMap": true, /* Generates corresponding '.map' file. */ 21 | // "outFile": "./", /* Concatenate and emit output to single file. */ 22 | "outDir": "./dist", 23 | /* Redirect output structure to the directory. */ 24 | "rootDir": "./src", 25 | /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 26 | // "composite": true, /* Enable project compilation */ 27 | // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ 28 | // "removeComments": true, /* Do not emit comments to output. */ 29 | // "noEmit": true, /* Do not emit outputs. */ 30 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 31 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 32 | "isolatedModules": false, 33 | /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 34 | 35 | /* Strict Type-Checking Options */ 36 | "strict": true, 37 | /* Enable all strict type-checking options. */ 38 | "noImplicitAny": true, 39 | /* Raise error on expressions and declarations with an implied 'any' type. */ 40 | "strictNullChecks": true, 41 | /* Enable strict null checks. */ 42 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */ 43 | // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ 44 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ 45 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 46 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 47 | 48 | /* Additional Checks */ 49 | // "noUnusedLocals": true, /* Report errors on unused locals. */ 50 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 51 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 52 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 53 | 54 | /* Module Resolution Options */ 55 | "moduleResolution": "node", 56 | /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 57 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 58 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 59 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 60 | // "typeRoots": [], /* List of folders to include type definitions from. */ 61 | // "types": [], /* Type declaration files to be included in compilation. */ 62 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 63 | "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 64 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 65 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 66 | 67 | /* Source Map Options */ 68 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 69 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 70 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 71 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 72 | 73 | /* Experimental Options */ 74 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 75 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 76 | } 77 | } 78 | --------------------------------------------------------------------------------