diff --git a/1-pack_web_static.py b/1-pack_web_static.py
old mode 100644
new mode 100755
diff --git a/2-do_deploy_web_static.py b/2-do_deploy_web_static.py
old mode 100644
new mode 100755
diff --git a/3-deploy_web_static.py b/3-deploy_web_static.py
old mode 100644
new mode 100755
diff --git a/README.md b/README.md
index ae0c24c98f4..de1acfe512d 100644
--- a/README.md
+++ b/README.md
@@ -158,7 +158,8 @@ Alexa Orrico - [Github](https://github.com/alexaorrico) / [Twitter](https://twit
Jennifer Huang - [Github](https://github.com/jhuang10123) / [Twitter](https://twitter.com/earthtojhuang)
Jhoan Zamora - [Github](https://github.com/jzamora5) / [Twitter](https://twitter.com/JhoanZamora10)
David Ovalle - [Github](https://github.com/Nukemenonai) / [Twitter](https://twitter.com/disartDave)
-
+Elelta Alemu - [Github](https://github.com/Lillymuller)
+Yared Kebede - [Github](https://github.com/Yared91)
Second part of Airbnb: Joann Vuong
## License
Public Domain. No copy write protection.
diff --git a/api/v1/app.py b/api/v1/app.py
index 2a74f26a1e5..1f8764f413f 100755
--- a/api/v1/app.py
+++ b/api/v1/app.py
@@ -11,7 +11,7 @@
app = Flask(__name__)
app.config['JSONIFY_PRETTYPRINT_REGULAR'] = True
app.register_blueprint(app_views)
-cors = CORS(app, resources={r"/*": {"origins": "0.0.0.0"}})
+cors = CORS(app, resources={r"/api/v1/*": {"origins": "*"}})
@app.teardown_appcontext
diff --git a/code_review.txt b/code_review.txt
old mode 100644
new mode 100755
diff --git a/models/__pycache__/__init__.cpython-38.pyc b/models/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 00000000000..15a3b115c8e
Binary files /dev/null and b/models/__pycache__/__init__.cpython-38.pyc differ
diff --git a/models/__pycache__/amenity.cpython-38.pyc b/models/__pycache__/amenity.cpython-38.pyc
new file mode 100644
index 00000000000..6b57c6ff541
Binary files /dev/null and b/models/__pycache__/amenity.cpython-38.pyc differ
diff --git a/models/__pycache__/base_model.cpython-38.pyc b/models/__pycache__/base_model.cpython-38.pyc
new file mode 100644
index 00000000000..22eedd03826
Binary files /dev/null and b/models/__pycache__/base_model.cpython-38.pyc differ
diff --git a/models/__pycache__/city.cpython-38.pyc b/models/__pycache__/city.cpython-38.pyc
new file mode 100644
index 00000000000..a4d2bb6132d
Binary files /dev/null and b/models/__pycache__/city.cpython-38.pyc differ
diff --git a/models/__pycache__/place.cpython-38.pyc b/models/__pycache__/place.cpython-38.pyc
new file mode 100644
index 00000000000..6d9962c94df
Binary files /dev/null and b/models/__pycache__/place.cpython-38.pyc differ
diff --git a/models/__pycache__/review.cpython-38.pyc b/models/__pycache__/review.cpython-38.pyc
new file mode 100644
index 00000000000..75eb56b650f
Binary files /dev/null and b/models/__pycache__/review.cpython-38.pyc differ
diff --git a/models/__pycache__/state.cpython-38.pyc b/models/__pycache__/state.cpython-38.pyc
new file mode 100644
index 00000000000..b81ae1808cc
Binary files /dev/null and b/models/__pycache__/state.cpython-38.pyc differ
diff --git a/models/__pycache__/user.cpython-38.pyc b/models/__pycache__/user.cpython-38.pyc
new file mode 100644
index 00000000000..17c3c3bd8f7
Binary files /dev/null and b/models/__pycache__/user.cpython-38.pyc differ
diff --git a/models/engine/__pycache__/__init__.cpython-38.pyc b/models/engine/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 00000000000..bcd71f9f42e
Binary files /dev/null and b/models/engine/__pycache__/__init__.cpython-38.pyc differ
diff --git a/models/engine/__pycache__/db_storage.cpython-38.pyc b/models/engine/__pycache__/db_storage.cpython-38.pyc
new file mode 100644
index 00000000000..fbdd1856725
Binary files /dev/null and b/models/engine/__pycache__/db_storage.cpython-38.pyc differ
diff --git a/setup_mysql_dev.sql b/setup_mysql_dev.sql
old mode 100644
new mode 100755
diff --git a/setup_mysql_test.sql b/setup_mysql_test.sql
old mode 100644
new mode 100755
diff --git a/web_dynamic/0-hbnb.py b/web_dynamic/0-hbnb.py
new file mode 100755
index 00000000000..f1addd4abea
--- /dev/null
+++ b/web_dynamic/0-hbnb.py
@@ -0,0 +1,49 @@
+#!/usr/bin/python3
+""" Starts a Flash Web Application """
+from models import storage
+from models.state import State
+from models.city import City
+from models.amenity import Amenity
+from models.place import Place
+from os import environ
+from flask import Flask, render_template
+import uuid
+
+
+app = Flask(__name__)
+# app.jinja_env.trim_blocks = True
+# app.jinja_env.lstrip_blocks = True
+
+
+@app.teardown_appcontext
+def close_db(error):
+ """ Remove the current SQLAlchemy Session """
+ storage.close()
+
+
+@app.route('/0-hbnb/', strict_slashes=False)
+def hbnb():
+ """ HBNB is alive! """
+ states = storage.all(State).values()
+ states = sorted(states, key=lambda k: k.name)
+ st_ct = []
+
+ for state in states:
+ st_ct.append([state, sorted(state.cities, key=lambda k: k.name)])
+
+ amenities = storage.all(Amenity).values()
+ amenities = sorted(amenities, key=lambda k: k.name)
+
+ places = storage.all(Place).values()
+ places = sorted(places, key=lambda k: k.name)
+
+ return render_template('0-hbnb.html',
+ states=st_ct,
+ amenities=amenities,
+ places=places
+ cache_id=(str(uuid.uuid4())))
+
+
+if __name__ == "__main__":
+ """ Main Function """
+ app.run(host='0.0.0.0', port=5000)
diff --git a/web_dynamic/1-hbnb.py b/web_dynamic/1-hbnb.py
new file mode 100755
index 00000000000..9984c81d317
--- /dev/null
+++ b/web_dynamic/1-hbnb.py
@@ -0,0 +1,49 @@
+#!/usr/bin/python3
+""" Starts a Flash Web Application """
+from models import storage
+from models.state import State
+from models.city import City
+from models.amenity import Amenity
+from models.place import Place
+from os import environ
+from flask import Flask, render_template
+import uuid
+
+
+app = Flask(__name__)
+# app.jinja_env.trim_blocks = True
+# app.jinja_env.lstrip_blocks = True
+
+
+@app.teardown_appcontext
+def close_db(error):
+ """ Remove the current SQLAlchemy Session """
+ storage.close()
+
+
+@app.route('/1-hbnb/', strict_slashes=False)
+def hbnb():
+ """ HBNB is alive! """
+ states = storage.all(State).values()
+ states = sorted(states, key=lambda k: k.name)
+ st_ct = []
+
+ for state in states:
+ st_ct.append([state, sorted(state.cities, key=lambda k: k.name)])
+
+ amenities = storage.all(Amenity).values()
+ amenities = sorted(amenities, key=lambda k: k.name)
+
+ places = storage.all(Place).values()
+ places = sorted(places, key=lambda k: k.name)
+
+ return render_template('1-hbnb.html',
+ states=st_ct,
+ amenities=amenities,
+ places=places
+ cache_id=(str(uuid.uuid4())))
+
+
+if __name__ == "__main__":
+ """ Main Function """
+ app.run(host='0.0.0.0', port=5000)
diff --git a/web_dynamic/100-hbnb.py b/web_dynamic/100-hbnb.py
new file mode 100755
index 00000000000..9f7754664fb
--- /dev/null
+++ b/web_dynamic/100-hbnb.py
@@ -0,0 +1,49 @@
+#!/usr/bin/python3
+""" Starts a Flash Web Application """
+from models import storage
+from models.state import State
+from models.city import City
+from models.amenity import Amenity
+from models.place import Place
+from os import environ
+from flask import Flask, render_template
+import uuid
+
+
+app = Flask(__name__)
+# app.jinja_env.trim_blocks = True
+# app.jinja_env.lstrip_blocks = True
+
+
+@app.teardown_appcontext
+def close_db(error):
+ """ Remove the current SQLAlchemy Session """
+ storage.close()
+
+
+@app.route('/100-hbnb/', strict_slashes=False)
+def hbnb():
+ """ HBNB is alive! """
+ states = storage.all(State).values()
+ states = sorted(states, key=lambda k: k.name)
+ st_ct = []
+
+ for state in states:
+ st_ct.append([state, sorted(state.cities, key=lambda k: k.name)])
+
+ amenities = storage.all(Amenity).values()
+ amenities = sorted(amenities, key=lambda k: k.name)
+
+ places = storage.all(Place).values()
+ places = sorted(places, key=lambda k: k.name)
+
+ return render_template('100-hbnb.html',
+ states=st_ct,
+ amenities=amenities,
+ places=places
+ cache_id=(str(uuid.uuid4())))
+
+
+if __name__ == "__main__":
+ """ Main Function """
+ app.run(host='0.0.0.0', port=5000)
diff --git a/web_dynamic/101-hbnb.py b/web_dynamic/101-hbnb.py
new file mode 100755
index 00000000000..8e43d0b50bd
--- /dev/null
+++ b/web_dynamic/101-hbnb.py
@@ -0,0 +1,49 @@
+#!/usr/bin/python3
+""" Starts a Flash Web Application """
+from models import storage
+from models.state import State
+from models.city import City
+from models.amenity import Amenity
+from models.place import Place
+from os import environ
+from flask import Flask, render_template
+import uuid
+
+
+app = Flask(__name__)
+# app.jinja_env.trim_blocks = True
+# app.jinja_env.lstrip_blocks = True
+
+
+@app.teardown_appcontext
+def close_db(error):
+ """ Remove the current SQLAlchemy Session """
+ storage.close()
+
+
+@app.route('/101-hbnb/', strict_slashes=False)
+def hbnb():
+ """ HBNB is alive! """
+ states = storage.all(State).values()
+ states = sorted(states, key=lambda k: k.name)
+ st_ct = []
+
+ for state in states:
+ st_ct.append([state, sorted(state.cities, key=lambda k: k.name)])
+
+ amenities = storage.all(Amenity).values()
+ amenities = sorted(amenities, key=lambda k: k.name)
+
+ places = storage.all(Place).values()
+ places = sorted(places, key=lambda k: k.name)
+
+ return render_template('101-hbnb.html',
+ states=st_ct,
+ amenities=amenities,
+ places=places
+ cache_id=(str(uuid.uuid4())))
+
+
+if __name__ == "__main__":
+ """ Main Function """
+ app.run(host='0.0.0.0', port=5000)
diff --git a/web_dynamic/2-hbnb.py b/web_dynamic/2-hbnb.py
new file mode 100755
index 00000000000..28721ca7b40
--- /dev/null
+++ b/web_dynamic/2-hbnb.py
@@ -0,0 +1,49 @@
+#!/usr/bin/python3
+""" Starts a Flash Web Application """
+from models import storage
+from models.state import State
+from models.city import City
+from models.amenity import Amenity
+from models.place import Place
+from os import environ
+from flask import Flask, render_template
+import uuid
+
+
+app = Flask(__name__)
+# app.jinja_env.trim_blocks = True
+# app.jinja_env.lstrip_blocks = True
+
+
+@app.teardown_appcontext
+def close_db(error):
+ """ Remove the current SQLAlchemy Session """
+ storage.close()
+
+
+@app.route('/2-hbnb/', strict_slashes=False)
+def hbnb():
+ """ HBNB is alive! """
+ states = storage.all(State).values()
+ states = sorted(states, key=lambda k: k.name)
+ st_ct = []
+
+ for state in states:
+ st_ct.append([state, sorted(state.cities, key=lambda k: k.name)])
+
+ amenities = storage.all(Amenity).values()
+ amenities = sorted(amenities, key=lambda k: k.name)
+
+ places = storage.all(Place).values()
+ places = sorted(places, key=lambda k: k.name)
+
+ return render_template('2-hbnb.html',
+ states=st_ct,
+ amenities=amenities,
+ places=places
+ cache_id=(str(uuid.uuid4())))
+
+
+if __name__ == "__main__":
+ """ Main Function """
+ app.run(host='0.0.0.0', port=5000)
diff --git a/web_dynamic/3-hbnb.py b/web_dynamic/3-hbnb.py
new file mode 100755
index 00000000000..62fc13bd04d
--- /dev/null
+++ b/web_dynamic/3-hbnb.py
@@ -0,0 +1,49 @@
+#!/usr/bin/python3
+""" Starts a Flash Web Application """
+from models import storage
+from models.state import State
+from models.city import City
+from models.amenity import Amenity
+from models.place import Place
+from os import environ
+from flask import Flask, render_template
+import uuid
+
+
+app = Flask(__name__)
+# app.jinja_env.trim_blocks = True
+# app.jinja_env.lstrip_blocks = True
+
+
+@app.teardown_appcontext
+def close_db(error):
+ """ Remove the current SQLAlchemy Session """
+ storage.close()
+
+
+@app.route('/3-hbnb/', strict_slashes=False)
+def hbnb():
+ """ HBNB is alive! """
+ states = storage.all(State).values()
+ states = sorted(states, key=lambda k: k.name)
+ st_ct = []
+
+ for state in states:
+ st_ct.append([state, sorted(state.cities, key=lambda k: k.name)])
+
+ amenities = storage.all(Amenity).values()
+ amenities = sorted(amenities, key=lambda k: k.name)
+
+ places = storage.all(Place).values()
+ places = sorted(places, key=lambda k: k.name)
+
+ return render_template('3-hbnb.html',
+ states=st_ct,
+ amenities=amenities,
+ places=places
+ cache_id=(str(uuid.uuid4())))
+
+
+if __name__ == "__main__":
+ """ Main Function """
+ app.run(host='0.0.0.0', port=5000)
diff --git a/web_dynamic/4-hbnb.py b/web_dynamic/4-hbnb.py
new file mode 100755
index 00000000000..f41be1aa78c
--- /dev/null
+++ b/web_dynamic/4-hbnb.py
@@ -0,0 +1,49 @@
+#!/usr/bin/python3
+""" Starts a Flash Web Application """
+from models import storage
+from models.state import State
+from models.city import City
+from models.amenity import Amenity
+from models.place import Place
+from os import environ
+from flask import Flask, render_template
+import uuid
+
+
+app = Flask(__name__)
+# app.jinja_env.trim_blocks = True
+# app.jinja_env.lstrip_blocks = True
+
+
+@app.teardown_appcontext
+def close_db(error):
+ """ Remove the current SQLAlchemy Session """
+ storage.close()
+
+
+@app.route('/4-hbnb/', strict_slashes=False)
+def hbnb():
+ """ HBNB is alive! """
+ states = storage.all(State).values()
+ states = sorted(states, key=lambda k: k.name)
+ st_ct = []
+
+ for state in states:
+ st_ct.append([state, sorted(state.cities, key=lambda k: k.name)])
+
+ amenities = storage.all(Amenity).values()
+ amenities = sorted(amenities, key=lambda k: k.name)
+
+ places = storage.all(Place).values()
+ places = sorted(places, key=lambda k: k.name)
+
+ return render_template('4-hbnb.html',
+ states=st_ct,
+ amenities=amenities,
+ places=places
+ cache_id=(str(uuid.uuid4())))
+
+
+if __name__ == "__main__":
+ """ Main Function """
+ app.run(host='0.0.0.0', port=5000)
diff --git a/web_dynamic/__init__.py b/web_dynamic/__init__.py
new file mode 100755
index 00000000000..e69de29bb2d
diff --git a/web_dynamic/static/images/icon.png b/web_dynamic/static/images/icon.png
new file mode 100644
index 00000000000..93492bb8df2
Binary files /dev/null and b/web_dynamic/static/images/icon.png differ
diff --git a/web_dynamic/static/images/icon_bath.png b/web_dynamic/static/images/icon_bath.png
new file mode 100644
index 00000000000..7a9bfed9d8d
Binary files /dev/null and b/web_dynamic/static/images/icon_bath.png differ
diff --git a/web_dynamic/static/images/icon_bed.png b/web_dynamic/static/images/icon_bed.png
new file mode 100644
index 00000000000..2a632848770
Binary files /dev/null and b/web_dynamic/static/images/icon_bed.png differ
diff --git a/web_dynamic/static/images/icon_group.png b/web_dynamic/static/images/icon_group.png
new file mode 100644
index 00000000000..3e012ab4d5c
Binary files /dev/null and b/web_dynamic/static/images/icon_group.png differ
diff --git a/web_dynamic/static/images/logo.png b/web_dynamic/static/images/logo.png
new file mode 100644
index 00000000000..9b255c95555
Binary files /dev/null and b/web_dynamic/static/images/logo.png differ
diff --git a/web_dynamic/static/scripts/1-hbnb.js b/web_dynamic/static/scripts/1-hbnb.js
new file mode 100755
index 00000000000..8bd0afe09f3
--- /dev/null
+++ b/web_dynamic/static/scripts/1-hbnb.js
@@ -0,0 +1,14 @@
+$('document').ready(function () {
+ let amenities = {};
+ $('INPUT[type="checkbox"]').change(function () {
+ const dataId = $(this).attr('data-id')
+ const dataName = $(this).attr('data-name')
+ if ($(this).is(':checked')) {
+ amenities[dataId] = dataName;
+ } else {
+ delete amenities[$(this).attr('data-id')];
+ }
+ const amenityList = Object.values(amenities).join(', ')
+ $('div.amenities H4').text(aminityList);
+ });
+});
diff --git a/web_dynamic/static/scripts/100-hbnb.js b/web_dynamic/static/scripts/100-hbnb.js
new file mode 100755
index 00000000000..af8d8540954
--- /dev/null
+++ b/web_dynamic/static/scripts/100-hbnb.js
@@ -0,0 +1,203 @@
+$('document').ready(function () {
+ const url = 'http://0.0.0.0:5001/api/v1/status/';
+ $.get(url, function (response) {
+ if (response.status === 'OK') {
+ $('div#api_status').addClass('available');
+ } else {
+ $('div#api_status').removeClass('available');
+ }
+ });
+
+$.ajax({
+ url: api + ':5001/api/v1/places_search/',
+ type: 'POST',
+ data: '{}',
+ contentType: 'application/json',
+ dataType: 'json',
+ success: appendPlaces
+ });
+
+$.ajax({
+ type: 'POST',
+ url: 'http://0.0.0.0:5001/api/v1/places_search/',
+ data: JSON.stringify({}),
+ contentType: 'application/json',
+ success: function (data) => {
+ data.forEach(place => {
+ const html = `
+
+
+
${place.name}
+
${place.price_by_night}
+
+
+ ${place.description}
+
+ `;
+ $('section.places').append(html);
+ });
+ }
+});
+
+$('button').click(function () {
+ // Remove existing articles
+ $('article').remove();
+
+ // Prepare data for AJAX request
+ const amenitiesData = {
+ amenities: Object.keys(ls_amen)
+ };
+
+$.ajax({
+ type: 'POST',
+ url: 'http://0.0.0.0:5001/api/v1/places_search/',
+ data: JSON.stringify(amenitiesData),
+ contentType: 'application/json',
+ success: function (data) {
+ // Process and display search results
+ for (let i = 0; i < data.length; i++) {
+ const place = data[i];
+ const html = `
+
+
+
${place.name}
+
${place.price_by_night}
+
+
+ ${place.description}
+
+ `;
+ $('section.places').append(html);
+ }
+ }
+ });
+});
+
+
+$('document').ready(function () {
+ let amenities = {};
+ $('INPUT[type="checkbox"]').change(function () {
+ const dataId = $(this).attr('data-id')
+ const dataName = $(this).attr('data-name')
+ if ($(this).is(':checked')) {
+ amenities[dataId] = dataName;
+ } else {
+ delete amenities[$(this).attr('data-id')];
+ }
+ const amenityList = Object.values(amenities).join(', ')
+ $('div.amenities H4').text(aminityList);
+ });
+});
+
+$('document').ready(function () {
+ let states = {};
+ $('.locations ul.popover LI.s input[type=checkbox]').change(function () {
+ const dataId = $(this).attr('data-id')
+ const dataName = $(this).attr('data-name')
+ if ($(this).is(':checked')) {
+ states[dataId] = dataName;
+ } else {
+ delete states[$(this).attr('data-id')];
+ }
+ const stateList = Object.values(states).join(', ')
+ $('.locations h4').text(stateList);
+ });
+});
+
+$('document').ready(function () {
+ let cities = {};
+ $('.locations ul.popover LI.s input[type=checkbox]').change(function () {
+ const dataId = $(this).attr('data-id')
+ const dataName = $(this).attr('data-name')
+ if ($(this).is(':checked')) {
+ cities[dataId] = dataName;
+ } else {
+ delete cities[$(this).attr('data-id')];
+ }
+ const cityList = Object.values(cities).join(', ')
+ $('.locations h4').text(cityList);
+ });
+});
+
+$('button').click(function () {
+ // Remove existing articles
+ $('article').remove();
+
+ // Prepare data for AJAX request
+ const searchData = {
+ amenities: Object.keys(ls_amen),
+ cities: Object.keys(ls_cities),
+ states: Object.keys(ls_states)
+ };
+
+$.ajax({
+ type: 'POST',
+ url: 'http://127.0.0.1:5002/api/v1/places_search/',
+ data: JSON.stringify(searchData),
+ contentType: 'application/json',
+ success: function (data) {
+ // Process and display search results
+ for (let i = 0; i < data.length; i++) {
+ const place = data[i];
+
+ // Log data for debugging purposes
+ console.log(place);
+ console.log(ls_amen);
+ console.log('cities: ', ls_cities);
+ console.log('states: ', ls_states);
+
+ // Build and append HTML content
+ const html = `
+
+
+
${place.name}
+
${place.price_by_night}
+
+
+ ${place.description}
+
+ `;
+ $('section.places').append(html);
+ }
+ }
+ });
+});
diff --git a/web_dynamic/static/scripts/101-hbnb.js b/web_dynamic/static/scripts/101-hbnb.js
new file mode 100755
index 00000000000..476f8a74c48
--- /dev/null
+++ b/web_dynamic/static/scripts/101-hbnb.js
@@ -0,0 +1,225 @@
+$('document').ready(function () {
+ const url = 'http://0.0.0.0:5001/api/v1/status/';
+ $.get(url, function (response) {
+ if (response.status === 'OK') {
+ $('div#api_status').addClass('available');
+ } else {
+ $('div#api_status').removeClass('available');
+ }
+ });
+
+$.ajax({
+ url: api + ':5001/api/v1/places_search/',
+ type: 'POST',
+ data: '{}',
+ contentType: 'application/json',
+ dataType: 'json',
+ success: appendPlaces
+ });
+
+$.ajax({
+ type: 'POST',
+ url: 'http://0.0.0.0:5001/api/v1/places_search/',
+ data: JSON.stringify({}),
+ contentType: 'application/json',
+ success: function (data) => {
+ data.forEach(place => {
+ const html = `
+
+
+
${place.name}
+
${place.price_by_night}
+
+
+ ${place.description}
+
+ `;
+ $('section.places').append(html);
+ });
+ }
+});
+
+$('button').click(function () {
+ // Remove existing articles
+ $('article').remove();
+
+ // Prepare data for AJAX request
+ const amenitiesData = {
+ amenities: Object.keys(ls_amen)
+ };
+
+$.ajax({
+ type: 'POST',
+ url: 'http://0.0.0.0:5001/api/v1/places_search/',
+ data: JSON.stringify(amenitiesData),
+ contentType: 'application/json',
+ success: function (data) {
+ // Process and display search results
+ for (let i = 0; i < data.length; i++) {
+ const place = data[i];
+ const html = `
+
+
+
${place.name}
+
${place.price_by_night}
+
+
+ ${place.description}
+
+ `;
+ $('section.places').append(html);
+ }
+ }
+ });
+});
+
+
+$('document').ready(function () {
+ let amenities = {};
+ $('INPUT[type="checkbox"]').change(function () {
+ const dataId = $(this).attr('data-id')
+ const dataName = $(this).attr('data-name')
+ if ($(this).is(':checked')) {
+ amenities[dataId] = dataName;
+ } else {
+ delete amenities[$(this).attr('data-id')];
+ }
+ const amenityList = Object.values(amenities).join(', ')
+ $('div.amenities H4').text(aminityList);
+ });
+});
+
+$('document').ready(function () {
+ let states = {};
+ $('.locations ul.popover LI.s input[type=checkbox]').change(function () {
+ const dataId = $(this).attr('data-id')
+ const dataName = $(this).attr('data-name')
+ if ($(this).is(':checked')) {
+ states[dataId] = dataName;
+ } else {
+ delete states[$(this).attr('data-id')];
+ }
+ const stateList = Object.values(states).join(', ')
+ $('.locations h4').text(stateList);
+ });
+});
+
+$('document').ready(function () {
+ let cities = {};
+ $('.locations ul.popover LI.s input[type=checkbox]').change(function () {
+ const dataId = $(this).attr('data-id')
+ const dataName = $(this).attr('data-name')
+ if ($(this).is(':checked')) {
+ cities[dataId] = dataName;
+ } else {
+ delete cities[$(this).attr('data-id')];
+ }
+ const cityList = Object.values(cities).join(', ')
+ $('.locations h4').text(cityList);
+ });
+});
+
+$('button').click(function () {
+ // Remove existing articles
+ $('article').remove();
+
+ // Prepare data for AJAX request
+ const searchData = {
+ amenities: Object.keys(ls_amen),
+ cities: Object.keys(ls_cities),
+ states: Object.keys(ls_states)
+ };
+
+$.ajax({
+ type: 'POST',
+ url: 'http://127.0.0.1:5002/api/v1/places_search/',
+ data: JSON.stringify(searchData),
+ contentType: 'application/json',
+ success: function (data) {
+ // Process and display search results
+ for (let i = 0; i < data.length; i++) {
+ const place = data[i];
+
+ // Log data for debugging purposes
+ console.log(place);
+ console.log(ls_amen);
+ console.log('cities: ', ls_cities);
+ console.log('states: ', ls_states);
+
+ // Build and append HTML content
+ const html = `
+
+
+
${place.name}
+
${place.price_by_night}
+
+
+ ${place.description}
+
+ `;
+ $('section.places').append(html);
+ }
+ }
+ });
+});
+
+$('.reviewSpan').click(function (event) {
+ const placeId = $(this).attr('data-id');
+ const reviewsContainer = $('.reviews ul');
+
+ $.ajax({
+ url: `http://0.0.0.0:5001/api/v1/places/${placeId}/reviews`,
+ })
+ .done(function (data) {
+ reviewsContainer.empty(); // Clear existing reviews
+
+ if ($(this).text() === 'show') {
+ for (const review of data) {
+ reviewsContainer.append(`
${review.text}`);
+ }
+ $(this).text('hide'); // Update button text
+ } else {
+ reviewsContainer.empty();
+ $(this).text('show'); // Update button text back
+ }
+ });
+});
diff --git a/web_dynamic/static/scripts/2-hbnb.js b/web_dynamic/static/scripts/2-hbnb.js
new file mode 100755
index 00000000000..862c5e3cfa4
--- /dev/null
+++ b/web_dynamic/static/scripts/2-hbnb.js
@@ -0,0 +1,24 @@
+$('document').ready(function () {
+ const url = 'http://0.0.0.0:5001/api/v1/status/';
+ $.get(url, function (response) {
+ if (response.status === 'OK') {
+ $('div#api_status').addClass('available');
+ } else {
+ $('div#api_status').removeClass('available');
+ }
+ });
+
+$('document').ready(function () {
+ let amenities = {};
+ $('INPUT[type="checkbox"]').change(function () {
+ const dataId = $(this).attr('data-id')
+ const dataName = $(this).attr('data-name')
+ if ($(this).is(':checked')) {
+ amenities[dataId] = dataName;
+ } else {
+ delete amenities[$(this).attr('data-id')];
+ }
+ const amenityList = Object.values(amenities).join(', ')
+ $('div.amenities H4').text(aminityList);
+ });
+});
diff --git a/web_dynamic/static/scripts/3-hbnb.js b/web_dynamic/static/scripts/3-hbnb.js
new file mode 100755
index 00000000000..26c1c22cfee
--- /dev/null
+++ b/web_dynamic/static/scripts/3-hbnb.js
@@ -0,0 +1,59 @@
+$('document').ready(function () {
+ const url = 'http://0.0.0.0:5001/api/v1/status/';
+ $.get(url, function (response) {
+ if (response.status === 'OK') {
+ $('div#api_status').addClass('available');
+ } else {
+ $('div#api_status').removeClass('available');
+ }
+ });
+
+$.ajax({
+ type: 'POST',
+ url: 'http://0.0.0.0:5001/api/v1/places_search/',
+ data: JSON.stringify({}),
+ contentType: 'application/json',
+ success: function (data) => {
+ data.forEach(place => {
+ const html = `
+
+
+
${place.name}
+
${place.price_by_night}
+
+
+ ${place.description}
+
+ `;
+ $('section.places').append(html);
+ });
+ }
+});
+
+$('document').ready(function () {
+ let amenities = {};
+ $('INPUT[type="checkbox"]').change(function () {
+ const dataId = $(this).attr('data-id')
+ const dataName = $(this).attr('data-name')
+ if ($(this).is(':checked')) {
+ amenities[dataId] = dataName;
+ } else {
+ delete amenities[$(this).attr('data-id')];
+ }
+ const amenityList = Object.values(amenities).join(', ')
+ $('div.amenities H4').text(aminityList);
+ });
+});
diff --git a/web_dynamic/static/scripts/4-hbnb.js b/web_dynamic/static/scripts/4-hbnb.js
new file mode 100755
index 00000000000..50fae73dfcb
--- /dev/null
+++ b/web_dynamic/static/scripts/4-hbnb.js
@@ -0,0 +1,116 @@
+$('document').ready(function () {
+ const url = 'http://0.0.0.0:5001/api/v1/status/';
+ $.get(url, function (response) {
+ if (response.status === 'OK') {
+ $('div#api_status').addClass('available');
+ } else {
+ $('div#api_status').removeClass('available');
+ }
+ });
+
+$.ajax({
+ url: api + ':5001/api/v1/places_search/',
+ type: 'POST',
+ data: '{}',
+ contentType: 'application/json',
+ dataType: 'json',
+ success: appendPlaces
+ });
+
+$.ajax({
+ type: 'POST',
+ url: 'http://0.0.0.0:5001/api/v1/places_search/',
+ data: JSON.stringify({}),
+ contentType: 'application/json',
+ success: function (data) => {
+ data.forEach(place => {
+ const html = `
+
+
+
${place.name}
+
${place.price_by_night}
+
+
+ ${place.description}
+
+ `;
+ $('section.places').append(html);
+ });
+ }
+});
+
+$('button').click(function () {
+ // Remove existing articles
+ $('article').remove();
+
+ // Prepare data for AJAX request
+ const amenitiesData = {
+ amenities: Object.keys(ls_amen)
+ };
+
+$.ajax({
+ type: 'POST',
+ url: 'http://0.0.0.0:5001/api/v1/places_search/',
+ data: JSON.stringify(amenitiesData),
+ contentType: 'application/json',
+ success: function (data) {
+ // Process and display search results
+ for (let i = 0; i < data.length; i++) {
+ const place = data[i];
+ const html = `
+
+
+
${place.name}
+
${place.price_by_night}
+
+
+ ${place.description}
+
+ `;
+ $('section.places').append(html);
+ }
+ }
+ });
+});
+
+
+$('document').ready(function () {
+ let amenities = {};
+ $('INPUT[type="checkbox"]').change(function () {
+ const dataId = $(this).attr('data-id')
+ const dataName = $(this).attr('data-name')
+ if ($(this).is(':checked')) {
+ amenities[dataId] = dataName;
+ } else {
+ delete amenities[$(this).attr('data-id')];
+ }
+ const amenityList = Object.values(amenities).join(', ')
+ $('div.amenities H4').text(aminityList);
+ });
+});
diff --git a/web_dynamic/static/styles/3-footer.css b/web_dynamic/static/styles/3-footer.css
new file mode 100755
index 00000000000..2cd4ff05d90
--- /dev/null
+++ b/web_dynamic/static/styles/3-footer.css
@@ -0,0 +1,16 @@
+footer {
+ position: fixed;
+ background: white;
+ height: 60px;
+ width: 100%;
+ bottom: 0;
+ border-top: 1px solid #CCCCCC;
+}
+footer p {
+ position: absolute;
+ text-align: center;
+ top: 10%;
+ bottom: 0;
+ right: 0;
+ left: 0;
+}
diff --git a/web_dynamic/static/styles/3-header.css b/web_dynamic/static/styles/3-header.css
new file mode 100755
index 00000000000..dd19cfb2e62
--- /dev/null
+++ b/web_dynamic/static/styles/3-header.css
@@ -0,0 +1,23 @@
+header {
+ background: white;
+ height: 70px;
+ width: 100%;
+ border-bottom: 1px solid #CCCCCC;
+}
+header .logo {
+ background: url("../images/logo.png") no-repeat;
+ left: 20px;
+ height: 100%;
+}
+
+header div#api_status {
+ width: 40px;
+ height: 40px;
+ border-radius: 50%;
+ margin-right: 30px;
+ background-color: #cccccc;
+}
+
+header div#api_status.available {
+ background-color: #ff545f;
+}
diff --git a/web_dynamic/static/styles/4-common.css b/web_dynamic/static/styles/4-common.css
new file mode 100755
index 00000000000..46cfc19d1c1
--- /dev/null
+++ b/web_dynamic/static/styles/4-common.css
@@ -0,0 +1,11 @@
+body {
+ margin: 0;
+ padding: 0;
+ color: #484848;
+ font-size: 14px;
+ font-family: Circular,"Helvetica Neue",Helvetica,Arial,sans-serif;
+}
+body .container {
+ max-width: 1000px;
+ margin: 30px auto;
+}
diff --git a/web_dynamic/static/styles/6-filters.css b/web_dynamic/static/styles/6-filters.css
new file mode 100755
index 00000000000..d47107732aa
--- /dev/null
+++ b/web_dynamic/static/styles/6-filters.css
@@ -0,0 +1,103 @@
+.container .filters {
+ position: relative;
+ background: white;
+ height: 70px;
+ width: 100%;
+ border: 1px solid #DDDDDD;
+ border-radius: 4px;
+}
+button {
+ position: absolute;
+ font-size: 18px;
+ background: #FF5A5F;
+ color: #FFFFFF;
+ height: 48px;
+ width: 20%;
+ border-style: none;
+ border-radius: 4px;
+ top: 15%;
+ right: 30px;
+}
+button:hover {
+ opacity: 0.9;
+}
+.filters div {
+ display: inline-grid;
+}
+.filters h2 {
+ margin-left: 15%;
+ margin-top: 0;
+ margin-bottom: 0;
+ font-weight: 600;
+}
+.filters h3 {
+ margin-left: 15%;
+ margin-bottom: 0;
+ font-weight: 600;
+}
+.filters h4 {
+ margin-left: 15%;
+ margin-top: 0;
+ font-weight: 400;
+ font-size: 14px;
+}
+.locations {
+ height: 100%;
+ width: 25%;
+ border-right: 1px solid #DDDDDD;
+}
+.amenities {
+ height: 100%;
+ width: 25%;
+}
+
+.popover {
+ visibility: hidden;
+ width: 100%;
+ border: 1px solid #DDDDDD;
+ border-radius: 4px;
+ background: #FAFAFA;
+ padding-bottom: 15px;
+ height: 300px;
+ overflow-y: scroll;
+ scrollbar-width: none;
+ max-height: 300px;
+}
+
+.popover::-webkit-scrollbar{
+ width: 0px;
+}
+
+.amenities .popover {
+ padding: 10px 0;
+ margin-left: -5px;
+ margin-top: 0%;
+}
+
+.amenities .popover ul{
+ margin: 0px;
+}
+
+.locations .popover {
+ margin-top: 0%;
+}
+.popover ul {
+ list-style-type: none;
+ padding-bottom: 10px;
+ padding-left: 10px;
+}
+.popover ul li{
+ padding: 4px;
+ padding-left: 10px;
+}
+
+.popover ul h2{
+ margin-top: 1.5%;
+ margin-bottom: 5%;
+ margin-left: 0px;
+}
+
+.amenities:hover .popover,
+.locations:hover .popover {
+ visibility: visible;
+}
diff --git a/web_dynamic/static/styles/8-places.css b/web_dynamic/static/styles/8-places.css
new file mode 100755
index 00000000000..9dac66c0d7f
--- /dev/null
+++ b/web_dynamic/static/styles/8-places.css
@@ -0,0 +1,101 @@
+.places {
+ column-count: 2;
+ columns: 30em;
+ justify-content: center;
+ padding: 0 20px;
+ margin-top: 1%;
+ margin-bottom: 8%;
+}
+@media only screen and (max-width: 920px)
+{
+ .places {
+ display: flex;
+ flex-wrap: wrap;
+ }
+}
+
+.placesh1 h1 {
+ width: 100%;
+ margin-right: 400px;
+ text-align: left;
+ font-size: 35px;
+}
+
+.places article {
+ -webkit-column-break-inside: avoid;
+ page-break-inside: avoid;
+ display: inline-block;
+ width: 390px;
+ height: 100%;
+ padding: 20px;
+ margin: 20px;
+ border: 1px solid #FF5A5F;
+ border-radius: 4px;
+}
+.places h2 {
+ font-size: 30px;
+ text-align: center;
+ margin-top: 0;
+}
+.title_box {
+ display: flex;
+ justify-content: space-between;
+ margin-top: -2%;
+}
+
+.title_box h2 {
+ text-align: left;
+ margin: 25px 3% 40px 2%;
+ max-width: 75%;
+ word-wrap: break-word;
+}
+.price_by_night {
+ display: flex;
+ height: 60px;
+ min-width: 60px;
+ font-size: 30px;
+ justify-content: center;
+ align-items: center;
+ color: #FF5A5F;
+ border: 4px solid #FF5A5F;
+ border-radius: 50%;
+ align-items: center;
+ padding: 2.3%;
+}
+
+.information {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: 80px;
+ border-top: 1px solid #DDDDDD;
+ border-bottom: 1px solid #DDDDDD;
+ margin-bottom: 5%;
+}
+
+.information div {
+ display: flex;
+ justify-content: flex-end;
+ align-items: center;
+ flex-direction: column;
+ height: 65px;
+}
+
+.information .max_guest {
+ background: url("../images/icon_group.png") no-repeat top center;
+ width: 100px;
+}
+
+.information .number_rooms {
+ background: url("../images/icon_bed.png") no-repeat top center;
+ width: 100px;
+}
+
+.information .number_bathrooms {
+ background: url("../images/icon_bath.png") no-repeat top center;
+ width: 100px;
+}
+
+.user {
+ margin-bottom: 1.5%;
+}
diff --git a/web_dynamic/static/styles/w3c_validator.py b/web_dynamic/static/styles/w3c_validator.py
new file mode 100755
index 00000000000..ee9593fce40
--- /dev/null
+++ b/web_dynamic/static/styles/w3c_validator.py
@@ -0,0 +1,123 @@
+#!/usr/bin/python3
+"""
+W3C validator for Holberton School
+
+For HTML and CSS files.
+
+Based on 2 APIs:
+
+- https://validator.w3.org/nu/
+- http://jigsaw.w3.org/css-validator/validator
+
+
+Usage:
+
+Simple file:
+
+```
+./w3c_validator.py index.html
+```
+
+Multiple files:
+
+```
+./w3c_validator.py index.html header.html styles/common.css
+```
+
+All errors are printed in `STDERR`
+
+Return:
+Exit status is the # of errors, 0 on Success
+
+References
+
+https://developer.mozilla.org/en-US/
+
+"""
+import sys
+import requests
+
+
+def __print_stdout(msg):
+ """Print message in STDOUT
+ """
+ sys.stdout.write(msg)
+
+
+def __print_stderr(msg):
+ """Print message in STDERR
+ """
+ sys.stderr.write(msg)
+
+
+def __analyse_html(file_path):
+ """Start analyse of HTML file
+ """
+ h = {'Content-Type': "text/html; charset=utf-8"}
+ d = open(file_path, "rb").read()
+ u = "https://validator.w3.org/nu/?out=json"
+ r = requests.post(u, headers=h, data=d)
+ res = []
+ messages = r.json().get('messages', [])
+ for m in messages:
+ res.append("[{}:{}] {}".format(file_path, m['lastLine'], m['message']))
+ return res
+
+
+def __analyse_css(file_path):
+ """Start analyse of CSS file
+ """
+ d = {'output': "json"}
+ f = {'file': (file_path, open(file_path, 'rb'), 'text/css')}
+ u = "http://jigsaw.w3.org/css-validator/validator"
+ r = requests.post(u, data=d, files=f)
+ res = []
+ errors = r.json().get('cssvalidation', {}).get('errors', [])
+ for e in errors:
+ res.append("[{}:{}] {}".format(file_path, e['line'], e['message']))
+ return res
+
+
+def __analyse(file_path):
+ """Start analyse of a file and print the result
+ """
+ nb_errors = 0
+ try:
+ result = None
+ if file_path.endswith('.css'):
+ result = __analyse_css(file_path)
+ else:
+ result = __analyse_html(file_path)
+
+ if len(result) > 0:
+ for msg in result:
+ __print_stderr("{}\n".format(msg))
+ nb_errors += 1
+ else:
+ __print_stdout("{}: OK\n".format(file_path))
+
+ except Exception as e:
+ __print_stderr("[{}] {}\n".format(e.__class__.__name__, e))
+ return nb_errors
+
+
+def __files_loop():
+ """Loop that analyses for each file from input arguments
+ """
+ nb_errors = 0
+ for file_path in sys.argv[1:]:
+ nb_errors += __analyse(file_path)
+
+ return nb_errors
+
+
+if __name__ == "__main__":
+ """Main
+ """
+ if len(sys.argv) < 2:
+ __print_stderr("usage: w3c_validator.py file1 file2 ...\n")
+ exit(1)
+
+ """execute tests, then exit. Exit status = # of errors (0 on success)
+ """
+ sys.exit(__files_loop())
diff --git a/web_dynamic/templates/0-hbnb.html b/web_dynamic/templates/0-hbnb.html
new file mode 100755
index 00000000000..03d3577c8b2
--- /dev/null
+++ b/web_dynamic/templates/0-hbnb.html
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
+ HBnB
+
+
+
+
+
+
+
States
+
+
+
+ {% for state in states %}
+ -
+
{{ state[0].name }}:
+
+ {% for city in state[1] %}
+ - {{ city.name }}
+ {% endfor %}
+
+
+ {% endfor %}
+
+
+
+
+
Amenities
+
+
+
+ {% for amenity in amenities %}
+ - {{ amenity.name }}
+ {% endfor %}
+
+
+
+
+
+
Places
+
+
+ {% for place in places %}
+
+
+
{{ place.name }}
+
${{ place.price_by_night }}
+
+
+
+ Owner: {{ place.user.first_name }} {{ place.user.last_name }}
+
+
+ {{ place.description | safe }}
+
+
+ {% endfor %}
+
+
+
+
+
diff --git a/web_dynamic/templates/1-hbnb.html b/web_dynamic/templates/1-hbnb.html
new file mode 100755
index 00000000000..9fe1988624f
--- /dev/null
+++ b/web_dynamic/templates/1-hbnb.html
@@ -0,0 +1,80 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ HBnB
+
+
+
+
+
+
+
States
+
+
+
+ {% for state in states %}
+ -
+
{{ state[0].name }}:
+
+ {% for city in state[1] %}
+ - {{ city.name }}
+ {% endfor %}
+
+
+ {% endfor %}
+
+
+
+
+
+
+
Places
+
+
+ {% for place in places %}
+
+
+
{{ place.name }}
+
${{ place.price_by_night }}
+
+
+
+ Owner: {{ place.user.first_name }} {{ place.user.last_name }}
+
+
+ {{ place.description | safe }}
+
+
+ {% endfor %}
+
+
+
+
+
diff --git a/web_dynamic/templates/100-hbnb.html b/web_dynamic/templates/100-hbnb.html
new file mode 100755
index 00000000000..945ff99b9ca
--- /dev/null
+++ b/web_dynamic/templates/100-hbnb.html
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ HBnB
+
+
+
+
+
+
+
diff --git a/web_dynamic/templates/101-hbnb.html b/web_dynamic/templates/101-hbnb.html
new file mode 100755
index 00000000000..484af22f001
--- /dev/null
+++ b/web_dynamic/templates/101-hbnb.html
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ HBnB
+
+
+
+
+
+
+
diff --git a/web_dynamic/templates/2-hbnb.html b/web_dynamic/templates/2-hbnb.html
new file mode 100755
index 00000000000..898b7a88e19
--- /dev/null
+++ b/web_dynamic/templates/2-hbnb.html
@@ -0,0 +1,81 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ HBnB
+
+
+
+
+
+
+
States
+
+
+
+ {% for state in states %}
+ -
+
{{ state[0].name }}:
+
+ {% for city in state[1] %}
+ - {{ city.name }}
+ {% endfor %}
+
+
+ {% endfor %}
+
+
+
+
+
+
+
Places
+
+
+ {% for place in places %}
+
+
+
{{ place.name }}
+
${{ place.price_by_night }}
+
+
+
+ Owner: {{ place.user.first_name }} {{ place.user.last_name }}
+
+
+ {{ place.description | safe }}
+
+
+ {% endfor %}
+
+
+
+
+
diff --git a/web_dynamic/templates/3-hbnb.html b/web_dynamic/templates/3-hbnb.html
new file mode 100755
index 00000000000..b3d837e1e75
--- /dev/null
+++ b/web_dynamic/templates/3-hbnb.html
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ HBnB
+
+
+
+
+
+
+
States
+
+
+
+ {% for state in states %}
+ -
+
{{ state[0].name }}:
+
+ {% for city in state[1] %}
+ - {{ city.name }}
+ {% endfor %}
+
+
+ {% endfor %}
+
+
+
+
+
+
+
Places
+
+
+
+
+
diff --git a/web_dynamic/templates/4-hbnb.html b/web_dynamic/templates/4-hbnb.html
new file mode 100755
index 00000000000..e3af3785f40
--- /dev/null
+++ b/web_dynamic/templates/4-hbnb.html
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ HBnB
+
+
+
+
+
+
+
States
+
+
+
+ {% for state in states %}
+ -
+
{{ state[0].name }}:
+
+ {% for city in state[1] %}
+ - {{ city.name }}
+ {% endfor %}
+
+
+ {% endfor %}
+
+
+
+
+
+
+
Places
+
+
+
+
+