diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f4fc3c2..1f7d7643 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,28 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Release v.1.7.0-beta - 8-10-2021 + +### Added +- Added pagination to own projects page. [#526](https://github.com/DigitalExcellence/dex-frontend/issues/526) +- Back button to add project wizard - [#563](https://github.com/DigitalExcellence/dex-frontend/issues/563) +- Fixed the wizard long description text area to wrap words. - [#562](https://github.com/DigitalExcellence/dex-frontend/issues/562) + +### Changed +- Projects overview not sorting on Likes High > Low [#557](https://github.com/DigitalExcellence/dex-frontend/issues/557) +- Changed project-edit page. Was a separate page, is now a part of te detail-modal [#536](https://github.com/DigitalExcellence/dex-frontend/issues/536) + +### Deprecated + +### Removed + +### Fixed +- Highlight project modal, not dissapearing when clicking out of it.[#569](https://github.com/DigitalExcellence/dex-frontend/issues/569) +- Project filter is not cleared anymore after editing project. [#561](https://github.com/DigitalExcellence/dex-frontend/issues/561) +- Added option to remove a previously uploaded icon to edit page and wizard[#482](https://github.com/DigitalExcellence/dex-frontend/issues/482) + +### Security + ## Release v.1.6.0-beta - 15-9-2021 ### Added diff --git a/angular.json b/angular.json index 6e192984..b6187366 100644 --- a/angular.json +++ b/angular.json @@ -90,8 +90,8 @@ }, { "type": "anyComponentStyle", - "maximumWarning": "6kb", - "maximumError": "10kb" + "maximumWarning": "8kb", + "maximumError": "15kb" } ] }, @@ -193,4 +193,4 @@ "cli": { "analytics": false } -} \ No newline at end of file +} diff --git a/package-lock.json b/package-lock.json index 45acb70e..0652402d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8438,9 +8438,9 @@ } }, "nth-check": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.0.tgz", - "integrity": "sha512-i4sc/Kj8htBrAiH1viZ0TgU8Y5XqCaV/FziYK6TBczxmeKm3AEFWqqF3195yKudrarqy7Zu80Ra5dobFjn9X/Q==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", + "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", "dev": true, "requires": { "boolbase": "^1.0.0" @@ -12583,6 +12583,7 @@ "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "dev": true, + "optional": true, "requires": { "arr-flatten": "^1.1.0", "array-unique": "^0.3.2", @@ -12601,6 +12602,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, + "optional": true, "requires": { "is-extendable": "^0.1.0" } @@ -12633,6 +12635,7 @@ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", "dev": true, + "optional": true, "requires": { "extend-shallow": "^2.0.1", "is-number": "^3.0.0", @@ -12645,6 +12648,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, + "optional": true, "requires": { "is-extendable": "^0.1.0" } @@ -12699,13 +12703,15 @@ "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true + "dev": true, + "optional": true }, "is-number": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, + "optional": true, "requires": { "kind-of": "^3.0.2" }, @@ -12715,6 +12721,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, + "optional": true, "requires": { "is-buffer": "^1.1.5" } @@ -12726,6 +12733,7 @@ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", "dev": true, + "optional": true, "requires": { "arr-diff": "^4.0.0", "array-unique": "^0.3.2", @@ -12759,6 +12767,7 @@ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", "dev": true, + "optional": true, "requires": { "is-number": "^3.0.0", "repeat-string": "^1.6.1" diff --git a/src/app/modules/project/add/main/wizard/wizard.component.html b/src/app/modules/project/add/main/wizard/wizard.component.html index dd060b78..edceee1d 100644 --- a/src/app/modules/project/add/main/wizard/wizard.component.html +++ b/src/app/modules/project/add/main/wizard/wizard.component.html @@ -24,25 +24,25 @@ - + - + - + - + - + - + - + diff --git a/src/app/modules/project/add/main/wizard/wizard.component.ts b/src/app/modules/project/add/main/wizard/wizard.component.ts index 6481103d..f75e82c4 100644 --- a/src/app/modules/project/add/main/wizard/wizard.component.ts +++ b/src/app/modules/project/add/main/wizard/wizard.component.ts @@ -94,6 +94,15 @@ export class WizardComponent implements OnInit { } } + /** + * Method which triggers when the button to the previous page is pressed + */ + public onPreviousStep() { + if (!this.wizardService.isFirstStep()) { + this.wizardService.moveToPreviousStep(); + } + } + /** * Method that will take the built project in the wizard and send it to the backend * @param newProject - the built project diff --git a/src/app/modules/project/add/main/wizard/wizardPages/default/project-call-to-action/project-call-to-action.component.html b/src/app/modules/project/add/main/wizard/wizardPages/default/project-call-to-action/project-call-to-action.component.html index 08b5bb66..a2aca0ba 100644 --- a/src/app/modules/project/add/main/wizard/wizardPages/default/project-call-to-action/project-call-to-action.component.html +++ b/src/app/modules/project/add/main/wizard/wizardPages/default/project-call-to-action/project-call-to-action.component.html @@ -20,5 +20,6 @@

Want to add a call to action?

Get people in action!

+
diff --git a/src/app/modules/project/add/main/wizard/wizardPages/default/project-call-to-action/project-call-to-action.component.scss b/src/app/modules/project/add/main/wizard/wizardPages/default/project-call-to-action/project-call-to-action.component.scss index d45e9473..d9da8f3f 100644 --- a/src/app/modules/project/add/main/wizard/wizardPages/default/project-call-to-action/project-call-to-action.component.scss +++ b/src/app/modules/project/add/main/wizard/wizardPages/default/project-call-to-action/project-call-to-action.component.scss @@ -18,5 +18,10 @@ .bottom-button-wrapper { display: flex; - justify-content: flex-end; + justify-content: center; + + button { + margin-left: 5px; + margin-right: 5px; + } } diff --git a/src/app/modules/project/add/main/wizard/wizardPages/default/project-categories/project-categories.component.html b/src/app/modules/project/add/main/wizard/wizardPages/default/project-categories/project-categories.component.html index 222f3a6c..6531f0bb 100644 --- a/src/app/modules/project/add/main/wizard/wizardPages/default/project-categories/project-categories.component.html +++ b/src/app/modules/project/add/main/wizard/wizardPages/default/project-categories/project-categories.component.html @@ -49,4 +49,10 @@

Categories

- +
+
+ + +
+
+ diff --git a/src/app/modules/project/add/main/wizard/wizardPages/default/project-categories/project-categories.component.scss b/src/app/modules/project/add/main/wizard/wizardPages/default/project-categories/project-categories.component.scss index 0a75dad4..ee65789a 100644 --- a/src/app/modules/project/add/main/wizard/wizardPages/default/project-categories/project-categories.component.scss +++ b/src/app/modules/project/add/main/wizard/wizardPages/default/project-categories/project-categories.component.scss @@ -38,6 +38,13 @@ } } +.buttons { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + #tag { box-shadow: $box-shadow; } diff --git a/src/app/modules/project/add/main/wizard/wizardPages/default/project-collaborators/project-collaborators.component.html b/src/app/modules/project/add/main/wizard/wizardPages/default/project-collaborators/project-collaborators.component.html index 637a4120..0c15234f 100644 --- a/src/app/modules/project/add/main/wizard/wizardPages/default/project-collaborators/project-collaborators.component.html +++ b/src/app/modules/project/add/main/wizard/wizardPages/default/project-collaborators/project-collaborators.component.html @@ -66,6 +66,9 @@

{{step.name}}

- +
+ + +
diff --git a/src/app/modules/project/add/main/wizard/wizardPages/default/project-description/project-description.component.html b/src/app/modules/project/add/main/wizard/wizardPages/default/project-description/project-description.component.html index 38a8026c..751cbccd 100644 --- a/src/app/modules/project/add/main/wizard/wizardPages/default/project-description/project-description.component.html +++ b/src/app/modules/project/add/main/wizard/wizardPages/default/project-description/project-description.component.html @@ -39,6 +39,9 @@

{{step.name}}

describe svg - +
+ + +
diff --git a/src/app/modules/project/add/main/wizard/wizardPages/default/project-description/project-description.component.scss b/src/app/modules/project/add/main/wizard/wizardPages/default/project-description/project-description.component.scss index 8db1b473..9948ee30 100644 --- a/src/app/modules/project/add/main/wizard/wizardPages/default/project-description/project-description.component.scss +++ b/src/app/modules/project/add/main/wizard/wizardPages/default/project-description/project-description.component.scss @@ -65,6 +65,7 @@ .project-long-description { .ql-container { width: 100%; + word-break: break-all; height: 350px; } } diff --git a/src/app/modules/project/add/main/wizard/wizardPages/default/project-icon/project-icon.component.html b/src/app/modules/project/add/main/wizard/wizardPages/default/project-icon/project-icon.component.html index 9a8c932a..6333afcd 100644 --- a/src/app/modules/project/add/main/wizard/wizardPages/default/project-icon/project-icon.component.html +++ b/src/app/modules/project/add/main/wizard/wizardPages/default/project-icon/project-icon.component.html @@ -20,14 +20,23 @@

{{step.name}}

{{step.description}}

- +
- +
+ + +
+
+
Workers svg
- +
+ + +
diff --git a/src/app/modules/project/add/main/wizard/wizardPages/default/project-icon/project-icon.component.scss b/src/app/modules/project/add/main/wizard/wizardPages/default/project-icon/project-icon.component.scss index 9b50c1a0..15bd0689 100644 --- a/src/app/modules/project/add/main/wizard/wizardPages/default/project-icon/project-icon.component.scss +++ b/src/app/modules/project/add/main/wizard/wizardPages/default/project-icon/project-icon.component.scss @@ -20,6 +20,11 @@ display: grid; grid-template-columns: 2fr 1fr; gap: 30px; + + .button-wrapper{ + display: flex; + justify-content: space-around; + } button { &.grey { display: none; @@ -78,6 +83,39 @@ } } + .overlay { + z-index: 2; + height: 100%; + width: 75%; + border-radius: 100%; + position: absolute; + background-color: rgba(0, 0, 0, 0.2); + left: 0; + top: 0; + opacity: 0; + transition: $transition-short; + display: flex; + justify-content: center; + align-items: center; + + em { + cursor: pointer; + color: white; + font-size: 48px; + } + } + @media only screen and (max-width: 600px) { + .overlay { + display: none; + } + } + + &:hover { + .overlay { + opacity: 1; + } + } + img { display: inline-block; z-index: 2; @@ -93,7 +131,7 @@ } } } - + button { margin-top: 30px; } diff --git a/src/app/modules/project/add/main/wizard/wizardPages/default/project-icon/project-icon.component.ts b/src/app/modules/project/add/main/wizard/wizardPages/default/project-icon/project-icon.component.ts index 1e0198af..3b42ce0f 100644 --- a/src/app/modules/project/add/main/wizard/wizardPages/default/project-icon/project-icon.component.ts +++ b/src/app/modules/project/add/main/wizard/wizardPages/default/project-icon/project-icon.component.ts @@ -75,6 +75,13 @@ export class ProjectIconComponent extends WizardStepBaseComponent implements OnI document.querySelector('input').click(); } + /** + * Method that triggers when the delete-overlay is clicked + */ + public deleteIconClicked() { + this.fileUploader.deleteFile(0); + } + /** * Method that determines which preview to use for the project icon */ diff --git a/src/app/modules/project/add/main/wizard/wizardPages/default/project-images/project-images.component.html b/src/app/modules/project/add/main/wizard/wizardPages/default/project-images/project-images.component.html index 5918dffb..7c39f568 100644 --- a/src/app/modules/project/add/main/wizard/wizardPages/default/project-images/project-images.component.html +++ b/src/app/modules/project/add/main/wizard/wizardPages/default/project-images/project-images.component.html @@ -11,6 +11,7 @@

{{ step.name }}

+ +
+ +
name svg diff --git a/src/app/modules/project/add/main/wizard/wizardPages/default/project-name/project-name.component.ts b/src/app/modules/project/add/main/wizard/wizardPages/default/project-name/project-name.component.ts index 9be4831f..4ebb2456 100644 --- a/src/app/modules/project/add/main/wizard/wizardPages/default/project-name/project-name.component.ts +++ b/src/app/modules/project/add/main/wizard/wizardPages/default/project-name/project-name.component.ts @@ -31,6 +31,10 @@ export class ProjectNameComponent extends WizardStepBaseComponent implements OnI * Form fields */ public projectName = new FormControl(''); + /** + * Remembers if project-name is the first step in the current wizard + */ + public isFirstStep: boolean; /** * Hold a copy of the project temporarily to prevent the service from listening to every change */ @@ -41,6 +45,7 @@ export class ProjectNameComponent extends WizardStepBaseComponent implements OnI } public ngOnInit(): void { + this.isFirstStep = this.wizardService.isFirstStep(); this.project = this.wizardService.builtProject; if (this.project.name) { this.projectName.setValue(this.project.name); diff --git a/src/app/modules/project/add/main/wizard/wizardPages/shared-wizard-styles.scss b/src/app/modules/project/add/main/wizard/wizardPages/shared-wizard-styles.scss index a8be669d..0ec3367b 100644 --- a/src/app/modules/project/add/main/wizard/wizardPages/shared-wizard-styles.scss +++ b/src/app/modules/project/add/main/wizard/wizardPages/shared-wizard-styles.scss @@ -62,9 +62,39 @@ p { } } +.form-previous-btn { + min-width: 100px; + width: fit-content; + height: 40px; + border: none; + border-radius: $border-radius; + background-color: $light-mode-grey-primary; + box-shadow: $box-shadow; + color: white; + outline: none; + display: grid; + grid-auto-flow: column; + gap: 10px; + align-items: center; + padding: 0 20px; + + &:hover { + background: $light-mode-grey-secondary; + } + + &.grey { + color: black; + background-color: $light-mode-grey-quaternary; + + &:hover { + background: $light-mode-grey-thertiary; + } + } +} + .inline-input { display: grid; - grid-template-columns: 1fr auto; + grid-template-columns: 1fr auto auto; input { line-height: 3rem; @@ -74,11 +104,11 @@ p { } button { - margin-left: -10px; + margin-left: 10px; @media only screen and (max-width: 500px) { width: fit-content; padding: 0 20px; - margin-left: 0; + margin-left: 4px; min-width: unset; } } diff --git a/src/app/modules/project/add/main/wizard/wizardPages/wizard-step-base/wizard-step-base.component.ts b/src/app/modules/project/add/main/wizard/wizardPages/wizard-step-base/wizard-step-base.component.ts index 9d347aec..99c6b921 100644 --- a/src/app/modules/project/add/main/wizard/wizardPages/wizard-step-base/wizard-step-base.component.ts +++ b/src/app/modules/project/add/main/wizard/wizardPages/wizard-step-base/wizard-step-base.component.ts @@ -26,6 +26,7 @@ export class WizardStepBaseComponent { @Input() step: WizardPage; @Input() isOptional = false; @Output() clickNext = new EventEmitter(); + @Output() clickPrevious = new EventEmitter(); /** * Method which triggers when the button to the next page is pressed @@ -34,4 +35,12 @@ export class WizardStepBaseComponent { this.step.isComplete = true; this.clickNext.emit(); } + + /** + * Method which triggers when the button to the previous page is pressed + */ + public onClickPrevious(): void { + this.step.isComplete = false; + this.clickPrevious.emit(); + } } diff --git a/src/app/modules/project/call-to-actions-edit/call-to-actions-edit.component.html b/src/app/modules/project/call-to-actions-edit/call-to-actions-edit.component.html index 2e69ba1b..e055bdb9 100644 --- a/src/app/modules/project/call-to-actions-edit/call-to-actions-edit.component.html +++ b/src/app/modules/project/call-to-actions-edit/call-to-actions-edit.component.html @@ -23,7 +23,6 @@

-

{{errorMessage}}

+

{{errorMessage}}

diff --git a/src/app/modules/project/call-to-actions-edit/call-to-actions-edit.component.scss b/src/app/modules/project/call-to-actions-edit/call-to-actions-edit.component.scss index 36c7df66..86918c51 100644 --- a/src/app/modules/project/call-to-actions-edit/call-to-actions-edit.component.scss +++ b/src/app/modules/project/call-to-actions-edit/call-to-actions-edit.component.scss @@ -28,6 +28,9 @@ .disabled { opacity: .5; } + .disabled::placeholder{ + color: transparent; +} .container { display: inline-block; @@ -129,3 +132,7 @@ margin: 0 auto; height: fit-content; } + +.error-message{ + color: $accent-color-red-primary; +} diff --git a/src/app/modules/project/details/bottom-drawer/bottom-drawer.component.html b/src/app/modules/project/details/bottom-drawer/bottom-drawer.component.html index f70dbdbb..4f7a8222 100644 --- a/src/app/modules/project/details/bottom-drawer/bottom-drawer.component.html +++ b/src/app/modules/project/details/bottom-drawer/bottom-drawer.component.html @@ -7,6 +7,7 @@ diff --git a/src/app/modules/project/details/bottom-drawer/bottom-drawer.component.ts b/src/app/modules/project/details/bottom-drawer/bottom-drawer.component.ts index 903192cd..be209caa 100644 --- a/src/app/modules/project/details/bottom-drawer/bottom-drawer.component.ts +++ b/src/app/modules/project/details/bottom-drawer/bottom-drawer.component.ts @@ -1,13 +1,12 @@ -import { Project } from '../../../../models/domain/project'; -import { scopes } from '../../../../models/domain/scopes'; -import { User } from '../../../../models/domain/user'; -import { AlertConfig } from '../../../../models/internal/alert-config'; -import { AlertType } from '../../../../models/internal/alert-type'; -import { AlertService } from '../../../../services/alert.service'; -import { AuthService } from '../../../../services/auth.service'; -import { HighlightByProjectIdService } from '../../../../services/highlightid.service'; - -import { Component, Input, OnInit } from '@angular/core'; +import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import { Project } from 'src/app/models/domain/project'; +import { scopes } from 'src/app/models/domain/scopes'; +import { User } from 'src/app/models/domain/user'; +import { AlertConfig } from 'src/app/models/internal/alert-config'; +import { AlertType } from 'src/app/models/internal/alert-type'; +import { AlertService } from 'src/app/services/alert.service'; +import { AuthService } from 'src/app/services/auth.service'; +import { HighlightByProjectIdService } from 'src/app/services/highlightid.service'; @Component({ selector: 'app-bottom-drawer', @@ -17,6 +16,8 @@ import { Component, Input, OnInit } from '@angular/core'; export class BottomDrawerComponent implements OnInit { @Input() project: Project; @Input() activeTab: string; + @Output() editMode = new EventEmitter(); + public currentUser: User; public isProjectHighlighted = false; @@ -112,4 +113,11 @@ export class BottomDrawerComponent implements OnInit { } this.displayEmbedButton = this.project.user.id === this.currentUser.id; } + + /** + * Method to handle commmunication about clicked-edit button + */ + public onEditButtonClicked(event: boolean) { + this.editMode.emit(event); + } } diff --git a/src/app/modules/project/details/bottom-drawer/settings-dropdown/settings-dropdown.component.html b/src/app/modules/project/details/bottom-drawer/settings-dropdown/settings-dropdown.component.html index 0f69d77b..65e1ada2 100644 --- a/src/app/modules/project/details/bottom-drawer/settings-dropdown/settings-dropdown.component.html +++ b/src/app/modules/project/details/bottom-drawer/settings-dropdown/settings-dropdown.component.html @@ -5,7 +5,7 @@ Highlight settings
- Edit project diff --git a/src/app/modules/project/details/bottom-drawer/settings-dropdown/settings-dropdown.component.ts b/src/app/modules/project/details/bottom-drawer/settings-dropdown/settings-dropdown.component.ts index aa6574dc..994ab4e8 100644 --- a/src/app/modules/project/details/bottom-drawer/settings-dropdown/settings-dropdown.component.ts +++ b/src/app/modules/project/details/bottom-drawer/settings-dropdown/settings-dropdown.component.ts @@ -1,20 +1,19 @@ -import { Highlight } from '../../../../../models/domain/highlight'; -import { scopes } from '../../../../../models/domain/scopes'; -import { User } from '../../../../../models/domain/user'; -import { AlertConfig } from '../../../../../models/internal/alert-config'; -import { HighlightAdd } from '../../../../../models/resources/highlight-add'; -import { HighlightUpdate } from '../../../../../models/resources/highlight-update'; -import { HighlightsModalComponent } from '../../../highlights-modal/highlights-modal.component'; -import { HighlightFormResult, ModalHighlightFormComponent } from '../../../modal-highlight-form/modal-highlight-form.component'; - import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { Router } from '@angular/router'; import { BsModalService, ModalOptions } from 'ngx-bootstrap/modal'; import { EMPTY } from 'rxjs'; import { switchMap } from 'rxjs/operators'; import { ModalDeleteGenericComponent } from 'src/app/components/modals/modal-delete-generic/modal-delete-generic.component'; +import { Highlight } from 'src/app/models/domain/highlight'; import { Project } from 'src/app/models/domain/project'; +import { scopes } from 'src/app/models/domain/scopes'; +import { User } from 'src/app/models/domain/user'; +import { AlertConfig } from 'src/app/models/internal/alert-config'; import { AlertType } from 'src/app/models/internal/alert-type'; +import { HighlightAdd } from 'src/app/models/resources/highlight-add'; +import { HighlightUpdate } from 'src/app/models/resources/highlight-update'; +import { HighlightsModalComponent } from 'src/app/modules/project/highlights-modal/highlights-modal.component'; +import { HighlightFormResult, ModalHighlightFormComponent } from 'src/app/modules/project/modal-highlight-form/modal-highlight-form.component'; import { AlertService } from 'src/app/services/alert.service'; import { AuthService } from 'src/app/services/auth.service'; import { HighlightService } from 'src/app/services/highlight.service'; @@ -30,6 +29,7 @@ export class SettingsDropdownComponent implements OnInit { @Input() project: Project; @Input() currentUser: User; @Output() projectHighlighted = new EventEmitter(); + @Output() editButtonClicked = new EventEmitter(); public displayEditButton = false; public displayDeleteProjectButton = false; @@ -258,4 +258,12 @@ export class SettingsDropdownComponent implements OnInit { this.onClickHighlightButton(true); }); } + + /* + * method to handle the edit-bottn being clicked + */ + public onEditButtonClicked() { + this.editButtonClicked.emit(true); + } + } diff --git a/src/app/modules/project/details/details.component.html b/src/app/modules/project/details/details.component.html index 3890e574..b407a199 100644 --- a/src/app/modules/project/details/details.component.html +++ b/src/app/modules/project/details/details.component.html @@ -25,28 +25,40 @@

-
- - - project-image - - -
- - -
- + +
+ + + project-image + + +
+ + +
+ +
-
+ + + + + +
diff --git a/src/app/modules/project/details/details.component.scss b/src/app/modules/project/details/details.component.scss index b0522edc..776b9809 100644 --- a/src/app/modules/project/details/details.component.scss +++ b/src/app/modules/project/details/details.component.scss @@ -39,6 +39,9 @@ flex-direction: column; width: 800px; max-width: 100%; + @media only screen and (max-width: 600px) { + padding: 45px + } } } diff --git a/src/app/modules/project/details/details.component.ts b/src/app/modules/project/details/details.component.ts index b63b2bd9..f28b5e2c 100644 --- a/src/app/modules/project/details/details.component.ts +++ b/src/app/modules/project/details/details.component.ts @@ -69,6 +69,11 @@ export class DetailsComponent implements OnInit { */ public animationTriggered = false; + /** + * Boolean to trigger showing the edit-mode + */ + public editModeActivated = false; + constructor( private projectService: ProjectService, private authService: AuthService, @@ -125,6 +130,10 @@ export class DetailsComponent implements OnInit { return this.fileRetrieverService.getIconUrl(file); } + public toggleEditMode(state: boolean) { + this.editModeActivated = state; + } + /** * This method will hide the active modal and remove the * according class. @@ -133,4 +142,13 @@ export class DetailsComponent implements OnInit { this.modalService.hide(1); document.getElementsByTagName('body')[0].classList.remove('modal-open'); } + + /** + * This method reloads the project detail page after edits have been made + * And sends the updated project Id to the projectservice for updating the overview + */ + updateProject(updatedProject: Project) { + this.projectService.projectUpdated$.emit(updatedProject.id); + this.ngOnInit(); + } } diff --git a/src/app/modules/project/details/edit/edit.component.html b/src/app/modules/project/details/edit/edit.component.html new file mode 100644 index 00000000..dea76bb2 --- /dev/null +++ b/src/app/modules/project/details/edit/edit.component.html @@ -0,0 +1,186 @@ + +
+
+
+

+

+ +
+ Code project +
+ + + +
+
+ +
+ +
+
+
+

Short description

+ +

Describe your project in one sentence or 170 characters.

+
+
+

Project Link

+ +
+
+

Categories

+ +
+
+
+
+ + +
+
+ + +
+
+ +
+
+
+

Collaborators

+
+ +
+ + +
+ +
+

+ {{collaborator?.fullName}}

+
+

-

+
+

{{collaborator?.role}}

+
+ +
+ +
+
+
+ + +
+
+
+

Collaborator full name

+ +
+
+
+
+

Collaborator role

+ +

e.g.: developer, designer, etc...

+
+
+ +
+ +
+
+ +
+ +
+

Select the type of call to action button you want for your project.

+ + +
+ +
+
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+ + +
+
+
+
+ +
+ +
+ + +
+ +
\ No newline at end of file diff --git a/src/app/modules/project/details/edit/edit.component.scss b/src/app/modules/project/details/edit/edit.component.scss new file mode 100644 index 00000000..fe15e04d --- /dev/null +++ b/src/app/modules/project/details/edit/edit.component.scss @@ -0,0 +1,433 @@ +/* + * + * Digital Excellence Copyright (C) 2020 Brend Smits + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Lesser General Public License for more details. + * + * You can find a copy of the GNU Lesser General Public License + * along with this program, in the LICENSE.md file in the root project directory. + * If not, see https://www.gnu.org/licenses/lgpl-3.0.txt + * + */ +@import "assets/styles/variables"; +@import "../summary/summary.component.scss"; +@import "../bottom-drawer/bottom-drawer.component.scss"; + +#edit-modal-content { + padding: 45px 60px; + width: 800px; + max-width: 100%; + @media only screen and (max-width: 600px) { + padding: 45px; + } + + #title-wrapper { + gap: 5px 25px; + + .project-title { + margin: 0; + display: block; + display: -webkit-box; + max-width: 100%; + max-height: 74px; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; + text-overflow: ellipsis; + } + + .circle { + position: relative; + + .overlay { + z-index: 2; + height: 100%; + width: 100%; + position: absolute; + background-color: rgba(0, 0, 0, 0.2); + left: 0; + top: 0; + opacity: 0; + transition: $transition-short; + display: flex; + justify-content: center; + align-items: center; + + em { + cursor: pointer; + color: white; + font-size: 24px; + } + } + + &:hover { + .overlay { + opacity: 1; + } + } + } + .icon-remove-btn { + grid-column: 2; + justify-items: center; + button { + border: none; + border-radius: 5px; + margin: 0; + width: 100%; + color: $white; + background-color: $accent-color-red-primary; + } + @media only screen and (max-width: 600px) { + grid-column: 1; + grid-row: 2; + } + } + } + + #specs-wrapper { + display: flex; + flex-direction: column; + gap: 12px; + + .title { + font-size: 0.9em; + } + + .short-desc-input { + width: 100%; + } + .form-footnote { + margin-left: 10px; + font-size: 0.9em; + } + + .project-categories { + display: flex; + flex-wrap: wrap; + margin-bottom: 10px; + + .category { + text-decoration: none; + border-radius: 999px; + background-color: $light-mode-grey-thertiary; + color: $black; + padding: 3px 20px; + box-shadow: rgba(0, 0, 0, 0.15) 0 3px 5px; + margin: 5px 5px 5px 0; + font-size: 12px; + + &.selected { + background: $accent-color-red-primary; + color: $white; + } + } + } + } + + .bottom { + .hidden { + display: none; + } + + .add-collaborator-col { + display: flex; + justify-content: flex-end; + align-self: center; + + .add-collaborator-button { + margin: 0; + align-self: flex-end; + } + + button { + background: $accent-color-red-primary; + border-radius: 40px; + width: 40px; + height: 40px; + border: none; + font-size: 14px; + font-weight: 800; + } + } + + @media only screen and (max-width: 800px) { + .add-collaborator { + grid-template-columns: 1fr; + .add-collaborator-item { + margin: 5px 0; + } + .add-collaborator-item, + .add-collaborator-col { + flex: 0 0 100%; + max-width: 100%; + } + } + } + + .collaborator-overview { + .collaborator-item { + display: flex; + align-items: center; + margin-bottom: 10px; + padding-top: 5px; + padding-bottom: 5px; + + strong { + margin-right: 5px; + margin-left: 10px; + } + + .collaborator-text-container { + display: flex; + justify-content: flex-start; + } + .collaborator-text-container .dash { + margin-left: 5px; + margin-right: 5px; + } + .collaborator-text-container div { + max-width: 50%; + } + .collaborator-text.font-weight-bold { + margin-left: 10px; + } + + .collaborator-text { + align-self: center; + margin: 0; + max-width: 100%; + + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + } + } + + button { + border-radius: 20px; + width: 20px; + height: 20px; + padding: 0; + font-size: 12px; + display: flex; + align-items: center; + justify-content: center; + background-color: $accent-color-red-primary; + } + + @media only screen and (max-width: 800px) { + grid-template-columns: 1fr; + .collaborator-item { + flex: 0 0 100%; + max-width: 100%; + } + } + } + + .project-images { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 30px; + + button { + background-color: $accent-color-red-primary; + color: $white; + border: none; + padding: 6px 16px; + border-radius: 3px; + + &.grey { + display: none; + } + } + + @media only screen and (max-width: 800px) { + grid-template-columns: 1fr; + .project-image-picker { + display: none; + } + button { + &.grey { + display: block; + } + } + img { + display: none; + } + } + + .project-image-picker { + min-width: 300px; + margin-bottom: 30px; + } + + .left { + display: flex; + flex-direction: column; + align-items: center; + justify-content: space-between; + + .file-preview { + display: grid; + grid-template-columns: 1fr 1fr 1fr; + gap: 15px; + max-width: 100%; + width: 100%; + position: relative; + + .preview { + position: relative; + border-radius: $border-radius; + width: 100% !important; + overflow: hidden; + background-size: cover; + background-position: center; + background-color: $light-mode-grey-quaternary; + + border: 2px solid $light-mode-grey-thertiary; + + &:first-child { + grid-column: span 3; + + .overlay { + em { + font-size: 35px; + } + } + } + + @media only screen and (max-width: 600px) { + width: 95%; + } + + &:after { + content: ""; + display: block; + padding-bottom: calc(55% + 10px); + } + + .overlay { + z-index: 2; + height: 100%; + width: 100%; + position: absolute; + background-color: rgba(0, 0, 0, 0.2); + left: 0; + top: 0; + opacity: 0; + transition: $transition-short; + display: flex; + justify-content: center; + align-items: center; + + em { + cursor: pointer; + color: white; + font-size: 24px; + } + } + + &:hover { + .overlay { + opacity: 1; + } + } + } + + img { + display: inline-block; + z-index: 2; + + &.workers { + position: absolute; + right: -5px; + bottom: -3px; + } + + @media only screen and (max-width: 600px) { + display: none; + } + } + } + + .buttons { + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: 15px; + margin-top: 30px; + } + } + } + } + + #bottom-button-wrapper { + display: flex; + justify-content: flex-end; + + .btn-success, + .btn-cancel { + display: flex; + white-space: nowrap; + gap: 10px; + color: #fff; + border: none; + padding: 12px 30px; + border-radius: 6px; + font-size: 18px; + margin-right: 24px; + @media only screen and (max-width: 600px) { + padding: 8px 20px; + font-size: 16px; + margin: 0; + } + } + + .btn-success { + background-color: $accent-color-red-primary; + } + + .btn-cancel { + background-color: #8e8e8e; + } + @media only screen and (max-width: 600px) { + justify-content: space-around; + } + } + + .project-form { + input, + textarea { + background-color: $light-mode-grey-thertiary; + border: none; + border-radius: 6px; + padding: 5px 15px; + margin: 5px 0; + width: 100%; + } + + textarea { + padding-top: 15px; + } + + input:focus { + outline: auto #0000001a; + } + + select { + height: 45px; + box-shadow: 0 3px 6px #0000001a; + } + + option::first-letter { + text-transform: uppercase; + } + } +} \ No newline at end of file diff --git a/src/app/modules/project/edit/edit.component.ts b/src/app/modules/project/details/edit/edit.component.ts similarity index 75% rename from src/app/modules/project/edit/edit.component.ts rename to src/app/modules/project/details/edit/edit.component.ts index 04e86907..e8372745 100644 --- a/src/app/modules/project/edit/edit.component.ts +++ b/src/app/modules/project/details/edit/edit.component.ts @@ -15,7 +15,7 @@ * If not, see https://www.gnu.org/licenses/lgpl-3.0.txt */ -import { Component, OnInit, ViewChild } from '@angular/core'; +import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { SafeUrl } from '@angular/platform-browser'; import { ActivatedRoute, Router } from '@angular/router'; @@ -43,6 +43,9 @@ import { QuillUtils } from 'src/app/utils/quill.utils'; styleUrls: ['./edit.component.scss'], }) export class EditComponent implements OnInit { + @Input() project: Project; + @Output() editMode = new EventEmitter(); + @Output() updatedProject = new EventEmitter(); /** * Configuration for file-picker */ @@ -58,7 +61,6 @@ export class EditComponent implements OnInit { */ public editProjectForm: FormGroup; public editCollaboratorForm: FormGroup; - public project: Project; public categories: ProjectCategory[]; /** @@ -90,13 +92,18 @@ export class EditComponent implements OnInit { */ public projectLoading = true; + /** + * Property to indicate the tab to open in the bottom menu + */ + public activeTab = 'description'; + constructor( - private router: Router, - private formBuilder: FormBuilder, - private projectService: ProjectService, - private activatedRoute: ActivatedRoute, - private alertService: AlertService, - private categoryService: CategoryService + private router: Router, + private formBuilder: FormBuilder, + private projectService: ProjectService, + private activatedRoute: ActivatedRoute, + private alertService: AlertService, + private categoryService: CategoryService ) { this.editProjectForm = this.formBuilder.group({ name: [null, Validators.required], @@ -112,47 +119,39 @@ export class EditComponent implements OnInit { } ngOnInit(): void { - const routeId = this.activatedRoute.snapshot.paramMap.get('id'); - if (!routeId) { - return; - } - - const id = Number(routeId); - if (!id || Number.isNaN(id) || id < 1) { - this.invalidId = routeId; - return; - } - - this.categoryService.getAll().subscribe(categories => { - this.categories = categories; - this.projectService.get(id) + if (Number(this.project.id)) { + const id = Number(this.project.id); + this.categoryService.getAll().subscribe(categories => { + this.categories = categories; + this.projectService.get(id) .pipe( - finalize(() => this.projectLoading = false) + finalize(() => this.projectLoading = false) ) .subscribe( - (projectResult) => { - this.project = projectResult; - this.collaborators = this.project.collaborators; - - this.categories = this.categories.map(category => ({ - ...category, - selected: !!this.project.categories?.find(c => c.name === category.name) - })); - - setTimeout(() => { - this.projectIconFileUploader.setFiles([this.project.projectIcon]); - this.projectImagesFileUploader.setFiles(this.project.images); - }, 1); - } + (projectResult) => { + this.project = projectResult; + this.collaborators = this.project.collaborators; + + this.categories = this.categories.map(category => ({ + ...category, + selected: !!this.project.categories?.find(c => c.name === category.name) + })); + + setTimeout(() => { + this.projectIconFileUploader.setFiles([this.project.projectIcon]); + this.projectImagesFileUploader.setFiles(this.project.images); + }, 1); + } ); - }); + }); + } } public onCategoryClick(category): void { this.categories = this.categories.map(cat => ( - cat.name === category.name - ? {...cat, selected: !category.selected} - : {...cat} + cat.name === category.name + ? { ...cat, selected: !category.selected } + : { ...cat } )); } @@ -171,6 +170,10 @@ export class EditComponent implements OnInit { this.projectImagesFileUploader.deleteFile(index); } + public iconRemoveButtonClick() { + this.projectIconFileUploader.deleteFile(0); + } + /** * Method that determines which preview to use for the project icon */ @@ -218,8 +221,8 @@ export class EditComponent implements OnInit { editedProject.categories = this.categories.filter(category => category.selected); const selectedCallToActions = this.callToActions.callToActionOptions - .filter(option => this.callToActions.selectedCallToActionOptionIds - .includes(option.id)); + .filter(option => this.callToActions.selectedCallToActionOptionIds + .includes(option.id)); editedProject.callToActions = selectedCallToActions.map(cta => ({ optionValue: cta.value, @@ -228,16 +231,16 @@ export class EditComponent implements OnInit { })); this.projectIconFileUploader.uploadFiles() - .subscribe(projectIcon => { - editedProject.iconId = this.getProjectIconId(projectIcon); - this.projectImagesFileUploader.uploadFiles() - .subscribe(projectImages => { - editedProject.imageIds = this.getProjectImagesIds(projectImages); - this.editProject(editedProject); - - this.uploadingFiles = false; - }); - }); + .subscribe(projectIcon => { + editedProject.iconId = this.getProjectIconId(projectIcon); + this.projectImagesFileUploader.uploadFiles() + .subscribe(projectImages => { + editedProject.imageIds = this.getProjectImagesIds(projectImages); + this.editProject(editedProject); + + this.uploadingFiles = false; + }); + }); } /** @@ -318,23 +321,28 @@ export class EditComponent implements OnInit { */ private editProject(edittedProject) { this.projectService - .put(this.project.id, edittedProject) - .pipe( - finalize(() => { - this.submitEnabled = false; - }) - ) - .subscribe(() => { - const alertConfig: AlertConfig = { - type: AlertType.success, - mainMessage: 'Project was succesfully updated', - dismissible: true, - autoDismiss: true, - timeout: this.alertService.defaultTimeout - - }; - this.alertService.pushAlert(alertConfig); - this.router.navigate([`project/details/${this.project.id}`]); - }); + .put(this.project.id, edittedProject) + .pipe( + finalize(() => { + this.submitEnabled = false; + }) + ) + .subscribe(() => { + const alertConfig: AlertConfig = { + type: AlertType.success, + mainMessage: 'Project was succesfully updated', + dismissible: true, + autoDismiss: true, + timeout: this.alertService.defaultTimeout + + }; + this.alertService.pushAlert(alertConfig); + this.editMode.emit(false); + this.updatedProject.emit(this.project); + }); + } + + public setActiveTab(newActiveTab): void { + this.activeTab = newActiveTab; } } diff --git a/src/app/modules/project/details/summary/summary.component.scss b/src/app/modules/project/details/summary/summary.component.scss index f96d48d9..d8303a28 100644 --- a/src/app/modules/project/details/summary/summary.component.scss +++ b/src/app/modules/project/details/summary/summary.component.scss @@ -4,8 +4,18 @@ display: grid; grid-template-columns: 1fr auto; justify-content: space-between; + align-items: center; gap: 20px; min-height: 70px; + @media only screen and (max-width: 600px) { + grid-template-columns: 1fr; + grid-template-rows: auto; + align-items: center; + gap: 10px; + margin-bottom: 20px; + justify-items: center; + } + h2 { margin: 0; @@ -34,6 +44,9 @@ width: 100%; object-fit: cover; } + @media only screen and (max-width: 600px) { + grid-row: 1; + } } button { diff --git a/src/app/modules/project/edit/edit.component.html b/src/app/modules/project/edit/edit.component.html deleted file mode 100644 index 1b9af605..00000000 --- a/src/app/modules/project/edit/edit.component.html +++ /dev/null @@ -1,234 +0,0 @@ - - -
-
-

Edit project

- - -

Project is being loaded

-
- -
-
-
-
- - - -
-
- Code project -
-
-

Project icon

-
-
-
- -
-
-
-

Project name*

- -
-
- -
-
-

Project link

- -
-
-
-
-
-
-

Short description*

- -
-
-
- -
-
-
-

Describe your project in one sentence or 170 characters.

-
-
-
-
-
-
-

Project categories*

- -
-
-
-
-
-
-

Description*

- - -
-
-
-
-
-

Project images

-
-
-
-
-
- -
-
-
-
-
- -
-
-
- - -
-
-
-
-
-
-
-

Call to action

-
- -
-
-
-

Select the type of call to action button you want for your project.

-
-
-
-
- -
-
-
-

Add project collaborators

-
-
-
-

Collaborator full name

- -
-
-
-
-

Collaborator role

- -
-
- -
- -
-
- -
-

e.g.: developer, designer, etc...

-
- -
-
-
- -
- -
-

Collaborators

-
- -
- - -
- -
-

{{collaborator?.fullName}}

-
-

-

-
-

{{collaborator?.role}}

-
- -
- -
-
-
- -
- - -
-
-
-

No project could be found with id: {{invalidId}}

-
-
-
-
diff --git a/src/app/modules/project/edit/edit.component.scss b/src/app/modules/project/edit/edit.component.scss deleted file mode 100644 index e088eaf3..00000000 --- a/src/app/modules/project/edit/edit.component.scss +++ /dev/null @@ -1,359 +0,0 @@ -/* - * - * Digital Excellence Copyright (C) 2020 Brend Smits - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published - * by the Free Software Foundation version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU Lesser General Public License for more details. - * - * You can find a copy of the GNU Lesser General Public License - * along with this program, in the LICENSE.md file in the root project directory. - * If not, see https://www.gnu.org/licenses/lgpl-3.0.txt - * - */ -@import "assets/styles/variables"; - -.project-form { - input, - textarea { - border: none; - border-radius: 6px; - box-shadow: 0 3px 6px #0000001a; - height: 45px; - width: 100%; - padding: 0 15px; - } - - textarea { - height: 250px; - padding-top: 15px; - } - - input:focus { - outline: auto #e4e4e4; - } - - select { - height: 45px; - box-shadow: 0 3px 6px #0000001a; - } - - option::first-letter { - text-transform: uppercase; - } -} - -.project-icon { - margin-bottom: 20px; - display: flex; - align-items: center; - gap: 20px; - - .overlay { - z-index: 2; - height: 100%; - width: 100%; - position: absolute; - background-color: rgba(0, 0, 0, 0.2); - left: 0; - top: 0; - opacity: 0; - transition: $transition-short; - display: flex; - justify-content: center; - align-items: center; - - em { - cursor: pointer; - color: white; - font-size: 24px; - } - } - - &:hover { - .overlay { - opacity: 1; - } - } - - .preview { - position: relative; - place-content: center; - background-color: $accent-color-red-primary; - width: 65px; - min-width: 65px; - height: 65px; - border-radius: 999px; - overflow: hidden; - box-shadow: 0 0 4px #0000001a; - - img { - height: 100%; - width: 100%; - object-fit: cover; - } - } -} - -.add-collaborator-col { - display: flex; - justify-content: flex-end; - align-self: center; - - .add-collaborator-button { - margin: 0; - align-self: flex-end; - } - - button { - background: $accent-color-red-primary; - border-radius: 50px; - width: 50px; - height: 50px; - border: none; - font-size: 25px; - font-weight: 800; - } -} - -.call-to-actions { - background-color: white; - border-radius: $border-radius; -} - -.project-categories { - display: flex; - flex-wrap: wrap; - margin-bottom: 10px; - - .category { - text-decoration: none; - border-radius: 999px; - background-color: $light-mode-grey-thertiary; - color: $black; - padding: 3px 20px; - box-shadow: rgba(0, 0, 0, 0.15) 0 3px 5px; - margin: 5px 5px 5px 0; - font-size: 12px; - - &.selected { - background: $accent-color-red-primary; - color: #fff; - } - } -} - -.long-description-editor { - margin-bottom: 25px; -} - -.title-spacing { - margin-bottom: 25px; -} - -.project-images { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 30px; - - button { - &.grey { - display: none; - } - } - - @media only screen and (max-width: 800px) { - grid-template-columns: 1fr; - .project-image-picker { - display: none; - } - button { - &.grey { - display: block; - } - } - img { - display: none; - } - } - - .project-image-picker { - min-width: 300px; - margin-bottom: 20px; - } - - .left { - display: flex; - flex-direction: column; - align-items: center; - justify-content: space-between; - - .file-preview { - display: grid; - grid-template-columns: 1fr 1fr 1fr; - gap: 15px; - max-width: 100%; - width: 100%; - position: relative; - - .preview { - position: relative; - border-radius: $border-radius; - width: 100% !important; - overflow: hidden; - background-size: cover; - background-position: center; - background-color: $light-mode-grey-quaternary; - - border: 2px solid $light-mode-grey-thertiary; - - &:first-child { - grid-column: span 3; - - .overlay { - em { - font-size: 35px; - } - } - } - - @media only screen and (max-width: 600px) { - width: 95%; - } - - &:after { - content: ""; - display: block; - padding-bottom: calc(55% + 10px); - } - - .overlay { - z-index: 2; - height: 100%; - width: 100%; - position: absolute; - background-color: rgba(0, 0, 0, 0.2); - left: 0; - top: 0; - opacity: 0; - transition: $transition-short; - display: flex; - justify-content: center; - align-items: center; - - em { - cursor: pointer; - color: white; - font-size: 24px; - } - } - - &:hover { - .overlay { - opacity: 1; - } - } - } - - img { - display: inline-block; - z-index: 2; - - &.workers { - position: absolute; - right: -5px; - bottom: -3px; - } - - @media only screen and (max-width: 600px) { - display: none; - } - } - } - - .buttons { - display: flex; - flex-wrap: wrap; - justify-content: center; - gap: 15px; - margin-top: 30px; - } - } -} - -.collaborator-overview { - .collaborator-item { - display: flex; - align-items: center; - margin-bottom: 10px; - padding-top: 5px; - padding-bottom: 5px; - - strong { - margin-right: 5px; - margin-left: 10px; - } - - .collaborator-text-container { - display: flex; - justify-content: flex-start; - } - .collaborator-text-container .dash { - margin-left: 5px; - margin-right: 5px; - } - .collaborator-text-container div { - max-width: 50%; - } - .collaborator-text.font-weight-bold { - margin-left: 10px; - } - - .collaborator-text { - align-self: center; - margin: 0; - max-width: 100%; - - text-overflow: ellipsis; - overflow: hidden; - white-space: nowrap; - } - } - - button { - border-radius: 20px; - width: 20px; - height: 20px; - padding: 0; - display: flex; - align-items: center; - justify-content: center; - background-color: $accent-color-red-primary; - } -} - -.btn-success, -.btn-cancel { - display: flex; - white-space: nowrap; - gap: 10px; - color: #fff; - border: none; - padding: 12px 30px; - border-radius: 6px; - font-size: 18px; - margin-right: 24px; -} - -.btn-success { - background-color: $accent-color-red-primary; -} - -.btn-cancel { - background-color: #8e8e8e; -} diff --git a/src/app/modules/project/modal-highlight-form/modal-highlight-form.component.ts b/src/app/modules/project/modal-highlight-form/modal-highlight-form.component.ts index 4e4c0388..bf2c1d22 100644 --- a/src/app/modules/project/modal-highlight-form/modal-highlight-form.component.ts +++ b/src/app/modules/project/modal-highlight-form/modal-highlight-form.component.ts @@ -170,7 +170,6 @@ export class ModalHighlightFormComponent implements OnInit, AfterViewInit { * Method which triggers when the back button is clicked. */ public onClickBack(): void { - this.goBack.emit(); this.bsModalRef.hide(); } diff --git a/src/app/modules/project/overview/filter-menu/filter-menu.component.ts b/src/app/modules/project/overview/filter-menu/filter-menu.component.ts index dc9029b8..d8ba1b8c 100644 --- a/src/app/modules/project/overview/filter-menu/filter-menu.component.ts +++ b/src/app/modules/project/overview/filter-menu/filter-menu.component.ts @@ -45,14 +45,14 @@ export class FilterMenuComponent implements OnInit { ]; public sortSelectOptions: SelectFormOption[] = [ + {value: 'likes,desc', viewValue: 'Likes (high-low)'}, + {value: 'likes,asc', viewValue: 'Likes (low-high)'}, {value: 'updated,desc', viewValue: 'Updated (new-old)'}, {value: 'updated,asc', viewValue: 'Updated (old-new)'}, {value: 'name,asc', viewValue: 'Name (a-z)'}, {value: 'name,desc', viewValue: 'Name (z-a)'}, {value: 'created,desc', viewValue: 'Created (new-old)'}, - {value: 'created,asc', viewValue: 'Created (old-new)'}, - {value: 'likes,desc', viewValue: 'Likes (high-low)'}, - {value: 'likes,asc', viewValue: 'Likes (low-high)'}, + {value: 'created,asc', viewValue: 'Created (old-new)'} ]; /** diff --git a/src/app/modules/project/overview/overview.component.ts b/src/app/modules/project/overview/overview.component.ts index 66a8e7ec..9f18710d 100644 --- a/src/app/modules/project/overview/overview.component.ts +++ b/src/app/modules/project/overview/overview.component.ts @@ -25,6 +25,7 @@ import { Project } from 'src/app/models/domain/project'; import { CategoryService } from 'src/app/services/category.service'; import { InternalSearchService } from 'src/app/services/internal-search.service'; import { PaginationService } from 'src/app/services/pagination.service'; +import { ProjectService } from 'src/app/services/project.service'; import { SEOService } from 'src/app/services/seo.service'; import { ProjectDetailModalUtility } from 'src/app/utils/project-detail-modal.util'; import { environment } from 'src/environments/environment'; @@ -77,11 +78,21 @@ export class OverviewComponent implements OnInit, AfterViewInit { private location: Location, private categoryService: CategoryService, private route: ActivatedRoute, - private modalUtility: ProjectDetailModalUtility) { + private modalUtility: ProjectDetailModalUtility, + private projectService: ProjectService) { } ngOnInit(): void { this.updateSEOTags(); + + // Code below is executed when a project is updated (for example on edit component) + // find the updated project in de database and replace it in the overview + this.projectService.projectUpdated$.subscribe(updatedProjectId => { + const projectIndexToUpdate = this.filteredProjects.findIndex(project => project.id === updatedProjectId); + this.projectService.get(updatedProjectId).subscribe(updatedProject => { + this.filteredProjects.splice(projectIndexToUpdate, 1, updatedProject); + }); + }); } ngAfterViewInit(): void { diff --git a/src/app/modules/project/project-routing.module.ts b/src/app/modules/project/project-routing.module.ts index 70647bc4..b6c92cad 100644 --- a/src/app/modules/project/project-routing.module.ts +++ b/src/app/modules/project/project-routing.module.ts @@ -14,7 +14,7 @@ * along with this program, in the LICENSE.md file in the root project directory. * If not, see https://www.gnu.org/licenses/lgpl-3.0.txt */ -import { EditComponent } from './edit/edit.component'; +import { EditComponent } from './details/edit/edit.component'; import { EmbedComponent } from './embed/embed.component'; import { OverviewComponent } from './overview/overview.component'; diff --git a/src/app/modules/project/project.module.ts b/src/app/modules/project/project.module.ts index c140155c..c17530ff 100644 --- a/src/app/modules/project/project.module.ts +++ b/src/app/modules/project/project.module.ts @@ -19,8 +19,8 @@ import { CollaboratorComponent } from './collaborator/collaborator.component'; import { BottomDrawerComponent } from './details/bottom-drawer/bottom-drawer.component'; import { SettingsDropdownComponent } from './details/bottom-drawer/settings-dropdown/settings-dropdown.component'; import { DetailsComponent } from './details/details.component'; +import { EditComponent } from './details/edit/edit.component'; import { SummaryComponent } from './details/summary/summary.component'; -import { EditComponent } from './edit/edit.component'; import { EmbedButtonComponent } from './embed-button/embed-button.component'; import { EmbedComponent } from './embed/embed.component'; import { HighlightsModalComponent } from './highlights-modal/highlights-modal.component'; @@ -96,7 +96,8 @@ import { SafeHtmlPipe } from 'src/app/utils/safeHtml.pipe'; FileUploaderComponent, SafeHtmlPipe, ProjectComponent, - CallToActionsEditComponent + CallToActionsEditComponent, + PaginationComponent ], providers: [Meta] }) diff --git a/src/app/modules/user/user-projects/user-projects.component.html b/src/app/modules/user/user-projects/user-projects.component.html index b7b31744..05387116 100644 --- a/src/app/modules/user/user-projects/user-projects.component.html +++ b/src/app/modules/user/user-projects/user-projects.component.html @@ -15,14 +15,38 @@ along with this program, in the LICENSE.md file in the root project directory. If not, see https://www.gnu.org/licenses/lgpl-3.0.txt --> -
- - +
+
+

Filters

+
+
+

Sort Options

+
+ + +
+
+
+
+

Pagination

+ + +
+
+
+

My projects

-
-

{{ userName }}

Projects:

-

{{ userprojects.length }}

- +

{{ totalAmountOfProjects }}

-
+
+ + +
-

No projects found

-

There are no projects available.

diff --git a/src/app/modules/user/user-projects/user-projects.component.scss b/src/app/modules/user/user-projects/user-projects.component.scss index fd1bfa58..cccd1bb8 100644 --- a/src/app/modules/user/user-projects/user-projects.component.scss +++ b/src/app/modules/user/user-projects/user-projects.component.scss @@ -17,6 +17,8 @@ * */ @import "assets/styles/variables"; + @import "app/modules/project/overview/project-list/project-list.component.scss"; + .userinfo{ display: flex; @@ -100,84 +102,6 @@ margin-left: auto; margin-right: auto; - .project-list-header { - width: 100%; - margin: 2em 0; - display: inline-flex; - justify-content: space-between; - align-content: center; - - h1 { - display: inline; - } - .list-view-toggle { - display: flex; - margin: auto 0 auto 20px; - gap: 12px; - flex-wrap: wrap; - justify-content: flex-end; - - @media only screen and (max-width: 720px) { - display: none; - } - - .container { - box-shadow: $box-shadow; - display: inline; - position: relative; - cursor: pointer; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - padding: 0; - width: fit-content; - margin: 0; - height: fit-content; - } - - // Hide the default radio button - .container input[type="radio"] { - position: absolute; - opacity: 0; - cursor: pointer; - height: 0; - width: 0; - } - - // Create custom radio button - .checkmark { - height: 40px; - width: 40px; - padding: 10px; - border-radius: 5px; - background-color: $white; - color: $accent-color-red-primary; - display: flex; - justify-content: center; - align-items: center; - transition: transform $transition-short; - - &:hover { - transform: $transform-grow-big; - } - svg { - size: inherit; - width: 100%; - height: 100%; - margin: 0; - } - } - } - - // If the sibling input is checked - .container input[type="radio"]:checked ~ .checkmark { - color: $light-mode-grey-quaternary; - background: $accent-color-red-primary; - } - } - - .project-list-wrapper { width: 100%; display: grid; @@ -207,3 +131,5 @@ border-bottom: 1px solid $light-mode-grey-thertiary; } } + + @import "app/modules/project/overview/filter-menu/filter-menu.component.scss"; diff --git a/src/app/modules/user/user-projects/user-projects.component.ts b/src/app/modules/user/user-projects/user-projects.component.ts index 5df45abc..c62464a6 100644 --- a/src/app/modules/user/user-projects/user-projects.component.ts +++ b/src/app/modules/user/user-projects/user-projects.component.ts @@ -17,12 +17,14 @@ import { Location } from '@angular/common'; import { Component, OnInit } from '@angular/core'; +import { FormControl } from '@angular/forms'; import { SafeUrl } from '@angular/platform-browser'; import { ActivatedRoute, Router } from '@angular/router'; import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal'; import { finalize } from 'rxjs/operators'; +import { SelectFormOption } from 'src/app/interfaces/select-form-option'; import { Project } from 'src/app/models/domain/project'; -import { DetailsComponent } from 'src/app/modules/project/details/details.component'; +import { InternalSearchQuery } from 'src/app/models/resources/internal-search-query'; import { AuthService } from 'src/app/services/auth.service'; import { FileRetrieverService } from 'src/app/services/file-retriever.service'; import { SEOService } from 'src/app/services/seo.service'; @@ -39,19 +41,22 @@ export class UserProjectsComponent implements OnInit { public projectsToDisplay: Project[] = []; /** - * User info + * Pagination object */ - public userName: string; + public internalSearchQuery: InternalSearchQuery = { + query: null, + // If there is a search query, search on all pages + page: null, + amountOnPage: 12, + sortBy: '', + sortDirection: '', + categories: null + }; /** - * The number of projects that belong to the user - */ - public totalNrOfProjects = 0; - - /** - * Boolean to determine whether the component is loading the information from the api. + * User info */ - public projectsLoading = true; + public userName: string; /** * Boolean to determine whether to show the projects in listview or gridview @@ -71,7 +76,7 @@ export class UserProjectsComponent implements OnInit { /** * Array to receive and store the projects from the api. */ - public userprojects: Project[] = []; + public userProjects: Project[] = []; /** * Boolean to determine whether the component is loading the information from the api. @@ -81,7 +86,6 @@ export class UserProjectsComponent implements OnInit { /** * Project parameter gets updated per project detail modal */ - public currentProject: Project = null; public noProjects = false; @@ -90,6 +94,37 @@ export class UserProjectsComponent implements OnInit { */ private modalRef: BsModalRef; + public totalAmountOfProjects: number; + + public amountOnPage: number; + public sortOptionControl: FormControl = null; + public paginationOptionControl: FormControl = null; + + public sortSelectOptions: SelectFormOption[] = [ + {value: 'updated,desc', viewValue: 'Updated (new-old)'}, + {value: 'updated,asc', viewValue: 'Updated (old-new)'}, + {value: 'name,asc', viewValue: 'Name (a-z)'}, + {value: 'name,desc', viewValue: 'Name (z-a)'}, + {value: 'created,desc', viewValue: 'Created (new-old)'}, + {value: 'created,asc', viewValue: 'Created (old-new)'}, + {value: 'likes,desc', viewValue: 'Likes (high-low)'}, + {value: 'likes,asc', viewValue: 'Likes (low-high)'}, + ]; + + public currentSortOptions: string = this.sortSelectOptions[0].value; + + public paginationDropDownOptions = [ + {id: 0, amountOnPage: 12}, + {id: 1, amountOnPage: 24}, + {id: 2, amountOnPage: 36}, + ]; + private currentSortType: string = this.currentSortOptions.split(',')[0]; + private currentSortDirection: string = this.currentSortOptions.split(',')[1]; + /** + * Object to keep track of a modal that was opened trough the url + */ + private urlOpenedModal = { state: false, projectId: null }; + constructor(private userService: UserService, private router: Router, private fileRetrieverService: FileRetrieverService, @@ -98,24 +133,17 @@ export class UserProjectsComponent implements OnInit { private seoService: SEOService, private location: Location, private modalService: BsModalService, - private activatedRoute: ActivatedRoute) {} + private activatedRoute: ActivatedRoute) { + this.sortOptionControl = new FormControl(this.sortSelectOptions[0]); + this.paginationOptionControl = new FormControl(this.paginationDropDownOptions[0]); + } ngOnInit(): void { + this.amountOnPage = this.paginationDropDownOptions[0].amountOnPage; this.authService.authNavStatus$.subscribe(status => { this.userName = this.authService.name; if (status) { - this.userService.getProjectsFromUser() - .pipe( - finalize(() => ( - this.userProjectsLoading = false - )) - ).subscribe(result => { - if (result) { - this.userprojects = result; - } else { - this.noProjects = true; - } - }); + this.getUserProjects(this.internalSearchQuery); } }); this.updateSEOTags(); @@ -123,40 +151,36 @@ export class UserProjectsComponent implements OnInit { ngAfterViewInit() { this.activatedRoute.params.subscribe(params => { - const projectId = params.id?.split('-')[0]; - this.createProjectModal(projectId); + const projectId = +params.id?.split('-')[0]; + // We need the 1ms timeout to make sure the components are rendered, I don't know why angular doesn't do this but whatever + setTimeout(() => { + // Methods below are executed when an ID has been provided in the URL + if (projectId) { + this.modalUtility.openProjectModal(projectId, '', '/project/overview'); + // object to handle check for like-subscribe in filteredProjectsChanged() + this.urlOpenedModal = { state: true, projectId: projectId }; + } + }, 1); }); } + /** + * Method to open the modal for a projects detail + * @param id the id of the project that should be shown. + * @param name the project name that should be shown. + */ + public onClickUserProject(id: number, name: string): void { name = name.split(' ').join('-'); - this.modalUtility.openProjectModal(id, name, '/home'); + this.modalUtility.openProjectModal(id, name, '/user/projects'); + this.updateSEOTags(); } /** * Checks whether there are any projects */ public projectsEmpty(): boolean { - return this.userprojects.length < 1; - } - - /** - * Triggers on project click in the list. - * @param event click event - * @param id project id. - * @param name project name - */ - public onClickProject(event: Event, id: number, name: string): void { - name = name.split(' ').join('-'); - - const clickedSection = event.target as Element; - - if (clickedSection.classList.contains('project-collaborators')) { - this.createProjectModal(id, 'collaborators'); - } else { - this.createProjectModal(id); - } - this.location.replaceState(`/project/details/${id}-${name}`); + return this.totalAmountOfProjects < 1; } /** @@ -167,38 +191,6 @@ export class UserProjectsComponent implements OnInit { return this.fileRetrieverService.getIconUrl(project.projectIcon); } - /** - * Method to open the modal for a projects detail - * @param projectId the id of the project that should be shown. - * @param activeTab Define the active tab - */ - private createProjectModal(projectId: number, activeTab: string = 'description') { - const initialState = { - projectId: projectId, - activeTab: activeTab - }; - if (projectId) { - this.modalRef = this.modalService.show(DetailsComponent, {animated: true, initialState}); - this.modalRef.setClass('project-modal'); - - this.modalRef.content.onLike.subscribe(isLiked => { - const projectIndexToUpdate = this.userprojects.findIndex(project => project.id === projectId); - if (isLiked) { - this.userprojects[projectIndexToUpdate].likeCount++; - this.userprojects[projectIndexToUpdate].userHasLikedProject = true; - } else { - this.userprojects[projectIndexToUpdate].likeCount--; - this.userprojects[projectIndexToUpdate].userHasLikedProject = false; - } - }); - - // Go back to home page after the modal is closed - this.modalService.onHide.subscribe(() => { - this.location.replaceState(`/user/projects`); - this.updateSEOTags(); - }); - } - } /** * Methods to update the title and description through the SEO service @@ -220,4 +212,51 @@ export class UserProjectsComponent implements OnInit { public addProjectClicked() { this.router.navigateByUrl('project/add'); } + + public pageChanged(event: number) { + this.internalSearchQuery.page = event; + this.getUserProjects(this.internalSearchQuery); + } + + /** + * Method to show the amount of items per page. + */ + public onPaginationChange() { + this.internalSearchQuery.amountOnPage = this.paginationOptionControl.value.amountOnPage; + this.getUserProjects(this.internalSearchQuery); + } +/** + * Method to select the sort order of the projects. + */ + public onSortChange() { + this.currentSortType = this.sortOptionControl.value.value.split(',')[0]; + this.currentSortDirection = this.sortOptionControl.value.value.split(',')[1]; + this.currentSortOptions = this.sortOptionControl.value.value; + + this.internalSearchQuery.sortBy = this.sortOptionControl.value.value.split(',')[0]; + this.internalSearchQuery.sortDirection = this.sortOptionControl.value.value.split(',')[1]; + + this.getUserProjects(this.internalSearchQuery); + } + + /** + * Method to retrieve the user projects. + * @param searchQuery The search query that's send with the api call. + */ + private getUserProjects(searchQuery: InternalSearchQuery) { + this.userProjectsLoading = true; + this.userService.getProjectsPaginated(searchQuery) + .pipe( + finalize(() => ( + this.userProjectsLoading = false + )) + ).subscribe(result => { + if (result) { + this.userProjects = result.results; + this.totalAmountOfProjects = result.totalCount; + } else { + this.noProjects = true; + } + }); + } } diff --git a/src/app/modules/user/user.module.ts b/src/app/modules/user/user.module.ts index 8c6ba2c5..e1a65338 100644 --- a/src/app/modules/user/user.module.ts +++ b/src/app/modules/user/user.module.ts @@ -3,7 +3,8 @@ import { UserRoutingModule } from './user-routing.module'; import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; -import { FormsModule } from '@angular/forms'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { PaginationModule } from 'ngx-bootstrap/pagination'; import { ProjectModule } from 'src/app/modules/project/project.module'; @@ -12,11 +13,13 @@ import { ProjectModule } from 'src/app/modules/project/project.module'; UserProjectsComponent ], imports: [ - CommonModule, - UserRoutingModule, - ProjectModule, - FormsModule - ] + CommonModule, + UserRoutingModule, + ProjectModule, + FormsModule, + PaginationModule, + ReactiveFormsModule, + ] }) export class UserModule { } diff --git a/src/app/services/project.service.ts b/src/app/services/project.service.ts index 8c5f19e0..9a322412 100644 --- a/src/app/services/project.service.ts +++ b/src/app/services/project.service.ts @@ -19,7 +19,7 @@ import { AuthService } from './auth.service'; import { HttpBaseService } from './http-base.service'; import { HttpClient } from '@angular/common/http'; -import { Injectable } from '@angular/core'; +import { EventEmitter, Injectable, Output } from '@angular/core'; import { from, Observable } from 'rxjs'; import { map, mergeMap } from 'rxjs/operators'; import { API_CONFIG } from 'src/app/config/api-config'; @@ -36,32 +36,34 @@ export class ProjectService extends HttpBaseService = new EventEmitter(); + get(id: number): Observable { return super.get(id) - .pipe( - map(project => { - return { - ...project, - callToActions: project.callToActions.length > 0 ? - project.callToActions.map(cta => ({ - ...cta, - iconName: CallToActionIconsConfig[cta.optionValue.toLowerCase()] - }) - ) - : undefined - }; - }), - mergeMap(project => - from(this.addLikes(project)) - )); + .pipe( + map(project => { + return { + ...project, + callToActions: project.callToActions.length > 0 ? + project.callToActions.map(cta => ({ + ...cta, + iconName: CallToActionIconsConfig[cta.optionValue.toLowerCase()] + }) + ) + : undefined + }; + }), + mergeMap(project => + from(this.addLikes(project)) + )); } private addLikes(project): Promise { return this.authService.getBackendUser() - .then(currentUser => { - project.likeCount = project.likes?.length ? project.likes.length : 0; - project.userHasLikedProject = project.likes.filter(like => like.userId === currentUser?.id).length > 0; - return project; - }); + .then(currentUser => { + project.likeCount = project.likes?.length ? project.likes.length : 0; + project.userHasLikedProject = project.likes.filter(like => like.userId === currentUser?.id).length > 0; + return project; + }); } } diff --git a/src/app/services/user.service.ts b/src/app/services/user.service.ts index 9fee03d5..4fd529e6 100644 --- a/src/app/services/user.service.ts +++ b/src/app/services/user.service.ts @@ -17,20 +17,21 @@ import { HttpBaseService } from './http-base.service'; -import { HttpClient } from '@angular/common/http'; +import { HttpClient, HttpParams } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { from, Observable } from 'rxjs'; import { mergeMap } from 'rxjs/operators'; import { API_CONFIG } from 'src/app/config/api-config'; -import { Project } from 'src/app/models/domain/project'; import { User } from 'src/app/models/domain/user'; +import { InternalSearchQuery } from 'src/app/models/resources/internal-search-query'; +import { SearchResultsResource } from 'src/app/models/resources/search-results'; import { UserAdd } from 'src/app/models/resources/user-add'; + @Injectable({ providedIn: 'root', }) export class UserService extends HttpBaseService { - constructor(http: HttpClient) { super(http, API_CONFIG.url + API_CONFIG.userRoute); } @@ -39,25 +40,44 @@ export class UserService extends HttpBaseService { return this.http.get(this.url); } - public getProjectsFromUser(): Observable { - return this.http.get(`${this.url}/projects`) - .pipe( - mergeMap(result => from( - this.addLikes(result) - )) - ); + public getProjectsFromUser(): Observable { + return this.http.get(`${this.url}/projects`).pipe(mergeMap((result) => from(this.addLikes(result)))); } - private addLikes(projects): Promise { - return new Promise(resolve => { - this.getCurrentUser().subscribe(currentUser => { - projects.map(project => { + private addLikes(projects): Promise { + return new Promise((resolve) => { + this.getCurrentUser().subscribe((currentUser) => { + projects.results.map((project) => { project.likeCount = project.likes.length ? project.likes.length : 0; - project.userHasLikedProject = project.likes.filter(like => like.userId === currentUser?.id).length > 0; + project.userHasLikedProject = project.likes.filter((like) => like.userId === currentUser?.id).length > 0; return project; }); resolve(projects); }); }); } + + public getProjectsPaginated(internalSearchQuery: InternalSearchQuery): Observable { + const url = `${this.url}/projects`; + let params = new HttpParams(); + + for (const key of Object.keys(internalSearchQuery)) { + if (internalSearchQuery[key] == null) { + continue; + } + if (Array.isArray(internalSearchQuery[key])) { + internalSearchQuery[key].forEach((item, index) => { + params = params.append(key + '[' + index + ']', item); + }); + } else { + params = params.append(key, internalSearchQuery[key]); + } + } + + return this.http + .get(url, { + params, + }) + .pipe(mergeMap((result) => from(this.addLikes(result)))); + } } diff --git a/src/app/services/wizard.service.ts b/src/app/services/wizard.service.ts index c934e2e6..1efa0a21 100644 --- a/src/app/services/wizard.service.ts +++ b/src/app/services/wizard.service.ts @@ -18,6 +18,7 @@ import { AuthService } from './auth.service'; import { HttpClient, HttpParams } from '@angular/common/http'; +import { THIS_EXPR } from '@angular/compiler/src/output/output_ast'; import { Injectable } from '@angular/core'; import { Router } from '@angular/router'; import { BehaviorSubject, Observable } from 'rxjs'; @@ -293,6 +294,13 @@ export class WizardService { return this.currentStep$.value.orderIndex === this.steps$.value.length; } + /** + * Method that checks if the current step is the first one of the flow + */ + public isFirstStep(): boolean { + return this.currentStep$.value.orderIndex === 1; + } + /** * Method that checks if all steps of the wizard have been completed */