Skip to content

Commit

Permalink
Create reservation page for dog-owner user
Browse files Browse the repository at this point in the history
After a dog owner user has selected the daycare he wishes to book a place for his dog,
he will be directed to the daycare owner's home page where he can read more details about the daycare,
and make a reservation from there.

Signed-off-by: Erez Cohen <[email protected]>
  • Loading branch information
ErezCohenn committed May 12, 2022
1 parent 5a719c6 commit ce0284f
Show file tree
Hide file tree
Showing 13 changed files with 221 additions and 50 deletions.
1 change: 1 addition & 0 deletions Hotails/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,6 @@
path('homepage/', views.homepage, name='homepage'),
path('logout/', views.logout_view, name='logout'),
path('about/', views.about, name='about'),
path('visit_daycare_home/<int:daycare_id>', views.visit_daycare_home, name='visit_daycare_home'),
path('orders/', views.orders_view, name='orders'),
]
33 changes: 33 additions & 0 deletions daycare/forms.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,39 @@
from django import forms
from .models import DayCare, Area
from django.db.models import Max, Min
from django.core.validators import validate_email


class DateInput(forms.DateInput):
input_type = 'date'


class BookForm(forms.Form):
dog_name = forms.CharField(required=True, label='Dog guest name',
widget=forms.TextInput(attrs={'class': 'form-control',
'placeholder': 'Enter Dog Name', 'col': 80}))
email = forms.EmailField(required=True, label='Email',
widget=forms.EmailInput(attrs={'class': 'form-control', 'placeholder': 'Enter Email'}))
start_date = forms.DateField(required=True, label=' Check-in date',
widget=forms.widgets.DateInput(attrs={'class': 'form-control', 'type': 'date'}))
end_date = forms.DateField(required=True, label=' Check-out date',
widget=forms.widgets.DateInput(attrs={'class': 'form-control', 'type': 'date'}))
requests = forms.CharField(required=False, label='Special requests', widget=forms.Textarea
(attrs={'placeholder': 'Please write your requests here. Special requests cannot be guaranteed – '
'but the property will do its best to meet your needs', 'rows': 7, 'cols': 80}))
agree_terms = forms.BooleanField(required=True, label='I agree with the terms', widget=forms.CheckboxInput)

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

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


class DayCareSearchForm(forms.Form):
Expand Down
9 changes: 7 additions & 2 deletions daycare/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,7 @@ def create(email, username, password, name, description, price_per_day, capacity
validate_max_length(address, 50, "address")
validate_price(price_per_day)

new_daycare = DayCare(user=User.objects.create_user(email=email, username=username, password=password,
),
new_daycare = DayCare(user=User.objects.create_user(email=email, username=username, password=password),
name=name, description=description, price_per_day=price_per_day,
capacity=capacity, area=area, city=city, address=address)

Expand All @@ -56,6 +55,12 @@ def create(email, username, password, name, description, price_per_day, capacity

return new_daycare

def get_daycare_primary_image_url(self):
daycare_images = Image.get_images_by_daycare_id(daycare_id=self.id)
if daycare_images is not None and daycare_images.first() is not None:
return daycare_images.first().url
return "../../static/images/daycare-default-profile-image.jpeg"


class Image(models.Model):
url = models.CharField(max_length=1000)
Expand Down
50 changes: 48 additions & 2 deletions daycare/templates/daycare/daycare-homepage.html
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
{% extends "main/base_template.html" %}

{% load crispy_forms_tags %}
{% block stylesheets %}
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.0/css/all.css"
integrity="sha384-lZN37f5QGtY3VHgisS14W3ExzMWZxybE1SJSEsQp9S+oqd12jhcu+A56Ebc1zFSJ" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>

<style>
/* Make the image fully responsive */
.img {
Expand All @@ -23,17 +24,27 @@
<div class="col-md-7">
<hr>
<div class="mt-5 mb-5">
{% if visited_user == 'daycare' %}
<h5> <i class="fas fa-user"></i> Hello {{ daycare.name }}</h5>
<h6>This is where you can manage your daycare.
<br> You will be able:</h6>
<p class="text-muted"># Manage your booking schedule</p>
<p class="text-muted"># Set filters of approved dogs and services you provide</p>
<p class="text-muted"># Read / write reviews of dog owners and their dogs</p>
<p class="text-muted"># Chat with dog owners</p>
{% elif visited_user == 'dogowner' %}
<h5> <i class="fas fa-user"></i> Welcome to {{ daycare.name }}</h5>
<h6>This is where you can book an order for {{ daycare.name }} daycare
<br> You will be able:</h6>
<p class="text-muted"># Look at the details of the daycare</p>
<p class="text-muted"># Read / write reviews of the daycare</p>
<p class="text-muted"># Chat with the daycare owners</p>
{% endif %}
</div>
<hr>
<div class="mt-5">
<h5>Have a look at your reviews</h5>
<div style="height: 1500px;overflow: scroll;">
<table class="table table-hover table-bordered table-responsive">
<thead class="table-dark">
<tr>
Expand All @@ -56,6 +67,7 @@ <h5>Have a look at your reviews</h5>
{% endfor %}
</tbody>
</table>
</div>

</div>
</div>
Expand Down Expand Up @@ -115,11 +127,45 @@ <h5 class="card-title">{{daycare.address}}, {{daycare.city}}</h5>
<h6><i class="fas fa-dog"></i> Capacity: {{daycare.capacity}}
<br>
<br>
<i class="fas fa-coins"></i> Price: {{daycare.price_per_day}}
<i class="fas fa-coins"></i> Price Per Night: {{daycare.price_per_day}}
</h6>
<br>
<h6><strong>About</strong></h6>
<p class="card-text">{{daycare.description}}</p>
{% if visited_user == 'dogowner' %}

<form method='POST' action=''>{% csrf_token %}
<div class="col-4" id="searchBoxArea">
<h2>Book now</h2>
<div class="form-group">
{{ form.dog_name|as_crispy_field }}
</div>
<div class="form-group">
{{ form.email|as_crispy_field }}
</div>
<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.requests|as_crispy_field }}
</div>
<div class="form-group">
{{ form.agree_terms|as_crispy_field }}
</div>
<button type="submit" class="btn btn-primary">Complete Booking</button>
</div>
<br>
{% if order == 'No Capacity' %}
<h6>Failed: Your order could not be submit, there is no space available on the dates specified, please try again</h6>
{% elif order != 'null' %}
<h6>Your order has been successfully received and waiting for {{ daycare.name }} to approve</h6>
<p class="text-muted">You can see the details of the reservation <a href="{% url 'orders' %}">here</a></p>
{% endif %}
</form>
{% endif %}
</div>
</div>
</div>
Expand Down
11 changes: 11 additions & 0 deletions daycare/test_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
from .models import Image
from django.core.exceptions import ValidationError

DEFAULT_DAYCARE_PROFILE_URL = "../../static/images/daycare-default-profile-image.jpeg"


@pytest.mark.django_db()
class TestImageModel:
Expand All @@ -20,3 +22,12 @@ def test_image_creation_with_invalid_image_url(self, create_daycare_user):
with pytest.raises(ValidationError,
match="Invalid URL image - URL should end with \'.gif\', \'.png\', \'.jpg\' or \'.jpeg\'."):
Image.create(url="NOT_VALID_URL", daycare_id=DayCare.objects.get(id=create_daycare_user.id))

def test_daycare_has_customized_profile_image(self, create_image1, create_image2, create_daycare_user):
daycare_profile_image = create_daycare_user.get_daycare_primary_image_url()
assert daycare_profile_image != DEFAULT_DAYCARE_PROFILE_URL
assert daycare_profile_image is not None

def test_daycare_has_default_profile_image_when_no_customized_picture_was_found(self, create_daycare_user):
daycare_profile_image = create_daycare_user.get_daycare_primary_image_url()
assert daycare_profile_image == DEFAULT_DAYCARE_PROFILE_URL
42 changes: 38 additions & 4 deletions daycare/views.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,49 @@
from django.shortcuts import render
from django.contrib.auth.decorators import login_required
from .models import Image
from orders.models import Order
from review.models import Review
from daycare.models import DayCare
from daycare.forms import BookForm
from dogowner.models import DogOwner


@login_required(login_url='login')
def daycare_home(request):
def daycare_home(request, daycare_id):
daycare = DayCare.objects.get(pk=daycare_id)
form = BookForm(request.POST or None)

if DogOwner.objects.filter(user=request.user):
visited_user = 'dogowner'
else:
visited_user = 'daycare'

context = {
'daycare': request.user.daycare,
'reviews': Review.get_review_by_daycare_id(request.user.daycare.id),
'images': Image.get_images_by_daycare_id(request.user.daycare.id)
'form': form,
'daycare': daycare,
'visited_user': visited_user,
'reviews': Review.get_review_by_daycare_id(daycare.id),
'images': Image.get_images_by_daycare_id(daycare.id),
'order': 'null'
}

if request.method == 'POST':
if form.is_valid():
if Order.are_order_dates_available(daycare_id, form.cleaned_data['start_date'],
form.cleaned_data['end_date']):
new_order = Order.create(request.user.dogowner, DayCare.objects.get(pk=daycare_id),
form.cleaned_data['start_date'], form.cleaned_data['end_date'],
DayCare.objects.get(pk=daycare_id).price_per_day)
else:
new_order = 'No Capacity'

context = {
'form': form,
'daycare': daycare,
'visited_user': visited_user,
'reviews': Review.get_review_by_daycare_id(daycare.id),
'images': Image.get_images_by_daycare_id(daycare.id),
'order': new_order
}

return render(request, 'daycare/daycare-homepage.html', context)
57 changes: 57 additions & 0 deletions dogowner/templates/dogowner/dog_owner_homepage.html
Original file line number Diff line number Diff line change
@@ -0,0 +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">
<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>
</div>
{% endblock %}
3 changes: 3 additions & 0 deletions dogowner/views.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from django.contrib.auth.decorators import login_required
from django.shortcuts import render
from daycare.models import DayCare
from daycare.views import daycare_home
from daycare.forms import DayCareSearchForm
from orders.models import Order

Expand All @@ -25,8 +26,10 @@ def dog_owner_home(request):
day_care_queryset = filter_day_cares.intersection(available_day_cares)

context = {
'dog-owner': request.user.dogowner,
'day_care_queryset': day_care_queryset,
'form': form
}

return render(request, 'dogowner/dog_owner_homepage.html', context)

1 change: 1 addition & 0 deletions main/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ def test_root_entrypoint_redirection_logged_daycare_user(self, client, create_da
assert response['Location'] == '/homepage/'


@pytest.mark.django_db
class TestHomepageView:
def test_unlogged_user_access_to_homepage(self, client):
response = client.get("/homepage/")
Expand Down
7 changes: 7 additions & 0 deletions main/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from django.urls import path
from . import views

urlpatterns = [
path('', views.homepage, name='homepage'),
path('about/', views.about, name='about'),
]
11 changes: 9 additions & 2 deletions main/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
from django.contrib.auth import logout
from daycare.models import DayCare
from dogowner.models import DogOwner
from daycare.models import DayCare
from dogowner.views import dog_owner_home
from daycare.views import daycare_home
import orders.views

Expand All @@ -17,9 +19,9 @@ def index(request):
@login_required()
def homepage(request):
if DogOwner.objects.filter(user=request.user).exists():
return render(request, 'main/homepage.html')
return dog_owner_home(request)
elif DayCare.objects.filter(user=request.user).exists():
return daycare_home(request)
return daycare_home(request, request.user.daycare.id)


def about(request):
Expand All @@ -31,5 +33,10 @@ def logout_view(request):
return index(request)


@login_required
def visit_daycare_home(request, daycare_id):
return daycare_home(request, daycare_id)


def orders_view(request):
return orders.views.orders(request)
Loading

0 comments on commit ce0284f

Please sign in to comment.