From d24a5b6c63a1cc35b2e9b1d72fe46a9ae4e9edc2 Mon Sep 17 00:00:00 2001 From: AlexMountain Date: Sun, 21 Mar 2021 22:05:04 -0400 Subject: [PATCH] Reunify all animals from SR and Owner pages. (#259) --- frontend/src/hotline/ServiceRequestDetails.js | 44 ++++++++++++++++- frontend/src/people/PersonDetails.js | 47 ++++++++++++++++++- hotline/models.py | 2 +- hotline/views.py | 11 ++++- people/views.py | 14 +++++- 5 files changed, 111 insertions(+), 7 deletions(-) diff --git a/frontend/src/hotline/ServiceRequestDetails.js b/frontend/src/hotline/ServiceRequestDetails.js index b1e5d2d1..1692edec 100644 --- a/frontend/src/hotline/ServiceRequestDetails.js +++ b/frontend/src/hotline/ServiceRequestDetails.js @@ -9,7 +9,7 @@ import { faClipboardCheck, faClipboardList, faComment, faEdit, faHouseDamage, faKey, faMapMarkedAlt, faMinusSquare, faPlusSquare, faTimes, faTrailer, faUsers } from '@fortawesome/free-solid-svg-icons'; -import { faCalendarEdit, faHomeAlt } from '@fortawesome/pro-solid-svg-icons'; +import { faCalendarEdit, faHomeAlt, faHomeHeart } from '@fortawesome/pro-solid-svg-icons'; import Header from '../components/Header'; import History from '../components/History'; import noImageFound from '../static/images/image-not-found.png'; @@ -64,10 +64,25 @@ function ServiceRequestDetails({id}) { visit_notes: [], }); + const [show, setShow] = useState(false); + const handleClose = () => setShow(false); const [animalToDelete, setAnimalToDelete] = useState({id:0, name:''}); const [showAnimalConfirm, setShowAnimalConfirm] = useState(false); const handleAnimalClose = () => setShowAnimalConfirm(false); + // Handle animal reunification submit. + const handleSubmit = async () => { + await axios.patch('/hotline/api/servicerequests/' + id + '/', {reunite_animals:true}) + .then(response => { + setData(prevState => ({ ...prevState, "status":"Closed", "animals":prevState['animals'].map(animal => ({...animal, status:animal.status !== 'DECEASED' ? 'REUNITED' : 'DECEASED'})) })); + handleClose() + }) + .catch(error => { + console.log(error.response); + }); + } + + // Handle animal removal submit. const handleAnimalSubmit = async () => { await axios.patch('/hotline/api/servicerequests/' + id + '/', {remove_animal:animalToDelete.id}) .then(response => { @@ -300,6 +315,19 @@ function ServiceRequestDetails({id}) { > + {data.status.toLowerCase() !== 'closed' ? + + Reunite all service request animals + + } + > + setShow(true)} style={{cursor:'pointer'}} className="ml-1 fa-move-up" inverse /> + + : ""}
@@ -517,6 +545,20 @@ function ServiceRequestDetails({id}) { + + + Confirm Animal Reunification + + +

+ Have all of the animals in this service request been reunited with their owner? +

+
+ + + + +
); }; diff --git a/frontend/src/people/PersonDetails.js b/frontend/src/people/PersonDetails.js index 5e8003d0..2ceb012c 100644 --- a/frontend/src/people/PersonDetails.js +++ b/frontend/src/people/PersonDetails.js @@ -1,11 +1,12 @@ import React, {useEffect, useState} from 'react'; import axios from "axios"; import { Link } from 'raviger'; -import { Card, ListGroup, OverlayTrigger, Tooltip } from 'react-bootstrap'; +import { Button, Card, ListGroup, Modal, OverlayTrigger, Tooltip } from 'react-bootstrap'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faClipboardList, faEdit, faPhone, faPlusSquare } from '@fortawesome/free-solid-svg-icons'; +import { faHomeHeart } from '@fortawesome/pro-solid-svg-icons'; import Moment from 'react-moment'; import Header from '../components/Header'; import History from '../components/History'; @@ -16,6 +17,21 @@ function PersonDetails({id}) { // Determine if this is an owner or reporter when creating a Person. var is_owner = window.location.pathname.includes("owner") + const [show, setShow] = useState(false); + const handleClose = () => setShow(false); + + // Handle animal reunification submit. + const handleSubmit = async () => { + await axios.patch('/people/api/person/' + id + '/', {reunite_animals:true}) + .then(response => { + setData(prevState => ({ ...prevState, "animals":prevState['animals'].map(animal => ({...animal, status:animal.status !== 'DECEASED' ? 'REUNITED' : 'DECEASED'})) })); + handleClose() + }) + .catch(error => { + console.log(error.response); + }); + } + const [data, setData] = useState({ first_name: '', last_name: '', @@ -73,7 +89,7 @@ function PersonDetails({id}) { placement="bottom" overlay={ - Add another owner + Add another owner for all of these animals } > @@ -166,6 +182,19 @@ function PersonDetails({id}) { > + {is_owner && data.animals.filter(animal => (!['REUNITED', 'DECEASED'].includes(animal.status))).length > 0 ? + + Reunite all owner animals + + } + > + setShow(true)} style={{cursor:'pointer'}} className="ml-1 fa-move-up" inverse /> + + : ""}
@@ -176,6 +205,20 @@ function PersonDetails({id}) { + + + Confirm Animal Reunification + + +

+ Have all of the animals been reunited with this owner? +

+
+ + + + +
); }; diff --git a/hotline/models.py b/hotline/models.py index 31ab35cf..62cbd221 100644 --- a/hotline/models.py +++ b/hotline/models.py @@ -13,7 +13,7 @@ class ServiceRequest(Location): #keys - owners = models.ManyToManyField(Person, blank=True) + owners = models.ManyToManyField(Person, blank=True, related_name='request') reporter = models.ForeignKey(Person, on_delete=models.SET_NULL, blank=True, null=True, related_name='reporter_service_request') status = models.CharField(max_length=10, choices=STATUS_CHOICES, blank=False, default='open') diff --git a/hotline/views.py b/hotline/views.py index 70df501b..1e6429f3 100644 --- a/hotline/views.py +++ b/hotline/views.py @@ -41,7 +41,16 @@ def perform_update(self, serializer): if service_request.status == 'canceled': service_request.animal_set.update(status='CANCELED') - action.send(self.request.user, verb='updated service request', target=service_request) + + if self.request.data.get('reunite_animals'): + service_request.animal_set.exclude(status='DECEASED').update(status='REUNITED', shelter=None, room=None) + for animal in service_request.animal_set.exclude(status='DECEASED'): + action.send(self.request.user, verb=f'changed animal status to reunited', target=animal) + service_request.status = 'closed' + service_request.save() + action.send(self.request.user, verb='closed service request', target=service_request) + else: + action.send(self.request.user, verb='updated service request', target=service_request) def get_queryset(self): queryset = ( diff --git a/people/views.py b/people/views.py index eaa587bf..c8f1db18 100644 --- a/people/views.py +++ b/people/views.py @@ -77,8 +77,18 @@ def perform_update(self, serializer): if change_dict: PersonChange.objects.create(user=self.request.user, person=person, changes=change_dict, reason=self.request.data.get('change_reason', '')) - # Record update action. - action.send(self.request.user, verb='updated person', target=person) + if self.request.data.get('reunite_animals'): + person.animal_set.exclude(status='DECEASED').update(status='REUNITED', shelter=None, room=None) + for animal in person.animal_set.exclude(status='DECEASED'): + action.send(self.request.user, verb=f'changed animal status to reunited', target=animal) + if person.request.exists(): + service_request = person.request.first() + service_request.status = 'closed' + service_request.save() + action.send(self.request.user, verb='closed service request', target=service_request) + else: + # Record update action. + action.send(self.request.user, verb='updated person', target=person) class OwnerContactViewSet(viewsets.ModelViewSet):