Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions app/components/action_completed_button_component.html.slim
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
.action-completed
.action-completed__action
button.a-button.is-sm.is-block.check-button.is-muted-borderd(
data-commentable-id='#{commentable_id}'
data-update-path='#{update_path}'
data-model-name='#{model_name}'
)
i.fas.fa-check
| 対応済です
Expand All @@ -18,7 +19,8 @@
.action-complete
.action-completed__action
button.a-button.is-sm.is-block.check-button.is-warning(
data-commentable-id='#{commentable_id}'
data-update-path='#{update_path}'
data-model-name='#{model_name}'
)
i.fas.fa-redo
| 対応済にする
Expand Down
11 changes: 7 additions & 4 deletions app/components/action_completed_button_component.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
# frozen_string_literal: true

class ActionCompletedButtonComponent < ViewComponent::Base
attr_reader :is_action_completed, :commentable_id

def initialize(is_initial_action_completed:, commentable_id:)
def initialize(is_initial_action_completed:, update_path:, model_name:)
@is_action_completed = is_initial_action_completed
@commentable_id = commentable_id
@update_path = update_path
@model_name = model_name
end

private

attr_reader :is_action_completed, :update_path, :model_name
end
3 changes: 2 additions & 1 deletion app/controllers/api/talks_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ def index; end

def update
talk = Talk.find(params[:id])
talk.update(talk_params)
talk.update!(talk_params)
head :no_content
end

private
Expand Down
78 changes: 43 additions & 35 deletions app/javascript/action_completed_button.js
Original file line number Diff line number Diff line change
@@ -1,39 +1,41 @@
import CSRF from 'csrf'
import { patch } from '@rails/request.js'
import { toast } from './vanillaToast'

document.addEventListener('DOMContentLoaded', function () {
document.addEventListener('DOMContentLoaded', () => {
const button = document.querySelector('.check-button')
if (!button) {
return
}
const commentableId = button.dataset.commentableId
button.addEventListener('click', function () {
if (!button) return

const updatePath = button.dataset.updatePath
const modelName = button.dataset.modelName
button.addEventListener('click', async () => {
button.disabled = true
const isInitialActionCompleted =
button.classList.contains('is-muted-borderd')
const isActionCompleted = !isInitialActionCompleted

fetch(`/api/talks/${commentableId}`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json; charset=utf-8',
'X-Requested-With': 'XMLHttpRequest',
'X-CSRF-Token': CSRF.getToken()
},
body: JSON.stringify({
talk: { action_completed: isActionCompleted }
try {
const response = await patch(updatePath, {
body: JSON.stringify({
[modelName]: { action_completed: isActionCompleted }
})
})
})
.then((response) => {
if (!response.ok) {
throw new Error('Network response was not ok')
if (response.ok) {
const forCompleted = {
newButtonText: '対応済です',
iconClass: 'fa-check',
newMessage:
'お疲れ様でした!相談者から次のアクションがあった際は、自動で未対応のステータスに変更されます。再度このボタンをクリックすると、未対応にステータスに戻ります。',
toastMessage: '対応済みにしました'
}
})
.then(() => {
const newButtonText = isActionCompleted ? '対応済です' : '対応済にする'
const iconClass = isActionCompleted ? 'fa-check' : 'fa-redo'
const newMessage = isActionCompleted
? 'お疲れ様でした!相談者から次のアクションがあった際は、自動で未対応のステータスに変更されます。再度このボタンをクリックすると、未対応にステータスに戻ります。'
: '返信が完了し次は相談者からのアクションの待ちの状態になったとき、もしくは、相談者とのやりとりが一通り完了した際は、このボタンをクリックして対応済のステータスに変更してください。'
const forNotCompleted = {
newButtonText: '対応済にする',
iconClass: 'fa-redo',
newMessage:
'返信が完了し次は相談者からのアクションの待ちの状態になったとき、もしくは、相談者とのやりとりが一通り完了した際は、このボタンをクリックして対応済のステータスに変更してください。',
toastMessage: '未対応にしました'
}
const { newButtonText, iconClass, newMessage, toastMessage } =
isActionCompleted ? forCompleted : forNotCompleted
button.innerHTML = `<i class="fas ${iconClass}"></i> ${newButtonText}`
button.classList.toggle('is-warning', !isActionCompleted)
button.classList.toggle('is-muted-borderd', isActionCompleted)
Expand All @@ -45,13 +47,19 @@ document.addEventListener('DOMContentLoaded', function () {
description.innerHTML = newMessage
}

const tostMessage = isActionCompleted
? '対応済みにしました'
: '未対応にしました'
toast(tostMessage, 'success')
})
.catch((error) => {
console.warn(error)
})
toast(toastMessage, 'success')
} else {
toast('更新に失敗しました', 'error')
const errorText = await response.text
console.warn('update action_completed failed', {
status: response.statusCode,
body: errorText
})
}
} catch (error) {
console.warn(error)
}

button.disabled = false
})
})
2 changes: 1 addition & 1 deletion app/views/talks/show.html.slim
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
= member.login_name
= render 'comments/comments', commentable: @talk, commentable_type: 'Talk'
- if current_user.admin?
= render(ActionCompletedButtonComponent.new(is_initial_action_completed: @talk.action_completed, commentable_id: @talk.id))
= render(ActionCompletedButtonComponent.new(is_initial_action_completed: @talk.action_completed, update_path: api_talk_path(@talk), model_name: 'talk'))

- if current_user.admin?
.col-xl-5.col-xs-12
Expand Down
18 changes: 18 additions & 0 deletions test/components/action_completed_button_component_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# frozen_string_literal: true

require 'test_helper'

class ActionCompletedButtonComponentTest < ViewComponent::TestCase
test 'action is completed' do
# update_pathとmodel_nameは使用されないため値は任意
render_inline(ActionCompletedButtonComponent.new(is_initial_action_completed: true, update_path: '/api/talks/1', model_name: 'talk'))

assert_text '対応済です'
end

test 'action is not completed' do
render_inline(ActionCompletedButtonComponent.new(is_initial_action_completed: false, update_path: '/api/talks/1', model_name: 'talk'))

assert_text '対応済にする'
end
end