Jaime Ramírez
2020-06-02 8b0b9e283e15f05b69c12fefe5fa935e244b01d1
Added Shelter detail view
1 files added
9 files modified
274 ■■■■ changed files
adopt-a-pup/web-app/src/App.tsx 15 ●●●● patch | view | raw | blame | history
adopt-a-pup/web-app/src/Components/AdoptableAnimalList.tsx 34 ●●●● 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/Services/AdoptionRESTService.ts 13 ●●●● 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/ShelterFakeService.ts 35 ●●●●● patch | view | raw | blame | history
adopt-a-pup/web-app/src/Services/ShelterRESTService.ts 8 ●●●● 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/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
@@ -23,6 +23,7 @@
import { ShelterService } from "./Services/ShelterService";
import AnimalDetails from "./Components/AnimalDetails";
import AnimalDetailsView from "./Views/AnimalDetailsView";
import ShelterDetailsView from "./Views/ShelterDetailsView";
// Backend SERVICES
@@ -34,28 +35,28 @@
if (process.env.REACT_APP_ADOPTION_SERVICE_URL) {
    adoptionService = new AdoptionRESTService(process.env.REACT_APP_ADOPTION_SERVICE_URL || "");
} else {
    console.log("Using AdoptionFakeService");
    console.log("Warning: No service url provided. Using AdoptionFakeService");
    adoptionService = new AdoptionFakeService();
}
if (process.env.REACT_APP_ANIMAL_SERVICE_URL) {
    animalService = new AnimalRESTService(process.env.REACT_APP_ANIMAL_SERVICE_URL || "");
} else {
    console.log("Using AnimalFakeService");
    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("Using ShelterFakeService");
    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("Using ShelterFakeService");
    console.log("Warning: No service url provided. Using ShelterFakeService");
    shelterService = new ShelterFakeService();
}
@@ -95,6 +96,12 @@
                                adoptionService={adoptionService}
                            /> } >
                        </Route>
                        <Route path={"/shelters/:shelterId"} render={ (props) =>
                            <ShelterDetailsView {...props}
                                shelterService={shelterService}
                                adoptionService={adoptionService}
                            /> } >
                        </Route>
                    </Structure>
                </Switch>
            </Router>
adopt-a-pup/web-app/src/Components/AdoptableAnimalList.tsx
@@ -1,48 +1,26 @@
import React from "react";
import {
    Gallery, GalleryItem, Card, CardBody, CardHeader, CardActions, Button, Alert
} from "@patternfly/react-core";
import { AnimalService } from "../Services/AnimalService";
import { Animal } from "../Models/Animal";
import { AdoptionService } from "../Services/AdoptionService";
import { Link } from "react-router-dom";
import {
    Gallery, GalleryItem, Card, CardBody, CardHeader, CardActions, Button
} from "@patternfly/react-core";
import { Animal } from "../Models/Animal";
type AnimalListProps = {
    animalService: AnimalService,
    adoptionService: AdoptionService
}
type AnimalListState = {
    animals: Animal[]
}
/**
 * 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: []
        };
    }
    public async componentDidMount() {
        const animals = await this.props.animalService.getAllAdoptable();
        this.setState({
            animals
        });
    }
export default class AdoptableAnimalList extends React.Component<AnimalListProps> {
    public render() {
        return (
            <React.Fragment>
                <Gallery>
                    {this.state.animals.map(animal => this.renderAnimalCard(animal))}
                    {this.props.animals.map(animal => this.renderAnimalCard(animal))}
                </Gallery>
            </React.Fragment>
        );
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/Services/AdoptionRESTService.ts
@@ -10,8 +10,17 @@
        super(baseUrl, "adoption-service");
    }
    public getAdoptableByShelter(): Promise<Animal[]> {
        return this.get("/adoption/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> {
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/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
@@ -13,7 +13,11 @@
        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/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>
        );
    }
}