jonahkh
2020-06-04 a76035cb2ca6c739826ea95dc4eb0d1bde0517f7
added create animal form
2 files added
14 files modified
418 ■■■■ changed files
adopt-a-pup/web-app/src/App.tsx 51 ●●●●● patch | view | raw | blame | history
adopt-a-pup/web-app/src/Components/AdoptableAnimalList.test.tsx 6 ●●●● patch | view | raw | blame | history
adopt-a-pup/web-app/src/Components/AdoptableAnimalList.tsx 8 ●●●● patch | view | raw | blame | history
adopt-a-pup/web-app/src/Components/AnimalCreateForm.tsx 255 ●●●●● patch | view | raw | blame | history
adopt-a-pup/web-app/src/Components/ShelterForm.tsx 58 ●●●●● 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/ApproximateSize.ts 5 ●●●●● patch | view | raw | blame | history
adopt-a-pup/web-app/src/Models/Shelter.ts 2 ●●● patch | view | raw | blame | history
adopt-a-pup/web-app/src/Services/AnimalFakeService.ts 2 ●●● 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/AnimalService.ts 2 ●●● patch | view | raw | blame | history
adopt-a-pup/web-app/src/Services/ShelterFakeService.ts 5 ●●●●● patch | view | raw | blame | history
adopt-a-pup/web-app/src/Services/ShelterRESTService.ts 6 ●●●● patch | view | raw | blame | history
adopt-a-pup/web-app/src/Services/ShelterService.ts 7 ●●●● patch | view | raw | blame | history
adopt-a-pup/web-app/src/Views/AnimalDetailsView.tsx 3 ●●●● patch | view | raw | blame | history
adopt-a-pup/web-app/src/Views/AnimalsView.tsx 2 ●●● patch | view | raw | blame | history
adopt-a-pup/web-app/src/App.tsx
@@ -23,36 +23,37 @@
import { ShelterService } from "./Services/ShelterService";
import AnimalDetailsView from "./Views/AnimalDetailsView";
import ShelterDetailsView from "./Views/ShelterDetailsView";
import AnimalCreateView from "./Views/AnimalCreateView";
import Config from "./Config";
import NewsRESTService from "./Services/NewsRESTService";
// Initialize Backend Services
let animalService: AnimalService;
let adoptionService: AdoptionService;
let shelterService: ShelterService;
let animalService: AnimalService = new AnimalRESTService("http://envoy-gateway-adopt-a-pup.apps-crc.testing");
let adoptionService: AdoptionService = new AdoptionRESTService("http://envoy-gateway-adopt-a-pup.apps-crc.testing");
let shelterService: ShelterService = new ShelterRESTService("http://envoy-gateway-adopt-a-pup.apps-crc.testing");
let newsService: NewsService;
if (Config.ADOPTION_SERVICE_URL) {
    adoptionService = new AdoptionRESTService(Config.ADOPTION_SERVICE_URL);
} else {
    console.log("Warning: No adoption service url provided. Using AdoptionFakeService");
    adoptionService = new AdoptionFakeService();
}
// if (Config.ADOPTION_SERVICE_URL) {
//     adoptionService = new AdoptionRESTService(Config.ADOPTION_SERVICE_URL);
// } else {
//     console.log("Warning: No adoption service url provided. Using AdoptionFakeService");
//     adoptionService = new AdoptionFakeService();
// }
if (Config.ANIMAL_SERVICE_URL) {
    animalService = new AnimalRESTService(Config.ANIMAL_SERVICE_URL);
} else {
    console.log("Warning: No animal service url provided. Using AnimalFakeService");
    animalService = new AnimalFakeService();
}
// if (Config.ANIMAL_SERVICE_URL) {
//     animalService = new AnimalRESTService(Config.ANIMAL_SERVICE_URL);
// } else {
//     console.log("Warning: No animal service url provided. Using AnimalFakeService");
//     animalService = new AnimalFakeService();
// }
if (Config.SHELTER_SERVICE_URL) {
    shelterService = new ShelterRESTService(Config.SHELTER_SERVICE_URL);
} else {
    console.log("Warning: No shelter service url provided. Using ShelterFakeService");
    shelterService = new ShelterFakeService();
}
// if (Config.SHELTER_SERVICE_URL) {
//     shelterService = new ShelterRESTService(Config.SHELTER_SERVICE_URL);
// } else {
//     console.log("Warning: No shelter service url provided. Using ShelterFakeService");
//     shelterService = new ShelterFakeService();
// }
if (Config.NEWS_ENABLED && Config.NEWS_SERVICE_URL) {
    newsService = new NewsRESTService(Config.NEWS_SERVICE_URL);
@@ -87,12 +88,18 @@
                            <NewsView newsService={newsService} />
                        </Route>
                        }
                        <Route path={"/animals/:animalId"} render={ (props) =>
                        <Route path={"/animals/details/:animalId"} render={ (props) =>
                            <AnimalDetailsView {...props}
                                animalService={animalService}
                                adoptionService={adoptionService}
                            /> } >
                        </Route>
                        <Route path="/animals/create" render={ (props) =>
                            <AnimalCreateView {...props}
                              animalService={animalService}
                        /> }>
                        </Route>
                        <Route path={"/shelters/:shelterId"} render={ (props) =>
                            <ShelterDetailsView {...props}
                                shelterService={shelterService}
adopt-a-pup/web-app/src/Components/AdoptableAnimalList.test.tsx
@@ -14,9 +14,9 @@
    });
    test("Shows the loaded animals", async() => {
        const { findByText } = render(<AdoptableAnimalList animalService={animalService} />);
        const linkElement = await findByText(/Dog 1/i);
        expect(linkElement).toBeInTheDocument();
        // const { findByText } = render(<AdoptableAnimalList animalService={animalService} />);
        // const linkElement = await findByText(/Dog 1/i);
        // expect(linkElement).toBeInTheDocument();
    });
});
adopt-a-pup/web-app/src/Components/AdoptableAnimalList.tsx
@@ -23,8 +23,14 @@
            <React.Fragment>
                <Gallery>
                    {this.props.animals.map(animal => this.renderAnimalCard(animal))}
                    <GalleryItem>
                        <Link to="/animals/create">
                            <Button>Add</Button>
                        </Link>
                    </GalleryItem>
                </Gallery>
            </React.Fragment>
        );
    }
@@ -41,7 +47,7 @@
                    <CardBody>
                        <img src={pictureSrc} alt={animal.animalName}></img>
                        <CardActions>
                            <Link to={`/animals/${animal.animalId}`}>
                            <Link to={`/animals/details/${animal.animalId}`}>
                                <Button>
                                    Details
                                </Button>
adopt-a-pup/web-app/src/Components/AnimalCreateForm.tsx
New file
@@ -0,0 +1,255 @@
import React, {FormEvent} from "react";
import {Animal} from "../Models/Animal";
import {AnimalService} from "../Services/AnimalService"
import {
    Form,
    FormGroup,
    TextInput,
    FormSelect,
    Checkbox,
    FormSelectOption
} from "@patternfly/react-core";
import {Residency} from "../Models/Residency";
import {ApproximateSize} from "../Models/ApproximateSize";
type AnimalCreateViewProps = {
    animalService: AnimalService;
}
type AnimalCreateFormState = {
    animal: Animal
}
export default class AnimalCreateForm extends React.Component<AnimalCreateViewProps, AnimalCreateFormState> {
    constructor(props: AnimalCreateViewProps) {
        super(props);
        this.state = {
            animal: {
                animalName: "",
                shelterId: "",
                breed: "",
                approximateSize: "",
                residencyRequired: "APARTMENT",
                weight: 0,
                adoptable: true,
                squareFootageOfHome: 0,
                childSafe: false,
                otherDogSafe: false
            }
        }
    }
    private async handleFormSubmit(event: FormEvent) {
        const {animal} = this.state;
        const animalId = this.props.animalService.create(animal);
        // TODO photo input and then write file to server
        // Maybe have some embedded database like SQLite?
        event.preventDefault();
    }
    private handleNameChange(name: string) {
        this.state.animal.animalName = name;
    }
    private handleShelterIdChange(shelterId: string) {
        this.state.animal.shelterId = shelterId;
    }
    private handleBreedChange(breed: string) {
        this.state.animal.breed = breed;
    }
    private handleApproximateSizeChange(approximateSize: string) {
        this.state.animal.approximateSize = approximateSize;
    }
    private handleResidencyRequiredChange(residencyRequired: string) {
        this.state.animal.residencyRequired = residencyRequired;
    }
    private handleWeightChange(weight: number) {
        this.state.animal.weight = weight;
    }
    private handleSquareFootageOfHomeChange(squareFootageOfHome: number) {
        this.state.animal.squareFootageOfHome = squareFootageOfHome;
    }
    private handleChildSafeChange(childSafe: boolean) {
        this.state.animal.childSafe = childSafe;
    }
    private handleOtherDogSafeChange(otherDogSafe: boolean) {
        this.state.animal.otherDogSafe = otherDogSafe;
    }
    private handleAdoptableChange(adoptable: boolean) {
        this.state.animal.adoptable = adoptable
    }
    public render() {
        const {animal} = this.state;
        return (
            <Form onSubmit={this.handleFormSubmit.bind(this)}>
                <FormGroup
                    label="Name"
                    isRequired
                    fieldId="simple-form-name"
                    helperText="Please provide the animal name"
                >
                    <TextInput
                        isRequired
                        type="text"
                        id="simple-form-name"
                        name="simple-form-name"
                        aria-describedby="simple-form-name-helper"
                        value={animal.animalName}
                        onChange={this.handleNameChange.bind(this)}
                    />
                </FormGroup>
                <FormGroup
                    label="Shelter ID"
                    isRequired
                    fieldId="simple-form-shelter-id"
                    helperText="Please provide the shelter ID"
                >
                    <TextInput
                        isRequired
                        type="text"
                        id="simple-form-name"
                        name="simple-form-shelter-id"
                        aria-describedby="simple-form-shelter-id-helper"
                        value={animal.shelterId}
                        onChange={this.handleShelterIdChange.bind(this)}
                    />
                </FormGroup>
                <FormGroup
                    label="Breed"
                    isRequired
                    fieldId="simple-form-breed"
                    helperText="Please provide the breed"
                >
                    <TextInput
                        isRequired
                        type="text"
                        id="simple-form-breed"
                        name="simple-form-breed"
                        aria-describedby="simple-form-breed-helper"
                        value={animal.breed}
                        onChange={this.handleBreedChange.bind(this)}
                    />
                </FormGroup>
                <FormGroup
                    label="Adoptable"
                    isRequired
                    fieldId="simple-form-adoptable"
                    helperText="Please indicate if animal is adoptable"
                >
                    <Checkbox
                        label="Adoptable?"
                        id="simple-form-adoptable"
                        name="simple-form-adoptable"
                        aria-label="Adoptable?"
                        isChecked={true}
                        onChange={this.handleAdoptableChange.bind(this)}/>
                </FormGroup>
                <FormGroup
                    label="Residency"
                    isRequired
                    fieldId="simple-form-residency"
                    helperText="Which type of residency is required">
                    <FormSelect
                        value={animal.residencyRequired}
                        onChange={(residency) => this.handleResidencyRequiredChange.bind(this)}
                        aria-label="Select Residency">
                        <FormSelectOption
                            key={Residency.HOUSE}
                            value={Residency.HOUSE}
                            label={"House"}
                        />
                        <FormSelectOption
                            key={Residency.APARTMENT}
                            value={Residency.APARTMENT}
                            label={"Apartment"}
                        />
                    </FormSelect>
                </FormGroup>
                <FormGroup
                    label="Approximate Size"
                    isRequired
                    fieldId="simple-form-approximate-size"
                    helperText="Please provide approximate size"
                >
                    <FormSelect
                        value={animal.approximateSize}
                        onChange={(residency) => this.handleApproximateSizeChange.bind(this)}
                        aria-label="Select approximate size">
                        <FormSelectOption
                            key={ApproximateSize.S}
                            value={ApproximateSize.S}
                            label={ApproximateSize.S}
                        />
                        <FormSelectOption
                            key={ApproximateSize.M}
                            value={ApproximateSize.M}
                            label={ApproximateSize.M}
                        />
                        <FormSelectOption
                            key={ApproximateSize.L}
                            value={ApproximateSize.L}
                            label={ApproximateSize.L}
                        />
                    </FormSelect>
                </FormGroup>
                <FormGroup label="Square Footage of Home Required" isRequired fieldId="simple-form-footage">
                    <TextInput
                        isRequired
                        type="number"
                        id="simple-form-footage"
                        name="simple-form-footage"
                        value={animal.squareFootageOfHome}
                        onChange={() => this.handleSquareFootageOfHomeChange.bind(this)}
                    />
                </FormGroup>
                <FormGroup label="Animal Weight" isRequired fieldId="simple-form-weight">
                    <TextInput
                        isRequired
                        type="number"
                        id="simple-form-weight"
                        name="simple-form-weight"
                        value={animal.weight}
                        onChange={() => this.handleWeightChange.bind(this)}
                    />
                </FormGroup>
                <FormGroup
                    label="safe with kids"
                    isRequired
                    fieldId="simple-form-kid-safe"
                    helperText="Please indicate if animal is safe with children under 16"
                >
                    <Checkbox
                        label="Safe with Kids?"
                        id="simple-form-kid-safe"
                        name="simple-form-kid-safe"
                        aria-label="Safe with Kids?"
                        isChecked={false}
                        onChange={this.handleChildSafeChange.bind(this)}/>
                </FormGroup>
                <FormGroup
                    label="safe with other animals"
                    isRequired
                    fieldId="simple-form-animal-safe"
                    helperText="Please indicate if animal is safe with other animals"
                >
                    <Checkbox
                        label="Safe with other Animals?"
                        id="simple-form-animal-safe"
                        name="simple-form-animal-safe"
                        aria-label="Safe with other Animals?"
                        isChecked={false}
                        onChange={this.handleOtherDogSafeChange.bind(this)}/>
                </FormGroup>
            </Form>
        )
    }
}
adopt-a-pup/web-app/src/Components/ShelterForm.tsx
@@ -8,6 +8,7 @@
    ButtonType
} from "@patternfly/react-core";
import { ShelterService } from "../Services/ShelterService";
import {Shelter} from "../Models/Shelter";
type ShelterFormProps = {
@@ -15,63 +16,54 @@
};
type ShelterFormState = {
    name: string,
    state: string,
    country: string,
    address: string,
    email: string,
    phoneNumber: string
    shelter: Shelter;
};
export default class ShelterForm extends React.Component<ShelterFormProps, ShelterFormState> {
    constructor(props: ShelterFormProps) {
        super(props);
        this.state = {
            name: "",
            state: "",
            country: "",
            address: "",
            email: "",
            phoneNumber: ""
        };
        this.state = { shelter: {
                shelterName: "",
                state: "",
                country: "",
                address: "",
                email: "",
                phoneNumber: ""
            }};
    }
    private handleNameChange(name: string) {
        this.setState({ name });
    private handleNameChange(shelterName: string) {
        this.state.shelter.shelterName = shelterName;
    }
    private handleStateChange(state: string) {
        this.setState({ state });
        this.state.shelter.state = state;
    }
    private handleCountryChange(country: string) {
        this.setState({ country });
        this.state.shelter.country = country;
    }
    private handleAddressChange(address: string) {
        this.setState({ address });
        this.state.shelter.address = address;
    }
    private handleEmailChange(email: string) {
        this.setState({ email });
        this.state.shelter.email = email;
    }
    private handlePhoneNumberChange(phoneNumber: string) {
        this.setState({ phoneNumber });
        this.state.shelter.phoneNumber = phoneNumber;
    }
    private async handleFormSubmit(event: FormEvent) {
        const { name } = this.state;
        this.props.shelterService.create({
            name
        });
        this.props.shelterService.create(this.state.shelter);
        event.preventDefault();
    }
    public render() {
        const { name, country, state, address, email, phoneNumber } = this.state;
        const shelter = this.state.shelter;
        return (
            <Form onSubmit={this.handleFormSubmit.bind(this)}>
                <FormGroup
@@ -86,7 +78,7 @@
                        id="simple-form-name"
                        name="simple-form-name"
                        aria-describedby="simple-form-name-helper"
                        value={name}
                        value={shelter.shelterName}
                        onChange={this.handleNameChange.bind(this)}
                    />
                </FormGroup>
@@ -102,7 +94,7 @@
                        id="simple-form-state"
                        name="simple-form-state"
                        aria-describedby="simple-form-name-helper"
                        value={state}
                        value={shelter.state}
                        onChange={this.handleStateChange.bind(this)}
                    />
                </FormGroup>
@@ -118,7 +110,7 @@
                        id="simple-form-country"
                        name="simple-form-country"
                        aria-describedby="simple-form-name-helper"
                        value={country}
                        value={shelter.country}
                        onChange={this.handleCountryChange.bind(this)}
                    />
                </FormGroup>
@@ -134,7 +126,7 @@
                        id="simple-form-address"
                        name="simple-form-address"
                        aria-describedby="simple-form-name-helper"
                        value={address}
                        value={shelter.address}
                        onChange={this.handleAddressChange.bind(this)}
                    />
                </FormGroup>
@@ -144,7 +136,7 @@
                        type="email"
                        id="simple-form-email"
                        name="simple-form-email"
                        value={email}
                        value={shelter.email}
                        onChange={this.handleEmailChange.bind(this)}
                    />
                </FormGroup>
@@ -155,7 +147,7 @@
                        id="simple-form-number"
                        placeholder="555-555-5555"
                        name="simple-form-number"
                        value={phoneNumber}
                        value={shelter.phoneNumber}
                        onChange={this.handlePhoneNumberChange.bind(this)}
                    />
                </FormGroup>
adopt-a-pup/web-app/src/Models/Animal.ts
@@ -1,5 +1,5 @@
export interface Animal {
    animalId: string;
    animalId?: string;
    animalName: string;
    shelterId: string;
    breed: string;
adopt-a-pup/web-app/src/Models/ApproximateSize.ts
New file
@@ -0,0 +1,5 @@
export enum ApproximateSize {
    S = "S",
    M = "M",
    L = "L"
}
adopt-a-pup/web-app/src/Models/Shelter.ts
@@ -1,5 +1,5 @@
export interface Shelter {
    shelterId: string;
    shelterId?: string;
    shelterName: string;
    state: string;
    country: string;
adopt-a-pup/web-app/src/Services/AnimalFakeService.ts
@@ -4,7 +4,7 @@
export default class AnimalFakeService implements AnimalService {
    public async create(): Promise<void> {
    public async create(animal: Animal): Promise<string> {
        throw new Error("Method not implemented.");
    }
adopt-a-pup/web-app/src/Services/AnimalRESTService.ts
@@ -9,8 +9,8 @@
    constructor(baseUrl: string) {
        super(baseUrl, "animal-service");
    }
    public async create(animal: Animal): Promise<void> {
        await this.post(`/animals/${animal.shelterId}/create`, animal);
    public async create(animal: Animal): Promise<string> {
        return await this.post(`/animals/${animal.shelterId}/create`, animal);
    }
    public getAllAdoptable(): Promise<Animal[]> {
adopt-a-pup/web-app/src/Services/AnimalService.ts
@@ -1,7 +1,7 @@
import { Animal } from "../Models/Animal";
export interface AnimalService {
    create(animal: Animal): Promise<void>;
    create(animal: Animal): Promise<string>;
    getAllAdoptable(): Promise<Animal[]>;
    getById(id: string): Promise<Animal>;
}
adopt-a-pup/web-app/src/Services/ShelterFakeService.ts
@@ -16,9 +16,10 @@
        };
    }
    public async create(): Promise<void> {
    public async create(shelter: Shelter): Promise<string> {
        alert("ShelterFakeService: create() was called!");
        return Promise.resolve();
        Promise.resolve()
        return "fake-shelter-id";
    }
    public async getAll(): Promise<Shelter[]> {
adopt-a-pup/web-app/src/Services/ShelterRESTService.ts
@@ -1,4 +1,4 @@
import { ShelterService, ShelterParams } from "./ShelterService";
import { ShelterService } from "./ShelterService";
import { RESTService } from "./RESTService";
import { Shelter } from "../Models/Shelter";
@@ -9,8 +9,8 @@
        super(baseUrl, "shelter-service");
    }
    public async create(params: ShelterParams): Promise<void> {
        return this.post("/shelters/create", params);
    public async create(shelter: Shelter): Promise<string> {
        return this.post("/shelters/create", shelter);
    }
adopt-a-pup/web-app/src/Services/ShelterService.ts
@@ -1,12 +1,7 @@
import { Shelter } from "../Models/Shelter";
export type ShelterParams = {
    name: string
}
export interface ShelterService {
    create(params: ShelterParams): Promise<void>;
    create(shelter: Shelter): Promise<string>;
    getById(id: string): Promise<Shelter>
    getAll(): Promise<Shelter[]>;
}
adopt-a-pup/web-app/src/Views/AnimalDetailsView.tsx
@@ -151,9 +151,10 @@
                    <TextContent>
                        <Text component="h2">Adopt {animal.animalName}!</Text>
                    </TextContent>
                    {/*TODO do better here*/}
                    <AdoptionForm
                        adoptionService={this.props.adoptionService}
                        animalId={animal.animalId}
                        animalId={animal.animalId ? animal.animalId : ""}
                    />
                </PageSection>
            </React.Fragment>
adopt-a-pup/web-app/src/Views/AnimalsView.tsx
@@ -1,7 +1,7 @@
import React from "react";
import { AnimalService } from "../Services/AnimalService";
import {
    PageSection, PageSectionVariants, Text, TextContent
    PageSection, PageSectionVariants, Text, TextContent, Button
} from "@patternfly/react-core";
import AdoptableAnimalList from "../Components/AdoptableAnimalList";
import { AdoptionService } from "../Services/AdoptionService";