Repository: awesome-academy/naitei_ruby_10_02_2025_hotel_management
Pull request #18: view detail and update room type
Author: login: tungnx-3642
Created: 2025-04-03T03:50:36Z | Merged: 2025-04-03T06:14:27Z

## Related Tickets
- [Ticket chỉnh sửa thông tin loại phòng](https://edu-redmine.sun-asterisk.vn/issues/86130)
- [Ticket Quản lý trang thiết bị trong loại phòng](https://edu-redmine.sun-asterisk.vn/issues/86353)
- [Ticket xem chi tiết thông tin loại phòng ](https://edu-redmine.sun-asterisk.vn/issues/86359?issue_count=32&issue_position=1&next_issue_id=86353)

## WHAT (optional)
- Change number items `completed/total` in admin page.

## HOW
- I edit js file, inject not_vary_normal items in calculate function.

## WHY (optional)
- Because in previous version - number just depends on `normal` items. But in new version, we have `state` and `confirm_state` depends on both `normal` + `not_normal` items.

## Evidence (Screenshot or Video)
![image](https://github.com/user-attachments/assets/27d720a2-fea0-48f9-8819-a3ea245c145e)
![Recording-2025-04-03-104511](https://github.com/user-attachments/assets/c562ea7a-636c-4272-9ef7-6faa4cc44aa4)



Diff:
diff --git a/app/assets/stylesheets/admin.scss b/app/assets/stylesheets/admin.scss
index 961f07f..3dd07b6 100644
--- a/app/assets/stylesheets/admin.scss
+++ b/app/assets/stylesheets/admin.scss
@@ -142,3 +142,27 @@
   display: flex;
   gap: 5px;
 }
+
+.room-type-detail-page {
+  padding: 20px;
+}
+
+.room_type_edit_page {
+  padding: 20px;
+}
+
+.delete-link {
+  color: red;
+}
+
+.room-type-images {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 10px;
+}
+
+.room-type-image img {
+  height: 50px;
+  width: auto;
+  object-fit: contain;
+}
diff --git a/app/assets/stylesheets/custom.scss b/app/assets/stylesheets/custom.scss
index f84fa37..e5b57fd 100644
--- a/app/assets/stylesheets/custom.scss
+++ b/app/assets/stylesheets/custom.scss
@@ -573,3 +573,10 @@ a {
 .book-button:hover {
   background-color: $accent-hover;
 }
+
+.img-thumbnail {
+  height: 200px;
+  width: 200px;
+  object-fit: contain;
+  margin-bottom: 10px;
+}
diff --git a/app/controllers/room_types_controller.rb b/app/controllers/room_types_controller.rb
index 82d7045..a82f0b0 100644
--- a/app/controllers/room_types_controller.rb
+++ b/app/controllers/room_types_controller.rb
@@ -3,7 +3,7 @@ class RoomTypesController < ApplicationController
   layout "admin"
   before_action :logged_in_user
   before_action :admin_user, only: %i(create destroy)
-  before_action :get_room_type, only: %i(show destroy)
+  before_action :get_room_type, only: %i(show edit update destroy)
 
   def index
     @room_types = RoomType.without_deleted
@@ -27,6 +27,17 @@ def create
 
   def show; end
 
+  def edit; end
+
+  def update
+    if @room_type.update room_type_params
+      flash[:success] = t "msg.room_type_updated"
+      redirect_to @room_type
+    else
+      render :edit, status: :unprocessable_entity
+    end
+  end
+
   def destroy
     if @room_type.destroy
       flash[:success] = t "msg.room_type_deleted"
@@ -36,6 +47,14 @@ def destroy
     redirect_to room_types_url
   end
 
+  def destroy_image
+    @room_type = RoomType.find_by id: params[:room_type_id]
+    image = @room_type.images.find(params[:image_id])
+    image.purge
+    flash[:success] = t "msg.image_removed"
+    redirect_to edit_room_type_path(@room_type)
+  end
+
   private
   def room_type_params
     params.require(:room_type).permit(*RoomType::PERMITTED_PARAMS)
diff --git a/app/controllers/user/room_types_controller.rb b/app/controllers/user/room_types_controller.rb
index aa107db..ff0b81e 100644
--- a/app/controllers/user/room_types_controller.rb
+++ b/app/controllers/user/room_types_controller.rb
@@ -5,9 +5,9 @@ def index
 
   def show
     @room_type = RoomType.find_by(id: params[:id])
-    if @room_type.nil?
-      flash[:danger] = t "room_type_not_found"
-      redirect_to user_room_types_path
-    end
+    return if @room_type.present?
+
+    flash[:danger] = t "room_type_not_found"
+    redirect_to user_room_types_path
   end
 end
diff --git a/app/javascript/custom/room_type_form.js b/app/javascript/custom/room_type_form.js
index c197d0f..88a6294 100644
--- a/app/javascript/custom/room_type_form.js
+++ b/app/javascript/custom/room_type_form.js
@@ -1,26 +1,43 @@
 document.addEventListener('turbo:load', function() {
-  document.getElementById('add-device').addEventListener('click', function(e) {
-    e.preventDefault();
-    
-    var deviceFields = document.getElementById('device-fields');
-    var index = deviceFields.children.length;
-    
-    var newFields = `
-      <div class='device-entry'>
-        <input type='text' name='room_type[devices_attributes][${index}][name]' placeholder='Device Name' class='form-control'>
-        <input type='number' name='room_type[devices_attributes][${index}][quantity]' placeholder='Quantity' class='form-control'>
-        <a href='#' class='remove-device btn btn-danger text-white'>
-          Remove
-        </a>
-      </div>`;
-    
-    deviceFields.insertAdjacentHTML('beforeend', newFields);
-  });
+  const urlPattern = /^\/(en|vi)\/admin\/room_types\/(\d+\/edit|new)$/;
+  if (urlPattern.test(window.location.pathname)) {
+    const addDeviceButton = document.getElementById('add-device');
+    const deviceFields = document.getElementById('device-fields');
 
-  document.addEventListener('click', function(e) {
-    if (e.target && e.target.classList.contains('remove-device')) {
-      e.preventDefault();
-      e.target.parentElement.remove();
+    if (!addDeviceButton || !deviceFields) return;
+
+    let index = deviceFields.children.length;
+    if (!addDeviceButton.dataset.listenerAdded) {
+      addDeviceButton.dataset.listenerAdded = "true";
+
+      addDeviceButton.addEventListener('click', function(e) {
+        e.preventDefault();
+
+        var newFields = `
+          <div class='device-entry'>
+            <input type='text' name='room_type[devices_attributes][${index}][name]' placeholder='Device Name' class='form-control'>
+            <input type='number' name='room_type[devices_attributes][${index}][quantity]' placeholder='Quantity' class='form-control'>
+            <input type='hidden' name='room_type[devices_attributes][${index}][_destroy]' value='false' class='device-destroy'>
+            <a href='#' class='remove-device btn btn-danger text-white'>Remove</a>
+          </div>`;
+
+        deviceFields.insertAdjacentHTML('beforeend', newFields);
+        index++; 
+      });
     }
-  });
+
+    document.addEventListener('click', function(e) {
+      if (e.target && e.target.classList.contains('remove-device')) {
+        e.preventDefault();
+        let deviceEntry = e.target.closest('.device-entry');
+        let destroyInput = deviceEntry.querySelector('.device-destroy');
+        if (destroyInput) {
+          destroyInput.value = 'true'; 
+          deviceEntry.style.display = 'none'; 
+        } else {
+          deviceEntry.remove(); 
+        }
+      }
+    });
+  }
 });
diff --git a/app/javascript/custom/upload_images.js b/app/javascript/custom/upload_images.js
index c8b7a47..a27f47b 100644
--- a/app/javascript/custom/upload_images.js
+++ b/app/javascript/custom/upload_images.js
@@ -1,26 +1,30 @@
 document.addEventListener('turbo:load', function () {
-  const imageInput = document.querySelector(`input[type='file'][name='room_type[images][]'`);
-  const previewContainer = document.createElement('div');
-  previewContainer.classList.add('image-preview-container');
-  imageInput.parentNode.insertBefore(previewContainer, imageInput.nextSibling);
+  const urlPattern = /^\/(en|vi)\/admin\/room_types\/(new|\d+\/edit)$/;
+  if (urlPattern.test(window.location.pathname)) {
+    const imageInput = document.getElementById('room_type_images');
+    if (imageInput.dataset.listener === 'true') return;
+    imageInput.dataset.listener = 'true';
+    const previewContainer = document.createElement('div');
+    previewContainer.classList.add('image-preview-container');
+    imageInput.parentNode.insertBefore(previewContainer, imageInput.nextSibling);
+    imageInput.addEventListener('change', function (event) {
+      previewContainer.innerHTML = '';
+      const files = event.target.files;
 
-  imageInput.addEventListener('change', function (event) {
-    previewContainer.innerHTML = ''
-    const files = event.target.files;
-
-    Array.from(files).forEach((file) => {
-      if (file.type.startsWith('image/')) {
-        const reader = new FileReader();
-        reader.onload = function (e) {
-          const img = document.createElement('img');
-          img.style.width = 'auto';
-          img.style.height = '80px';
-          img.src = e.target.result;
-          img.classList.add('image-preview');
-          previewContainer.appendChild(img);
-        };
-        reader.readAsDataURL(file);
-      }
+      Array.from(files).forEach((file) => {
+        if (file.type.startsWith('image/')) {
+          const reader = new FileReader();
+          reader.onload = function (e) {
+            const img = document.createElement('img');
+            img.style.width = 'auto';
+            img.style.height = '80px';
+            img.src = e.target.result;
+            img.classList.add('image-preview');
+            previewContainer.appendChild(img);
+          };
+          reader.readAsDataURL(file);
+        }
+      });
     });
-  });
+  }
 });
diff --git a/app/models/device.rb b/app/models/device.rb
index 3a804e6..5c9559c 100644
--- a/app/models/device.rb
+++ b/app/models/device.rb
@@ -1,4 +1,4 @@
 class Device < ApplicationRecord
-  PERMITTED_PARAMS = %i(name quantity _destroy).freeze
+  PERMITTED_PARAMS = %i(id name quantity _destroy).freeze
   belongs_to :room_type
 end
diff --git a/app/models/room_type.rb b/app/models/room_type.rb
index a8a53d3..2fa7290 100644
--- a/app/models/room_type.rb
+++ b/app/models/room_type.rb
@@ -17,5 +17,4 @@ class RoomType < ApplicationRecord
   validates :price, presence: true, numericality:
             {greater_than_or_equal_to: Settings.zero,
              less_than: Settings.max_price_value}
-
 end
diff --git a/app/views/room_types/_form.html.erb b/app/views/room_types/_form.html.erb
new file mode 100644
index 0000000..61fd896
--- /dev/null
+++ b/app/views/room_types/_form.html.erb
@@ -0,0 +1,57 @@
+<%= form_for(@room_type) do |f| %>
+  <%= render "shared/error_messages", object: f.object %>
+  <div class="form-group">
+    <%= f.label :name %>
+    <%= f.text_field :name, class: "form-control" %>
+  </div>
+
+  <div class="form-group">
+    <%= f.label :description %>
+    <%= f.text_area :description, class: "form-control" %>
+  </div>
+
+  <div class="form-group">
+    <%= f.label :price %>
+    <%= f.number_field :price, class: "form-control" %>
+  </div>
+
+  <div class="form-group">
+    <%= f.label :view %>
+    <%= f.text_field :view, class: "form-control" %>
+  </div>
+
+  <div class="form-group">
+    <%= f.label :images %>
+    <% if @room_type.images.attached? %>
+      <div class="existing-images">
+        <% @room_type.images.each do |image| %>
+          <div class="image-preview">
+            <%= image_tag image, class: "img-thumbnail" %>
+            <%= link_to t("room_types.delete"), room_type_image_path(@room_type, image.id), data: {turbo_method: :delete, turbo_confirm: t("msg.you_sure")}, class: "btn btn-danger btn-sm" %>
+          </div>
+        <% end %>
+      </div>
+    <% end %>
+    <%= f.file_field :images, multiple: true %>
+  </div>
+
+  <h3><%= t "room_types.form.devices" %></h3>
+  <div id="device-fields">
+    <%= f.fields_for :devices do |device_form| %>
+      <div class="device-entry">
+        <%= device_form.text_field :name, placeholder: t(".device_name"), class: "form-control" %>
+        <%= device_form.number_field :quantity, placeholder:  t(".quantity"), class: "form-control" %>
+        <%= device_form.hidden_field :_destroy, class: "device-destroy" %>
+        <%= link_to "#", class: "remove-device btn btn-danger" do %>
+          <%= t "room_types.delete" %>
+        <% end %>
+      </div>
+    <% end %>
+  </div>
+
+  <button type="button" id="add-device" class="btn btn-primary"><%= t "room_types.form.add_device" %></button>
+
+  <div class="form-actions">
+    <%= f.submit t("room_types.form.create"), class: "btn btn-primary" %>
+  </div>
+<% end %>
diff --git a/app/views/room_types/edit.html.erb b/app/views/room_types/edit.html.erb
new file mode 100644
index 0000000..2da2c32
--- /dev/null
+++ b/app/views/room_types/edit.html.erb
@@ -0,0 +1,10 @@
+<% provide :title, t(".room_type_management") %>
+<div class="room_type_edit_page">
+  <div class="breadcrumbs">
+    <%= link_to @room_type do %>
+      <%= bootstrap_icon "arrow-return-left", height: Settings.default.view.sidebar.icon_size, class:"action-logo" %>
+    <% end %>
+    <span><%= t ".room_type_detail" %></span> 
+  </div>
+  <%= render "form" %>
+</div>
diff --git a/app/views/room_types/new.html.erb b/app/views/room_types/new.html.erb
index 5f4282b..6bec31a 100644
--- a/app/views/room_types/new.html.erb
+++ b/app/views/room_types/new.html.erb
@@ -7,50 +7,6 @@
     <span><%= t ".create_room_type" %></span> 
   </div>
 
-   <%= form_with model: @room_type, local: true do |f| %>
-   <%= render "shared/error_messages", object: f.object %>
-    <div class="form-group">
-      <%= f.label :name, t(".name") %>
-      <%= f.text_field :name, class: "form-control" %>
-    </div>
+  <%= render "form" %>
 
-    <div class="form-group">
-      <%= f.label :description, t(".description") %>
-      <%= f.text_area :description, class: "form-control" %>
-    </div>
-
-    <div class="form-group">
-      <%= f.label :price, t(".price") %>
-      <%= f.number_field :price, class: "form-control" %>
-    </div>
-
-    <div class="form-group">
-      <%= f.label :view, t(".view") %>
-      <%= f.text_field :view, class: "form-control" %>
-    </div>
-
-    <div class="form-group">
-      <%= f.label :images %>
-      <%= f.file_field :images, multiple: true %>
-    </div>
-
-    <h3><%= t ".devices" %></h3>
-    <div id="device-fields">
-      <%= f.fields_for :devices do |device_form| %>
-        <div class="device-entry">
-          <%= device_form.text_field :name, placeholder: t(".device_name"), class: "form-control" %>
-          <%= device_form.number_field :quantity, placeholder:  t(".quantity"), class: "form-control" %>
-          <%= link_to "#", class: "remove-device btn btn-danger" do %>
-            <%= t ".remove" %>
-          <% end %>
-        </div>
-      <% end %>
-    </div>
-    <button type="button" id="add-device" class="btn btn-primary">
-      <%= t ".add_device" %>
-    </button>
-    <div class="form-actions">
-      <%= f.submit t(".create"), class: "btn btn-primary" %>
-    </div>
-  <% end %>
 </div>
diff --git a/app/views/room_types/show.html.erb b/app/views/room_types/show.html.erb
index 5f7373c..b54ad39 100644
--- a/app/views/room_types/show.html.erb
+++ b/app/views/room_types/show.html.erb
@@ -1 +1,52 @@
 <% provide :title, t("room_types.index.room_type_management") %>
+<div class="room-type-detail-page">
+  <div class="breadcrumbs">
+    <%= link_to room_types_url do %>
+      <%= bootstrap_icon "arrow-return-left", height: Settings.default.view.sidebar.icon_size, class:"action-logo" %>
+    <% end %>
+    <span><%= t ".room_type_detail" %></span> 
+  </div>
+
+  <h1><%= @room_type.name %></h1>
+  <p>
+    <strong><%= t ".description" %></strong>
+    <%= @room_type.description %>
+  </p>
+  <p>
+    <strong><%= t ".price" %>:</strong>
+    <%= @room_type.price %> VND
+  </p>
+  <p>
+    <strong><%= t ".view" %>:</strong>
+    <%= @room_type.view %>
+  </p>
+
+  <h2><%= t ".images" %></h2>
+  <div class="room-type-images">
+    <% if @room_type.images.attached? %>
+      <% @room_type.images.each do |image| %>
+        <div class="room-type-image">
+          <%= image_tag image %>
+        </div>
+      <% end %>
+    <% else %>
+      <p><%= t ".no_image" %></p>
+    <% end %>
+  </div>
+
+  <h2><%= t ".devices" %></h2>
+  <table class="table">
+    
+    <% @room_type.devices.each do |device| %>
+      <tr>
+        <td><%= device.name %></td>
+        <td><%= device.quantity %></td>
+      </tr>
+    <% end %>
+  </table>
+
+  <%= link_to edit_room_type_url(@room_type) do %>
+    <%= bootstrap_icon "pencil-fill", height: Settings.default.view.sidebar.icon_size, class:"action-logo" %>
+    Edit
+  <% end %> 
+</div>
diff --git a/config/environments/development.rb b/config/environments/development.rb
index e522e6e..92610a7 100644
--- a/config/environments/development.rb
+++ b/config/environments/development.rb
@@ -52,6 +52,7 @@
 
   # Raise an error on page load if there are pending migrations.
   config.active_record.migration_error = :page_load
+  config.active_storage.replace_on_assign_to_many = false
 
   # Highlight code that triggered database queries in logs.
   config.active_record.verbose_query_logs = true
diff --git a/config/locales/en.yml b/config/locales/en.yml
index b9e8cfe..164b2b2 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -1,4 +1,14 @@
 en:
+  activerecord:
+    models:
+      room_type: "Room type"
+    attributes:
+      room_type:
+        name: "Name"
+        view: "View"
+        description: "Description"
+        price: "Price"
+        images: "Images"
   hello: "Hello"
   language:
     english: "English"
@@ -43,16 +53,25 @@ en:
       price: "Price"
     new:
       create_room_type: "Create room type"
-      create: "Create"
       name: "Name"
       price: "Price"
       description: "Description"
       view: "View"
-      devices: "Devices"
-      device_name: "Device Name"
+      remove: "Remove"
+    form:
+      create: "Create"
       quantity: "Quantity"
+      device_name: "Device Name"
+      devices: "Devices"
       add_device: "Add device"
-      remove: "Remove"
+    show:
+      room_type_detail: "Room type's detail"
+      description: "Description:"
+      view: "View:"
+      images: "Images"
+      devices: "Devices"
+      price: "Price"
+      no_image: "No image available"
     view: "View"
     delete: "Delete"
   msg:
@@ -60,8 +79,10 @@ en:
     invalid_image_format: "Invalid image format"
     room_type_deleted: "Room type deleted"
     delete_fail: "Delete failed"
-    you_sure: "Are you sure ?"
+    you_sure: "Are you sure?"
     invalid_room_type: "Room type not found!"
+    room_type_updated: "Room type updated!"
+    image_removed: "Image removed!"
   menu:
     overview: "Overview"
     room_list: "Room List"
diff --git a/config/locales/vi.yml b/config/locales/vi.yml
index 19c66ec..56cee59 100644
--- a/config/locales/vi.yml
+++ b/config/locales/vi.yml
@@ -1,5 +1,15 @@
 
 vi:
+  activerecord:
+    models:
+      room_type: "Room type"
+    attributes:
+      room_type:
+        name: "Tên loại phòng"
+        view: "View cửa sổ"
+        description: "Mô tả"
+        price: "Giá"
+        images: "Hình ảnh phòng"
   hello: "Xin chào"
   language:
     english: "Tiếng Anh"
@@ -44,16 +54,28 @@ vi:
       price: "Giá"
     new:
       create_room_type: "Tạo loại phòng mới"
-      create: "Tạo"
       description: "Mô tả"
       view: "View cửa sổ"
       devices: "Thiết bị"
       device_name: "Tên thiết bị"
       quantity: "Số lượng"
-      add_device: "Thêm thiết bị"
       remove: "Xóa"
+    form:
+      create: "Tạo"
+      quantity: "Số lượng"
+      device_name: "Tên thiết bị"
+      devices: "Thiết bị"
+      add_device: "Thêm thiết bị"
     view: "Xem"
     delete: "Xóa"
+    show:
+      room_type_detail: "Chi tiết loại phòng"
+      description: "Mô tả:"
+      view: "View cửa sổ:"
+      images: "Hình ảnh"
+      devices: "Thiết bị"
+      price: "Giá"
+      no_image: "Chưa có hình ảnh"
   msg:
     room_type_created: "Tạo phòng thành công!"
     invalid_image_format: "Ảnh không đúng định dạng"
@@ -61,6 +83,8 @@ vi:
     delete_fail: "Xóa thất bại"
     you_sure: "Bạn có chắc không?"
     invalid_room_type: "Không tìm thấy loại phòng!"
+    room_type_updated: "Đã cập nhật loại phòng"
+    image_removed: "Đã xóa ảnh!"
   menu:
     overview: "Tổng quan"
     room_list: "Danh sách phòng"
diff --git a/config/routes.rb b/config/routes.rb
index c4d5fea..17133d4 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -11,7 +11,10 @@
     get "sessions/create"
     get "sessions/destroy"
     scope "admin" do
-      resources :room_types
+      resources :room_types do
+        delete "images/:image_id", to: "room_types#destroy_image", as: "image"
+      end
+      resources :rooms
     end
     scope :user do
       get "room_types", to: "user/room_types#index", as: "user_room_types"
diff --git a/db/schema.rb b/db/schema.rb
index eda5392..c87bbe2 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -114,8 +114,8 @@
     t.string "view"
     t.datetime "created_at", null: false
     t.datetime "updated_at", null: false
-    t.integer "size"
     t.datetime "deleted_at"
+    t.integer "size"
     t.index ["deleted_at"], name: "index_room_types_on_deleted_at"
   end
 


Reviews:
body: cmt
state: COMMENTED
author_association: NONE
submitted_at: 2025-04-03T05:47:55Z
body: cmt
state: COMMENTED
author_association: NONE
submitted_at: 2025-04-03T06:11:36Z
body: merged
state: COMMENTED
author_association: NONE
submitted_at: 2025-04-03T06:14:22Z

Review comments:
diff_hunk: @@ -0,0 +1,57 @@
+<%= form_for(@room_type) do |f| %>
+  <%= render "shared/error_messages", object: f.object %>
+  <div class="form-group">
+    <%= f.label :name %>
+    <%= f.text_field :name, class: "form-control" %>
+  </div>
+
+  <div class="form-group">
+    <%= f.label :description %>
+    <%= f.text_area :description, class: "form-control" %>
+  </div>
+
+  <div class="form-group">
+    <%= f.label :price %>
+    <%= f.number_field :price, class: "form-control" %>
+  </div>
+
+  <div class="form-group">
+    <%= f.label :view %>
+    <%= f.text_field :view, class: "form-control" %>
+  </div>
+
+  <div class="form-group">
+    <%= f.label :images %>
+    <% if @room_type.images.attached? %>
+      <div class="existing-images">
+        <% @room_type.images.each do |image| %>
+          <div class="image-preview">
+            <%= image_tag image, class: "img-thumbnail" %>
+            <%= link_to t("room_types.delete"), room_type_image_path(@room_type, image.id), data: {turbo_method: :delete, turbo_confirm: t("msg.you_sure")}, class: "btn btn-danger btn-sm" %>
+          </div>
+        <% end %>
+      </div>
+    <% end %>
+    <%= f.file_field :images, multiple: true %>
+  </div>
+
+  <h3><%= t "room_types.form.devices" %></h3>
+  <div id="device-fields">
+    <%= f.fields_for :devices do |device_form| %>
+      <div class="device-entry">
+        <%= device_form.text_field :name, placeholder: t(".device_name"), class: "form-control" %>
+        <%= device_form.number_field :quantity, placeholder:  t(".quantity"), class: "form-control" %>
+        <%= device_form.hidden_field :_destroy, class: "device-destroy" %>
+        <%= link_to "#", class: "remove-device btn btn-danger" do %>
+            <%= t "room_types.delete" %>
path: app/views/room_types/_form.html.erb
body: ```suggestion
          <%= t "room_types.delete" %>
```
created_at: 2025-04-03T05:46:43Z
author_association: NONE
diff_hunk: @@ -0,0 +1,10 @@
+<% provide :title, t(".room_type_management") %>
+<div class="room_type_edit_page">
+  <div class="breadcrumbs">
+        <%= link_to @room_type do %>
+          <%= bootstrap_icon "arrow-return-left", height: Settings.default.view.sidebar.icon_size, class:"action-logo" %>
+        <% end %>
+        <span><%= t ".room_type_detail" %></span> 
path: app/views/room_types/edit.html.erb
body: indent 
created_at: 2025-04-03T05:47:28Z
author_association: NONE
diff_hunk: @@ -1 +1,52 @@
 <% provide :title, t("room_types.index.room_type_management") %>
+<div class="room-type-detail-page">
+  <div class="breadcrumbs">
+      <%= link_to room_types_url do %>
path: app/views/room_types/show.html.erb
body: indent
created_at: 2025-04-03T05:47:47Z
author_association: NONE
diff_hunk: @@ -11,7 +11,9 @@
     get "sessions/create"
     get "sessions/destroy"
     scope "admin" do
-      resources :room_types
+      resources :room_types do
+        delete 'images/:image_id', to: 'room_types#destroy_image', as: 'image'
path: config/routes.rb
body: Dùng "
created_at: 2025-04-03T06:11:29Z
author_association: NONE

PR comments:
user: login: tungnx-3642
created_at: 2025-04-03T03:52:35Z
body: ready
author_association: CONTRIBUTOR
user: login: tungnx-3642
created_at: 2025-04-03T05:52:17Z
body: ready
author_association: CONTRIBUTOR
user: login: tungnx-3642
created_at: 2025-04-03T06:13:32Z
body: ready
author_association: CONTRIBUTOR