diff --git a/app/assets/images/banner_showroom_detail.png b/app/assets/images/banner_showroom_detail.png new file mode 100644 index 0000000..f0afc42 Binary files /dev/null and b/app/assets/images/banner_showroom_detail.png differ diff --git a/app/assets/images/house.png b/app/assets/images/house.png new file mode 100644 index 0000000..7cbf7a1 Binary files /dev/null and b/app/assets/images/house.png differ diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index a9d6086..1f854c1 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -6,6 +6,7 @@ //= require bootstrap //= require custom //= require toastr +//= require multislider /*global toastr*/ toastr.options = { diff --git a/app/assets/javascripts/custom.js b/app/assets/javascripts/custom.js index 4c715cf..ca6d433 100644 --- a/app/assets/javascripts/custom.js +++ b/app/assets/javascripts/custom.js @@ -1,30 +1,28 @@ $(document).ready(function() { - var $headline = $('.headline'), - $inner = $('.inner'), - $nav = $('nav'), - navHeight = 75; - - $(window).scroll(function() { - var scrollTop = $(this).scrollTop(), - headlineHeight = $headline.outerHeight() - navHeight, - navOffset = $nav.offset().top; - - $headline.css({ - 'opacity': (1 - scrollTop / headlineHeight) - }); + $(".preview-signup").change(function() { + readURL(this, '#img-prev-signup'); + }); - $inner.children().css({ - 'transform': 'translateY('+ scrollTop * 0.4 +'px)' - }); - if (navOffset > headlineHeight) { - $nav.addClass('scrolled'); - } else { - $nav.removeClass('scrolled'); + $('.carousel .item').each(function(){ + var next = $(this).next(); + if (!next.length) { + next = $(this).siblings(':first'); + } + next.children(':first-child').clone().appendTo($(this)); + + for (var i=0;i<2;i++) { + next=next.next(); + if (!next.length) { + next = $(this).siblings(':first'); + } + + next.children(':first-child').clone().appendTo($(this)); } }); - $(".preview-signup").change(function() { - readURL(this, '#img-prev-signup'); + $('#exampleSlider').multislider({ + interval: 5000, + slideAll: false }); $(".preview-edit-profile").change(function() { @@ -43,8 +41,7 @@ function readURL(f, previewId) { if (f.files && f.files[0]) { var reader = new FileReader(); reader.onload = function (e) { - $(previewId) - .attr('src', e.target.result); + $(previewId).attr('src', e.target.result); }; reader.readAsDataURL(f.files[0]); } diff --git a/app/assets/javascripts/manager/custom.js b/app/assets/javascripts/manager/custom.js index d71f217..8aa8e04 100644 --- a/app/assets/javascripts/manager/custom.js +++ b/app/assets/javascripts/manager/custom.js @@ -102,7 +102,68 @@ $(document).ready(function(){ }); $('[data-toggle="tooltip"]').tooltip(); + $('.preview-image').on("change", previewImages); + $('#new_address_modal, #editModal').on('hidden.bs.modal', function(){ + location.reload(); + }); + + $('#new-areas').submit(function(){ + $.ajax({ + url: $(this).attr('action'), + type: $(this).attr('method'), + data: $(this).serialize(), + success: function(data) { + if(data.type == 'success') { + $('.name_area').val(''); + toastr.success('', data.message); + $('.load-areas').load(location.href + ' .load-areas'); + } else { + toastr.error('', data.message); + } + } + }); + return false; + }); + $('#new-address').submit(function(){ + $.ajax({ + url: $(this).attr('action'), + type: $(this).attr('method'), + data: $(this).serialize(), + success: function(data) { + if(data.type == 'success') { + $('.name_address').val(''); + toastr.success('', data.message); + $('.load-address').load(location.href + ' .load-address'); + } else { + toastr.error('', data.message); + } + } + }); + return false; + }); + + $('#edit-address').submit(function(){ + $.ajax({ + url: $(this).attr('action'), + type: 'PATCH', + data: $(this).serialize(), + success: function(data) { + if(data.type == 'success') { + toastr.success('', data.message); + $('.load-address').load(location.href + ' .load-address'); + } else { + toastr.error('', data.message); + } + } + }); + return false; + }); + + $('.address-edit').click(function() { + $('.name_address').val($(this).data('address-name')) + $('#edit-address').attr('action', $(this).data('address-url')) + }) $('.preview-image').on("change", previewImages); $(".select2").select2({ diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css index d0dfcc5..d882dd7 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.css @@ -1,5 +1,5 @@ /* - *= require custom -.*= require toastr - *= require_self - */ + *= require custom + *= require toastr + *= require_self +*/ diff --git a/app/assets/stylesheets/custom.scss b/app/assets/stylesheets/custom.scss index bd01892..139317b 100644 --- a/app/assets/stylesheets/custom.scss +++ b/app/assets/stylesheets/custom.scss @@ -1,5 +1,17 @@ @import 'bootstrap'; +html { + margin: 0; + height: 100%; + width: 100%; +} + +body { + font-weight: 500; + font-size: 1rem; + color: #222; +} + /* ---------------------------- header ---------------------------- */ @@ -13,10 +25,6 @@ body { font-size: 1rem; } -header { - background: #111; -} - .headline { position: relative; height: 78px; @@ -44,10 +52,9 @@ header { .custom-nav { position: fixed; width: 100%; + height: 78px; z-index: 10; - &.scrolled { - background: rgba(#111, 0.9); - } + background-color: #333; ul { float: right; list-style: none; @@ -373,12 +380,12 @@ $offWhite: #e9eaea; } @media (min-width: 1200px){ - .container { + .container #custom { padding: 0 2.8rem; } } -.container { +.container #custom{ margin: auto; padding: 0 1.25rem; } @@ -639,3 +646,179 @@ h1, h2, h3, h4, h5, h6 { .preview-edit-profile { padding: 3px; } + +#exampleSlider { + position: relative; +} +@media (max-width: 767px) { + #exampleSlider { + border-color: transparent; + } +} +#exampleSlider .MS-content { + overflow: hidden; + white-space: nowrap; +} +@media (max-width: 767px) { + #exampleSlider .MS-content { + margin: 0; + } +} +#exampleSlider .MS-content .item { + display: inline-block; + height: 100%; + overflow: hidden; + position: relative; + vertical-align: top; + border-right: none; + width: 20%; +} +@media (max-width: 1200px) { + #exampleSlider .MS-content .item { + width: 25%; + } +} +@media (max-width: 992px) { + #exampleSlider .MS-content .item { + width: 33.3333%; + } +} +@media (max-width: 767px) { + #exampleSlider .MS-content .item { + width: 50%; + } +} +#exampleSlider .MS-content .item p { + font-size: 30px; + text-align: center; + line-height: 1; + vertical-align: middle; + margin: 0; + padding: 10px 0; +} +#exampleSlider .MS-controls button { + position: absolute; + border: none; + background: transparent; + font-size: 30px; + outline: 0; + top: 35px; +} +@media (max-width: 767px) { + #exampleSlider .MS-controls button { + display: none; + } +} +#exampleSlider .MS-controls button:hover { + cursor: pointer; +} +#exampleSlider .MS-controls .MS-left { + left: 10px; +} +@media (max-width: 992px) { + #exampleSlider .MS-controls .MS-left { + left: -2px; + } +} +#exampleSlider .MS-controls .MS-right { + right: 10px; +} +@media (max-width: 992px) { + #exampleSlider .MS-controls .MS-right { + right: -2px; + } +} + +.title-favorite-space { + margin-bottom: 18px!important; +} + +.item p img { + width: 100%; + padding: 0 10px; +} + +.title-content { + font-size: .75rem; + text-transform: uppercase; +} + +.article_content { + padding: 0 8px; +} + +#exampleSlider .MS-controls .MS-right { + top: 40%; +} + +#exampleSlider .MS-controls .MS-left { + top: 40%; +} + +.title-favorite { + margin: 0px; + padding-top: 20px; +} + +.icon-favorite { + display: inline; + width: 32px; + height: 32px; +} + +.card { + background: none; +} + +.text-title { + display: inline; + padding: 0 15px; +} + +.small { + font-size: 14px; +} + +.extra-bold span { + font-size: 15px; +} + +.address { + padding-top: 10px; +} + +.tales { + width: 100%; +} + +.carousel-showroomdetails { + height: 400px; +} + +.img-room-detail { + width: 100%; + height: 583px; +} + +.favorite-room { + width: 120%; +} + +a.name-room { + text-decoration: none; + font-size: 20px; + color: #333; +} + +a.name-room:hover { + color: red; + transition: all .5s; +} + +.image-banner { + width: 100%; +} + +.pagination { + padding: 10px 40%; +} diff --git a/app/assets/stylesheets/manager/custom.scss b/app/assets/stylesheets/manager/custom.scss index b357cd2..499c3a3 100644 --- a/app/assets/stylesheets/manager/custom.scss +++ b/app/assets/stylesheets/manager/custom.scss @@ -162,6 +162,16 @@ i.fa.fa-caret-down { margin-top: 27px; padding: 3px; } +#content { + -webkit-box-flex: 1; + flex: 1 0 auto; +} +.sticky-footer.bg-white { + border-top: 1px solid #858796; +} +.wrapper { + width: 100%; +} #content { -webkit-box-flex: 1; @@ -347,6 +357,76 @@ a.account:hover { text-decoration: none !important; } +.image-detail { + width: 400px; + border-radius: 4%; + height: 300px; + padding: 10px; +} + +td.action { + padding: 0; +} + +.action { + padding: 0 10px 0 10px; + margin: 0 10px 0 10px; +} + +.nested-image { + float: left; + margin: 10px 0px; +} + +.nested-image:before { + content: 'x'; + color: #000000c4; + font-weight: 600; + font-family: Arial, sans-serif; + font-size: 28px; +} + +.nested-add-image { + margin: 10px 0px; +} + +.show-image { + width: 100%; + float: left; +} + +.thumb-image { + float: left; + padding: 0 20px 25px 0; +} + +.links { + width: 100%; + float: left; +} + +.submit { + width: 100%; + float: left; +} + +.nested-image.btn.remove_fields.existing { + margin: -19px -50px 0; +} + +.preview-image { + width: 200px; + float: left; +} + +.edit-location { + margin-bottom: 10px; +} + +.new-areas { + float: right; +} + .image-detail{ width: 400px; border-radius: 4%; diff --git a/app/controllers/home_controller.rb b/app/controllers/home_controller.rb index a0ac1f8..9af9b64 100644 --- a/app/controllers/home_controller.rb +++ b/app/controllers/home_controller.rb @@ -1,5 +1,12 @@ # frozen_string_literal: true class HomeController < ApplicationController - def index; end + def index + @favorite_spaces = FavoriteSpace.newest + end + + def show + @favorite_space = FavoriteSpace.find(params[:id]) + @room_favorite_space = @favorite_space.rooms.page(params[:page]).per(16) + end end diff --git a/app/controllers/manager/rooms_controller.rb b/app/controllers/manager/rooms_controller.rb index c06aa0d..5560101 100644 --- a/app/controllers/manager/rooms_controller.rb +++ b/app/controllers/manager/rooms_controller.rb @@ -30,7 +30,7 @@ def create def update if @room.update room_params upload_images if params[:room_images] - redirect_to manager_room_path(@room), success: t(".update_success") + redirect_to manager_rooms_path(@room), success: t(".update_success") else render :edit, danger: t(".update_fail") end diff --git a/app/models/bill.rb b/app/models/bill.rb index 6197f18..bbd3507 100644 --- a/app/models/bill.rb +++ b/app/models/bill.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true class Bill < ApplicationRecord - belongs_to :voucher + belongs_to :voucher, dependent: :destroy belongs_to :price end diff --git a/app/models/favorite_space.rb b/app/models/favorite_space.rb index 4f8d743..ca1dc50 100644 --- a/app/models/favorite_space.rb +++ b/app/models/favorite_space.rb @@ -1,8 +1,10 @@ # frozen_string_literal: true class FavoriteSpace < ApplicationRecord - has_many :location_favorites, dependent: :destroy - has_many :locations, through: :location_favorites + has_many :locations, dependent: :destroy + has_many :rooms, dependent: :destroy + + scope :newest, -> { order created_at: :desc } validates :name, length: { in: 3..50 }, uniqueness: { case_sensitive: false } end diff --git a/app/models/image.rb b/app/models/image.rb new file mode 100644 index 0000000..ebe3522 --- /dev/null +++ b/app/models/image.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +class Image < ApplicationRecord + belongs_to :room +end diff --git a/app/models/location.rb b/app/models/location.rb index bbc7768..6691b1f 100644 --- a/app/models/location.rb +++ b/app/models/location.rb @@ -3,8 +3,9 @@ class Location < ApplicationRecord has_many :rooms, dependent: :destroy has_many :areas, dependent: :destroy - has_many :location_favorites, dependent: :destroy - has_many :favorite_spaces, through: :location_favorites + belongs_to :favorite_space, optional: true validates :name, presence: true, uniqueness: { case_sensitive: false } + + scope :newest, -> { order created_at: :desc } end diff --git a/app/models/price.rb b/app/models/price.rb index 91b9888..e1fe96e 100644 --- a/app/models/price.rb +++ b/app/models/price.rb @@ -2,7 +2,8 @@ class Price < ApplicationRecord has_many :bills, dependent: :destroy - has_many :vouchers, through: :bills, dependent: :destroy + has_many :vouchers, through: :bills + has_many :rooms, dependent: :destroy validates :cost, format: { with: /\A\d+(?:\.\d{0,2})?\z/ }, diff --git a/app/models/room.rb b/app/models/room.rb index 6cf6b39..f628360 100644 --- a/app/models/room.rb +++ b/app/models/room.rb @@ -3,6 +3,8 @@ class Room < ApplicationRecord belongs_to :location belongs_to :user + belongs_to :favorite_space + belongs_to :price has_many :room_images validates :name, presence: true, length: { maximum: 50 } @@ -14,5 +16,7 @@ class Room < ApplicationRecord enum type_room: { private_room: 0, entire: 1 } + scope :newest, -> { order create_at: :DESC } + accepts_nested_attributes_for :room_images, allow_destroy: true end diff --git a/app/views/home/index.html.slim b/app/views/home/index.html.slim index a54dfbb..feef920 100644 --- a/app/views/home/index.html.slim +++ b/app/views/home/index.html.slim @@ -1,54 +1,19 @@ .container.favorite-space - .title - h2.extra-bold.p--giant Explore In Your Way - .row - .col-md-3 style="width: 308px;" - div - div style="width: 100%; display: inline-block;" - .triptype - = link_to '', "https://www.luxstay.com/vi/s/?property_type=31&property_type=1", - class: "triptype__link" - .triptype__cover - = image_tag "location_6" - .triptype__title - p.bold.p--large.mb--0 Căn Hộ - .col-md-3 style="width: 308px;" - div - div style="width: 100%; display: inline-block;" - .triptype - = link_to '', "https://www.luxstay.com/vi/s/?property_type=31&property_type=1", class: "triptype__link" - .triptype__cover - = image_tag "location_7" - .triptype__title - p.bold.p--large.mb--0 Biệt Thự - .col-md-3 style="width: 308px;" - div - div style="width: 100%; display: inline-block;" - .triptype - = link_to '', "https://www.luxstay.com/vi/s/?property_type=31&property_type=1", class: "triptype__link" - .triptype__cover - = image_tag "location_8" - .triptype__title - p.bold.p--large.mb--0 Nhà Riêng - .col-md-3 style="width: 308px;" - div - div style="width: 100%; display: inline-block;" - .triptype - = link_to '', "https://www.luxstay.com/vi/s/?property_type=31&property_type=1", class: "triptype__link" - .triptype__cover - = image_tag "location_9" - .triptype__title - p.bold.p--large.mb--0 Studio - .title-location - h2.extra-bold.p--giant Top Destinations - .row style="width: 246px;" - div - = link_to "#", style: "width: 100%; display: inline-block;" - .product.is-relative - .product__cover - = image_tag "location_2", class: "product__image image-tag" - .product__content.is-absolute.white-deep - .product__title.extra-bold Hanoi - span.product__price.d-block - b 2108 - | Listings + .title-favorite-space + h2.extra-bold.p--giant = t(".extra-bold") + p = t(".description") + #exampleSlider + .MS-content + - @favorite_spaces.each do |favorite_space| + .item + p + = image_tag "location_6" + br + .article_content + .article_content.bold.title-content.text-center + = link_to favorite_space.name, favorite_space_path(favorite_space) + .MS-controls + button.MS-left + i.fa.fa-arrow-left + button.MS-right + i.fa.fa-arrow-right diff --git a/app/views/home/show.html.slim b/app/views/home/show.html.slim new file mode 100644 index 0000000..c4d5540 --- /dev/null +++ b/app/views/home/show.html.slim @@ -0,0 +1,25 @@ +.banner-room-details + = image_tag "banner_showroom_detail", class: "image-banner" +.container.title-favorite + .row + .col-12 + .icon + = image_tag "house", class: "icon-favorite" + p.text-secondary.font-weight-bold.text-title Now available #{ @favorite_space.rooms.count } rooms be allowed quick ticket booking + #multi-item-example.carousel.slide.carousel-multi-item.main-content data-ride="carousel" + .carousel-inner.favorite-room role="listbox" + .carousel-item.active + .row.main-content + - @room_favorite_space.each do |f| + .col-md-3 + .card.mb-2 + img.card-img-top alt=("Card image cap") src="https://mdbootstrap.com/img/Photos/Horizontal/Nature/4-col/img%20(34).jpg" / + .card-body.body-room + h4.card-title.text-center = f.name + .card-text + p.small = "#{ f.guest } Guest - #{ f.bed_room } Bed Room - #{ f.bath_room } Bath Room" + .card-text + p.small.bold = number_to_currency(f.price.cost) + .card-text + p.small = f.location.name + = paginate @room_favorite_space, theme: "twitter-bootstrap-4" diff --git a/app/views/manager/areas/_address.html.slim b/app/views/manager/areas/_address.html.slim index 2c5698b..784aa8f 100644 --- a/app/views/manager/areas/_address.html.slim +++ b/app/views/manager/areas/_address.html.slim @@ -1,7 +1,5 @@ tr td = address_counter.next - td - = address.name - td - = link_to t(".delete"), "#", class: "btn btn-danger" + td = address.name + td = link_to t(".delete"), "#", class: "btn btn-danger diff --git a/app/views/manager/areas/_edit_address.html.slim b/app/views/manager/areas/_edit_address.html.slim new file mode 100644 index 0000000..9aced32 --- /dev/null +++ b/app/views/manager/areas/_edit_address.html.slim @@ -0,0 +1,13 @@ +#editModal.modal.fade + .modal-dialog + .modal-content + .modal-header + h4.modal-title = t ".edit" + button.close data-dismiss="modal" type="button" × + .modal-body + = form_tag "", id: "edit-address" do |f| + .form-group + = text_field_tag :name, nil, class: "form-control name_address" + = submit_tag t(".save"), class: "btn btn-primary" + .modal-footer + button.btn.btn-danger data-dismiss="modal" type="button"= t ".close" diff --git a/app/views/manager/areas/edit.html.slim b/app/views/manager/areas/edit.html.slim index 99d33a2..e6c14a6 100644 --- a/app/views/manager/areas/edit.html.slim +++ b/app/views/manager/areas/edit.html.slim @@ -26,6 +26,6 @@ th= t ".name" th= t ".action" tbody - = render partial: "address", collection: @addresses - = paginate @addresses, theme: "twitter-bootstrap-4", pagination_class: "pagination-sm" + = render partial: "address", collection: @addresses += paginate @addresses, theme: "twitter-bootstrap-4", pagination_class: "pagination-sm" = render "new_address", address: @address diff --git a/app/views/manager/favorite_spaces/_favorite_space.html.slim b/app/views/manager/favorite_spaces/_favorite_space.html.slim new file mode 100644 index 0000000..4ea09cf --- /dev/null +++ b/app/views/manager/favorite_spaces/_favorite_space.html.slim @@ -0,0 +1,7 @@ +tr + td + = favorite_space_counter.next + td + = link_to favorite_space.name, edit_manager_favorite_space_path(favorite_space), class: "link-to-edit" + td + = link_to t(".delete"), manager_favorite_space_path(favorite_space), method: :delete, data: {confirm: t(".sure")}, class: "btn btn-danger" diff --git a/app/views/manager/favorite_spaces/edit.html.slim b/app/views/manager/favorite_spaces/edit.html.slim index 5d9d34d..fe64bb6 100644 --- a/app/views/manager/favorite_spaces/edit.html.slim +++ b/app/views/manager/favorite_spaces/edit.html.slim @@ -1,7 +1,13 @@ -= form_for [:manager, @favorite_space] do |f| - = render "shared/manager/error_messages", object: @favorite_space - = f.label t(".name") - = f.text_field :name, class: "form-control" - br - = f.submit t(".update"), class: "btn btn-primary" - = link_to t(".back"), manager_favorite_spaces_path, class: "btn btn-danger" +- provide :title, t(".title") +.row + .col-md-12 + .card + .card-header + h4.card-title= t ".add" + .card-body + = form_for [:manager, @favorite_space] do |f| + = render "shared/manager/error_messages", object: @favorite_space + = f.label t(".name") + = f.text_field :name, class: "form-control" + br + = f.submit t(".save"), class: "btn btn-primary" diff --git a/app/views/manager/favorite_spaces/index.html.slim b/app/views/manager/favorite_spaces/index.html.slim index 8842d45..ced11d2 100644 --- a/app/views/manager/favorite_spaces/index.html.slim +++ b/app/views/manager/favorite_spaces/index.html.slim @@ -1,11 +1,16 @@ -h1 Listing favorite space -table - tr - th Name - - @favorite_spaces.each do |favorite| - tr - td= favorite.name - td = link_to t(".edit"), edit_manager_favorite_space_path(favorite) - td = link_to t(".destroy"), manager_favorite_space_path(favorite), method: :delete, data: { confirm: "Are you sure?" } -br/ -= link_to t(".new"), new_manager_favorite_space_path +- provide :title, t(".title") +.row + .col-md-12 + .card + .card-header + h4.card-title + = link_to t(".new"), new_manager_favorite_space_path, class: "btn btn-primary btn-xs right" + .card-body + table.table.table-hover.table-striped + thead + th = t ".key" + th= t ".name" + th= t ".action" + tbody + = render @favorite_spaces + = paginate @favorite_spaces, theme: "twitter-bootstrap-4", pagination_class: "pagination-sm" diff --git a/app/views/manager/favorite_spaces/new.html.slim b/app/views/manager/favorite_spaces/new.html.slim index 17aeb33..07effad 100644 --- a/app/views/manager/favorite_spaces/new.html.slim +++ b/app/views/manager/favorite_spaces/new.html.slim @@ -1,7 +1,14 @@ -= form_for [:manager, @favorite_space] do |f| - = render "shared/manager/error_messages", object: @favorite_space - = f.label t(".name") - = f.text_field :name, class: "form-control" - br - = f.submit t(".create"), class: "btn btn-primary" - = link_to t(".back"), manager_favorite_spaces_path, class: "btn btn-danger" +- provide :title, t(".title") +.row + .col-md-12 + .card + .card-header + h4.card-title= t ".add" + .card-body + = form_for [:manager, @favorite_space] do |f| + = render "shared/manager/error_messages", object: @favorite_space + .form-group + = f.label t(".name") + = f.text_field :name, class: "form-control" + .form-group + = f.submit t(".create"), class: "btn btn-primary" diff --git a/app/views/manager/prices/_price.html.slim b/app/views/manager/prices/_price.html.slim index c9cade6..faa7dc7 100644 --- a/app/views/manager/prices/_price.html.slim +++ b/app/views/manager/prices/_price.html.slim @@ -1,20 +1,22 @@ h2.text-center - @prices.each do |price| - tr - td = number_to_currency(price.cost) - td = number_to_currency(price.cleaning_fee) - td - - price.bills.each do |price_bill| - = number_to_percentage(price_bill.voucher.sale, precision: 0) - br - td - - price.bills.each do |price_bill| - = price_bill.voucher.code - br - td - - price.bills.each do |price_bill| - = number_to_currency(bill_vouchers(price_bill)) - br - td - = link_to t(".edit"), edit_manager_price_path(price), class: "btn btn-primary" - = link_to t(".destroy"), manager_price_path(price), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-danger" + tr + td + = number_to_currency(price.cost) + td + = number_to_currency(price.cleaning_fee) + td + - price.bills.each do |price_bill| + = number_to_percentage(price_bill.voucher.sale, precision: 0) + br + td + - price.bills.each do |price_bill| + = price_bill.voucher.code + br + td + - price.bills.each do |price_bill| + = number_to_currency(bill_vouchers(price_bill)) + br + td + = link_to t(".edit"), edit_manager_price_path(price), class: "btn btn-primary" + = link_to t(".destroy"), manager_price_path(price), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-danger" diff --git a/app/views/manager/prices/_voucher_fields.html.slim b/app/views/manager/prices/_voucher_fields.html.slim index 97f5264..fde9f14 100644 --- a/app/views/manager/prices/_voucher_fields.html.slim +++ b/app/views/manager/prices/_voucher_fields.html.slim @@ -2,7 +2,6 @@ ul.voucher = link_to_remove_association f do span.fa.fa-times-circle aria-hidden="true" - = f.hidden_field :_destroy, as: :hidden = f.label :code = f.text_field :code, class: "form-control form-control-sm" br diff --git a/app/views/manager/prices/index.html.slim b/app/views/manager/prices/index.html.slim index aeabc71..263f6eb 100644 --- a/app/views/manager/prices/index.html.slim +++ b/app/views/manager/prices/index.html.slim @@ -3,6 +3,7 @@ table#admin-prices.table.table-striped.table-bordered.text-center style=("width: = link_to t(".new"), new_manager_price_path, class: "btn btn-primary new-price" thead tr + th = t(".cost") th = t(".cleaning") th = t(".sale") th = t(".code") diff --git a/app/views/manager/rooms/_form.html.slim b/app/views/manager/rooms/_form.html.slim index 46c8539..c7fdf6c 100644 --- a/app/views/manager/rooms/_form.html.slim +++ b/app/views/manager/rooms/_form.html.slim @@ -39,8 +39,7 @@ - if builder.object.image? = image_tag builder.object.image.thumb.url, class: "thumb-image" = link_to_remove_association "", builder, class: "nested-image btn" - = f.file_field :image, multiple: true, name: "room_images[image][]", - class: "form-control preview-image", presence: true + - else + = builder.file_field :image, multiple: true, name: "room_images[image][]", + class: "form-control preview-image", presence: true #preview - .submit - = f.submit yield(:button_title), class: "create-room btn btn-outline-primary" diff --git a/app/views/manager/rooms/edit.html.slim b/app/views/manager/rooms/edit.html.slim index 9c4c96a..f2b4d68 100644 --- a/app/views/manager/rooms/edit.html.slim +++ b/app/views/manager/rooms/edit.html.slim @@ -1,3 +1,9 @@ - provide(:button_title, t(".save")) h1 = t(".edit_room") -= render "form" += form_for [:manager, @room] do |f| + = render "form", f: f + .links + = link_to_add_association "add image", f, :room_images, partial: "image", + class: "nested-add-image btn btn-success" + .submit + = f.submit yield(:button_title), class: "create-room btn btn-outline-primary" diff --git a/app/views/manager/rooms/new.html.slim b/app/views/manager/rooms/new.html.slim index 84be124..f1a588f 100644 --- a/app/views/manager/rooms/new.html.slim +++ b/app/views/manager/rooms/new.html.slim @@ -1,3 +1,6 @@ - provide(:button_title,t(".create_room") ) h1 = t(".create_room") -= render "form" += form_for [:manager, @room] do |f| + = render "form", f: f + .submit + = f.submit yield(:button_title), class: "create-room btn btn-outline-primary" diff --git a/app/views/manager/rooms/show.html.slim b/app/views/manager/rooms/show.html.slim index fd0ba40..6c206be 100644 --- a/app/views/manager/rooms/show.html.slim +++ b/app/views/manager/rooms/show.html.slim @@ -1,17 +1,13 @@ .bs-example ul.nav.nav-tabs li.nav-item - = link_to "#home", class: "nav-link active", data:{toggle: "tab"} do - = t ".description" + a.nav-link.active data-toggle="tab" href="#home" = t ".description" li - = link_to "#menu1", class: "nav-link", data:{toggle: "tab"} do - = t ".room" + a.nav-link data-toggle="tab" href="#menu1" = t ".room" li - = link_to "#menu2", class: "nav-link", data:{toggle: "tab"} do - = t ".utility" + a.nav-link data-toggle="tab" href="#menu2" = t ".utility" li - = link_to "#menu3", class: "nav-link", data:{toggle: "tab"} do - = t ".image" + a.nav-link data-toggle="tab" href="#menu3" = t ".image" .tab-content #home.tab-pane.fade.show.active h3 = @room.name diff --git a/app/views/shared/_view_content.html.slim b/app/views/shared/_view_content.html.slim index 502c551..4b46ac9 100644 --- a/app/views/shared/_view_content.html.slim +++ b/app/views/shared/_view_content.html.slim @@ -1,5 +1,5 @@ .welcome - .container.container--sm + .container.container--sm#custom .row .col-md-7.col-xs-12.title-welcome h1.welcome__title diff --git a/app/views/shared/manager/_left_menu.html.slim b/app/views/shared/manager/_left_menu.html.slim index 595417b..252c3c4 100644 --- a/app/views/shared/manager/_left_menu.html.slim +++ b/app/views/shared/manager/_left_menu.html.slim @@ -10,10 +10,19 @@ ul#accordionSidebar.navbar-nav.bg-gradient-primary.sidebar.sidebar-dark.accordio i.fa.fa-fw.fa-tachometer-alt span = t ".dashboard" hr.sidebar-divider.my-0/ + - if current_admin.flag? + li.nav-item + = link_to manager_admins_path, class: "nav-link collapsed" do + i.fa.fa-user.fa-tachometer-alt + span = t ".manager_admin" li.nav-item = link_to manager_locations_path, class: "nav-link collapsed" do i.fa.fa-map-marker span = t ".location" + li.nav-item + = link_to manager_favorite_spaces_path, class: "nav-link collapsed" do + i.fa.fa-star + span = t ".favorite_space" li.nav-item.sidenav .dropdown-btn.nav-link.collapsed i.fa.fa-home diff --git a/config/locales/en.yml b/config/locales/en.yml index 66810fa..e1ff0fd 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1,7 +1,6 @@ en: please_choose_one: please choose one sure: "Are you sure?" - layouts: header: signup: "Sign Up" @@ -45,7 +44,6 @@ en: acreage: Acreage address: Address type_room: Type Rooms - shared: manager: left_menu: @@ -133,3 +131,4 @@ en: not_valid: "wrong format or size is too big" format: "wrong format" size: "is too big" + favorite_space: "Manager Favorite Spaces" diff --git a/config/locales/manager/en.yml b/config/locales/manager/en.yml index ea5080e..babf8b5 100644 --- a/config/locales/manager/en.yml +++ b/config/locales/manager/en.yml @@ -10,12 +10,23 @@ en: new: name: "Name" create: "Create" - back: "Back" + add: "New Favorite Spaces" + title: "New Favorite Spaces" edit: name: "Name" update: "Update" + title: "Edit Favorite Spaces" + add: "Edit Favorite Spaces" + save: "Save Changes" index: - new: "New" + new: "New Favorite Spaces" + key: "#" + name: "Name" + action: "Action" + title: "Favorite Spaces" + favorite_space: + delete: "Delete" + sure: "Are you sure?" locations: form: name: "Name" @@ -59,6 +70,43 @@ en: area: delete: "Delete" sure: "Are you sure?" + areas: + create: + success: "Create area successfully!" + error: "Create area has problem!" + edit: + title: "Edit Areas" + name: "Name" + submit: "Save Changes" + address: "Address" + new_address: "New Address" + key: "#" + name: "Name" + action: "Action" + update: + success: "Update area successfully!" + danger: "Update area has problem!" + destroy: + success: "Destroy area successfully!" + danger: "Destroy area has problem!" + new_address: + new: New Address + save: "Save Changes" + enter_name: "Enter address..." + address: + delete: "Delete" + sure: "Are you sure?" + edit_address: + edit: "Edit Address" + save: "Save Changes" + close: "Close" + addresses: + create: + success: "Create address successfully!" + danger: "Create address has problem!" + update: + success: "Update address successfully!" + danger: "Update address has problem!" prices: create: success: "Create successfully!!!" @@ -70,6 +118,7 @@ en: new: "New" listing_prices: "Listing prices" destroy: "Destroy" + cost: "Cost" sale: "Sale" code: "Code" total: "Total" @@ -91,6 +140,10 @@ en: create: "Create" form: cancel: "Cancel" + areas: + create: + success: "Create area successfully!" + danger: "Create area has problem!" index: create: "Create" all_admin: "All admins" @@ -100,12 +153,7 @@ en: address: "Address" access: "Access" action: "Action" - areas: - create: - success: "Create area successfully!" - danger: "Create area has problem!" edit: - title: "Edit Areas" title: "Edit Areas" name: "Name" save: "Save Changes" @@ -202,3 +250,8 @@ en: not_default_admin: "You can not delete default admin!" members: not_edit: "Not edit member %{id}" + home: + index: + extra-bold: "Nghĩ lễ đến đâu giảm sâu đến đó." + description: "Lễ này bạn đi đâu, Group đều giảm sâu đến đó,mức giảm lên tới 25%. Chớp lấy cơ hội, đặt ngay để có chuyến đi tiết kiệm nhất." + diff --git a/config/routes.rb b/config/routes.rb index 4f62886..a3f1845 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -2,9 +2,11 @@ Rails.application.routes.draw do devise_for :admins, controllers: { sessions: "manager/sessions", passwords: "manager/passwords" } - devise_for :members, controllers: { registrations: "registrations", - sessions: "sessions", passwords: "passwords", confirmations: "confirmations" } + devise_for :members, controllers: { registrations: "registrations", sessions: "sessions", passwords: "passwords" } + root "home#index" + get "favorite_spaces/:id", to: "home#show" + resources :favorite_spaces, only: [:show] namespace :manager do root "members#index" resources :favorite_spaces @@ -12,12 +14,16 @@ resources :admins resources :members resources :prices + resources :locations do - resources :areas, only: %i[new create] + resources :areas, except: %i[destroy edit update] end - resources :areas, except: %i[new create] do - resources :addresses, only: %i[new create] + + resources :areas, only: %i[edit update destroy] do + resources :addresses, except: %i[destroy edit update] end + + resources :addresses, only: %i[destroy edit update] end root "home#index" end diff --git a/config/settings.yml b/config/settings.yml index 3b16349..9673476 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -3,3 +3,4 @@ max_size: 5_242_880 file_path: image/ time_out: 30 address_per: 10 +favorite_per: 10 diff --git a/db/migrate/20190816042328_create_rooms.rb b/db/migrate/20190816042328_create_rooms.rb index b45f057..ae418d3 100644 --- a/db/migrate/20190816042328_create_rooms.rb +++ b/db/migrate/20190816042328_create_rooms.rb @@ -3,6 +3,8 @@ def change create_table :rooms do |t| t.references :user, foreign_key: true t.references :location, foreign_key: true + t.references :price + t.references :favorite_space t.string :name t.string :address t.decimal :rate_point diff --git a/db/migrate/20190823021741_create_images.rb b/db/migrate/20190823021741_create_images.rb new file mode 100644 index 0000000..cd3514f --- /dev/null +++ b/db/migrate/20190823021741_create_images.rb @@ -0,0 +1,10 @@ +class CreateImages < ActiveRecord::Migration[5.2] + def change + create_table :images do |t| + t.references :room, foreign_key: true + t.string :name + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index e161c2e..d301980 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -64,6 +64,14 @@ t.datetime "updated_at", null: false end + create_table "images", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t| + t.bigint "room_id" + t.string "name" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["room_id"], name: "index_images_on_room_id" + end + create_table "location_favorites", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t| t.bigint "location_id" t.bigint "favorite_space_id" @@ -97,6 +105,8 @@ create_table "rooms", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t| t.bigint "user_id" t.bigint "location_id" + t.bigint "price_id" + t.bigint "favorite_space_id" t.string "name" t.string "address" t.decimal "rate_point", precision: 10 @@ -108,7 +118,9 @@ t.integer "bath_room" t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.index ["favorite_space_id"], name: "index_rooms_on_favorite_space_id" t.index ["location_id"], name: "index_rooms_on_location_id" + t.index ["price_id"], name: "index_rooms_on_price_id" t.index ["user_id"], name: "index_rooms_on_user_id" end @@ -145,6 +157,7 @@ add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id" add_foreign_key "addresses", "areas" add_foreign_key "areas", "locations" + add_foreign_key "images", "rooms" add_foreign_key "location_favorites", "favorite_spaces" add_foreign_key "location_favorites", "locations" add_foreign_key "rooms", "locations" diff --git a/db/seeds.rb b/db/seeds.rb index 9560ee6..d4f8052 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -39,3 +39,30 @@ ["CĂN HỘ CHUNG CƯ","NHÀ RIÊNG", "CĂN HỘ STUDIO", "KHÁC", "BIỆT THỰ"].each do |favorite_space| FavoriteSpace.create! name: favorite_space end + +["LOCATION TEST 01", "LOCATION TEST 02", "LOCATION TEST 03", "LOCATION TEST 04"].each do |location| + Location.create! name: location +end + +20.times do |price| + price = rand(1..999999) + Price.create!(cost: price, + cleaning_fee: price) +end + +20.times do |f| + 5.times do |n| + name = Faker::Name.name + address = Faker::Address.country + Room.create!(name: name, + address: address, + guest: 1, + bed_room: rand(1..5), + bath_room: rand(1..5), + type_room: rand(0..1), + location_id: rand(1..4), + user_id: 1, + favorite_space_id: n+1, + price_id: rand(1..20)) + end +end diff --git a/storage/.keep b/storage/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/vendor/assets/javascripts/multislider.js b/vendor/assets/javascripts/multislider.js new file mode 100644 index 0000000..68022e4 --- /dev/null +++ b/vendor/assets/javascripts/multislider.js @@ -0,0 +1,366 @@ +/* +* MultiSlider | MIT License +* +* Copyright (c) 2017 Trevor Blackman +* http://www.multislider.info +* +*/ + +(function($){ + + // ==== BEGINS PLUGGIN ==== + $.fn.multislider = function(data, callback){ + + // ==== CACHE DOM ==== + var $multislider = $(this); + var $msContent = $multislider.find('.MS-content'); + var $msRight = $multislider.find('button.MS-right'); + var $msLeft = $multislider.find('button.MS-left'); + var $imgFirst = $msContent.find('.item:first'); + + // === DETERMINE ACTION ==== + // string = method | object or nothing is to initialize + if(typeof data === 'string'){ + getStringArgs(data); + return $multislider; + } else if (typeof data === 'object' || typeof data ==='undefined'){ + init(); + } + + // ==== PLUGGIN VARIABLES ==== + var $imgLast, + totalWidth, + numberVisibleSlides, + animateDistance, + animateSlideRight, + animateSlideLeft, + defaults, + settings, + animateDuration, + autoSlideInterval; + + // = INITIALIZE = + function init(){ + minifyContent(); // minify html + createSettings(); // merge defaults and user provided options + saveData(); // add data object to DOM el with reference to animation functions, allows for methods to reference at any time + selectAnimations(); // choose default animation + } + + + // ==== EVENT HANDLERS ==== + $msRight.on('click', animateSlideLeft); + $msLeft.on('click', animateSlideRight); + $multislider.on('click','.MS-right, .MS-left', resetInterval); + $(window).on('resize', findItemWidth); + + + // ==== FUNCTIONS (for days...) ==== + // ================================= + + function pauseAbove(){ + if (window.innerWidth > settings.pauseAbove){ $multislider.addClass('ms-PAUSE'); } + $(window).on('resize',function(){ + if (window.innerWidth > settings.pauseAbove){ + $multislider.addClass('ms-PAUSE'); + } else { + $multislider.removeClass('ms-PAUSE'); + } + }); + } + + function pauseBelow(){ + if (window.innerWidth < settings.pauseBelow){ $multislider.addClass('ms-PAUSE'); } + $(window).on('resize',function(){ + if (window.innerWidth < settings.pauseBelow){ + $multislider.addClass('ms-PAUSE'); + } else { + $multislider.removeClass('ms-PAUSE'); + } + }); + } + + // used if method is called after initialization + function getStringArgs(str){ + if (typeof $multislider.data(str) !== 'undefined'){ + $multislider.data(str)(); + } else { + console.error("Multislider currently only accepts the following methods: next, prev, pause, play"); + } + } + + // saves data object to DOM element + function saveData(){ + $multislider.data({ + "pause":function(){ $multislider.addClass('ms-PAUSE'); }, + "unPause":function(){ $multislider.removeClass('ms-PAUSE'); }, + "continuous":function(){ $multislider.removeClass('ms-PAUSE'); continuousLeft(); }, + "next":function(){ overRidePause(singleLeft); }, + "nextAll":function(){ overRidePause(allLeft); }, + "prev":function(){ overRidePause(singleRight); }, + "prevAll":function(){ overRidePause(allRight); }, + "settings":settings + }); + } + + // used when calling 'next', 'prev' methods + function overRidePause(animation){ + if ($multislider.hasClass('ms-PAUSE')){ + $multislider.removeClass('ms-PAUSE'); + animation(); + $multislider.addClass('ms-PAUSE'); + } else { + animation(); + } + resetInterval(); + } + + // CRITICAL for items to be perfectly side-by-side without floating them + function minifyContent(){ + $msContent.contents().filter(function(){ + return (this.nodeType == 3 && !/\S/.test(this.nodeValue)); + }).remove(); + } + + // updated options with defaults, measure slide widths for animation calculations, carry out setting implementations + function createSettings() { + defaults = settings || { + continuous: false, // endless scrolling with no pauses + slideAll: false, // slide all visible slides, or just one at a time + // autoSlide: true, // DEPRECATED + interval: 2000, // time bewteen slide animation, 0 or 'false' prevents auto-sliding + duration: 500, // duration of slide animation + hoverPause: true, // pause slideshow on hover + pauseAbove: null, // pause above specified screen width + pauseBelow: null // pause below specified screen width + }; + + settings = $.extend({},defaults,data); + + findItemWidth(); + animateDuration = settings.duration; + + if (settings.hoverPause){pauseHover();} + // autoSlide is being depricated | Feb 2 2017 + if (settings.continuous !== true && settings.interval !== 0 && settings.interval !== false && settings.autoSlide !== false){autoSlide();} + if (settings.pauseAbove !== null && typeof settings.pauseAbove === 'number'){ pauseAbove(); } + if (settings.pauseBelow !== null && typeof settings.pauseBelow === 'number'){ pauseBelow(); } + } + + // determine between single and multi-slide animations + function selectAnimations () { + if (settings.continuous){ + settings.autoSlide = false; + continuousLeft(); + } else if (settings.slideAll){ + animateSlideRight = $multislider.data('prevAll'); + animateSlideLeft = $multislider.data('nextAll'); + } else { + animateSlideRight = $multislider.data('prev'); + animateSlideLeft = $multislider.data('next'); + } + } + + // measure slide width, for animation calculations + function findItemWidth(){ + reTargetSlides(); + animateDistance = $imgFirst.width(); + var left = parseInt($msContent.find('.item:first').css('padding-left')); + var right = parseInt($msContent.find('.item:first').css('padding-right')); + if (left !== 0){animateDistance += left;} + if (right !== 0){animateDistance += right;} + } + + // recursive auto-slide loop + function autoSlide() { + autoSlideInterval = setInterval(function(){ + if (!$multislider.hasClass('ms-PAUSE')){ + animateSlideLeft(); + } + }, settings.interval); + } + + function resetInterval() { + if (settings.interval !== 0 && settings.interval !== false && settings.continuous !== true){ + clearInterval(autoSlideInterval); + autoSlide(); + } + } + + // target first and last visible slides before each new animation + function reTargetSlides(){ + $imgFirst = $msContent.find('.item:first'); + $imgLast = $msContent.find('.item:last'); + } + + // prevent animation firing if multislider is currently animating + // all animations pass through this function, which emits events, and adds/removes animating class + function isItAnimating(callback){ + if(!$multislider.hasClass('ms-animating') && + !$multislider.hasClass('ms-HOVER') && + !$multislider.hasClass('ms-PAUSE')){ + $multislider.trigger('ms.before.animate'); // event! + $multislider.addClass('ms-animating'); + callback(); //callback is animation + } + } + + // update multislider at the end of each animation + function doneAnimating() { + if($multislider.hasClass('ms-animating')){ + $multislider.removeClass('ms-animating'); + $multislider.trigger('ms.after.animate'); // event! + } + } + + // logic for pausing and restarting the multislider on hover + function pauseHover() { + // continuous scroll pause slightly different + if(settings.continuous){ + $msContent.on('mouseover',function(){ + doneAnimating(); + $msContent.children('.item:first').stop(); + }); + $msContent.on('mouseout',function(){ + continuousLeft(); + }); + } else { + // regular animation pausing + $msContent.on('mouseover',function(){ + $multislider.addClass('ms-HOVER'); + }); + $msContent.on('mouseout',function(){ + $multislider.removeClass('ms-HOVER'); + }); + } + } + + // calculate remaining animation, if stopped mid-animation and resuming + function midAnimateResume(){ + animateDuration = settings.duration; + var currentMargin = parseFloat($msContent.find('.item:first').css("margin-left")); + var percentageRemaining = 1-(currentMargin/-(animateDistance-1)); + animateDuration = percentageRemaining*animateDuration; + } + + // determine how many slides need to be moved over, if slideAll is true + function calcNumSlidesToMove(){ + totalWidth = $msContent.width(); // total width of .MS-content containing all visible slides + numberVisibleSlides = Math.floor(totalWidth/animateDistance); // number of (visible) slides needed to be moved in each animation + } + + + // ==== ANIMATION FUNCTIONS ==== + // ============================= + function continuousLeft () { + isItAnimating(function(){ + reTargetSlides(); + midAnimateResume(); + $imgFirst.animate( + {marginLeft: -(animateDistance+1)}, + { + duration: animateDuration, + easing: "linear", + complete: function(){ + $imgFirst.insertAfter($imgLast).removeAttr("style"); + doneAnimating(); + continuousLeft (); + } + } + ); + }); + } + + function allLeft(){ + isItAnimating(function(){ + reTargetSlides(); + calcNumSlidesToMove(); + + var $clonedItemSet = $msContent.children('.item').clone(); + var filteredClones = $clonedItemSet.splice(0, numberVisibleSlides); + + $msContent.append(filteredClones); + + $imgFirst.animate( + {marginLeft: -totalWidth}, { + duration: animateDuration, + easing: "swing", + complete: function(){ + $($msContent.children('.item').splice(0,numberVisibleSlides)).remove(); + doneAnimating(); + } + } + ); + }); + } + + function allRight() { + isItAnimating(function(){ + reTargetSlides(); + calcNumSlidesToMove(); + + var numberTotalSlides = $msContent.children('.item').length; + var $clonedItemSet = $msContent.children('.item').clone(); + var filteredClones = $clonedItemSet.splice(numberTotalSlides-numberVisibleSlides,numberTotalSlides); + + $($(filteredClones)[0]).css('margin-left',-totalWidth); // give clone array negative margin before preppending + $msContent.prepend(filteredClones); + + reTargetSlides(); + + $imgFirst.animate( + { + marginLeft: 0 + }, { + duration: animateDuration, + easing: "swing", + complete: function(){ + numberTotalSlides = $msContent.find('.item').length; + $($msContent.find('.item').splice(numberTotalSlides-numberVisibleSlides,numberTotalSlides)).remove(); + $imgFirst.removeAttr('style'); + doneAnimating(); + } + } + ); + }); + } + + function singleLeft(){ + isItAnimating(function(){ + reTargetSlides(); + $imgFirst.animate( + { + marginLeft: -animateDistance + }, { + duration: animateDuration, + easing: "swing", + complete: function(){ + $imgFirst.detach().removeAttr('style').appendTo($msContent); + doneAnimating(); + } + } + ); + }); + } + + function singleRight(){ + isItAnimating(function(){ + reTargetSlides(); + $imgLast.css('margin-left',-animateDistance).prependTo($msContent); + $imgLast.animate( + { + marginLeft: 0 + }, { + duration: animateDuration, + easing: "swing", + complete: function(){ + $imgLast.removeAttr("style"); + doneAnimating(); + } + } + ); + }); + } + return $multislider; + } +})(jQuery);