-
Notifications
You must be signed in to change notification settings - Fork 41
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Mass assign * Add case replies * Thumbnails * Lint * Fix issue with mass update * replies -> templates
- Loading branch information
Cory McDonald
authored
Jul 19, 2019
1 parent
580f997
commit 24b5f1b
Showing
17 changed files
with
426 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
module Admin | ||
class CaseRepliesController < AdminController | ||
def index | ||
@open_cases = Case.where(status: Case::OPEN) | ||
@assigned_cases = Case.where(assignee: current_user, status: Case::IN_PROGRESS) | ||
|
||
@replies = CaseReply.all | ||
end | ||
|
||
def create | ||
CaseReply.create(reply_params) | ||
redirect_to admin_case_replies_path, flash: { notice: "Your saved reply was created successfully."} | ||
end | ||
|
||
def edit | ||
@reply = CaseReply.find(params[:id]) | ||
@open_cases = Case.where(status: Case::OPEN) | ||
@assigned_cases = Case.where(assignee: current_user, status: Case::IN_PROGRESS) | ||
end | ||
|
||
def update | ||
CaseReply.find(params[:id]).update(reply_params) | ||
redirect_to admin_case_replies_path, flash: { notice: "Your saved reply was updated successfully."} | ||
end | ||
|
||
def destroy | ||
CaseReply.find(params[:id]).destroy | ||
redirect_to admin_case_replies_path, flash: { notice: "Deleted the reply"} | ||
end | ||
|
||
|
||
private | ||
|
||
def reply_params | ||
params.require(:case_reply).permit(:id, :title, :body) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
import React from "react"; | ||
import * as ReactDOM from "react-dom"; | ||
|
||
export default class CaseReply extends React.Component { | ||
constructor(props) { | ||
super(props); | ||
this.state = { | ||
filterText: "", | ||
isVisible: false | ||
}; | ||
} | ||
|
||
setText = e => { | ||
this.setState({ filterText: e.target.value }); | ||
}; | ||
|
||
getReplies = () => { | ||
if (this.state.filterText === "") { | ||
return this.props.replies; | ||
} | ||
|
||
return this.props.replies.filter(reply => { | ||
let query = this.state.filterText.toLowerCase(); | ||
let title = reply.title.toLowerCase(); | ||
let body = reply.body.toLowerCase(); | ||
|
||
return title.includes(query) || body.includes(query); | ||
}); | ||
}; | ||
|
||
renderDropdown = () => { | ||
this.setState(prevState => ({ | ||
isVisible: !prevState.isVisible | ||
})); | ||
}; | ||
|
||
clickReply = body => { | ||
const textarea = document.getElementsByName("case_note[note]")[0]; | ||
|
||
textarea.value += body + "\n"; | ||
|
||
this.setState({ isVisible: false }); | ||
}; | ||
|
||
render() { | ||
const button = ( | ||
<div className="btn btn-light ml-2 mb-2" onClick={this.renderDropdown}> | ||
<i className="fa fa-comment-o" /> | ||
<i | ||
className="small ml-0 mr-2 fa fa-caret-down" | ||
style={{ top: "5px", position: "relative" }} | ||
/> | ||
Saved templates | ||
</div> | ||
); | ||
let replies = ( | ||
<div className="text-muted"> | ||
<i className="fa fa-frown-o mx-2" /> | ||
<span>No replies</span> | ||
</div> | ||
); | ||
|
||
const savedReplies = this.getReplies(); | ||
if (savedReplies.length > 0) { | ||
replies = savedReplies.map(reply => ( | ||
<div | ||
className="reply p-2 rounded" | ||
key={reply.id} | ||
onClick={() => this.clickReply(reply.body)} | ||
> | ||
<div className="font-weight-bold text-dark text-truncate"> | ||
{reply.title} | ||
</div> | ||
<div className="text-muted text-truncate">{reply.body}</div> | ||
</div> | ||
)); | ||
} | ||
|
||
return ( | ||
<div> | ||
{button} | ||
{this.state.isVisible && ( | ||
<div | ||
className="p-2 border rounded bg-white" | ||
style={{ width: "500px" }} | ||
> | ||
<strong className="p-1">Select a reply</strong> | ||
<div className="my-1 py-2 border-top"> | ||
<input | ||
type="text" | ||
autoFocus | ||
placeholder="Filter replies..." | ||
className="border rounded-pill px-3 py-1 w-100" | ||
style={{ outline: "none" }} | ||
value={this.state.filterText} | ||
onChange={this.setText} | ||
/> | ||
</div> | ||
<div style={{ maxHeight: "200px", overflow: "auto" }}> | ||
{replies} | ||
</div> | ||
</div> | ||
)} | ||
</div> | ||
); | ||
} | ||
} | ||
|
||
document.addEventListener("DOMContentLoaded", () => { | ||
const element = document.querySelector("#replySection"); | ||
const replies = JSON.parse(element.dataset.replies); | ||
ReactDOM.render(<CaseReply replies={replies} />, element); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# frozen_string_literal: true | ||
|
||
class CaseReply < ApplicationRecord | ||
validates :title, :body, presence: true, allow_blank: false | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
= form_with model: [:admin, reply], local: true do |f| | ||
.form-group | ||
label.font-weight-bold Saved reply title | ||
= f.text_field :title, { class:'form-control', placeholder: "Add a short title to your reply"} | ||
.form-group | ||
= f.text_area :body, { class:'form-control', rows:'4', placeholder: "Add your saved reply" } | ||
=submit_tag(reply.persisted? ? "Update saved reply" : "Add saved reply", class: "btn btn-primary") | ||
- if reply.persisted? | ||
=link_to "Cancel", admin_case_replies_path, class: 'btn btn-dark ml-3' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
.row | ||
.col-2.shadow-sm.pb-3 | ||
=render partial: 'admin/cases/sidebar' | ||
.col-10 | ||
h4 Edit saved reply | ||
hr | ||
= render partial: 'form', locals: { reply: @reply } |
Oops, something went wrong.