jonahkh
2020-06-02 5d0dd32b75118aab9bfa43f5a3b6a73b3a65912a
merged
2 files added
16 files modified
780 ■■■■ changed files
adopt-a-pup/web-app/src/App.tsx 62 ●●●● patch | view | raw | blame | history
adopt-a-pup/web-app/src/Components/AdoptableAnimalList.tsx 82 ●●●●● patch | view | raw | blame | history
adopt-a-pup/web-app/src/Components/AdoptionForm.tsx 241 ●●●●● patch | view | raw | blame | history
adopt-a-pup/web-app/src/Components/ShelterForm.tsx 4 ●●●● patch | view | raw | blame | history
adopt-a-pup/web-app/src/Components/SheltersList.tsx 28 ●●●●● patch | view | raw | blame | history
adopt-a-pup/web-app/src/Models/Animal.ts 2 ●●● patch | view | raw | blame | history
adopt-a-pup/web-app/src/Models/Residency.ts 4 ●●●● patch | view | raw | blame | history
adopt-a-pup/web-app/src/Services/AdoptionRESTService.ts 17 ●●●● patch | view | raw | blame | history
adopt-a-pup/web-app/src/Services/AdoptionService.ts 2 ●●● patch | view | raw | blame | history
adopt-a-pup/web-app/src/Services/AnimalFakeService.ts 41 ●●●●● patch | view | raw | blame | history
adopt-a-pup/web-app/src/Services/AnimalRESTService.ts 4 ●●●● patch | view | raw | blame | history
adopt-a-pup/web-app/src/Services/RESTService.ts 2 ●●● patch | view | raw | blame | history
adopt-a-pup/web-app/src/Services/ShelterFakeService.ts 35 ●●●●● patch | view | raw | blame | history
adopt-a-pup/web-app/src/Services/ShelterRESTService.ts 11 ●●●● patch | view | raw | blame | history
adopt-a-pup/web-app/src/Services/ShelterService.ts 5 ●●●● patch | view | raw | blame | history
adopt-a-pup/web-app/src/Views/AnimalDetailsView.tsx 106 ●●●●● patch | view | raw | blame | history
adopt-a-pup/web-app/src/Views/AnimalsView.tsx 28 ●●●● patch | view | raw | blame | history
adopt-a-pup/web-app/src/Views/ShelterDetailsView.tsx 106 ●●●●● patch | view | raw | blame | history
adopt-a-pup/web-app/src/App.tsx
@@ -6,7 +6,6 @@
    Switch,
    Route,
} from "react-router-dom";
// import ShelterRESTService from "./Services/ShelterRESTService";
import SheltersView from "./Views/SheltersView";
import NewsView from "./Views/NewsView";
import ShelterFakeService from "./Services/ShelterFakeService";
@@ -22,27 +21,50 @@
import { AnimalService } from "./Services/AnimalService";
import { AdoptionService } from "./Services/AdoptionService";
import { ShelterService } from "./Services/ShelterService";
import AnimalDetailsView from "./Views/AnimalDetailsView";
import AnimalDetails from "./Components/AnimalDetails";
// import ShelterRESTService from "./Services/ShelterRESTService";
import AnimalDetailsView from "./Views/AnimalDetailsView";
import ShelterDetailsView from "./Views/ShelterDetailsView";
// Services to connect to backends
// Backend SERVICES
let animalService: AnimalService;
let adoptionService: AdoptionService;
let shelterService: ShelterService;
let newsService: NewsService;
// Fake services for frontend-isolated developemtn
// shelterService = new ShelterFakeService();
// newsService = new NewsFakeService();
// animalService = new AnimalFakeService();
// adoptionService = new AdoptionFakeService();
if (process.env.REACT_APP_ADOPTION_SERVICE_URL) {
    adoptionService = new AdoptionRESTService(process.env.REACT_APP_ADOPTION_SERVICE_URL || "");
} else {
    console.log("Warning: No service url provided. Using AdoptionFakeService");
    adoptionService = new AdoptionFakeService();
}
// Uncomment to use Real services
adoptionService = new AdoptionRESTService(process.env.REACT_APP_ADOPTION_SERVICE_URL || "");
animalService = new AnimalRESTService(process.env.REACT_APP_ANIMAL_SERVICE_URL || "");
shelterService = new ShelterRESTService(process.env.REACT_APP_SHELTER_SERVICE_URL || "");
if (process.env.REACT_APP_ANIMAL_SERVICE_URL) {
    animalService = new AnimalRESTService(process.env.REACT_APP_ANIMAL_SERVICE_URL || "");
} else {
    console.log("Warning: No service url provided. Using AnimalFakeService");
    animalService = new AnimalFakeService();
}
if (process.env.REACT_APP_SHELTER_SERVICE_URL) {
    shelterService = new ShelterRESTService(process.env.REACT_APP_SHELTER_SERVICE_URL || "");
} else {
    console.log("Warning: No service url provided. Using ShelterFakeService");
    shelterService = new ShelterFakeService();
}
if (process.env.REACT_APP_SHELTER_SERVICE_URL) {
    shelterService = new ShelterRESTService(process.env.REACT_APP_SHELTER_SERVICE_URL || "");
} else {
    console.log("Warning: No service url provided. Using ShelterFakeService");
    shelterService = new ShelterFakeService();
}
// TODO: Create REST News service
newsService = new NewsFakeService();
// MAIN APP
// The main React component that runs the whole webapp
export default class App extends Component {
    render() {
@@ -68,11 +90,17 @@
                            <NewsView newsService={newsService} />
                        </Route>
                        }
                        <Route path={`/animals/:animalId`} component={AnimalDetails}>
                            {/* <AnimalDetailsView
                                // animalId={this.pro}
                        <Route path={"/animals/:animalId"} render={ (props) =>
                            <AnimalDetailsView {...props}
                                animalService={animalService}
                                adoptionService={adoptionService}/> */}
                                adoptionService={adoptionService}
                            /> } >
                        </Route>
                        <Route path={"/shelters/:shelterId"} render={ (props) =>
                            <ShelterDetailsView {...props}
                                shelterService={shelterService}
                                adoptionService={adoptionService}
                            /> } >
                        </Route>
                    </Structure>
                </Switch>
adopt-a-pup/web-app/src/Components/AdoptableAnimalList.tsx
@@ -1,84 +1,28 @@
import React from "react";
import { Link } from "react-router-dom";
import {
    Gallery, GalleryItem, Card, CardBody, CardHeader, CardActions, Button, Alert
    Gallery, GalleryItem, Card, CardBody, CardHeader, CardActions, Button
} from "@patternfly/react-core";
import { AnimalService } from "../Services/AnimalService";
import { Animal } from "../Models/Animal";
import { AdoptionService } from "../Services/AdoptionService";
import { Residency } from "../Models/Residency";
import AnimalDetailsView from "../Views/AnimalDetailsView";
import { Link, useHistory } from "react-router-dom";
type AnimalListProps = {
    animalService: AnimalService,
    adoptionService: AdoptionService
    animals: Animal[]
}
type AnimalListState = {
    animals: Animal[],
    showAdoptSucessAlert: boolean,
    showAdoptErrorAlert: boolean
}
/**
 * Card list to show adoptable animals and apply for adoption
 */
export default class AdoptableAnimalList extends React.Component<AnimalListProps, AnimalListState> {
    constructor(props: AnimalListProps) {
        super(props);
        this.state = {
            animals: [],
            showAdoptErrorAlert: false,
            showAdoptSucessAlert: false
        };
    }
    public async componentDidMount() {
        const animals = await this.props.animalService.getAllAdoptable();
        this.setState({
            animals
        });
    }
    private async handleAdoptButtonClick(animal: Animal) {
        try {
            // TODO: Application form
            const adoptionApplication = {
                username: "todo",
                residency: Residency.HOUSE,
                animalId: animal.animalId,
                squareFootageOfHome: 100,
                occupation: "todo",
                ownOtherAnimals: false,
                kidsUnder16: true,
                email: "todo@todo.com"
            };
            await this.props.adoptionService.applyForAdoption(adoptionApplication);
            this.setState({ showAdoptSucessAlert: true });
        } catch {
            this.setState({ showAdoptErrorAlert: true });
        }
        setTimeout(() => {
            this.setState({
                showAdoptErrorAlert: false,
                showAdoptSucessAlert: false,
            });
        }, 2000);
    }
export default class AdoptableAnimalList extends React.Component<AnimalListProps> {
    public render() {
        return (
            <React.Fragment>
                {this.renderAdoptSuccessAlert()}
                {this.renderAdoptErrorAlert()}
                <Gallery>
                    {this.state.animals.map(animal => this.renderAnimalCard(animal))}
                    {this.props.animals.map(animal => this.renderAnimalCard(animal))}
                </Gallery>
            </React.Fragment>
        );
@@ -97,9 +41,6 @@
                    <CardBody>
                        <img src={pictureSrc} alt={animal.animalName}></img>
                        <CardActions>
                            {/* <Button onClick={() => this.handleAdoptButtonClick(animal)}>
                                Adopt
                            </Button> */}
                            <Link to={`/animals/${animal.animalId}`}>
                                <Button>
                                    Details
@@ -113,17 +54,4 @@
    }
    private renderAdoptErrorAlert(): React.ReactNode | null {
        if (this.state.showAdoptErrorAlert) {
            return <Alert variant="danger" title="The adoption application failed" />;
        }
        return null;
    }
    private renderAdoptSuccessAlert(): React.ReactNode | null {
        if (this.state.showAdoptSucessAlert) {
            return <Alert variant="success" title="Adoption application sent successfully" />;
        }
        return null;
    }
}
adopt-a-pup/web-app/src/Components/AdoptionForm.tsx
New file
@@ -0,0 +1,241 @@
import React, { FormEvent } from "react";
import {
    Form,
    FormGroup,
    TextInput,
    ActionGroup,
    Button,
    ButtonType,
    FormSelect,
    FormSelectOption,
    Checkbox,
    Alert
} from "@patternfly/react-core";
import { AdoptionService } from "../Services/AdoptionService";
import { Residency } from "../Models/Residency";
type AdoptionFormProps = {
    adoptionService: AdoptionService,
    animalId: string
};
type AdoptionFormState = {
    username: string,
    email: string,
    residency: Residency,
    squareFootageOfHome: number,
    kidsUnder16: boolean,
    occupation: string,
    ownOtherAnimals: boolean,
    showAdoptSucessAlert: boolean,
    showAdoptErrorAlert: boolean
};
export default class AdoptionForm extends React.Component<AdoptionFormProps, AdoptionFormState> {
    constructor(props: AdoptionFormProps) {
        super(props);
        this.state = {
            username: "",
            email: "",
            occupation: "",
            residency: Residency.APARTMENT,
            squareFootageOfHome: 0,
            kidsUnder16: false,
            ownOtherAnimals: false,
            showAdoptErrorAlert: false,
            showAdoptSucessAlert: false
        };
    }
    private handleNameChange(username: string) {
        this.setState({ username });
    }
    private handleEmailChange(email: string) {
        this.setState({ email });
    }
    private handleOccupationChange(occupation: string) {
        this.setState({ occupation });
    }
    private handleResidencyChange(residency: Residency) {
        this.setState({ residency });
    }
    private handleSquareFootageChange(squareFootageOfHome: string) {
        this.setState({ squareFootageOfHome: parseInt(squareFootageOfHome) });
    }
    private handleKidsUnder16Change(kidsUnder16: boolean) {
        this.setState({ kidsUnder16 });
    }
    private handleOwnOtherAnimalsChange(ownOtherAnimals: boolean) {
        this.setState({ ownOtherAnimals });
    }
    private async handleFormSubmit(event: FormEvent) {
        const application = {
            animalId: this.props.animalId,
            ...this.state
        };
        event.preventDefault();
        try {
            await this.props.adoptionService.applyForAdoption(application);
            this.setState({ showAdoptSucessAlert: true });
        } catch {
            this.setState({ showAdoptErrorAlert: true });
        }
        setTimeout(() => {
            this.setState({
                showAdoptErrorAlert: false,
                showAdoptSucessAlert: false,
            });
        }, 2000);
    }
    public render() {
        const {
            username,
            email,
            occupation,
            residency,
            squareFootageOfHome,
            kidsUnder16,
            ownOtherAnimals
        } = this.state;
        return (
            <Form onSubmit={this.handleFormSubmit.bind(this)}>
                {this.renderAdoptSuccessAlert()}
                {this.renderAdoptErrorAlert()}
                <FormGroup
                    label="Name"
                    isRequired
                    fieldId="simple-form-username"
                    helperText="Please provide your name"
                >
                    <TextInput
                        isRequired
                        type="text"
                        id="simple-form-username"
                        name="simple-form-username"
                        aria-describedby="simple-form-name-helper"
                        value={username}
                        onChange={this.handleNameChange.bind(this)}
                    />
                </FormGroup>
                <FormGroup label="Email" isRequired fieldId="simple-form-email">
                    <TextInput
                        isRequired
                        type="email"
                        id="simple-form-email"
                        name="simple-form-email"
                        value={email}
                        onChange={this.handleEmailChange.bind(this)}
                    />
                </FormGroup>
                <FormGroup
                    label="Occupation"
                    isRequired
                    fieldId="simple-form-occupation"
                    helperText="Please provide your occupation"
                >
                    <TextInput
                        isRequired
                        type="text"
                        id="simple-form-occupation"
                        name="simple-form-occupation"
                        aria-describedby="simple-form-name-helper"
                        value={occupation}
                        onChange={this.handleOccupationChange.bind(this)}
                    />
                </FormGroup>
                <FormGroup
                    label="Residency"
                    isRequired
                    fieldId="simple-form-residency"
                    helperText="Please provide the address"
                >
                    <FormSelect
                        value={residency}
                        onChange={(residency) => this.handleResidencyChange(residency as Residency)}
                        aria-label="Select Residency">
                        <FormSelectOption
                            key={Residency.HOUSE}
                            value={Residency.HOUSE}
                            label={Residency.HOUSE}
                        />
                        <FormSelectOption
                            key={Residency.APARTMENT}
                            value={Residency.APARTMENT}
                            label={Residency.APARTMENT}
                        />
                    </FormSelect>
                </FormGroup>
                <FormGroup label="Square Footage of Home" isRequired fieldId="simple-form-footage">
                    <TextInput
                        isRequired
                        type="number"
                        id="simple-form-footage"
                        name="simple-form-footage"
                        value={squareFootageOfHome}
                        onChange={this.handleSquareFootageChange.bind(this)}
                    />
                </FormGroup>
                <FormGroup fieldId="simple-form-kids">
                    <Checkbox
                        label="I have kids under 16"
                        id="simple-form-kids"
                        name="simple-form-kids"
                        aria-label="I have kids under 16"
                        isChecked={kidsUnder16}
                        onChange={this.handleKidsUnder16Change.bind(this)} />
                </FormGroup>
                <FormGroup fieldId="simple-form-other-animals">
                    <Checkbox
                        label="I own other animals"
                        id="simple-form-other-animals"
                        name="simple-form-other-animals"
                        aria-label="I own other animals"
                        isChecked={ownOtherAnimals}
                        onChange={this.handleOwnOtherAnimalsChange.bind(this)} />
                </FormGroup>
                <ActionGroup>
                    <Button variant="primary" type={ButtonType.submit}>Apply for Adoption</Button>
                </ActionGroup>
            </Form>
        );
    }
    private renderAdoptErrorAlert(): React.ReactNode | null {
        if (this.state.showAdoptErrorAlert) {
            return <Alert variant="danger" title="The adoption application failed" />;
        }
        return null;
    }
    private renderAdoptSuccessAlert(): React.ReactNode | null {
        if (this.state.showAdoptSucessAlert) {
            return <Alert
                variant="success"
                title="Congratulations! The Adoption application was sent."
            />;
        }
        return null;
    }
}
adopt-a-pup/web-app/src/Components/ShelterForm.tsx
@@ -145,7 +145,7 @@
                        id="simple-form-email"
                        name="simple-form-email"
                        value={email}
                        onChange={this.handleEmailChange}
                        onChange={this.handleEmailChange.bind(this)}
                    />
                </FormGroup>
                <FormGroup label="Phone number" isRequired fieldId="simple-form-number">
@@ -156,7 +156,7 @@
                        placeholder="555-555-5555"
                        name="simple-form-number"
                        value={phoneNumber}
                        onChange={this.handlePhoneNumberChange}
                        onChange={this.handlePhoneNumberChange.bind(this)}
                    />
                </FormGroup>
                <ActionGroup>
adopt-a-pup/web-app/src/Components/SheltersList.tsx
@@ -1,6 +1,8 @@
import React from "react";
import { List, ListItem } from "@patternfly/react-core";
import { List, ListItem, Button, Level, LevelItem } from "@patternfly/react-core";
import { ShelterService } from "../Services/ShelterService";
import { Shelter } from "../Models/Shelter";
import { Link } from "react-router-dom";
type ShelterListProps = {
@@ -32,8 +34,30 @@
        return (
            <List>
                {shelters.map(shelter => <ListItem key={shelter.shelterId}>{shelter.shelterName}</ListItem>)}
                {shelters.map(shelter => <ListItem key={shelter.shelterId}>
                    {this.renderShelter(shelter)}
                </ListItem>)}
            </List>
        );
    }
    private renderShelter(shelter: Shelter) {
        return (
            <React.Fragment>
                <Level>
                    <LevelItem>
                        {shelter.shelterName}
                    </LevelItem>
                    <LevelItem>
                        <Link to={`/shelters/${shelter.shelterId}`}>
                            <Button>
                                Details
                            </Button>
                        </Link>
                    </LevelItem>
                </Level>
            </React.Fragment>
        );
    }
adopt-a-pup/web-app/src/Models/Animal.ts
@@ -4,7 +4,7 @@
    shelterId: string;
    breed: string;
    adoptable: boolean;
    approximateSize: string;
    approximateSize: string;
    residencyRequired: string;
    weight: number;
    squareFootageOfHome: number;
adopt-a-pup/web-app/src/Models/Residency.ts
@@ -1,4 +1,4 @@
export enum Residency {
    APARTMENT,
    HOUSE
    APARTMENT = "APARTMENT",
    HOUSE = "HOUSE"
}
adopt-a-pup/web-app/src/Services/AdoptionRESTService.ts
@@ -7,15 +7,24 @@
export default class AdoptionRESTService extends RESTService implements AdoptionService {
    constructor(baseUrl: string) {
        super(baseUrl, "shelter-service");
        super(baseUrl, "adoption-service");
    }
    public getAdoptableByShelter(): Promise<Animal[]> {
        return this.get("/getAllAdoptableByShelter");
    public async getAdoptableByShelter(shelterId: string): Promise<Animal[]> {
        const animalsByShelter = await this.get<Record<string,Animal[]>>(
            "/adoption/getAllAdoptableByShelter"
        );
        for(const key of Object.keys(animalsByShelter)) {
            if (key.includes(`shelterId=${shelterId}`)) {
                return animalsByShelter[key];
            }
        }
        return [];
    }
    public async applyForAdoption(adoptionApplication: AdoptionApplication): Promise<void> {
        await this.post("/applyForAdoption", adoptionApplication);
        await this.post("/adoption/applyForAdoption", adoptionApplication);
    }
}
adopt-a-pup/web-app/src/Services/AdoptionService.ts
@@ -3,6 +3,6 @@
export interface AdoptionService {
    getAdoptableByShelter(): Promise<Animal[]>;
    getAdoptableByShelter(shelterId: string): Promise<Animal[]>;
    applyForAdoption(adoptionApplication: AdoptionApplication): Promise<void>;
}
adopt-a-pup/web-app/src/Services/AnimalFakeService.ts
@@ -22,11 +22,50 @@
                squareFootageOfHome: 800,
                childSafe: true,
                otherDogSafe: true
            },
            {
                animalId: "a1",
                animalName: "Dog 1",
                breed: "Shepherd",
                shelterId: "s1",
                adoptable: true,
                weight: 100,
                approximateSize: "L",
                residencyRequired: "HOUSE",
                squareFootageOfHome: 800,
                childSafe: true,
                otherDogSafe: true
            },
            {
                animalId: "a1",
                animalName: "Dog 1",
                breed: "Shepherd",
                shelterId: "s1",
                adoptable: true,
                weight: 100,
                approximateSize: "L",
                residencyRequired: "HOUSE",
                squareFootageOfHome: 800,
                childSafe: true,
                otherDogSafe: true
            },
            {
                animalId: "a1",
                animalName: "Dog 1",
                breed: "Shepherd",
                shelterId: "s1",
                adoptable: true,
                weight: 100,
                approximateSize: "L",
                residencyRequired: "HOUSE",
                squareFootageOfHome: 800,
                childSafe: true,
                otherDogSafe: true
            }
        ];
    }
    public async getById(id: string): Promise<Animal> {
    public async getById(): Promise<Animal> {
        return             {
            animalId: "a1",
            animalName: "Dog 1",
adopt-a-pup/web-app/src/Services/AnimalRESTService.ts
@@ -7,14 +7,14 @@
export default class AnimalRESTService extends RESTService implements AnimalService {
    constructor(baseUrl: string) {
        super(baseUrl, "shelter-service");
        super(baseUrl, "animal-service");
    }
    public async create(animal: Animal): Promise<void> {
        await this.post(`/animals/${animal.shelterId}/create`, animal);
    }
    public getAllAdoptable(): Promise<Animal[]> {
        return this.get("/animals/getAllAdoptable")
        return this.get("/animals/getAllAdoptable");
    }
    public getById(id: string): Promise<Animal> {
adopt-a-pup/web-app/src/Services/RESTService.ts
@@ -26,7 +26,7 @@
            const r = await this.axiosInstance.post<T>(url, body);
            return r.data;
        } catch (e) {
            throw new RESTConnectionError(e, this.remoteServiceName, e.response.status);
            throw new RESTConnectionError(e, this.remoteServiceName, e.response?.status);
        }
    }
adopt-a-pup/web-app/src/Services/ShelterFakeService.ts
@@ -1,17 +1,46 @@
import { ShelterService } from "./ShelterService";
import { Shelter } from "../Models/Shelter";
export default class ShelterFakeService implements ShelterService {
    public async getById(id: string): Promise<Shelter> {
        return {
            shelterId: id,
            shelterName: "A Fake Shelter",
            state: "Minnesota",
            country: "US",
            address: "200 Good Boy Ave",
            email: "frontdesk@minneapolismutts.com",
            phoneNumber: "212-555-9758"
        };
    }
    public async create(): Promise<void> {
        alert("ShelterFakeService: create() was called!");
        return Promise.resolve();
    }
    public async getAll(): Promise<any[]> {
    public async getAll(): Promise<Shelter[]> {
        return [
            { shelterId: "s1", shelterName: "Shelter 1" },
            { shelterId: "s2", shelterName: "Shelter 2" }
            {
                shelterId: "1234",
                shelterName: "A Fake Shelter 1",
                state: "Minnesota",
                country: "US",
                address: "200 Good Boy Ave",
                email: "frontdesk@minneapolismutts.com",
                phoneNumber: "212-555-9758"
            },
            {
                shelterId: "3456",
                shelterName: "A Fake Shelter 2",
                state: "Minnesota",
                country: "US",
                address: "100 Good Boy Ave",
                email: "frontdesk@minneapolismutts2.com",
                phoneNumber: "212-444-8475"
            }
        ];
    }
}
adopt-a-pup/web-app/src/Services/ShelterRESTService.ts
@@ -10,10 +10,15 @@
    }
    public async create(params: ShelterParams): Promise<void> {
        return this.post("/create", params);
        return this.post("/shelters/create", params);
    }
    public getAll(): Promise<Array<Shelter>> {
        return this.get<Array<Shelter>>("/shelters/getAll");
    public async getById(id: string): Promise<Shelter> {
        return this.get<Shelter>(`/shelters/${id}/getShelter`);
    }
    public getAll(): Promise<Shelter[]> {
        return this.get<Shelter[]>("/shelters/getAll");
    }
}
adopt-a-pup/web-app/src/Services/ShelterService.ts
@@ -1,3 +1,5 @@
import { Shelter } from "../Models/Shelter";
export type ShelterParams = {
    name: string
}
@@ -5,6 +7,7 @@
export interface ShelterService {
    create(params: ShelterParams): Promise<void>;
    getAll(): Promise<any[]>;
    getById(id: string): Promise<Shelter>
    getAll(): Promise<Shelter[]>;
}
adopt-a-pup/web-app/src/Views/AnimalDetailsView.tsx
@@ -1,19 +1,117 @@
import React from "react";
import { PageSection, PageSectionVariants, Text, TextContent } from "@patternfly/react-core";
import { PageSection, PageSectionVariants, Text, TextContent, GridItem, Grid } from "@patternfly/react-core";
import { AdoptionService } from "../Services/AdoptionService";
import { AnimalService } from "../Services/AnimalService";
import { Animal } from "../Models/Animal";
import AdoptionForm from "../Components/AdoptionForm";
type AnimalDetailsViewProps = {
    adoptionService: AdoptionService;
    animalService: AnimalService;
}
export default class AnimalDetailsView extends React.Component<AnimalDetailsViewProps, AnimalService> {
type AnimalDetailsViewState = {
    animal?: Animal
}
export default class AnimalDetailsView
    extends React.Component<AnimalDetailsViewProps, AnimalDetailsViewState> {
    constructor(props: AnimalDetailsViewProps) {
        super(props);
        this.state = {
            animal: undefined
        };
    }
    public async componentDidMount() {
        const { animalId } = this.props.match.params;
        const animal = await this.props.animalService.getById(animalId);
        this.setState({
            animal
        });
    }
    public render() {
        const { animal } = this.state;
        return animal ? this.renderAnimal(animal) : this.renderMissingAnimal();
    }
    private renderAnimal(animal: Animal) {
        return (
            <React.Fragment>
                <PageSection variant={PageSectionVariants.light}>
                    <TextContent>
                        <Text component="h1">{animal.animalName}</Text>
                    </TextContent>
                    <Grid>
                        <GridItem span={4}>
                            <img src={`/photos/${animal.animalId}.jpeg`}  />
                        </GridItem>
                        <GridItem span={8}>
                            <TextContent>
                                <Text component="p">
                                    <strong>Name: </strong>{animal.animalName}
                                </Text>
                                <Text component="p">
                                    <strong>Breed: </strong>{animal.breed}
                                </Text>
                                <Text component="p">
                                    <strong>Weight: </strong>{animal.weight}
                                </Text>
                                <Text component="p">
                                    <strong>Approximate Size: </strong>{animal.approximateSize}
                                </Text>
                                <Text component="p">
                                    <strong>Child Safe: </strong>
                                    {animal.childSafe ? "Yes" : "No"}
                                </Text>
                                <Text component="p">
                                    <strong>Other Dogs Safe: </strong>
                                    {animal.otherDogSafe ? "Yes" : "No"}
                                </Text>
                                <Text component="p">
                                    <strong>Residency Required: </strong>
                                    {animal.residencyRequired ? "Yes" : "No"}
                                </Text>
                                <Text component="p">
                                    <strong>Residency Required: </strong>
                                    {animal.residencyRequired ? "Yes" : "No"}
                                </Text>
                                <Text component="p">
                                    <strong>Square Footage of Home: </strong>
                                    {animal.squareFootageOfHome}
                                </Text>
                            </TextContent>
                        </GridItem>
                    </Grid>
                </PageSection>
                <PageSection>
                    <TextContent>
                        <Text component="h2">Adopt {animal.animalName}!</Text>
                    </TextContent>
                    <AdoptionForm adoptionService={this.props.adoptionService} animalId={animal.animalId} />
                </PageSection>
            </React.Fragment>
        );
    }
    private renderMissingAnimal() {
        return (
            <PageSection variant={PageSectionVariants.light}>
                <TextContent>
                    <Text component="h1">Not Found</Text>
                    <Text component="p">
                        This animal does not exist.
                    </Text>
                </TextContent>
            </PageSection>
        )
        );
    }
}
adopt-a-pup/web-app/src/Views/AnimalsView.tsx
@@ -3,6 +3,7 @@
import { PageSection, PageSectionVariants, Text, TextContent } from "@patternfly/react-core";
import AdoptableAnimalList from "../Components/AdoptableAnimalList";
import { AdoptionService } from "../Services/AdoptionService";
import { Animal } from "../Models/Animal";
type AnimalsViewProps = {
@@ -10,8 +11,26 @@
    adoptionService: AdoptionService;
}
type AnimalsViewState = {
    animals: Animal[]
}
export default class AnimalsView extends React.Component<AnimalsViewProps> {
export default class AnimalsView extends React.Component<AnimalsViewProps, AnimalsViewState> {
    constructor(props: AnimalsViewProps) {
        super(props);
        this.state = {
            animals: []
        };
    }
    public async componentDidMount() {
        const animals = await this.props.animalService.getAllAdoptable();
        this.setState({
            animals
        });
    }
    public render() {
        return (
@@ -25,11 +44,8 @@
                    </TextContent>
                </PageSection>
                <PageSection>
                    <Text component="h2">Create a Shelter</Text>
                    <AdoptableAnimalList
                        animalService={this.props.animalService}
                        adoptionService={this.props.adoptionService}
                    />
                    <Text component="h2">Adoptable Animals</Text>
                    <AdoptableAnimalList animals={this.state.animals} />
                </PageSection>
            </React.Fragment>
        );
adopt-a-pup/web-app/src/Views/ShelterDetailsView.tsx
New file
@@ -0,0 +1,106 @@
import React from "react";
import { PageSection, PageSectionVariants, Text, TextContent } from "@patternfly/react-core";
import { ShelterService } from "../Services/ShelterService";
import { Shelter } from "../Models/Shelter";
import { AdoptionService } from "../Services/AdoptionService";
import { Animal } from "../Models/Animal";
import AdoptableAnimalList from "../Components/AdoptableAnimalList";
type ShelterDetailsViewProps = {
    shelterService: ShelterService;
    adoptionService: AdoptionService;
    match: {
        params: {
            shelterId: string
        }
    }
}
type ShelterDetailsViewState = {
    shelter?: Shelter,
    adoptableAnimals: Animal[]
}
export default class ShelterDetailsView
    extends React.Component<ShelterDetailsViewProps, ShelterDetailsViewState> {
    constructor(props: ShelterDetailsViewProps) {
        super(props);
        this.state = {
            shelter: undefined,
            adoptableAnimals: []
        };
    }
    public async componentDidMount() {
        const { shelterId } = this.props.match.params;
        const [ shelter, adoptableAnimals ] = await Promise.all([
            this.props.shelterService.getById(shelterId),
            this.props.adoptionService.getAdoptableByShelter(shelterId)
        ]);
        this.setState({
            shelter,
            adoptableAnimals
        });
    }
    public render() {
        const { shelter } = this.state;
        return shelter ? this.renderShelter(shelter) : this.renderMissingShelter();
    }
    private renderShelter(shelter: Shelter) {
        return (
            <React.Fragment>
                <PageSection variant={PageSectionVariants.light}>
                    <TextContent>
                        <Text component="h1">
                            {shelter.shelterName}
                        </Text>
                        <Text component="p">
                            <strong>Name: </strong>{shelter.shelterName}
                        </Text>
                        <Text component="p">
                            <strong>State: </strong>{shelter.state}
                        </Text>
                        <Text component="p">
                            <strong>Country: </strong>{shelter.country}
                        </Text>
                        <Text component="p">
                            <strong>Address: </strong>{shelter.address}
                        </Text>
                        <Text component="p">
                            <strong>Email: </strong>{shelter.email}
                        </Text>
                        <Text component="p">
                            <strong>Phone Number: </strong>{shelter.phoneNumber}
                        </Text>
                    </TextContent>
                </PageSection>
                <PageSection>
                    <TextContent>
                        <Text component="h1">
                            Adoptable Animals
                        </Text>
                    </TextContent>
                    <AdoptableAnimalList animals={this.state.adoptableAnimals}></AdoptableAnimalList>
                </PageSection>
            </React.Fragment>
        );
    }
    private renderMissingShelter() {
        return (
            <PageSection variant={PageSectionVariants.light}>
                <TextContent>
                    <Text component="h1">Not Found</Text>
                    <Text component="p">
                        This shelter does not exist.
                    </Text>
                </TextContent>
            </PageSection>
        );
    }
}