mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 10:04:11 +00:00
282 lines
9.6 KiB
TypeScript
282 lines
9.6 KiB
TypeScript
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
|
|
|
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
|
|
|
|
import { BehaviorSubject, combineLatest, from, shareReplay } from 'rxjs';
|
|
import { map, mergeMap, take, tap } from 'rxjs/operators';
|
|
import { TranslateService } from '@ngx-translate/core';
|
|
import { NgbActiveModal, NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
|
import findIndex from 'lodash/findIndex';
|
|
|
|
import { Subscription } from '../models/subscription.model';
|
|
import { DSpaceObject } from '../../../core/shared/dspace-object.model';
|
|
import { SubscriptionsDataService } from '../subscriptions-data.service';
|
|
import { NotificationsService } from '../../notifications/notifications.service';
|
|
import { PaginatedList } from '../../../core/data/paginated-list.model';
|
|
import { RemoteData } from '../../../core/data/remote-data';
|
|
import { getFirstCompletedRemoteData, getFirstSucceededRemoteDataPayload } from '../../../core/shared/operators';
|
|
import { AuthService } from '../../../core/auth/auth.service';
|
|
import { isNotEmpty } from '../../empty.util';
|
|
|
|
@Component({
|
|
selector: 'ds-subscription-modal',
|
|
templateUrl: './subscription-modal.component.html',
|
|
styleUrls: ['./subscription-modal.component.scss']
|
|
})
|
|
/**
|
|
* Modal that allows to manage the subscriptions for the selected item
|
|
*/
|
|
export class SubscriptionModalComponent implements OnInit {
|
|
|
|
/**
|
|
* DSpaceObject of which to get the subscriptions
|
|
*/
|
|
@Input() dso: DSpaceObject;
|
|
|
|
/**
|
|
* If given the subscription to edit by the form
|
|
*/
|
|
@Input() subscription: Subscription;
|
|
|
|
/**
|
|
* The eperson related to the subscription
|
|
*/
|
|
ePersonId: string;
|
|
|
|
/**
|
|
* A boolean representing if a request operation is pending
|
|
* @type {BehaviorSubject<boolean>}
|
|
*/
|
|
public processing$ = new BehaviorSubject<boolean>(false);
|
|
|
|
/**
|
|
* If true, show a message explaining how to delete a subscription
|
|
*/
|
|
public showDeleteInfo$ = new BehaviorSubject<boolean>(false);
|
|
|
|
/**
|
|
* Reactive form group that will be used to add/edit subscriptions
|
|
*/
|
|
subscriptionForm: UntypedFormGroup;
|
|
|
|
/**
|
|
* Used to show validation errors when user submits
|
|
*/
|
|
submitted = false;
|
|
|
|
/**
|
|
* Types of subscription to be shown on select
|
|
*/
|
|
subscriptionDefaultTypes = ['content'];
|
|
|
|
/**
|
|
* Frequencies to be shown as checkboxes
|
|
*/
|
|
frequencyDefaultValues = ['D', 'W', 'M'];
|
|
|
|
/**
|
|
* True if form status has changed and at least one frequency is checked
|
|
*/
|
|
isValid = false;
|
|
/**
|
|
* Event emitted when a given subscription has been updated
|
|
*/
|
|
@Output() updateSubscription: EventEmitter<Subscription> = new EventEmitter<Subscription>();
|
|
|
|
constructor(
|
|
private formBuilder: UntypedFormBuilder,
|
|
private modalService: NgbModal,
|
|
private notificationsService: NotificationsService,
|
|
private subscriptionService: SubscriptionsDataService,
|
|
public activeModal: NgbActiveModal,
|
|
private authService: AuthService,
|
|
private translate: TranslateService,
|
|
) {
|
|
}
|
|
|
|
/**
|
|
* When component starts initialize starting functionality
|
|
*/
|
|
ngOnInit(): void {
|
|
this.authService.getAuthenticatedUserFromStore().pipe(
|
|
take(1),
|
|
map((ePerson) => ePerson.uuid),
|
|
shareReplay(),
|
|
).subscribe((ePersonId: string) => {
|
|
this.ePersonId = ePersonId;
|
|
if (isNotEmpty(this.subscription)) {
|
|
this.initFormByGivenSubscription();
|
|
} else {
|
|
this.initFormByAllSubscriptions();
|
|
}
|
|
});
|
|
|
|
this.subscriptionForm.valueChanges.subscribe((newValue) => {
|
|
let anyFrequencySelected = false;
|
|
for (let f of this.frequencyDefaultValues) {
|
|
anyFrequencySelected = anyFrequencySelected || newValue.content.frequencies[f];
|
|
}
|
|
this.isValid = anyFrequencySelected;
|
|
});
|
|
}
|
|
|
|
initFormByAllSubscriptions(): void {
|
|
this.subscriptionForm = new UntypedFormGroup({});
|
|
for (let t of this.subscriptionDefaultTypes) {
|
|
const formGroup = new UntypedFormGroup({});
|
|
formGroup.addControl('subscriptionId', this.formBuilder.control(''));
|
|
formGroup.addControl('frequencies', this.formBuilder.group({}));
|
|
for (let f of this.frequencyDefaultValues) {
|
|
(formGroup.controls.frequencies as UntypedFormGroup).addControl(f, this.formBuilder.control(false));
|
|
}
|
|
this.subscriptionForm.addControl(t, formGroup);
|
|
}
|
|
|
|
this.initFormDataBySubscriptions();
|
|
}
|
|
|
|
/**
|
|
* If the subscription is passed start the form with the information of subscription
|
|
*/
|
|
initFormByGivenSubscription(): void {
|
|
const formGroup = new UntypedFormGroup({});
|
|
formGroup.addControl('subscriptionId', this.formBuilder.control(this.subscription.id));
|
|
formGroup.addControl('frequencies', this.formBuilder.group({}));
|
|
(formGroup.get('frequencies') as UntypedFormGroup).addValidators(Validators.required);
|
|
for (let f of this.frequencyDefaultValues) {
|
|
const value = findIndex(this.subscription.subscriptionParameterList, ['value', f]) !== -1;
|
|
(formGroup.controls.frequencies as UntypedFormGroup).addControl(f, this.formBuilder.control(value));
|
|
}
|
|
|
|
this.subscriptionForm = this.formBuilder.group({
|
|
[this.subscription.subscriptionType]: formGroup
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get subscriptions for the current ePerson & dso object relation.
|
|
* If there are no subscriptions then start with an empty form.
|
|
*/
|
|
initFormDataBySubscriptions(): void {
|
|
this.processing$.next(true);
|
|
this.subscriptionService.getSubscriptionsByPersonDSO(this.ePersonId, this.dso?.uuid).pipe(
|
|
getFirstSucceededRemoteDataPayload(),
|
|
).subscribe({
|
|
next: (res: PaginatedList<Subscription>) => {
|
|
if (res.pageInfo.totalElements > 0) {
|
|
this.showDeleteInfo$.next(true);
|
|
for (let subscription of res.page) {
|
|
const type = subscription.subscriptionType;
|
|
const subscriptionGroup: UntypedFormGroup = this.subscriptionForm.get(type) as UntypedFormGroup;
|
|
if (isNotEmpty(subscriptionGroup)) {
|
|
subscriptionGroup.controls.subscriptionId.setValue(subscription.id);
|
|
for (let parameter of subscription.subscriptionParameterList.filter((p) => p.name === 'frequency')) {
|
|
(subscriptionGroup.controls.frequencies as UntypedFormGroup).controls[parameter.value]?.setValue(true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
this.processing$.next(false);
|
|
},
|
|
error: err => {
|
|
this.processing$.next(false);
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Create/update subscriptions if needed
|
|
*/
|
|
submit() {
|
|
this.submitted = true;
|
|
const subscriptionTypes: string[] = Object.keys(this.subscriptionForm.controls);
|
|
const subscriptionsToBeCreated = [];
|
|
const subscriptionsToBeUpdated = [];
|
|
|
|
subscriptionTypes.forEach((subscriptionType: string) => {
|
|
const subscriptionGroup: UntypedFormGroup = this.subscriptionForm.controls[subscriptionType] as UntypedFormGroup;
|
|
if (subscriptionGroup.touched && subscriptionGroup.dirty) {
|
|
const body = this.createBody(
|
|
subscriptionGroup.controls.subscriptionId.value,
|
|
subscriptionType,
|
|
subscriptionGroup.controls.frequencies as UntypedFormGroup
|
|
);
|
|
|
|
if (isNotEmpty(body.id)) {
|
|
subscriptionsToBeUpdated.push(body);
|
|
} else if (isNotEmpty(body.subscriptionParameterList)) {
|
|
subscriptionsToBeCreated.push(body);
|
|
}
|
|
}
|
|
|
|
});
|
|
|
|
const toBeProcessed = [];
|
|
if (isNotEmpty(subscriptionsToBeCreated)) {
|
|
toBeProcessed.push(from(subscriptionsToBeCreated).pipe(
|
|
mergeMap((subscriptionBody) => {
|
|
return this.subscriptionService.createSubscription(subscriptionBody, this.ePersonId, this.dso.uuid).pipe(
|
|
getFirstCompletedRemoteData()
|
|
);
|
|
}),
|
|
tap((res: RemoteData<Subscription>) => {
|
|
if (res.hasSucceeded) {
|
|
const msg = this.translate.instant('subscriptions.modal.create.success', { type: res.payload.subscriptionType });
|
|
this.notificationsService.success(null, msg);
|
|
} else {
|
|
this.notificationsService.error(null, this.translate.instant('subscriptions.modal.create.error'));
|
|
}
|
|
})
|
|
));
|
|
}
|
|
|
|
if (isNotEmpty(subscriptionsToBeUpdated)) {
|
|
toBeProcessed.push(from(subscriptionsToBeUpdated).pipe(
|
|
mergeMap((subscriptionBody) => {
|
|
return this.subscriptionService.updateSubscription(subscriptionBody, this.ePersonId, this.dso.uuid).pipe(
|
|
getFirstCompletedRemoteData()
|
|
);
|
|
}),
|
|
tap((res: RemoteData<Subscription>) => {
|
|
if (res.hasSucceeded) {
|
|
const msg = this.translate.instant('subscriptions.modal.update.success', { type: res.payload.subscriptionType });
|
|
this.notificationsService.success(null, msg);
|
|
if (isNotEmpty(this.subscription)) {
|
|
this.updateSubscription.emit(res.payload);
|
|
}
|
|
} else {
|
|
this.notificationsService.error(null, this.translate.instant('subscriptions.modal.update.error'));
|
|
}
|
|
})
|
|
));
|
|
}
|
|
|
|
combineLatest([...toBeProcessed]).subscribe((res) => {
|
|
this.activeModal.close();
|
|
});
|
|
|
|
}
|
|
|
|
private createBody(subscriptionId: string, subscriptionType: string, frequencies: UntypedFormGroup): Partial<any> {
|
|
const body = {
|
|
id: (isNotEmpty(subscriptionId) ? subscriptionId : null),
|
|
subscriptionType: subscriptionType,
|
|
subscriptionParameterList: []
|
|
};
|
|
|
|
for (let frequency of this.frequencyDefaultValues) {
|
|
if (frequencies.value[frequency]) {
|
|
body.subscriptionParameterList.push(
|
|
{
|
|
name: 'frequency',
|
|
value: frequency,
|
|
}
|
|
);
|
|
}
|
|
}
|
|
|
|
return body;
|
|
}
|
|
|
|
}
|