Skip to content

Commit aa56684

Browse files
committed
typescript
1 parent d1ab7df commit aa56684

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

94 files changed

+4924
-0
lines changed

typescript-1/.babelrc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"plugins": ["@babel/plugin-proposal-class-properties"]
3+
}

typescript-1/.eslintrc.json

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
{
2+
"extends": [
3+
"eslint:recommended",
4+
"plugin:import/errors",
5+
"plugin:react/recommended",
6+
"plugin:jsx-a11y/recommended",
7+
"plugin:react-hooks/recommended",
8+
"plugin:@typescript-eslint/recommended",
9+
"prettier"
10+
],
11+
"rules": {
12+
"react/prop-types": 0,
13+
"react/react-in-jsx-scope": 0,
14+
"@typescript-eslint/no-empty-function": 0
15+
},
16+
"plugins": ["react", "import", "jsx-a11y", "@typescript-eslint"],
17+
"parser": "@typescript-eslint/parser",
18+
"parserOptions": {
19+
"ecmaVersion": 2022,
20+
"sourceType": "module",
21+
"ecmaFeatures": {
22+
"jsx": true
23+
}
24+
},
25+
"env": {
26+
"es6": true,
27+
"browser": true,
28+
"node": true
29+
},
30+
"settings": {
31+
"import/parsers": {
32+
"@typescript-eslint/parser": [".ts", ".tsx"]
33+
},
34+
"import/resolver": {
35+
"typescript": {
36+
"alwaysTryTypes": true
37+
}
38+
},
39+
"react": {
40+
"version": "detect"
41+
}
42+
}
43+
}

typescript-1/.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
node_modules
2+
.parcel-cache/
3+
dist/
4+
.env
5+
.DS_Store
6+
coverage/
7+
.vscode/

typescript-1/.prettierrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{}

typescript-1/package.json

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
{
2+
"name": "adopt-me",
3+
"version": "7.0.0",
4+
"description": "Adopt pets via adopt-me",
5+
"main": "src/App.js",
6+
"scripts": {
7+
"dev": "parcel src/index.html",
8+
"format": "prettier --write \"src/**/*.{js,jsx}\"",
9+
"lint": "eslint \"src/**/*.{js,jsx}\" --quiet"
10+
},
11+
"author": "Brian Holt <btholt+citr-v7-project@gmail.com>",
12+
"license": "Apache-2.0",
13+
"devDependencies": {
14+
"@babel/plugin-proposal-class-properties": "7.16.7",
15+
"@types/react": "17.0.39",
16+
"@types/react-dom": "17.0.11",
17+
"@typescript-eslint/eslint-plugin": "^5.12.0",
18+
"@typescript-eslint/parser": "^5.12.0",
19+
"eslint": "8.8.0",
20+
"eslint-config-prettier": "8.3.0",
21+
"eslint-import-resolver-typescript": "^2.5.0",
22+
"eslint-plugin-import": "2.25.4",
23+
"eslint-plugin-jsx-a11y": "^6.5.1",
24+
"eslint-plugin-react": "^7.28.0",
25+
"eslint-plugin-react-hooks": "4.3.0",
26+
"parcel": "2.2.1",
27+
"prettier": "2.5.1",
28+
"typescript": "4.5.5"
29+
},
30+
"dependencies": {
31+
"react": "17.0.2",
32+
"react-dom": "17.0.2",
33+
"react-router-dom": "^6.2.1"
34+
},
35+
"browserslist": [
36+
"last 2 Chrome versions"
37+
]
38+
}

typescript-1/src/App.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { render } from "react-dom";
2+
import SearchParams from "./SearchParams";
3+
import { StrictMode, useState } from "react";
4+
import { BrowserRouter, Routes, Route, Link } from "react-router-dom";
5+
import Details from "./Details";
6+
import ThemeContext from "./ThemeContext";
7+
8+
const App = () => {
9+
const theme = useState("darkblue");
10+
return (
11+
<StrictMode>
12+
<ThemeContext.Provider value={theme}>
13+
<BrowserRouter>
14+
<header>
15+
<Link to="/">Adopt Me!</Link>
16+
</header>
17+
<Routes>
18+
<Route path="/details/:id" element={<Details />} />
19+
<Route path="/" element={<SearchParams />} />
20+
</Routes>
21+
</BrowserRouter>
22+
</ThemeContext.Provider>
23+
</StrictMode>
24+
);
25+
};
26+
27+
render(<App />, document.getElementById("root"));

typescript-1/src/Carousel.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { Component } from "react";
2+
3+
class Carousel extends Component {
4+
state = {
5+
active: 0,
6+
};
7+
8+
static defaultProps = {
9+
images: ["http://pets-images.dev-apis.com/pets/none.jpg"],
10+
};
11+
12+
handleIndexClick = (event) => {
13+
this.setState({
14+
active: +event.target.dataset.index,
15+
});
16+
};
17+
18+
render() {
19+
const { active } = this.state;
20+
const { images } = this.props;
21+
return (
22+
<div className="carousel">
23+
<img src={images[active]} alt="animal" />
24+
<div className="carousel-smaller">
25+
{images.map((photo, index) => (
26+
// eslint-disable-next-line
27+
<img
28+
key={photo}
29+
src={photo}
30+
className={index === active ? "active" : ""}
31+
alt="animal thumbnail"
32+
onClick={this.handleIndexClick}
33+
data-index={index}
34+
/>
35+
))}
36+
</div>
37+
</div>
38+
);
39+
}
40+
}
41+
42+
export default Carousel;

typescript-1/src/Details.js

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { Component } from "react";
2+
import { useParams } from "react-router-dom";
3+
import Carousel from "./Carousel";
4+
import ErrorBoundary from "./ErrorBoundary";
5+
import ThemeContext from "./ThemeContext";
6+
import Modal from "./Modal";
7+
8+
class Details extends Component {
9+
state = { loading: true, showModal: false };
10+
11+
async componentDidMount() {
12+
const res = await fetch(
13+
`http://pets-v2.dev-apis.com/pets?id=${this.props.params.id}`
14+
);
15+
const json = await res.json();
16+
this.setState(Object.assign({ loading: false }, json.pets[0]));
17+
}
18+
toggleModal = () => this.setState({ showModal: !this.state.showModal });
19+
adopt = () => (window.location = "http://bit.ly/pet-adopt");
20+
render() {
21+
if (this.state.loading) {
22+
return <h2>loading … </h2>;
23+
}
24+
25+
const { animal, breed, city, state, description, name, images, showModal } =
26+
this.state;
27+
28+
return (
29+
<div className="details">
30+
<Carousel images={images} />
31+
<div>
32+
<h1>{name}</h1>
33+
<h2>{`${animal}${breed}${city}, ${state}`}</h2>
34+
<ThemeContext.Consumer>
35+
{([theme]) => (
36+
<button
37+
onClick={this.toggleModal}
38+
style={{ backgroundColor: theme }}
39+
>
40+
Adopt {name}
41+
</button>
42+
)}
43+
</ThemeContext.Consumer>
44+
<p>{description}</p>
45+
{showModal ? (
46+
<Modal>
47+
<div>
48+
<h1>Would you like to adopt {name}?</h1>
49+
<div className="buttons">
50+
<a href="https://bit.ly/pet-adopt">Yes</a>
51+
<button onClick={this.toggleModal}>No</button>
52+
</div>
53+
</div>
54+
</Modal>
55+
) : null}
56+
</div>
57+
</div>
58+
);
59+
}
60+
}
61+
62+
const WrappedDetails = () => {
63+
const params = useParams();
64+
return (
65+
<ErrorBoundary>
66+
<Details params={params} />
67+
</ErrorBoundary>
68+
);
69+
};
70+
71+
export default WrappedDetails;

typescript-1/src/ErrorBoundary.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// mostly code from reactjs.org/docs/error-boundaries.html
2+
import { Component } from "react";
3+
import { Link, Navigate } from "react-router-dom";
4+
5+
class ErrorBoundary extends Component {
6+
state = { hasError: false, redirect: false };
7+
static getDerivedStateFromError() {
8+
return { hasError: true };
9+
}
10+
componentDidCatch(error, info) {
11+
console.error("ErrorBoundary caught an error", error, info);
12+
}
13+
componentDidUpdate() {
14+
if (this.state.hasError) {
15+
setTimeout(() => this.setState({ redirect: true }), 5000);
16+
}
17+
}
18+
render() {
19+
if (this.state.redirect) {
20+
return <Navigate to="/" />;
21+
} else if (this.state.hasError) {
22+
return (
23+
<h2>
24+
There was an error with this listing. <Link to="/">Click here</Link>{" "}
25+
to back to the home page or wait five seconds.
26+
</h2>
27+
);
28+
}
29+
30+
return this.props.children;
31+
}
32+
}
33+
34+
export default ErrorBoundary;

typescript-1/src/Modal.tsx

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import React, { FunctionComponent, MutableRefObject, useEffect, useRef } from "react";
2+
import { createPortal } from "react-dom";
3+
4+
const Modal: FunctionComponent = ({ children }) => {
5+
const elRef: MutableRefObject<HTMLDivElement | null> = useRef(null);
6+
if (!elRef.current) {
7+
elRef.current = document.createElement("div");
8+
}
9+
10+
useEffect(() => {
11+
const modalRoot = document.getElementById("modal");
12+
if (!modalRoot || !elRef.current) {
13+
return;
14+
}
15+
modalRoot.appendChild(elRef.current);
16+
return () => {
17+
if (elRef.current) {
18+
modalRoot.removeChild(elRef.current);
19+
}
20+
}
21+
}, []);
22+
23+
return createPortal(<div>{children}</div>, elRef.current);
24+
};
25+
26+
export default Modal;

0 commit comments

Comments
 (0)