Skip to content

Commit

Permalink
Add search day-care funconallity to dog-owner homepage.
Browse files Browse the repository at this point in the history
The dog-owner user can search for day-care that relevant for him.
If the user didnt search for day-care he will see all Day-Cares in the application.

Signed-off-by: tamirmatok <[email protected]>
  • Loading branch information
tamirmatok committed May 4, 2022
1 parent ce941d3 commit cd2ab3d
Show file tree
Hide file tree
Showing 6 changed files with 218 additions and 36 deletions.
31 changes: 31 additions & 0 deletions daycare/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from django import forms
from .models import DayCare, Area
from django.db.models import Max, Min


class DayCareSearchForm(forms.Form):
min_price = DayCare.objects.all().aggregate(Min('price_per_day')).get('price_per_day__min')
max_price = DayCare.objects.all().aggregate(Max('price_per_day')).get('price_per_day__max')
start_date = forms.DateField(required=True, label=' Start date',
widget=forms.widgets.DateInput(attrs={'class': 'form-control', 'type': 'date'}))
end_date = forms.DateField(required=True, label=' End date',
widget=forms.widgets.DateInput(attrs={'class': 'form-control', 'type': 'date'}))

area = forms.ChoiceField(required=False, label='Area',
choices=(Area.choices + [('', 'All'), ]), initial="")
city = forms.CharField(required=False, label='City')
name = forms.CharField(required=False, label='Day care name')
price_per_day = forms.ChoiceField(required=False, label='Max price',
choices=((str(x), x) for x in range(min_price, max_price + 11, 10)),
initial=str(max_price))

def clean(self):
cleaned_data = super().clean()
start_date = cleaned_data.get("start_date")
end_date = cleaned_data.get("end_date")

if start_date and end_date:
if end_date < start_date:
self._errors['end_date'] = self.error_class(["End date should be greater!"])

return cleaned_data
60 changes: 46 additions & 14 deletions dogowner/templates/dogowner/dog_owner_homepage.html
Original file line number Diff line number Diff line change
@@ -1,25 +1,57 @@
{% extends "main/base_template.html" %}
{% load crispy_forms_tags %}
{% load static %}

{% block stylesheets %}
<link rel="stylesheet" href="{% static 'CSS/dog_owner_homepage.css' %}">
{% endblock %}

{% block content %}
<div class="row row-cols-1 g-3 cards">
<div style="display: flex; flex-direction: row; flex-wrap: wrap">
{% for daycare in daycares %}
<div class="card">
<img src="{{ daycare.get_daycare_primary_image_url }}" alt="{{ daycare.name }} image" class="card-img-top">
<div class="card-body">
<div style="display: flex; flex-direction: row">
<h5 class="card-title">{{ daycare.name }}</h5>

<div class="row">
<form method='POST' action=''>{% csrf_token %}
<div class="col-4" id="searchBoxArea">
<span>Search for daycare:</span>
<div class="form-group">
{{ form.start_date|as_crispy_field }}
</div>
<div class="form-group">
{{ form.end_date|as_crispy_field }}
</div>
<div class="form-group">
{{ form.price_per_day|as_crispy_field }}
</div>
<div class="form-group">
{{ form.area|as_crispy_field }}
</div>
<div class="form-group">
{{ form.city|as_crispy_field }}
</div>
<div class="form-group">
{{ form.name|as_crispy_field }}
</div>
<input type="submit" value='Search' style="height:30px;width:70px">
</div>
</form>
<div class="col-10">
<span id="searchResult">Found {{ day_care_queryset.count }} results for your dog!</span>
<div class="cards">
{% for daycare in day_care_queryset %}
<div class="card">
<img src="{{ daycare.get_daycare_primary_image_url }}" alt="{{ daycare.name }} image" class="card-img-top">
<div class="card-body">
<div style="display: flex; flex-direction: row">
<h5 class="card-title">{{ daycare.name }}</h5>
</div>
<p class="card-text">{{ daycare.area | truncatechars:20 }}</p>
<p class="card-text">{{ daycare.city | truncatechars:20 }}</p>
<p class="card-text">{{ daycare.price_per_day | truncatechars:20 }}</p>
<p class="card-text">{{ daycare.description | truncatechars:35}}</p>
<a href="/daycare/{{ daycare.id }}" class="btn btn-warning">Daycare Profile</a>
</div>
</div>
{% endfor %}
</div>
</div>
<p class="card-text">{{ daycare.description | truncatechars:250 }}</p>
<a href="/daycare/{{ daycare.id }}" class="btn btn-primary">Daycare Profile</a>
</div>
</div>
{% endfor %}
</div>
</div>
{% endblock %}
23 changes: 22 additions & 1 deletion dogowner/views.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,32 @@
from django.contrib.auth.decorators import login_required
from django.shortcuts import render
from daycare.models import DayCare
from daycare.forms import DayCareSearchForm
from orders.models import Order


@login_required()
def dog_owner_home(request):
form = DayCareSearchForm(request.POST or None)
day_care_queryset = DayCare.objects.all()
context = {
'daycares': DayCare.objects.all(),
'day_care_queryset': day_care_queryset,
'form': form
}
if request.method == 'POST':
if form.is_valid():
filter_day_cares = DayCare.objects.filter(area__startswith=form['area'].value(),
city__icontains=form['city'].value(),
name__icontains=form['name'].value(),
price_per_day__lte=form['price_per_day'].value())

available_day_cares = Order.get_all_day_cares_available_on_dates(form['start_date'].value(),
form['end_date'].value())
day_care_queryset = filter_day_cares.intersection(available_day_cares)

context = {
'day_care_queryset': day_care_queryset,
'form': form
}

return render(request, 'dogowner/dog_owner_homepage.html', context)
1 change: 0 additions & 1 deletion main/templates/main/base_template.html
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
{% if request.user.is_authenticated %}
<li class="nav-item"><a class="nav-link text-white" href="/profile">Profile</a></li>
<li class="nav-item"><a class="nav-link text-white" href="">Orders</a></li>
<li class="nav-item"><a class="nav-link text-white" href="">Search</a></li>
<li class="nav-item"><a class="nav-link text-white" href="">Chats</a></li>
{% endif %}
<li class="nav-item"><a class="nav-link text-white" href="/about">About</a></li>
Expand Down
80 changes: 80 additions & 0 deletions main/tests.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,24 @@
import pytest
from dogowner.models import DogOwner
from daycare.models import DayCare
from orders.models import Order


@pytest.fixture
def create_dog_owner_user():
return DogOwner.create(email='[email protected]',
username='dogOwnerUser01',
password='password123',
dog_name='dog name',
first_name='test',
last_name='user',
phone_number=1234567890,
dog_race='dog race',
dog_picture_url='https://www.google.com/user1.jpg',
dog_age=4,
dog_weight=2,
dog_gender='M'
)


@pytest.mark.django_db
Expand Down Expand Up @@ -77,3 +96,64 @@ def test_dog_owner_homepage_is_visible_for_dog_owner(self, client, create_dog_ow
response = client.get("/homepage/")
assert response.status_code == 200
assert list(response.context['daycares']) == list(DayCare.objects.all())


@pytest.mark.django_db
class TestDogOwnerHomePageView:
def test_dog_owner_present_all_day_cares_at_entrypoint(self, client, create_dog_owner_user):
client.force_login(user=create_dog_owner_user.user)
response = client.get("/homepage/")
day_care_queryset = response.context['day_care_queryset']
assert set(day_care_queryset) == set(DayCare.objects.all())

def test_search_daycare_present_only_available_daycares_on_specific_dates(self, client, create_dog_owner_user):
test_day_care = DayCare.create(username='testuser', email='[email protected]', password='test_password',
name='name', description='test description', price_per_day=100,
capacity=1, area='CENTER', city='tel aviv', address='address')
client.force_login(user=create_dog_owner_user.user)
search_form = {'area': "",
'city': "",
'price_per_day': 100,
'name': "",
'start_date': "2022-05-03",
'end_date': "2022-05-08",
}
response = client.post('/homepage/', search_form, follow=True)
day_care_queryset = response.context['day_care_queryset']
assert test_day_care in day_care_queryset
Order.create(dog_owner_id=DogOwner.objects.get(id=1), daycare_id=test_day_care,
start_date="2022-05-02", end_date="2022-08-02", price_per_day=100).approve_order()
response = client.post('/homepage/', search_form, follow=True)
assert test_day_care not in response.context['day_care_queryset']

def test_successful_dog_owner_search_for_day_care(self, client, create_dog_owner_user):
client.force_login(user=create_dog_owner_user.user)
search_form = {'area': "C",
'city': "tel aviv",
'price_per_day': 800,
'name': "",
'start_date': "2022-05-03",
'end_date': "2022-05-08",
}
response = client.post('/homepage/', search_form, follow=True)
day_care_queryset = response.context['day_care_queryset']
available_day_cares = Order.get_all_day_cares_available_on_dates("2022-05-03", "2022-05-08")
filters_day_cares = DayCare.objects.filter(area__startswith='C',
city__icontains="tel aviv",
price_per_day__lte=800)
assert set(day_care_queryset) == set(available_day_cares.intersection(filters_day_cares))

def test_search_for_day_care_with_start_date_greater_than_end_date_show_error_and_present_all_daycares(
self, client, create_dog_owner_user):
client.force_login(user=create_dog_owner_user.user)
search_form = {'area': "C",
'city': "tel aviv",
'price_per_day': 800,
'name': "",
'start_date': "2022-05-03",
'end_date': "2022-05-01",
}
response = client.post('/homepage/', search_form, follow=True)
day_care_queryset = response.context['day_care_queryset']
assert set(day_care_queryset) == set(DayCare.objects.all())
assert response.context['form']._errors['end_date']
59 changes: 39 additions & 20 deletions static/CSS/dog_owner_homepage.css
Original file line number Diff line number Diff line change
@@ -1,32 +1,24 @@
.cards
{
display: flex;
flex-direction: row;
flex-wrap: wrap;
margin-left: 50px;
justify-content: center;
align-items: center;
float:left;
margin: 0 0 0 5em;
position:relative;
width:100%;
}

.row
{
height: 30rem;
width: 120rem;
margin-left: 200px;
#searchResult {
font-weight:bold;
position: relative;
left: 6.3em;
top:30px;
}

.card
{
width: 18.5%;
width: 330px;
height: 30rem;
margin: 60px 60px 0 60px;
max-width: 100%;
}

.card-body
{
display: flex;
flex-direction: column;
float:left;
margin: 60px 20px 0 20px;
}

.card-body .btn
Expand All @@ -40,3 +32,30 @@
height: 200px;
}

#searchBoxArea {
background-color:#dcdcdc;
left:5em;
top: 5.2em;
max-width:100%;
padding: 2em 2em 2em 2em;
}

#searchBoxArea span {
font-weight:bold;
font-size:18px;
color:#3e3e3e;
padding: 5px 0 1em 0;
float:left;
}

#searchBoxArea input[type="submit"] {
background-color:#3e3e3e;
border: 0;
border-radius:12px;
color:#FFF;
}

#searchBoxArea input[type="submit"]:hover {
background-color:#1e1e1e;
}

0 comments on commit cd2ab3d

Please sign in to comment.