Skip to content

Commit

Permalink
🎨 [#1795] Added skeleton for selected case-documents to be uploaded
Browse files Browse the repository at this point in the history
  • Loading branch information
jiromaykin authored and svenvandescheur committed Nov 17, 2023
1 parent 0af2a12 commit bc2b406
Show file tree
Hide file tree
Showing 10 changed files with 262 additions and 46 deletions.
5 changes: 4 additions & 1 deletion src/open_inwoner/cms/cases/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@

class CaseUploadForm(forms.Form):
title = forms.CharField(
label=_("Titel bestand"), max_length=255, validators=[CharFieldValidator()]
label=_("Titel bestand"),
max_length=255,
# empty_value=_("Titel bestand"),#TypeError: Object of type __proxy__ is not JSON serializable
required=False,
)
type = forms.ModelChoiceField(
ZaakTypeInformatieObjectTypeConfig.objects.none(),
Expand Down
8 changes: 2 additions & 6 deletions src/open_inwoner/cms/cases/tests/test_htmx.py
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,7 @@ def test_cases(self, m):
upload_form = page.locator("#document-upload")
expect(upload_form).to_be_visible()

upload_form.get_by_label(_("Document selecteren")).set_input_files(
upload_form.get_by_label(_("Selecteer bestanden")).set_input_files(
files=[
{
"name": "uploaded_test_file.txt",
Expand All @@ -441,13 +441,9 @@ def test_cases(self, m):
}
],
)
submit_button = upload_form.get_by_role("button", name=_("Document uploaden"))
submit_button = upload_form.get_by_role("button", name=_("Upload documenten"))
expect(submit_button).to_be_visible()

title_input = upload_form.get_by_label(_("Titel bestand"))
expect(title_input).to_be_visible()
title_input.fill("uploaded document")

submit_button.click()

# check for new file
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@
<div class="inputfile-group">
<label class="label">
<span class="input-file">
{{ field|addclass:"inputfile" }}
<p>{% icon icon="upload" icon_position="before" outlined=True %}</p>

<span class="label__label" for="{{ field.auto_id }}">
{% icon icon="cloud_upload" icon_position="before" outlined=True %}
{{ text }}
{{ field|addclass:"inputfile" }}
{# appended HTML #}
{# <input type="file" name="file" class="inputfile" required="" id="id_file" data-max-size="13000">#}

</span>{% if field.field.required %}<span class="label__label--required"> * </span>{% endif %}
<span class="label__label cloud" for="{{ field.auto_id }}">
{{ text }}
</span>
</span>

{% if field.errors %}
Expand Down
2 changes: 1 addition & 1 deletion src/open_inwoner/components/templatetags/form_tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ def file_input(file, text, **kwargs):
Displaying a file upload interface.
Usage:
{% file_input form.field text=_('Document selecteren') %}
{% file_input form.field text=_('Selecteer bestanden') %}
Variables:
+ field: Field | The field that needs to be rendered.
Expand Down
85 changes: 85 additions & 0 deletions src/open_inwoner/js/components/upload-document/file-uploader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// // JavaScript code for handling file selection and removal
// const fileInput = document.getElementById("id_file");
// const fileList = document.getElementById("fileList");
// const maxBytes = Number(fileInput.dataset.maxSize);
// let selectedFiles = [];
//
// fileInput.addEventListener("change", handleFileSelect);
//
// function getFileExtension(fileName) {
// // Split the file name by '.' and get the last part (the file extension)
// const parts = fileName.split(".");
// return parts[parts.length - 1];
// }
//
// function handleFileSelect(event) {
// const files = Array.from(event.target.files);
//
// // Clear the file list container and selectedFiles array
// fileList.innerHTML = "";
// selectedFiles = [];
//
// files.forEach((file) => {
// const fileDiv = document.createElement("div");
// fileDiv.classList.add("file-item");
//
// const fileHTML = `
// <span class="file-material-icon">
// <i class="material-icons assignment"></i>
// </span>
// <span class="file-name">${file.name}</span>
// <span class="file-size">Size: ${file.size}</span>
// <span class="file-extension">Extension: ${getFileExtension(
// file.name
// )}</span>
// <button class="button button--textless button--icon button--icon-after button--transparent button-file-remove" type="button" title="Toegevoegd bestand verwijderen" aria-label="Toegevoegd bestand verwijderen">
// <span class="material-icons"><i class="material-icons auto_delete"></i></span>
// Delete
// </button>
// `;
//
// fileDiv.innerHTML = fileHTML;
//
// if (file.size > maxBytes) {
// fileDiv.classList.add("error-message");
// const fileSizeError = document.createElement("div");
// fileSizeError.textContent = "Dit bestand is te groot";
// fileSizeError.classList.add("error-message");
// fileDiv.querySelector(".file-material-icon").appendChild(fileSizeError);
// }
//
// fileList.appendChild(fileDiv);
// selectedFiles.push(file);
// });
// }
//
// // Use event delegation to handle file removal
// fileList.addEventListener("click", (event) => {
// if (event.target.classList.contains("button-file-remove")) {
// const fileDiv = event.target.parentElement;
// const index = selectedFiles.findIndex(
// (file) => file.name === fileDiv.querySelector(".file-name").textContent
// );
//
// if (index !== -1) {
// selectedFiles.splice(index, 1);
// }
//
// fileDiv.remove();
// fileInput.value = "";
// }
// });
//
// function submitForm() {
// let content = "Selected Files:\n";
// selectedFiles.forEach((file, index) => {
// content += `${index + 1}. ${file.name} - Size: ${file.size} bytes\n`;
// });
// alert(content);
//
// const formData = new FormData();
// selectedFiles.forEach((file, index) => {
// formData.append(`file${index + 1}`, file);
// });
// // Submit formData to the backend using AJAX or form submission
// }
57 changes: 55 additions & 2 deletions src/open_inwoner/js/components/upload-document/show-file-info.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ export class ShowInfo {
this.showData()
}

getFileExtension(fileName) {
const parts = fileName.split('.')
return parts[parts.length - 1]
}

showData() {
// get the closest parent element (the form section element)
const documentUpload = this.fileUploadInput.closest('#form_upload')
Expand All @@ -21,6 +26,13 @@ export class ShowInfo {
const formControlInfo = documentUpload.querySelectorAll(
'.form__control__info'
)
const fileInput = document.getElementById('id_file')
const fileList = document.getElementById('fileList')
const fileDivsContainer =
documentUpload.querySelectorAll('.fieldset--files')
let selectedFiles = []
// read maximum size from backend
const maxBytes = Number(fileInput.dataset.maxSize)

// Convert the file size to a readable format
const formatFileSize = function (bytes) {
Expand All @@ -36,8 +48,8 @@ export class ShowInfo {
elem.classList.add('error')
})

this.fileUploadInput.addEventListener('change', function (e) {
const files = e.target.files
this.fileUploadInput.addEventListener('change', (e) => {
const files = Array.from(e.target.files)

if ((files.length === 0) | (files === null) | (files === undefined)) {
submit_upload.disabled = true
Expand All @@ -52,13 +64,54 @@ export class ShowInfo {
elem.style.display = 'none'
})
} else {
//When files are selected
console.log('More than 1 file is selected.', files)
console.log('This is the data attribute size: ', maxBytes)
submit_upload.disabled = false
validationInfo.classList.remove('error')
closeButton.classList.remove('error')
iconDrive.forEach((elem) => {
elem.classList.remove('error')
})

fileDivsContainer.forEach((file) => {
//add template for selected files
const fileName = files[0].name
const fileExtension = this.getFileExtension(fileName)
const fileDivBig = document.createElement('div')
fileDivBig.classList.add('file-item')

const fileHTML = `
<div class="file__file symbol"><span class="file-material-icon">
<span aria-hidden="true" class="material-icons-outlined ">insert_drive_file</span>
</span></div>
<span class="file-name">name: ${files[0].name}</span>
<span class="file-extension"><span class="file--uppercase">(${fileExtension}</span>, ${formatFileSize(
files[0].size
)})</span>
<button class="button button--textless button--icon button--icon-after button--transparent button-file-remove" type="button" title="Toegevoegd bestand verwijderen" aria-label="Toegevoegd bestand verwijderen">
<span aria-hidden="true" class="material-icons-outlined ">delete</span>
</button>
`

fileDivBig.innerHTML = fileHTML

if (files[0].size > maxBytes) {
console.log('Dit bestand is te groot')
fileDivBig.classList.add('error-message')
const fileSizeError = document.createElement('div')
fileSizeError.textContent = 'Dit bestand is te groot'
fileSizeError.classList.add('error-message')
fileDivBig
.querySelector('.file-material-icon')
.appendChild(fileSizeError)
}

fileList.appendChild(fileDivBig)
selectedFiles.push(file)
})
//end template

// Display info
sizeInfo.textContent = formatFileSize(files[0].size)
nameInfo.textContent = `${files[0].name}`
Expand Down
2 changes: 1 addition & 1 deletion src/open_inwoner/openzaak/tests/test_case_detail.py
Original file line number Diff line number Diff line change
Expand Up @@ -904,7 +904,7 @@ def test_successful_document_upload_flow(self, m):
form.action = reverse(
"cases:case_detail_document_form", kwargs={"object_id": self.zaak["uuid"]}
)
form["title"] = "uploaded file"
# form["title"] = "uploaded file"
form["type"] = zaak_type_iotc.id
form["file"] = Upload("upload.txt", b"data", "text/plain")
form_response = form.submit()
Expand Down
106 changes: 88 additions & 18 deletions src/open_inwoner/scss/components/Form/DocumentUpload.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#document-upload {
gap: var(--spacing-tiny);
max-width: var(--mobile-xs-width);

.button[type='submit']:disabled {
background-color: var(--color-gray) !important;
Expand All @@ -25,12 +24,6 @@
.close {
display: block;
}

.input-file {
.label__label--required {
display: none;
}
}
}

.form__control__info {
Expand All @@ -40,6 +33,86 @@
display: block;
}
}

//Codepen
.upload__selector {
padding: var(--spacing-giant);
border: 1px var(--color-gray) solid;
text-align: center;
}

#fileList {
padding: 0;
}

.file-item {
display: flex;
flex-direction: row;
column-gap: 30px;
background-color: white;
border: 1px solid #d3d3d3;
margin-bottom: 20px;
padding-top: var(--spacing-large);
border-radius: 4px;
box-sizing: border-box;
min-height: 80px;
justify-content: space-between;

[class*='icon'] {
position: static;
transform: none;
}

.file--uppercase {
text-transform: uppercase;
}
}

.file-material-icon {
color: grey;
}

.file-item.error-message {
background-color: LavenderBlush;
color: deeppink;
border: 2px solid red;
margin: 2px;
padding: 9px;
}

.error-message {
background-color: lightpink;
}

.file-item.error-message .file-material-icon {
color: deeppink;
}

.file-name {
display: inline-block;
font-family: var(--font-family-body);
font-size: var(--font-size-body);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 200px;
}

.file-size {
font-style: italic;
min-width: 150px;
}

#id_file {
font-family: 'Verdana', sans-serif;
}
#id_file {
background-color: #9fbddf;
height: 2em;
border: 1px solid #007acc;
border-radius: 6px;
}
//end codepen
}

/// File-input site wide
Expand Down Expand Up @@ -101,19 +174,12 @@ input[type='file']::file-selector-button {
}

.input-file {
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
gap: 7px;
position: relative;
//width: 200px;
display: inline-block;

*[class*='icons'] {
position: absolute;
top: 18px;
left: 12px;
color: orange;
position: static;
color: black;
transform: none;
}

/// Hidden file-input for cases
Expand Down Expand Up @@ -252,4 +318,8 @@ input[type='file']::file-selector-button {
}
}
}

.notifications__errors {
margin: 1.5em var(--spacing-small) 0 0;
}
}
Loading

0 comments on commit bc2b406

Please sign in to comment.