Skip to content

Commit 30ea82d

Browse files
committed
Issue #254: Adoption & Foster records
1 parent 4768326 commit 30ea82d

File tree

5 files changed

+299
-27
lines changed

5 files changed

+299
-27
lines changed

src/client/src/pages/DataView360/View/View.js

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import ContactInfo from './components/ContactInfo';
1717
import Volunteer from './components/Volunteer';
1818
import Donations from './components/Donations';
1919
import Adoptions from './components/Adoptions';
20+
import Fosters from './components/Fosters';
2021
import {matchPath} from "react-router";
2122

2223

@@ -38,6 +39,7 @@ class View360 extends Component {
3839

3940
this.state = {
4041
participantData: {},
42+
animalData: {},
4143
matchId: undefined,
4244
isDataBusy: false,
4345
}
@@ -57,12 +59,34 @@ class View360 extends Component {
5759
let response = await fetch(`/api/360/${this.state.matchId}`);
5860
response = await response.json();
5961

62+
let animalInfo = await fetch(`/api/person/${this.state.matchId}/animals`);
63+
animalInfo = await animalInfo.json()
64+
const animalIds = _.keys(animalInfo);
65+
66+
for (let id of animalIds) {
67+
this.getAnimalEvents(id).then((events) => {
68+
animalInfo[id]["events"] = events[id]
69+
animalInfo[id]["adoptionEvents"] = _.filter(events[id], function(e) {
70+
return e["Type"] && e["Type"].toLowerCase().includes("adopt");
71+
});
72+
animalInfo[id]["fosterEvents"] = _.filter(events[id], function(e) {
73+
return e["Type"] && e["Type"].toLowerCase().includes("foster");
74+
});
75+
})
76+
}
77+
6078
this.setState({
6179
participantData: response.result,
80+
animalData: animalInfo,
6281
isDataBusy: false
6382
});
6483
}
6584

85+
async getAnimalEvents(animalId) {
86+
let response = await fetch(`/api/animal/${animalId}/events`);
87+
return await response.json()
88+
}
89+
6690
extractVolunteerActivity() {
6791
const volgistics = _.find(this.state.participantData.contact_details, {"source_type": "volgistics"}) || {};
6892
let volunteerActivity = {"life_hours": 0, "ytd_hours": 0, "start_date": "N/A"}
@@ -114,7 +138,8 @@ class View360 extends Component {
114138
<Grid item sm>
115139
<Grid container direction="column" style={{"marginTop": "1em"}}>
116140
<Donations donations={_.get(this.state, 'participantData.donations')}/>
117-
<Adoptions adoptions={_.get(this.state, 'participantData.adoptions')}/>
141+
<Adoptions adoptions={_.get(this.state, 'animalData')}/>
142+
<Fosters fosters={_.get(this.state, 'animalData')}/>
118143
<Volunteer volunteer={this.extractVolunteerActivity()}
119144
volunteerShifts={_.get(this.state, 'participantData.shifts')}/>
120145
</Grid>

src/client/src/pages/DataView360/View/components/Adoptions.js

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import React, {Component} from 'react';
22
import {
3+
Button,
4+
Dialog,
35
Paper,
46
Typography,
57
Table,
@@ -18,6 +20,8 @@ import moment from "moment";
1820
import Grid from "@material-ui/core/Grid";
1921
import PetsIcon from "@material-ui/icons/Pets";
2022

23+
import EventsModal from './EventsModal';
24+
2125

2226
const customStyles = theme => ({
2327
spaceIcon: {
@@ -26,21 +30,36 @@ const customStyles = theme => ({
2630
},
2731
headerCell: {
2832
fontWeight: "bold",
29-
}
33+
},
34+
paper: {
35+
position: 'absolute',
36+
width: 400,
37+
backgroundColor: theme.palette.background.paper,
38+
border: '2px solid #000',
39+
boxShadow: theme.shadows[5],
40+
padding: theme.spacing(2, 4, 3),
41+
}
3042
});
3143

32-
const PET_COUNT = 3;
44+
const PET_COUNT = 5;
45+
46+
let modalIsOpen = false;
47+
let modalData = [];
3348

3449
class Adoptions extends Component {
3550

36-
getLatestPets(petList) {
37-
let retVal;
51+
handleOpen(data) {
52+
modalIsOpen = true;
53+
modalData = data;
54+
}
3855

39-
if (petList) {
40-
retVal = petList.slice(0, PET_COUNT);
41-
}
56+
handleClose() {
57+
modalIsOpen = false;
58+
modalData = [];
59+
}
4260

43-
return retVal;
61+
getLatestPets(petObject) {
62+
return petObject;
4463
}
4564

4665
getAnimalAge(epochTime) {
@@ -60,7 +79,7 @@ class Adoptions extends Component {
6079
<PetsIcon color='primary' fontSize='inherit'/>
6180
</Grid>
6281
<Grid item>
63-
Adoption/Foster Records {(numOfPets > 3) && "(Showing 3 Pets out of " + numOfPets + ")"}
82+
Adoption Records {(numOfPets > PET_COUNT) && "(Showing " + PET_COUNT + " Pets out of " + numOfPets + ")"}
6483
</Grid>
6584
<Grid item>
6685
<IconButton style={{'padding': 0, 'paddingLeft': 5}} color="primary" aria-label="link" component="span">
@@ -69,7 +88,17 @@ class Adoptions extends Component {
6988
</Grid>
7089
</Grid>
7190
</Typography>
72-
91+
<Dialog
92+
open={modalIsOpen}
93+
onClose={this.handleClose}
94+
aria-labelledby="simple-dialog-title"
95+
aria-describedby="simple-dialog-description"
96+
>
97+
<EventsModal data={modalData}/>
98+
<Button variant="contained" color="primary" onClick={this.handleClose}>
99+
Close
100+
</Button>
101+
</Dialog>
73102
<TableContainer component={Paper} style={{"marginBottom": "1em"}} variant='outlined'>
74103
<Table>
75104
<TableHead>
@@ -79,11 +108,11 @@ class Adoptions extends Component {
79108
<TableCell className={classes.headerCell} align="center">Breed</TableCell>
80109
<TableCell className={classes.headerCell} align="center">Age</TableCell>
81110
<TableCell className={classes.headerCell} align="center">Photo</TableCell>
111+
<TableCell className={classes.headerCell} align="center"></TableCell>
82112
</TableRow>
83113
</TableHead>
84114
<TableBody>
85115
{_.map(latestPets, (adoptionInfo, index) => {
86-
87116
const photoLink = _.get(adoptionInfo, "Photos.[0]");
88117
const photo = <img src={photoLink} alt="animal" style={{"maxWidth": "100px"}}/>
89118

@@ -94,6 +123,11 @@ class Adoptions extends Component {
94123
<TableCell
95124
align="center">{this.getAnimalAge(adoptionInfo["DOBUnixTime"])}</TableCell>
96125
<TableCell align="center">{photo}</TableCell>
126+
<TableCell align="center">
127+
<Button variant="contained" color="primary" onClick={() => this.handleOpen(adoptionInfo.adoptionEvents)}>
128+
More
129+
</Button>
130+
</TableCell>
97131
</TableRow>
98132
})}
99133
</TableBody>
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import React, { Component, Fragment } from 'react';
2+
import {
3+
Paper,
4+
Table,
5+
TableContainer,
6+
TableHead,
7+
TableBody,
8+
TableRow,
9+
TableCell,
10+
} from '@material-ui/core';
11+
import { withStyles } from '@material-ui/core/styles';
12+
import _ from 'lodash';
13+
14+
15+
const customStyles = theme => ({
16+
spaceIcon: {
17+
marginTop: 3,
18+
marginRight: 3
19+
},
20+
headerCell: {
21+
fontWeight: "bold",
22+
},
23+
paper: {
24+
position: 'absolute',
25+
width: 400,
26+
backgroundColor: theme.palette.background.paper,
27+
border: '2px solid #000',
28+
boxShadow: theme.shadows[5],
29+
padding: theme.spacing(2, 4, 3),
30+
}
31+
});
32+
33+
class EventsModal extends Component {
34+
35+
render() {
36+
37+
return (
38+
<Fragment>
39+
<TableContainer component={Paper} style={{ "marginBottom": "1em" }} variant='outlined'>
40+
<Table>
41+
<TableHead>
42+
<TableRow>
43+
<TableCell align="center">Subtype</TableCell>
44+
<TableCell align="center">Time</TableCell>
45+
<TableCell align="center">Type</TableCell>
46+
<TableCell align="center">User</TableCell>
47+
</TableRow>
48+
</TableHead>
49+
<TableBody>
50+
{_.map(this.props.data, (adoptionInfo, index) => {
51+
return <TableRow key={index}>
52+
<TableCell align="center">{adoptionInfo["Subtype"]}</TableCell>
53+
<TableCell align="center">{adoptionInfo["Time"]}</TableCell>
54+
<TableCell align="center">{adoptionInfo["Type"]}</TableCell>
55+
<TableCell align="center">{adoptionInfo["User"]}</TableCell>
56+
</TableRow>
57+
})}
58+
</TableBody>
59+
</Table>
60+
</TableContainer>
61+
</Fragment>)
62+
}
63+
}
64+
65+
export default withStyles(customStyles)(EventsModal);
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
import React, {Component} from 'react';
2+
import {
3+
Button,
4+
Dialog,
5+
Paper,
6+
Typography,
7+
Table,
8+
TableContainer,
9+
TableHead,
10+
TableBody,
11+
TableRow,
12+
TableCell,
13+
Container,
14+
IconButton
15+
} from '@material-ui/core';
16+
import LinkIcon from '@material-ui/icons/Link';
17+
import {withStyles} from '@material-ui/core/styles';
18+
import _ from 'lodash';
19+
import moment from "moment";
20+
import Grid from "@material-ui/core/Grid";
21+
import PetsIcon from "@material-ui/icons/Pets";
22+
23+
import EventsModal from './EventsModal';
24+
25+
26+
const customStyles = theme => ({
27+
spaceIcon: {
28+
marginTop: 3,
29+
marginRight: 3
30+
},
31+
headerCell: {
32+
fontWeight: "bold",
33+
}
34+
});
35+
36+
const PET_COUNT = 5;
37+
38+
let modalIsOpen = false;
39+
let modalData = [];
40+
41+
class Fosters extends Component {
42+
43+
handleOpen(data) {
44+
modalIsOpen = true;
45+
modalData = data;
46+
}
47+
48+
handleClose() {
49+
modalIsOpen = false;
50+
modalData = [];
51+
}
52+
53+
getLatestPets(petObject) {
54+
return petObject;
55+
}
56+
57+
getAnimalAge(epochTime) {
58+
let dateOfBirth = moment(epochTime * 1000);
59+
return moment().diff(dateOfBirth, 'years');
60+
}
61+
62+
render() {
63+
const {classes} = this.props;
64+
const numOfPets = _.size(this.props.fosters);
65+
const latestPets = this.getLatestPets(this.props.fosters);
66+
67+
return (<Container component={Paper} style={{"marginTop": "1em"}}>
68+
<Typography variant='h5'>
69+
<Grid container style={{"margin": "0.5em"}} direction={'row'}>
70+
<Grid item className={classes.spaceIcon}>
71+
<PetsIcon color='primary' fontSize='inherit'/>
72+
</Grid>
73+
<Grid item>
74+
Foster Records {(numOfPets > PET_COUNT) && `(Showing ${PET_COUNT} Pets out of " + numOfPets + ")`}
75+
</Grid>
76+
<Grid item>
77+
<IconButton style={{'padding': 0, 'paddingLeft': 5}} color="primary" aria-label="link" component="span">
78+
<LinkIcon />
79+
</IconButton>
80+
</Grid>
81+
</Grid>
82+
</Typography>
83+
<Dialog
84+
open={modalIsOpen}
85+
onClose={this.handleClose}
86+
aria-labelledby="simple-dialog-title"
87+
aria-describedby="simple-dialog-description"
88+
>
89+
<EventsModal data={modalData}/>
90+
<Button variant="contained" color="primary" onClick={this.handleClose}>
91+
Close
92+
</Button>
93+
</Dialog>
94+
<TableContainer component={Paper} style={{"marginBottom": "1em"}} variant='outlined'>
95+
<Table>
96+
<TableHead>
97+
<TableRow>
98+
<TableCell className={classes.headerCell} align="center">Name</TableCell>
99+
<TableCell className={classes.headerCell} align="center">Animal Type</TableCell>
100+
<TableCell className={classes.headerCell} align="center">Breed</TableCell>
101+
<TableCell className={classes.headerCell} align="center">Age</TableCell>
102+
<TableCell className={classes.headerCell} align="center">Photo</TableCell>
103+
<TableCell className={classes.headerCell} align="center"></TableCell>
104+
</TableRow>
105+
</TableHead>
106+
<TableBody>
107+
{_.map(latestPets, (fosterInfo, index) => {
108+
const photoLink = _.get(fosterInfo, "Photos.[0]");
109+
const photo = <img src={photoLink} alt="animal" style={{"maxWidth": "100px"}}/>
110+
111+
return <TableRow key={index}>
112+
<TableCell align="center">{fosterInfo["Name"]}</TableCell>
113+
<TableCell align="center">{fosterInfo["Type"]}</TableCell>
114+
<TableCell align="center">{fosterInfo["Breed"]}</TableCell>
115+
<TableCell
116+
align="center">{this.getAnimalAge(fosterInfo["DOBUnixTime"])}</TableCell>
117+
<TableCell align="center">{photo}</TableCell>
118+
<TableCell align="center">
119+
<Button variant="contained" color="primary" onClick={() => this.handleOpen(fosterInfo.fosterEvents)}>
120+
More
121+
</Button>
122+
</TableCell>
123+
</TableRow>
124+
})}
125+
</TableBody>
126+
</Table>
127+
</TableContainer>
128+
</Container>
129+
);
130+
}
131+
}
132+
133+
134+
export default withStyles(customStyles)(Fosters);

0 commit comments

Comments
 (0)