mirror of
https://github.com/rjNemo/devbook_ts
synced 2026-06-06 02:36:39 +00:00
🐙 GitHub (#13)
* edit package.json * eslint * fetch git repos * create repo array on fetch * update repo array on profile edit * edit profile presentation
This commit is contained in:
parent
4880d2853d
commit
191130a7ad
12 changed files with 944 additions and 633 deletions
6
.eslintignore
Normal file
6
.eslintignore
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
# don't ever lint node_modules
|
||||||
|
node_modules
|
||||||
|
# don't lint build output (make sure it's set to your correct build folder name)
|
||||||
|
build
|
||||||
|
# don't lint nyc coverage output
|
||||||
|
coverage
|
||||||
74
.eslintrc.js
74
.eslintrc.js
|
|
@ -1,19 +1,79 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
extends: ["react-app", "prettier"],
|
extends: [
|
||||||
plugins: ["prettier", "jest", "cypress"],
|
'react-app',
|
||||||
parser: "babel-eslint",
|
'prettier',
|
||||||
|
'eslint:recommended',
|
||||||
|
'plugin:@typescript-eslint/eslint-recommended',
|
||||||
|
'plugin:@typescript-eslint/recommended',
|
||||||
|
'airbnb-typescript',
|
||||||
|
],
|
||||||
|
plugins: ['prettier', 'jest', 'cypress', '@typescript-eslint'],
|
||||||
|
// parser: 'babel-eslint',
|
||||||
|
parser: '@typescript-eslint/parser',
|
||||||
|
parserOptions: {
|
||||||
|
project: './tsconfig.json',
|
||||||
|
},
|
||||||
env: {
|
env: {
|
||||||
browser: true,
|
browser: true,
|
||||||
"cypress/globals": true,
|
'cypress/globals': true,
|
||||||
es6: true,
|
es6: true,
|
||||||
"jest/globals": true,
|
'jest/globals': true,
|
||||||
},
|
},
|
||||||
settings: {
|
settings: {
|
||||||
react: {
|
react: {
|
||||||
version: "detect",
|
version: 'detect',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
"prettier/prettier": "warn",
|
'prettier/prettier': 'warn',
|
||||||
|
'adjacent-overload-signatures': true,
|
||||||
|
'ban-comma-operator': true,
|
||||||
|
'no-namespace': true,
|
||||||
|
'no-parameter-reassignment': true,
|
||||||
|
'no-reference': true,
|
||||||
|
'no-unnecessary-type-assertion': true,
|
||||||
|
'label-position': true,
|
||||||
|
'no-conditional-assignment': true,
|
||||||
|
'no-construct': true,
|
||||||
|
'no-duplicate-super': true,
|
||||||
|
'no-duplicate-switch-case': true,
|
||||||
|
'no-duplicate-variable': [true, 'check-parameters'],
|
||||||
|
'no-shadowed-variable': true,
|
||||||
|
'no-empty': [true, 'allow-empty-catch'],
|
||||||
|
'no-floating-promises': true,
|
||||||
|
'no-implicit-dependencies': true,
|
||||||
|
'no-invalid-this': true,
|
||||||
|
'no-string-throw': true,
|
||||||
|
'no-unsafe-finally': true,
|
||||||
|
'no-void-expression': [true, 'ignore-arrow-function-shorthand'],
|
||||||
|
'no-duplicate-imports': true,
|
||||||
|
// Warn when an empty interface is defined. These are generally not useful.
|
||||||
|
'no-empty-interface': {
|
||||||
|
severity: 'warning',
|
||||||
|
},
|
||||||
|
'no-import-side-effect': {
|
||||||
|
severity: 'warning',
|
||||||
|
},
|
||||||
|
'no-var-keyword': {
|
||||||
|
severity: 'warning',
|
||||||
|
},
|
||||||
|
'triple-equals': {
|
||||||
|
severity: 'warning',
|
||||||
|
},
|
||||||
|
deprecation: {
|
||||||
|
severity: 'warning',
|
||||||
|
},
|
||||||
|
'prefer-for-of': {
|
||||||
|
severity: 'warning',
|
||||||
|
},
|
||||||
|
'unified-signatures': {
|
||||||
|
severity: 'warning',
|
||||||
|
},
|
||||||
|
'prefer-const': {
|
||||||
|
severity: 'warning',
|
||||||
|
},
|
||||||
|
'trailing-comma': {
|
||||||
|
severity: 'warning',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
||||||
13
package.json
13
package.json
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "client",
|
"name": "devbook",
|
||||||
"version": "0.1.0",
|
"version": "1.0.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fortawesome/fontawesome-free": "^5.13.0",
|
"@fortawesome/fontawesome-free": "^5.13.0",
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
"@fortawesome/free-regular-svg-icons": "^5.13.0",
|
"@fortawesome/free-regular-svg-icons": "^5.13.0",
|
||||||
"@fortawesome/free-solid-svg-icons": "^5.13.0",
|
"@fortawesome/free-solid-svg-icons": "^5.13.0",
|
||||||
"@fortawesome/react-fontawesome": "^0.1.9",
|
"@fortawesome/react-fontawesome": "^0.1.9",
|
||||||
|
"@octokit/rest": "^17.9.2",
|
||||||
"@reduxjs/toolkit": "^1.3.6",
|
"@reduxjs/toolkit": "^1.3.6",
|
||||||
"@testing-library/jest-dom": "^4.2.4",
|
"@testing-library/jest-dom": "^4.2.4",
|
||||||
"@testing-library/react": "^9.3.2",
|
"@testing-library/react": "^9.3.2",
|
||||||
|
|
@ -19,7 +20,13 @@
|
||||||
"@types/react-dom": "^16.9.0",
|
"@types/react-dom": "^16.9.0",
|
||||||
"@types/react-redux": "^7.1.8",
|
"@types/react-redux": "^7.1.8",
|
||||||
"@types/react-router-dom": "^5.1.5",
|
"@types/react-router-dom": "^5.1.5",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^2.34.0",
|
||||||
|
"@typescript-eslint/parser": "^2.34.0",
|
||||||
"cypress": "^4.5.0",
|
"cypress": "^4.5.0",
|
||||||
|
"eslint-plugin-import": "^2.20.2",
|
||||||
|
"eslint-plugin-jsx-a11y": "^6.2.3",
|
||||||
|
"eslint-plugin-react": "^7.20.0",
|
||||||
|
"eslint-plugin-react-hooks": "^4.0.2",
|
||||||
"firebase": "^7.14.3",
|
"firebase": "^7.14.3",
|
||||||
"moment": "^2.25.3",
|
"moment": "^2.25.3",
|
||||||
"react": "^16.13.1",
|
"react": "^16.13.1",
|
||||||
|
|
@ -54,4 +61,4 @@
|
||||||
"last 1 safari version"
|
"last 1 safari version"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -128,7 +128,7 @@ export const dummyDev: IDev = {
|
||||||
name: 'Repo #1',
|
name: 'Repo #1',
|
||||||
description:
|
description:
|
||||||
'Lorem ipsum dolor sit amet consectetur adipisicing elit. Fugit,deserunt.',
|
'Lorem ipsum dolor sit amet consectetur adipisicing elit. Fugit,deserunt.',
|
||||||
link: '#',
|
url: '#',
|
||||||
stars: 42,
|
stars: 42,
|
||||||
watchers: 2,
|
watchers: 2,
|
||||||
forks: 4,
|
forks: 4,
|
||||||
|
|
@ -137,7 +137,7 @@ export const dummyDev: IDev = {
|
||||||
name: 'Repo #2',
|
name: 'Repo #2',
|
||||||
description:
|
description:
|
||||||
'Lorem ipsum dolor sit amet consectetur adipisicing elit. Fugit,deserunt.',
|
'Lorem ipsum dolor sit amet consectetur adipisicing elit. Fugit,deserunt.',
|
||||||
link: '#',
|
url: '#',
|
||||||
stars: 21,
|
stars: 21,
|
||||||
watchers: 1,
|
watchers: 1,
|
||||||
forks: 2,
|
forks: 2,
|
||||||
|
|
@ -146,7 +146,7 @@ export const dummyDev: IDev = {
|
||||||
name: 'Repo #3',
|
name: 'Repo #3',
|
||||||
description:
|
description:
|
||||||
'Lorem ipsum dolor sit amet consectetur adipisicing elit. Fugit,deserunt.',
|
'Lorem ipsum dolor sit amet consectetur adipisicing elit. Fugit,deserunt.',
|
||||||
link: '#',
|
url: '#',
|
||||||
stars: 50,
|
stars: 50,
|
||||||
watchers: 32,
|
watchers: 32,
|
||||||
forks: 12,
|
forks: 12,
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ import Alert from '../components/Alert';
|
||||||
import Statuses from '../constants/statuses';
|
import Statuses from '../constants/statuses';
|
||||||
// Form
|
// Form
|
||||||
import useForm from '../hooks';
|
import useForm from '../hooks';
|
||||||
|
import getGithubRepos from '../services/github';
|
||||||
// Typing
|
// Typing
|
||||||
import Dev from '../models/Dev';
|
import Dev from '../models/Dev';
|
||||||
import User from '../models/User';
|
import User from '../models/User';
|
||||||
|
|
@ -75,7 +76,7 @@ const EditProfile: FC<IProps> = ({
|
||||||
const {formData, handleChange} = useForm<FormData>(initFormData);
|
const {formData, handleChange} = useForm<FormData>(initFormData);
|
||||||
|
|
||||||
/** construct profile object from formData */
|
/** construct profile object from formData */
|
||||||
const makeProfile = ({
|
const makeProfile = async ({
|
||||||
status,
|
status,
|
||||||
company,
|
company,
|
||||||
location,
|
location,
|
||||||
|
|
@ -99,6 +100,7 @@ const EditProfile: FC<IProps> = ({
|
||||||
youtube: parseLink(youtube),
|
youtube: parseLink(youtube),
|
||||||
};
|
};
|
||||||
const newSkills: string[] = skills?.split(',');
|
const newSkills: string[] = skills?.split(',');
|
||||||
|
const newRepos = await getGithubRepos(github);
|
||||||
return {
|
return {
|
||||||
status,
|
status,
|
||||||
company,
|
company,
|
||||||
|
|
@ -107,12 +109,13 @@ const EditProfile: FC<IProps> = ({
|
||||||
github,
|
github,
|
||||||
links: newLinks,
|
links: newLinks,
|
||||||
skills: newSkills,
|
skills: newSkills,
|
||||||
|
repos: newRepos,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSubmit = (e: React.FormEvent<HTMLFormElement>): void => {
|
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const updatedDev = makeProfile(formData);
|
const updatedDev = await makeProfile(formData);
|
||||||
try {
|
try {
|
||||||
firebase.updateProfile(updatedDev, {useSet: true, merge: true});
|
firebase.updateProfile(updatedDev, {useSet: true, merge: true});
|
||||||
setAlert({
|
setAlert({
|
||||||
|
|
@ -122,6 +125,7 @@ const EditProfile: FC<IProps> = ({
|
||||||
'Profile successfully updated. You may go back to your dashboard.',
|
'Profile successfully updated. You may go back to your dashboard.',
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
setAlert({...alert, show: true});
|
setAlert({...alert, show: true});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
|
||||||
import {faThumbsUp} from '@fortawesome/free-solid-svg-icons';
|
import {faThumbsUp} from '@fortawesome/free-solid-svg-icons';
|
||||||
import Header from '../components/Header';
|
import Header from '../components/Header';
|
||||||
// Typing
|
// Typing
|
||||||
import Post, {dummyPost as post} from '../models/Post';
|
import Post from '../models/Post';
|
||||||
import Collections from '../constants/collections';
|
import Collections from '../constants/collections';
|
||||||
|
|
||||||
interface IProps extends WithFirestoreProps {
|
interface IProps extends WithFirestoreProps {
|
||||||
|
|
|
||||||
|
|
@ -46,9 +46,6 @@ const Profile: FC<IProps> = ({dev}) => {
|
||||||
return <NotFound />;
|
return <NotFound />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const fn = dev?.description;
|
|
||||||
console.log(fn);
|
|
||||||
|
|
||||||
/** return the icon corresponding to the social name */
|
/** return the icon corresponding to the social name */
|
||||||
const renderSocialIcon = (name: string): IconDefinition => {
|
const renderSocialIcon = (name: string): IconDefinition => {
|
||||||
switch (name) {
|
switch (name) {
|
||||||
|
|
@ -192,23 +189,23 @@ const Profile: FC<IProps> = ({dev}) => {
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
dev.repos.map((r: Repo, i: number) => (
|
dev.repos.map((r: Repo, i: number) => (
|
||||||
<div className="repo bg-white my-1 p-1">
|
<div className="repo bg-white my-1 p-1" key={i}>
|
||||||
<div>
|
<div>
|
||||||
<h4>
|
<h4>
|
||||||
<a href={r.link}>{r.name}</a>
|
<a href={r.url}>{r.name}</a>
|
||||||
</h4>
|
</h4>
|
||||||
<p>{r.description}</p>
|
<p>{r.description}</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<ul>
|
<ul>
|
||||||
<li className="badge badge-primary">
|
<li className="badge badge-primary">
|
||||||
<FontAwesomeIcon icon={faStar} /> Stars: 42
|
<FontAwesomeIcon icon={faStar} /> Stars: {r.stars}
|
||||||
</li>
|
</li>
|
||||||
<li className="badge badge-dark">
|
<li className="badge badge-dark">
|
||||||
<FontAwesomeIcon icon={faEye} /> Watchers: 2
|
<FontAwesomeIcon icon={faEye} /> Watchers: {r.watchers}
|
||||||
</li>
|
</li>
|
||||||
<li className="badge badge-light">
|
<li className="badge badge-light">
|
||||||
<FontAwesomeIcon icon={faCodeBranch} /> Forks: 4
|
<FontAwesomeIcon icon={faCodeBranch} /> Forks: {r.forks}
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
35
src/services/github/index.ts
Normal file
35
src/services/github/index.ts
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
// Github
|
||||||
|
import {Octokit} from '@octokit/rest';
|
||||||
|
import Repo from '../../types/Repo';
|
||||||
|
|
||||||
|
/** official GitHub wrapper library */
|
||||||
|
const octokit = new Octokit({
|
||||||
|
auth: process.env.REACT_APP_GITHUB_TOKEN,
|
||||||
|
userAgent: 'devBook v1',
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fetch one user github repos and create a
|
||||||
|
* @param owner githubusername
|
||||||
|
* @returns a Repo array or undefined
|
||||||
|
*/
|
||||||
|
const getGithubRepos = async (owner: string) => {
|
||||||
|
try {
|
||||||
|
const {data: repos} = await octokit.repos.listForAuthenticatedUser({
|
||||||
|
owner,
|
||||||
|
});
|
||||||
|
const newRepo: Repo[] = repos.map((r: any) => ({
|
||||||
|
url: r.url,
|
||||||
|
stars: r.stargazers_count,
|
||||||
|
forks: r.forks_count,
|
||||||
|
description: r.description,
|
||||||
|
name: r.name,
|
||||||
|
watchers: r.watchers_count,
|
||||||
|
}));
|
||||||
|
return newRepo;
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default getGithubRepos;
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
interface Repo {
|
interface Repo {
|
||||||
name: string;
|
name: string;
|
||||||
description: string;
|
description: string;
|
||||||
link: string;
|
url: string;
|
||||||
stars: number;
|
stars: number;
|
||||||
watchers: number;
|
watchers: number;
|
||||||
forks: number;
|
forks: number;
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,7 @@
|
||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es5",
|
"target": "es2017",
|
||||||
"lib": [
|
"lib": ["dom", "dom.iterable", "esnext"],
|
||||||
"dom",
|
|
||||||
"dom.iterable",
|
|
||||||
"esnext"
|
|
||||||
],
|
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
|
|
@ -19,7 +15,5 @@
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"jsx": "react"
|
"jsx": "react"
|
||||||
},
|
},
|
||||||
"include": [
|
"include": ["src"]
|
||||||
"src"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
63
tslint.json
63
tslint.json
|
|
@ -1,63 +0,0 @@
|
||||||
{
|
|
||||||
"rules": {
|
|
||||||
"adjacent-overload-signatures": true,
|
|
||||||
"ban-comma-operator": true,
|
|
||||||
"no-namespace": true,
|
|
||||||
"no-parameter-reassignment": true,
|
|
||||||
"no-reference": true,
|
|
||||||
"no-unnecessary-type-assertion": true,
|
|
||||||
"label-position": true,
|
|
||||||
"no-conditional-assignment": true,
|
|
||||||
"no-construct": true,
|
|
||||||
"no-duplicate-super": true,
|
|
||||||
"no-duplicate-switch-case": true,
|
|
||||||
"no-duplicate-variable": [
|
|
||||||
true,
|
|
||||||
"check-parameters"
|
|
||||||
],
|
|
||||||
"no-shadowed-variable": true,
|
|
||||||
"no-empty": [
|
|
||||||
true,
|
|
||||||
"allow-empty-catch"
|
|
||||||
],
|
|
||||||
"no-floating-promises": true,
|
|
||||||
"no-implicit-dependencies": true,
|
|
||||||
"no-invalid-this": true,
|
|
||||||
"no-string-throw": true,
|
|
||||||
"no-unsafe-finally": true,
|
|
||||||
"no-void-expression": [
|
|
||||||
true,
|
|
||||||
"ignore-arrow-function-shorthand"
|
|
||||||
],
|
|
||||||
"no-duplicate-imports": true,
|
|
||||||
// Warn when an empty interface is defined. These are generally not useful.
|
|
||||||
"no-empty-interface": {
|
|
||||||
"severity": "warning"
|
|
||||||
},
|
|
||||||
"no-import-side-effect": {
|
|
||||||
"severity": "warning"
|
|
||||||
},
|
|
||||||
"no-var-keyword": {
|
|
||||||
"severity": "warning"
|
|
||||||
},
|
|
||||||
"triple-equals": {
|
|
||||||
"severity": "warning"
|
|
||||||
},
|
|
||||||
"deprecation": {
|
|
||||||
"severity": "warning"
|
|
||||||
},
|
|
||||||
"prefer-for-of": {
|
|
||||||
"severity": "warning"
|
|
||||||
},
|
|
||||||
"unified-signatures": {
|
|
||||||
"severity": "warning"
|
|
||||||
},
|
|
||||||
"prefer-const": {
|
|
||||||
"severity": "warning"
|
|
||||||
},
|
|
||||||
"trailing-comma": {
|
|
||||||
"severity": "warning"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"defaultSeverity": "error"
|
|
||||||
}
|
|
||||||
Loading…
Reference in a new issue