update borrow + fix invite
This commit is contained in:
parent
59ac345933
commit
925a03fd46
@ -24,6 +24,7 @@
|
||||
"tsConfig": "tsconfig.app.json",
|
||||
"assets": [
|
||||
"src/.htaccess",
|
||||
"src/qr-scanner-worker.min.js",
|
||||
"src/favicon.ico",
|
||||
"src/assets"
|
||||
],
|
||||
|
826
package-lock.json
generated
826
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
36
package.json
36
package.json
@ -12,34 +12,36 @@
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular-material-components/datetime-picker": "^6.0.3",
|
||||
"@angular/animations": "~12.2.8",
|
||||
"@angular/cdk": "^12.2.8",
|
||||
"@angular/common": "~12.2.8",
|
||||
"@angular/compiler": "~12.2.8",
|
||||
"@angular/core": "~12.2.8",
|
||||
"@angular/animations": "^12.2.10",
|
||||
"@angular/cdk": "^12.2.10",
|
||||
"@angular/common": "^12.2.10",
|
||||
"@angular/compiler": "^12.2.10",
|
||||
"@angular/core": "^12.2.10",
|
||||
"@angular/flex-layout": "^12.0.0-beta.35",
|
||||
"@angular/forms": "~12.2.8",
|
||||
"@angular/material": "^12.2.8",
|
||||
"@angular/material-moment-adapter": "^12.2.8",
|
||||
"@angular/platform-browser": "~12.2.8",
|
||||
"@angular/platform-browser-dynamic": "~12.2.8",
|
||||
"@angular/router": "~12.2.8",
|
||||
"@angular/forms": "^12.2.10",
|
||||
"@angular/material": "^12.2.10",
|
||||
"@angular/material-moment-adapter": "^12.2.10",
|
||||
"@angular/platform-browser": "^12.2.10",
|
||||
"@angular/platform-browser-dynamic": "^12.2.10",
|
||||
"@angular/router": "^12.2.10",
|
||||
"moment": "^2.29.1",
|
||||
"ng-qrcode": "^5.1.1",
|
||||
"ngx-mat-timepicker": "^12.1.0",
|
||||
"openpgp": "^4.10.10",
|
||||
"qr-scanner": "^1.3.0",
|
||||
"rxjs": "~6.6.7",
|
||||
"tslib": "^2.3.1",
|
||||
"unique-names-generator": "^4.6.0",
|
||||
"zone.js": "~0.11.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "^12.2.8",
|
||||
"@angular/cli": "~12.2.8",
|
||||
"@angular/compiler-cli": "~12.2.8",
|
||||
"@angular/localize": "^12.2.8",
|
||||
"@types/jasmine": "^3.6.11",
|
||||
"@angular-devkit/build-angular": "^12.2.10",
|
||||
"@angular/cli": "^12.2.10",
|
||||
"@angular/compiler-cli": "^12.2.10",
|
||||
"@angular/localize": "^12.2.10",
|
||||
"@types/jasmine": "^3.10.0",
|
||||
"@types/jasminewd2": "^2.0.10",
|
||||
"@types/node": "^12.20.27",
|
||||
"@types/node": "^12.20.33",
|
||||
"@types/openpgp": "^4.4.18",
|
||||
"codelyzer": "^6.0.2",
|
||||
"jasmine-core": "~3.6.0",
|
||||
|
@ -27,6 +27,11 @@ import { InvitesComponent } from './pages/invites/invites.component';
|
||||
import { UrlShortenerComponent, UrlShortenerPasswordComponent } from './pages/urlshortener/urlshortener.component';
|
||||
import { MinetestAccountsComponent } from './pages/minetest/accounts/accounts.component';
|
||||
import { DividertestComponent } from './pages/dividertest/dividertest.component'
|
||||
import { BorrowProvingComponent } from './pages/borrow/proving/proving.component';
|
||||
import { BorrowItemEditComponent, BorrowItemsComponent } from './pages/borrow/items/items.component';
|
||||
import { BorrowRequestsComponent } from './pages/borrow/requests/requests.component';
|
||||
import { BorrowComponent } from './pages/borrow/borrow.component';
|
||||
import { InviteCodeComponent } from './pages/invites/code/code.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: 'profile/:username', component: UserComponent, canActivate: [ AuthUpdateGuard ] },
|
||||
@ -52,6 +57,14 @@ const routes: Routes = [
|
||||
{ path: 'domains', component: DomainsComponent, canActivate: [ AuthenticatedGuard ] }
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'borrow', component: BorrowComponent, canActivate: [ AuthenticatedGuard ], children: [
|
||||
{ path: '', redirectTo: "/borrow/items", pathMatch: 'full' },
|
||||
{ path: 'items', component: BorrowItemsComponent, canActivate: [ AuthenticatedGuard ] },
|
||||
{ path: 'requests', component: BorrowRequestsComponent, canActivate: [ AuthenticatedGuard ] },
|
||||
{ path: 'proving', component: BorrowProvingComponent, canActivate: [ AuthenticatedGuard ] }
|
||||
]
|
||||
},
|
||||
{ path: 'register', component: RegisterComponent, canActivate: [ AnonymousGuard ] },
|
||||
{ path: 'tokens', component: TokensComponent, canActivate: [ AuthGuard ] },
|
||||
{ path: 'jitsi', component: JitsiComponent, canActivate: [ AuthenticatedGuard ] },
|
||||
@ -62,6 +75,7 @@ const routes: Routes = [
|
||||
{ path: 'urlshortener', component: UrlShortenerComponent, canActivate: [ AuthenticatedGuard ] },
|
||||
{ path: 'urlshortener/:code', component: UrlShortenerPasswordComponent, canActivate: [ AuthUpdateGuard ] },
|
||||
{ path: 'invites/:quota', component: InvitesComponent, canActivate: [ AuthenticatedGuard ] },
|
||||
{ path: 'invite/:code', component: InviteCodeComponent, canActivate: [ AuthGuard ] },
|
||||
{ path: 'unavailable', component: UnavailableComponent },
|
||||
{ path: 'p/:username', component: UserComponent, canActivate: [ AuthUpdateGuard ] },
|
||||
{ path: '**', component: NotfoundComponent, pathMatch: 'full', canActivate: [ AuthUpdateGuard ] }, ]
|
||||
|
@ -13,6 +13,7 @@ import { DatePipe } from '@angular/common';
|
||||
import { AutofocusDirective } from './material/autofocus';
|
||||
|
||||
import { I18nPipe } from './utils/i18n.pipe';
|
||||
import { MomentPipe } from './utils/moment.pipe';
|
||||
import { MainComponent } from './ui/main/main.component';
|
||||
import { AccountComponent } from './pages/account/account.component';
|
||||
import { ServicesComponent } from './pages/services/services.component';
|
||||
@ -42,18 +43,25 @@ import { UsernameDialog } from './pages/register/username-dialog/username.dialog
|
||||
import { UnavailableComponent } from './pages/unavailable/unavailable.component';
|
||||
import { NotfoundComponent } from './pages/notfound/notfound.component';
|
||||
import { HtmlComponent } from './utils/html/html.component';
|
||||
import { ConfirmDialog } from './ui/confirm/confirm.component'
|
||||
import { UserComponent } from './pages/user/user.component'
|
||||
import { JitsiComponent, JitsiEditDialog, JitsiShareDialog } from './pages/jitsi/jitsi.component'
|
||||
import { ParteyComponent } from './pages/partey/partey.component'
|
||||
import { ParteyTimeslotsComponent, ParteyTimeslotDialog } from './pages/partey/timeslots/timeslots.compontent'
|
||||
import { UrlShortenerComponent, UrlShortenerPasswordComponent, UrlShortenerShareDialog, UrlShortenerEditDialog } from './pages/urlshortener/urlshortener.component'
|
||||
import { DividerComponent } from './ui/divider/divider.component'
|
||||
import { DividertestComponent } from './pages/dividertest/dividertest.component'
|
||||
import { ConfirmDialog } from './ui/confirm/confirm.component';
|
||||
import { UserComponent } from './pages/user/user.component';
|
||||
import { JitsiComponent, JitsiEditDialog, JitsiShareDialog } from './pages/jitsi/jitsi.component';
|
||||
import { ParteyComponent } from './pages/partey/partey.component';
|
||||
import { ParteyTimeslotsComponent, ParteyTimeslotDialog } from './pages/partey/timeslots/timeslots.compontent';
|
||||
import { UrlShortenerComponent, UrlShortenerPasswordComponent, UrlShortenerShareDialog, UrlShortenerEditDialog } from './pages/urlshortener/urlshortener.component';
|
||||
import { BorrowItemEditComponent, BorrowItemsComponent } from './pages/borrow/items/items.component';
|
||||
import { BorrowRequestEditComponent, BorrowRequestsComponent } from './pages/borrow/requests/requests.component';
|
||||
import { BorrowProvingComponent, BorrowProvingResultDialog } from './pages/borrow/proving/proving.component';
|
||||
import { DividerComponent } from './ui/divider/divider.component';
|
||||
import { DividertestComponent } from './pages/dividertest/dividertest.component';
|
||||
|
||||
|
||||
import { I18nService } from './services/i18n.service';
|
||||
import { MinetestAccountsComponent } from './pages/minetest/accounts/accounts.component';
|
||||
import { BorrowComponent } from './pages/borrow/borrow.component';
|
||||
import { DurationpickerComponent } from './ui/durationpicker/durationpicker.component';
|
||||
import { InviteCodeComponent } from './pages/invites/code/code.component';
|
||||
import { InviteEditComponent } from './pages/invites/edit/invite.edit';
|
||||
|
||||
|
||||
export function init_app(i18n: I18nService) {
|
||||
@ -75,6 +83,7 @@ export class XhrInterceptor implements HttpInterceptor {
|
||||
declarations: [
|
||||
AutofocusDirective,
|
||||
I18nPipe,
|
||||
MomentPipe,
|
||||
MainComponent,
|
||||
AppComponent,
|
||||
AccountComponent,
|
||||
@ -82,7 +91,7 @@ export class XhrInterceptor implements HttpInterceptor {
|
||||
FormLoginComponent,
|
||||
FormLogin2FAComponent,
|
||||
TokensComponent,
|
||||
InvitesComponent,
|
||||
InvitesComponent, InviteCodeComponent, InviteEditComponent,
|
||||
ServicesComponent,
|
||||
PermissionsComponent,
|
||||
ProfileFieldsComponent, ProfileFieldDialog, ProfileFieldBlob, ProfileFieldPgpBlob,
|
||||
@ -110,7 +119,9 @@ export class XhrInterceptor implements HttpInterceptor {
|
||||
ParteyComponent, ParteyTimeslotsComponent, ParteyTimeslotDialog,
|
||||
MinetestAccountsComponent,
|
||||
UrlShortenerComponent, UrlShortenerShareDialog, UrlShortenerEditDialog, UrlShortenerPasswordComponent,
|
||||
DividerComponent, DividertestComponent
|
||||
BorrowComponent, BorrowItemsComponent, BorrowItemEditComponent, BorrowRequestsComponent, BorrowRequestEditComponent, BorrowProvingComponent, BorrowProvingResultDialog,
|
||||
DividerComponent, DividertestComponent,
|
||||
DurationpickerComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
|
@ -47,10 +47,11 @@ import {FlexLayoutModule} from '@angular/flex-layout';
|
||||
|
||||
import {
|
||||
NgxMatDatetimePickerModule,
|
||||
NgxMatNativeDateModule,
|
||||
NgxMatTimepickerModule
|
||||
NgxMatNativeDateModule
|
||||
} from '@angular-material-components/datetime-picker';
|
||||
|
||||
import { NgxMatTimepickerModule } from 'ngx-mat-timepicker';
|
||||
|
||||
@NgModule({
|
||||
declarations: [],
|
||||
imports: [
|
||||
|
15
src/app/pages/borrow/borrow.component.html
Normal file
15
src/app/pages/borrow/borrow.component.html
Normal file
@ -0,0 +1,15 @@
|
||||
<h2>{{'borrow' | i18n}}</h2>
|
||||
|
||||
<nav mat-tab-nav-bar>
|
||||
<a mat-tab-link routerLink="items" routerLinkActive="active-tab" #rlaitems="routerLinkActive"
|
||||
[active]="rlaitems.isActive">{{'borrow.items'
|
||||
| i18n}}</a>
|
||||
<a mat-tab-link routerLink="requests" routerLinkActive="active-tab" #rlarequests="routerLinkActive"
|
||||
[active]="rlarequests.isActive">{{'borrow.requests'
|
||||
| i18n}}</a>
|
||||
<a mat-tab-link routerLink="proving" routerLinkActive="active-tab" #rlaproving="routerLinkActive"
|
||||
[active]="rlaproving.isActive">{{'borrow.proving'
|
||||
| i18n}}</a>
|
||||
</nav>
|
||||
|
||||
<router-outlet></router-outlet>
|
0
src/app/pages/borrow/borrow.component.scss
Normal file
0
src/app/pages/borrow/borrow.component.scss
Normal file
10
src/app/pages/borrow/borrow.component.ts
Normal file
10
src/app/pages/borrow/borrow.component.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-borrow',
|
||||
templateUrl: './borrow.component.html',
|
||||
styleUrls: [ './borrow.component.scss' ]
|
||||
})
|
||||
export class BorrowComponent {
|
||||
|
||||
}
|
204
src/app/pages/borrow/items/item.edit.html
Normal file
204
src/app/pages/borrow/items/item.edit.html
Normal file
@ -0,0 +1,204 @@
|
||||
<h2 mat-dialog-title>{{(create ? 'borrow.items.create' : 'borrow.items.edit') | i18n}}</h2>
|
||||
<mat-dialog-content>
|
||||
<form [formGroup]="form">
|
||||
<mat-form-field>
|
||||
<input matInput placeholder="{{'borrow.items.name' | i18n}}" formControlName="name">
|
||||
<mat-error>
|
||||
{{'borrow.items.error.name' | i18n}}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field>
|
||||
<textarea matInput placeholder="{{'borrow.items.description' | i18n}}" formControlName="description"></textarea>
|
||||
<mat-error>
|
||||
{{'borrow.items.error.description' | i18n}}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field>
|
||||
<input matInput placeholder="{{'borrow.items.url' | i18n}}" formControlName="url">
|
||||
<mat-error>
|
||||
{{'borrow.items.error.url' | i18n}}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<div fxLayout="row wrap" fxLayoutGap="24px grid">
|
||||
<mat-form-field floatLabel="always" appearance="none" fxFlex="50%" fxFlex.sm="100%" fxFlex.xs="100%">
|
||||
<input matInput hidden formControlName="minDuration" />
|
||||
<label>{{'borrow.items.minDuration' | i18n}}</label>
|
||||
<app-durationpicker formControlName="minDuration"></app-durationpicker>
|
||||
<mat-error>
|
||||
{{'borrow.items.error.minDuration' | i18n}}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field floatLabel="always" appearance="none" fxFlex="50%" fxFlex.sm="100%" fxFlex.xs="100%">
|
||||
<input matInput hidden formControlName="maxDuration" />
|
||||
<label>{{'borrow.items.maxDuration' | i18n}}</label>
|
||||
<app-durationpicker formControlName="maxDuration"></app-durationpicker>
|
||||
<mat-error>
|
||||
{{'borrow.items.error.maxDuration' | i18n}}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div fxLayout="row wrap" fxLayoutAlign="start stretch" fxLayoutGap="24px grid">
|
||||
<mat-form-field>
|
||||
<mat-select formControlName="availability" placeholder="{{'borrow.items.availability' | i18n}}">
|
||||
<mat-option value="ALWAYS">
|
||||
{{'borrow.items.availability.ALWAYS' | i18n}}
|
||||
</mat-option>
|
||||
<mat-option value="PERIOD">
|
||||
{{'borrow.items.availability.PERIOD' | i18n}}
|
||||
</mat-option>
|
||||
<mat-option value="MANUAL">
|
||||
{{'borrow.items.availability.MANUAL' | i18n}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
<mat-error>
|
||||
{{'borrow.items.error.availability' | i18n}}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field floatLabel="always" appearance="none">
|
||||
<mat-slide-toggle formControlName="autoAccept">{{'borrow.items.autoAccept' | i18n}}
|
||||
</mat-slide-toggle>
|
||||
<input matInput hidden />
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field floatLabel="always" appearance="none">
|
||||
<mat-slide-toggle formControlName="emailNotification">
|
||||
{{'borrow.items.emailNotification' | i18n}}
|
||||
</mat-slide-toggle>
|
||||
<input matInput hidden />
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field *ngIf="form.get('emailNotification').value" fxFlex="1 1 0%">
|
||||
<input matInput type="email" placeholder="{{'borrow.items.email' | i18n}}" formControlName="email">
|
||||
<mat-error>
|
||||
{{'borrow.items.error.email' | i18n}}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<ng-container *ngIf="form.get('availability').value == 'MANUAL'">
|
||||
<mat-divider></mat-divider><br>
|
||||
<label>{{'borrow.items.slot.MANUAL' | i18n}}</label>
|
||||
<button mat-icon-button (click)="addManualSlot('','','')" title="{{'borrow.items.slot.add' | i18n}}">
|
||||
<mat-icon>control_point_duplicate</mat-icon>
|
||||
</button>
|
||||
<ng-container *ngFor="let slotForm of slots.controls; let i = index">
|
||||
<div [formGroup]="slotForm" fxLayout="row wrap" fxLayoutAlign="start stretch" fxLayoutGap="24px grid">
|
||||
<mat-form-field>
|
||||
<input matInput [ngxMatDatetimePicker]="slotStartPicker" formControlName="start"
|
||||
placeholder="{{'borrow.items.slot.start' | i18n}}">
|
||||
<mat-datepicker-toggle matSuffix [for]="slotStartPicker"></mat-datepicker-toggle>
|
||||
<ngx-mat-datetime-picker #slotStartPicker></ngx-mat-datetime-picker>
|
||||
<mat-error>
|
||||
{{'borrow.items.error.slot.start' | i18n}}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field>
|
||||
<input matInput [ngxMatDatetimePicker]="slotEndPicker" formControlName="end"
|
||||
placeholder="{{'borrow.items.slot.end' | i18n}}">
|
||||
<mat-datepicker-toggle matSuffix [for]="slotEndPicker"></mat-datepicker-toggle>
|
||||
<ngx-mat-datetime-picker #slotEndPicker></ngx-mat-datetime-picker>
|
||||
<mat-error>
|
||||
{{'borrow.items.error.slot.end' | i18n}}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<div>
|
||||
<button mat-icon-button (click)="dublicateSlot(i)" title="{{'borrow.items.slot.dublicate' | i18n}}">
|
||||
<mat-icon>control_point_duplicate</mat-icon>
|
||||
</button>
|
||||
<button mat-icon-button (click)="deleteSlot(i)" title="{{'borrow.items.slot.delete' | i18n}}">
|
||||
<mat-icon>delete</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="form.get('availability').value == 'PERIOD'">
|
||||
<mat-divider></mat-divider><br>
|
||||
<label>{{'borrow.items.slot.PERIOD' | i18n}}</label>
|
||||
<button mat-icon-button (click)="addPeriodSlot('','','','','')" title="{{'borrow.items.slot.add' | i18n}}">
|
||||
<mat-icon>control_point_duplicate</mat-icon>
|
||||
</button>
|
||||
<ng-container *ngFor="let slotForm of slots.controls; let i = index">
|
||||
<div [formGroup]="slotForm" fxLayout="row wrap" fxLayoutAlign="start stretch" fxLayoutGap="12px grid">
|
||||
<mat-form-field>
|
||||
<mat-select formControlName="startDay" placeholder="{{'borrow.items.slot.startDay' | i18n}}">
|
||||
<mat-option *ngFor="let day of weekdays" [value]="day">
|
||||
{{'borrow.items.slot.day.' + day | i18n}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
<mat-error>
|
||||
{{'borrow.items.error.slot.startDay' | i18n}}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field>
|
||||
<input matInput format="24" [ngxMatTimepicker]="startTimePicker" formControlName="startTime"
|
||||
placeholder="{{'borrow.items.slot.startTime' | i18n}}">
|
||||
<mat-icon matSuffix (click)="startTimePicker.open()">
|
||||
watch_later
|
||||
</mat-icon>
|
||||
<mat-error>
|
||||
{{'borrow.items.error.slot.startTime' | i18n}}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
<ngx-mat-timepicker #startTimePicker></ngx-mat-timepicker>
|
||||
|
||||
<mat-form-field>
|
||||
<mat-select formControlName="endDay" placeholder="{{'borrow.items.slot.endDay' | i18n}}">
|
||||
<mat-option *ngFor="let day of weekdays" [value]="day">
|
||||
{{'borrow.items.slot.day.' + day | i18n}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
<mat-error>
|
||||
{{'borrow.items.error.slot.endDay' | i18n}}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field>
|
||||
<input matInput format="24" [ngxMatTimepicker]="endTimePicker" formControlName="endTime"
|
||||
placeholder="{{'borrow.items.slot.endTime' | i18n}}">
|
||||
<mat-icon matSuffix (click)="endTimePicker.open()">
|
||||
watch_later
|
||||
</mat-icon>
|
||||
<mat-error>
|
||||
{{'borrow.items.error.slot.endTime' | i18n}}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
<ngx-mat-timepicker #endTimePicker></ngx-mat-timepicker>
|
||||
|
||||
<div>
|
||||
<button mat-icon-button (click)="dublicateSlot(i)" title="{{'borrow.items.slot.dublicate' | i18n}}">
|
||||
<mat-icon>control_point_duplicate</mat-icon>
|
||||
</button>
|
||||
<button mat-icon-button (click)="deleteSlot(i)" title="{{'borrow.items.slot.delete' | i18n}}">
|
||||
<mat-icon>delete</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</form>
|
||||
</mat-dialog-content>
|
||||
<mat-dialog-actions>
|
||||
<div fxLayout="row" fxLayoutAlign="space-between start">
|
||||
<div>
|
||||
<button mat-button [mat-dialog-close]="false">{{'cancel' | i18n}}</button>
|
||||
<button [disabled]="form.invalid" mat-raised-button (click)="save()" color="accent">
|
||||
<mat-icon>save</mat-icon>{{(create ? 'borrow.items.create' : 'borrow.items.save') | i18n}}
|
||||
</button>
|
||||
</div>
|
||||
<button *ngIf="borrowItemId" mat-button color="warn" (click)="confirmDelete()">
|
||||
<mat-icon>delete</mat-icon> {{ 'borrow.items.delete' |
|
||||
i18n}}
|
||||
</button>
|
||||
</div>
|
||||
</mat-dialog-actions>
|
7
src/app/pages/borrow/items/item.edit.scss
Normal file
7
src/app/pages/borrow/items/item.edit.scss
Normal file
@ -0,0 +1,7 @@
|
||||
mat-form-field {
|
||||
display: block;
|
||||
}
|
||||
|
||||
mat-dialog-actions>div {
|
||||
width: 100%;
|
||||
}
|
65
src/app/pages/borrow/items/items.component.html
Normal file
65
src/app/pages/borrow/items/items.component.html
Normal file
@ -0,0 +1,65 @@
|
||||
<h3>{{'borrow.items' | i18n}}</h3>
|
||||
<div *ngIf="borrowItems">
|
||||
<div fxLayout="row" fxLayoutAlign="space-between start">
|
||||
<form>
|
||||
<mat-form-field>
|
||||
<input matInput [formControl]="searchFormControl" placeholder="{{'borrow.items.search' | i18n}}">
|
||||
</mat-form-field>
|
||||
<mat-form-field floatLabel="always" appearance="none">
|
||||
<mat-slide-toggle [formControl]="ownerFormControl">{{'borrow.items.mine' | i18n}}</mat-slide-toggle>
|
||||
<input matInput hidden />
|
||||
</mat-form-field>
|
||||
</form>
|
||||
<button mat-raised-button (click)="create()" color="accent">{{'borrow.items.create' | i18n}}</button>
|
||||
</div>
|
||||
<table mat-table matSort [dataSource]="borrowItems.content" (matSortChange)="updateSort($event)">
|
||||
<ng-container matColumnDef="name">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header="name"> {{'borrow.items.name' | i18n}} </th>
|
||||
<td mat-cell *matCellDef="let borrowItem"> {{ borrowItem.name}} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="description">
|
||||
<th mat-header-cell *matHeaderCellDef> {{'borrow.items.description' | i18n}} </th>
|
||||
<td mat-cell *matCellDef="let borrowItem"> {{ borrowItem.description}} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="availability">
|
||||
<th mat-header-cell *matHeaderCellDef> {{'borrow.items.availability' | i18n}} </th>
|
||||
<td mat-cell *matCellDef="let borrowItem"> {{ 'borrow.items.availability.' + borrowItem.availability | i18n}}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="url">
|
||||
<th mat-header-cell *matHeaderCellDef> {{'borrow.items.url' | i18n}} </th>
|
||||
<td mat-cell *matCellDef="let borrowItem">
|
||||
<a *ngIf="borrowItem.url" mat-button color="accent" href="{{ borrowItem.url }}" target="_blank">
|
||||
{{ borrowItem.url }}
|
||||
<mat-icon style="font-size: 1em;">open_in_new</mat-icon>
|
||||
</a>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef class="align-right"> {{'borrow.items.actions' | i18n}} </th>
|
||||
<td mat-cell *matCellDef="let borrowItem" class="text-right">
|
||||
<a mat-icon-button *ngIf="borrowItem.owner == userId">
|
||||
<mat-icon (click)="request(borrowItem)">pending_actions</mat-icon>
|
||||
</a>
|
||||
<a mat-icon-button *ngIf="borrowItem.owner == userId">
|
||||
<mat-icon (click)="edit(borrowItem)">edit</mat-icon>
|
||||
</a>
|
||||
<a mat-icon-button *ngIf="borrowItem.owner == userId">
|
||||
<mat-icon (click)="confirmDelete(borrowItem)">delete</mat-icon>
|
||||
</a>
|
||||
<a mat-icon-button *ngIf="borrowItem.owner != userId">
|
||||
<mat-icon (click)="request(borrowItem)">pending_actions</mat-icon>
|
||||
</a>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="borrowItemColumns"></tr>
|
||||
<tr mat-row *matRowDef="let myRowData; columns: borrowItemColumns"></tr>
|
||||
</table>
|
||||
<mat-paginator [pageSizeOptions]="pageSizeOptions" [length]="borrowItems.totalElements" [pageSize]="borrowItems.size"
|
||||
(page)="updatePages($event)" showFirstLastButtons></mat-paginator>
|
||||
</div>
|
21
src/app/pages/borrow/items/items.component.scss
Normal file
21
src/app/pages/borrow/items/items.component.scss
Normal file
@ -0,0 +1,21 @@
|
||||
.mat-form-field+.mat-form-field, .mat-form-field+.mat-slide-toggle {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.mat-header-cell,
|
||||
.mat-cell {
|
||||
&.text-right {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
.mat-cell .mat-button {
|
||||
padding-left: 0px;
|
||||
padding-right: 0px;
|
||||
}
|
||||
|
||||
.align-right{
|
||||
display: flex;
|
||||
padding: 21px 0;
|
||||
justify-content: flex-end;
|
||||
}
|
410
src/app/pages/borrow/items/items.component.ts
Normal file
410
src/app/pages/borrow/items/items.component.ts
Normal file
@ -0,0 +1,410 @@
|
||||
import { Component, Inject, OnInit } from '@angular/core';
|
||||
import { FormArray, FormBuilder, FormControl, FormGroup, ValidatorFn, Validators } from '@angular/forms';
|
||||
import { debounceTime } from 'rxjs/operators';
|
||||
import { PageEvent } from '@angular/material/paginator';
|
||||
import { Sort } from '@angular/material/sort';
|
||||
import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
import * as moment from 'moment';
|
||||
|
||||
import { ConfirmDialog } from '../../../ui/confirm/confirm.component';
|
||||
import { BorrowItemsService } from './../../../services/borrow.service';
|
||||
import { AuthService } from './../../../services/auth.service';
|
||||
import { BorrowRequestEditComponent } from '../requests/requests.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-borrow-items',
|
||||
templateUrl: './items.component.html',
|
||||
styleUrls: [ './items.component.scss' ]
|
||||
})
|
||||
export class BorrowItemsComponent implements OnInit {
|
||||
|
||||
borrowItems: any[];
|
||||
page: any = { page: 0, size: 10, sort: "id", desc: false };
|
||||
pageSizeOptions: number[] = [ 5, 10, 25, 50 ];
|
||||
searchFormControl = new FormControl();
|
||||
ownerFormControl = new FormControl();
|
||||
userId: any;
|
||||
|
||||
borrowItemColumns = [ "name", "description", "availability", "url", "actions" ];
|
||||
|
||||
constructor(private borrowItemsService: BorrowItemsService,
|
||||
private authService: AuthService,
|
||||
public dialog: MatDialog) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.authService.auth.subscribe((auth: any) => {
|
||||
if (auth.principal && auth.principal.userId) {
|
||||
this.userId = auth.principal.userId;
|
||||
}
|
||||
});
|
||||
|
||||
this.searchFormControl.valueChanges.pipe(debounceTime(500)).subscribe(value => {
|
||||
this.borrowItemsService.getItems(0, this.page.size, this.page.sort, this.page.desc, value, this.ownerFormControl.value).subscribe((data: any) => {
|
||||
this.borrowItems = data;
|
||||
}, (error) => { })
|
||||
})
|
||||
|
||||
this.ownerFormControl.valueChanges.subscribe(value => {
|
||||
this.borrowItemsService.getItems(0, this.page.size, this.page.sort, this.page.desc, this.searchFormControl.value, value).subscribe((data: any) => {
|
||||
this.borrowItems = data;
|
||||
}, (error) => { })
|
||||
})
|
||||
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
refresh(): void {
|
||||
this.borrowItemsService.getItems(this.page.page, this.page.size, this.page.sort, this.page.desc, this.searchFormControl.value, this.ownerFormControl.value).subscribe((data: any) => {
|
||||
this.borrowItems = data;
|
||||
})
|
||||
}
|
||||
|
||||
updatePages(event: PageEvent) {
|
||||
this.page.page = event.pageIndex;
|
||||
this.page.size = event.pageSize;
|
||||
this.borrowItemsService.getItems(this.page.page, this.page.size, this.page.sort, this.page.desc, this.searchFormControl.value, this.ownerFormControl.value).subscribe((data: any) => {
|
||||
this.borrowItems = data;
|
||||
}, (error) => { })
|
||||
}
|
||||
|
||||
updateSort(sort: Sort) {
|
||||
if (sort.direction == "") {
|
||||
this.page.sort = "id";
|
||||
this.page.desc = false;
|
||||
} else {
|
||||
this.page.sort = sort.active;
|
||||
this.page.desc = sort.direction == "desc";
|
||||
}
|
||||
this.borrowItemsService.getItems(this.page.page, this.page.size, this.page.sort, this.page.desc, this.searchFormControl.value, this.ownerFormControl.value).subscribe((data: any) => {
|
||||
this.borrowItems = data;
|
||||
}, (error) => { })
|
||||
}
|
||||
|
||||
edit(borrowItem) {
|
||||
const dialogRef = this.dialog.open(BorrowItemEditComponent, {
|
||||
data: borrowItem,
|
||||
minWidth: '80%'
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
if (result) {
|
||||
this.refresh();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
create() {
|
||||
const dialogRef = this.dialog.open(BorrowItemEditComponent, {
|
||||
data: {},
|
||||
minWidth: '80%'
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
if (result) {
|
||||
this.refresh();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
request(borrowItem) {
|
||||
const dialogRef = this.dialog.open(BorrowRequestEditComponent, {
|
||||
data: {
|
||||
"user": this.userId,
|
||||
"borrowItem": borrowItem
|
||||
}
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
if (result) {
|
||||
this.refresh();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
confirmDelete(borrowItem) {
|
||||
const dialogRef = this.dialog.open(ConfirmDialog, {
|
||||
data: {
|
||||
'label': 'borrow.items.confirmDelete',
|
||||
'args': [ borrowItem.name ]
|
||||
}
|
||||
})
|
||||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
if (result) {
|
||||
this.borrowItemsService.deleteItem(borrowItem.id).subscribe((result: any) => {
|
||||
this.refresh();
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-borrow-item-edit',
|
||||
templateUrl: './item.edit.html',
|
||||
styleUrls: [ './item.edit.scss' ]
|
||||
})
|
||||
export class BorrowItemEditComponent {
|
||||
|
||||
borrowItemId: number;
|
||||
create: boolean = false;
|
||||
form: FormGroup;
|
||||
weekdays: string[] = [ 'MONDAY', 'TUESDAY', 'WEDNESDAY', 'THURSDAY', 'FRIDAY', 'SATURDAY', 'SUNDAY' ];
|
||||
|
||||
constructor(private borrowItemsService: BorrowItemsService,
|
||||
private formBuilder: FormBuilder,
|
||||
@Inject(MAT_DIALOG_DATA) public data: any,
|
||||
public dialogRef: MatDialogRef<BorrowItemEditComponent>,
|
||||
public dialog: MatDialog) {
|
||||
|
||||
this.form = this.formBuilder.group({
|
||||
name: [ '', Validators.required ],
|
||||
description: [ '', Validators.nullValidator ],
|
||||
url: [ '', Validators.nullValidator ],
|
||||
minDuration: [ '', Validators.nullValidator ],
|
||||
maxDuration: [ '', Validators.nullValidator ],
|
||||
availability: [ '', Validators.required ],
|
||||
autoAccept: [ '', Validators.nullValidator ],
|
||||
emailNotification: [ '', Validators.nullValidator ],
|
||||
email: [ '', Validators.nullValidator ],
|
||||
slots: this.formBuilder.array([])
|
||||
}, { validators: [ durationValidator ] })
|
||||
|
||||
this.form.get('availability').valueChanges.subscribe((value) => {
|
||||
this.slots.clear();
|
||||
if (value == 'MANUAL') {
|
||||
this.addManualSlot('', '', '');
|
||||
} else if (value == 'PERIOD') {
|
||||
this.addPeriodSlot('', '', '', '', '');
|
||||
}
|
||||
})
|
||||
|
||||
if (data.id) {
|
||||
this.borrowItemId = + data.id;
|
||||
} else {
|
||||
this.create = true;
|
||||
this.borrowItemId = undefined;
|
||||
}
|
||||
|
||||
this.form.get('name').setValue(data.name, { emitEvent: false });
|
||||
this.form.get('description').setValue(data.description, { emitEvent: false });
|
||||
this.form.get('url').setValue(data.url, { emitEvent: false });
|
||||
this.form.get('minDuration').setValue(data.minDuration, { emitEvent: false });
|
||||
this.form.get('maxDuration').setValue(data.maxDuration, { emitEvent: false });
|
||||
this.form.get('availability').setValue(data.availability || 'ALWAYS', { emitEvent: false });
|
||||
this.form.get('autoAccept').setValue(data.autoAccept, { emitEvent: false });
|
||||
this.form.get('emailNotification').setValue(data.emailNotification, { emitEvent: false });
|
||||
this.form.get('email').setValue(data.email), { emitEvent: false };
|
||||
if (data.slots) {
|
||||
for (let slot of data.slots) {
|
||||
if (data.availability == 'MANUAL') {
|
||||
this.addManualSlot(slot.id, slot.start, slot.end);
|
||||
} else if (data.availability == 'PERIOD') {
|
||||
this.addPeriodSlot(slot.id, slot.startDay, slot.startTime, slot.endDay, slot.endTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
formToBorrowItem(): any {
|
||||
const borrowItem: any = {};
|
||||
borrowItem.id = this.borrowItemId;
|
||||
borrowItem.name = this.form.get('name').value;
|
||||
borrowItem.description = this.form.get('description').value;
|
||||
borrowItem.url = this.form.get('url').value;
|
||||
borrowItem.minDuration = this.form.get('minDuration').value;
|
||||
borrowItem.maxDuration = this.form.get('maxDuration').value;
|
||||
borrowItem.availability = this.form.get('availability').value;
|
||||
borrowItem.autoAccept = this.form.get('autoAccept').value;
|
||||
borrowItem.emailNotification = this.form.get('emailNotification').value;
|
||||
borrowItem.email = this.form.get('email').value;
|
||||
const slots: any[] = [];
|
||||
for (let slotForm of this.slots.controls) {
|
||||
if (borrowItem.availability == 'MANUAL') {
|
||||
slots.push({
|
||||
id: slotForm.get('id').value,
|
||||
start: slotForm.get('start').value,
|
||||
end: slotForm.get('end').value,
|
||||
type: 'MANUAL'
|
||||
})
|
||||
} else if (borrowItem.availability == 'PERIOD') {
|
||||
slots.push({
|
||||
id: slotForm.get('id').value,
|
||||
startDay: slotForm.get('startDay').value,
|
||||
startTime: slotForm.get('startTime').value,
|
||||
endDay: slotForm.get('endDay').value,
|
||||
endTime: slotForm.get('endTime').value,
|
||||
type: 'PERIOD'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
borrowItem.slots = slots;
|
||||
return borrowItem;
|
||||
}
|
||||
|
||||
get slots() {
|
||||
return this.form.controls[ "slots" ] as FormArray;
|
||||
}
|
||||
|
||||
deleteSlot(index: number) {
|
||||
this.slots.removeAt(index);
|
||||
}
|
||||
|
||||
dublicateSlot(index: number) {
|
||||
this.slots.push(this.slots.at(index));
|
||||
}
|
||||
|
||||
addManualSlot(id, start, end) {
|
||||
const manualSlotForm = this.formBuilder.group({
|
||||
id: [ id, Validators.required ],
|
||||
start: [ start, Validators.required ],
|
||||
end: [ end, Validators.required ]
|
||||
}, { validators: [ manualSlotValidator ] });
|
||||
this.slots.push(manualSlotForm);
|
||||
}
|
||||
|
||||
addPeriodSlot(id, startDay: string, startTime: string, endDay: string, endTime: string) {
|
||||
if (startTime.length == 8) {
|
||||
startTime = startTime.substr(0, 5);
|
||||
}
|
||||
if (endTime.length == 8) {
|
||||
endTime = endTime.substr(0, 5);
|
||||
}
|
||||
const perdiodSlotForm = this.formBuilder.group({
|
||||
id: [ id, Validators.required ],
|
||||
startDay: [ startDay, Validators.required ],
|
||||
startTime: [ startTime, Validators.required ],
|
||||
endDay: [ endDay, Validators.required ],
|
||||
endTime: [ endTime, Validators.required ]
|
||||
}, { validators: [ periodSlotValidator ] });
|
||||
this.slots.push(perdiodSlotForm);
|
||||
}
|
||||
|
||||
|
||||
save() {
|
||||
this.borrowItemsService.createOrUpdateItem(this.formToBorrowItem()).subscribe((data: any) => {
|
||||
this.dialogRef.close(data);
|
||||
}, (error) => {
|
||||
if (error.status == 409) {
|
||||
let errors = {};
|
||||
for (let code of error.error) {
|
||||
errors[ code.field ] = errors[ code.field ] || {};
|
||||
errors[ code.field ][ code.code ] = true;
|
||||
}
|
||||
|
||||
for (let code in errors) {
|
||||
this.form.get(code).setErrors(errors[ code ]);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
confirmDelete() {
|
||||
const borrowItem = this.formToBorrowItem();
|
||||
|
||||
const dialogRef = this.dialog.open(ConfirmDialog, {
|
||||
data: {
|
||||
'label': 'borrow.items.confirmDelete',
|
||||
'args': [ borrowItem.name ]
|
||||
}
|
||||
})
|
||||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
if (result) {
|
||||
this.borrowItemsService.deleteItem(borrowItem.id).subscribe((result: any) => {
|
||||
this.dialogRef.close(true);
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const durationValidator: ValidatorFn = (fg: FormGroup) => {
|
||||
const minDuration = fg.get('minDuration').value;
|
||||
const maxDuration = fg.get('maxDuration').value;
|
||||
fg.get('minDuration').setErrors(null);
|
||||
fg.get('maxDuration').setErrors(null);
|
||||
|
||||
if (minDuration && maxDuration && (moment.duration(minDuration).asMinutes() >= moment.duration(maxDuration).asMinutes())) {
|
||||
fg.get('minDuration').setErrors([ 'INVALID' ]);
|
||||
fg.get('maxDuration').setErrors([ 'INVALID' ]);
|
||||
return { 'INVALID': true };
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
|
||||
const manualSlotValidator: ValidatorFn = (fg: FormGroup) => {
|
||||
const start = fg.get('start').value;
|
||||
const end = fg.get('end').value;
|
||||
|
||||
fg.get('id').setErrors(null);
|
||||
fg.get('start').setErrors(null);
|
||||
fg.get('end').setErrors(null);
|
||||
|
||||
if (!start) {
|
||||
fg.get('start').setErrors([ 'MISSING_DATES' ]);
|
||||
return { 'MISSING_DATES': true };
|
||||
}
|
||||
if (!end) {
|
||||
fg.get('end').setErrors([ 'MISSING_DATES' ]);
|
||||
return { 'MISSING_DATES': true };
|
||||
}
|
||||
|
||||
if (start >= end) {
|
||||
fg.get('start').setErrors([ 'INVALID_DATES' ]);
|
||||
fg.get('end').setErrors([ 'INVALID_DATES' ]);
|
||||
return { 'INVALID_DATES': true };
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const periodSlotValidator: ValidatorFn = (fg: FormGroup) => {
|
||||
const weekdays: string[] = [ 'MONDAY', 'TUESDAY', 'WEDNESDAY', 'THURSDAY', 'FRIDAY', 'SATURDAY', 'SUNDAY' ];
|
||||
const startDay = fg.get('startDay').value;
|
||||
const startTime = fg.get('startTime').value;
|
||||
const endDay = fg.get('endDay').value;
|
||||
const endTime = fg.get('endTime').value;
|
||||
|
||||
fg.get('id').setErrors(null);
|
||||
fg.get('startDay').setErrors(null);
|
||||
fg.get('startTime').setErrors(null);
|
||||
fg.get('endDay').setErrors(null);
|
||||
fg.get('endTime').setErrors(null);
|
||||
|
||||
if (!startDay) {
|
||||
fg.get('startDay').setErrors([ 'MISSING_DATES' ]);
|
||||
return { 'MISSING_DATES': true };
|
||||
}
|
||||
if (!startTime) {
|
||||
fg.get('startTime').setErrors([ 'MISSING_DATES' ]);
|
||||
return { 'MISSING_DATES': true };
|
||||
}
|
||||
if (!endDay) {
|
||||
fg.get('endDay').setErrors([ 'MISSING_DATES' ]);
|
||||
return { 'MISSING_DATES': true };
|
||||
}
|
||||
if (!endTime) {
|
||||
fg.get('endTime').setErrors([ 'MISSING_DATES' ]);
|
||||
return { 'MISSING_DATES': true };
|
||||
}
|
||||
|
||||
if (weekdays.indexOf(startDay) > weekdays.indexOf(endDay)) {
|
||||
fg.get('startDay').setErrors([ 'INVALID_DAY' ]);
|
||||
fg.get('endDay').setErrors([ 'INVALID_DAY' ]);
|
||||
return { 'INVALID_DAY': true };
|
||||
}
|
||||
|
||||
if (weekdays.indexOf(startDay) == weekdays.indexOf(endDay) && startTime >= endTime) {
|
||||
fg.get('startTime').setErrors([ 'INVALID_TIME' ]);
|
||||
fg.get('endTime').setErrors([ 'INVALID_TIME' ]);
|
||||
return { 'INVALID_TIME': true };
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
30
src/app/pages/borrow/proving/proving.component.html
Normal file
30
src/app/pages/borrow/proving/proving.component.html
Normal file
@ -0,0 +1,30 @@
|
||||
<video #qrCam></video>
|
||||
|
||||
<form fxLayout="row wrap" fxLayoutGap="24px grid">
|
||||
<mat-form-field>
|
||||
<mat-select [formControl]="camera" name="camera" placeholder="{{'borrow.proving.camera' | i18n}}">
|
||||
<mat-option *ngFor="let camera of cameras" [value]="camera.id">
|
||||
{{camera.label || camera.id}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field floatLabel="always" appearance="none">
|
||||
<mat-slide-toggle [formControl]="toggleFlash" disabled>{{'borrow.proving.flash' | i18n}}</mat-slide-toggle>
|
||||
<input matInput hidden name="toggleFlash" />
|
||||
</mat-form-field>
|
||||
</form>
|
||||
|
||||
<mat-card class="warn" *ngIf="initialized && noCamera">
|
||||
<mat-card-header>
|
||||
<mat-card-title>
|
||||
<mat-icon>no_photography</mat-icon>
|
||||
</mat-card-title>
|
||||
<mat-card-subtitle>{{'borrow.proving.noCamera' | i18n}}</mat-card-subtitle>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<p>
|
||||
{{'borrow.proving.noCamera.text' | i18n}}
|
||||
</p>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
4
src/app/pages/borrow/proving/proving.component.scss
Normal file
4
src/app/pages/borrow/proving/proving.component.scss
Normal file
@ -0,0 +1,4 @@
|
||||
video {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
105
src/app/pages/borrow/proving/proving.component.ts
Normal file
105
src/app/pages/borrow/proving/proving.component.ts
Normal file
@ -0,0 +1,105 @@
|
||||
import { AfterViewInit, Component, ElementRef, ViewChild, Inject } from '@angular/core';
|
||||
import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
|
||||
import { BorrowRequestsService } from 'src/app/services/borrow.service';
|
||||
|
||||
import QrScanner from 'qr-scanner';
|
||||
import { HttpResponse } from '@angular/common/http';
|
||||
import { FormControl } from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
selector: 'app-borrow-proving',
|
||||
templateUrl: './proving.component.html',
|
||||
styleUrls: [ './proving.component.scss' ]
|
||||
})
|
||||
export class BorrowProvingComponent implements AfterViewInit {
|
||||
|
||||
@ViewChild('qrCam') private qrCamVideo: ElementRef;
|
||||
toggleFlash = new FormControl();
|
||||
camera = new FormControl();
|
||||
|
||||
qrScanner: QrScanner;
|
||||
cameras: QrScanner.Camera[];
|
||||
noCamera: boolean = true;
|
||||
initialized: boolean = false;
|
||||
|
||||
constructor(private borrowRequestService: BorrowRequestsService, private dialog: MatDialog) {
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.qrScanner = new QrScanner(this.qrCamVideo.nativeElement, (result) => {
|
||||
this.onResult(result);
|
||||
});
|
||||
|
||||
this.qrScanner.start().then(() => {
|
||||
this.initialized = true;
|
||||
QrScanner.listCameras(true).then((cameras: QrScanner.Camera[]) => {
|
||||
this.cameras = cameras;
|
||||
if (this.cameras.length) {
|
||||
this.noCamera = false;
|
||||
this.camera.setValue(this.cameras[ 0 ].id, { emitEvent: false });
|
||||
this.camera.valueChanges.subscribe((value) => {
|
||||
this.qrScanner.setCamera(value);
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
this.qrScanner.hasFlash().then(hasFlash => {
|
||||
if (hasFlash) {
|
||||
this.toggleFlash.enable();
|
||||
this.toggleFlash.valueChanges.subscribe(value => {
|
||||
if (value) {
|
||||
this.qrScanner.turnFlashOn();
|
||||
} else {
|
||||
this.qrScanner.turnFlashOff();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.toggleFlash.disable();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
onResult(result: string) {
|
||||
this.qrScanner.pause();
|
||||
this.borrowRequestService.verifyRequest(result).subscribe((response) => {
|
||||
this.openResultDialog(response, true);
|
||||
}, (error) => {
|
||||
this.openResultDialog(error, false);
|
||||
});
|
||||
}
|
||||
|
||||
openResultDialog(response, success: boolean) {
|
||||
const dialogRef = this.dialog.open(BorrowProvingResultDialog, {
|
||||
data: { "success": success, "response": response },
|
||||
minWidth: '400px',
|
||||
panelClass: "mat-card-dialog",
|
||||
closeOnNavigation: false,
|
||||
disableClose: true,
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
this.qrScanner.start();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-borrow-prooving-result',
|
||||
templateUrl: 'proving.dialog.html',
|
||||
styleUrls: [ './proving.dialog.scss' ]
|
||||
})
|
||||
export class BorrowProvingResultDialog {
|
||||
|
||||
result: any;
|
||||
|
||||
constructor(
|
||||
@Inject(MAT_DIALOG_DATA) private data: any) {
|
||||
this.result = JSON.parse(JSON.stringify(data));
|
||||
console.log(this.result);
|
||||
}
|
||||
|
||||
}
|
55
src/app/pages/borrow/proving/proving.dialog.html
Normal file
55
src/app/pages/borrow/proving/proving.dialog.html
Normal file
@ -0,0 +1,55 @@
|
||||
<mat-dialog-content>
|
||||
<mat-card [ngClass]="result.success ? 'success' : (result.response.status == 412 ? 'accent' : 'warn')">
|
||||
<mat-card-header>
|
||||
<mat-card-title>
|
||||
<mat-icon *ngIf="!result.success && result.response.status != 412">block</mat-icon>
|
||||
<mat-icon *ngIf="!result.success && result.response.status == 412">help_outline</mat-icon>
|
||||
<mat-icon *ngIf="result.success">check</mat-icon>
|
||||
</mat-card-title>
|
||||
<mat-card-subtitle>{{'borrow.proving.' + (result.success ? 'valid' : 'invalid') | i18n}}</mat-card-subtitle>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<p>
|
||||
{{'borrow.proving.' + (result.success ? 'valid' : 'invalid') + '.text' | i18n}}
|
||||
</p>
|
||||
<p *ngFor="let error of result.response.error">
|
||||
<ng-container [ngSwitch]="error.field">
|
||||
<span *ngSwitchCase="'nbf'">
|
||||
{{'borrow.proving.error.' + error.code | i18n:(error.defaultMessage | datef)}}
|
||||
</span>
|
||||
<span *ngSwitchCase="'exp'">
|
||||
{{'borrow.proving.error.' + error.code | i18n:(error.defaultMessage | datef)}}
|
||||
</span>
|
||||
<span *ngSwitchDefault>
|
||||
{{'borrow.proving.error.default.' + error.code | i18n:error.defaultMessage}}
|
||||
</span>
|
||||
</ng-container>
|
||||
</p>
|
||||
<table *ngIf="result.success">
|
||||
<tr>
|
||||
<th>{{'borrow.request.user' | i18n}}</th>
|
||||
<td>{{result.response.user}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{'borrow.request.item' | i18n}}</th>
|
||||
<td>{{result.response.name}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{'borrow.request.owner' | i18n}}</th>
|
||||
<td>{{result.response.owner}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{'borrow.request.started' | i18n}}</th>
|
||||
<td>{{result.response.nbf | datef}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{'borrow.request.ends' | i18n}}</th>
|
||||
<td>{{result.response.exp | datef}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</mat-card-content>
|
||||
<mat-card-actions>
|
||||
<button mat-raised-button [mat-dialog-close]="false">{{'ok' | i18n}}</button>
|
||||
</mat-card-actions>
|
||||
</mat-card>
|
||||
</mat-dialog-content>
|
1
src/app/pages/borrow/proving/proving.dialog.scss
Normal file
1
src/app/pages/borrow/proving/proving.dialog.scss
Normal file
@ -0,0 +1 @@
|
||||
|
66
src/app/pages/borrow/requests/request.edit.html
Normal file
66
src/app/pages/borrow/requests/request.edit.html
Normal file
@ -0,0 +1,66 @@
|
||||
<h2 mat-dialog-title>{{(create ? 'borrow.request.create' : 'borrow.request.edit') | i18n}}</h2>
|
||||
<mat-dialog-content>
|
||||
|
||||
<h3>{{borrowRequest.borrowItem.name}}</h3>
|
||||
<p>{{borrowRequest.borrowItem.description}}</p>
|
||||
|
||||
<a *ngIf="borrowRequest.borrowItem.url" mat-button color="accent" href="{{ borrowRequest.borrowItem.url }}"
|
||||
target="_blank">
|
||||
{{ borrowRequest.borrowItem.url }}
|
||||
<mat-icon style="font-size: 1em;">open_in_new</mat-icon>
|
||||
</a>
|
||||
<br>
|
||||
<br>
|
||||
<mat-divider></mat-divider>
|
||||
|
||||
<ng-container *ngIf="borrowRequest.id">
|
||||
<mat-chip-list *ngSwitch="borrowRequest.status">
|
||||
<mat-chip *ngSwtichCase="'PENDING'" color="primary" selected></mat-chip>
|
||||
<mat-chip color="accent" selected>Accent fish</mat-chip>
|
||||
</mat-chip-list>
|
||||
|
||||
</ng-container>
|
||||
|
||||
<form [formGroup]="form">
|
||||
<mat-form-field>
|
||||
<input matInput [ngxMatDatetimePicker]="startPicker" formControlName="start"
|
||||
placeholder="{{'borrow.request.start' | i18n}}">
|
||||
<mat-datepicker-toggle matSuffix [for]="startPicker"></mat-datepicker-toggle>
|
||||
<ngx-mat-datetime-picker #startPicker></ngx-mat-datetime-picker>
|
||||
<mat-error>
|
||||
{{'borrow.request.error.start' | i18n}}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field>
|
||||
<input matInput [ngxMatDatetimePicker]="endPicker" formControlName="end"
|
||||
placeholder="{{'borrow.request.end' | i18n}}">
|
||||
<mat-datepicker-toggle matSuffix [for]="endPicker"></mat-datepicker-toggle>
|
||||
<ngx-mat-datetime-picker #endPicker></ngx-mat-datetime-picker>
|
||||
<mat-error>
|
||||
{{'borrow.request.error.end' | i18n}}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field>
|
||||
<textarea matInput placeholder="{{'borrow.request.comment' | i18n}}" formControlName="comment"></textarea>
|
||||
<mat-error>
|
||||
{{'borrow.request.error.comment' | i18n}}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
</form>
|
||||
</mat-dialog-content>
|
||||
<mat-dialog-actions>
|
||||
<div fxLayout="row" fxLayoutAlign="space-between start">
|
||||
<div>
|
||||
<button mat-button [mat-dialog-close]="false">{{'cancel' | i18n}}</button>
|
||||
<button [disabled]="form.invalid" mat-raised-button (click)="save()" color="accent">
|
||||
<mat-icon>save</mat-icon>{{(create ? 'borrow.request.create' : 'borrow.request.save') | i18n}}
|
||||
</button>
|
||||
</div>
|
||||
<button *ngIf="borrowRequest.id" mat-button color="warn" (click)="confirmDelete()">
|
||||
<mat-icon>delete</mat-icon> {{ 'borrow.request.delete' |
|
||||
i18n}}
|
||||
</button>
|
||||
</div>
|
||||
</mat-dialog-actions>
|
7
src/app/pages/borrow/requests/request.edit.scss
Normal file
7
src/app/pages/borrow/requests/request.edit.scss
Normal file
@ -0,0 +1,7 @@
|
||||
mat-form-field {
|
||||
display: block;
|
||||
}
|
||||
|
||||
mat-dialog-actions>div {
|
||||
width: 100%;
|
||||
}
|
55
src/app/pages/borrow/requests/requests.component.html
Normal file
55
src/app/pages/borrow/requests/requests.component.html
Normal file
@ -0,0 +1,55 @@
|
||||
<h3>{{'borrow.requests' | i18n}}</h3>
|
||||
<div *ngIf="borrowRequests">
|
||||
<div fxLayout="row" fxLayoutAlign="space-between start">
|
||||
<form>
|
||||
<mat-form-field floatLabel="always" appearance="none">
|
||||
<mat-slide-toggle [formControl]="ownerFormControl">{{'borrow.requests.mine' | i18n}}</mat-slide-toggle>
|
||||
<input matInput hidden />
|
||||
</mat-form-field>
|
||||
</form>
|
||||
</div>
|
||||
<table mat-table matSort [dataSource]="borrowRequests.content" (matSortChange)="updateSort($event)">
|
||||
<ng-container matColumnDef="name">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header="name"> {{'borrow.item.name' | i18n}} </th>
|
||||
<td mat-cell *matCellDef="let borrowRequest"> {{ borrowRequest.borrowItem.name}} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="starts">
|
||||
<th mat-header-cell *matHeaderCellDef> {{'borrow.requests.starts' | i18n}} </th>
|
||||
<td mat-cell *matCellDef="let borrowRequest"> {{ borrowRequest.starts | datef}}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="ends">
|
||||
<th mat-header-cell *matHeaderCellDef> {{'borrow.requests.ends' | i18n}} </th>
|
||||
<td mat-cell *matCellDef="let borrowRequest"> {{ borrowRequest.ends | datef}}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="status">
|
||||
<th mat-header-cell *matHeaderCellDef> {{'borrow.requests.status' | i18n}} </th>
|
||||
<td mat-cell *matCellDef="let borrowRequest"> {{ 'borrow.requests.status.' + borrowRequest.status | i18n}}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef class="align-right"> {{'borrow.requests.actions' | i18n}} </th>
|
||||
<td mat-cell *matCellDef="let borrowRequest" class="text-right">
|
||||
<a mat-icon-button *ngIf="borrowRequest.user == userId">
|
||||
<mat-icon (click)="edit(borrowRequest)">edit</mat-icon>
|
||||
</a>
|
||||
<a mat-icon-button *ngIf="borrowRequest.user == userId">
|
||||
<mat-icon (click)="confirmDelete(borrowRequest)">delete</mat-icon>
|
||||
</a>
|
||||
<a mat-icon-button *ngIf="borrowRequest.item.owner != userId">
|
||||
<mat-icon (click)="updateStatus(borrowRequest)">pending_actions</mat-icon>
|
||||
</a>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="borrowRequestColumns"></tr>
|
||||
<tr mat-row *matRowDef="let myRowData; columns: borrowRequestColumns"></tr>
|
||||
</table>
|
||||
<mat-paginator [pageSizeOptions]="pageSizeOptions" [length]="borrowRequests.totalElements"
|
||||
[pageSize]="borrowRequests.size" (page)="updatePages($event)" showFirstLastButtons></mat-paginator>
|
||||
</div>
|
21
src/app/pages/borrow/requests/requests.component.scss
Normal file
21
src/app/pages/borrow/requests/requests.component.scss
Normal file
@ -0,0 +1,21 @@
|
||||
.mat-form-field+.mat-form-field, .mat-form-field+.mat-slide-toggle {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.mat-header-cell,
|
||||
.mat-cell {
|
||||
&.text-right {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
.mat-cell .mat-button {
|
||||
padding-left: 0px;
|
||||
padding-right: 0px;
|
||||
}
|
||||
|
||||
.align-right{
|
||||
display: flex;
|
||||
padding: 21px 0;
|
||||
justify-content: flex-end;
|
||||
}
|
181
src/app/pages/borrow/requests/requests.component.ts
Normal file
181
src/app/pages/borrow/requests/requests.component.ts
Normal file
@ -0,0 +1,181 @@
|
||||
import { Component, Inject, OnInit } from '@angular/core';
|
||||
import { FormArray, FormBuilder, FormControl, FormGroup, ValidatorFn, Validators } from '@angular/forms';
|
||||
import { debounceTime } from 'rxjs/operators';
|
||||
import { PageEvent } from '@angular/material/paginator';
|
||||
import { Sort } from '@angular/material/sort';
|
||||
import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
import * as moment from 'moment';
|
||||
|
||||
import { ConfirmDialog } from '../../../ui/confirm/confirm.component';
|
||||
import { BorrowRequestsService } from './../../../services/borrow.service';
|
||||
import { I18nService } from './../../../services/i18n.service';
|
||||
import { AuthService } from './../../../services/auth.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-borrow-requests',
|
||||
templateUrl: './requests.component.html',
|
||||
styleUrls: [ './requests.component.scss' ]
|
||||
})
|
||||
export class BorrowRequestsComponent implements OnInit {
|
||||
|
||||
borrowRequests: any[];
|
||||
page: any = { page: 0, size: 10, sort: "id", desc: false };
|
||||
pageSizeOptions: number[] = [ 5, 10, 25, 50 ];
|
||||
ownerFormControl = new FormControl();
|
||||
userId: any;
|
||||
|
||||
borrowRequestColumns = [ "name", "status", "starts", "ends", "actions" ];
|
||||
|
||||
constructor(private borrowRequestsService: BorrowRequestsService,
|
||||
private i18n: I18nService,
|
||||
private authService: AuthService,
|
||||
public dialog: MatDialog) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.authService.auth.subscribe((auth: any) => {
|
||||
if (auth.principal && auth.principal.userId) {
|
||||
this.userId = auth.principal.userId;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
this.ownerFormControl.valueChanges.subscribe(value => {
|
||||
this.borrowRequestsService.getRequests(0, this.page.size, this.page.sort, this.page.desc, value).subscribe((data: any) => {
|
||||
this.borrowRequests = data;
|
||||
}, (error) => { })
|
||||
})
|
||||
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
refresh(): void {
|
||||
this.borrowRequestsService.getRequests(this.page.page, this.page.size, this.page.sort, this.page.desc, this.ownerFormControl.value).subscribe((data: any) => {
|
||||
this.borrowRequests = data;
|
||||
})
|
||||
}
|
||||
|
||||
updatePages(event: PageEvent) {
|
||||
this.page.page = event.pageIndex;
|
||||
this.page.size = event.pageSize;
|
||||
this.borrowRequestsService.getRequests(this.page.page, this.page.size, this.page.sort, this.page.desc, this.ownerFormControl.value).subscribe((data: any) => {
|
||||
this.borrowRequests = data;
|
||||
}, (error) => { })
|
||||
}
|
||||
|
||||
updateSort(sort: Sort) {
|
||||
if (sort.direction == "") {
|
||||
this.page.sort = "id";
|
||||
this.page.desc = false;
|
||||
} else {
|
||||
this.page.sort = sort.active;
|
||||
this.page.desc = sort.direction == "desc";
|
||||
}
|
||||
this.borrowRequestsService.getRequests(this.page.page, this.page.size, this.page.sort, this.page.desc, this.ownerFormControl.value).subscribe((data: any) => {
|
||||
this.borrowRequests = data;
|
||||
}, (error) => { })
|
||||
}
|
||||
|
||||
edit(borrowRequest) {
|
||||
const dialogRef = this.dialog.open(BorrowRequestEditComponent, {
|
||||
data: borrowRequest
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
if (result) {
|
||||
this.refresh();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
confirmDelete(borrowRequest) {
|
||||
const dialogRef = this.dialog.open(ConfirmDialog, {
|
||||
data: {
|
||||
'label': 'borrow.items.confirmDelete',
|
||||
'args': [ borrowRequest.name ]
|
||||
}
|
||||
})
|
||||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
if (result) {
|
||||
this.borrowRequestsService.deleteRequest(borrowRequest.id).subscribe((result: any) => {
|
||||
this.refresh();
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-borrow-request-edit',
|
||||
templateUrl: './request.edit.html',
|
||||
styleUrls: [ './request.edit.scss' ]
|
||||
})
|
||||
export class BorrowRequestEditComponent {
|
||||
|
||||
borrowRequest: any;
|
||||
create: boolean = false;
|
||||
form: FormGroup;
|
||||
|
||||
constructor(private borrowRequestsService: BorrowRequestsService,
|
||||
private formBuilder: FormBuilder,
|
||||
@Inject(MAT_DIALOG_DATA) public data: any,
|
||||
public dialogRef: MatDialogRef<BorrowRequestEditComponent>,
|
||||
public dialog: MatDialog) {
|
||||
|
||||
this.form = this.formBuilder.group({
|
||||
})
|
||||
|
||||
this.borrowRequest = data;
|
||||
|
||||
if (!this.borrowRequest.id) {
|
||||
this.create = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
formToBorrowRequest(): any {
|
||||
const borrowRequest: any = {};
|
||||
return borrowRequest;
|
||||
}
|
||||
|
||||
|
||||
|
||||
save() {
|
||||
this.borrowRequestsService.createOrUpdateRequest(this.formToBorrowRequest()).subscribe((data: any) => {
|
||||
this.dialogRef.close(data);
|
||||
}, (error) => {
|
||||
if (error.status == 409) {
|
||||
let errors = {};
|
||||
for (let code of error.error) {
|
||||
errors[ code.field ] = errors[ code.field ] || {};
|
||||
errors[ code.field ][ code.code ] = true;
|
||||
}
|
||||
|
||||
for (let code in errors) {
|
||||
this.form.get(code).setErrors(errors[ code ]);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
confirmDelete() {
|
||||
const borrowRequest = this.formToBorrowRequest();
|
||||
|
||||
const dialogRef = this.dialog.open(ConfirmDialog, {
|
||||
data: {
|
||||
'label': 'borrow.requests.confirmDelete',
|
||||
'args': [ borrowRequest.name ]
|
||||
}
|
||||
})
|
||||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
if (result) {
|
||||
this.borrowRequestsService.deleteRequest(borrowRequest.id).subscribe((result: any) => {
|
||||
this.dialogRef.close(true);
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
117
src/app/pages/invites/code/code.component.html
Normal file
117
src/app/pages/invites/code/code.component.html
Normal file
@ -0,0 +1,117 @@
|
||||
<mat-card>
|
||||
<mat-card-header>
|
||||
<mat-card-title>{{'invites.register' | i18n}}</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<ng-container *ngIf="invite">
|
||||
<h3>
|
||||
<mat-icon inline=true>{{'invites.quota.' + invite.quota + ".icon" | i18n}}</mat-icon> {{'invites.quota.'
|
||||
+
|
||||
invite.quota
|
||||
| i18n}}
|
||||
</h3>
|
||||
|
||||
<p>{{'invites.quota.' + invite.quota +
|
||||
".text" | i18n}}</p>
|
||||
<p *ngIf="invite.url">
|
||||
<a mat-button href="{{invite.url}}" target="_blank" color="accent">{{'invites.register.url' |
|
||||
i18n}}</a>
|
||||
</p>
|
||||
|
||||
<ng-container *ngIf="!success">
|
||||
<blockquote *ngIf="invite.message && auth.principal.userId != invite.owner" class="message">
|
||||
{{invite.message}}</blockquote>
|
||||
<blockquote *ngIf="invite.note && auth.principal.userId != invite.owner" class="note">{{invite.note}}
|
||||
</blockquote>
|
||||
<form [formGroup]="form" *ngIf="!error">
|
||||
<ng-container *ngIf="!auth.authenticated">
|
||||
<mat-form-field>
|
||||
<input matInput placeholder="{{'username' | i18n}}" formControlName="username" matAutofocus
|
||||
tabindex="1">
|
||||
<mat-error>
|
||||
{{'username.error' | i18n}}
|
||||
</mat-error>
|
||||
<a mat-button matSuffix mat-icon-button (click)="genUsername()" tabindex="5">
|
||||
<mat-icon>autorenew</mat-icon>
|
||||
</a>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<input matInput type="password" placeholder="{{'password' | i18n}}"
|
||||
formControlName="password" tabindex="2">
|
||||
<mat-error>
|
||||
<div *ngFor="let error of form.get('password').errors | keyvalue">
|
||||
{{'password.error.' + error.key | i18n}}<br>
|
||||
</div>
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<input matInput type="password" placeholder="{{'password.confirm' | i18n}}"
|
||||
formControlName="password2" tabindex="3">
|
||||
<mat-error>
|
||||
{{'password.not-match' | i18n}}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="auth.principal.userId == invite.owner">
|
||||
<mat-form-field>
|
||||
<textarea matInput placeholder="{{'invite.message' | i18n}}"
|
||||
formControlName="message"></textarea>
|
||||
<mat-error>
|
||||
{{'invite.errors.message' | i18n}}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<textarea matInput placeholder="{{'invite.note' | i18n}}" formControlName="note"></textarea>
|
||||
<mat-error>
|
||||
{{'invites.error.note' | i18n}}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
</ng-container>
|
||||
</form>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="success">
|
||||
<h2>{{'invites.register.success' | i18n}}</h2>
|
||||
<p>{{'invites.register.success.text' | i18n}}</p>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="error">
|
||||
<mat-error>
|
||||
{{'invites.register.error.' + error | i18n}}
|
||||
</mat-error>
|
||||
</ng-container>
|
||||
</mat-card-content>
|
||||
<mat-card-actions>
|
||||
<ng-container *ngIf="!success && invite">
|
||||
<button *ngIf="!working && !auth.authenticated && !error" mat-raised-button color="primary"
|
||||
[disabled]="form.invalid" (click)="register()" tabindex="4">
|
||||
{{'invites.register' | i18n}}
|
||||
</button>
|
||||
|
||||
<button *ngIf="auth.principal.userId == invite.owner && !error" mat-raised-button color="primary"
|
||||
(click)="save()" tabindex="4">
|
||||
{{'invites.edit.save' | i18n}}
|
||||
</button>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="success">
|
||||
<a routerLink="/login" mat-raised-button color="primary">
|
||||
{{'invites.register.login' | i18n}}
|
||||
</a>
|
||||
</ng-container>
|
||||
<mat-progress-bar *ngIf="working" mode="indeterminate"></mat-progress-bar>
|
||||
</mat-card-actions>
|
||||
<mat-card-footer>
|
||||
<a href="https://wiki.bstly.de/services/webstly#invite" class="help-button"
|
||||
matTooltip="{{'help-button' | i18n}}" matTooltipPosition="above" target="_blank" mat-fab color="accent">
|
||||
<mat-icon>contact_support</mat-icon>
|
||||
</a>
|
||||
</mat-card-footer>
|
||||
</mat-card>
|
||||
|
||||
<div *ngIf="!success && permissions && permissions[0] && !error">
|
||||
<h3>{{'permissions' | i18n}}</h3>
|
||||
<app-permissions [permissions]="permissions"></app-permissions>
|
||||
</div>
|
||||
<div *ngIf="!success && quotas && quotas[0] && !error">
|
||||
<h3>{{'quotas' | i18n}}</h3>
|
||||
<app-quotas [quotas]="quotas"></app-quotas>
|
||||
</div>
|
23
src/app/pages/invites/code/code.component.scss
Normal file
23
src/app/pages/invites/code/code.component.scss
Normal file
@ -0,0 +1,23 @@
|
||||
@import '../../../../variables.scss';
|
||||
|
||||
|
||||
mat-form-field {
|
||||
display: block;
|
||||
}
|
||||
|
||||
mat-hint {
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin-left: 5px;
|
||||
padding: 5px;
|
||||
|
||||
&.message {
|
||||
border-left: 2px solid $accent;
|
||||
}
|
||||
|
||||
&.note {
|
||||
border-left: 2px solid $primary;
|
||||
}
|
||||
}
|
166
src/app/pages/invites/code/code.component.ts
Normal file
166
src/app/pages/invites/code/code.component.ts
Normal file
@ -0,0 +1,166 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
|
||||
import { MatchingValidator } from './../../../utils/matching.validator';
|
||||
import { InviteService } from './../../../services/invites.service';
|
||||
import { uniqueNamesGenerator, Config, adjectives, colors, animals } from 'unique-names-generator';
|
||||
import { I18nService } from 'src/app/services/i18n.service';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { InviteEditComponent } from '../edit/invite.edit';
|
||||
import { AuthService } from 'src/app/services/auth.service';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-invite-code',
|
||||
templateUrl: './code.component.html',
|
||||
styleUrls: [ './code.component.scss' ]
|
||||
})
|
||||
export class InviteCodeComponent implements OnInit {
|
||||
|
||||
form: FormGroup;
|
||||
error: string;
|
||||
working: boolean = true;
|
||||
success: boolean = false;
|
||||
invite: any;
|
||||
datetimeformat: string;
|
||||
auth: any;
|
||||
permissions = [];
|
||||
quotas = [];
|
||||
|
||||
constructor(
|
||||
private authService: AuthService,
|
||||
private inviteService: InviteService,
|
||||
private formBuilder: FormBuilder,
|
||||
private i18n: I18nService,
|
||||
public dialog: MatDialog,
|
||||
private route: ActivatedRoute) {
|
||||
this.authService.auth.subscribe(data => {
|
||||
this.auth = data;
|
||||
})
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
|
||||
this.datetimeformat = this.i18n.get('format.datetime', []);
|
||||
|
||||
this.form = this.formBuilder.group({
|
||||
username: [ '', Validators.required ],
|
||||
password: [ '', Validators.nullValidator ],
|
||||
password2: [ '', Validators.required ]
|
||||
}, {
|
||||
validators: MatchingValidator('password', 'password2')
|
||||
});
|
||||
|
||||
const code = this.route.snapshot.paramMap.get('code');
|
||||
this.inviteService.code(code).subscribe((data) => {
|
||||
this.invite = data;
|
||||
|
||||
if (this.invite.redeemed) {
|
||||
this.error = "ALREADY_REDEEMED";
|
||||
}
|
||||
|
||||
if (this.invite.owner == this.auth.principal.userId) {
|
||||
this.form = this.formBuilder.group({
|
||||
message: [ '', Validators.nullValidator ],
|
||||
note: [ '', Validators.nullValidator ],
|
||||
});
|
||||
|
||||
this.form.get("message").setValue(this.invite.message);
|
||||
this.form.get("note").setValue(this.invite.note);
|
||||
}
|
||||
|
||||
this.working = false;
|
||||
}, (error) => {
|
||||
this.working = false;
|
||||
if (error.status == 406) {
|
||||
this.error = "INVALID_CODE";
|
||||
}
|
||||
})
|
||||
|
||||
this.inviteService.permissions(code).subscribe((data: any) => {
|
||||
this.permissions = data;
|
||||
})
|
||||
|
||||
this.inviteService.quotas(code).subscribe((data: any) => {
|
||||
this.quotas = data;
|
||||
})
|
||||
}
|
||||
|
||||
genUsername() {
|
||||
const config: Config = {
|
||||
dictionaries: [ adjectives, colors, animals ],
|
||||
separator: "",
|
||||
style: "capital",
|
||||
length: 3
|
||||
};
|
||||
|
||||
this.form.get("username").setValue(uniqueNamesGenerator(config));
|
||||
}
|
||||
|
||||
register() {
|
||||
if (this.form.valid && !this.working) {
|
||||
this.working = true;
|
||||
|
||||
const model: any = {};
|
||||
model.token = this.invite.code;
|
||||
model.username = this.form.get("username").value;
|
||||
model.password = this.form.get("password").value;
|
||||
model.password2 = this.form.get("password2").value;
|
||||
|
||||
this.inviteService.register(model).subscribe((result: any) => {
|
||||
this.working = false;
|
||||
this.success = true;
|
||||
}, (error) => {
|
||||
this.working = false;
|
||||
if (error.status == 401) {
|
||||
this.error = "NO_CODE";
|
||||
} else if (error.status == 406) {
|
||||
this.error = "INVALID_CODE";
|
||||
} else if (error.status == 410) {
|
||||
this.error = "ALREADY_REDEEMED";
|
||||
} else if (error.status == 409) {
|
||||
let errors = {};
|
||||
for (let code of error.error) {
|
||||
errors[ code.field ] = errors[ code.field ] || {};
|
||||
errors[ code.field ][ code.code ] = true;
|
||||
}
|
||||
|
||||
for (let code in errors) {
|
||||
this.form.get(code).setErrors(errors[ code ]);
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
save() {
|
||||
if (this.form.valid && !this.working) {
|
||||
this.working = true;
|
||||
this.invite.message = this.form.get("message").value;
|
||||
this.invite.note = this.form.get("note").value;
|
||||
this.inviteService.update(this.invite).subscribe((result: any) => {
|
||||
this.invite = result;
|
||||
this.working = false;
|
||||
}, (error) => {
|
||||
this.working = false;
|
||||
if (error.status == 406) {
|
||||
this.error = "INVALID_CODE";
|
||||
} if (error.status == 410) {
|
||||
this.error = "ALREADY_REDEEMED";
|
||||
} else if (error.status == 409) {
|
||||
let errors = {};
|
||||
for (let code of error.error) {
|
||||
errors[ code.field ] = errors[ code.field ] || {};
|
||||
errors[ code.field ][ code.code ] = true;
|
||||
}
|
||||
|
||||
for (let code in errors) {
|
||||
this.form.get(code).setErrors(errors[ code ]);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
26
src/app/pages/invites/edit/invite.edit.html
Normal file
26
src/app/pages/invites/edit/invite.edit.html
Normal file
@ -0,0 +1,26 @@
|
||||
<h2 mat-dialog-title>{{'invites.edit' | i18n}}</h2>
|
||||
<mat-dialog-content>
|
||||
<form [formGroup]="form">
|
||||
<mat-error *ngIf="error">
|
||||
{{'invites.register.error.' + error | i18n}}
|
||||
</mat-error>
|
||||
<mat-form-field>
|
||||
<textarea matInput placeholder="{{'invite.message' | i18n}}" formControlName="message"></textarea>
|
||||
<mat-error>
|
||||
{{'invite.errors.message' | i18n}}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<textarea matInput placeholder="{{'invite.note' | i18n}}" formControlName="note" ></textarea>
|
||||
<mat-error>
|
||||
{{'invites.error.note' | i18n}}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
</form>
|
||||
</mat-dialog-content>
|
||||
<mat-dialog-actions>
|
||||
<button mat-button [mat-dialog-close]="false">{{'cancel' | i18n}}</button>
|
||||
<button mat-raised-button color="primary" [disabled]="form.invalid || working" (click)="save()">
|
||||
{{'invites.edit.save' | i18n}}
|
||||
</button>
|
||||
</mat-dialog-actions>
|
7
src/app/pages/invites/edit/invite.edit.scss
Normal file
7
src/app/pages/invites/edit/invite.edit.scss
Normal file
@ -0,0 +1,7 @@
|
||||
mat-form-field {
|
||||
display: block;
|
||||
}
|
||||
|
||||
mat-hint {
|
||||
white-space: normal;
|
||||
}
|
71
src/app/pages/invites/edit/invite.edit.ts
Normal file
71
src/app/pages/invites/edit/invite.edit.ts
Normal file
@ -0,0 +1,71 @@
|
||||
import { Component, Inject, OnInit } from '@angular/core';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
|
||||
import { MatchingValidator } from '../../../utils/matching.validator';
|
||||
import { InviteService } from '../../../services/invites.service';
|
||||
import { uniqueNamesGenerator, Config, adjectives, colors, animals } from 'unique-names-generator';
|
||||
import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-invite-edit',
|
||||
templateUrl: './invite.edit.html',
|
||||
styleUrls: [ './invite.edit.scss' ]
|
||||
})
|
||||
export class InviteEditComponent {
|
||||
|
||||
form: FormGroup;
|
||||
error: string;
|
||||
working: boolean = false;
|
||||
success: boolean = false;
|
||||
invite: any;
|
||||
|
||||
constructor(
|
||||
private inviteService: InviteService,
|
||||
private formBuilder: FormBuilder,
|
||||
@Inject(MAT_DIALOG_DATA) public data: any,
|
||||
public dialogRef: MatDialogRef<InviteEditComponent>,
|
||||
public dialog: MatDialog) {
|
||||
this.form = this.formBuilder.group({
|
||||
message: [ '', Validators.nullValidator ],
|
||||
note: [ '', Validators.nullValidator ],
|
||||
});
|
||||
|
||||
this.invite = data;
|
||||
this.form.get("message").setValue(this.invite.message);
|
||||
this.form.get("note").setValue(this.invite.note);
|
||||
}
|
||||
|
||||
save() {
|
||||
if (this.form.valid && !this.working) {
|
||||
this.working = true;
|
||||
|
||||
this.invite.message = this.form.get("message").value;
|
||||
this.invite.note = this.form.get("note").value;
|
||||
|
||||
this.inviteService.update(this.invite).subscribe((result: any) => {
|
||||
this.working = false;
|
||||
this.dialogRef.close(result);
|
||||
}, (error) => {
|
||||
this.working = false;
|
||||
if (error.status == 406) {
|
||||
this.error = "INVALID_CODE";
|
||||
} if (error.status == 410) {
|
||||
this.error = "ALREADY_REDEEMED";
|
||||
} else if (error.status == 409) {
|
||||
let errors = {};
|
||||
for (let code of error.error) {
|
||||
errors[ code.field ] = errors[ code.field ] || {};
|
||||
errors[ code.field ][ code.code ] = true;
|
||||
}
|
||||
|
||||
for (let code in errors) {
|
||||
this.form.get(code).setErrors(errors[ code ]);
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -37,17 +37,17 @@
|
||||
<td mat-cell *matCellDef="let invite"> {{ invite.expires | date:datetimeformat}} </td>
|
||||
</ng-container>
|
||||
|
||||
|
||||
<ng-container matColumnDef="link">
|
||||
<th mat-header-cell *matHeaderCellDef> {{'invite.link' | i18n}} </th>
|
||||
<td mat-cell *matCellDef="let invite"> <a href="{{ invite.codeLink}}" target="_blank" mat-button color="accent">
|
||||
{{
|
||||
invite.code}}</a> </td>
|
||||
<td mat-cell *matCellDef="let invite">
|
||||
<a href="{{ invite.codeLink }}" target="_blank" mat-button color="accent">{{invite.code}}</a>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="note">
|
||||
<th mat-header-cell *matHeaderCellDef> {{'invite.note' | i18n}} </th>
|
||||
<td mat-cell *matCellDef="let invite"> <span *ngIf="invite.note">{{ invite.note}}</span> <i *ngIf="!invite.note">{{ 'invite.noNote' | i18n}}</i>
|
||||
<td mat-cell *matCellDef="let invite"> <span *ngIf="invite.note">{{ invite.note}}</span> <i
|
||||
*ngIf="!invite.note">{{ 'invite.noNote' | i18n}}</i>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
@ -65,10 +65,20 @@
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef> {{'invite.actions' | i18n}} </th>
|
||||
<td mat-cell *matCellDef="let invite">
|
||||
<a mat-icon-button>
|
||||
<mat-icon (click)="edit(invite)">edit</mat-icon>
|
||||
</a>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="inviteColumns"></tr>
|
||||
<tr mat-row *matRowDef="let myRowData; columns: inviteColumns"></tr>
|
||||
</table>
|
||||
<mat-paginator [pageSizeOptions]="pageSizeOptions" [length]="invites.totalElements" [pageSize]="invites.size" (page)="updatePages($event)" showFirstLastButtons></mat-paginator>
|
||||
<mat-paginator [pageSizeOptions]="pageSizeOptions" [length]="invites.totalElements" [pageSize]="invites.size"
|
||||
(page)="updatePages($event)" showFirstLastButtons></mat-paginator>
|
||||
</div>
|
||||
|
||||
<mat-card>
|
||||
@ -117,7 +127,8 @@
|
||||
<table mat-table matSort [dataSource]="others.content">
|
||||
<ng-container matColumnDef="note">
|
||||
<th mat-header-cell *matHeaderCellDef> {{'invite.note' | i18n}} </th>
|
||||
<td mat-cell *matCellDef="let invite"> <span *ngIf="invite.note">{{ invite.note}}</span> <i *ngIf="!invite.note">{{ 'invite.noNote' | i18n}}</i> </td>
|
||||
<td mat-cell *matCellDef="let invite"> <span *ngIf="invite.note">{{ invite.note}}</span> <i
|
||||
*ngIf="!invite.note">{{ 'invite.noNote' | i18n}}</i> </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="redeemed">
|
||||
@ -130,5 +141,6 @@
|
||||
<tr mat-header-row *matHeaderRowDef="otherColumns"></tr>
|
||||
<tr mat-row *matRowDef="let myRowData; columns: otherColumns"></tr>
|
||||
</table>
|
||||
<mat-paginator [pageSizeOptions]="pageSizeOptions" [length]="others.totalElements" [pageSize]="others.size" (page)="updateOthers($event)" showFirstLastButtons></mat-paginator>
|
||||
<mat-paginator [pageSizeOptions]="pageSizeOptions" [length]="others.totalElements" [pageSize]="others.size"
|
||||
(page)="updateOthers($event)" showFirstLastButtons></mat-paginator>
|
||||
</div>
|
@ -1,19 +1,21 @@
|
||||
import {Component, OnInit, ViewChild} from '@angular/core';
|
||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||
|
||||
import {ActivatedRoute, Router} from '@angular/router';
|
||||
import {PageEvent} from '@angular/material/paginator';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { PageEvent } from '@angular/material/paginator';
|
||||
|
||||
import {AuthService} from '../../services/auth.service';
|
||||
import {I18nService} from '../../services/i18n.service';
|
||||
import {QuotaService} from '../../services/quota.service';
|
||||
import {InviteService} from '../../services/invites.service';
|
||||
import {FormControl} from '@angular/forms';
|
||||
import {debounceTime} from 'rxjs/operators';
|
||||
import { AuthService } from '../../services/auth.service';
|
||||
import { I18nService } from '../../services/i18n.service';
|
||||
import { QuotaService } from '../../services/quota.service';
|
||||
import { InviteService } from '../../services/invites.service';
|
||||
import { FormControl } from '@angular/forms';
|
||||
import { debounceTime } from 'rxjs/operators';
|
||||
import { InviteEditComponent } from './edit/invite.edit';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
|
||||
@Component({
|
||||
selector: 'app-invites',
|
||||
templateUrl: './invites.component.html',
|
||||
styleUrls: ['./invites.component.scss']
|
||||
styleUrls: [ './invites.component.scss' ]
|
||||
})
|
||||
export class InvitesComponent implements OnInit {
|
||||
|
||||
@ -24,21 +26,20 @@ export class InvitesComponent implements OnInit {
|
||||
success: boolean;
|
||||
working: boolean;
|
||||
datetimeformat: string;
|
||||
pageSizeOptions: number[] = [5, 10, 25, 50];
|
||||
pageSizeOptions: number[] = [ 5, 10, 25, 50 ];
|
||||
searchFormControl = new FormControl();
|
||||
redeemedFormControl = new FormControl();
|
||||
searchOthersFormControl = new FormControl();
|
||||
redeemedOthersFormControl = new FormControl();
|
||||
|
||||
inviteColumns = ["starts", "expires", "link", "note", "message", "redeemed"];
|
||||
otherColumns = ["note", "redeemed"];
|
||||
inviteColumns = [ "starts", "expires", "link", "note", "message", "redeemed", "actions" ];
|
||||
otherColumns = [ "note", "redeemed" ];
|
||||
|
||||
constructor(
|
||||
private authService: AuthService,
|
||||
private inviteService: InviteService,
|
||||
private i18n: I18nService,
|
||||
private quotaService: QuotaService,
|
||||
private router: Router,
|
||||
public dialog: MatDialog,
|
||||
private route: ActivatedRoute) {
|
||||
}
|
||||
|
||||
@ -49,23 +50,23 @@ export class InvitesComponent implements OnInit {
|
||||
this.searchFormControl.valueChanges.pipe(debounceTime(500)).subscribe(value => {
|
||||
this.inviteService.getPages(this.quota, 0, this.invites.size, value, this.redeemedFormControl.value).subscribe((data: any) => {
|
||||
this.invites = data;
|
||||
}, (error) => {})
|
||||
}, (error) => { })
|
||||
})
|
||||
this.redeemedFormControl.valueChanges.subscribe(value => {
|
||||
this.inviteService.getPages(this.quota, 0, this.invites.size, this.searchFormControl.value ? this.searchFormControl.value : "", value).subscribe((data: any) => {
|
||||
this.invites = data;
|
||||
}, (error) => {})
|
||||
}, (error) => { })
|
||||
})
|
||||
|
||||
this.searchOthersFormControl.valueChanges.pipe(debounceTime(500)).subscribe(value => {
|
||||
this.inviteService.getOthersPages(this.quota, 0, this.others.size, value, this.redeemedOthersFormControl.value).subscribe((data: any) => {
|
||||
this.others = data;
|
||||
}, (error) => {})
|
||||
}, (error) => { })
|
||||
})
|
||||
this.redeemedOthersFormControl.valueChanges.subscribe(value => {
|
||||
this.inviteService.getOthersPages(this.quota, 0, this.others.size, this.searchOthersFormControl.value ? this.searchOthersFormControl.value : "", value).subscribe((data: any) => {
|
||||
this.others = data;
|
||||
}, (error) => {})
|
||||
}, (error) => { })
|
||||
})
|
||||
|
||||
this.update();
|
||||
@ -75,56 +76,67 @@ export class InvitesComponent implements OnInit {
|
||||
update(): void {
|
||||
this.inviteQuota = 0;
|
||||
this.quotaService.quotas().subscribe((data: any) => {
|
||||
for(let quota of data) {
|
||||
if(quota.name == "invite_" + this.quota) {
|
||||
for (let quota of data) {
|
||||
if (quota.name == "invite_" + this.quota) {
|
||||
this.inviteQuota = quota.value;
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if(!this.invites) {
|
||||
if (!this.invites) {
|
||||
this.inviteService.get(this.quota).subscribe((data: any) => {
|
||||
this.invites = data;
|
||||
})
|
||||
} else {
|
||||
this.inviteService.getPages(this.quota, this.invites.number || 0, this.invites.size || 10, this.searchFormControl.value ? this.searchFormControl.value : "", this.redeemedFormControl.value).subscribe((data: any) => {
|
||||
this.invites = data;
|
||||
}, (error) => {})
|
||||
}, (error) => { })
|
||||
}
|
||||
|
||||
this.inviteService.getOthers(this.quota).subscribe((data: any) => {
|
||||
this.others = data;
|
||||
}, (error) => {})
|
||||
}, (error) => { })
|
||||
}
|
||||
|
||||
updatePages(event: PageEvent) {
|
||||
this.inviteService.getPages(this.quota, event.pageIndex, event.pageSize, this.searchFormControl.value ? this.searchFormControl.value : "", this.redeemedFormControl.value).subscribe((data: any) => {
|
||||
this.invites = data;
|
||||
}, (error) => {})
|
||||
}, (error) => { })
|
||||
}
|
||||
|
||||
create(): void {
|
||||
this.working = true;
|
||||
|
||||
|
||||
this.inviteService.create(this.quota, {}).subscribe(response => {
|
||||
this.update();
|
||||
this.working = false;
|
||||
}, (error) => {
|
||||
this.working = false;
|
||||
if(error.status == 409) {
|
||||
if (error.status == 409) {
|
||||
let errors = {};
|
||||
for(let code of error.error) {
|
||||
errors[code.field] = errors[code.field] || {};
|
||||
errors[code.field][code.code] = true;
|
||||
for (let code of error.error) {
|
||||
errors[ code.field ] = errors[ code.field ] || {};
|
||||
errors[ code.field ][ code.code ] = true;
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
edit(invite) {
|
||||
const dialogRef = this.dialog.open(InviteEditComponent, {
|
||||
data: invite,
|
||||
minWidth: "400px"
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
if (result) {
|
||||
this.update();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
updateOthers(event: PageEvent) {
|
||||
this.inviteService.getOthersPages(this.quota, event.pageIndex, event.pageSize, this.searchOthersFormControl.value ? this.searchOthersFormControl.value : "", this.redeemedOthersFormControl.value).subscribe((data: any) => {
|
||||
this.others = data;
|
||||
}, (error) => {})
|
||||
}, (error) => { })
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,11 @@
|
||||
<p *ngIf="!tags || tags.length == 0">{{'partey.tags.none' | i18n}}</p>
|
||||
|
||||
<mat-chip-list>
|
||||
<mat-chip *ngFor="let tag of tags">{{tag.tag}}</mat-chip>
|
||||
<ng-container *ngFor="let tag of tags">
|
||||
<mat-chip *ngIf="activeTag(tag)" color="accent" selected>{{tag.tag}}</mat-chip>
|
||||
<mat-chip *ngIf="upcomingTag(tag)" disabled matTooltip="{{'partey.tags.upcoming' | i18n:(tag.starts | datef)}}" selected>{{tag.tag}}</mat-chip>
|
||||
<mat-chip *ngIf="expiringTag(tag)" color="primary" matTooltip="{{'partey.tags.expires' | i18n:(tag.expires | datef)}}" selected>{{tag.tag}}</mat-chip>
|
||||
</ng-container>
|
||||
</mat-chip-list>
|
||||
|
||||
|
||||
|
@ -21,4 +21,20 @@ export class ParteyComponent implements OnInit {
|
||||
})
|
||||
}
|
||||
|
||||
toDate(value : string) {
|
||||
return new Date(value);
|
||||
}
|
||||
|
||||
activeTag(tag: any) {
|
||||
return !tag.starts && !tag.expires;
|
||||
}
|
||||
|
||||
upcomingTag(tag: any) {
|
||||
return tag.starts && (new Date() < this.toDate(tag.starts));
|
||||
}
|
||||
|
||||
expiringTag(tag: any) {
|
||||
return !(this.upcomingTag(tag)) && tag.expires;
|
||||
}
|
||||
|
||||
}
|
@ -9,17 +9,17 @@
|
||||
</mat-error>
|
||||
<mat-form-field>
|
||||
<input matInput placeholder="{{'username' | i18n}}" formControlName="username"
|
||||
[(ngModel)]="model.username" required matAutofocus>
|
||||
[(ngModel)]="model.username" required matAutofocus tabindex="1">
|
||||
<mat-error>
|
||||
{{'username.error' | i18n}}
|
||||
</mat-error>
|
||||
<a mat-button matSuffix mat-icon-button (click)="genUsername()">
|
||||
<a mat-button matSuffix mat-icon-button (click)="genUsername()" tabindex="8">
|
||||
<mat-icon>autorenew</mat-icon>
|
||||
</a>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<input matInput type="password" placeholder="{{'password' | i18n}}" formControlName="password"
|
||||
[(ngModel)]="model.password" required>
|
||||
[(ngModel)]="model.password" required tabindex="2">
|
||||
<mat-error>
|
||||
<div *ngFor="let error of form.get('password').errors | keyvalue">
|
||||
{{'password.error.' + error.key | i18n}}<br>
|
||||
@ -28,14 +28,14 @@
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<input matInput type="password" placeholder="{{'password.confirm' | i18n}}" formControlName="password2"
|
||||
[(ngModel)]="model.password2" required>
|
||||
[(ngModel)]="model.password2" required tabindex="3">
|
||||
<mat-error>
|
||||
{{'password.not-match' | i18n}}
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-slide-toggle formControlName="primaryEmail" [(ngModel)]="model.primaryEmail"
|
||||
(change)="onPrimaryChange()">
|
||||
(change)="onPrimaryChange()" tabindex="4">
|
||||
{{'email.primary' | i18n}}
|
||||
</mat-slide-toggle>
|
||||
<mat-icon #primaryHint="matTooltip" (click)="primaryHint.toggle()" inline="true"
|
||||
@ -43,7 +43,7 @@
|
||||
|
||||
<mat-form-field *ngIf="model.primaryEmail">
|
||||
<input matInput type="email" placeholder="{{'email' | i18n}}" formControlName="email"
|
||||
[(ngModel)]="model.email" required>
|
||||
[(ngModel)]="model.email" required tabindex="5">
|
||||
<mat-error>
|
||||
{{'email.invalid' | i18n}}
|
||||
</mat-error>
|
||||
@ -59,14 +59,16 @@
|
||||
<mat-divider></mat-divider>
|
||||
</mat-card-content>
|
||||
<mat-card-actions>
|
||||
<button *ngIf="!working" mat-raised-button color="primary" [disabled]="form.invalid">
|
||||
<button *ngIf="!working" mat-raised-button color="primary" [disabled]="form.invalid" tabindex="6">
|
||||
{{'register' | i18n}}
|
||||
</button>
|
||||
|
||||
<mat-progress-bar *ngIf="working" mode="indeterminate"></mat-progress-bar>
|
||||
</mat-card-actions>
|
||||
<mat-card-footer>
|
||||
<a href="https://wiki.bstly.de/services/webstly#registration" class="help-button" matTooltip="{{'help-button' | i18n}}" matTooltipPosition="above" target="_blank" mat-fab color="accent">
|
||||
<a href="https://wiki.bstly.de/services/webstly#registration" class="help-button"
|
||||
matTooltip="{{'help-button' | i18n}}" matTooltipPosition="above" target="_blank" mat-fab color="accent"
|
||||
tabindex="7">
|
||||
<mat-icon>contact_support</mat-icon>
|
||||
</a>
|
||||
</mat-card-footer>
|
||||
|
106
src/app/services/borrow.service.ts
Normal file
106
src/app/services/borrow.service.ts
Normal file
@ -0,0 +1,106 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient, HttpParams } from '@angular/common/http';
|
||||
|
||||
import { environment } from '../../environments/environment';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class BorrowItemsService {
|
||||
|
||||
constructor(private http: HttpClient) {
|
||||
}
|
||||
|
||||
getItems(page: number, size: number, sort: string, desc: boolean, search: string, owner: boolean) {
|
||||
let httpParams = new HttpParams();
|
||||
if (page != undefined) {
|
||||
httpParams = httpParams.set("page", "" + page);
|
||||
}
|
||||
if (size != undefined) {
|
||||
httpParams = httpParams.set("size", "" + size);
|
||||
}
|
||||
|
||||
if (sort != undefined) {
|
||||
httpParams = httpParams.set("sort", sort);
|
||||
}
|
||||
|
||||
if (desc != undefined) {
|
||||
httpParams = httpParams.set("desc", "" + desc);
|
||||
}
|
||||
|
||||
if (search != undefined) {
|
||||
httpParams = httpParams.set("search", "" + search);
|
||||
}
|
||||
|
||||
if (owner != undefined && owner) {
|
||||
httpParams = httpParams.set("owner", "" + owner);
|
||||
}
|
||||
|
||||
return this.http.get(environment.apiUrl + "/borrow/items", { params: httpParams });
|
||||
}
|
||||
|
||||
getItem(id) {
|
||||
return this.http.get(environment.apiUrl + "/borrow/items/" + id);
|
||||
}
|
||||
|
||||
createOrUpdateItem(borrowItem) {
|
||||
return this.http.post(environment.apiUrl + "/borrow/items", borrowItem);
|
||||
}
|
||||
|
||||
deleteItem(id) {
|
||||
return this.http.delete(environment.apiUrl + "/borrow/items/" + id);
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class BorrowRequestsService {
|
||||
|
||||
constructor(private http: HttpClient) {
|
||||
}
|
||||
|
||||
getRequests(page: number, size: number, sort: string, desc: boolean, owner: boolean) {
|
||||
let httpParams = new HttpParams();
|
||||
if (page != undefined) {
|
||||
httpParams = httpParams.set("page", "" + page);
|
||||
}
|
||||
if (size != undefined) {
|
||||
httpParams = httpParams.set("size", "" + size);
|
||||
}
|
||||
|
||||
if (sort != undefined) {
|
||||
httpParams = httpParams.set("sort", sort);
|
||||
}
|
||||
|
||||
if (desc != undefined) {
|
||||
httpParams = httpParams.set("desc", "" + desc);
|
||||
}
|
||||
|
||||
if (owner != undefined && owner) {
|
||||
httpParams = httpParams.set("owner", "" + owner);
|
||||
}
|
||||
|
||||
return this.http.get(environment.apiUrl + "/borrow/requests", { params: httpParams });
|
||||
}
|
||||
|
||||
createOrUpdateRequest(borrowRequest) {
|
||||
return this.http.post(environment.apiUrl + "/borrow/requests", borrowRequest);
|
||||
}
|
||||
|
||||
deleteRequest(id) {
|
||||
return this.http.delete(environment.apiUrl + "/borrow/requests/" + id);
|
||||
}
|
||||
|
||||
setRequestStatus(borrowRequest) {
|
||||
return this.http.put(environment.apiUrl + "/borrow/requests", borrowRequest);
|
||||
}
|
||||
|
||||
getRequestCode(id) {
|
||||
return this.http.get(environment.apiUrl + "/borrow/requests/code/" + id);
|
||||
}
|
||||
|
||||
verifyRequest(serialized) {
|
||||
return this.http.post(environment.apiUrl + "/borrow/requests/verify", serialized);
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import {Injectable} from '@angular/core';
|
||||
import {HttpClient} from '@angular/common/http';
|
||||
import {environment} from '../../environments/environment';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { environment } from '../../environments/environment';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
@ -8,7 +8,7 @@ import {environment} from '../../environments/environment';
|
||||
export class I18nService {
|
||||
|
||||
locale: string = "de-informal";
|
||||
locales: any[] = ["de-informal"];
|
||||
locales: any[] = [ "de-informal" ];
|
||||
i18n: any;
|
||||
|
||||
constructor(private http: HttpClient) {
|
||||
@ -31,13 +31,13 @@ export class I18nService {
|
||||
|
||||
let browserLocale = navigator.language;
|
||||
|
||||
if(browserLocale.indexOf("-") != -1) {
|
||||
browserLocale = browserLocale.split("-")[0];
|
||||
if (browserLocale.indexOf("-") != -1) {
|
||||
browserLocale = browserLocale.split("-")[ 0 ];
|
||||
}
|
||||
|
||||
let locale = localStorage.getItem("bstly.locale") || browserLocale || this.locales[0];
|
||||
let locale = localStorage.getItem("bstly.locale") || browserLocale || this.locales[ 0 ];
|
||||
|
||||
if(locale == 'de') {
|
||||
if (locale == 'de') {
|
||||
locale = 'de-informal';
|
||||
}
|
||||
|
||||
@ -45,54 +45,58 @@ export class I18nService {
|
||||
await this.http.get(environment.apiUrl + "/i18n").toPromise().then((response: any) => {
|
||||
this.locales = response;
|
||||
});
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
console.debug("fallback to default locales");
|
||||
}
|
||||
|
||||
if(this.locales.indexOf(locale) == -1) {
|
||||
locale = this.locales[0];
|
||||
if (this.locales.indexOf(locale) == -1) {
|
||||
locale = this.locales[ 0 ];
|
||||
}
|
||||
|
||||
this.setLocale(locale);
|
||||
try {
|
||||
this.i18n = await this.http.get(environment.apiUrl + "/i18n/" + locale).toPromise();
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
this.i18n = await this.http.get("/assets/i18n/" + locale + ".json").toPromise();
|
||||
console.debug("fallback to default locale");
|
||||
}
|
||||
}
|
||||
|
||||
get(key, args: string[]): string {
|
||||
return this.getInternal(key, args, this.i18n);
|
||||
return this.getInternal(key, args, this.i18n, "");
|
||||
}
|
||||
|
||||
getInternal(key, args: string[], from): string {
|
||||
getInternal(key, args: string[], from, path): string {
|
||||
key += '';
|
||||
if(!from) {
|
||||
return key;
|
||||
} else if(from[key]) {
|
||||
if(typeof from[key] === 'object') {
|
||||
if(from[key]["."]) {
|
||||
return this.insertArguments(from[key]["."], args);
|
||||
if (!from) {
|
||||
return this.empty(key, args, path);
|
||||
} else if (from[ key ]) {
|
||||
if (typeof from[ key ] === 'object') {
|
||||
if (from[ key ][ "." ]) {
|
||||
return this.insertArguments(from[ key ][ "." ], args);
|
||||
}
|
||||
return key;
|
||||
return this.empty(key, args, path);
|
||||
}
|
||||
return this.insertArguments(from[key], args);
|
||||
return this.insertArguments(from[ key ], args);
|
||||
} else {
|
||||
let keys = key.split(".");
|
||||
if(from[keys[0]]) {
|
||||
if (from[ keys[ 0 ] ]) {
|
||||
key = keys.slice(1, keys.length).join(".");
|
||||
return this.getInternal(key, args, from[keys[0]])
|
||||
return this.getInternal(key, args, from[ keys[ 0 ] ], path + keys[ 0 ] + ".")
|
||||
}
|
||||
}
|
||||
|
||||
return key;
|
||||
return this.empty(key, args, path);
|
||||
}
|
||||
|
||||
empty(key, args: string[], path: string): string {
|
||||
return (path ? path + (path.endsWith(".") ? "" : ".") : "") + key + (args && args.length > 0 ? (" [" + args + "]") : "");
|
||||
}
|
||||
|
||||
insertArguments(label: string, args: string[]) {
|
||||
if(args) {
|
||||
for(let index in args) {
|
||||
label = label.replace(`{${index}}`, this.get(args[index], []));
|
||||
if (args) {
|
||||
for (let index in args) {
|
||||
label = label.replace(`{${index}}`, this.get(args[ index ], []));
|
||||
}
|
||||
}
|
||||
return label;
|
||||
|
@ -1,7 +1,7 @@
|
||||
import {Injectable} from '@angular/core';
|
||||
import {HttpClient} from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
|
||||
import {environment} from '../../environments/environment';
|
||||
import { environment } from '../../environments/environment';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
@ -19,6 +19,23 @@ export class InviteService {
|
||||
return this.http.get(environment.apiUrl + "/invites" + (quota ? "?quota=" + quota + "&" : "?") + "page=" + page + "&size=" + size + "&search=" + search + (redeemed ? "&redeemed=" + redeemed : ""));
|
||||
}
|
||||
|
||||
code(code: string) {
|
||||
return this.http.get(environment.apiUrl + "/invites/" + code);
|
||||
}
|
||||
|
||||
permissions(code: string) {
|
||||
return this.http.get(environment.apiUrl + "/invites/" + code + "/permissions");
|
||||
}
|
||||
|
||||
quotas(code: string) {
|
||||
return this.http.get(environment.apiUrl + "/invites/" + code + "/quotas");
|
||||
}
|
||||
|
||||
|
||||
register(model: any) {
|
||||
return this.http.post(environment.apiUrl + "/invites", model);
|
||||
}
|
||||
|
||||
getOthers(quota: string) {
|
||||
return this.http.get(environment.apiUrl + "/invites/" + quota + "/others");
|
||||
}
|
||||
@ -32,7 +49,7 @@ export class InviteService {
|
||||
}
|
||||
|
||||
update(invite: any) {
|
||||
return this.http.post(environment.apiUrl + "/invites", invite);
|
||||
return this.http.patch(environment.apiUrl + "/invites", invite);
|
||||
}
|
||||
|
||||
}
|
20
src/app/ui/durationpicker/durationpicker.component.html
Normal file
20
src/app/ui/durationpicker/durationpicker.component.html
Normal file
@ -0,0 +1,20 @@
|
||||
<div fxLayout="row wrap" fxLayoutAlign="start stretch">
|
||||
<div fxFlex="33%">
|
||||
<mat-form-field>
|
||||
<input matInput type="number" min="0" placeholder="{{'durationpicker.days' | i18n}}" [formControl]="days">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div fxFlex="33%">
|
||||
<mat-form-field>
|
||||
<input matInput type="number" min="0" max="23" placeholder="{{'durationpicker.hours' | i18n}}"
|
||||
[formControl]="hours">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div fxFlex="33%">
|
||||
<mat-form-field>
|
||||
<input matInput type="number" min="0" max="59" placeholder="{{'durationpicker.minutes' | i18n}}"
|
||||
[formControl]="minutes">
|
||||
<mat-hint align="end">{{duration}}</mat-hint>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
4
src/app/ui/durationpicker/durationpicker.component.scss
Normal file
4
src/app/ui/durationpicker/durationpicker.component.scss
Normal file
@ -0,0 +1,4 @@
|
||||
mat-form-field {
|
||||
display: block;
|
||||
padding-right: 8px;
|
||||
}
|
98
src/app/ui/durationpicker/durationpicker.component.ts
Normal file
98
src/app/ui/durationpicker/durationpicker.component.ts
Normal file
@ -0,0 +1,98 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { ControlValueAccessor, FormControl, NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||
import * as moment from 'moment';
|
||||
|
||||
@Component({
|
||||
selector: 'app-durationpicker',
|
||||
templateUrl: './durationpicker.component.html',
|
||||
styleUrls: [ './durationpicker.component.scss' ],
|
||||
providers: [
|
||||
{
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
multi: true,
|
||||
useExisting: DurationpickerComponent
|
||||
}
|
||||
]
|
||||
})
|
||||
export class DurationpickerComponent implements OnInit, ControlValueAccessor {
|
||||
|
||||
days = new FormControl();
|
||||
hours = new FormControl();
|
||||
minutes = new FormControl();
|
||||
|
||||
duration: string;
|
||||
model: moment.Duration;
|
||||
onChange = (duration) => { };
|
||||
onTouched = () => { };
|
||||
isDisabled = false;
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
this.days.valueChanges.subscribe(value => {
|
||||
if (value < this.model.days()) {
|
||||
this.model.subtract((this.model.days() - value), "days");
|
||||
} else {
|
||||
this.model.add((value - this.model.days()), "days");
|
||||
}
|
||||
this.checkValue();
|
||||
})
|
||||
|
||||
this.hours.valueChanges.subscribe(value => {
|
||||
if (value < this.model.hours()) {
|
||||
this.model.subtract((this.model.hours() - value), "hours");
|
||||
} else {
|
||||
this.model.add((value - this.model.hours()), "hours");
|
||||
}
|
||||
this.checkValue();
|
||||
})
|
||||
|
||||
this.minutes.valueChanges.subscribe(value => {
|
||||
if (value < this.model.minutes()) {
|
||||
this.model.subtract((this.model.minutes() - value), "minutes");
|
||||
} else {
|
||||
this.model.add((value - this.model.minutes()), "minutes");
|
||||
}
|
||||
this.checkValue();
|
||||
})
|
||||
}
|
||||
|
||||
checkValue() {
|
||||
if (this.model.asMinutes() <= 0) {
|
||||
this.days.setValue(0, { emitEvent: false });
|
||||
this.hours.setValue(0, { emitEvent: false });
|
||||
this.minutes.setValue(0, { emitEvent: false });
|
||||
this.duration = null;
|
||||
} else {
|
||||
this.duration = this.model.toISOString();
|
||||
}
|
||||
|
||||
this.onChange(this.duration);
|
||||
this.onTouched();
|
||||
}
|
||||
|
||||
|
||||
|
||||
writeValue(duration: string): void {
|
||||
this.duration = duration;
|
||||
this.model = moment.duration(this.duration);
|
||||
this.days.setValue(this.model.days(), { emitEvent: false });
|
||||
this.hours.setValue(this.model.hours()), { emitEvent: false };
|
||||
this.minutes.setValue(this.model.minutes(), { emitEvent: false });
|
||||
this.onTouched();
|
||||
}
|
||||
|
||||
registerOnChange(onChange: any): void {
|
||||
this.onChange = onChange;
|
||||
}
|
||||
|
||||
registerOnTouched(onTouched: any): void {
|
||||
this.onTouched = onTouched;
|
||||
}
|
||||
|
||||
setDisabledState?(isDisabled: boolean): void {
|
||||
this.isDisabled = isDisabled;
|
||||
}
|
||||
|
||||
|
||||
}
|
13
src/app/utils/moment.pipe.ts
Normal file
13
src/app/utils/moment.pipe.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
import * as moment from 'moment';
|
||||
|
||||
@Pipe({ name: 'datef' })
|
||||
export class MomentPipe implements PipeTransform {
|
||||
transform(value: Date | moment.Moment, dateFormat: string): any {
|
||||
if (!dateFormat) {
|
||||
return moment(value).fromNow();
|
||||
}
|
||||
|
||||
return moment(value).format(dateFormat);
|
||||
}
|
||||
}
|
@ -4,8 +4,8 @@
|
||||
|
||||
export const environment = {
|
||||
production: false,
|
||||
apiUrl : 'http://localhost:9000',
|
||||
//apiUrl : 'https://api.bstly.lh8.de',
|
||||
// apiUrl : 'http://localhost:9000',
|
||||
apiUrl : 'https://api.bstly.lh8.de',
|
||||
};
|
||||
|
||||
/*
|
||||
|
87
src/qr-scanner-worker.min.js
vendored
Normal file
87
src/qr-scanner-worker.min.js
vendored
Normal file
@ -0,0 +1,87 @@
|
||||
'use strict';(function(){function T(a,b){let c=[],d="";b=a.readBits([8,16,16][b]);for(let d=0;d<b;d++){let b=a.readBits(8);c.push(b)}try{d+=decodeURIComponent(c.map(a=>`%${("0"+a.toString(16)).substr(-2)}`).join(""))}catch(e){}return{bytes:c,text:d}}function U(a,b){a=new V(a);let c=9>=b?0:26>=b?1:2;for(b={text:"",bytes:[],chunks:[],version:b};4<=a.available();){var d=a.readBits(4);if(d===t.Terminator)return b;if(d===t.ECI)0===a.readBits(1)?b.chunks.push({type:r.ECI,assignmentNumber:a.readBits(7)}):
|
||||
0===a.readBits(1)?b.chunks.push({type:r.ECI,assignmentNumber:a.readBits(14)}):0===a.readBits(1)?b.chunks.push({type:r.ECI,assignmentNumber:a.readBits(21)}):b.chunks.push({type:r.ECI,assignmentNumber:-1});else if(d===t.Numeric){var e=a;d=[];for(var f="",g=e.readBits([10,12,14][c]);3<=g;){var h=e.readBits(10);if(1E3<=h)throw Error("Invalid numeric value above 999");var k=Math.floor(h/100),n=Math.floor(h/10)%10;h%=10;d.push(48+k,48+n,48+h);f+=k.toString()+n.toString()+h.toString();g-=3}if(2===g){g=e.readBits(7);
|
||||
if(100<=g)throw Error("Invalid numeric value above 99");e=Math.floor(g/10);g%=10;d.push(48+e,48+g);f+=e.toString()+g.toString()}else if(1===g){e=e.readBits(4);if(10<=e)throw Error("Invalid numeric value above 9");d.push(48+e);f+=e.toString()}d={bytes:d,text:f};b.text+=d.text;b.bytes.push(...d.bytes);b.chunks.push({type:r.Numeric,text:d.text})}else if(d===t.Alphanumeric){e=a;d=[];f="";for(g=e.readBits([9,11,13][c]);2<=g;)n=e.readBits(11),k=Math.floor(n/45),n%=45,d.push(B[k].charCodeAt(0),B[n].charCodeAt(0)),
|
||||
f+=B[k]+B[n],g-=2;1===g&&(e=e.readBits(6),d.push(B[e].charCodeAt(0)),f+=B[e]);d={bytes:d,text:f};b.text+=d.text;b.bytes.push(...d.bytes);b.chunks.push({type:r.Alphanumeric,text:d.text})}else if(d===t.Byte)d=T(a,c),b.text+=d.text,b.bytes.push(...d.bytes),b.chunks.push({type:r.Byte,bytes:d.bytes,text:d.text});else if(d===t.Kanji){f=a;d=[];e=f.readBits([8,10,12][c]);for(g=0;g<e;g++)k=f.readBits(13),k=Math.floor(k/192)<<8|k%192,k=7936>k?k+33088:k+49472,d.push(k>>8,k&255);f=(new TextDecoder("shift-jis")).decode(Uint8Array.from(d));
|
||||
d={bytes:d,text:f};b.text+=d.text;b.bytes.push(...d.bytes);b.chunks.push({type:r.Kanji,bytes:d.bytes,text:d.text})}else d===t.StructuredAppend&&b.chunks.push({type:r.StructuredAppend,currentSequence:a.readBits(4),totalSequence:a.readBits(4),parity:a.readBits(8)})}if(0===a.available()||0===a.readBits(a.available()))return b}function J(a,b){return a^b}function W(a,b,c,d){b.degree()<c.degree()&&([b,c]=[c,b]);let e=a.zero;for(var f=a.one;c.degree()>=d/2;){var g=b;let d=e;b=c;e=f;if(b.isZero())return null;
|
||||
c=g;f=a.zero;g=b.getCoefficient(b.degree());for(g=a.inverse(g);c.degree()>=b.degree()&&!c.isZero();){let d=c.degree()-b.degree(),e=a.multiply(c.getCoefficient(c.degree()),g);f=f.addOrSubtract(a.buildMonomial(d,e));c=c.addOrSubtract(b.multiplyByMonomial(d,e))}f=f.multiplyPoly(e).addOrSubtract(d);if(c.degree()>=b.degree())return null}d=f.getCoefficient(0);if(0===d)return null;a=a.inverse(d);return[f.multiply(a),c.multiply(a)]}function X(a,b){let c=new Uint8ClampedArray(a.length);c.set(a);a=new Y(285,
|
||||
256,0);var d=new w(a,c),e=new Uint8ClampedArray(b),f=!1;for(var g=0;g<b;g++){var h=d.evaluateAt(a.exp(g+a.generatorBase));e[e.length-1-g]=h;0!==h&&(f=!0)}if(!f)return c;d=new w(a,e);d=W(a,a.buildMonomial(b,1),d,b);if(null===d)return null;b=d[0];g=b.degree();if(1===g)b=[b.getCoefficient(1)];else{e=Array(g);f=0;for(h=1;h<a.size&&f<g;h++)0===b.evaluateAt(h)&&(e[f]=a.inverse(h),f++);b=f!==g?null:e}if(null==b)return null;d=d[1];e=b.length;f=Array(e);for(g=0;g<e;g++){h=a.inverse(b[g]);let c=1;for(let d=
|
||||
0;d<e;d++)g!==d&&(c=a.multiply(c,J(1,a.multiply(b[d],h))));f[g]=a.multiply(d.evaluateAt(h),a.inverse(c));0!==a.generatorBase&&(f[g]=a.multiply(f[g],h))}d=f;for(e=0;e<b.length;e++){f=c.length-1-a.log(b[e]);if(0>f)return null;c[f]^=d[e]}return c}function E(a,b){a^=b;for(b=0;a;)b++,a&=a-1;return b}function C(a,b){return b<<1|a}function Z(a,b,c){c=aa[c.dataMask];let d=a.height;var e=17+4*b.versionNumber,f=A.createEmpty(e,e);f.setRegion(0,0,9,9,!0);f.setRegion(e-8,0,8,9,!0);f.setRegion(0,e-8,9,8,!0);for(var g of b.alignmentPatternCenters)for(var h of b.alignmentPatternCenters)6===
|
||||
g&&6===h||6===g&&h===e-7||g===e-7&&6===h||f.setRegion(g-2,h-2,5,5,!0);f.setRegion(6,9,1,e-17,!0);f.setRegion(9,6,e-17,1,!0);6<b.versionNumber&&(f.setRegion(e-11,0,3,6,!0),f.setRegion(0,e-11,6,3,!0));b=f;g=[];e=h=0;f=!0;for(let k=d-1;0<k;k-=2){6===k&&k--;for(let n=0;n<d;n++){let m=f?d-1-n:n;for(let d=0;2>d;d++){let f=k-d;if(!b.get(f,m)){e++;let b=a.get(f,m);c({y:m,x:f})&&(b=!b);h=h<<1|b;8===e&&(g.push(h),h=e=0)}}}f=!f}return g}function ba(a){var b=a.height,c=Math.floor((b-17)/4);if(6>=c)return K[c-
|
||||
1];c=0;for(var d=5;0<=d;d--)for(var e=b-9;e>=b-11;e--)c=C(a.get(e,d),c);d=0;for(e=5;0<=e;e--)for(let c=b-9;c>=b-11;c--)d=C(a.get(e,c),d);a=Infinity;let f;for(let e of K){if(e.infoBits===c||e.infoBits===d)return e;b=E(c,e.infoBits);b<a&&(f=e,a=b);b=E(d,e.infoBits);b<a&&(f=e,a=b)}if(3>=a)return f}function ca(a){let b=0;for(var c=0;8>=c;c++)6!==c&&(b=C(a.get(c,8),b));for(c=7;0<=c;c--)6!==c&&(b=C(a.get(8,c),b));var d=a.height;c=0;for(var e=d-1;e>=d-7;e--)c=C(a.get(8,e),c);for(e=d-8;e<d;e++)c=C(a.get(e,
|
||||
8),c);a=Infinity;d=null;for(let {bits:f,formatInfo:g}of da){if(f===b||f===c)return g;e=E(b,f);e<a&&(d=g,a=e);b!==c&&(e=E(c,f),e<a&&(d=g,a=e))}return 3>=a?d:null}function ea(a,b,c){let d=b.errorCorrectionLevels[c],e=[],f=0;d.ecBlocks.forEach(a=>{for(let b=0;b<a.numBlocks;b++)e.push({numDataCodewords:a.dataCodewordsPerBlock,codewords:[]}),f+=a.dataCodewordsPerBlock+d.ecCodewordsPerBlock});if(a.length<f)return null;a=a.slice(0,f);b=d.ecBlocks[0].dataCodewordsPerBlock;for(c=0;c<b;c++)for(var g of e)g.codewords.push(a.shift());
|
||||
if(1<d.ecBlocks.length)for(g=d.ecBlocks[0].numBlocks,b=d.ecBlocks[1].numBlocks,c=0;c<b;c++)e[g+c].codewords.push(a.shift());for(;0<a.length;)for(let b of e)b.codewords.push(a.shift());return e}function L(a){let b=ba(a);if(!b)return null;var c=ca(a);if(!c)return null;a=Z(a,b,c);var d=ea(a,b,c.errorCorrectionLevel);if(!d)return null;c=d.reduce((a,b)=>a+b.numDataCodewords,0);c=new Uint8ClampedArray(c);a=0;for(let b of d){d=X(b.codewords,b.codewords.length-b.numDataCodewords);if(!d)return null;for(let e=
|
||||
0;e<b.numDataCodewords;e++)c[a++]=d[e]}try{return U(c,b.versionNumber)}catch(e){return null}}function M(a,b,c,d){var e=a.x-b.x+c.x-d.x;let f=a.y-b.y+c.y-d.y;if(0===e&&0===f)return{a11:b.x-a.x,a12:b.y-a.y,a13:0,a21:c.x-b.x,a22:c.y-b.y,a23:0,a31:a.x,a32:a.y,a33:1};{let h=b.x-c.x;var g=d.x-c.x;let k=b.y-c.y,n=d.y-c.y;c=h*n-g*k;g=(e*n-g*f)/c;e=(h*f-e*k)/c;return{a11:b.x-a.x+g*b.x,a12:b.y-a.y+g*b.y,a13:g,a21:d.x-a.x+e*d.x,a22:d.y-a.y+e*d.y,a23:e,a31:a.x,a32:a.y,a33:1}}}function fa(a,b,c,d){a=M(a,b,c,d);
|
||||
return{a11:a.a22*a.a33-a.a23*a.a32,a12:a.a13*a.a32-a.a12*a.a33,a13:a.a12*a.a23-a.a13*a.a22,a21:a.a23*a.a31-a.a21*a.a33,a22:a.a11*a.a33-a.a13*a.a31,a23:a.a13*a.a21-a.a11*a.a23,a31:a.a21*a.a32-a.a22*a.a31,a32:a.a12*a.a31-a.a11*a.a32,a33:a.a11*a.a22-a.a12*a.a21}}function ha(a,b){var c=fa({x:3.5,y:3.5},{x:b.dimension-3.5,y:3.5},{x:b.dimension-6.5,y:b.dimension-6.5},{x:3.5,y:b.dimension-3.5}),d=M(b.topLeft,b.topRight,b.alignmentPattern,b.bottomLeft),e=d.a11*c.a11+d.a21*c.a12+d.a31*c.a13,f=d.a12*c.a11+
|
||||
d.a22*c.a12+d.a32*c.a13,g=d.a13*c.a11+d.a23*c.a12+d.a33*c.a13,h=d.a11*c.a21+d.a21*c.a22+d.a31*c.a23,k=d.a12*c.a21+d.a22*c.a22+d.a32*c.a23,n=d.a13*c.a21+d.a23*c.a22+d.a33*c.a23,m=d.a11*c.a31+d.a21*c.a32+d.a31*c.a33,l=d.a12*c.a31+d.a22*c.a32+d.a32*c.a33,p=d.a13*c.a31+d.a23*c.a32+d.a33*c.a33;c=A.createEmpty(b.dimension,b.dimension);d=(a,b)=>{const c=g*a+n*b+p;return{x:(e*a+h*b+m)/c,y:(f*a+k*b+l)/c}};for(let e=0;e<b.dimension;e++)for(let f=0;f<b.dimension;f++){let b=d(f+.5,e+.5);c.set(f,e,a.get(Math.floor(b.x),
|
||||
Math.floor(b.y)))}return{matrix:c,mappingFunction:d}}function x(a){return a.reduce((a,c)=>a+c)}function ia(a,b,c){let d=y(a,b),e=y(b,c),f=y(a,c),g,h,k;e>=d&&e>=f?[g,h,k]=[b,a,c]:f>=e&&f>=d?[g,h,k]=[a,b,c]:[g,h,k]=[a,c,b];0>(k.x-h.x)*(g.y-h.y)-(k.y-h.y)*(g.x-h.x)&&([g,k]=[k,g]);return{bottomLeft:g,topLeft:h,topRight:k}}function ja(a,b,c,d){d=(x(z(a,c,d,5))/7+x(z(a,b,d,5))/7+x(z(c,a,d,5))/7+x(z(b,a,d,5))/7)/4;if(1>d)throw Error("Invalid module size");b=Math.round(y(a,b)/d);a=Math.round(y(a,c)/d);a=
|
||||
Math.floor((b+a)/2)+7;switch(a%4){case 0:a++;break;case 2:a--}return{dimension:a,moduleSize:d}}function N(a,b,c,d){let e=[{x:Math.floor(a.x),y:Math.floor(a.y)}];var f=Math.abs(b.y-a.y)>Math.abs(b.x-a.x);if(f){var g=Math.floor(a.y);var h=Math.floor(a.x);a=Math.floor(b.y);b=Math.floor(b.x)}else g=Math.floor(a.x),h=Math.floor(a.y),a=Math.floor(b.x),b=Math.floor(b.y);let k=Math.abs(a-g),n=Math.abs(b-h),m=Math.floor(-k/2),l=g<a?1:-1,p=h<b?1:-1,q=!0;for(let v=g,u=h;v!==a+l;v+=l){g=f?u:v;h=f?v:u;if(c.get(g,
|
||||
h)!==q&&(q=!q,e.push({x:g,y:h}),e.length===d+1))break;m+=n;if(0<m){if(u===b)break;u+=p;m-=k}}c=[];for(f=0;f<d;f++)e[f]&&e[f+1]?c.push(y(e[f],e[f+1])):c.push(0);return c}function z(a,b,c,d){let e=b.y-a.y,f=b.x-a.x;b=N(a,b,c,Math.ceil(d/2));a=N(a,{x:a.x-f,y:a.y-e},c,Math.ceil(d/2));c=b.shift()+a.shift()-1;return a.concat(c).concat(...b)}function F(a,b){let c=x(a)/x(b),d=0;b.forEach((b,f)=>{d+=Math.pow(a[f]-b*c,2)});return{averageSize:c,error:d}}function O(a,b,c){try{let d=z(a,{x:-1,y:a.y},c,b.length),
|
||||
e=z(a,{x:a.x,y:-1},c,b.length),f=z(a,{x:Math.max(0,a.x-a.y)-1,y:Math.max(0,a.y-a.x)-1},c,b.length),g=z(a,{x:Math.min(c.width,a.x+a.y)+1,y:Math.min(c.height,a.y+a.x)+1},c,b.length),h=F(d,b),k=F(e,b),n=F(f,b),m=F(g,b),l=(h.averageSize+k.averageSize+n.averageSize+m.averageSize)/4;return Math.sqrt(h.error*h.error+k.error*k.error+n.error*n.error+m.error*m.error)+(Math.pow(h.averageSize-l,2)+Math.pow(k.averageSize-l,2)+Math.pow(n.averageSize-l,2)+Math.pow(m.averageSize-l,2))/l}catch(d){return Infinity}}
|
||||
function H(a,b){for(var c=Math.round(b.x);a.get(c,Math.round(b.y));)c--;for(var d=Math.round(b.x);a.get(d,Math.round(b.y));)d++;c=(c+d)/2;for(d=Math.round(b.y);a.get(Math.round(c),d);)d--;for(b=Math.round(b.y);a.get(Math.round(c),b);)b++;return{x:c,y:(d+b)/2}}function ka(a){var b=[],c=[];let d=[];var e=[];for(let m=0;m<=a.height;m++){var f=0,g=!1;let l=[0,0,0,0,0];for(let b=-1;b<=a.width;b++){var h=a.get(b,m);if(h===g)f++;else{l=[l[1],l[2],l[3],l[4],f];f=1;g=h;var k=x(l)/7;k=Math.abs(l[0]-k)<k&&Math.abs(l[1]-
|
||||
k)<k&&Math.abs(l[2]-3*k)<3*k&&Math.abs(l[3]-k)<k&&Math.abs(l[4]-k)<k&&!h;var n=x(l.slice(-3))/3;h=Math.abs(l[2]-n)<n&&Math.abs(l[3]-n)<n&&Math.abs(l[4]-n)<n&&h;if(k){let a=b-l[3]-l[4],d=a-l[2];k={startX:d,endX:a,y:m};n=c.filter(b=>d>=b.bottom.startX&&d<=b.bottom.endX||a>=b.bottom.startX&&d<=b.bottom.endX||d<=b.bottom.startX&&a>=b.bottom.endX&&1.5>l[2]/(b.bottom.endX-b.bottom.startX)&&.5<l[2]/(b.bottom.endX-b.bottom.startX));0<n.length?n[0].bottom=k:c.push({top:k,bottom:k})}if(h){let a=b-l[4],c=a-
|
||||
l[3];h={startX:c,y:m,endX:a};k=e.filter(b=>c>=b.bottom.startX&&c<=b.bottom.endX||a>=b.bottom.startX&&c<=b.bottom.endX||c<=b.bottom.startX&&a>=b.bottom.endX&&1.5>l[2]/(b.bottom.endX-b.bottom.startX)&&.5<l[2]/(b.bottom.endX-b.bottom.startX));0<k.length?k[0].bottom=h:e.push({top:h,bottom:h})}}}b.push(...c.filter(a=>a.bottom.y!==m&&2<=a.bottom.y-a.top.y));c=c.filter(a=>a.bottom.y===m);d.push(...e.filter(a=>a.bottom.y!==m));e=e.filter(a=>a.bottom.y===m)}b.push(...c.filter(a=>2<=a.bottom.y-a.top.y));d.push(...e);
|
||||
c=[];for(var m of b)2>m.bottom.y-m.top.y||(b=(m.top.startX+m.top.endX+m.bottom.startX+m.bottom.endX)/4,e=(m.top.y+m.bottom.y+1)/2,a.get(Math.round(b),Math.round(e))&&(f=[m.top.endX-m.top.startX,m.bottom.endX-m.bottom.startX,m.bottom.y-m.top.y+1],f=x(f)/f.length,g=O({x:Math.round(b),y:Math.round(e)},[1,1,3,1,1],a),c.push({score:g,x:b,y:e,size:f})));if(3>c.length)return null;c.sort((a,b)=>a.score-b.score);m=[];for(b=0;b<Math.min(c.length,5);++b){e=c[b];f=[];for(var l of c)l!==e&&f.push(Object.assign(Object.assign({},
|
||||
l),{score:l.score+Math.pow(l.size-e.size,2)/e.size}));f.sort((a,b)=>a.score-b.score);m.push({points:[e,f[0],f[1]],score:e.score+f[0].score+f[1].score})}m.sort((a,b)=>a.score-b.score);let {topRight:p,topLeft:q,bottomLeft:v}=ia(...m[0].points);m=P(a,d,p,q,v);l=[];m&&l.push({alignmentPattern:{x:m.alignmentPattern.x,y:m.alignmentPattern.y},bottomLeft:{x:v.x,y:v.y},dimension:m.dimension,topLeft:{x:q.x,y:q.y},topRight:{x:p.x,y:p.y}});m=H(a,p);b=H(a,q);c=H(a,v);(a=P(a,d,m,b,c))&&l.push({alignmentPattern:{x:a.alignmentPattern.x,
|
||||
y:a.alignmentPattern.y},bottomLeft:{x:c.x,y:c.y},topLeft:{x:b.x,y:b.y},topRight:{x:m.x,y:m.y},dimension:a.dimension});return 0===l.length?null:l}function P(a,b,c,d,e){let f,g;try{({dimension:f,moduleSize:g}=ja(d,c,e,a))}catch(m){return null}var h=c.x-d.x+e.x,k=c.y-d.y+e.y;c=(y(d,e)+y(d,c))/2/g;e=1-3/c;let n={x:d.x+e*(h-d.x),y:d.y+e*(k-d.y)};b=b.map(b=>{const c=(b.top.startX+b.top.endX+b.bottom.startX+b.bottom.endX)/4;b=(b.top.y+b.bottom.y+1)/2;if(a.get(Math.floor(c),Math.floor(b))){var d=O({x:Math.floor(c),
|
||||
y:Math.floor(b)},[1,1,1],a)+y({x:c,y:b},n);return{x:c,y:b,score:d}}}).filter(a=>!!a).sort((a,b)=>a.score-b.score);return{alignmentPattern:15<=c&&b.length?b[0]:n,dimension:f}}function Q(a){var b=ka(a);if(!b)return null;for(let e of b){b=ha(a,e);var c=b.matrix;if(null==c)c=null;else{var d=L(c);if(d)c=d;else{for(d=0;d<c.width;d++)for(let a=d+1;a<c.height;a++)c.get(d,a)!==c.get(a,d)&&(c.set(d,a,!c.get(d,a)),c.set(a,d,!c.get(a,d)));c=L(c)}}if(c)return{binaryData:c.bytes,data:c.text,chunks:c.chunks,version:c.version,
|
||||
location:{topRightCorner:b.mappingFunction(e.dimension,0),topLeftCorner:b.mappingFunction(0,0),bottomRightCorner:b.mappingFunction(e.dimension,e.dimension),bottomLeftCorner:b.mappingFunction(0,e.dimension),topRightFinderPattern:e.topRight,topLeftFinderPattern:e.topLeft,bottomLeftFinderPattern:e.bottomLeft,bottomRightAlignmentPattern:e.alignmentPattern},matrix:b.matrix}}return null}function R(a,b){Object.keys(b).forEach(c=>{a[c]=b[c]})}function I(a,b,c,d={}){let e=Object.create(null);R(e,la);R(e,d);
|
||||
d="onlyInvert"===e.inversionAttempts||"invertFirst"===e.inversionAttempts;var f="attemptBoth"===e.inversionAttempts||d;var g=e.greyScaleWeights,h=e.canOverwriteImage,k=b*c;if(a.length!==4*k)throw Error("Malformed data passed to binarizer.");var n=0;if(h){var m=new Uint8ClampedArray(a.buffer,n,k);n+=k}m=new S(b,c,m);if(g.useIntegerApproximation)for(var l=0;l<c;l++)for(var p=0;p<b;p++){var q=4*(l*b+p);m.set(p,l,g.red*a[q]+g.green*a[q+1]+g.blue*a[q+2]+128>>8)}else for(l=0;l<c;l++)for(p=0;p<b;p++)q=4*
|
||||
(l*b+p),m.set(p,l,g.red*a[q]+g.green*a[q+1]+g.blue*a[q+2]);g=Math.ceil(b/8);l=Math.ceil(c/8);p=g*l;if(h){var v=new Uint8ClampedArray(a.buffer,n,p);n+=p}v=new S(g,l,v);for(p=0;p<l;p++)for(q=0;q<g;q++){var u=Infinity,r=0;for(var t=0;8>t;t++)for(let a=0;8>a;a++){let b=m.get(8*q+a,8*p+t);u=Math.min(u,b);r=Math.max(r,b)}t=(u+r)/2;t=Math.min(255,1.11*t);24>=r-u&&(t=u/2,0<p&&0<q&&(r=(v.get(q,p-1)+2*v.get(q-1,p)+v.get(q-1,p-1))/4,u<r&&(t=r)));v.set(q,p,t)}h?(p=new Uint8ClampedArray(a.buffer,n,k),n+=k,p=new A(p,
|
||||
b)):p=A.createEmpty(b,c);q=null;f&&(h?(a=new Uint8ClampedArray(a.buffer,n,k),q=new A(a,b)):q=A.createEmpty(b,c));for(b=0;b<l;b++)for(a=0;a<g;a++){c=g-3;c=2>a?2:a>c?c:a;h=l-3;h=2>b?2:b>h?h:b;k=0;for(n=-2;2>=n;n++)for(u=-2;2>=u;u++)k+=v.get(c+n,h+u);c=k/25;for(h=0;8>h;h++)for(k=0;8>k;k++)n=8*a+h,u=8*b+k,r=m.get(n,u),p.set(n,u,r<=c),f&&q.set(n,u,!(r<=c))}f=f?{binarized:p,inverted:q}:{binarized:p};let {binarized:w,inverted:x}=f;(f=Q(d?x:w))||"attemptBoth"!==e.inversionAttempts&&"invertFirst"!==e.inversionAttempts||
|
||||
(f=Q(d?w:x));return f}class A{constructor(a,b){this.width=b;this.height=a.length/b;this.data=a}static createEmpty(a,b){return new A(new Uint8ClampedArray(a*b),a)}get(a,b){return 0>a||a>=this.width||0>b||b>=this.height?!1:!!this.data[b*this.width+a]}set(a,b,c){this.data[b*this.width+a]=c?1:0}setRegion(a,b,c,d,e){for(let f=b;f<b+d;f++)for(let b=a;b<a+c;b++)this.set(b,f,!!e)}}class S{constructor(a,b,c){this.width=a;a*=b;if(c&&c.length!==a)throw Error("Wrong buffer size");this.data=c||new Uint8ClampedArray(a)}get(a,
|
||||
b){return this.data[b*this.width+a]}set(a,b,c){this.data[b*this.width+a]=c}}class V{constructor(a){this.bitOffset=this.byteOffset=0;this.bytes=a}readBits(a){if(1>a||32<a||a>this.available())throw Error("Cannot read "+a.toString()+" bits");var b=0;if(0<this.bitOffset){b=8-this.bitOffset;var c=a<b?a:b;b-=c;b=(this.bytes[this.byteOffset]&255>>8-c<<b)>>b;a-=c;this.bitOffset+=c;8===this.bitOffset&&(this.bitOffset=0,this.byteOffset++)}if(0<a){for(;8<=a;)b=b<<8|this.bytes[this.byteOffset]&255,this.byteOffset++,
|
||||
a-=8;0<a&&(c=8-a,b=b<<a|(this.bytes[this.byteOffset]&255>>c<<c)>>c,this.bitOffset+=a)}return b}available(){return 8*(this.bytes.length-this.byteOffset)-this.bitOffset}}var r;(function(a){a.Numeric="numeric";a.Alphanumeric="alphanumeric";a.Byte="byte";a.Kanji="kanji";a.ECI="eci";a.StructuredAppend="structuredappend"})(r||(r={}));var t;(function(a){a[a.Terminator=0]="Terminator";a[a.Numeric=1]="Numeric";a[a.Alphanumeric=2]="Alphanumeric";a[a.Byte=4]="Byte";a[a.Kanji=8]="Kanji";a[a.ECI=7]="ECI";a[a.StructuredAppend=
|
||||
3]="StructuredAppend"})(t||(t={}));let B="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:".split("");class w{constructor(a,b){if(0===b.length)throw Error("No coefficients.");this.field=a;let c=b.length;if(1<c&&0===b[0]){let d=1;for(;d<c&&0===b[d];)d++;if(d===c)this.coefficients=a.zero.coefficients;else for(this.coefficients=new Uint8ClampedArray(c-d),a=0;a<this.coefficients.length;a++)this.coefficients[a]=b[d+a]}else this.coefficients=b}degree(){return this.coefficients.length-1}isZero(){return 0===
|
||||
this.coefficients[0]}getCoefficient(a){return this.coefficients[this.coefficients.length-1-a]}addOrSubtract(a){if(this.isZero())return a;if(a.isZero())return this;let b=this.coefficients;a=a.coefficients;b.length>a.length&&([b,a]=[a,b]);let c=new Uint8ClampedArray(a.length),d=a.length-b.length;for(var e=0;e<d;e++)c[e]=a[e];for(e=d;e<a.length;e++)c[e]=b[e-d]^a[e];return new w(this.field,c)}multiply(a){if(0===a)return this.field.zero;if(1===a)return this;let b=this.coefficients.length,c=new Uint8ClampedArray(b);
|
||||
for(let d=0;d<b;d++)c[d]=this.field.multiply(this.coefficients[d],a);return new w(this.field,c)}multiplyPoly(a){if(this.isZero()||a.isZero())return this.field.zero;let b=this.coefficients,c=b.length;a=a.coefficients;let d=a.length,e=new Uint8ClampedArray(c+d-1);for(let h=0;h<c;h++){let c=b[h];for(let b=0;b<d;b++){var f=h+b,g=this.field.multiply(c,a[b]);e[f]=e[h+b]^g}}return new w(this.field,e)}multiplyByMonomial(a,b){if(0>a)throw Error("Invalid degree less than 0");if(0===b)return this.field.zero;
|
||||
let c=this.coefficients.length;a=new Uint8ClampedArray(c+a);for(let d=0;d<c;d++)a[d]=this.field.multiply(this.coefficients[d],b);return new w(this.field,a)}evaluateAt(a){let b=0;if(0===a)return this.getCoefficient(0);let c=this.coefficients.length;if(1===a)return this.coefficients.forEach(a=>{b^=a}),b;b=this.coefficients[0];for(let d=1;d<c;d++)b=J(this.field.multiply(a,b),this.coefficients[d]);return b}}class Y{constructor(a,b,c){this.primitive=a;this.size=b;this.generatorBase=c;this.expTable=Array(this.size);
|
||||
this.logTable=Array(this.size);a=1;for(b=0;b<this.size;b++)this.expTable[b]=a,a*=2,a>=this.size&&(a=(a^this.primitive)&this.size-1);for(a=0;a<this.size-1;a++)this.logTable[this.expTable[a]]=a;this.zero=new w(this,Uint8ClampedArray.from([0]));this.one=new w(this,Uint8ClampedArray.from([1]))}multiply(a,b){return 0===a||0===b?0:this.expTable[(this.logTable[a]+this.logTable[b])%(this.size-1)]}inverse(a){if(0===a)throw Error("Can't invert 0");return this.expTable[this.size-this.logTable[a]-1]}buildMonomial(a,
|
||||
b){if(0>a)throw Error("Invalid monomial degree less than 0");if(0===b)return this.zero;a=new Uint8ClampedArray(a+1);a[0]=b;return new w(this,a)}log(a){if(0===a)throw Error("Can't take log(0)");return this.logTable[a]}exp(a){return this.expTable[a]}}let K=[{infoBits:null,versionNumber:1,alignmentPatternCenters:[],errorCorrectionLevels:[{ecCodewordsPerBlock:7,ecBlocks:[{numBlocks:1,dataCodewordsPerBlock:19}]},{ecCodewordsPerBlock:10,ecBlocks:[{numBlocks:1,dataCodewordsPerBlock:16}]},{ecCodewordsPerBlock:13,
|
||||
ecBlocks:[{numBlocks:1,dataCodewordsPerBlock:13}]},{ecCodewordsPerBlock:17,ecBlocks:[{numBlocks:1,dataCodewordsPerBlock:9}]}]},{infoBits:null,versionNumber:2,alignmentPatternCenters:[6,18],errorCorrectionLevels:[{ecCodewordsPerBlock:10,ecBlocks:[{numBlocks:1,dataCodewordsPerBlock:34}]},{ecCodewordsPerBlock:16,ecBlocks:[{numBlocks:1,dataCodewordsPerBlock:28}]},{ecCodewordsPerBlock:22,ecBlocks:[{numBlocks:1,dataCodewordsPerBlock:22}]},{ecCodewordsPerBlock:28,ecBlocks:[{numBlocks:1,dataCodewordsPerBlock:16}]}]},
|
||||
{infoBits:null,versionNumber:3,alignmentPatternCenters:[6,22],errorCorrectionLevels:[{ecCodewordsPerBlock:15,ecBlocks:[{numBlocks:1,dataCodewordsPerBlock:55}]},{ecCodewordsPerBlock:26,ecBlocks:[{numBlocks:1,dataCodewordsPerBlock:44}]},{ecCodewordsPerBlock:18,ecBlocks:[{numBlocks:2,dataCodewordsPerBlock:17}]},{ecCodewordsPerBlock:22,ecBlocks:[{numBlocks:2,dataCodewordsPerBlock:13}]}]},{infoBits:null,versionNumber:4,alignmentPatternCenters:[6,26],errorCorrectionLevels:[{ecCodewordsPerBlock:20,ecBlocks:[{numBlocks:1,
|
||||
dataCodewordsPerBlock:80}]},{ecCodewordsPerBlock:18,ecBlocks:[{numBlocks:2,dataCodewordsPerBlock:32}]},{ecCodewordsPerBlock:26,ecBlocks:[{numBlocks:2,dataCodewordsPerBlock:24}]},{ecCodewordsPerBlock:16,ecBlocks:[{numBlocks:4,dataCodewordsPerBlock:9}]}]},{infoBits:null,versionNumber:5,alignmentPatternCenters:[6,30],errorCorrectionLevels:[{ecCodewordsPerBlock:26,ecBlocks:[{numBlocks:1,dataCodewordsPerBlock:108}]},{ecCodewordsPerBlock:24,ecBlocks:[{numBlocks:2,dataCodewordsPerBlock:43}]},{ecCodewordsPerBlock:18,
|
||||
ecBlocks:[{numBlocks:2,dataCodewordsPerBlock:15},{numBlocks:2,dataCodewordsPerBlock:16}]},{ecCodewordsPerBlock:22,ecBlocks:[{numBlocks:2,dataCodewordsPerBlock:11},{numBlocks:2,dataCodewordsPerBlock:12}]}]},{infoBits:null,versionNumber:6,alignmentPatternCenters:[6,34],errorCorrectionLevels:[{ecCodewordsPerBlock:18,ecBlocks:[{numBlocks:2,dataCodewordsPerBlock:68}]},{ecCodewordsPerBlock:16,ecBlocks:[{numBlocks:4,dataCodewordsPerBlock:27}]},{ecCodewordsPerBlock:24,ecBlocks:[{numBlocks:4,dataCodewordsPerBlock:19}]},
|
||||
{ecCodewordsPerBlock:28,ecBlocks:[{numBlocks:4,dataCodewordsPerBlock:15}]}]},{infoBits:31892,versionNumber:7,alignmentPatternCenters:[6,22,38],errorCorrectionLevels:[{ecCodewordsPerBlock:20,ecBlocks:[{numBlocks:2,dataCodewordsPerBlock:78}]},{ecCodewordsPerBlock:18,ecBlocks:[{numBlocks:4,dataCodewordsPerBlock:31}]},{ecCodewordsPerBlock:18,ecBlocks:[{numBlocks:2,dataCodewordsPerBlock:14},{numBlocks:4,dataCodewordsPerBlock:15}]},{ecCodewordsPerBlock:26,ecBlocks:[{numBlocks:4,dataCodewordsPerBlock:13},
|
||||
{numBlocks:1,dataCodewordsPerBlock:14}]}]},{infoBits:34236,versionNumber:8,alignmentPatternCenters:[6,24,42],errorCorrectionLevels:[{ecCodewordsPerBlock:24,ecBlocks:[{numBlocks:2,dataCodewordsPerBlock:97}]},{ecCodewordsPerBlock:22,ecBlocks:[{numBlocks:2,dataCodewordsPerBlock:38},{numBlocks:2,dataCodewordsPerBlock:39}]},{ecCodewordsPerBlock:22,ecBlocks:[{numBlocks:4,dataCodewordsPerBlock:18},{numBlocks:2,dataCodewordsPerBlock:19}]},{ecCodewordsPerBlock:26,ecBlocks:[{numBlocks:4,dataCodewordsPerBlock:14},
|
||||
{numBlocks:2,dataCodewordsPerBlock:15}]}]},{infoBits:39577,versionNumber:9,alignmentPatternCenters:[6,26,46],errorCorrectionLevels:[{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:2,dataCodewordsPerBlock:116}]},{ecCodewordsPerBlock:22,ecBlocks:[{numBlocks:3,dataCodewordsPerBlock:36},{numBlocks:2,dataCodewordsPerBlock:37}]},{ecCodewordsPerBlock:20,ecBlocks:[{numBlocks:4,dataCodewordsPerBlock:16},{numBlocks:4,dataCodewordsPerBlock:17}]},{ecCodewordsPerBlock:24,ecBlocks:[{numBlocks:4,dataCodewordsPerBlock:12},
|
||||
{numBlocks:4,dataCodewordsPerBlock:13}]}]},{infoBits:42195,versionNumber:10,alignmentPatternCenters:[6,28,50],errorCorrectionLevels:[{ecCodewordsPerBlock:18,ecBlocks:[{numBlocks:2,dataCodewordsPerBlock:68},{numBlocks:2,dataCodewordsPerBlock:69}]},{ecCodewordsPerBlock:26,ecBlocks:[{numBlocks:4,dataCodewordsPerBlock:43},{numBlocks:1,dataCodewordsPerBlock:44}]},{ecCodewordsPerBlock:24,ecBlocks:[{numBlocks:6,dataCodewordsPerBlock:19},{numBlocks:2,dataCodewordsPerBlock:20}]},{ecCodewordsPerBlock:28,ecBlocks:[{numBlocks:6,
|
||||
dataCodewordsPerBlock:15},{numBlocks:2,dataCodewordsPerBlock:16}]}]},{infoBits:48118,versionNumber:11,alignmentPatternCenters:[6,30,54],errorCorrectionLevels:[{ecCodewordsPerBlock:20,ecBlocks:[{numBlocks:4,dataCodewordsPerBlock:81}]},{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:1,dataCodewordsPerBlock:50},{numBlocks:4,dataCodewordsPerBlock:51}]},{ecCodewordsPerBlock:28,ecBlocks:[{numBlocks:4,dataCodewordsPerBlock:22},{numBlocks:4,dataCodewordsPerBlock:23}]},{ecCodewordsPerBlock:24,ecBlocks:[{numBlocks:3,
|
||||
dataCodewordsPerBlock:12},{numBlocks:8,dataCodewordsPerBlock:13}]}]},{infoBits:51042,versionNumber:12,alignmentPatternCenters:[6,32,58],errorCorrectionLevels:[{ecCodewordsPerBlock:24,ecBlocks:[{numBlocks:2,dataCodewordsPerBlock:92},{numBlocks:2,dataCodewordsPerBlock:93}]},{ecCodewordsPerBlock:22,ecBlocks:[{numBlocks:6,dataCodewordsPerBlock:36},{numBlocks:2,dataCodewordsPerBlock:37}]},{ecCodewordsPerBlock:26,ecBlocks:[{numBlocks:4,dataCodewordsPerBlock:20},{numBlocks:6,dataCodewordsPerBlock:21}]},
|
||||
{ecCodewordsPerBlock:28,ecBlocks:[{numBlocks:7,dataCodewordsPerBlock:14},{numBlocks:4,dataCodewordsPerBlock:15}]}]},{infoBits:55367,versionNumber:13,alignmentPatternCenters:[6,34,62],errorCorrectionLevels:[{ecCodewordsPerBlock:26,ecBlocks:[{numBlocks:4,dataCodewordsPerBlock:107}]},{ecCodewordsPerBlock:22,ecBlocks:[{numBlocks:8,dataCodewordsPerBlock:37},{numBlocks:1,dataCodewordsPerBlock:38}]},{ecCodewordsPerBlock:24,ecBlocks:[{numBlocks:8,dataCodewordsPerBlock:20},{numBlocks:4,dataCodewordsPerBlock:21}]},
|
||||
{ecCodewordsPerBlock:22,ecBlocks:[{numBlocks:12,dataCodewordsPerBlock:11},{numBlocks:4,dataCodewordsPerBlock:12}]}]},{infoBits:58893,versionNumber:14,alignmentPatternCenters:[6,26,46,66],errorCorrectionLevels:[{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:3,dataCodewordsPerBlock:115},{numBlocks:1,dataCodewordsPerBlock:116}]},{ecCodewordsPerBlock:24,ecBlocks:[{numBlocks:4,dataCodewordsPerBlock:40},{numBlocks:5,dataCodewordsPerBlock:41}]},{ecCodewordsPerBlock:20,ecBlocks:[{numBlocks:11,dataCodewordsPerBlock:16},
|
||||
{numBlocks:5,dataCodewordsPerBlock:17}]},{ecCodewordsPerBlock:24,ecBlocks:[{numBlocks:11,dataCodewordsPerBlock:12},{numBlocks:5,dataCodewordsPerBlock:13}]}]},{infoBits:63784,versionNumber:15,alignmentPatternCenters:[6,26,48,70],errorCorrectionLevels:[{ecCodewordsPerBlock:22,ecBlocks:[{numBlocks:5,dataCodewordsPerBlock:87},{numBlocks:1,dataCodewordsPerBlock:88}]},{ecCodewordsPerBlock:24,ecBlocks:[{numBlocks:5,dataCodewordsPerBlock:41},{numBlocks:5,dataCodewordsPerBlock:42}]},{ecCodewordsPerBlock:30,
|
||||
ecBlocks:[{numBlocks:5,dataCodewordsPerBlock:24},{numBlocks:7,dataCodewordsPerBlock:25}]},{ecCodewordsPerBlock:24,ecBlocks:[{numBlocks:11,dataCodewordsPerBlock:12},{numBlocks:7,dataCodewordsPerBlock:13}]}]},{infoBits:68472,versionNumber:16,alignmentPatternCenters:[6,26,50,74],errorCorrectionLevels:[{ecCodewordsPerBlock:24,ecBlocks:[{numBlocks:5,dataCodewordsPerBlock:98},{numBlocks:1,dataCodewordsPerBlock:99}]},{ecCodewordsPerBlock:28,ecBlocks:[{numBlocks:7,dataCodewordsPerBlock:45},{numBlocks:3,dataCodewordsPerBlock:46}]},
|
||||
{ecCodewordsPerBlock:24,ecBlocks:[{numBlocks:15,dataCodewordsPerBlock:19},{numBlocks:2,dataCodewordsPerBlock:20}]},{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:3,dataCodewordsPerBlock:15},{numBlocks:13,dataCodewordsPerBlock:16}]}]},{infoBits:70749,versionNumber:17,alignmentPatternCenters:[6,30,54,78],errorCorrectionLevels:[{ecCodewordsPerBlock:28,ecBlocks:[{numBlocks:1,dataCodewordsPerBlock:107},{numBlocks:5,dataCodewordsPerBlock:108}]},{ecCodewordsPerBlock:28,ecBlocks:[{numBlocks:10,dataCodewordsPerBlock:46},
|
||||
{numBlocks:1,dataCodewordsPerBlock:47}]},{ecCodewordsPerBlock:28,ecBlocks:[{numBlocks:1,dataCodewordsPerBlock:22},{numBlocks:15,dataCodewordsPerBlock:23}]},{ecCodewordsPerBlock:28,ecBlocks:[{numBlocks:2,dataCodewordsPerBlock:14},{numBlocks:17,dataCodewordsPerBlock:15}]}]},{infoBits:76311,versionNumber:18,alignmentPatternCenters:[6,30,56,82],errorCorrectionLevels:[{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:5,dataCodewordsPerBlock:120},{numBlocks:1,dataCodewordsPerBlock:121}]},{ecCodewordsPerBlock:26,
|
||||
ecBlocks:[{numBlocks:9,dataCodewordsPerBlock:43},{numBlocks:4,dataCodewordsPerBlock:44}]},{ecCodewordsPerBlock:28,ecBlocks:[{numBlocks:17,dataCodewordsPerBlock:22},{numBlocks:1,dataCodewordsPerBlock:23}]},{ecCodewordsPerBlock:28,ecBlocks:[{numBlocks:2,dataCodewordsPerBlock:14},{numBlocks:19,dataCodewordsPerBlock:15}]}]},{infoBits:79154,versionNumber:19,alignmentPatternCenters:[6,30,58,86],errorCorrectionLevels:[{ecCodewordsPerBlock:28,ecBlocks:[{numBlocks:3,dataCodewordsPerBlock:113},{numBlocks:4,
|
||||
dataCodewordsPerBlock:114}]},{ecCodewordsPerBlock:26,ecBlocks:[{numBlocks:3,dataCodewordsPerBlock:44},{numBlocks:11,dataCodewordsPerBlock:45}]},{ecCodewordsPerBlock:26,ecBlocks:[{numBlocks:17,dataCodewordsPerBlock:21},{numBlocks:4,dataCodewordsPerBlock:22}]},{ecCodewordsPerBlock:26,ecBlocks:[{numBlocks:9,dataCodewordsPerBlock:13},{numBlocks:16,dataCodewordsPerBlock:14}]}]},{infoBits:84390,versionNumber:20,alignmentPatternCenters:[6,34,62,90],errorCorrectionLevels:[{ecCodewordsPerBlock:28,ecBlocks:[{numBlocks:3,
|
||||
dataCodewordsPerBlock:107},{numBlocks:5,dataCodewordsPerBlock:108}]},{ecCodewordsPerBlock:26,ecBlocks:[{numBlocks:3,dataCodewordsPerBlock:41},{numBlocks:13,dataCodewordsPerBlock:42}]},{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:15,dataCodewordsPerBlock:24},{numBlocks:5,dataCodewordsPerBlock:25}]},{ecCodewordsPerBlock:28,ecBlocks:[{numBlocks:15,dataCodewordsPerBlock:15},{numBlocks:10,dataCodewordsPerBlock:16}]}]},{infoBits:87683,versionNumber:21,alignmentPatternCenters:[6,28,50,72,94],errorCorrectionLevels:[{ecCodewordsPerBlock:28,
|
||||
ecBlocks:[{numBlocks:4,dataCodewordsPerBlock:116},{numBlocks:4,dataCodewordsPerBlock:117}]},{ecCodewordsPerBlock:26,ecBlocks:[{numBlocks:17,dataCodewordsPerBlock:42}]},{ecCodewordsPerBlock:28,ecBlocks:[{numBlocks:17,dataCodewordsPerBlock:22},{numBlocks:6,dataCodewordsPerBlock:23}]},{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:19,dataCodewordsPerBlock:16},{numBlocks:6,dataCodewordsPerBlock:17}]}]},{infoBits:92361,versionNumber:22,alignmentPatternCenters:[6,26,50,74,98],errorCorrectionLevels:[{ecCodewordsPerBlock:28,
|
||||
ecBlocks:[{numBlocks:2,dataCodewordsPerBlock:111},{numBlocks:7,dataCodewordsPerBlock:112}]},{ecCodewordsPerBlock:28,ecBlocks:[{numBlocks:17,dataCodewordsPerBlock:46}]},{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:7,dataCodewordsPerBlock:24},{numBlocks:16,dataCodewordsPerBlock:25}]},{ecCodewordsPerBlock:24,ecBlocks:[{numBlocks:34,dataCodewordsPerBlock:13}]}]},{infoBits:96236,versionNumber:23,alignmentPatternCenters:[6,30,54,74,102],errorCorrectionLevels:[{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:4,
|
||||
dataCodewordsPerBlock:121},{numBlocks:5,dataCodewordsPerBlock:122}]},{ecCodewordsPerBlock:28,ecBlocks:[{numBlocks:4,dataCodewordsPerBlock:47},{numBlocks:14,dataCodewordsPerBlock:48}]},{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:11,dataCodewordsPerBlock:24},{numBlocks:14,dataCodewordsPerBlock:25}]},{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:16,dataCodewordsPerBlock:15},{numBlocks:14,dataCodewordsPerBlock:16}]}]},{infoBits:102084,versionNumber:24,alignmentPatternCenters:[6,28,54,80,106],errorCorrectionLevels:[{ecCodewordsPerBlock:30,
|
||||
ecBlocks:[{numBlocks:6,dataCodewordsPerBlock:117},{numBlocks:4,dataCodewordsPerBlock:118}]},{ecCodewordsPerBlock:28,ecBlocks:[{numBlocks:6,dataCodewordsPerBlock:45},{numBlocks:14,dataCodewordsPerBlock:46}]},{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:11,dataCodewordsPerBlock:24},{numBlocks:16,dataCodewordsPerBlock:25}]},{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:30,dataCodewordsPerBlock:16},{numBlocks:2,dataCodewordsPerBlock:17}]}]},{infoBits:102881,versionNumber:25,alignmentPatternCenters:[6,
|
||||
32,58,84,110],errorCorrectionLevels:[{ecCodewordsPerBlock:26,ecBlocks:[{numBlocks:8,dataCodewordsPerBlock:106},{numBlocks:4,dataCodewordsPerBlock:107}]},{ecCodewordsPerBlock:28,ecBlocks:[{numBlocks:8,dataCodewordsPerBlock:47},{numBlocks:13,dataCodewordsPerBlock:48}]},{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:7,dataCodewordsPerBlock:24},{numBlocks:22,dataCodewordsPerBlock:25}]},{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:22,dataCodewordsPerBlock:15},{numBlocks:13,dataCodewordsPerBlock:16}]}]},
|
||||
{infoBits:110507,versionNumber:26,alignmentPatternCenters:[6,30,58,86,114],errorCorrectionLevels:[{ecCodewordsPerBlock:28,ecBlocks:[{numBlocks:10,dataCodewordsPerBlock:114},{numBlocks:2,dataCodewordsPerBlock:115}]},{ecCodewordsPerBlock:28,ecBlocks:[{numBlocks:19,dataCodewordsPerBlock:46},{numBlocks:4,dataCodewordsPerBlock:47}]},{ecCodewordsPerBlock:28,ecBlocks:[{numBlocks:28,dataCodewordsPerBlock:22},{numBlocks:6,dataCodewordsPerBlock:23}]},{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:33,dataCodewordsPerBlock:16},
|
||||
{numBlocks:4,dataCodewordsPerBlock:17}]}]},{infoBits:110734,versionNumber:27,alignmentPatternCenters:[6,34,62,90,118],errorCorrectionLevels:[{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:8,dataCodewordsPerBlock:122},{numBlocks:4,dataCodewordsPerBlock:123}]},{ecCodewordsPerBlock:28,ecBlocks:[{numBlocks:22,dataCodewordsPerBlock:45},{numBlocks:3,dataCodewordsPerBlock:46}]},{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:8,dataCodewordsPerBlock:23},{numBlocks:26,dataCodewordsPerBlock:24}]},{ecCodewordsPerBlock:30,
|
||||
ecBlocks:[{numBlocks:12,dataCodewordsPerBlock:15},{numBlocks:28,dataCodewordsPerBlock:16}]}]},{infoBits:117786,versionNumber:28,alignmentPatternCenters:[6,26,50,74,98,122],errorCorrectionLevels:[{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:3,dataCodewordsPerBlock:117},{numBlocks:10,dataCodewordsPerBlock:118}]},{ecCodewordsPerBlock:28,ecBlocks:[{numBlocks:3,dataCodewordsPerBlock:45},{numBlocks:23,dataCodewordsPerBlock:46}]},{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:4,dataCodewordsPerBlock:24},{numBlocks:31,
|
||||
dataCodewordsPerBlock:25}]},{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:11,dataCodewordsPerBlock:15},{numBlocks:31,dataCodewordsPerBlock:16}]}]},{infoBits:119615,versionNumber:29,alignmentPatternCenters:[6,30,54,78,102,126],errorCorrectionLevels:[{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:7,dataCodewordsPerBlock:116},{numBlocks:7,dataCodewordsPerBlock:117}]},{ecCodewordsPerBlock:28,ecBlocks:[{numBlocks:21,dataCodewordsPerBlock:45},{numBlocks:7,dataCodewordsPerBlock:46}]},{ecCodewordsPerBlock:30,
|
||||
ecBlocks:[{numBlocks:1,dataCodewordsPerBlock:23},{numBlocks:37,dataCodewordsPerBlock:24}]},{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:19,dataCodewordsPerBlock:15},{numBlocks:26,dataCodewordsPerBlock:16}]}]},{infoBits:126325,versionNumber:30,alignmentPatternCenters:[6,26,52,78,104,130],errorCorrectionLevels:[{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:5,dataCodewordsPerBlock:115},{numBlocks:10,dataCodewordsPerBlock:116}]},{ecCodewordsPerBlock:28,ecBlocks:[{numBlocks:19,dataCodewordsPerBlock:47},
|
||||
{numBlocks:10,dataCodewordsPerBlock:48}]},{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:15,dataCodewordsPerBlock:24},{numBlocks:25,dataCodewordsPerBlock:25}]},{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:23,dataCodewordsPerBlock:15},{numBlocks:25,dataCodewordsPerBlock:16}]}]},{infoBits:127568,versionNumber:31,alignmentPatternCenters:[6,30,56,82,108,134],errorCorrectionLevels:[{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:13,dataCodewordsPerBlock:115},{numBlocks:3,dataCodewordsPerBlock:116}]},{ecCodewordsPerBlock:28,
|
||||
ecBlocks:[{numBlocks:2,dataCodewordsPerBlock:46},{numBlocks:29,dataCodewordsPerBlock:47}]},{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:42,dataCodewordsPerBlock:24},{numBlocks:1,dataCodewordsPerBlock:25}]},{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:23,dataCodewordsPerBlock:15},{numBlocks:28,dataCodewordsPerBlock:16}]}]},{infoBits:133589,versionNumber:32,alignmentPatternCenters:[6,34,60,86,112,138],errorCorrectionLevels:[{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:17,dataCodewordsPerBlock:115}]},
|
||||
{ecCodewordsPerBlock:28,ecBlocks:[{numBlocks:10,dataCodewordsPerBlock:46},{numBlocks:23,dataCodewordsPerBlock:47}]},{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:10,dataCodewordsPerBlock:24},{numBlocks:35,dataCodewordsPerBlock:25}]},{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:19,dataCodewordsPerBlock:15},{numBlocks:35,dataCodewordsPerBlock:16}]}]},{infoBits:136944,versionNumber:33,alignmentPatternCenters:[6,30,58,86,114,142],errorCorrectionLevels:[{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:17,dataCodewordsPerBlock:115},
|
||||
{numBlocks:1,dataCodewordsPerBlock:116}]},{ecCodewordsPerBlock:28,ecBlocks:[{numBlocks:14,dataCodewordsPerBlock:46},{numBlocks:21,dataCodewordsPerBlock:47}]},{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:29,dataCodewordsPerBlock:24},{numBlocks:19,dataCodewordsPerBlock:25}]},{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:11,dataCodewordsPerBlock:15},{numBlocks:46,dataCodewordsPerBlock:16}]}]},{infoBits:141498,versionNumber:34,alignmentPatternCenters:[6,34,62,90,118,146],errorCorrectionLevels:[{ecCodewordsPerBlock:30,
|
||||
ecBlocks:[{numBlocks:13,dataCodewordsPerBlock:115},{numBlocks:6,dataCodewordsPerBlock:116}]},{ecCodewordsPerBlock:28,ecBlocks:[{numBlocks:14,dataCodewordsPerBlock:46},{numBlocks:23,dataCodewordsPerBlock:47}]},{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:44,dataCodewordsPerBlock:24},{numBlocks:7,dataCodewordsPerBlock:25}]},{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:59,dataCodewordsPerBlock:16},{numBlocks:1,dataCodewordsPerBlock:17}]}]},{infoBits:145311,versionNumber:35,alignmentPatternCenters:[6,
|
||||
30,54,78,102,126,150],errorCorrectionLevels:[{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:12,dataCodewordsPerBlock:121},{numBlocks:7,dataCodewordsPerBlock:122}]},{ecCodewordsPerBlock:28,ecBlocks:[{numBlocks:12,dataCodewordsPerBlock:47},{numBlocks:26,dataCodewordsPerBlock:48}]},{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:39,dataCodewordsPerBlock:24},{numBlocks:14,dataCodewordsPerBlock:25}]},{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:22,dataCodewordsPerBlock:15},{numBlocks:41,dataCodewordsPerBlock:16}]}]},
|
||||
{infoBits:150283,versionNumber:36,alignmentPatternCenters:[6,24,50,76,102,128,154],errorCorrectionLevels:[{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:6,dataCodewordsPerBlock:121},{numBlocks:14,dataCodewordsPerBlock:122}]},{ecCodewordsPerBlock:28,ecBlocks:[{numBlocks:6,dataCodewordsPerBlock:47},{numBlocks:34,dataCodewordsPerBlock:48}]},{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:46,dataCodewordsPerBlock:24},{numBlocks:10,dataCodewordsPerBlock:25}]},{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:2,
|
||||
dataCodewordsPerBlock:15},{numBlocks:64,dataCodewordsPerBlock:16}]}]},{infoBits:152622,versionNumber:37,alignmentPatternCenters:[6,28,54,80,106,132,158],errorCorrectionLevels:[{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:17,dataCodewordsPerBlock:122},{numBlocks:4,dataCodewordsPerBlock:123}]},{ecCodewordsPerBlock:28,ecBlocks:[{numBlocks:29,dataCodewordsPerBlock:46},{numBlocks:14,dataCodewordsPerBlock:47}]},{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:49,dataCodewordsPerBlock:24},{numBlocks:10,dataCodewordsPerBlock:25}]},
|
||||
{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:24,dataCodewordsPerBlock:15},{numBlocks:46,dataCodewordsPerBlock:16}]}]},{infoBits:158308,versionNumber:38,alignmentPatternCenters:[6,32,58,84,110,136,162],errorCorrectionLevels:[{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:4,dataCodewordsPerBlock:122},{numBlocks:18,dataCodewordsPerBlock:123}]},{ecCodewordsPerBlock:28,ecBlocks:[{numBlocks:13,dataCodewordsPerBlock:46},{numBlocks:32,dataCodewordsPerBlock:47}]},{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:48,
|
||||
dataCodewordsPerBlock:24},{numBlocks:14,dataCodewordsPerBlock:25}]},{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:42,dataCodewordsPerBlock:15},{numBlocks:32,dataCodewordsPerBlock:16}]}]},{infoBits:161089,versionNumber:39,alignmentPatternCenters:[6,26,54,82,110,138,166],errorCorrectionLevels:[{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:20,dataCodewordsPerBlock:117},{numBlocks:4,dataCodewordsPerBlock:118}]},{ecCodewordsPerBlock:28,ecBlocks:[{numBlocks:40,dataCodewordsPerBlock:47},{numBlocks:7,dataCodewordsPerBlock:48}]},
|
||||
{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:43,dataCodewordsPerBlock:24},{numBlocks:22,dataCodewordsPerBlock:25}]},{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:10,dataCodewordsPerBlock:15},{numBlocks:67,dataCodewordsPerBlock:16}]}]},{infoBits:167017,versionNumber:40,alignmentPatternCenters:[6,30,58,86,114,142,170],errorCorrectionLevels:[{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:19,dataCodewordsPerBlock:118},{numBlocks:6,dataCodewordsPerBlock:119}]},{ecCodewordsPerBlock:28,ecBlocks:[{numBlocks:18,
|
||||
dataCodewordsPerBlock:47},{numBlocks:31,dataCodewordsPerBlock:48}]},{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:34,dataCodewordsPerBlock:24},{numBlocks:34,dataCodewordsPerBlock:25}]},{ecCodewordsPerBlock:30,ecBlocks:[{numBlocks:20,dataCodewordsPerBlock:15},{numBlocks:61,dataCodewordsPerBlock:16}]}]}],da=[{bits:21522,formatInfo:{errorCorrectionLevel:1,dataMask:0}},{bits:20773,formatInfo:{errorCorrectionLevel:1,dataMask:1}},{bits:24188,formatInfo:{errorCorrectionLevel:1,dataMask:2}},{bits:23371,formatInfo:{errorCorrectionLevel:1,
|
||||
dataMask:3}},{bits:17913,formatInfo:{errorCorrectionLevel:1,dataMask:4}},{bits:16590,formatInfo:{errorCorrectionLevel:1,dataMask:5}},{bits:20375,formatInfo:{errorCorrectionLevel:1,dataMask:6}},{bits:19104,formatInfo:{errorCorrectionLevel:1,dataMask:7}},{bits:30660,formatInfo:{errorCorrectionLevel:0,dataMask:0}},{bits:29427,formatInfo:{errorCorrectionLevel:0,dataMask:1}},{bits:32170,formatInfo:{errorCorrectionLevel:0,dataMask:2}},{bits:30877,formatInfo:{errorCorrectionLevel:0,dataMask:3}},{bits:26159,
|
||||
formatInfo:{errorCorrectionLevel:0,dataMask:4}},{bits:25368,formatInfo:{errorCorrectionLevel:0,dataMask:5}},{bits:27713,formatInfo:{errorCorrectionLevel:0,dataMask:6}},{bits:26998,formatInfo:{errorCorrectionLevel:0,dataMask:7}},{bits:5769,formatInfo:{errorCorrectionLevel:3,dataMask:0}},{bits:5054,formatInfo:{errorCorrectionLevel:3,dataMask:1}},{bits:7399,formatInfo:{errorCorrectionLevel:3,dataMask:2}},{bits:6608,formatInfo:{errorCorrectionLevel:3,dataMask:3}},{bits:1890,formatInfo:{errorCorrectionLevel:3,
|
||||
dataMask:4}},{bits:597,formatInfo:{errorCorrectionLevel:3,dataMask:5}},{bits:3340,formatInfo:{errorCorrectionLevel:3,dataMask:6}},{bits:2107,formatInfo:{errorCorrectionLevel:3,dataMask:7}},{bits:13663,formatInfo:{errorCorrectionLevel:2,dataMask:0}},{bits:12392,formatInfo:{errorCorrectionLevel:2,dataMask:1}},{bits:16177,formatInfo:{errorCorrectionLevel:2,dataMask:2}},{bits:14854,formatInfo:{errorCorrectionLevel:2,dataMask:3}},{bits:9396,formatInfo:{errorCorrectionLevel:2,dataMask:4}},{bits:8579,formatInfo:{errorCorrectionLevel:2,
|
||||
dataMask:5}},{bits:11994,formatInfo:{errorCorrectionLevel:2,dataMask:6}},{bits:11245,formatInfo:{errorCorrectionLevel:2,dataMask:7}}],aa=[a=>0===(a.y+a.x)%2,a=>0===a.y%2,a=>0===a.x%3,a=>0===(a.y+a.x)%3,a=>0===(Math.floor(a.y/2)+Math.floor(a.x/3))%2,a=>0===a.x*a.y%2+a.x*a.y%3,a=>0===(a.y*a.x%2+a.y*a.x%3)%2,a=>0===((a.y+a.x)%2+a.y*a.x%3)%2],y=(a,b)=>Math.sqrt(Math.pow(b.x-a.x,2)+Math.pow(b.y-a.y,2)),la={inversionAttempts:"attemptBoth",greyScaleWeights:{red:.2126,green:.7152,blue:.0722,useIntegerApproximation:!1},
|
||||
canOverwriteImage:!0};I.default=I;let G="dontInvert",D={red:77,green:150,blue:29,useIntegerApproximation:!0};self.onmessage=a=>{let b=a.data.data;switch(a.data.type){case "decode":a=I(b.data,b.width,b.height,{inversionAttempts:G,greyScaleWeights:D});self.postMessage({type:"qrResult",data:a?a.data:null});break;case "grayscaleWeights":D.red=b.red;D.green=b.green;D.blue=b.blue;D.useIntegerApproximation=b.useIntegerApproximation;break;case "inversionMode":switch(b){case "original":G="dontInvert";break;
|
||||
case "invert":G="onlyInvert";break;case "both":G="attemptBoth";break;default:throw Error("Invalid inversion mode");}break;case "close":self.close()}}})()
|
||||
//# sourceMappingURL=qr-scanner-worker.min.js.map
|
@ -1,5 +1,5 @@
|
||||
// Custom Theming for Angular Material
|
||||
@use '~@angular/material' as mat;
|
||||
@use '~@angular/material'as mat;
|
||||
// For more information: https://material.angular.io/guide/theming
|
||||
// Plus imports for other components in your app.
|
||||
|
||||
@ -83,7 +83,8 @@ body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol" !important;
|
||||
}
|
||||
|
||||
app-root, app-main {
|
||||
app-root,
|
||||
app-main {
|
||||
height: 100%;
|
||||
max-height: 100%;
|
||||
display: flex;
|
||||
@ -327,3 +328,45 @@ table {
|
||||
top: -40px;
|
||||
right: 15px;
|
||||
}
|
||||
|
||||
mat-card.success {
|
||||
padding: 0;
|
||||
|
||||
mat-card-header {
|
||||
padding: 16px;
|
||||
padding-bottom: 16px;
|
||||
padding-bottom: 0;
|
||||
background-color: #43A047 !important;
|
||||
}
|
||||
|
||||
mat-card-content {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
mat-card-actions {
|
||||
padding: 16px !important;
|
||||
padding-top: 16px;
|
||||
padding-top: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.mat-card-dialog {
|
||||
.mat-dialog-container {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
.mat-dialog-content {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
.mat-card {
|
||||
margin: 0;
|
||||
|
||||
.mat-card-actions {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user