Skip to content

Commit 77593b8

Browse files
committed
feature/Extract toast to stimulus component
1 parent 34ba170 commit 77593b8

File tree

11 files changed

+141
-16
lines changed

11 files changed

+141
-16
lines changed

app/assets/stylesheets/toast.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
.toast {
44
&--container {
5-
position: absolute;
5+
position: fixed;
66
left: 50%;
77
margin-left: -150px;
88
width: 300px;

app/controllers/folders_controller.rb

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ def delete_alert
2020
@message = DELETE_CONFIRM_TEXT
2121
@confirm_word = 'DELETE'
2222
@confirm_path = folder_path(@folder, redirect_url: folders_path)
23+
@resource_id = @folder.client_id
2324
@method = :delete
2425

2526
render layout: false, partial: 'shared/alert'
@@ -96,13 +97,17 @@ def update
9697
end
9798

9899
def destroy
99-
if @folder.destroy
100-
flash[:notice] = 'Folder deleted!'
101-
else
102-
flash[:alert] = 'Unable to delete folder'
100+
respond_to do |format|
101+
format.html do
102+
if @folder.destroy
103+
flash[:notice] = 'Folder deleted!'
104+
else
105+
flash[:alert] = 'Unable to delete folder'
106+
end
107+
108+
redirect_to folders_path
109+
end
103110
end
104-
105-
redirect_to folders_path
106111
end
107112

108113
# Remove this once all routes no longer use JSON

app/controllers/snippets_controller.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ def delete_alert
8383
@message = DELETE_CONFIRM_TEXT
8484
@confirm_word = 'DELETE'
8585
@confirm_path = snippet_path(@snippet)
86-
@method = :delete
86+
@resource_id = @snippet.client_id
8787

8888
render layout: false
8989
end

app/javascript/controllers/alert_controller.js

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,56 @@ import { Controller } from 'stimulus';
22
import axios from 'axios';
33

44
export default class extends Controller {
5-
static targets = ["alert"];
5+
static targets = ["alert", "confirm"]; d
66

7+
initialize() {
8+
const csrfToken = document.querySelector("meta[name=csrf-token]").content
9+
axios.defaults.headers.common['X-CSRF-Token'] = csrfToken
10+
}
711
present(event) {
812
event.preventDefault()
913

1014
axios.get(this.url)
11-
.then(res => {
12-
document.getElementById('vue-app').insertAdjacentHTML('afterbegin', res.data);
13-
})
15+
.then(res => this.app.insertAdjacentHTML('afterbegin', res.data))
1416
.catch(console.error)
1517
}
1618

1719
close(event) {
1820
this.alertTarget.remove()
1921
}
2022

23+
confirm() {
24+
console.log(this.confirmPath)
25+
26+
axios.delete(this.confirmPath, { headers: { 'accept': 'application/json' } })
27+
.then(res => {
28+
document.getElementById(this.resourceId).remove()
29+
this.alertTarget.remove()
30+
this.toast.display('Snippet deleted!')
31+
})
32+
.catch(error => {
33+
console.error(error)
34+
this.toast.display('Unable to delete snippet')
35+
})
36+
}
37+
2138
get url() {
2239
return this.data.get('url')
2340
}
41+
42+
get confirmPath() {
43+
return this.data.get('confirmPath')
44+
}
45+
46+
get resourceId() {
47+
return this.data.get('resourceId')
48+
}
49+
50+
get app() {
51+
return document.getElementById('vue-app')
52+
}
53+
54+
get toast() {
55+
return document.getElementById('toast').toast
56+
}
2457
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { Controller } from 'stimulus';
2+
import axios from 'axios';
3+
4+
export default class extends Controller {
5+
static targets = ["toast", "message"];
6+
7+
connect() {
8+
this.element[this.identifier] = this
9+
}
10+
11+
initialize() {
12+
const csrfToken = document.querySelector("meta[name=csrf-token]").content
13+
axios.defaults.headers.common['X-CSRF-Token'] = csrfToken
14+
15+
this.checkForNotice();
16+
}
17+
18+
checkForNotice() {
19+
if (this.hasNotice() || this.hasAlert()) {
20+
const message = this.hasNotice() ? this.notice : this.alert
21+
22+
this.display(message)
23+
}
24+
}
25+
26+
hasNotice() {
27+
return this.notice.length > 0
28+
}
29+
30+
hasAlert() {
31+
return this.alert.length > 0
32+
}
33+
34+
display(message, type = 'notice') {
35+
this.messageTarget.innerHTML = message
36+
this.toastTarget.classList.remove('hidden')
37+
setTimeout(() => this.hideToast(), 3000)
38+
}
39+
40+
hideToast() {
41+
this.toastTarget.classList.add('hidden')
42+
}
43+
44+
get notice() {
45+
return this.data.get('notice')
46+
}
47+
48+
get alert() {
49+
return this.data.get('alert')
50+
}
51+
}

app/models/folder.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,8 @@ def popover_options_for(user)
1515

1616
options
1717
end
18+
19+
def client_id
20+
"folder_#{id}"
21+
end
1822
end

app/models/snippet.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ def highlighted
4949
).html_safe
5050
end
5151

52+
def client_id
53+
"snippet_#{id}"
54+
end
55+
5256
private
5357

5458
def owner_folder_presence

app/views/layouts/application.html.erb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@
3131
<% else %>
3232
<div id="vue-app" v-cloak>
3333
<% end %>
34-
<toast alert="<%= alert %>" notice="<%= notice %>"></toast>
35-
<%# <alert></alert> %>
34+
<%= render partial: 'shared/toast' %>
35+
3636
<popover></popover>
3737

3838
<%= render partial: 'shared/topbar' %>

app/views/shared/_alert.html.erb

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
<div data-controller="alert" data-target="alert.alert" class="alert-mask">
1+
<div
2+
class="alert-mask"
3+
data-controller="alert"
4+
data-target="alert.alert"
5+
data-alert-confirm-path="<%= @confirm_path %>"
6+
data-alert-resource-id="<%= @resource_id %>"
7+
>
28
<div class="alert-wrapper">
39
<div class="alert-container">
410
<div class="alert-header">
@@ -16,7 +22,18 @@
1622
<button data-action="click->alert#close" class="button--cta-cancel">
1723
CANCEL
1824
</button>
19-
<%= link_to @confirm_word, @confirm_path, method: @method, class: "button--cta-new" %>
25+
26+
<% if @method == :delete %>
27+
<%= link_to @confirm_word, @confirm_path, method: @method, class: "button--cta-new" %>
28+
<% else %>
29+
<button
30+
class="button--cta-new"
31+
data-action="click->alert#confirm"
32+
>
33+
<%= @confirm_word %>
34+
</button>
35+
<% end %>
36+
2037
</div>
2138
</div>
2239
</div>

app/views/shared/_toast.html.erb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<div
2+
id="toast"
3+
class="toast--container-notice hidden"
4+
data-controller="toast"
5+
data-target="toast.toast"
6+
data-toast-notice="<%= notice %>"
7+
data-toast-alert="<%= alert %>"
8+
>
9+
<span data-target="toast.message"></span>
10+
</div>

0 commit comments

Comments
 (0)