Skip to content

Commit

Permalink
💄 [#1817] Added max file-size check for selected documents
Browse files Browse the repository at this point in the history
  • Loading branch information
jiromaykin committed Nov 30, 2023
1 parent 8905450 commit 845e6d9
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 31 deletions.
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
{% load i18n button_tags card_tags form_tags icon_tags %}
{% load i18n solo_tags button_tags card_tags form_tags icon_tags %}

{% get_solo 'openzaak.OpenZaakConfig' as openzaak_config %}

<div class="form__control file-input">
{% render_card direction="vertical" %}
{% icon icon="upload" icon_position="before" outlined=True %}
<input class="file-input__input" id="{{ field.auto_id }}" name="file" type="file"{% if field.field.required %} required{% endif %}{% if multiple %} multiple{% endif %}>
<input class="file-input__input" id="{{ field.auto_id }}" name="file" type="file"{% if field.field.required %} required{% endif %}{% if multiple %} multiple{% endif %} data-max-size="{{ openzaak_config.max_upload_size }}">
<label class="button button--primary" for="{{ field.auto_id }}">
{% if multiple %}{% trans 'Sleep of selecteer bestanden' %}{% else %}{% trans 'Sleep of selecteer bestand' %}{% endif %}
</label>
{% endrender_card %}

{% if field.help_text %}<p class="p p--muted p--small">{{ field.help_text }}</p>{% endif %}
{% if field.help_text %}<p class="p p--small p--upload-info">{{ field.help_text }}</p>{% endif %}
{% if field.errors %}{% errors errors=field.errors %}{% endif %}

<div class="file-list" aria-live="polite">
Expand Down
92 changes: 65 additions & 27 deletions src/open_inwoner/js/components/form/FileInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ export class FileInput extends Component {
/** @type {string} Use this as selector to instantiate the file input. */
static selector = '.file-input'

/**
* Get configured maximum filesize from 'data-max-size' and use in node.
* @returns {string} Maximum file size.
*/
getLimit() {
return this.getInput().dataset.maxSize
}

/**
* Returns the card (drop zone) associated with the file input.
* @return {HTMLDivElement}
Expand All @@ -17,7 +25,7 @@ export class FileInput extends Component {

/**
* Return the input associated with the file input.
* @return HTMLInputElement
* @return {HTMLInputElement}
*/
getInput() {
return this.node.querySelector(`${FileInput.selector}__input`)
Expand All @@ -33,12 +41,20 @@ export class FileInput extends Component {

/**
* Return the element associated with the file list.
* @return {HTMLUListElement}
* @return {HTMLUListElement} File list element.
*/
getFilesList() {
return this.node.querySelector(`${FileInput.selector} .file-list__list`)
}

/**
* Returns the element associated with the help section.
* @return {HTMLDivElement} Help section element.
*/
getUploadHelpElement() {
return document.querySelector('.p--upload-help')
}

/**
* Binds events to callbacks.
* Callbacks should trigger `setState` which in turn triggers `render`.
Expand Down Expand Up @@ -76,7 +92,7 @@ export class FileInput extends Component {

/**
* Gets called when files are dropped on the card (drop zone).
* @param {DragEvent} e
* @param {DragEvent} e - The drag event.
*/
onDrop(e) {
e.preventDefault()
Expand All @@ -91,12 +107,13 @@ export class FileInput extends Component {
/**
* Gets called when dragging starts on the card (drop zone).
*/
onDragEnter(e) {
onDragEnter() {
this.node.classList.add('file-input--drag-active')
}

/**
* Gets called when dragging ends on the card (drop zone).
* @param {Event} e - The drag leave event.
*/
onDragLeave(e) {
if (e.target !== this.getCard()) {
Expand All @@ -106,9 +123,8 @@ export class FileInput extends Component {
}

/**
* Gets called when click event is received on the files list, it originates from a delete button, handle the deletion
* accordingly.
* @param {PointerEvent} e
* Gets called when click event is received on the files list, it originates from a delete button, handle the deletion accordingly.
* @param {PointerEvent} e - The click event.
*/
onClick(e) {
e.preventDefault()
Expand Down Expand Up @@ -137,22 +153,22 @@ export class FileInput extends Component {

/**
* Generic no op (no operation) event handler. Calls `preventDefault()` on given event.
* @param {Event} e
* @param {Event} e - The event.
*/
noop(e) {
e.preventDefault()
}

/**
* Adds files in dataTransfer to input, only the first item is added if not `[multiple]`.
* @param {File[]} files
* @param {File[]} files - Array of files to add.
*/
addFiles(files) {
const input = this.getInput()
const dataTransfer = new DataTransfer()
const _files = input.multiple ? [...files] : [files[0]]

_files.filter((v) => v).forEach((file) => dataTransfer.items.add(file))
_files.filter(Boolean).forEach((file) => dataTransfer.items.add(file))
input.files = dataTransfer.files
}

Expand All @@ -166,8 +182,7 @@ export class FileInput extends Component {
const filesSection = this.getFilesSection()

// Only show files section when files are selected.
filesSection.setAttribute('hidden', true)
files.length && filesSection.removeAttribute('hidden')
filesSection.toggleAttribute('hidden', !files.length)

// Populate the file list.
const html = [...files].map((file) => this.renderFileHTML(file)).join('')
Expand All @@ -176,35 +191,58 @@ export class FileInput extends Component {

/**
* Returns the HTML to be used for a file.
* @param {File} file
* @return {string}
* @param {File} file - The file to render HTML for.
* @return {string} HTML for the file.
*/
renderFileHTML(file) {
const { name, size, type } = file
const ext = name.split('.').pop().toUpperCase()
const sizeMB = (size / (1024 * 1024)).toFixed(2)
const labelDelete = this.getFilesList().dataset.labelDelete || 'Delete'

return `
// Only show errors notification if data-max-file-size is exceeded + add error class to file-list
const maxMegabytes = this.getLimit()

const htmlStart = `
<li class="file-list__list-item">
<aside class="file">
<div class="file__container">
<div class="file__file">
<p class="file__symbol">
<div class="file__container">
${
sizeMB > maxMegabytes
? '<div class="file__file error">'
: '<div class="file__file">'
}
<p class="file__symbol">
<span aria-hidden="true" class="material-icons-outlined">${
type.match('image') ? 'image' : 'description'
}</span>
</p>
<p class="p file__data">
<span class="file__name">${name} (${ext}, ${sizeMB}MB)</span>
</p>
<a class="link link--primary" href="#" role="button" aria-label="${labelDelete}">
<span aria-hidden="true" class="material-icons-outlined">delete</span>
</a>
</p>
<p class="p file__data">
<span class="file__name">${name} (${ext}, ${sizeMB}MB)</span>
</p>
<a class="link link--primary" href="#" role="button" aria-label="${labelDelete}">
<span aria-hidden="true" class="material-icons-outlined">delete</span>
</a>
</div>
</div>
</aside>
</li>
`
</li>`

if (sizeMB > maxMegabytes) {
const uploadHelpElement = this.getUploadHelpElement()
if (uploadHelpElement) {
uploadHelpElement.classList.add('error')
}

return (
htmlStart +
`<p class="p p--upload-error error">
<span aria-hidden="true" class="material-icons-outlined">warning_amber</span>
Dit bestand is te groot
</p>`
)
}

return htmlStart
}
}
15 changes: 15 additions & 0 deletions src/open_inwoner/scss/components/Cases/CaseDetail.scss
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
}

#document-upload {
color: var(--color-gray-dark);
gap: 0;
padding: 0 0 var(--row-height-giant) 0;

Expand Down Expand Up @@ -44,6 +45,20 @@
}
}

.p--upload-info {
text-align: center;

&.p--upload-help {
display: none;

&.error {
color: var(--color-gray-dark);
display: block;
margin-top: var(--spacing-medium);
}
}
}

/// Make required asterisk visible for this component
.label__label--required {
color: var(--color-red);
Expand Down
2 changes: 1 addition & 1 deletion src/open_inwoner/scss/components/File/FileList.scss
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
}

&__list-item {
margin-bottom: var(--spacing-large);
margin-bottom: var(--spacing-medium);

&:last-child {
margin-bottom: 0;
Expand Down
30 changes: 30 additions & 0 deletions src/open_inwoner/scss/components/Form/FileInput.scss
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,42 @@
text-align: center;
}

.p--upload-error {
color: var(--color-red-notification);
display: flex;
align-items: normal;
gap: var(--spacing-small);
justify-content: flex-start;

[class*='icon'] {
color: var(--color-red-notification);
font-size: var(--font-size-body-large);
}
}

.h4 {
margin-top: var(--spacing-large);
margin-bottom: calc(0.5 * var(--spacing-large));
}

& .file-list {
margin-bottom: var(--spacing-large) !important;

// upload-error styles
.file__file.error {
border-color: var(--color-red-notification);

.p {
color: var(--color-gray-90);
}

[class*='icon'] {
color: var(--color-gray-light);
}

.link [class*='icon'] {
color: var(--color-red-notification);
}
}
}
}
1 change: 1 addition & 0 deletions src/open_inwoner/templates/pages/cases/document_form.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@
{% input form.type no_label=True no_help=True class="label input" id="id_type" extra_classes="file-type__select" %}
{% file_input form.files %}
{% form_actions primary_text=_("Upload documenten") primary_icon="arrow_forward" enctype="multipart/form-data" %}
<p class="p--upload-error p--small p--upload-info p--upload-help">{% trans "Verwijder eerst bestanden die niet voldoen aan de voorwaarden" %}</p>
{% endrender_form %}

0 comments on commit 845e6d9

Please sign in to comment.