mirror of
https://github.com/Noratrieb/mx-3.git
synced 2026-01-14 23:35:05 +01:00
nils althaus
This commit is contained in:
parent
2e5473f2be
commit
223f11750d
9 changed files with 207 additions and 3293 deletions
|
|
@ -1,5 +1,5 @@
|
|||
import axiosInstance from "./AxiosInstance";
|
||||
import { Band } from "./Types";
|
||||
import { Band, Response } from "./Types";
|
||||
|
||||
export class ApiClient {
|
||||
private readonly _cache: { [route: string]: any };
|
||||
|
|
@ -8,12 +8,12 @@ export class ApiClient {
|
|||
this._cache = {};
|
||||
}
|
||||
|
||||
public async get<T>(route: string, force = false): Promise<T> {
|
||||
public async get<T, Name extends string>(route: string, force = false): Promise<Response<T, Name>> {
|
||||
if (!force && this._cache[route]) {
|
||||
return this._cache[route];
|
||||
}
|
||||
const res = await axiosInstance.get(route);
|
||||
const data = res.data.response;
|
||||
const data: Response<T, Name> = res.data.response;
|
||||
if (res.status === 200) {
|
||||
this._cache[route] = data;
|
||||
}
|
||||
|
|
@ -21,7 +21,7 @@ export class ApiClient {
|
|||
}
|
||||
|
||||
public async searchBand(name: string): Promise<Band[]> {
|
||||
const res = await this.get<any>(`/bands?query=${encodeURIComponent(name)}`);
|
||||
const res = await this.get<Band[], "bands">(`/bands?query=${encodeURIComponent(name)}`);
|
||||
return res.bands;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
49
src/App.tsx
49
src/App.tsx
|
|
@ -1,19 +1,33 @@
|
|||
import React, { useRef, useState } from "react";
|
||||
import { Button, Card, Container, FormControl, FormGroup, FormLabel, Row } from "react-bootstrap";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { Button, Card, Container, FormControl, FormGroup, FormLabel, Row, Spinner } from "react-bootstrap";
|
||||
import client from "./ApiClient";
|
||||
import { Band } from "./Types";
|
||||
import { Band, Option } from "./Types";
|
||||
import ModalBand from "./ModalBand";
|
||||
import { useHistory, useParams } from "react-router-dom";
|
||||
|
||||
function App() {
|
||||
const searchRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
const [bands, setBands] = useState<Band[]>([]);
|
||||
const [bands, setBands] = useState<Option<Band[]>>(null);
|
||||
const [selectedBand, setSelectedBand] = useState<Option<Band>>(null);
|
||||
|
||||
const params = useParams<any>();
|
||||
const bandQuery = decodeURIComponent(params.query);
|
||||
const history = useHistory();
|
||||
|
||||
useEffect(() => {
|
||||
if (bandQuery) {
|
||||
client.searchBand(bandQuery).then((res) => setBands(res));
|
||||
}
|
||||
}, [bandQuery]);
|
||||
|
||||
const search = () => {
|
||||
const input = searchRef.current?.value;
|
||||
if (!input) {
|
||||
return;
|
||||
}
|
||||
client.searchBand(input).then((res) => setBands(res));
|
||||
history.push(`/${encodeURIComponent(input)}`);
|
||||
setBands(null);
|
||||
};
|
||||
|
||||
return (
|
||||
|
|
@ -26,22 +40,35 @@ function App() {
|
|||
<Button onClick={search}>Search</Button>
|
||||
</Row>
|
||||
<Row>
|
||||
{bands &&
|
||||
{selectedBand && <ModalBand onClose={() => setSelectedBand(null)} band={selectedBand} />}
|
||||
{bands ? (
|
||||
bands.map((band) => (
|
||||
<Card style={{ width: "18rem" }} key={band.uid}>
|
||||
<Card onClick={() => setSelectedBand(band)} style={{ width: "18rem" }} key={band.uid}>
|
||||
<Card.Img variant="top" src={band.url_for_image_original} />
|
||||
<Card.Title>{band.name}</Card.Title>
|
||||
<Card.Body>{getBioText(band)}</Card.Body>
|
||||
<Card.Body>{getBioText(band, 200)}</Card.Body>
|
||||
</Card>
|
||||
))}
|
||||
))
|
||||
) : bandQuery ? (
|
||||
<></>
|
||||
) : (
|
||||
<Spinner animation="border" />
|
||||
)}
|
||||
</Row>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
function getBioText(band: Band): string {
|
||||
export function getBioText(band: Band, maxLen: number): string {
|
||||
const bio = band.biographies.find((bio) => bio.lang === "de") || band.biographies[0];
|
||||
return bio?.description || "Keine Biographie angegeben.";
|
||||
return limit(bio?.description || "Keine Biographie angegeben.", maxLen);
|
||||
}
|
||||
|
||||
function limit(str: string, max: number): string {
|
||||
if (str.length > max) {
|
||||
return str.substr(0, max - 3) + "...";
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
export default App;
|
||||
|
|
|
|||
15
src/Band.tsx
15
src/Band.tsx
|
|
@ -1,15 +0,0 @@
|
|||
import React, { useEffect, useState } from "react";
|
||||
import client from "./ApiClient";
|
||||
import { BandById, Option } from "./Types";
|
||||
|
||||
const Band = ({ id }: { id: number }) => {
|
||||
const [band, setBand] = useState<Option<BandById>>(null);
|
||||
|
||||
useEffect(() => {
|
||||
client.get<BandById>(`/bands/${id}`).then((data) => setBand(data));
|
||||
}, [id]);
|
||||
|
||||
return <div></div>;
|
||||
};
|
||||
|
||||
export default Band;
|
||||
28
src/ModalBand.tsx
Normal file
28
src/ModalBand.tsx
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
import React from "react";
|
||||
import { Band } from "./Types";
|
||||
import { Button, Modal, Spinner } from "react-bootstrap";
|
||||
import { getBioText } from "./App";
|
||||
|
||||
interface Props {
|
||||
onClose: () => void;
|
||||
band: Band;
|
||||
}
|
||||
|
||||
const ModalBand = ({ band, onClose }: Props) => {
|
||||
return (
|
||||
<div>
|
||||
<Modal show={true}>
|
||||
<Modal.Footer>
|
||||
<Button onClick={onClose}>Close</Button>
|
||||
</Modal.Footer>
|
||||
<Modal.Header>{band.name}</Modal.Header>
|
||||
<Modal.Body>
|
||||
<img width="400" src={band.url_for_image_original} alt={band.name} />
|
||||
<div>{getBioText(band, 10000)}</div>
|
||||
</Modal.Body>
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ModalBand;
|
||||
|
|
@ -1,5 +1,3 @@
|
|||
import band from "./bandByIdRes.json";
|
||||
|
||||
export type Option<T> = T | null;
|
||||
|
||||
export interface Band {
|
||||
|
|
@ -34,4 +32,8 @@ export interface Band {
|
|||
singles_count: number;
|
||||
performances: Array<any>;
|
||||
}
|
||||
export type BandById = typeof band;
|
||||
|
||||
export type Response<T, Name extends string> = {
|
||||
status: string;
|
||||
code: string;
|
||||
} & { [P in Name]: T };
|
||||
|
|
|
|||
3249
src/bandByIdRes.json
3249
src/bandByIdRes.json
File diff suppressed because it is too large
Load diff
|
|
@ -2,10 +2,18 @@ import React from "react";
|
|||
import ReactDOM from "react-dom";
|
||||
import App from "./App";
|
||||
import "bootstrap/dist/css/bootstrap.min.css";
|
||||
import { BrowserRouter, Route, Switch } from "react-router-dom";
|
||||
|
||||
ReactDOM.render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
<BrowserRouter>
|
||||
<Switch>
|
||||
<Route path="/:query">
|
||||
<App />
|
||||
</Route>
|
||||
<Route path="/" component={App} />
|
||||
</Switch>
|
||||
</BrowserRouter>
|
||||
</React.StrictMode>,
|
||||
document.getElementById("root")
|
||||
);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue