mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-31 09:37:15 +01:00
Merged PR 660: TK Feature merge
Related work items: #10, #15, #16, #1591, #1592, #1604, #1611, #1617, #1618, #1628, #1632, #1637, #1644, #1655, #1676, #1681, #1682, #1683
This commit is contained in:
200
angular.json
200
angular.json
@@ -2096,6 +2096,206 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@page/task-calendar": {
|
||||
"projectType": "library",
|
||||
"root": "apps/page/task-calendar",
|
||||
"sourceRoot": "apps/page/task-calendar/src",
|
||||
"prefix": "page",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
"options": {
|
||||
"tsConfig": "apps/page/task-calendar/tsconfig.lib.json",
|
||||
"project": "apps/page/task-calendar/ng-package.json"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"tsConfig": "apps/page/task-calendar/tsconfig.lib.prod.json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "apps/page/task-calendar/src/test.ts",
|
||||
"tsConfig": "apps/page/task-calendar/tsconfig.spec.json",
|
||||
"karmaConfig": "apps/page/task-calendar/karma.conf.js"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"options": {
|
||||
"tsConfig": [
|
||||
"apps/page/task-calendar/tsconfig.lib.json",
|
||||
"apps/page/task-calendar/tsconfig.spec.json"
|
||||
],
|
||||
"exclude": [
|
||||
"**/node_modules/**"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@domain/task-calendar": {
|
||||
"projectType": "library",
|
||||
"root": "apps/domain/task-calendar",
|
||||
"sourceRoot": "apps/domain/task-calendar/src",
|
||||
"prefix": "lib",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
"options": {
|
||||
"tsConfig": "apps/domain/task-calendar/tsconfig.lib.json",
|
||||
"project": "apps/domain/task-calendar/ng-package.json"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"tsConfig": "apps/domain/task-calendar/tsconfig.lib.prod.json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "apps/domain/task-calendar/src/test.ts",
|
||||
"tsConfig": "apps/domain/task-calendar/tsconfig.spec.json",
|
||||
"karmaConfig": "apps/domain/task-calendar/karma.conf.js"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"options": {
|
||||
"tsConfig": [
|
||||
"apps/domain/task-calendar/tsconfig.lib.json",
|
||||
"apps/domain/task-calendar/tsconfig.spec.json"
|
||||
],
|
||||
"exclude": [
|
||||
"**/node_modules/**"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@ui/calendar": {
|
||||
"projectType": "library",
|
||||
"root": "apps/ui/calendar",
|
||||
"sourceRoot": "apps/ui/calendar/src",
|
||||
"prefix": "lib",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
"options": {
|
||||
"tsConfig": "apps/ui/calendar/tsconfig.lib.json",
|
||||
"project": "apps/ui/calendar/ng-package.json"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"tsConfig": "apps/ui/calendar/tsconfig.lib.prod.json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "apps/ui/calendar/src/test.ts",
|
||||
"tsConfig": "apps/ui/calendar/tsconfig.spec.json",
|
||||
"karmaConfig": "apps/ui/calendar/karma.conf.js"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"options": {
|
||||
"tsConfig": [
|
||||
"apps/ui/calendar/tsconfig.lib.json",
|
||||
"apps/ui/calendar/tsconfig.spec.json"
|
||||
],
|
||||
"exclude": [
|
||||
"**/node_modules/**"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@ui/notes": {
|
||||
"projectType": "library",
|
||||
"root": "apps/ui/notes",
|
||||
"sourceRoot": "apps/ui/notes/src",
|
||||
"prefix": "ui",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
"options": {
|
||||
"tsConfig": "apps/ui/notes/tsconfig.lib.json",
|
||||
"project": "apps/ui/notes/ng-package.json"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"tsConfig": "apps/ui/notes/tsconfig.lib.prod.json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "apps/ui/notes/src/test.ts",
|
||||
"tsConfig": "apps/ui/notes/tsconfig.spec.json",
|
||||
"karmaConfig": "apps/ui/notes/karma.conf.js"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"options": {
|
||||
"tsConfig": [
|
||||
"apps/ui/notes/tsconfig.lib.json",
|
||||
"apps/ui/notes/tsconfig.spec.json"
|
||||
],
|
||||
"exclude": [
|
||||
"**/node_modules/**"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@ui/tshirt": {
|
||||
"projectType": "library",
|
||||
"root": "apps/ui/tshirt",
|
||||
"sourceRoot": "apps/ui/tshirt/src",
|
||||
"prefix": "ui",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
"options": {
|
||||
"tsConfig": "apps/ui/tshirt/tsconfig.lib.json",
|
||||
"project": "apps/ui/tshirt/ng-package.json"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"tsConfig": "apps/ui/tshirt/tsconfig.lib.prod.json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "apps/ui/tshirt/src/test.ts",
|
||||
"tsConfig": "apps/ui/tshirt/tsconfig.spec.json",
|
||||
"karmaConfig": "apps/ui/tshirt/karma.conf.js"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"options": {
|
||||
"tsConfig": [
|
||||
"apps/ui/tshirt/tsconfig.lib.json",
|
||||
"apps/ui/tshirt/tsconfig.spec.json"
|
||||
],
|
||||
"exclude": [
|
||||
"**/node_modules/**"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"defaultProject": "sales"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ArticleDTO, DisplayInfoDTO, EISPublicDocumentService } from '@swagger/eis';
|
||||
import {
|
||||
CatalogPrintService,
|
||||
CheckoutPrintService,
|
||||
@@ -17,18 +17,17 @@ import { Printer } from './defs/printer.model';
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class PrinterService {
|
||||
export class DomainPrinterService {
|
||||
constructor(
|
||||
private printService: PrintService,
|
||||
private oMSPrintService: OMSPrintService,
|
||||
private catalogPrintService: CatalogPrintService,
|
||||
private checkoutPrintService: CheckoutPrintService,
|
||||
private http: HttpClient
|
||||
private eisPublicDocumentService: EISPublicDocumentService
|
||||
) {}
|
||||
|
||||
getAvailablePrinters(): Observable<Printer[] | { error: string }> {
|
||||
return this.printService.PrintPrinters().pipe(
|
||||
timeout(20000),
|
||||
catchError((error) => of({ error })),
|
||||
map((response: any) => {
|
||||
if (response.error && response.error.status === 503) {
|
||||
@@ -58,12 +57,9 @@ export class PrinterService {
|
||||
);
|
||||
}
|
||||
|
||||
getAvailablePrintersDev() {
|
||||
return this.http.get('http://127.0.0.1:5000/api/printers').pipe(
|
||||
timeout(20000),
|
||||
catchError((error) => {
|
||||
return of({ error });
|
||||
}),
|
||||
getAvailableOfficePrinters(): Observable<Printer[] | { error: string }> {
|
||||
return this.printService.PrintOfficePrinters().pipe(
|
||||
catchError((error) => of({ error })),
|
||||
map((response: any) => {
|
||||
if (response.error && response.error.status === 503) {
|
||||
return {
|
||||
@@ -78,6 +74,7 @@ export class PrinterService {
|
||||
error: response.message ? response.message : response.error.message ? response.error.message : 'Ein Fehler ist aufgetreten',
|
||||
};
|
||||
}
|
||||
|
||||
return response.result.map(
|
||||
(t) =>
|
||||
<Printer>{
|
||||
@@ -91,34 +88,28 @@ export class PrinterService {
|
||||
);
|
||||
}
|
||||
|
||||
async printOrder(orderIds: number[], printer: string): Promise<ResponseArgs> {
|
||||
printOrder({ orderIds, printer }: { orderIds: number[]; printer: string }): Observable<ResponseArgs> {
|
||||
const params = <any>{
|
||||
printer: printer,
|
||||
data: orderIds,
|
||||
};
|
||||
const response = await this.oMSPrintService.OMSPrintAbholscheinById(params).pipe(timeout(20000)).toPromise();
|
||||
|
||||
return response;
|
||||
return this.oMSPrintService.OMSPrintAbholscheinById(params).pipe(timeout(20000));
|
||||
}
|
||||
|
||||
async printProduct(item: ItemDTO, printer: string): Promise<ResponseArgs> {
|
||||
printProduct({ item, printer }: { item: ItemDTO; printer: string }): Observable<ResponseArgs> {
|
||||
const params = <PrintRequestOfIEnumerableOfItemDTO>{
|
||||
printer: printer,
|
||||
data: [item],
|
||||
};
|
||||
const response = await this.catalogPrintService.CatalogPrintArtikelDetail(params).pipe(timeout(20000)).toPromise();
|
||||
|
||||
return response;
|
||||
return this.catalogPrintService.CatalogPrintArtikelDetail(params).pipe(timeout(20000));
|
||||
}
|
||||
|
||||
async printCart(cartId: number, printer: string): Promise<ResponseArgs> {
|
||||
printCart({ cartId, printer }: { cartId: number; printer: string }): Observable<ResponseArgs> {
|
||||
const params = <any>{
|
||||
printer: printer,
|
||||
data: cartId,
|
||||
};
|
||||
const response = await this.checkoutPrintService.CheckoutPrintWarenkorbById(params).pipe(timeout(20000)).toPromise();
|
||||
|
||||
return response;
|
||||
return this.checkoutPrintService.CheckoutPrintWarenkorbById(params).pipe(timeout(20000));
|
||||
}
|
||||
|
||||
async printGoodsInLabel(subsetItemIds: number[]): Promise<ResponseArgs> {
|
||||
@@ -147,4 +138,35 @@ export class PrinterService {
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
printPdf({ printer, data }: { printer: string; data: string }) {
|
||||
return this.printService.PrintPrintPdf({
|
||||
printer,
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
printDisplayInfoDTOArticles({ articles, printer, title }: { articles: ArticleDTO[]; printer: string; title?: string }) {
|
||||
return this.eisPublicDocumentService
|
||||
.EISPublicDocumentGetArticlesPdfAsBase64({
|
||||
payload: { data: articles.map((article) => article.ean), title },
|
||||
})
|
||||
.pipe(switchMap((res) => this.printPdf({ printer, data: res.result })));
|
||||
}
|
||||
|
||||
printDisplayInfoDTOList({ displayInfos, printer, title }: { displayInfos: DisplayInfoDTO[]; printer: string; title?: string }) {
|
||||
return this.eisPublicDocumentService
|
||||
.EISPublicDocumentGetInfosPdfAsBase64({
|
||||
payload: { data: displayInfos, title },
|
||||
})
|
||||
.pipe(switchMap((res) => this.printPdf({ printer, data: res.result })));
|
||||
}
|
||||
|
||||
getDefaultPrinter({ printerType }: { printerType: 'Office' | 'Label' }): string {
|
||||
return localStorage.getItem(`Default_${printerType}_Printer`) ?? undefined;
|
||||
}
|
||||
|
||||
setDefaultPrinter({ printerType, printer }: { printerType: 'Office' | 'Label'; printer: string }): void {
|
||||
localStorage.setItem(`Default_${printerType}_Printer`, printer);
|
||||
}
|
||||
}
|
||||
|
||||
25
apps/domain/task-calendar/README.md
Normal file
25
apps/domain/task-calendar/README.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# TaskCalendar
|
||||
|
||||
This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 10.1.2.
|
||||
|
||||
## Code scaffolding
|
||||
|
||||
Run `ng generate component component-name --project task-calendar` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project task-calendar`.
|
||||
|
||||
> Note: Don't forget to add `--project task-calendar` or else it will be added to the default project in your `angular.json` file.
|
||||
|
||||
## Build
|
||||
|
||||
Run `ng build task-calendar` to build the project. The build artifacts will be stored in the `dist/` directory.
|
||||
|
||||
## Publishing
|
||||
|
||||
After building your library with `ng build task-calendar`, go to the dist folder `cd dist/task-calendar` and run `npm publish`.
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `ng test task-calendar` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
||||
|
||||
## Further help
|
||||
|
||||
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
|
||||
32
apps/domain/task-calendar/karma.conf.js
Normal file
32
apps/domain/task-calendar/karma.conf.js
Normal file
@@ -0,0 +1,32 @@
|
||||
// Karma configuration file, see link for more information
|
||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
basePath: '',
|
||||
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||
plugins: [
|
||||
require('karma-jasmine'),
|
||||
require('karma-chrome-launcher'),
|
||||
require('karma-jasmine-html-reporter'),
|
||||
require('karma-coverage-istanbul-reporter'),
|
||||
require('@angular-devkit/build-angular/plugins/karma'),
|
||||
],
|
||||
client: {
|
||||
clearContext: false, // leave Jasmine Spec Runner output visible in browser
|
||||
},
|
||||
coverageIstanbulReporter: {
|
||||
dir: require('path').join(__dirname, '../../../coverage/domain/task-calendar'),
|
||||
reports: ['html', 'lcovonly', 'text-summary'],
|
||||
fixWebpackSourcePaths: true,
|
||||
},
|
||||
reporters: ['progress', 'kjhtml'],
|
||||
port: 9876,
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
||||
autoWatch: true,
|
||||
browsers: ['Chrome'],
|
||||
singleRun: false,
|
||||
restartOnFileChange: true,
|
||||
});
|
||||
};
|
||||
7
apps/domain/task-calendar/ng-package.json
Normal file
7
apps/domain/task-calendar/ng-package.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json",
|
||||
"dest": "../../../dist/domain/task-calendar",
|
||||
"lib": {
|
||||
"entryFile": "src/public-api.ts"
|
||||
}
|
||||
}
|
||||
11
apps/domain/task-calendar/package.json
Normal file
11
apps/domain/task-calendar/package.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "@domain/task-calendar",
|
||||
"version": "0.0.1",
|
||||
"peerDependencies": {
|
||||
"@angular/common": "^10.1.2",
|
||||
"@angular/core": "^10.1.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": "^2.0.0"
|
||||
}
|
||||
}
|
||||
4
apps/domain/task-calendar/src/lib/defs/index.ts
Normal file
4
apps/domain/task-calendar/src/lib/defs/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
// start:ng42.barrel
|
||||
export * from './info.type';
|
||||
export * from './processing-status-list.type';
|
||||
// end:ng42.barrel
|
||||
1
apps/domain/task-calendar/src/lib/defs/info.type.ts
Normal file
1
apps/domain/task-calendar/src/lib/defs/info.type.ts
Normal file
@@ -0,0 +1 @@
|
||||
export type InfoType = 'Task' | 'Info' | 'PreInfo';
|
||||
@@ -0,0 +1,3 @@
|
||||
export type ProcessingStatusType = 'Approved' | 'InProcess' | 'Completed' | 'Overdue' | 'Archived';
|
||||
|
||||
export type ProcessingStatusList = ProcessingStatusType[];
|
||||
@@ -0,0 +1,8 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
|
||||
@NgModule({
|
||||
declarations: [],
|
||||
imports: [],
|
||||
exports: [],
|
||||
})
|
||||
export class TaskCalendarModule {}
|
||||
@@ -0,0 +1,16 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { TaskCalendarService } from './task-calendar.service';
|
||||
|
||||
describe('TaskCalendarService', () => {
|
||||
let service: TaskCalendarService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(TaskCalendarService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
||||
268
apps/domain/task-calendar/src/lib/task-calendar.service.ts
Normal file
268
apps/domain/task-calendar/src/lib/task-calendar.service.ts
Normal file
@@ -0,0 +1,268 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { DisplayInfoRequest, EISPublicService, FileDTO, ProcessingStatus, QueryTokenDTO } from '@swagger/eis';
|
||||
import { DateAdapter } from '@ui/common';
|
||||
import { memorize } from '@utils/common';
|
||||
import { combineLatest } from 'rxjs';
|
||||
import { map, shareReplay, switchMap } from 'rxjs/operators';
|
||||
import { InfoType, ProcessingStatusList } from './defs';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class DomainTaskCalendarService {
|
||||
readonly currentBranchId$ = this.eisPublicService.EISPublicGetCurrentBranch({}).pipe(
|
||||
map((response) => response.result?.id),
|
||||
shareReplay()
|
||||
);
|
||||
|
||||
constructor(private eisPublicService: EISPublicService, private dateAdapter: DateAdapter) {}
|
||||
|
||||
getFilters() {
|
||||
return this.eisPublicService.EISPublicQueryDisplayInfoFilter();
|
||||
}
|
||||
|
||||
getInfos(queryToken: QueryTokenDTO) {
|
||||
return this.eisPublicService.EISPublicQueryDisplayInfo({
|
||||
queryToken,
|
||||
});
|
||||
}
|
||||
|
||||
getInfoById({ infoId }: { infoId: number }) {
|
||||
return this.eisPublicService.EISPublicGetDisplayInfoById({
|
||||
infoId,
|
||||
});
|
||||
}
|
||||
|
||||
setToEdit({ infoId }: { infoId: number }) {
|
||||
return this.eisPublicService.EISPublicSetInfoToEdit({
|
||||
infoId,
|
||||
});
|
||||
}
|
||||
|
||||
complete({ infoId, file }: { infoId: number; file?: string | ArrayBuffer }) {
|
||||
let fileDTO: FileDTO;
|
||||
let _file: string;
|
||||
|
||||
if (typeof file === 'string') {
|
||||
_file = file;
|
||||
} else if (file instanceof ArrayBuffer) {
|
||||
_file = this.arrayBufferToString(file);
|
||||
}
|
||||
|
||||
if (_file) {
|
||||
fileDTO = {
|
||||
name: 'confirmation image',
|
||||
mime: this.parseMimeTypeFromBase64String(_file),
|
||||
content: this.removeMetaDataFromBase64(_file),
|
||||
};
|
||||
} else {
|
||||
fileDTO = {};
|
||||
}
|
||||
|
||||
return this.eisPublicService.EISPublicCompleteConfirmation({
|
||||
infoId,
|
||||
file: fileDTO,
|
||||
});
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
arrayBufferToString(arrayBuffer: ArrayBuffer): string {
|
||||
return String.fromCharCode.apply(null, new Uint16Array(arrayBuffer));
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
parseMimeTypeFromBase64String(base64: string): string {
|
||||
return base64.substring('data:'.length, base64.indexOf(';'));
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
removeMetaDataFromBase64(base64: string): string {
|
||||
const stringFromWhichToStart = 'base64,';
|
||||
return base64.substring(base64.indexOf(stringFromWhichToStart) + stringFromWhichToStart.length, base64.length);
|
||||
}
|
||||
|
||||
resetConfirmation({ infoId }: { infoId: number }) {
|
||||
return this.eisPublicService.EISPublicResetConfirmation({
|
||||
infoId,
|
||||
});
|
||||
}
|
||||
|
||||
@memorize({ ttl: 60000 })
|
||||
getFile({ fileId, download }: { fileId: number; download?: boolean }) {
|
||||
return this.eisPublicService
|
||||
.EISPublicGetFileContent({
|
||||
fileId,
|
||||
download,
|
||||
})
|
||||
.pipe(shareReplay());
|
||||
}
|
||||
|
||||
@memorize({ ttl: 60000 })
|
||||
getFiles({ infoId }: { infoId: number }) {
|
||||
return this.eisPublicService
|
||||
.EISPublicGetFiles({
|
||||
infoId,
|
||||
})
|
||||
.pipe(shareReplay());
|
||||
}
|
||||
|
||||
@memorize({ ttl: 60000 })
|
||||
getImageFiles({ infoId }: { infoId: number }) {
|
||||
return this.eisPublicService
|
||||
.EISPublicGetImages({
|
||||
infoId,
|
||||
})
|
||||
.pipe(shareReplay());
|
||||
}
|
||||
|
||||
@memorize({ ttl: 60000 })
|
||||
getTeaserFile({ infoId }: { infoId: number }) {
|
||||
return this.eisPublicService
|
||||
.EISPublicGetTeaserImage({
|
||||
infoId,
|
||||
})
|
||||
.pipe(shareReplay());
|
||||
}
|
||||
|
||||
getConfirmationFiles({ infoId }: { infoId: number }) {
|
||||
return this.currentBranchId$.pipe(
|
||||
switchMap((branchId) => this.eisPublicService.EISPublicGetConfirmationFilesByBranchId({ infoId, branchId }))
|
||||
);
|
||||
}
|
||||
|
||||
getArticles({ infoId }: { infoId: number }) {
|
||||
return this.eisPublicService.EISPublicGetArticles({
|
||||
infoId,
|
||||
});
|
||||
}
|
||||
|
||||
getProcessingStatusList({ processingStatus = 0 }: { processingStatus?: ProcessingStatus }): ProcessingStatusList {
|
||||
/**
|
||||
* ProcessingStatus
|
||||
* 1 = Approved
|
||||
* 2 = InProcess
|
||||
* 4 = Completed
|
||||
* 8 = Overdue
|
||||
* 16 = Archived
|
||||
*/
|
||||
const processingStatusList: ProcessingStatusList = [];
|
||||
|
||||
if (!!(processingStatus & 1)) {
|
||||
processingStatusList.push('Approved');
|
||||
}
|
||||
|
||||
if (!!(processingStatus & 2)) {
|
||||
processingStatusList.push('InProcess');
|
||||
}
|
||||
|
||||
if (!!(processingStatus & 4)) {
|
||||
processingStatusList.push('Completed');
|
||||
}
|
||||
|
||||
if (!!(processingStatus & 8)) {
|
||||
processingStatusList.push('Overdue');
|
||||
}
|
||||
|
||||
if (!!(processingStatus & 16)) {
|
||||
processingStatusList.push('Archived');
|
||||
}
|
||||
|
||||
return processingStatusList;
|
||||
}
|
||||
|
||||
getProcessingStatusColorCode({
|
||||
processingStatus,
|
||||
hasTask,
|
||||
publicationDate,
|
||||
announcementDate,
|
||||
}: {
|
||||
processingStatus?: ProcessingStatus;
|
||||
publicationDate?: string;
|
||||
announcementDate?: string;
|
||||
hasTask?: boolean;
|
||||
}) {
|
||||
const type = this.getInfoType({ hasTask, publicationDate, announcementDate });
|
||||
|
||||
if (type === ('Info' || 'PreInfo')) {
|
||||
return '#8A949E';
|
||||
}
|
||||
|
||||
const processingStatusList = this.getProcessingStatusList({ processingStatus });
|
||||
|
||||
if (processingStatusList.includes('Archived')) {
|
||||
return '#44942e';
|
||||
}
|
||||
|
||||
if (processingStatusList.includes('Completed')) {
|
||||
return '#44942e';
|
||||
}
|
||||
|
||||
if (processingStatusList.includes('InProcess')) {
|
||||
return '#FFCC01';
|
||||
}
|
||||
|
||||
if (processingStatusList.includes('Overdue')) {
|
||||
return '#f70400';
|
||||
}
|
||||
|
||||
if (processingStatusList.includes('Approved')) {
|
||||
return '#8A949E';
|
||||
}
|
||||
|
||||
return '#8A949E';
|
||||
}
|
||||
|
||||
getInfoType({
|
||||
hasTask,
|
||||
publicationDate,
|
||||
announcementDate,
|
||||
}: {
|
||||
publicationDate?: string;
|
||||
announcementDate?: string;
|
||||
hasTask?: boolean;
|
||||
}): InfoType {
|
||||
if (hasTask) {
|
||||
return 'Task';
|
||||
}
|
||||
|
||||
if (!publicationDate || !announcementDate) {
|
||||
return 'Info';
|
||||
}
|
||||
|
||||
const _publicationDate = new Date(publicationDate);
|
||||
const _announcmentDate = new Date(announcementDate);
|
||||
|
||||
return this.dateAdapter.compareDate(_announcmentDate, _publicationDate) > 0 ? 'PreInfo' : 'Info';
|
||||
}
|
||||
|
||||
getDisplayInfoDate(source: { taskDate?: string; publicationDate?: string; announcementDate?: string }) {
|
||||
// Wenn announcementDate abgelaufen ist wird der taskDate/publicationDate genommen
|
||||
let displayDate = new Date(source.taskDate || source.publicationDate);
|
||||
if (source.announcementDate && new Date(source.announcementDate) >= this.dateAdapter.today()) {
|
||||
displayDate = new Date(source.announcementDate);
|
||||
}
|
||||
|
||||
return displayDate;
|
||||
}
|
||||
|
||||
getComments({ infoId }: { infoId: number }) {
|
||||
return this.currentBranchId$.pipe(
|
||||
switchMap((branchId) =>
|
||||
this.eisPublicService.EISPublicGetCommentsByBranchId({
|
||||
branchId,
|
||||
infoId,
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
addComment({ infoId, text }: { infoId: number; text: string }) {
|
||||
return this.currentBranchId$.pipe(
|
||||
switchMap((branchId) =>
|
||||
this.eisPublicService.EISPublicAddComment({
|
||||
infoId,
|
||||
payload: { text, branch: { id: branchId } },
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
7
apps/domain/task-calendar/src/public-api.ts
Normal file
7
apps/domain/task-calendar/src/public-api.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
/*
|
||||
* Public API Surface of task-calendar
|
||||
*/
|
||||
|
||||
export * from './lib/task-calendar.service';
|
||||
export * from './lib/task-calendar.module';
|
||||
export * from './lib/defs';
|
||||
24
apps/domain/task-calendar/src/test.ts
Normal file
24
apps/domain/task-calendar/src/test.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
||||
|
||||
import 'zone.js/dist/zone';
|
||||
import 'zone.js/dist/zone-testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
declare const require: {
|
||||
context(
|
||||
path: string,
|
||||
deep?: boolean,
|
||||
filter?: RegExp
|
||||
): {
|
||||
keys(): string[];
|
||||
<T>(id: string): T;
|
||||
};
|
||||
};
|
||||
|
||||
// First, initialize the Angular testing environment.
|
||||
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting());
|
||||
// Then we find all the tests.
|
||||
const context = require.context('./', true, /\.spec\.ts$/);
|
||||
// And load the modules.
|
||||
context.keys().map(context);
|
||||
25
apps/domain/task-calendar/tsconfig.lib.json
Normal file
25
apps/domain/task-calendar/tsconfig.lib.json
Normal file
@@ -0,0 +1,25 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../out-tsc/lib",
|
||||
"target": "es2015",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"inlineSources": true,
|
||||
"types": [],
|
||||
"lib": [
|
||||
"dom",
|
||||
"es2018"
|
||||
]
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"skipTemplateCodegen": true,
|
||||
"strictMetadataEmit": true,
|
||||
"enableResourceInlining": true
|
||||
},
|
||||
"exclude": [
|
||||
"src/test.ts",
|
||||
"**/*.spec.ts"
|
||||
]
|
||||
}
|
||||
10
apps/domain/task-calendar/tsconfig.lib.prod.json
Normal file
10
apps/domain/task-calendar/tsconfig.lib.prod.json
Normal file
@@ -0,0 +1,10 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"extends": "./tsconfig.lib.json",
|
||||
"compilerOptions": {
|
||||
"declarationMap": false
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"enableIvy": false
|
||||
}
|
||||
}
|
||||
17
apps/domain/task-calendar/tsconfig.spec.json
Normal file
17
apps/domain/task-calendar/tsconfig.spec.json
Normal file
@@ -0,0 +1,17 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../out-tsc/spec",
|
||||
"types": [
|
||||
"jasmine"
|
||||
]
|
||||
},
|
||||
"files": [
|
||||
"src/test.ts"
|
||||
],
|
||||
"include": [
|
||||
"**/*.spec.ts",
|
||||
"**/*.d.ts"
|
||||
]
|
||||
}
|
||||
17
apps/domain/task-calendar/tslint.json
Normal file
17
apps/domain/task-calendar/tslint.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"extends": "../../../tslint.json",
|
||||
"rules": {
|
||||
"directive-selector": [
|
||||
true,
|
||||
"attribute",
|
||||
"lib",
|
||||
"camelCase"
|
||||
],
|
||||
"component-selector": [
|
||||
true,
|
||||
"element",
|
||||
"lib",
|
||||
"kebab-case"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||
import { PrinterComponent } from './modal-printer.component';
|
||||
|
||||
@Component({
|
||||
selector: 'modal-print-cart',
|
||||
templateUrl: 'modal-printer.component.html',
|
||||
styleUrls: ['modal-printer.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class PrintCartComponent extends PrinterComponent {
|
||||
async print() {
|
||||
this.loaded = false;
|
||||
const printResponse = await this.printerService.printCart(this.modalRef.data, this.selectedPrinterValue);
|
||||
|
||||
if (!printResponse.error) {
|
||||
this.modalRef.close();
|
||||
} else {
|
||||
this.setError(printResponse.message);
|
||||
}
|
||||
this.loaded = true;
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||
import { PrinterComponent } from './modal-printer.component';
|
||||
|
||||
@Component({
|
||||
selector: 'modal-print-order',
|
||||
templateUrl: 'modal-printer.component.html',
|
||||
styleUrls: ['modal-printer.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class PrintOrderComponent extends PrinterComponent {
|
||||
async print() {
|
||||
this.loaded = false;
|
||||
const printResponse = await this.printerService.printOrder(this.modalRef.data, this.selectedPrinterValue);
|
||||
|
||||
if (!printResponse.error) {
|
||||
this.modalRef.close();
|
||||
} else {
|
||||
this.setError(printResponse.message);
|
||||
}
|
||||
this.loaded = true;
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||
import { PrinterComponent } from './modal-printer.component';
|
||||
|
||||
@Component({
|
||||
selector: 'modal-print-product',
|
||||
templateUrl: 'modal-printer.component.html',
|
||||
styleUrls: ['modal-printer.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class PrintProductComponent extends PrinterComponent {
|
||||
async print() {
|
||||
this.loaded = false;
|
||||
const printResponse = await this.printerService.printProduct(this.modalRef.data, this.selectedPrinterValue);
|
||||
|
||||
if (!printResponse.error) {
|
||||
this.modalRef.close();
|
||||
} else {
|
||||
this.setError(printResponse.message);
|
||||
}
|
||||
this.loaded = true;
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@
|
||||
<div class="body">
|
||||
<ui-spinner [show]="!loaded">
|
||||
<ui-select class="select" [(ngModel)]="selectedPrinterValue">
|
||||
<ui-select-option *ngFor="let printer of printers" [label]="printer.text" [value]="printer.key"></ui-select-option>
|
||||
<ui-select-option *ngFor="let printer of printers$ | async" [label]="printer.text" [value]="printer.key"></ui-select-option>
|
||||
</ui-select>
|
||||
</ui-spinner>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
|
||||
import { Printer, PrinterService } from '@domain/printer';
|
||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core';
|
||||
import { Printer, DomainPrinterService } from '@domain/printer';
|
||||
import { UiModalRef } from '@ui/modal';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { Observable } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { PrintModalData } from './modal-printer.data';
|
||||
|
||||
@Component({
|
||||
selector: 'modal-print-cart',
|
||||
@@ -9,39 +11,50 @@ import { Subscription } from 'rxjs';
|
||||
styleUrls: ['modal-printer.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class PrinterComponent implements OnInit, OnDestroy {
|
||||
export class PrintModalComponent implements OnInit {
|
||||
protected selectedPrinterValue: string;
|
||||
printers: { key: string; text: string; selected: boolean }[] = [];
|
||||
printerSubscription: Subscription;
|
||||
printers$: Observable<{ key: string; text: string; selected: boolean }[]>;
|
||||
|
||||
error = false;
|
||||
errorMessage = 'Der Druckauftrag konnte nicht ausgeführt werden.';
|
||||
loaded = false;
|
||||
|
||||
constructor(protected printerService: PrinterService, public modalRef: UiModalRef, private cdr: ChangeDetectorRef) {}
|
||||
constructor(
|
||||
protected printerService: DomainPrinterService,
|
||||
public modalRef: UiModalRef<string, PrintModalData>,
|
||||
private cdr: ChangeDetectorRef
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.loadPrinters();
|
||||
}
|
||||
|
||||
loadPrinters() {
|
||||
let printerResult$: Observable<Printer[] | { error: string }>;
|
||||
this.loaded = false;
|
||||
this.error = false;
|
||||
|
||||
this.printerSubscription = this.printerService.getAvailablePrinters().subscribe((response) => {
|
||||
if ((response as { error: string }).error) {
|
||||
const errorResponse = response as { error: string };
|
||||
this.error = true;
|
||||
this.errorMessage = errorResponse.error;
|
||||
return;
|
||||
}
|
||||
if (this.modalRef.data.printerType === 'Office') {
|
||||
printerResult$ = this.printerService.getAvailableOfficePrinters();
|
||||
} else if (this.modalRef.data.printerType === 'Label') {
|
||||
printerResult$ = this.printerService.getAvailablePrinters();
|
||||
}
|
||||
this.printers$ = printerResult$.pipe(map((printers) => this.loadPrinterHelper(printers)));
|
||||
}
|
||||
|
||||
loadPrinterHelper(response: Printer[] | { error: string }): { key: string; text: string; selected: boolean }[] {
|
||||
if ((response as { error: string }).error) {
|
||||
const errorResponse = response as { error: string };
|
||||
this.error = true;
|
||||
this.errorMessage = errorResponse.error;
|
||||
} else {
|
||||
const result = response as Printer[];
|
||||
this.printers = result.map((t) => {
|
||||
const printers = result.map((t) => {
|
||||
return { key: t.key, text: t.description, selected: t.selected };
|
||||
});
|
||||
const selectedPrinter = this.printers.find((printer) => printer.selected);
|
||||
this.selectedPrinterValue = selectedPrinter ? selectedPrinter.key : this.printers[0].key;
|
||||
const defaultPrinter = this.printerService.getDefaultPrinter({ printerType: this.modalRef.data.printerType });
|
||||
const selectedPrinter = printers.find((printer) => (printer.selected || defaultPrinter ? printer.key === defaultPrinter : false));
|
||||
this.selectedPrinterValue = selectedPrinter ? selectedPrinter.key : printers[0].key;
|
||||
|
||||
this.error = false;
|
||||
this.loaded = true;
|
||||
@@ -51,7 +64,9 @@ export class PrinterComponent implements OnInit, OnDestroy {
|
||||
this.errorMessage = 'Keine Drucker verfügbar.';
|
||||
}
|
||||
this.cdr.markForCheck();
|
||||
});
|
||||
return printers;
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
setError(errorMessage?: string) {
|
||||
@@ -61,13 +76,15 @@ export class PrinterComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
print() {
|
||||
this.modalRef.close(this.selectedPrinterValue);
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
if (this.printerSubscription) {
|
||||
this.printerSubscription.unsubscribe();
|
||||
async print() {
|
||||
this.loaded = false;
|
||||
const printResponse = await this.modalRef.data.print(this.selectedPrinterValue);
|
||||
if (!printResponse.error) {
|
||||
this.printerService.setDefaultPrinter({ printerType: this.modalRef.data.printerType, printer: this.selectedPrinterValue });
|
||||
this.modalRef.close();
|
||||
} else {
|
||||
this.setError(printResponse.message);
|
||||
}
|
||||
this.loaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
4
apps/modal/printer/src/lib/modal-printer.data.ts
Normal file
4
apps/modal/printer/src/lib/modal-printer.data.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export interface PrintModalData {
|
||||
printerType: 'Office' | 'Label';
|
||||
print: (printer: string) => Promise<{ error?: boolean; message?: string } | null>;
|
||||
}
|
||||
@@ -5,14 +5,11 @@ import { UiIconModule } from '@ui/icon';
|
||||
import { UiModalModule } from '@ui/modal';
|
||||
import { UiSelectModule } from '@ui/select';
|
||||
import { UiSpinnerModule } from 'apps/ui/spinner/src/lib/ui-spinner.module';
|
||||
import { PrintCartComponent } from './modal-print-cart.component';
|
||||
import { PrintOrderComponent } from './modal-print-order.component';
|
||||
import { PrintProductComponent } from './modal-print-product.component';
|
||||
import { PrinterComponent } from './modal-printer.component';
|
||||
import { PrintModalComponent } from './modal-printer.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [PrinterComponent, PrintOrderComponent, PrintCartComponent, PrintProductComponent],
|
||||
declarations: [PrintModalComponent],
|
||||
imports: [CommonModule, FormsModule, UiModalModule, UiIconModule, UiSelectModule, UiSpinnerModule],
|
||||
exports: [PrinterComponent, PrintOrderComponent, PrintCartComponent, PrintProductComponent],
|
||||
exports: [PrintModalComponent],
|
||||
})
|
||||
export class ModalPrinterModule {}
|
||||
|
||||
@@ -4,6 +4,4 @@
|
||||
|
||||
export * from './lib/modal-printer.module';
|
||||
export * from './lib/modal-printer.component';
|
||||
export * from './lib/modal-print-product.component';
|
||||
export * from './lib/modal-print-cart.component';
|
||||
export * from './lib/modal-print-order.component';
|
||||
export * from './lib/modal-printer.data';
|
||||
|
||||
@@ -5,8 +5,8 @@ import { AvailabilityService } from '@domain/availability';
|
||||
import { DomainCheckoutService } from '@domain/checkout';
|
||||
import { AvailabilityDTO, DestinationDTO, ShoppingCartItemDTO } from '@swagger/checkout';
|
||||
import { UiMessageModalComponent, UiModalService } from '@ui/modal';
|
||||
import { PrintCartComponent } from '@modal/printer';
|
||||
import { first, map, shareReplay, switchMap, takeUntil, tap } from 'rxjs/operators';
|
||||
import { PrintModalData, PrintModalComponent } from '@modal/printer';
|
||||
import { first, map, shareReplay, switchMap, takeUntil } from 'rxjs/operators';
|
||||
import { SsoService } from 'sso';
|
||||
import { PurchasingOptionsModalComponent, PurchasingOptionsModalData } from '../modals/purchasing-options-modal';
|
||||
import { PurchasingOptions } from '../modals/purchasing-options-modal/purchasing-options-modal.store';
|
||||
@@ -14,6 +14,7 @@ import { Subject, NEVER } from 'rxjs';
|
||||
import { StringDictionary } from '@cmf/core';
|
||||
import { DomainCatalogService } from '@domain/catalog';
|
||||
import { BreadcrumbService } from '@core/breadcrumb';
|
||||
import { DomainPrinterService } from '@domain/printer';
|
||||
|
||||
@Component({
|
||||
selector: 'page-checkout-review',
|
||||
@@ -122,7 +123,8 @@ export class CheckoutReviewComponent {
|
||||
private router: Router,
|
||||
private cdr: ChangeDetectorRef,
|
||||
private domainCatalogService: DomainCatalogService,
|
||||
private breadcrumb: BreadcrumbService
|
||||
private breadcrumb: BreadcrumbService,
|
||||
private domainPrinterService: DomainPrinterService
|
||||
) {
|
||||
this.breadcrumb
|
||||
.getBreadcrumbsByKeyAndTag$(this.applicationService.activatedProcessId, 'checkout')
|
||||
@@ -308,8 +310,11 @@ export class CheckoutReviewComponent {
|
||||
async openPrintModal() {
|
||||
let shoppingCart = await this.shoppingCart$.pipe(first()).toPromise();
|
||||
this.uiModal.open({
|
||||
content: PrintCartComponent,
|
||||
data: shoppingCart.id,
|
||||
content: PrintModalComponent,
|
||||
data: {
|
||||
printerType: 'Office',
|
||||
print: (printer) => this.domainPrinterService.printCart({ cartId: shoppingCart.id, printer }).toPromise(),
|
||||
} as PrintModalData,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { DomainCheckoutService } from '@domain/checkout';
|
||||
import { UiModalService } from '@ui/modal';
|
||||
import { PrintOrderComponent } from '@modal/printer';
|
||||
import { PrintModalComponent, PrintModalData } from '@modal/printer';
|
||||
import { first, map, switchMap } from 'rxjs/operators';
|
||||
import { CrmCustomerService } from '@domain/crm';
|
||||
import { Router } from '@angular/router';
|
||||
@@ -10,6 +10,7 @@ import { DomainCatalogService } from '@domain/catalog';
|
||||
import { DisplayOrderItemDTO } from '@swagger/oms';
|
||||
import { BreadcrumbService } from '@core/breadcrumb';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { DomainPrinterService } from '@domain/printer';
|
||||
|
||||
@Component({
|
||||
selector: 'page-checkout-summary',
|
||||
@@ -84,7 +85,8 @@ export class CheckoutSummaryComponent {
|
||||
private omsService: OmsService,
|
||||
private uiModal: UiModalService,
|
||||
private breadcrumb: BreadcrumbService,
|
||||
private applicationService: ApplicationService
|
||||
private applicationService: ApplicationService,
|
||||
private domainPrinterService: DomainPrinterService
|
||||
) {
|
||||
this.breadcrumb
|
||||
.getBreadcrumbsByKeyAndTags$(this.applicationService.activatedProcessId, ['checkout'])
|
||||
@@ -104,8 +106,11 @@ export class CheckoutSummaryComponent {
|
||||
|
||||
openPrintModal(id: number) {
|
||||
this.uiModal.open({
|
||||
content: PrintOrderComponent,
|
||||
data: [id],
|
||||
content: PrintModalComponent,
|
||||
data: {
|
||||
printerType: 'Office',
|
||||
print: (printer) => this.domainPrinterService.printOrder({ orderIds: [id], printer }).toPromise(),
|
||||
} as PrintModalData,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
25
apps/page/task-calendar/README.md
Normal file
25
apps/page/task-calendar/README.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# TaskCalendar
|
||||
|
||||
This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 10.1.2.
|
||||
|
||||
## Code scaffolding
|
||||
|
||||
Run `ng generate component component-name --project task-calendar` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project task-calendar`.
|
||||
|
||||
> Note: Don't forget to add `--project task-calendar` or else it will be added to the default project in your `angular.json` file.
|
||||
|
||||
## Build
|
||||
|
||||
Run `ng build task-calendar` to build the project. The build artifacts will be stored in the `dist/` directory.
|
||||
|
||||
## Publishing
|
||||
|
||||
After building your library with `ng build task-calendar`, go to the dist folder `cd dist/task-calendar` and run `npm publish`.
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `ng test task-calendar` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
||||
|
||||
## Further help
|
||||
|
||||
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
|
||||
32
apps/page/task-calendar/karma.conf.js
Normal file
32
apps/page/task-calendar/karma.conf.js
Normal file
@@ -0,0 +1,32 @@
|
||||
// Karma configuration file, see link for more information
|
||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
basePath: '',
|
||||
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||
plugins: [
|
||||
require('karma-jasmine'),
|
||||
require('karma-chrome-launcher'),
|
||||
require('karma-jasmine-html-reporter'),
|
||||
require('karma-coverage-istanbul-reporter'),
|
||||
require('@angular-devkit/build-angular/plugins/karma'),
|
||||
],
|
||||
client: {
|
||||
clearContext: false, // leave Jasmine Spec Runner output visible in browser
|
||||
},
|
||||
coverageIstanbulReporter: {
|
||||
dir: require('path').join(__dirname, '../../../coverage/page/task-calendar'),
|
||||
reports: ['html', 'lcovonly', 'text-summary'],
|
||||
fixWebpackSourcePaths: true,
|
||||
},
|
||||
reporters: ['progress', 'kjhtml'],
|
||||
port: 9876,
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
||||
autoWatch: true,
|
||||
browsers: ['Chrome'],
|
||||
singleRun: false,
|
||||
restartOnFileChange: true,
|
||||
});
|
||||
};
|
||||
7
apps/page/task-calendar/ng-package.json
Normal file
7
apps/page/task-calendar/ng-package.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json",
|
||||
"dest": "../../../dist/page/task-calendar",
|
||||
"lib": {
|
||||
"entryFile": "src/public-api.ts"
|
||||
}
|
||||
}
|
||||
11
apps/page/task-calendar/package.json
Normal file
11
apps/page/task-calendar/package.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "@page/task-calendar",
|
||||
"version": "0.0.1",
|
||||
"peerDependencies": {
|
||||
"@angular/common": "^10.1.2",
|
||||
"@angular/core": "^10.1.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": "^2.0.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
<div class="info-header">
|
||||
<h5>
|
||||
{{ dayOfWeek }}
|
||||
</h5>
|
||||
<span class="muted">
|
||||
<ng-container *ngIf="checkSameDay(); else notToday">{{ date | date: 'EEEE, dd. MMMM yyyy' }}</ng-container>
|
||||
<ng-template #notToday>{{ date | date: 'dd. MMMM yyyy' }}</ng-template>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="info-body">
|
||||
<div class="time-span">{{ timeSpan }}</div>
|
||||
<div class="indicator" *ngIf="type$ | async; let type" [ngClass]="type">
|
||||
<div class="task-indicator" *ngIf="type === 'Task'" [style.backgroundColor]="indicatorColor$ | async"> </div>
|
||||
<ui-icon icon="info" size="16px" *ngIf="type !== 'Task'"></ui-icon>
|
||||
</div>
|
||||
<div class="teaser" *ngIf="teaser$ | async; let teaser">
|
||||
<img [isaBlobImage]="teaser" />
|
||||
</div>
|
||||
<div class="content">
|
||||
<div>{{ info.text | stripHtmlTags }}</div>
|
||||
<div class="task-date" *ngIf="showTaskDate">{{ taskDate }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ng-container *ngIf="info?.link">
|
||||
<hr />
|
||||
<div class="link">
|
||||
<div class="link-heading">Titelinformationen</div>
|
||||
<hr />
|
||||
<div class="link-item">
|
||||
<ui-icon icon="vlbtix" size="19px" *ngIf="showVlbtixIcon$ | async"></ui-icon>
|
||||
<div class="grow">Digitale Titelübersicht</div>
|
||||
|
||||
<button class="link-cta" type="button" (click)="openUrl(info.link)">
|
||||
Öffnen
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="info?.attachments > 0 || info?.articles?.length > 0">
|
||||
<hr />
|
||||
<div class="attachments">
|
||||
<div class="attachments-heading">Dateianhang</div>
|
||||
<hr />
|
||||
<ng-container *ngFor="let attachment of attachments$ | async">
|
||||
<div class="attachments-item">
|
||||
<ui-icon icon="attachment" size="19px"></ui-icon>
|
||||
<div class="grow">
|
||||
{{ attachment.name }}
|
||||
</div>
|
||||
|
||||
<button class="attachments-cta" type="button" (click)="openFile(attachment)">
|
||||
Öffnen
|
||||
</button>
|
||||
</div>
|
||||
<hr />
|
||||
</ng-container>
|
||||
<ng-container *ngIf="info?.articles?.length > 0">
|
||||
<div class="attachments-item">
|
||||
<ui-icon icon="attachment" size="19px"></ui-icon>
|
||||
<div class="grow">
|
||||
Artikelliste
|
||||
</div>
|
||||
|
||||
<button class="copy-article-cta" type="button" (click)="copyArticleList()">
|
||||
EAN-Liste kopieren
|
||||
</button>
|
||||
<button class="open-article-cta" type="button" (click)="openArticleList()">
|
||||
Öffnen
|
||||
</button>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="showNotes$ | async">
|
||||
<hr />
|
||||
<div class="notes">
|
||||
<div class="notes-heading">
|
||||
<div>Notizen</div>
|
||||
<div class="muted">{{ (notes$ | async)?.length }} Notizen</div>
|
||||
</div>
|
||||
<hr />
|
||||
<ui-notes [notes]="notes$ | async" (add)="addNote($event)" [value]="noteValue" (valueChange)="setNoteValue($event)"></ui-notes>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<hr *ngIf="(type$ | async) === 'Task'" />
|
||||
@@ -0,0 +1,107 @@
|
||||
:host {
|
||||
@apply flex flex-col;
|
||||
}
|
||||
|
||||
.info-header {
|
||||
@apply flex flex-row items-baseline;
|
||||
|
||||
h5 {
|
||||
@apply font-bold m-0 text-lg;
|
||||
}
|
||||
|
||||
.muted {
|
||||
@apply ml-4 text-cool-grey text-base font-semibold;
|
||||
}
|
||||
}
|
||||
|
||||
hr {
|
||||
@apply bg-disabled-branch h-px-2 -ml-4 my-4;
|
||||
width: calc(100% + 2rem);
|
||||
}
|
||||
|
||||
.info-body {
|
||||
@apply flex flex-row items-center;
|
||||
|
||||
.time-span {
|
||||
@apply text-lg font-bold mr-2 whitespace-nowrap;
|
||||
}
|
||||
|
||||
.indicator {
|
||||
@apply mx-2;
|
||||
|
||||
ui-icon {
|
||||
@apply text-cool-grey;
|
||||
}
|
||||
}
|
||||
|
||||
.task-indicator {
|
||||
@apply w-px-2 h-full;
|
||||
}
|
||||
|
||||
.indicator.Task {
|
||||
@apply mx-2 self-stretch;
|
||||
}
|
||||
|
||||
.teaser {
|
||||
@apply mx-2;
|
||||
|
||||
img {
|
||||
@apply h-px-50;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
@apply overflow-y-auto ml-2 font-semibold;
|
||||
max-height: 19rem;
|
||||
}
|
||||
|
||||
.time-frame {
|
||||
@apply mt-3;
|
||||
}
|
||||
}
|
||||
|
||||
.attachments,
|
||||
.notes,
|
||||
.link {
|
||||
@apply mt-3;
|
||||
|
||||
.attachments-heading,
|
||||
.notes-heading,
|
||||
.link-heading {
|
||||
@apply flex flex-row items-center text-lg font-bold;
|
||||
|
||||
.muted {
|
||||
@apply ml-4 text-cool-grey font-semibold;
|
||||
}
|
||||
}
|
||||
|
||||
.attachments-item,
|
||||
.link-item {
|
||||
@apply flex flex-row items-center text-lg;
|
||||
|
||||
ui-icon {
|
||||
@apply mr-3 text-cool-grey;
|
||||
}
|
||||
|
||||
.attachments-cta,
|
||||
.copy-article-cta,
|
||||
.open-article-cta,
|
||||
.link-cta {
|
||||
@apply bg-transparent justify-self-end border-none outline-none text-brand text-cta-l font-bold p-0;
|
||||
}
|
||||
|
||||
.copy-article-cta {
|
||||
@apply mr-7;
|
||||
}
|
||||
}
|
||||
|
||||
.link-item {
|
||||
ui-icon {
|
||||
@apply mt-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.grow {
|
||||
@apply flex-grow;
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
import { Clipboard } from '@angular/cdk/clipboard';
|
||||
import { DatePipe } from '@angular/common';
|
||||
import { Component, ChangeDetectionStrategy, Input, OnChanges, SimpleChanges, Optional } from '@angular/core';
|
||||
import { DomainTaskCalendarService } from '@domain/task-calendar';
|
||||
import { FileDTO } from '@swagger/checkout';
|
||||
import { DisplayInfoDTO } from '@swagger/eis';
|
||||
import { DateAdapter } from '@ui/common';
|
||||
import { UiModalRef, UiModalService } from '@ui/modal';
|
||||
import { isNullOrUndefined } from '@utils/common';
|
||||
import { combineLatest, ReplaySubject, Subject } from 'rxjs';
|
||||
import { catchError, filter, first, map, startWith, switchMap } from 'rxjs/operators';
|
||||
import { ArticleListModalComponent } from '../../modals/article-list/article-list-modal.component';
|
||||
import { ImageViewerModalComponent } from '../../modals/image-viewer/image-viewer-modal.component';
|
||||
import { ImageViewerModalData } from '../../modals/image-viewer/image-viewer-modal.data';
|
||||
import { PdfViewerModalComponent } from '../../modals/pdf-viewer/pdf-viewer-modal.component';
|
||||
import { PdfViewerModalData } from '../../modals/pdf-viewer/pdf-viewer-modal.data';
|
||||
import { WebViewerModalComponent } from '../../modals/web-viewer/web-viewer-modal.component';
|
||||
|
||||
@Component({
|
||||
selector: 'page-task-info',
|
||||
templateUrl: 'task-info.component.html',
|
||||
styleUrls: ['task-info.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class TaskInfoComponent implements OnChanges {
|
||||
@Input()
|
||||
info: DisplayInfoDTO;
|
||||
|
||||
@Input()
|
||||
showTaskDate: boolean;
|
||||
|
||||
get dayOfWeek() {
|
||||
if (this.checkSameDay()) {
|
||||
return 'Heute';
|
||||
}
|
||||
return this.datePipe.transform(this.date, 'EEEE');
|
||||
}
|
||||
|
||||
get date(): Date {
|
||||
const taskDate = this.info.taskDate;
|
||||
const publicationDate = this.info.publicationDate;
|
||||
const announcementDate = this.info.announcementDate;
|
||||
return this.domainTaskCalendarService.getDisplayInfoDate({ taskDate, publicationDate, announcementDate });
|
||||
}
|
||||
|
||||
get timeSpan(): string {
|
||||
if (this.info?.timeFrom && this.info?.timeTo) {
|
||||
const dateFrom = new Date(this.info?.timeFrom);
|
||||
const dateTo = new Date(this.info?.timeTo);
|
||||
return `${this.datePipe.transform(dateFrom, 'HH:mm')} - ${this.datePipe.transform(dateTo, 'HH:mm')}`;
|
||||
}
|
||||
return 'Ganztägig';
|
||||
}
|
||||
|
||||
get taskDate(): string {
|
||||
if (this.info?.taskDate && this.info?.taskOverdueDate) {
|
||||
const dateFrom = new Date(this.info?.taskDate);
|
||||
const dateTo = new Date(this.info?.taskOverdueDate);
|
||||
return `${this.datePipe.transform(dateFrom, 'dd.MM.yy HH:mm')} Uhr bis ${this.datePipe.transform(dateTo, 'dd.MM.yy HH:mm')} Uhr`;
|
||||
}
|
||||
}
|
||||
|
||||
get noteValue() {
|
||||
return sessionStorage.getItem(`INFO_NOTE_${this.info?.id}`) || '';
|
||||
}
|
||||
|
||||
private info$ = new ReplaySubject<DisplayInfoDTO>();
|
||||
|
||||
showVlbtixIcon$ = this.info$.pipe(map((info) => (info?.link ? new URL(info.link).hostname === 'www.vlbtix.de' : false)));
|
||||
|
||||
teaser$ = this.info$.pipe(
|
||||
filter((info) => !isNullOrUndefined(info)),
|
||||
switchMap((info) => this.domainTaskCalendarService.getTeaserFile({ infoId: info.id }).pipe(catchError((error) => [undefined])))
|
||||
);
|
||||
|
||||
attachments$ = this.info$.pipe(
|
||||
filter((info) => info.attachments > 0),
|
||||
switchMap((info) => this.domainTaskCalendarService.getFiles({ infoId: info.id })),
|
||||
map((response) => response.result)
|
||||
);
|
||||
|
||||
type$ = this.info$.pipe(map((info) => this.domainTaskCalendarService.getInfoType(info)));
|
||||
|
||||
showNotes$ = this.type$.pipe(map((type) => type === 'Info' || type === 'Task'));
|
||||
|
||||
indicatorColor$ = this.info$.pipe(map((info) => this.domainTaskCalendarService.getProcessingStatusColorCode(info)));
|
||||
|
||||
private noteAdded$ = new Subject();
|
||||
|
||||
notes$ = combineLatest([this.info$, this.noteAdded$.pipe(startWith([undefined]))]).pipe(
|
||||
switchMap(([info]) => this.domainTaskCalendarService.getComments({ infoId: info.id })),
|
||||
map((res) =>
|
||||
res.result.map((comment) => ({
|
||||
date: new Date(comment.created),
|
||||
note: comment.text,
|
||||
}))
|
||||
)
|
||||
);
|
||||
|
||||
constructor(
|
||||
private dateAdapter: DateAdapter,
|
||||
private datePipe: DatePipe,
|
||||
private domainTaskCalendarService: DomainTaskCalendarService,
|
||||
private uiModal: UiModalService,
|
||||
private clipboard: Clipboard,
|
||||
@Optional() private modalRef: UiModalRef
|
||||
) {}
|
||||
|
||||
ngOnChanges({ info }: SimpleChanges): void {
|
||||
if (info) {
|
||||
this.info$.next(this.info);
|
||||
}
|
||||
}
|
||||
|
||||
setNoteValue(note: string) {
|
||||
sessionStorage.setItem(`INFO_NOTE_${this.info?.id}`, note);
|
||||
}
|
||||
|
||||
async openFile(file: FileDTO) {
|
||||
const content = await this.domainTaskCalendarService.getFile({ fileId: file.id }).toPromise();
|
||||
|
||||
// TODO: Logik um den richtigen Dialog zu öffnen
|
||||
if (file.mime === 'application/pdf') {
|
||||
this.uiModal.open({
|
||||
content: PdfViewerModalComponent,
|
||||
data: {
|
||||
file,
|
||||
content,
|
||||
} as PdfViewerModalData,
|
||||
});
|
||||
} else if (['image/gif', 'image/jpeg', 'image/png', 'image/svg+xml'].includes(file.mime)) {
|
||||
this.uiModal.open({
|
||||
content: ImageViewerModalComponent,
|
||||
data: {
|
||||
file,
|
||||
content,
|
||||
} as ImageViewerModalData,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
copyArticleList() {
|
||||
const eanString = this.info.articles.map((article) => article.data.ean).join(',');
|
||||
this.clipboard.copy(eanString);
|
||||
}
|
||||
|
||||
checkSameDay(): boolean {
|
||||
return this.dateAdapter.equals(this.date, this.dateAdapter.today());
|
||||
}
|
||||
|
||||
async openArticleList() {
|
||||
const articleListModal = this.uiModal.open({
|
||||
content: ArticleListModalComponent,
|
||||
data: this.info,
|
||||
});
|
||||
const result = await articleListModal.afterClosed$.pipe(first()).toPromise();
|
||||
if (result.data === 'closeAll') {
|
||||
this.modalRef?.close();
|
||||
}
|
||||
}
|
||||
|
||||
openUrl(url: string) {
|
||||
this.uiModal.open({
|
||||
content: WebViewerModalComponent,
|
||||
data: url,
|
||||
config: {
|
||||
width: '1120px',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async addNote(note: string) {
|
||||
await this.domainTaskCalendarService.addComment({ infoId: this.info.id, text: note }).toPromise();
|
||||
sessionStorage.removeItem(`INFO_NOTE_${this.info?.id}`);
|
||||
this.noteAdded$.next();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { TaskInfoComponent } from './task-info.component';
|
||||
import { UiCommonModule } from '@ui/common';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
import { ClipboardModule } from '@angular/cdk/clipboard';
|
||||
import { UiNotesModule } from 'apps/ui/notes/src/lib/ui-notes.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, UiCommonModule, UiIconModule, ClipboardModule, UiNotesModule],
|
||||
exports: [TaskInfoComponent],
|
||||
declarations: [TaskInfoComponent],
|
||||
})
|
||||
export class TaskInfoModule {}
|
||||
@@ -1,5 +1,4 @@
|
||||
// start:ng42.barrel
|
||||
export * from './task-list-header.component';
|
||||
export * from './task-list-item.component';
|
||||
export * from './task-list.component';
|
||||
export * from './task-list.module';
|
||||
@@ -0,0 +1,29 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
import { DomainTaskCalendarService, ProcessingStatusList } from '@domain/task-calendar';
|
||||
import { DisplayInfoDTO } from '@swagger/eis';
|
||||
|
||||
@Pipe({
|
||||
name: 'filterStatus',
|
||||
})
|
||||
export class FilterStatusPipe implements PipeTransform {
|
||||
constructor(private domainTaskCalendarService: DomainTaskCalendarService) {}
|
||||
|
||||
transform(items: DisplayInfoDTO[], includes: ProcessingStatusList = [], excludes: ProcessingStatusList = []): DisplayInfoDTO[] {
|
||||
return items?.filter((item) => {
|
||||
const processingStatus = this.domainTaskCalendarService.getProcessingStatusList(item);
|
||||
let isIncluded = false;
|
||||
let isExcluded = false;
|
||||
for (const include of includes) {
|
||||
isIncluded = processingStatus.includes(include);
|
||||
// Early Exit
|
||||
if (!isIncluded) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (const exclude of excludes) {
|
||||
isExcluded = !processingStatus.includes(exclude);
|
||||
}
|
||||
return isIncluded && !isExcluded;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
import { DomainTaskCalendarService, InfoType } from '@domain/task-calendar';
|
||||
import { DisplayInfoDTO } from '@swagger/eis';
|
||||
import { isArray } from '@utils/common';
|
||||
|
||||
@Pipe({
|
||||
name: 'filterType',
|
||||
})
|
||||
export class FilterTypePipe implements PipeTransform {
|
||||
constructor(private domainTaskCalendarService: DomainTaskCalendarService) {}
|
||||
|
||||
transform(items: DisplayInfoDTO[], types: InfoType[]): any {
|
||||
return items?.filter((item) => {
|
||||
const type = this.domainTaskCalendarService.getInfoType(item);
|
||||
return types.includes(type);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
// start:ng42.barrel
|
||||
export * from './filter-status.pipe';
|
||||
export * from './filter-type.pipe';
|
||||
// end:ng42.barrel
|
||||
@@ -0,0 +1,32 @@
|
||||
<div class="date">
|
||||
<ng-container *ngIf="showDate">
|
||||
{{ item?.taskDate || item?.publicationDate | date }}
|
||||
</ng-container>
|
||||
<ng-container *ngIf="!showDate">
|
||||
<ng-container [ngSwitch]="showTime$ | async">
|
||||
<ng-container *ngSwitchCase="true"> {{ item?.timeFrom | date: 'HH:mm' }} - {{ item?.timeTo | date: 'HH:mm' }} </ng-container>
|
||||
<ng-container *ngSwitchCase="false">
|
||||
Ganztägig
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</div>
|
||||
<ng-container *ngIf="itemType$ | async; let itemType">
|
||||
<div class="indicator" *ngIf="isTask$ | async" [style.backgroundColor]="indicatorColor$ | async"></div>
|
||||
<div class="icon" *ngIf="hasIcon$ | async">
|
||||
<ui-icon icon="info" *ngIf="isInfoOrPreInfo$ | async" size="16px"></ui-icon>
|
||||
<ui-icon icon="calendar" size="16px" *ngIf="isPreInfo$ | async"></ui-icon>
|
||||
<ui-icon icon="chat" size="16px" *ngIf="hasComments$ | async"></ui-icon>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<ui-tshirt class="shirt-size" *ngIf="item?.effort" [effort]="item?.effort"></ui-tshirt>
|
||||
<div class="task-content">
|
||||
<div class="task-content-title">
|
||||
<b>{{ item?.title }}</b>
|
||||
<ui-icon class="icon" icon="camera" size="16px" *ngIf="item.requiresImageOnConfirmation"></ui-icon>
|
||||
<ui-icon class="icon" icon="attachment" size="16px" *ngIf="hasAttachments$ | async"></ui-icon>
|
||||
</div>
|
||||
|
||||
<div>{{ item?.text | stripHtmlTags | substr: 70 }}</div>
|
||||
</div>
|
||||
@@ -0,0 +1,34 @@
|
||||
:host {
|
||||
@apply flex flex-row px-4 py-3;
|
||||
|
||||
.date {
|
||||
@apply text-right font-bold mr-2 self-start w-24;
|
||||
}
|
||||
|
||||
.indicator {
|
||||
@apply w-px-2 bg-gray-100 self-stretch mx-4;
|
||||
}
|
||||
|
||||
.icon {
|
||||
@apply mx-2 self-start mt-px-3 text-inactive-branch flex flex-row;
|
||||
ui-icon + ui-icon {
|
||||
@apply ml-2;
|
||||
}
|
||||
}
|
||||
|
||||
.indicator + .icon {
|
||||
@apply ml-0;
|
||||
}
|
||||
|
||||
.shirt-size {
|
||||
@apply mx-2 mt-px-3;
|
||||
}
|
||||
|
||||
.task-content {
|
||||
@apply flex flex-col ml-2;
|
||||
|
||||
.task-content-title {
|
||||
@apply flex flex-row;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
import { Component, ChangeDetectionStrategy, Input, OnChanges, SimpleChanges, HostBinding } from '@angular/core';
|
||||
import { DomainTaskCalendarService } from '@domain/task-calendar';
|
||||
import { DisplayInfoDTO } from '@swagger/eis';
|
||||
import { combineLatest, ReplaySubject } from 'rxjs';
|
||||
import { catchError, map, shareReplay, switchMap } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'page-task-list-item',
|
||||
templateUrl: 'task-list-item.component.html',
|
||||
styleUrls: ['task-list-item.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class TaskListItemComponent implements OnChanges {
|
||||
@Input()
|
||||
item: DisplayInfoDTO;
|
||||
|
||||
@Input()
|
||||
showDate = true;
|
||||
|
||||
item$ = new ReplaySubject<DisplayInfoDTO>();
|
||||
|
||||
itemType$ = this.item$.pipe(
|
||||
map((item) => this.domainTaskCalendarService.getInfoType(item)),
|
||||
shareReplay()
|
||||
);
|
||||
|
||||
isPreInfo$ = this.itemType$.pipe(map((type) => type === 'PreInfo'));
|
||||
|
||||
isTask$ = this.itemType$.pipe(map((type) => type === 'Task'));
|
||||
|
||||
isInfo$ = this.itemType$.pipe(map((type) => type === 'Info'));
|
||||
|
||||
isInfoOrPreInfo$ = combineLatest([this.isInfo$, this.isPreInfo$]).pipe(map(([info, preInfo]) => info || preInfo));
|
||||
|
||||
hasComments$ = this.item$.pipe(map((item) => item.comments > 0));
|
||||
|
||||
hasIcon$ = combineLatest([this.isInfoOrPreInfo$, this.hasComments$]).pipe(map(([infoOrPreInfo, comments]) => infoOrPreInfo || comments));
|
||||
|
||||
indicatorColor$ = this.item$.pipe(map((item) => this.domainTaskCalendarService.getProcessingStatusColorCode(item)));
|
||||
|
||||
hasAttachments$ = this.item$.pipe(map((info) => info.attachments > 0 || info.articles?.length > 0));
|
||||
|
||||
showTime$ = this.item$.pipe(map((item) => !!item?.timeFrom && !!item?.timeTo));
|
||||
|
||||
@HostBinding('class')
|
||||
get completed() {
|
||||
return this.domainTaskCalendarService.getProcessingStatusList(this.item);
|
||||
}
|
||||
|
||||
constructor(private domainTaskCalendarService: DomainTaskCalendarService) {}
|
||||
|
||||
ngOnChanges({ item }: SimpleChanges): void {
|
||||
if (item) {
|
||||
this.item$.next(this.item);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<!-- <div class="task-list overdue-list" *ngIf="items | filterType: ['Task'] | filterStatus: ['Overdue']; let overdieItems"> -->
|
||||
<div class="task-list overdue-list" *ngIf="overdueItems$ | async; let overdieItems">
|
||||
<div class="head-row">
|
||||
<h4>Überfällig</h4>
|
||||
<span class="muted"> {{ overdieItems?.length }} Aufgaben </span>
|
||||
</div>
|
||||
<hr />
|
||||
<ng-container *ngFor="let item of overdieItems">
|
||||
<page-task-list-item [item]="item" (click)="select.emit(item)"></page-task-list-item>
|
||||
<hr />
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
<ng-container *ngIf="selectedItems$ | async; let itemsForSelectedDate">
|
||||
<div class="task-list today-list" *ngIf="itemsForSelectedDate?.length">
|
||||
<div class="head-row">
|
||||
<div class="head-row-title">
|
||||
<h4>{{ selected | date: 'EEEE' }}</h4>
|
||||
<div class="muted">{{ selected | date }}</div>
|
||||
</div>
|
||||
<div class="head-row-info">
|
||||
<button (click)="print()" type="button" class="cta-print">Drucken</button>
|
||||
<span class="muted"> {{ itemsForSelectedDate?.length }} Aufgaben und Infos </span>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<ng-container *ngFor="let item of itemsForSelectedDate">
|
||||
<page-task-list-item [item]="item" (click)="select.emit(item)" [showDate]="false"></page-task-list-item>
|
||||
<hr />
|
||||
</ng-container>
|
||||
</div>
|
||||
</ng-container>
|
||||
@@ -0,0 +1,44 @@
|
||||
:host {
|
||||
@apply flex flex-col box-border;
|
||||
}
|
||||
|
||||
.task-list {
|
||||
@apply pt-6;
|
||||
|
||||
.head-row {
|
||||
@apply flex flex-row justify-between items-baseline px-4 py-3;
|
||||
|
||||
.head-row-title {
|
||||
@apply flex flex-row self-end;
|
||||
|
||||
.muted {
|
||||
@apply ml-4 self-end;
|
||||
}
|
||||
}
|
||||
|
||||
.head-row-info {
|
||||
@apply flex flex-col text-right;
|
||||
|
||||
.cta-print {
|
||||
@apply border-none outline-none bg-transparent text-brand text-cta-l font-bold pr-0 mb-3;
|
||||
}
|
||||
}
|
||||
|
||||
h4 {
|
||||
@apply m-0;
|
||||
}
|
||||
|
||||
.muted {
|
||||
@apply text-active-branch font-semibold text-sm;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.task-list.today-list ::ng-deep page-task-list-item.Completed {
|
||||
.date,
|
||||
.icon,
|
||||
.shirt-size,
|
||||
.task-content {
|
||||
@apply opacity-30;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
import { DatePipe } from '@angular/common';
|
||||
import {
|
||||
Component,
|
||||
ChangeDetectionStrategy,
|
||||
Input,
|
||||
EventEmitter,
|
||||
Output,
|
||||
OnChanges,
|
||||
SimpleChanges,
|
||||
ChangeDetectorRef,
|
||||
} from '@angular/core';
|
||||
import { DomainPrinterService } from '@domain/printer';
|
||||
import { DomainTaskCalendarService, ProcessingStatusList } from '@domain/task-calendar';
|
||||
import { PrintModalComponent, PrintModalData } from '@modal/printer';
|
||||
import { DisplayInfoDTO } from '@swagger/eis';
|
||||
import { DateAdapter } from '@ui/common';
|
||||
import { UiModalService } from '@ui/modal';
|
||||
import { BehaviorSubject, combineLatest } from 'rxjs';
|
||||
import { first, map, tap } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'page-task-list',
|
||||
templateUrl: 'task-list.component.html',
|
||||
styleUrls: ['task-list.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class TaskListComponent {
|
||||
today = this.dateAdapter.today();
|
||||
|
||||
/* @internal */
|
||||
items$ = new BehaviorSubject<DisplayInfoDTO[]>([]);
|
||||
|
||||
@Input()
|
||||
get items() {
|
||||
return this.items$.value;
|
||||
}
|
||||
set items(value) {
|
||||
this.items$.next(value);
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
selected$ = new BehaviorSubject<Date>(new Date());
|
||||
|
||||
@Input()
|
||||
get selected() {
|
||||
return this.selected$.value;
|
||||
}
|
||||
set selected(value) {
|
||||
if (this.selected !== value) {
|
||||
this.selected$.next(value);
|
||||
}
|
||||
}
|
||||
|
||||
overdueItems$ = this.items$.pipe(
|
||||
map((items) => {
|
||||
const last7Days = this.dateAdapter.addCalendarDays(this.today, -7);
|
||||
items.filter((item) => {
|
||||
const type = this.domainTaskCalendarService.getInfoType(item);
|
||||
const processingStatus = this.domainTaskCalendarService.getProcessingStatusList(item);
|
||||
if (type === 'Task' && processingStatus.includes('Overdue')) {
|
||||
return new Date(item.taskDate || item.publicationDate) >= last7Days;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
selectedItems$ = combineLatest([this.items$, this.selected$]).pipe(
|
||||
map(([items, date]) =>
|
||||
items.filter(
|
||||
(item) => (item.taskDate || item.publicationDate) && this.dateAdapter.equals(new Date(item.taskDate || item.publicationDate), date)
|
||||
)
|
||||
),
|
||||
// Sortierung der aufgaben nach Rot => Gelb => Grau => Grün
|
||||
map((list) => this.sort(list, ['Overdue', 'InProcess', 'Approved', 'Completed']))
|
||||
);
|
||||
|
||||
@Output()
|
||||
select = new EventEmitter<DisplayInfoDTO>();
|
||||
|
||||
constructor(
|
||||
private dateAdapter: DateAdapter,
|
||||
private datePipe: DatePipe,
|
||||
private domainTaskCalendarService: DomainTaskCalendarService,
|
||||
private uiModal: UiModalService,
|
||||
private domainPrinterService: DomainPrinterService
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Returns an Array of DisplayInfoDTO, sorted by ProcessingStatus
|
||||
* Ignores Overdue if Task is already Completed
|
||||
* Compared DisploayInfoDTO is of Type Task and Info Or PreInfo then sort by Type
|
||||
* @param items DisplayInfoDTO Array to sort
|
||||
* @param order Processing Status Order
|
||||
* @returns DisplayInfoDTO Array ordered by Processing Status anf Type
|
||||
*/
|
||||
sort(items: DisplayInfoDTO[], order: ProcessingStatusList) {
|
||||
let result = [...items];
|
||||
|
||||
for (const status of [...order].reverse()) {
|
||||
result = result?.sort((a, b) => {
|
||||
const statusA = this.domainTaskCalendarService.getProcessingStatusList(a);
|
||||
const statusB = this.domainTaskCalendarService.getProcessingStatusList(b);
|
||||
|
||||
// Ignore Overdue when it is already Completed
|
||||
if (status === 'Overdue' && statusA.includes('Completed')) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const aHasStatus = statusA.includes(status);
|
||||
const bHasStatus = statusB.includes(status);
|
||||
|
||||
if (aHasStatus && bHasStatus) {
|
||||
// If it has the same ProcessingStatus then Sort by Type
|
||||
const aType = this.domainTaskCalendarService.getInfoType(a);
|
||||
const bType = this.domainTaskCalendarService.getInfoType(b);
|
||||
if (aType !== bType) {
|
||||
if (aType === 'Info' || aType === 'PreInfo') {
|
||||
return -1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
} else if (aHasStatus && !bHasStatus) {
|
||||
return -1;
|
||||
} else if (!aHasStatus && bHasStatus) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
async print() {
|
||||
const displayInfos = await this.selectedItems$.pipe(first()).toPromise();
|
||||
this.uiModal.open({
|
||||
content: PrintModalComponent,
|
||||
data: {
|
||||
printerType: 'Office',
|
||||
print: (printer) =>
|
||||
this.domainPrinterService
|
||||
.printDisplayInfoDTOList({
|
||||
displayInfos,
|
||||
printer,
|
||||
title: `Tätigkeitskalender \n Liste für ${this.datePipe.transform(this.selected, 'EEEE, dd. MMMM yyyy')}`,
|
||||
})
|
||||
.toPromise(),
|
||||
} as PrintModalData,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { TaskListComponent } from './task-list.component';
|
||||
import { TaskListItemComponent } from './task-list-item.component';
|
||||
import { FilterStatusPipe, FilterTypePipe } from './pipes';
|
||||
import { UiCommonModule } from '@ui/common';
|
||||
import { UiTshirtModule } from '@ui/tshirt';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, UiCommonModule, UiTshirtModule, UiIconModule],
|
||||
exports: [TaskListComponent],
|
||||
declarations: [TaskListComponent, TaskListItemComponent, FilterStatusPipe, FilterTypePipe],
|
||||
})
|
||||
export class TaskListModule {}
|
||||
@@ -0,0 +1,17 @@
|
||||
<ui-selected-filter-options
|
||||
*ngIf="!!selectedFilters"
|
||||
[(value)]="selectedFilters"
|
||||
[initialFilter]="initialFilter"
|
||||
(valueChange)="updateFilter($event)"
|
||||
>
|
||||
</ui-selected-filter-options>
|
||||
|
||||
<ui-filter-group *ngIf="!!selectedFilters" [(value)]="selectedFilters" (valueChange)="updateFilter($event)"></ui-filter-group>
|
||||
|
||||
<div class="sticky-cta-wrapper">
|
||||
<button class="apply-filter" (click)="applyFilters()">
|
||||
<span>
|
||||
Filter anwenden
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
@@ -0,0 +1,39 @@
|
||||
:host {
|
||||
@apply flex flex-col box-border w-full;
|
||||
|
||||
ui-filter-group ::ng-deep .select-filter-options {
|
||||
overflow: scroll;
|
||||
max-height: 400px;
|
||||
}
|
||||
}
|
||||
|
||||
.sticky-cta-wrapper {
|
||||
@apply fixed text-center inset-x-0 bottom-0;
|
||||
bottom: 30px;
|
||||
}
|
||||
|
||||
button.apply-filter {
|
||||
@apply border-none bg-brand text-white rounded-full py-cta-y-l px-cta-x-l text-cta-l font-bold;
|
||||
min-width: 201px;
|
||||
}
|
||||
|
||||
button.apply-filter:disabled {
|
||||
@apply bg-inactive-customer;
|
||||
}
|
||||
|
||||
button.apply-filter.loading {
|
||||
padding-top: 15px;
|
||||
padding-bottom: 17px;
|
||||
}
|
||||
|
||||
ui-selected-filter-options {
|
||||
@apply my-px-8;
|
||||
}
|
||||
|
||||
ui-icon {
|
||||
@apply inline-flex;
|
||||
}
|
||||
|
||||
.spin {
|
||||
@apply animate-spin;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, OnDestroy, OnInit, Output } from '@angular/core';
|
||||
import { Filter } from '@ui/filter';
|
||||
import { first } from 'rxjs/operators';
|
||||
import { TaskCalendarStore } from '../../task-calendar.store';
|
||||
|
||||
@Component({
|
||||
selector: 'page-task-calendar-filter',
|
||||
templateUrl: 'task-calendar-filter.component.html',
|
||||
styleUrls: ['task-calendar-filter.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class TaskCalendarFilterComponent implements OnInit, OnDestroy {
|
||||
@Output() exitFilter = new EventEmitter<void>();
|
||||
selectedFilters: Filter[];
|
||||
initialFilter: Filter[];
|
||||
updatedFilter: Filter[];
|
||||
|
||||
readonly initialFilters$ = this.taskCalendarStore.selectInitialFilter;
|
||||
readonly filters$ = this.taskCalendarStore.selectFilter;
|
||||
readonly displayInfos$ = this.taskCalendarStore.selectDisplayInfos;
|
||||
|
||||
constructor(private cdr: ChangeDetectorRef, private taskCalendarStore: TaskCalendarStore) {}
|
||||
|
||||
async ngOnInit() {
|
||||
this.initialFilter = await this.initialFilters$.pipe(first()).toPromise();
|
||||
const filters = await this.filters$.pipe(first()).toPromise();
|
||||
this.selectedFilters = filters;
|
||||
this.updatedFilter = filters;
|
||||
this.cdr.markForCheck();
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
const filters = this.updatedFilter;
|
||||
this.taskCalendarStore.setFilter({ filters });
|
||||
}
|
||||
|
||||
applyFilters() {
|
||||
this.taskCalendarStore.loadItems();
|
||||
this.updatedFilter = this.selectedFilters;
|
||||
this.exitFilter.emit();
|
||||
}
|
||||
|
||||
updateFilter(filters: Filter[]) {
|
||||
this.taskCalendarStore.setFilter({ filters });
|
||||
this.selectedFilters = filters;
|
||||
this.cdr.markForCheck();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<h1>{{ article?.ean }}</h1>
|
||||
<div class="details">
|
||||
<img class="details-image" [src]="article?.ean | productImage: 150:150:true" alt="product-image" />
|
||||
<div class="details-text">
|
||||
<p>
|
||||
{{ article?.text }}
|
||||
</p>
|
||||
<button (click)="closeDetails.emit()" class="btn-cta-less" type="button">
|
||||
<ui-icon rotate="180deg" icon="arrow" size="16px"></ui-icon> Weniger
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,33 @@
|
||||
:host {
|
||||
@apply flex flex-col relative mb-8;
|
||||
}
|
||||
|
||||
h1 {
|
||||
@apply text-xl font-bold text-center mb-3;
|
||||
}
|
||||
|
||||
.details {
|
||||
@apply flex flex-row;
|
||||
|
||||
.details-image {
|
||||
@apply rounded-customerCard mt-5;
|
||||
width: 58px;
|
||||
height: 95px;
|
||||
}
|
||||
|
||||
.details-text {
|
||||
@apply flex flex-col;
|
||||
|
||||
p {
|
||||
@apply px-5 py-0;
|
||||
}
|
||||
|
||||
.btn-cta-less {
|
||||
@apply border-none bg-transparent outline-none text-regular text-ucla-blue font-bold px-5 self-start;
|
||||
|
||||
ui-icon {
|
||||
@apply inline mx-1 align-middle;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||
import { ArticleDTO } from '@swagger/eis';
|
||||
|
||||
@Component({
|
||||
selector: 'page-article-list-details',
|
||||
templateUrl: 'article-list-details.component.html',
|
||||
styleUrls: ['article-list-details.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ArticleListDetailsComponent implements OnInit {
|
||||
@Input() article: ArticleDTO;
|
||||
@Output() closeDetails = new EventEmitter<void>();
|
||||
|
||||
constructor() {}
|
||||
|
||||
ngOnInit() {}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<button class="close" type="button"><ui-icon icon="close" size="16px" (click)="close()"></ui-icon></button>
|
||||
<ng-container *ngIf="!expandedArticle">
|
||||
<h1>Artikelliste</h1>
|
||||
<div class="slider-wrapper">
|
||||
<button class="cta-slider-prev" (click)="prev()" *ngIf="!!showSliderButtons">
|
||||
<ui-icon class="slider-icon" rotate="180deg" icon="arrow" size="15px"></ui-icon>
|
||||
</button>
|
||||
<div #sliderContainer class="articles">
|
||||
<div class="article" *ngFor="let article of articles$ | async">
|
||||
<img [src]="article?.ean | productImage: 190:310:true" alt="product-image" />
|
||||
<h2>{{ article?.ean }}</h2>
|
||||
<p>
|
||||
{{ article?.text | trim: 50 }}
|
||||
<button (click)="expandedArticle = article" *ngIf="article?.text?.length > 53" class="btn-cta-more" type="button">
|
||||
Mehr <ui-icon icon="arrow" size="16px"></ui-icon>
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<button class="cta-slider-next" (click)="next()" *ngIf="!!showSliderButtons">
|
||||
<ui-icon class="slider-icon" icon="arrow" size="15px"></ui-icon>
|
||||
</button>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button (click)="print()" class="btn-cta-secondary">
|
||||
Drucken
|
||||
</button>
|
||||
<button (click)="eanCopy()" class="btn-cta-secondary">
|
||||
EAN-Liste kopieren
|
||||
</button>
|
||||
<button (click)="articleSearch()" class="btn-cta">
|
||||
Liste in Artikelsuche anzeigen
|
||||
</button>
|
||||
</div>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="!!expandedArticle">
|
||||
<page-article-list-details (closeDetails)="expandedArticle = undefined" [article]="expandedArticle"></page-article-list-details>
|
||||
</ng-container>
|
||||
@@ -0,0 +1,80 @@
|
||||
:host {
|
||||
@apply flex flex-col relative;
|
||||
}
|
||||
|
||||
h1 {
|
||||
@apply text-xl font-bold text-center mb-7;
|
||||
}
|
||||
|
||||
.slider-wrapper {
|
||||
@apply relative flex flex-row items-center;
|
||||
.cta-slider-next,
|
||||
.cta-slider-prev {
|
||||
@apply outline-none border-none bg-white rounded-card opacity-70;
|
||||
height: 310px;
|
||||
width: 55px;
|
||||
box-shadow: 3px 0 14px 8px white;
|
||||
}
|
||||
.slider-icon {
|
||||
@apply items-center justify-center;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
background-color: #e9f0f8;
|
||||
color: #0f1542;
|
||||
}
|
||||
}
|
||||
|
||||
.articles {
|
||||
@apply flex flex-row overflow-scroll;
|
||||
scroll-behavior: smooth;
|
||||
width: calc(100% + 1rem);
|
||||
|
||||
.article {
|
||||
@apply flex flex-col mr-5;
|
||||
width: 190px;
|
||||
|
||||
img {
|
||||
@apply rounded-customerCard;
|
||||
width: 190px;
|
||||
height: 310px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
@apply text-lg font-bold m-0 mt-4 mb-2;
|
||||
}
|
||||
|
||||
p {
|
||||
@apply m-0 break-all;
|
||||
}
|
||||
|
||||
.btn-cta-more {
|
||||
@apply border-none bg-transparent outline-none text-regular text-ucla-blue font-bold p-0;
|
||||
|
||||
ui-icon {
|
||||
@apply inline mx-1 align-middle;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.actions {
|
||||
@apply flex flex-row justify-center p-8;
|
||||
|
||||
.btn-cta {
|
||||
@apply bg-brand text-white font-bold text-lg outline-none border-none rounded-full px-6 py-3;
|
||||
}
|
||||
|
||||
.btn-cta-secondary {
|
||||
@apply text-brand border-2 border-none bg-white font-bold text-lg px-4 py-2 rounded-full mr-2;
|
||||
}
|
||||
}
|
||||
|
||||
.close {
|
||||
@apply absolute top-0 right-0 outline-none border-none bg-transparent;
|
||||
z-index: 10;
|
||||
|
||||
ui-icon {
|
||||
@apply text-inactive-branch;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
import { Clipboard } from '@angular/cdk/clipboard';
|
||||
import { ChangeDetectionStrategy, Component, ElementRef, OnInit, ViewChild } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { DomainPrinterService } from '@domain/printer';
|
||||
import { DomainTaskCalendarService } from '@domain/task-calendar';
|
||||
import { PrintModalComponent, PrintModalData } from '@modal/printer';
|
||||
import { ModuleSwitcherService } from '@sales/core-services';
|
||||
import { ArticleDTO, DisplayInfoDTO } from '@swagger/eis';
|
||||
import { UiModalRef, UiModalService } from '@ui/modal';
|
||||
import { NativeContainerService } from 'native-container';
|
||||
import { first, map } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'page-article-list-modal',
|
||||
templateUrl: 'article-list-modal.component.html',
|
||||
styleUrls: ['article-list-modal.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ArticleListModalComponent implements OnInit {
|
||||
@ViewChild('sliderContainer', { static: false }) sliderContainer: ElementRef<HTMLDivElement>;
|
||||
|
||||
articles$ = this.domainTaskCalendarService.getArticles({ infoId: this.modalRef.data.id }).pipe(map((response) => response.result));
|
||||
expandedArticle: ArticleDTO;
|
||||
showSliderButtons: boolean;
|
||||
|
||||
constructor(
|
||||
private modalRef: UiModalRef<any, DisplayInfoDTO>,
|
||||
private router: Router,
|
||||
private moduleSwitcherService: ModuleSwitcherService,
|
||||
private clipboard: Clipboard,
|
||||
private nativeContainer: NativeContainerService,
|
||||
private domainTaskCalendarService: DomainTaskCalendarService,
|
||||
private domainPrinterService: DomainPrinterService,
|
||||
private uiModal: UiModalService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
if (!this.nativeContainer.isUiWebview()?.isNative) {
|
||||
this.showSliderButtons = true;
|
||||
}
|
||||
}
|
||||
|
||||
close() {
|
||||
this.modalRef.close();
|
||||
}
|
||||
|
||||
async print() {
|
||||
const articles = await this.articles$.pipe(first()).toPromise();
|
||||
this.uiModal.open({
|
||||
content: PrintModalComponent,
|
||||
data: {
|
||||
printerType: 'Office',
|
||||
print: (printer) =>
|
||||
this.domainPrinterService.printDisplayInfoDTOArticles({ articles, printer, title: `${this.modalRef.data.title}` }).toPromise(),
|
||||
} as PrintModalData,
|
||||
});
|
||||
}
|
||||
|
||||
async eanCopy() {
|
||||
const articles = await this.articles$.toPromise();
|
||||
const eanString = articles.map((article: ArticleDTO) => article.ean).join(',');
|
||||
this.clipboard.copy(eanString);
|
||||
}
|
||||
|
||||
prev() {
|
||||
this.sliderContainer.nativeElement.scrollLeft -= 190;
|
||||
}
|
||||
|
||||
next() {
|
||||
this.sliderContainer.nativeElement.scrollLeft += 190;
|
||||
}
|
||||
|
||||
async articleSearch() {
|
||||
const articles = await this.articles$.toPromise();
|
||||
const taskCalendarSearch: string = articles.map((article: ArticleDTO) => article.ean).join(';');
|
||||
this.modalRef.close('closeAll');
|
||||
this.moduleSwitcherService.switchToCustomer();
|
||||
this.router.navigate(['/product', 'search'], { queryParams: { taskCalendarSearch } });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
import { ProductImageModule } from 'apps/cdn/product-image/src/public-api';
|
||||
import { ArticleListDetailsComponent } from './article-list-details/article-list-details.component';
|
||||
import { ArticleListModalComponent } from './article-list-modal.component';
|
||||
import { TrimPipe } from './pipes/trim.pipe';
|
||||
import { ClipboardModule } from '@angular/cdk/clipboard';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, UiIconModule, ProductImageModule, ClipboardModule],
|
||||
exports: [ArticleListModalComponent],
|
||||
declarations: [ArticleListModalComponent, ArticleListDetailsComponent, TrimPipe],
|
||||
providers: [],
|
||||
})
|
||||
export class ArticleListModalModule {}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
import { isString } from '@utils/common';
|
||||
|
||||
@Pipe({
|
||||
name: 'trim',
|
||||
})
|
||||
export class TrimPipe implements PipeTransform {
|
||||
transform(value: string, length: number = 15): any {
|
||||
if (isString(value) && value.length > length + 3) {
|
||||
return value.substr(0, length - 1) + '...';
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<div class="picture-wrapper">
|
||||
<img class="picture" [src]="image" />
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<button class="cancel-btn" (click)="close()">Abbrechen</button>
|
||||
<button class="repeat-btn" (click)="repeat()">Wiederholen</button>
|
||||
<button class="send-btn" (click)="send()">Absenden</button>
|
||||
</div>
|
||||
@@ -0,0 +1,21 @@
|
||||
.picture-wrapper {
|
||||
@apply flex flex-row justify-center;
|
||||
|
||||
.picture {
|
||||
@apply w-auto h-auto max-w-full;
|
||||
max-height: calc(100vh - 300px);
|
||||
}
|
||||
}
|
||||
|
||||
.actions {
|
||||
@apply flex flex-row justify-center mt-4;
|
||||
|
||||
.send-btn {
|
||||
@apply bg-brand text-white font-bold text-lg outline-none border-none rounded-full px-6 py-3 ml-2;
|
||||
}
|
||||
|
||||
.cancel-btn,
|
||||
.repeat-btn {
|
||||
@apply text-brand border-none outline-none bg-white font-bold text-lg px-4 py-2 rounded-full ml-2;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import { ChangeDetectionStrategy, Component, EventEmitter, Output } from '@angular/core';
|
||||
import { UiModalRef } from '@ui/modal';
|
||||
|
||||
@Component({
|
||||
selector: 'camera-capture-modal',
|
||||
templateUrl: 'camera-capture-modal.component.html',
|
||||
styleUrls: ['camera-capture-modal.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class CameraCaptureModalComponent {
|
||||
image: string;
|
||||
|
||||
constructor(private modalRef: UiModalRef<string>) {
|
||||
this.image = this.modalRef.data;
|
||||
}
|
||||
|
||||
close() {
|
||||
this.modalRef.close();
|
||||
}
|
||||
|
||||
repeat() {
|
||||
this.modalRef.close('');
|
||||
}
|
||||
|
||||
send() {
|
||||
this.modalRef.close(this.image);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
|
||||
import { CameraCaptureModalComponent } from './camera-capture-modal.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [],
|
||||
exports: [CameraCaptureModalComponent],
|
||||
declarations: [CameraCaptureModalComponent],
|
||||
})
|
||||
export class CameraCaptureModalModule {}
|
||||
@@ -0,0 +1,5 @@
|
||||
<button class="close" type="button"><ui-icon icon="close" size="16px" (click)="close()"></ui-icon></button>
|
||||
|
||||
<h1>{{ file?.name }}</h1>
|
||||
|
||||
<img alt="file?.name" [isaBlobImage]="content" />
|
||||
@@ -0,0 +1,19 @@
|
||||
:host {
|
||||
@apply flex flex-col relative;
|
||||
}
|
||||
|
||||
h1 {
|
||||
@apply my-6 text-card-heading text-center;
|
||||
}
|
||||
|
||||
img {
|
||||
@apply max-w-full;
|
||||
}
|
||||
|
||||
button.close {
|
||||
@apply absolute top-0 right-0 outline-none border-none bg-transparent;
|
||||
|
||||
ui-icon {
|
||||
@apply text-inactive-branch;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { FileDTO } from '@swagger/eis';
|
||||
import { UiModalRef } from '@ui/modal';
|
||||
import { ImageViewerModalData } from './image-viewer-modal.data';
|
||||
|
||||
@Component({
|
||||
selector: 'page-image-viewer-modal',
|
||||
templateUrl: 'image-viewer-modal.component.html',
|
||||
styleUrls: ['image-viewer-modal.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ImageViewerModalComponent {
|
||||
file: FileDTO;
|
||||
|
||||
content: Blob;
|
||||
|
||||
constructor(private modalRef: UiModalRef<ImageViewerModalData>) {
|
||||
this.content = this.modalRef.data.content;
|
||||
this.file = this.modalRef.data.file;
|
||||
}
|
||||
|
||||
close() {
|
||||
this.modalRef.close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import { FileDTO } from '@swagger/checkout';
|
||||
|
||||
export interface ImageViewerModalData {
|
||||
file: FileDTO;
|
||||
content: Blob;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { ImageViewerModalComponent } from './image-viewer-modal.component';
|
||||
import { UiCommonModule } from '@ui/common';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, UiCommonModule, UiIconModule],
|
||||
exports: [ImageViewerModalComponent],
|
||||
declarations: [ImageViewerModalComponent],
|
||||
})
|
||||
export class ImageViewerModalModule {}
|
||||
@@ -0,0 +1,3 @@
|
||||
<h1>{{ info?.title }}</h1>
|
||||
<page-task-info [info]="info"></page-task-info>
|
||||
<button type="button"><ui-icon icon="close" size="16px" (click)="close()"></ui-icon></button>
|
||||
@@ -0,0 +1,15 @@
|
||||
:host {
|
||||
@apply flex flex-col relative;
|
||||
}
|
||||
|
||||
h1 {
|
||||
@apply text-xl font-bold text-center;
|
||||
}
|
||||
|
||||
button {
|
||||
@apply absolute top-0 right-0 outline-none border-none bg-transparent;
|
||||
|
||||
ui-icon {
|
||||
@apply text-inactive-branch;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { DisplayInfoDTO } from '@swagger/eis';
|
||||
import { UiModalRef } from '@ui/modal';
|
||||
import { Subscription } from 'rxjs';
|
||||
|
||||
@Component({
|
||||
selector: 'page-info-modal',
|
||||
templateUrl: 'info-modal.component.html',
|
||||
styleUrls: ['info-modal.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class InfoModalComponent {
|
||||
info: DisplayInfoDTO;
|
||||
|
||||
constructor(private modalRef: UiModalRef<DisplayInfoDTO>) {
|
||||
this.info = this.modalRef.data;
|
||||
}
|
||||
|
||||
close() {
|
||||
this.modalRef.close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { InfoModalComponent } from './info-modal.component';
|
||||
import { TaskInfoModule } from '../../components/task-info/task-info.module';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, TaskInfoModule, UiIconModule],
|
||||
exports: [InfoModalComponent],
|
||||
declarations: [InfoModalComponent],
|
||||
})
|
||||
export class InfoModalModule {}
|
||||
33
apps/page/task-calendar/src/lib/modals/modals.module.ts
Normal file
33
apps/page/task-calendar/src/lib/modals/modals.module.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { ImageViewerModalModule } from './image-viewer/image-viewer-modal.module';
|
||||
import { CameraCaptureModalModule } from './camera/camera-capture-modal.module';
|
||||
import { InfoModalModule } from './info/info-modal.module';
|
||||
import { PdfViewerModalModule } from './pdf-viewer/pdf-viewer-modal.module';
|
||||
import { PreInfoModalModule } from './preinfo/preinfo-modal.module';
|
||||
import { TaskModalModule } from './task/task-modal.module';
|
||||
import { ArticleListModalModule } from './article-list/article-list-modal.module';
|
||||
import { WebViewerModalModule } from './web-viewer/web-viewer-modal.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
InfoModalModule,
|
||||
PreInfoModalModule,
|
||||
TaskModalModule,
|
||||
PdfViewerModalModule,
|
||||
ImageViewerModalModule,
|
||||
CameraCaptureModalModule,
|
||||
ArticleListModalModule,
|
||||
WebViewerModalModule,
|
||||
],
|
||||
exports: [
|
||||
InfoModalModule,
|
||||
PreInfoModalModule,
|
||||
TaskModalModule,
|
||||
PdfViewerModalModule,
|
||||
ImageViewerModalModule,
|
||||
CameraCaptureModalModule,
|
||||
ArticleListModalModule,
|
||||
WebViewerModalModule,
|
||||
],
|
||||
})
|
||||
export class ModalsModule {}
|
||||
@@ -0,0 +1,19 @@
|
||||
<button class="close" type="button"><ui-icon icon="close" size="16px" (click)="close()"></ui-icon></button>
|
||||
|
||||
<h1>{{ file?.name }}</h1>
|
||||
|
||||
<h5>Seite {{ page }} / {{ totalPages }}</h5>
|
||||
|
||||
<pdf-viewer
|
||||
[src]="objectURL"
|
||||
[render-text]="true"
|
||||
[(page)]="page"
|
||||
(after-load-complete)="callBackFn($event)"
|
||||
zoom-scale="page-height"
|
||||
></pdf-viewer>
|
||||
|
||||
<div class="cta-wrapper">
|
||||
<button (click)="print()" class="cta-print" type="button">
|
||||
Drucken
|
||||
</button>
|
||||
</div>
|
||||
@@ -0,0 +1,35 @@
|
||||
:host {
|
||||
@apply grid grid-cols-1 relative;
|
||||
max-height: calc(100vh - 4rem);
|
||||
}
|
||||
|
||||
h1 {
|
||||
@apply my-6 text-card-heading text-center;
|
||||
}
|
||||
|
||||
h5 {
|
||||
@apply mt-0 mb-6 text-lg text-center text-inactive-branch font-normal;
|
||||
}
|
||||
|
||||
pdf-viewer {
|
||||
@apply flex-grow overflow-y-auto max-h-full;
|
||||
|
||||
::ng-deep .canvasWrapper {
|
||||
@apply border-2 border-gray-200 border-solid rounded-card;
|
||||
}
|
||||
}
|
||||
|
||||
button.close {
|
||||
@apply absolute top-0 right-0 outline-none border-none bg-transparent;
|
||||
|
||||
ui-icon {
|
||||
@apply text-inactive-branch;
|
||||
}
|
||||
}
|
||||
.cta-wrapper {
|
||||
@apply absolute bottom-6 left-0 right-0 text-center;
|
||||
|
||||
button.cta-print {
|
||||
@apply bg-brand text-xl px-6 py-3 text-white rounded-full border-none outline-none font-bold shadow-cta;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import { Component, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
|
||||
import { DomainPrinterService } from '@domain/printer';
|
||||
import { DomainTaskCalendarService } from '@domain/task-calendar';
|
||||
import { PrintModalComponent, PrintModalData } from '@modal/printer';
|
||||
import { FileDTO } from '@swagger/eis';
|
||||
import { UiModalRef, UiModalService } from '@ui/modal';
|
||||
import { PDFDocumentProxy } from 'ng2-pdf-viewer';
|
||||
import { PdfViewerModalData } from './pdf-viewer-modal.data';
|
||||
|
||||
@Component({
|
||||
selector: 'page-pdf-viewer-modal',
|
||||
templateUrl: 'pdf-viewer-modal.component.html',
|
||||
styleUrls: ['pdf-viewer-modal.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class PdfViewerModalComponent {
|
||||
objectURL: string;
|
||||
|
||||
file: FileDTO;
|
||||
|
||||
page = 1;
|
||||
|
||||
totalPages = 1;
|
||||
|
||||
constructor(
|
||||
private modalRef: UiModalRef<any, PdfViewerModalData>,
|
||||
private cdr: ChangeDetectorRef,
|
||||
private uiModal: UiModalService,
|
||||
private taskCalendarService: DomainTaskCalendarService,
|
||||
private domainPrinterService: DomainPrinterService
|
||||
) {
|
||||
this.objectURL = URL.createObjectURL(this.modalRef.data.content);
|
||||
this.file = this.modalRef.data.file;
|
||||
}
|
||||
|
||||
close() {
|
||||
this.modalRef.close();
|
||||
}
|
||||
|
||||
callBackFn(pdf: PDFDocumentProxy) {
|
||||
this.totalPages = pdf.numPages;
|
||||
this.cdr.markForCheck();
|
||||
}
|
||||
|
||||
print() {
|
||||
const blob = this.modalRef.data.content;
|
||||
const reader = new FileReader();
|
||||
reader.readAsDataURL(blob);
|
||||
reader.onloadend = () => {
|
||||
const base64data = reader.result as string;
|
||||
this.uiModal.open({
|
||||
content: PrintModalComponent,
|
||||
data: {
|
||||
printerType: 'Office',
|
||||
print: (printer) =>
|
||||
this.domainPrinterService
|
||||
.printPdf({ printer, data: this.taskCalendarService.removeMetaDataFromBase64(base64data) })
|
||||
.toPromise(),
|
||||
} as PrintModalData,
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import { FileDTO } from '@swagger/checkout';
|
||||
|
||||
export interface PdfViewerModalData {
|
||||
file: FileDTO;
|
||||
content: Blob;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { PdfViewerModule } from 'ng2-pdf-viewer';
|
||||
|
||||
import { PdfViewerModalComponent } from './pdf-viewer-modal.component';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, PdfViewerModule, UiIconModule],
|
||||
exports: [PdfViewerModalComponent],
|
||||
declarations: [PdfViewerModalComponent],
|
||||
})
|
||||
export class PdfViewerModalModule {}
|
||||
@@ -0,0 +1,4 @@
|
||||
<h3>Vorabinfo</h3>
|
||||
<h1>{{ info?.title }}</h1>
|
||||
<page-task-info [info]="info" showTaskDate="true"></page-task-info>
|
||||
<button type="button"><ui-icon icon="close" size="16px" (click)="close()"></ui-icon></button>
|
||||
@@ -0,0 +1,19 @@
|
||||
:host {
|
||||
@apply flex flex-col relative;
|
||||
}
|
||||
|
||||
h1 {
|
||||
@apply text-xl font-bold text-center;
|
||||
}
|
||||
|
||||
h3 {
|
||||
@apply absolute m-0 top-0 left-0 text-regular text-active-branch uppercase;
|
||||
}
|
||||
|
||||
button {
|
||||
@apply absolute top-0 right-0 outline-none border-none bg-transparent;
|
||||
|
||||
ui-icon {
|
||||
@apply text-inactive-branch;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||
import { DisplayInfoDTO } from '@swagger/eis';
|
||||
import { UiModalRef } from '@ui/modal';
|
||||
|
||||
@Component({
|
||||
selector: 'page-preinfo-modal',
|
||||
templateUrl: 'preinfo-modal.component.html',
|
||||
styleUrls: ['preinfo-modal.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class PreInfoModalComponent {
|
||||
info: DisplayInfoDTO;
|
||||
|
||||
constructor(private modalRef: UiModalRef<DisplayInfoDTO>) {
|
||||
this.info = this.modalRef.data;
|
||||
}
|
||||
|
||||
close() {
|
||||
this.modalRef.close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
import { TaskInfoModule } from '../../components/task-info/task-info.module';
|
||||
|
||||
import { PreInfoModalComponent } from './preinfo-modal.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, TaskInfoModule, UiIconModule],
|
||||
exports: [PreInfoModalComponent],
|
||||
declarations: [PreInfoModalComponent],
|
||||
})
|
||||
export class PreInfoModalModule {}
|
||||
@@ -0,0 +1,40 @@
|
||||
<button class="btn-close" type="button"><ui-icon icon="close" size="16px" (click)="close()"></ui-icon></button>
|
||||
|
||||
<div class="header">
|
||||
<ui-tshirt *ngIf="info?.effort" [effort]="info?.effort"></ui-tshirt>
|
||||
<h1>{{ info?.title }}</h1>
|
||||
</div>
|
||||
<div class="status">
|
||||
<div class="indicator" [style.backgroundColor]="indicatorColor$ | async"></div>
|
||||
<span class="status-text">{{ status$ | async }}</span>
|
||||
</div>
|
||||
|
||||
<div class="body">
|
||||
<page-task-info [info]="info"></page-task-info>
|
||||
</div>
|
||||
|
||||
<div class="camera-preview" *ngIf="cameraPreview$ | async; let cameraPreview">
|
||||
<img [isaBlobImage]="cameraPreview" />
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<button *ngIf="showStartEditCta$ | async" class="btn-cta" type="button" (click)="startEdit()">Jetzt bearbeiten</button>
|
||||
<button *ngIf="showCompleteEditCta$ | async" class="btn-cta" type="button" (click)="completeEdit()">
|
||||
Bearbeitung abschließen
|
||||
</button>
|
||||
<div *ngIf="showCameraCta$ | async">
|
||||
<ng-container>
|
||||
<!-- *ngIf="isIpad" -->
|
||||
<div class="camera-hint">Bitte fotografieren Sie die Präsentation, um die<br />Aufgabe abschließen zu können</div>
|
||||
<input uiCapture #captureInput id="file-input" capture="camera" type="file" (fileChanged)="cameraCapture($event)" />
|
||||
<label class="btn-camera" for="file-input">Kamera öffnen</label>
|
||||
</ng-container>
|
||||
<!-- <div class="camera-hint" *ngIf="!isIpad">
|
||||
Bitte auf dem iPad fortfahren
|
||||
</div> -->
|
||||
</div>
|
||||
<ng-container *ngIf="showResetEditCta$ | async">
|
||||
<button class="btn-cta-secondary" type="button" (click)="resetEdit()">Erneut bearbeiten</button>
|
||||
<button class="btn-cta" type="button" (click)="close()">Fenster schließen</button>
|
||||
</ng-container>
|
||||
</div>
|
||||
@@ -0,0 +1,63 @@
|
||||
:host {
|
||||
@apply flex flex-col relative;
|
||||
}
|
||||
|
||||
.header {
|
||||
@apply flex flex-row justify-center items-center mt-3;
|
||||
|
||||
h1 {
|
||||
@apply text-xl font-bold text-center m-0 ml-4;
|
||||
}
|
||||
}
|
||||
|
||||
.status {
|
||||
@apply flex flex-row justify-center items-center mt-px-10 mb-4;
|
||||
|
||||
.indicator {
|
||||
@apply h-px-10 w-px-10 rounded-full bg-gray-50;
|
||||
}
|
||||
|
||||
.status-text {
|
||||
@apply text-lg font-bold ml-2;
|
||||
}
|
||||
}
|
||||
|
||||
.camera-preview {
|
||||
@apply flex flex-row justify-center;
|
||||
|
||||
img {
|
||||
height: 200px;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-close {
|
||||
@apply absolute top-0 right-0 outline-none border-none bg-transparent;
|
||||
|
||||
ui-icon {
|
||||
@apply text-inactive-branch;
|
||||
}
|
||||
}
|
||||
|
||||
.actions {
|
||||
@apply text-center mb-5 mt-6 sticky bottom-1;
|
||||
|
||||
.btn-cta {
|
||||
@apply bg-brand text-white font-bold text-lg outline-none border-none rounded-full px-6 py-3;
|
||||
}
|
||||
|
||||
.btn-cta-secondary {
|
||||
@apply text-brand border-2 border-solid border-brand bg-white font-bold text-lg px-4 py-2 rounded-full mr-2;
|
||||
}
|
||||
|
||||
#file-input {
|
||||
@apply hidden;
|
||||
}
|
||||
|
||||
.btn-camera {
|
||||
@apply inline-block bg-brand text-white font-bold text-lg outline-none border-none rounded-full px-6 py-3 cursor-pointer;
|
||||
}
|
||||
|
||||
.camera-hint {
|
||||
@apply text-inactive-branch mb-4;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
import { ChangeDetectionStrategy, Component, ElementRef, ViewChild } from '@angular/core';
|
||||
import { DomainTaskCalendarService } from '@domain/task-calendar';
|
||||
import { DisplayInfoDTO } from '@swagger/eis';
|
||||
import { UiModalRef, UiModalService } from '@ui/modal';
|
||||
import { isNullOrUndefined } from '@utils/common';
|
||||
import { NativeContainerService } from 'native-container';
|
||||
import { combineLatest, ReplaySubject } from 'rxjs';
|
||||
import { map, shareReplay, switchMap } from 'rxjs/operators';
|
||||
import { CameraCaptureModalComponent } from '../camera/camera-capture-modal.component';
|
||||
|
||||
@Component({
|
||||
selector: 'page-task-modal',
|
||||
templateUrl: 'task-modal.component.html',
|
||||
styleUrls: ['task-modal.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class TaskModalComponent {
|
||||
@ViewChild('captureInput')
|
||||
captureInput: ElementRef<HTMLInputElement>;
|
||||
|
||||
info: DisplayInfoDTO;
|
||||
isIpad = this.nativeContainer.isUiWebview()?.isNative;
|
||||
|
||||
info$ = new ReplaySubject<DisplayInfoDTO>();
|
||||
|
||||
processingStatus$ = this.info$.pipe(
|
||||
map((info) => this.domainTaskCalendarService.getProcessingStatusList(info)),
|
||||
shareReplay()
|
||||
);
|
||||
|
||||
status$ = this.processingStatus$.pipe(
|
||||
map((processingStatus) => {
|
||||
if (processingStatus.includes('InProcess')) {
|
||||
return 'In Bearbeitung';
|
||||
}
|
||||
if (processingStatus.includes('Completed')) {
|
||||
return 'Erledigt';
|
||||
}
|
||||
return 'Offen';
|
||||
})
|
||||
);
|
||||
|
||||
indicatorColor$ = this.info$.pipe(map((info) => this.domainTaskCalendarService.getProcessingStatusColorCode(info)));
|
||||
|
||||
cameraPreview$ = this.info$.pipe(
|
||||
switchMap((info) =>
|
||||
this.domainTaskCalendarService.getConfirmationFiles({ infoId: info.id }).pipe(map((response) => response.result[0]))
|
||||
),
|
||||
switchMap((file) => (!isNullOrUndefined(file?.id) ? this.domainTaskCalendarService.getFile({ fileId: file.id }) : [undefined]))
|
||||
);
|
||||
|
||||
showStartEditCta$ = this.processingStatus$.pipe(
|
||||
map((processingStatus) => !processingStatus.includes('InProcess') && !processingStatus.includes('Completed'))
|
||||
);
|
||||
|
||||
showCompleteEditCta$ = combineLatest([this.processingStatus$, this.info$]).pipe(
|
||||
map(([processingStatus, info]) => processingStatus.includes('InProcess') && !info.requiresImageOnConfirmation)
|
||||
);
|
||||
|
||||
showCameraCta$ = combineLatest([this.processingStatus$, this.info$]).pipe(
|
||||
map(([processingStatus, info]) => processingStatus.includes('InProcess') && info.requiresImageOnConfirmation)
|
||||
);
|
||||
|
||||
showResetEditCta$ = this.processingStatus$.pipe(map((processingStatus) => processingStatus.includes('Completed')));
|
||||
|
||||
constructor(
|
||||
private modalRef: UiModalRef<DisplayInfoDTO>,
|
||||
private domainTaskCalendarService: DomainTaskCalendarService,
|
||||
private uiModal: UiModalService,
|
||||
private nativeContainer: NativeContainerService
|
||||
) {
|
||||
this.info = this.modalRef.data;
|
||||
this.info$.next(this.info);
|
||||
}
|
||||
|
||||
close() {
|
||||
this.modalRef.close();
|
||||
}
|
||||
|
||||
async startEdit() {
|
||||
await this.domainTaskCalendarService.setToEdit({ infoId: this.info.id }).toPromise();
|
||||
this.reloadInfo();
|
||||
}
|
||||
|
||||
async completeEdit() {
|
||||
await this.domainTaskCalendarService.complete({ infoId: this.info.id }).toPromise();
|
||||
this.close();
|
||||
}
|
||||
|
||||
async resetEdit() {
|
||||
await this.domainTaskCalendarService.resetConfirmation({ infoId: this.info.id }).toPromise();
|
||||
this.reloadInfo();
|
||||
}
|
||||
|
||||
reloadInfo() {
|
||||
this.domainTaskCalendarService
|
||||
.getInfoById({ infoId: this.info.id })
|
||||
.pipe(map((response) => response.result))
|
||||
.subscribe((info) => {
|
||||
this.info$.next(info);
|
||||
this.info = info;
|
||||
});
|
||||
}
|
||||
|
||||
cameraCapture(image: string) {
|
||||
const modalRef = this.uiModal.open({
|
||||
content: CameraCaptureModalComponent,
|
||||
data: image,
|
||||
});
|
||||
modalRef.afterClosed$.subscribe(async (result) => {
|
||||
if (result.data === '') {
|
||||
this.captureInput?.nativeElement?.click();
|
||||
} else if (result.data?.length > 0) {
|
||||
await this.domainTaskCalendarService.complete({ infoId: this.info.id, file: result.data }).toPromise();
|
||||
this.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { UiCommonModule } from '@ui/common';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
import { UiInputModule } from '@ui/input';
|
||||
import { UiTshirtModule } from '@ui/tshirt';
|
||||
import { TaskInfoModule } from '../../components/task-info/task-info.module';
|
||||
import { TaskModalComponent } from './task-modal.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, UiTshirtModule, UiIconModule, TaskInfoModule, UiInputModule, UiCommonModule],
|
||||
exports: [TaskModalComponent],
|
||||
declarations: [TaskModalComponent],
|
||||
})
|
||||
export class TaskModalModule {}
|
||||
@@ -0,0 +1,3 @@
|
||||
<button class="close" type="button"><ui-icon icon="close" size="16px" (click)="close()"></ui-icon></button>
|
||||
<h1>Digitale Titelvorschau</h1>
|
||||
<iframe [src]="src"></iframe>
|
||||
@@ -0,0 +1,20 @@
|
||||
:host {
|
||||
@apply flex flex-col relative;
|
||||
}
|
||||
|
||||
iframe {
|
||||
@apply w-full;
|
||||
height: calc(100vh - 8rem);
|
||||
}
|
||||
|
||||
h1 {
|
||||
@apply my-6 text-card-heading text-center;
|
||||
}
|
||||
|
||||
button.close {
|
||||
@apply absolute top-0 right-0 outline-none border-none bg-transparent;
|
||||
|
||||
ui-icon {
|
||||
@apply text-inactive-branch;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { DomSanitizer, SafeUrl } from '@angular/platform-browser';
|
||||
import { UiModalRef } from '@ui/modal';
|
||||
|
||||
@Component({
|
||||
selector: 'page-web-viewer-modal',
|
||||
templateUrl: 'web-viewer-modal.component.html',
|
||||
styleUrls: ['./web-viewer-modal.component.scss'],
|
||||
})
|
||||
export class WebViewerModalComponent {
|
||||
src: SafeUrl;
|
||||
|
||||
constructor(private sanitizer: DomSanitizer, private modalRef: UiModalRef<string>) {
|
||||
this.src = this.sanitizer.bypassSecurityTrustResourceUrl(this.modalRef.data);
|
||||
}
|
||||
|
||||
close() {
|
||||
this.modalRef.close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
|
||||
import { WebViewerModalComponent } from './web-viewer-modal.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [UiIconModule],
|
||||
exports: [],
|
||||
declarations: [WebViewerModalComponent],
|
||||
})
|
||||
export class WebViewerModalModule {}
|
||||
@@ -0,0 +1,25 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import { PageTaskCalendarComponent } from './page-task-calendar.component';
|
||||
import { CalendarComponent } from './pages/calendar/calendar.component';
|
||||
import { CalendarModule } from './pages/calendar/calendar.module';
|
||||
import { TasksComponent } from './pages/tasks/tasks.component';
|
||||
import { TasksModule } from './pages/tasks/tasks.module';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: PageTaskCalendarComponent,
|
||||
children: [
|
||||
{ path: 'calendar', component: CalendarComponent },
|
||||
{ path: 'tasks', component: TasksComponent },
|
||||
{ path: '', pathMatch: 'full', redirectTo: './calendar' },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes), CalendarModule, TasksModule],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class PageTaskCalendarRoutingModule {}
|
||||
@@ -0,0 +1,34 @@
|
||||
<shell-breadcrumb key="task-calendar"></shell-breadcrumb>
|
||||
|
||||
<button class="filter" (click)="filterActive$.next(true)">
|
||||
<ui-icon size="20px" icon="filter_alit"></ui-icon>
|
||||
<span class="label">Filter</span>
|
||||
</button>
|
||||
|
||||
<div class="content-container" *ngIf="showMainContent$ | async">
|
||||
<div class="switch-group">
|
||||
<a class="calendar-switch" [routerLink]="['./calendar']" routerLinkActive="active">
|
||||
<ui-icon icon="calendar" size="16px"></ui-icon>
|
||||
<span>Kalender</span>
|
||||
</a>
|
||||
<a class="calendar-switch" [routerLink]="['./tasks']" routerLinkActive="active">
|
||||
<ui-icon icon="tasks" size="16px"></ui-icon>
|
||||
<span>Tätigkeiten</span>
|
||||
</a>
|
||||
</div>
|
||||
<router-outlet></router-outlet>
|
||||
</div>
|
||||
|
||||
<div class="filter-overlay" [class.active]="filterActive$ | async">
|
||||
<div class="filter-content">
|
||||
<div class="filter-close-right">
|
||||
<button class="filter-close" (click)="filterActive$.next(false)">
|
||||
<ui-icon size="20px" icon="close"></ui-icon>
|
||||
</button>
|
||||
</div>
|
||||
<h2 class="filter-header">
|
||||
Filter
|
||||
</h2>
|
||||
<page-task-calendar-filter (exitFilter)="filterActive$.next(false)" *ngIf="filterActive$ | async"> </page-task-calendar-filter>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,84 @@
|
||||
shell-breadcrumb {
|
||||
margin-top: -5px;
|
||||
@apply mb-px-10 pb-px-10;
|
||||
}
|
||||
|
||||
.filter {
|
||||
@apply absolute font-sans flex items-center font-bold bg-gray-400 border-0 text-regular py-px-8 px-px-15 rounded-filter justify-center;
|
||||
|
||||
right: 0;
|
||||
top: 10px;
|
||||
min-width: 106px;
|
||||
|
||||
.label {
|
||||
@apply ml-px-5;
|
||||
}
|
||||
|
||||
&.active {
|
||||
@apply bg-dark-cerulean text-white ml-px-5;
|
||||
}
|
||||
}
|
||||
|
||||
.filter-content {
|
||||
@apply max-w-content mx-auto mt-px-25 px-px-15;
|
||||
|
||||
.filter-close-right {
|
||||
@apply pr-px-10 text-right;
|
||||
}
|
||||
|
||||
.filter-header {
|
||||
@apply text-center text-page-heading mt-0;
|
||||
}
|
||||
|
||||
button.filter-close {
|
||||
@apply border-0 bg-transparent text-ucla-blue;
|
||||
}
|
||||
}
|
||||
|
||||
.filter-overlay {
|
||||
@apply fixed bg-munsell z-fixed;
|
||||
|
||||
transform: translatex(100%);
|
||||
transition: transform 0.5s ease-out;
|
||||
top: 135px;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
|
||||
&.active {
|
||||
transform: translatex(0%);
|
||||
}
|
||||
}
|
||||
|
||||
.content-container {
|
||||
max-height: calc(100vh - 267px);
|
||||
overflow: scroll;
|
||||
@apply bg-white rounded-card;
|
||||
}
|
||||
|
||||
.switch-group {
|
||||
@apply flex flex-row justify-center my-9;
|
||||
|
||||
a.calendar-switch {
|
||||
@apply flex flex-row items-center px-7 py-2 no-underline text-black bg-munsell;
|
||||
&:first-child {
|
||||
@apply rounded-l-card;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
@apply rounded-r-card;
|
||||
}
|
||||
ui-icon {
|
||||
@apply mr-3;
|
||||
}
|
||||
}
|
||||
|
||||
a.calendar-switch.active,
|
||||
a.calendar-switch:active {
|
||||
@apply text-white bg-active-branch;
|
||||
}
|
||||
}
|
||||
|
||||
:host ::ng-deep ui-calendar .navigation .title {
|
||||
margin-left: -140px;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { BreadcrumbService } from '@core/breadcrumb';
|
||||
import { BehaviorSubject, Observable, of } from 'rxjs';
|
||||
import { delay, switchMap } from 'rxjs/operators';
|
||||
import { TaskCalendarStore } from './task-calendar.store';
|
||||
|
||||
@Component({
|
||||
selector: 'page-task-calendar',
|
||||
templateUrl: 'page-task-calendar.component.html',
|
||||
styleUrls: ['page-task-calendar.component.scss'],
|
||||
providers: [TaskCalendarStore],
|
||||
})
|
||||
export class PageTaskCalendarComponent implements OnInit {
|
||||
filterActive$ = new BehaviorSubject<boolean>(false);
|
||||
showMainContent$ = this.getShowMainContent();
|
||||
|
||||
constructor(private breadcrumb: BreadcrumbService, private taskCalendarStore: TaskCalendarStore) {
|
||||
this.taskCalendarStore.loadFilter();
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.breadcrumb.addBreadcrumbIfNotExists({
|
||||
key: 'task-calendar',
|
||||
name: 'Tätigkeitskalender',
|
||||
path: '/task-calendar/calendar',
|
||||
tags: ['task-calendar'],
|
||||
});
|
||||
}
|
||||
|
||||
getShowMainContent(animationDelayInMs: number = 500): Observable<boolean> {
|
||||
return this.filterActive$.pipe(
|
||||
switchMap((filterActive) => {
|
||||
const onExitMainContent = filterActive;
|
||||
if (onExitMainContent) {
|
||||
return of(!filterActive).pipe(delay(animationDelayInMs));
|
||||
}
|
||||
return of(!filterActive);
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
16
apps/page/task-calendar/src/lib/page-task-calendar.module.ts
Normal file
16
apps/page/task-calendar/src/lib/page-task-calendar.module.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { ShellBreadcrumbModule } from '@shell/breadcrumb';
|
||||
import { UiFilterModule } from '@ui/filter';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
import { TaskCalendarFilterComponent } from './containers/task-calendar-filter/task-calendar-filter.component';
|
||||
import { ModalsModule } from './modals/modals.module';
|
||||
import { PageTaskCalendarRoutingModule } from './page-task-calendar-routing.module';
|
||||
import { PageTaskCalendarComponent } from './page-task-calendar.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [PageTaskCalendarComponent, TaskCalendarFilterComponent],
|
||||
imports: [CommonModule, PageTaskCalendarRoutingModule, ShellBreadcrumbModule, UiIconModule, ModalsModule, UiFilterModule],
|
||||
exports: [PageTaskCalendarComponent],
|
||||
})
|
||||
export class PageTaskCalendarModule {}
|
||||
@@ -0,0 +1,10 @@
|
||||
<ui-calendar
|
||||
mode="month"
|
||||
[selected]="selectedDate$ | async"
|
||||
[displayed]="displayedDate$ | async"
|
||||
[minDate]="minDate$ | async"
|
||||
[maxDate]="maxDate$ | async"
|
||||
[indicators]="indicators$ | async"
|
||||
(selectedChange)="setSelectedDate($event)"
|
||||
(displayedChange)="setDisplayedDate($event)"
|
||||
></ui-calendar>
|
||||
@@ -0,0 +1,35 @@
|
||||
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { TaskCalendarStore } from '../../task-calendar.store';
|
||||
|
||||
@Component({
|
||||
selector: 'page-calendar',
|
||||
templateUrl: 'calendar.component.html',
|
||||
styleUrls: ['calendar.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class CalendarComponent {
|
||||
readonly selectedDate$ = this.taskCalendarStore.selectSelectedDate;
|
||||
|
||||
readonly displayedDate$ = this.taskCalendarStore.selectDisplayedDate;
|
||||
|
||||
readonly indicators$ = this.taskCalendarStore.selectCalendarIndicators;
|
||||
|
||||
readonly minDate$ = this.taskCalendarStore.selectMinDate;
|
||||
|
||||
readonly maxDate$ = this.taskCalendarStore.selectMaxDate;
|
||||
|
||||
constructor(private taskCalendarStore: TaskCalendarStore, private activatedRoute: ActivatedRoute, private router: Router) {
|
||||
this.taskCalendarStore.loadItems();
|
||||
}
|
||||
|
||||
setSelectedDate = (date: Date) => {
|
||||
this.taskCalendarStore.setSelectedDate({ date });
|
||||
this.taskCalendarStore.setDisplayedDate({ date });
|
||||
this.router.navigate(['../tasks'], {
|
||||
relativeTo: this.activatedRoute,
|
||||
});
|
||||
};
|
||||
|
||||
setDisplayedDate = (date: Date) => this.taskCalendarStore.setDisplayedDate({ date });
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { CalendarComponent } from './calendar.component';
|
||||
import { TaskCalendarPipesModule } from '../../pipes';
|
||||
import { UiCalendarModule } from '@ui/calendar';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, TaskCalendarPipesModule],
|
||||
imports: [CommonModule, UiCalendarModule],
|
||||
exports: [CalendarComponent],
|
||||
declarations: [CalendarComponent],
|
||||
providers: [],
|
||||
})
|
||||
export class CalendarModule {}
|
||||
@@ -0,0 +1,12 @@
|
||||
<ui-calendar
|
||||
mode="week"
|
||||
[selected]="selectedDate$ | async"
|
||||
[displayed]="displayedDate$ | async"
|
||||
[minDate]="minDate$ | async"
|
||||
[maxDate]="maxDate$ | async"
|
||||
[indicators]="indicators$ | async"
|
||||
(selectedChange)="setSelectedDate($event)"
|
||||
(displayedChange)="setDisplayedDate($event)"
|
||||
></ui-calendar>
|
||||
|
||||
<page-task-list [items]="items$ | async" [selected]="selectedDate$ | async" (select)="open($event)"></page-task-list>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user