Skip to content

Commit

Permalink
feat(*): add errorhandling and skeleton loading
Browse files Browse the repository at this point in the history
  • Loading branch information
velrest committed Sep 1, 2020
1 parent 3b861f2 commit d0c8252
Show file tree
Hide file tree
Showing 33 changed files with 806 additions and 126 deletions.
20 changes: 12 additions & 8 deletions addon/components/category-nav.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
class="uk-padding-small uk-margin-top uk-width-1 uk-text-bold uk-border-horizontal"
>
<div class="uk-text-center">
Kategorien
{{t "alexandria.category-nav.categories"}}
</div>
</div>
<ul class="uk-nav uk-width-medium uk-margin-top">
Expand All @@ -16,13 +16,17 @@
}}
@selected={{eq @selected undefined}}
/>
{{#each this.categories as |category|}}
<CategoryNav::Category
@category={{category}}
@selected={{eq category.id @selected}}
/>
{{#if this.fetchCategories.isRunning}}
{{#each (range 0 5)}}
<CategoryNav::Category::Skeleton />
{{/each}}
{{else}}
No categories
{{/each}}
{{#each this.categories as |category|}}
<CategoryNav::Category
@category={{category}}
@selected={{eq category.id @selected}}
/>
{{/each}}
{{/if}}
</ul>
</nav>
10 changes: 9 additions & 1 deletion addon/components/category-nav.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,18 @@ import { lastValue, task } from "ember-concurrency-decorators";

export default class CategoryNavComponent extends Component {
@service store;
@service notification;
@service intl;

@lastValue("fetchCategories") categories;
@task
*fetchCategories() {
return yield this.store.findAll("category");
try {
return yield this.store.findAll("category");
} catch (error) {
this.notification.danger(
this.intl.t("alexandria.errors.fetch-categories")
);
}
}
}
16 changes: 16 additions & 0 deletions addon/components/category-nav/category/skeleton.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<li class="category-nav--category">
<a href="#" disabled>
<div class="uk-flex uk-flex-middle">
<div>
<FaIcon
@icon="folder"
@size="2x"
class="uk-margin-right"
{{set-style color="#999"}}
/>
</div>
<span class="skeleton-text">
</span>
</div>
</a>
</li>
59 changes: 50 additions & 9 deletions addon/components/document-card.hbs
Original file line number Diff line number Diff line change
@@ -1,18 +1,59 @@
<div
class="document-card uk-card uk-card-body uk-border-rounded-circular uk-padding-remove"
>
<div class="uk-card-media-top uk-text-center uk-border-bottom uk-padding">
<FaIcon
@icon="file-alt"
@prefix="far"
@size="7x"
{{set-style color=@document.category.color}}
/>
<div class="uk-card-media-top uk-text-center uk-border-bottom">
{{#if this.showLoadingState}}
<div class="uk-padding">
<span uk-spinner="ratio: 4.5" class="uk-position-relative"></span>
<FaIcon
@icon="file-download"
@prefix="far"
@size="7x"
{{set-style color=@document.category.color}}
/>
</div>
{{else}}
{{#if @document.thumbnail}}
<img
data-src={{@document.thumbnail}}
width="200"
height="170"
uk-img
alt={{@document.title}}
/>
{{else}}
<div class="uk-padding">
<FaIcon
@icon="file-alt"
@prefix="far"
@size="7x"
{{set-style color=@document.category.color}}
/>
</div>
{{/if}}
{{/if}}
</div>
<div
class="uk-card-body uk-padding-small uk-flex uk-flex-between document-name"
>
{{@document.name}}
<FaIcon @icon="ellipsis-v" />
<span
class="uk-text-truncate"
uk-tooltip="title: {{@document.title}}; pos: bottom; delay: 300;"
>
{{@document.title}}
</span>
<span>
<FaIcon @icon="ellipsis-v" />
</span>
<Drop @width="uk-width-small" @position="left-center" as |Item|>
<Item {{on "click" (perform this.download)}}>
<FaIcon @icon="file-download" />
{{t "alexandria.download"}}
</Item>
<Item {{on "click" (perform this.delete)}}>
<FaIcon @icon="trash-alt" @prefix="far" />
{{t "alexandria.delete"}}
</Item>
</Drop>
</div>
</div>
40 changes: 40 additions & 0 deletions addon/components/document-card.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import Component from "@glimmer/component";
import { task } from "ember-concurrency-decorators";
import { inject as service } from "@ember/service";
import { saveAs } from "file-saver";

export default class DocumentCardComponent extends Component {
@service notification;
@service intl;

get showLoadingState() {
return this.download.isRunning || this.delete.isRunning;
}

@task *download() {
try {
// There is a known issue with file-saver and urls. The filename passed as the second argument is ignored.
// https://github.com/eligrey/FileSaver.js/issues/670
yield saveAs(
this.args.document.files.filter((file) => file.type === "original")[0]
.downloadUrl,
this.args.document.title
);
} catch (error) {
this.notification.danger(this.intl.t("alexandria.errors.save-file"));
}
}

@task *delete() {
try {
yield this.args.document.destroyRecord();
this.notification.success(
this.intl.t("alexandria.success.delete-document")
);
} catch (error) {
this.notification.danger(
this.intl.t("alexandria.errors.delete-document")
);
}
}
}
23 changes: 23 additions & 0 deletions addon/components/document-card/skeleton.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<div
class="document-card uk-card uk-card-body uk-border-rounded-circular uk-padding-remove"
>
<div class="uk-card-media-top uk-text-center uk-border-bottom">
<img
width="200"
height="180"
uk-img
class="skeleton-img"
alt={{t "alexandria.loading"}}
/>
</div>
<div
class="uk-card-body uk-padding-small uk-flex uk-flex-between document-name"
>
<span class="skeleton-text">
</span>

<span {{set-style color="#F4F4F4"}}>
<FaIcon @icon="ellipsis-v" />
</span>
</div>
</div>
38 changes: 30 additions & 8 deletions addon/components/document-grid.hbs
Original file line number Diff line number Diff line change
@@ -1,16 +1,38 @@
<div class="uk-flex uk-flex-middle uk-padding-small">
<DocumentUploadButton
@category={{@filters.category}}
@afterUpload={{perform this.fetchDocuments}}
/>
<TagFilter
@filters={{hash category=@filters.category}}
@selectedTags={{@filters.tags}}
class="uk-margin-left"
/>
</div>

<div
class="uk-padding-small uk-overflow-auto uk-flex-center"
class="uk-padding uk-overflow-auto uk-flex-center"
uk-grid
...attributes
{{did-insert (perform this.fetchDocuments)}}
{{did-update (perform this.fetchDocuments) @filters}}
>
{{#each this.documents as |document|}}
{{! This wrapper div is needed for the uk-grid spacing between elements }}
<div>
<DocumentCard @document={{document}} />
</div>
{{#if this.fetchDocuments.isRunning}}
{{#each (range 0 10)}}
<div>
<DocumentCard::Skeleton />
</div>
{{/each}}
{{else}}
No documents
{{/each}}
{{#each this.documents as |document|}}
{{! This wrapper div is needed for the uk-grid spacing between elements }}
<div>
<DocumentCard @document={{document}} />
</div>
{{else}}
<div>
<EmptyIcon />
</div>
{{/each}}
{{/if}}
</div>
4 changes: 3 additions & 1 deletion addon/components/document-grid.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ import { lastValue, task } from "ember-concurrency-decorators";
export default class DocumentGridComponent extends Component {
@service store;

loadingElementsAmount = 10;

@lastValue("fetchDocuments") documents;
@task
*fetchDocuments() {
return yield this.store.query("document", {
include: "category",
include: "category,files",
filter: { ...this.args.filters },
});
}
Expand Down
45 changes: 45 additions & 0 deletions addon/components/document-upload-button.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<div
class="uk-height-1-1"
uk-form-custom
...attributes
{{did-insert (perform this.fetchCategories)}}
>
<UkButton
@color="primary"
@size="small"
class="uk-height-1-1"
tabindex="-1"
@loading={{this.upload.isRunning}}
>
{{t "alexandria.upload-file"}}
</UkButton>

{{#if @category}}
<input
type="file"
multiple
{{on "change" (perform this.upload @category)}}
/>
{{else}}
<Drop @width="uk-with-medium" as |Item|>
{{#each this.categories as |category|}}
<Item uk-form-custom>
<input
type="file"
multiple
{{on "change" (perform this.upload category)}}
/>
<FaIcon
@icon="folder"
@size="2x"
class="uk-margin-small-right"
{{set-style color=category.color}}
/>
{{category.name}}
</Item>
{{else}}
{{t "alexandria.document-upload-button.no-categories"}}
{{/each}}
</Drop>
{{/if}}
</div>
68 changes: 68 additions & 0 deletions addon/components/document-upload-button.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import Component from "@glimmer/component";
import { inject as service } from "@ember/service";
import { task, lastValue } from "ember-concurrency-decorators";
import fetch from "fetch";

export default class DocumentUploadButtonComponent extends Component {
@service notification;
@service intl;
@service store;

@lastValue("fetchCategories") categories;

@task *upload(category, { target: { files = [] } = {} }) {
try {
if (!category.id) {
category = yield this.store.peekRecord("category", category) ||
this.store.findRecord("category", category);
}

yield Promise.all(
Array.from(files).map(async (file) => {
const documentModel = this.store.createRecord("document", {
category,
});
documentModel.title = file.name;
await documentModel.save();

const fileModel = this.store.createRecord("file", {
name: file.name,
type: "original",
document: documentModel,
});
await fileModel.save();

const response = await fetch(fileModel.uploadUrl, {
method: "put",
body: file,
});

console.error("Needs error handling here", response);
})
);
this.notification.success(
this.intl.t("alexandria.success.upload-document", {
count: files.length,
})
);
this.args.afterUpload();
} catch (error) {
this.notification.danger(
this.intl.t("alexandria.errors.upload-document", {
count: files.length,
})
);
}
}

@task *fetchCategories() {
try {
return yield this.store.peekAll("category") ||
this.store.findAll("category");
} catch (e) {
this.notification.danger(
this.intl.t("alexandria.errors.fetch-categories")
);
}
}
}
10 changes: 10 additions & 0 deletions addon/components/drop.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<div
uk-drop="mode: click; pos: {{if @position @position "bottom-left"}}; offset: 5;"
class="{{@width}} drop"
>
<div
class="uk-corner-rounded uk-background-default uk-box-shadow-large uk-flex uk-flex-column uk-overflow-hidden uk-border"
>
{{yield (component "drop/item")}}
</div>
</div>
Loading

0 comments on commit d0c8252

Please sign in to comment.