Skip to content

Commit

Permalink
Merge pull request #1767 from tactilenews/1755_improve_request_edit_w…
Browse files Browse the repository at this point in the history
…ith_files

Improve UX by adding request files to request form
  • Loading branch information
mattwr18 authored Jan 24, 2024
2 parents 3f2e840 + f0d33f1 commit ec2d573
Show file tree
Hide file tree
Showing 4 changed files with 165 additions and 45 deletions.
35 changes: 34 additions & 1 deletion app/components/request_form/request_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
data-controller="request-form"
data-request-form-members-count-message-value="<%= t('components.request_form.members_count_message').to_json %>"
data-request-form-preview-fallback-value="<%= t('components.request_form.preview_fallback') %>"
data-request-form-request-files-url-value="<%= @request.files.map { |file| url_for(file) } %>"
>

<div class="RequestForm-column" data-action="input->request-form#updatePreview">
Expand All @@ -27,10 +28,22 @@
class: 'RequestForm-insertPlaceholderButton',
type: 'button',
data: { action: 'request-form#insertImage' } do %>
<% if @request.planned? && @request.files.attached? %>
<% @request.files.each do |file| %>
<%= field.hidden_field(:request,
:files,
data: { request_form_target: 'imageInputAttachedFile' },
multiple: true,
value: file.signed_id

) %>
<% end %>
<% end %>
<%= field.file_field(:request,
:files,
data: { request_form_target: 'imageInput' },
multiple: true,
hidden: true,
accept: 'image/*'

) %>
Expand Down Expand Up @@ -58,7 +71,27 @@
<ul
data-request-form-target="filenames"
class="RequestForm-filenamesList"
></ul>
>
<% if @request.planned? && @request.files.attached? %>
<% @request.files.each do |file| %>
<li
id="image-filename-<%= file.blob[:filename] %>"
class="RequestForm-filenamesListItem"
>
<p class="RequestForm-filename"><%= file.blob[:filename] %></p>
<button
class="RequestForm-removeListItemButton Button"
data-action="request-form#removeAttachedImage"
data-request-form-image-id-value="<%= file.signed_id %>"
data-request-form-image-url-value="<%= url_for(file) %>"
type="button"
>
x
</button>
</li>
<% end %>
<% end %>
</ul>
</div>
<% end %>

Expand Down
170 changes: 128 additions & 42 deletions app/components/request_form/request_form.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,17 @@ export default class extends Controller {
'submitButton',
'characterCounter',
'modal',
'imageInputAttachedFile',
];
static values = {
membersCountMessage: String,
previewFallback: String,
requestFilesUrl: Array,
};

connect() {
this.updatePreview();
this.updateMembersCount();
this.imageInputTarget.classList.add('hidden');
this.updateCharacterCounter();
}

Expand All @@ -47,10 +48,20 @@ export default class extends Controller {
this.previewTarget.innerHTML = this.setMessage();
}

if (event?.target?.files?.length) {
if (event?.target?.files?.length || this.requestFilesUrlValue.length) {
this.previewTarget.innerHTML = '';
this.messageTarget.removeAttribute('required');
}
if (event?.target?.files?.length)
this.addImagePreview(event.target.files, this.setCaption());
if (this.requestFilesUrlValue.length) {
this.filenamesTarget.parentNode.classList.remove(
'RequestForm-filenamesWrapper--hidden'
);
this.addAttachedRequestFilesPreview(
this.requestFilesUrlValue,
this.setCaption()
);
}
}

Expand Down Expand Up @@ -85,11 +96,26 @@ export default class extends Controller {
this.imageInputTarget.click();
}

setUpImagePreview() {
let figure = document.getElementById('file-preview');
let div;
if (figure) {
div = document.getElementById('image-preview-wrapper');
} else {
figure = document.createElement('figure');
div = document.createElement('div');
div.classList.add('RequestForm-imagePreviewWrapper');
div.setAttribute('id', 'image-preview-wrapper');
}

figure.appendChild(div);
this.previewTarget.parentNode.appendChild(figure);

return [figure, div];
}

addImagePreview(files, message) {
const figure = document.createElement('figure');
const div = document.createElement('div');
div.classList.add('RequestForm-imagePreviewWrapper');
this.removeExistingPreview();
const [figure, div] = this.setUpImagePreview();

for (let i = 0; i < files.length; i++) {
let file = files.item(i);
Expand All @@ -114,20 +140,47 @@ export default class extends Controller {
img.classList.add('RequestForm-firstImageInOddNumber');
}
div.appendChild(img);
this.setImageAttributes(img, file);
this.setImageAttributes(img, URL.createObjectURL(file));
}
figure.appendChild(div);
const figcaption = document.createElement('figcaption');
figcaption.setAttribute('id', 'caption');
figure.setAttribute('id', 'file-preview');
figure.appendChild(figcaption);

this.previewTarget.parentNode.appendChild(figure);
const firstFigcaption = figure.querySelector('figcaption');
firstFigcaption.innerHTML = message;
this.addPreview(figure, message);
}

addAttachedRequestFilesPreview(urls, message) {
const [figure, div] = this.setUpImagePreview();

urls.forEach((url, i) => {
const existingImage = document.getElementById(`image-${url}`);
if (!existingImage) {
const img = document.createElement('img');
img.setAttribute('id', `image-${url}`);
img.classList.add('RequestForm-imagePreview');
if (urls.length % 2 == 1 && i == 0) {
img.classList.add('RequestForm-firstImageInOddNumber');
}
div.appendChild(img);
this.setImageAttributes(img, url);
}
});

this.addPreview(figure, message);
}

addPreview(figure, message) {
let figcaption = document.getElementById('caption');

if (!figcaption) {
figcaption = document.createElement('figcaption');
figcaption.setAttribute('id', 'caption');
figure.setAttribute('id', 'file-preview');
figure.appendChild(figcaption);
}

figure.appendChild(figcaption);
figcaption.innerHTML = message;
}

removeExistingPreview() {
removeExistingImagePreview() {
const existingFigure = document.getElementById('file-preview');
if (existingFigure) existingFigure.remove();
const chatPreviewBubbles = document.querySelectorAll(
Expand All @@ -138,14 +191,17 @@ export default class extends Controller {
element.remove();
}
});
}

removeExistingFilesname() {
const listItems = document.querySelectorAll(
'.RequestForm-filenamesListItem'
);
listItems.forEach(listItem => listItem.remove());
}

setImageAttributes(img, file) {
img.setAttribute('src', URL.createObjectURL(file));
setImageAttributes(img, url) {
img.setAttribute('src', url);
img.setAttribute('width', 100);
img.setAttribute('width', 100);
}
Expand All @@ -162,15 +218,41 @@ export default class extends Controller {

this.imageInputTarget.files = dt.files;
event.target.parentNode.remove();
if (this.imageInputTarget.files.length == 0) {
this.removeExistingPreview();
this.removeExistingImagePreview();
this.updatePreviewAfterRemoveEvent();
}

removeAttachedImage(event) {
event.target.parentNode.remove();

const id = event.target.dataset.requestFormImageIdValue;
const url = event.target.dataset.requestFormImageUrlValue;
this.requestFilesUrlValue = this.requestFilesUrlValue.filter(u => u != url);
const hiddenInputs = this.imageInputAttachedFileTargets;
const inputToDelete = hiddenInputs.find(
image => image.getAttribute('value') == id
);
inputToDelete.remove();
this.removeExistingImagePreview();
this.updatePreviewAfterRemoveEvent();
}

updatePreviewAfterRemoveEvent() {
if (
this.imageInputTarget.files.length == 0 &&
this.imageInputAttachedFileTargets.length == 0
) {
this.filenamesTarget.parentNode.classList.add(
'RequestForm-filenamesWrapper--hidden'
);
this.previewTarget.innerHTML = this.setMessage();
this.messageTarget.setAttribute('required', true);
} else {
this.addImagePreview(this.imageInputTarget.files, this.setCaption());
this.addAttachedRequestFilesPreview(
this.requestFilesUrlValue,
this.setCaption()
);
}
}

Expand All @@ -192,28 +274,32 @@ export default class extends Controller {
}

updateFilesname(index, file) {
const listItem = document.createElement('li');
listItem.setAttribute('id', `image-filename-${file.name}`);
listItem.classList.add('RequestForm-filenamesListItem');

const paragraph = document.createElement('p');
paragraph.innerText = file.name;
paragraph.classList.add('RequestForm-filename');
listItem.appendChild(paragraph);

const removeButton = document.createElement('button');
removeButton.innerText = 'x';
removeButton.setAttribute('data-action', 'request-form#removeImage');
removeButton.setAttribute('data-request-form-image-index-value', index);
removeButton.setAttribute('type', 'button');
removeButton.classList.add('Button');
removeButton.classList.add('RequestForm-removeListItemButton');
listItem.appendChild(removeButton);

this.filenamesTarget.appendChild(listItem);
this.filenamesTarget.parentNode.classList.remove(
'RequestForm-filenamesWrapper--hidden'
);
let listItem = document.getElementById(`image-filename-${file.name}`);

if (!listItem) {
listItem = document.createElement('li');
listItem.setAttribute('id', `image-filename-${file.name}`);
listItem.classList.add('RequestForm-filenamesListItem');

const paragraph = document.createElement('p');
paragraph.innerText = file.name;
paragraph.classList.add('RequestForm-filename');
listItem.appendChild(paragraph);

const removeButton = document.createElement('button');
removeButton.innerText = 'x';
removeButton.setAttribute('data-action', 'request-form#removeImage');
removeButton.setAttribute('data-request-form-image-index-value', index);
removeButton.setAttribute('type', 'button');
removeButton.classList.add('Button');
removeButton.classList.add('RequestForm-removeListItemButton');
listItem.appendChild(removeButton);

this.filenamesTarget.appendChild(listItem);
this.filenamesTarget.parentNode.classList.remove(
'RequestForm-filenamesWrapper--hidden'
);
}
}

updateCharacterCounter() {
Expand Down
1 change: 1 addition & 0 deletions app/controllers/requests_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ def new
def edit; end

def update
@request.files.purge_later if @request.files.attached? && request_params[:files].blank?
if @request.update(request_params)
if @request.planned?
redirect_to requests_path(filter: :planned), flash: {
Expand Down
4 changes: 2 additions & 2 deletions spec/system/requests/sending_images_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
expect(message).to eq 'Please fill out this field.'
expect(page).to have_current_path(new_request_path, ignore_query: true)

# with no text, with file
# With no text, with file
visit new_request_path(as: user)

fill_in 'Titel', with: 'Message with files, no text'
Expand All @@ -37,6 +37,7 @@
find_field('request_files', visible: :all).attach_file(image_file)

click_button 'Frage an die Community senden'

expect(page).to have_content('Message with files, no text')
expect(page).to have_current_path(request_path(Request.first))

Expand Down Expand Up @@ -73,7 +74,6 @@
expect(page).to have_css(
'button.RequestForm-removeListItemButton[data-action="request-form#removeImage"][data-request-form-image-index-value="0"]'
)

click_button 'x'

expect(page).not_to have_content('Angehängte Bilder')
Expand Down

0 comments on commit ec2d573

Please sign in to comment.