Renders label layout
This commit is contained in:
parent
b75126779a
commit
0d4ed8f6d9
|
@ -3,7 +3,7 @@
|
|||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/e2e",
|
||||
"module": "commonjs",
|
||||
"target": "es5",
|
||||
"target": "es2018",
|
||||
"types": [
|
||||
"jasmine",
|
||||
"jasminewd2",
|
||||
|
|
File diff suppressed because it is too large
Load Diff
49
package.json
49
package.json
|
@ -22,48 +22,49 @@
|
|||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "~9.1.11",
|
||||
"@angular/cdk": "^9.2.4",
|
||||
"@angular/common": "~9.1.11",
|
||||
"@angular/compiler": "~9.1.11",
|
||||
"@angular/core": "~9.1.11",
|
||||
"@angular/animations": "~11.0.0-next.2",
|
||||
"@angular/cdk": "^10.2.2",
|
||||
"@angular/common": "~11.0.0-next.2",
|
||||
"@angular/compiler": "~11.0.0-next.2",
|
||||
"@angular/core": "~10.1.2",
|
||||
"@angular/flex-layout": "^9.0.0-beta.31",
|
||||
"@angular/forms": "~9.1.11",
|
||||
"@angular/material": "^9.2.4",
|
||||
"@angular/platform-browser": "~9.1.11",
|
||||
"@angular/platform-browser-dynamic": "~9.1.11",
|
||||
"@angular/router": "~9.1.11",
|
||||
"@angular/forms": "~11.0.0-next.2",
|
||||
"@angular/material": "^10.2.2",
|
||||
"@angular/platform-browser": "~11.0.0-next.2",
|
||||
"@angular/platform-browser-dynamic": "~11.0.0-next.2",
|
||||
"@angular/router": "~11.0.0-next.2",
|
||||
"@ngx-formly/core": "^5.8.0",
|
||||
"@ngx-formly/material": "^5.8.0",
|
||||
"lodash.isequal": "^4.5.0",
|
||||
"ngx-qrcode-svg": "^2.0.0",
|
||||
"rfdc": "^1.1.4",
|
||||
"rxjs": "~6.5.4",
|
||||
"tslib": "^1.13.0",
|
||||
"rxjs": "~6.6.3",
|
||||
"tslib": "^2.0.0",
|
||||
"zone.js": "~0.10.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "^0.901.10",
|
||||
"@angular/cli": "^9.1.10",
|
||||
"@angular/compiler-cli": "~9.1.11",
|
||||
"@angular/language-service": "~9.1.11",
|
||||
"@angular-devkit/build-angular": "^0.1001.2",
|
||||
"@angular/cli": "^10.1.2",
|
||||
"@angular/compiler-cli": "~11.0.0-next.2",
|
||||
"@angular/language-service": "~11.0.0-next.2",
|
||||
"@types/jasmine": "^3.5.11",
|
||||
"@types/jasminewd2": "~2.0.3",
|
||||
"@types/node": "^12.12.47",
|
||||
"codelyzer": "^5.1.2",
|
||||
"jasmine-core": "~3.5.0",
|
||||
"jasmine-spec-reporter": "~4.2.1",
|
||||
"karma": "^5.1.0",
|
||||
"jasmine-spec-reporter": "~5.0.0",
|
||||
"karma": "~5.0.0",
|
||||
"karma-chrome-launcher": "~3.1.0",
|
||||
"karma-coverage-istanbul-reporter": "~2.1.1",
|
||||
"karma-jasmine": "~3.1.1",
|
||||
"karma-jasmine-html-reporter": "^1.5.4",
|
||||
"karma-coverage-istanbul-reporter": "~3.0.2",
|
||||
"karma-jasmine": "~4.0.0",
|
||||
"karma-jasmine-html-reporter": "^1.5.0",
|
||||
"lodash.get": "^4.4.2",
|
||||
"lodash.set": "^4.3.2",
|
||||
"protractor": "^7.0.0",
|
||||
"protractor": "~7.0.0",
|
||||
"protractor-http-client": "^1.0.4",
|
||||
"sonar-scanner": "^3.1.0",
|
||||
"ts-node": "~8.6.2",
|
||||
"tslint": "~6.0.0",
|
||||
"typescript": "~3.7.5"
|
||||
"tslint": "~6.1.0",
|
||||
"typescript": "~4.0.3"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
import {NgModule} from '@angular/core';
|
||||
import {RouterModule, Routes} from '@angular/router';
|
||||
import {ThisEnvironment} from '../environments/environment.injectable';
|
||||
import {CountComponent} from './count/count.component';
|
||||
import {HomeComponent} from './home/home.component';
|
||||
import {PrintComponent} from './print/print.component';
|
||||
import {SampleComponent} from './sample/sample.component';
|
||||
import {SettingsComponent} from './settings/settings.component';
|
||||
|
||||
export const routes: Routes = [
|
||||
{
|
||||
|
@ -9,6 +13,26 @@ export const routes: Routes = [
|
|||
pathMatch: 'full',
|
||||
component: HomeComponent
|
||||
},
|
||||
{
|
||||
path: 'sample',
|
||||
pathMatch: 'full',
|
||||
component: SampleComponent
|
||||
},
|
||||
{
|
||||
path: 'print',
|
||||
pathMatch: 'full',
|
||||
component: PrintComponent
|
||||
},
|
||||
{
|
||||
path: 'count',
|
||||
pathMatch: 'full',
|
||||
component: CountComponent
|
||||
},
|
||||
{
|
||||
path: 'settings',
|
||||
pathMatch: 'full',
|
||||
component: SettingsComponent
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<div class="mat-typography">
|
||||
<app-navbar></app-navbar>
|
||||
<app-navbar [testingLocation]="testingLocation"></app-navbar>
|
||||
<router-outlet *ngIf="!loading; else loadingMessage"></router-outlet>
|
||||
<app-footer></app-footer>
|
||||
</div>
|
||||
|
|
|
@ -3,6 +3,7 @@ import {MatIconRegistry} from '@angular/material/icon';
|
|||
import {DomSanitizer, Title} from '@angular/platform-browser';
|
||||
import {Router} from '@angular/router';
|
||||
import {AppEnvironment} from './interfaces/appEnvironment.interface';
|
||||
import {TestingLocation} from './interfaces/testingLocation.interface';
|
||||
import {GoogleAnalyticsService} from './services/google-analytics.service';
|
||||
|
||||
@Component({
|
||||
|
@ -12,6 +13,10 @@ import {GoogleAnalyticsService} from './services/google-analytics.service';
|
|||
})
|
||||
export class AppComponent {
|
||||
loading: boolean;
|
||||
testingLocation: TestingLocation = {
|
||||
id: '0000',
|
||||
name: 'Click here to set location',
|
||||
};
|
||||
|
||||
constructor(
|
||||
@Inject('APP_ENVIRONMENT') private environment: AppEnvironment,
|
||||
|
|
|
@ -4,20 +4,28 @@ import {NgModule} from '@angular/core';
|
|||
import {FlexLayoutModule} from '@angular/flex-layout';
|
||||
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
|
||||
import {MatButtonModule} from '@angular/material/button';
|
||||
import {MAT_FORM_FIELD_DEFAULT_OPTIONS} from '@angular/material/form-field';
|
||||
import {MatCardModule} from '@angular/material/card';
|
||||
import {MAT_FORM_FIELD_DEFAULT_OPTIONS, MatFormFieldModule} from '@angular/material/form-field';
|
||||
import {MatIconModule} from '@angular/material/icon';
|
||||
import {MatInputModule} from '@angular/material/input';
|
||||
import {MatProgressSpinnerModule} from '@angular/material/progress-spinner';
|
||||
import {MatToolbarModule} from '@angular/material/toolbar';
|
||||
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
||||
import {FormlyModule} from '@ngx-formly/core';
|
||||
import {QRCodeSVGModule} from 'ngx-qrcode-svg';
|
||||
import {ThisEnvironment} from '../environments/environment.injectable';
|
||||
import {AppRoutingModule} from './app-routing.module';
|
||||
import {AppComponent} from './app.component';
|
||||
import {CountComponent} from './count/count.component';
|
||||
import {FooterComponent} from './footer/footer.component';
|
||||
import {HomeComponent} from './home/home.component';
|
||||
import {LoadingComponent} from './loading/loading.component';
|
||||
import {NavbarComponent} from './navbar/navbar.component';
|
||||
import {PrintComponent} from './print/print.component';
|
||||
import {SampleComponent} from './sample/sample.component';
|
||||
import {ApiService} from './services/api.service';
|
||||
import {SettingsComponent} from './settings/settings.component';
|
||||
import { LabelLayoutComponent } from './label-layout/label-layout.component';
|
||||
|
||||
/**
|
||||
* This function is used internal to get a string instance of the `<base href="" />` value from `index.html`.
|
||||
|
@ -41,6 +49,11 @@ export function getBaseHref(platformLocation: PlatformLocation): string {
|
|||
FooterComponent,
|
||||
NavbarComponent,
|
||||
HomeComponent,
|
||||
SampleComponent,
|
||||
CountComponent,
|
||||
SettingsComponent,
|
||||
PrintComponent,
|
||||
LabelLayoutComponent,
|
||||
],
|
||||
imports: [
|
||||
BrowserAnimationsModule,
|
||||
|
@ -50,11 +63,14 @@ export function getBaseHref(platformLocation: PlatformLocation): string {
|
|||
HttpClientModule,
|
||||
MatProgressSpinnerModule,
|
||||
ReactiveFormsModule,
|
||||
AppRoutingModule,
|
||||
MatCardModule,
|
||||
MatInputModule,
|
||||
MatToolbarModule,
|
||||
MatButtonModule,
|
||||
MatIconModule,
|
||||
// <-- This line MUST be last (https://angular.io/guide/router#module-import-order-matters)
|
||||
MatFormFieldModule,
|
||||
QRCodeSVGModule,
|
||||
AppRoutingModule, // <-- This line MUST be last (https://angular.io/guide/router#module-import-order-matters)
|
||||
],
|
||||
providers: [
|
||||
{provide: MAT_FORM_FIELD_DEFAULT_OPTIONS, useValue: {appearance: 'outline'}},
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
import {AppDefaults} from '../interfaces/appDefaults.interface';
|
||||
import {LabelLayout, LabelLayoutType} from '../interfaces/labelLayout';
|
||||
|
||||
// Default form field and data values
|
||||
export const defaults: AppDefaults = {
|
||||
countsCollection: 'counts', // Name of collection for Line Counts in Firebase.
|
||||
samplesCollection: 'samples', // Name of collection for Line Counts in Firebase.
|
||||
dateEncodedFormat: 'yyyyMMddHHmm', // Format for dates when encoded in IDs for database records.
|
||||
dateDisplayFormat: 'MM/dd/yyyy, hh:mm aa', // Format for dates when displayed to user.
|
||||
numCopies: 3, // Default number of copies of labels to print. Can be overridden by user setting.
|
||||
labelLayout: 'round_32mm_1up' as LabelLayoutType, // Which label layout to use for printing. Can be overridden by user setting.
|
||||
locationId: '0000', // Default location ID. Can be overridden by user setting.
|
||||
lineCountRegex: /^[\d]{4}-[\d]{12}$/, // ID format for Line Count records.
|
||||
qrCodeRegex: /^[\d]{9}-[a-zA-Z]+-[\d]{12}-[\d]{4}$/, // ID format for QR Code records.
|
||||
barCodeNumLength: 9, // Number of digits in Bar Code.
|
||||
barCodeRegex: /^[\d]{14}$|^[\d]{9}$/, // Pattern for Bar Code data. Scanned barcodes will be either 9 or 14 digits long.
|
||||
// Manually-entered ID numbers will be exactly 9 digits long.
|
||||
initialsLength: 5,
|
||||
initialsRegex: /^[a-zA-Z]{2,5}$/,
|
||||
};
|
||||
|
||||
export const labelLayouts = {
|
||||
round_32mm_1up: new LabelLayout({
|
||||
numCols: 1,
|
||||
columnGap: 0,
|
||||
}),
|
||||
round_32mm_2up: new LabelLayout({
|
||||
numCols: 2,
|
||||
columnGap: 1.3,
|
||||
}),
|
||||
};
|
|
@ -0,0 +1 @@
|
|||
<p>count works!</p>
|
|
@ -0,0 +1,25 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { CountComponent } from './count.component';
|
||||
|
||||
describe('CountComponent', () => {
|
||||
let component: CountComponent;
|
||||
let fixture: ComponentFixture<CountComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ CountComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(CountComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,15 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-count',
|
||||
templateUrl: './count.component.html',
|
||||
styleUrls: ['./count.component.scss']
|
||||
})
|
||||
export class CountComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
<p>footer works!</p>
|
|
@ -1 +1,19 @@
|
|||
<p>home works!</p>
|
||||
<div
|
||||
class="full-height bg-primary"
|
||||
fxLayout="column"
|
||||
fxLayoutAlign="center center"
|
||||
fxLayoutGap="40px"
|
||||
>
|
||||
<button
|
||||
mat-flat-button
|
||||
color="accent"
|
||||
class="btn-xl"
|
||||
routerLink="/sample"
|
||||
autofocus
|
||||
>New sample</button>
|
||||
<button
|
||||
mat-flat-button
|
||||
class="btn-xl"
|
||||
routerLink="/count"
|
||||
>Line count</button>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
import {LabelLayoutType} from './labelLayout';
|
||||
|
||||
export interface AppDefaults {
|
||||
countsCollection: string;
|
||||
samplesCollection: string;
|
||||
dateEncodedFormat: string;
|
||||
dateDisplayFormat: string;
|
||||
numCopies: number;
|
||||
labelLayout: LabelLayoutType;
|
||||
locationId: string;
|
||||
lineCountRegex: RegExp;
|
||||
qrCodeRegex: RegExp;
|
||||
barCodeRegex: RegExp;
|
||||
barCodeNumLength: number;
|
||||
initialsRegex: RegExp;
|
||||
initialsLength: number;
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
export declare type LabelLayoutType = 'round_32mm_1up' | 'round_32mm_2up';
|
||||
|
||||
export interface LayoutOptions {
|
||||
units?: string;
|
||||
pointsPerUnit?: number;
|
||||
labelSize?: number;
|
||||
marginSize?: number;
|
||||
numCols?: number;
|
||||
columnGap?: number;
|
||||
sideTextWidth?: number;
|
||||
sideTextTop?: number;
|
||||
sideTextMargin?: number;
|
||||
topTextMargin?: number;
|
||||
bottomTextMargin?: number;
|
||||
fontSizePt?: number;
|
||||
numCopies?: number;
|
||||
}
|
||||
|
||||
export class LabelLayout {
|
||||
units = 'mm';
|
||||
pointsPerUnit = 0.3528;
|
||||
labelSize = 28.6;
|
||||
marginSize = 1.7;
|
||||
numCols = 2;
|
||||
columnGap = 4;
|
||||
sideTextWidth = 4;
|
||||
sideTextTop = 11;
|
||||
sideTextMargin = 1.5;
|
||||
topTextMargin = 3;
|
||||
bottomTextMargin = 2.5;
|
||||
fontSizePt = 6;
|
||||
numCopies = 1;
|
||||
|
||||
constructor(private options: LayoutOptions) {
|
||||
this.units = options.units || this.units;
|
||||
this.pointsPerUnit = options.pointsPerUnit || this.pointsPerUnit;
|
||||
this.marginSize = options.marginSize || this.marginSize;
|
||||
this.labelSize = options.labelSize || this.labelSize;
|
||||
this.numCols = options.numCols || this.numCols;
|
||||
this.columnGap = options.columnGap || this.columnGap;
|
||||
this.sideTextWidth = options.sideTextWidth || this.sideTextWidth;
|
||||
this.sideTextTop = options.sideTextTop || this.sideTextTop;
|
||||
this.sideTextMargin = options.sideTextMargin || this.sideTextMargin;
|
||||
this.topTextMargin = options.topTextMargin || this.topTextMargin;
|
||||
this.bottomTextMargin = options.bottomTextMargin || this.bottomTextMargin;
|
||||
this.fontSizePt = options.fontSizePt || this.fontSizePt;
|
||||
}
|
||||
|
||||
get dimensions() {
|
||||
return {
|
||||
columnGap: this._toUnits(this.columnGap),
|
||||
sideTextWidth: this._toUnits(this.sideTextWidth),
|
||||
sideTextTop: this._toUnits(this.sideTextTop),
|
||||
sideTextMargin: this._toUnits(this.sideTextMargin),
|
||||
topTextMargin: this._toUnits(this.topTextMargin),
|
||||
bottomTextMargin: this._toUnits(this.bottomTextMargin),
|
||||
columnGapWidth: this._toUnits(this.columnGapWidth),
|
||||
marginWidth: this._toUnits(this.marginSize),
|
||||
labelSize: this._toUnits(this.labelSize),
|
||||
labelSizeWithMargins: this._toUnits(this.labelSizeWithMargins),
|
||||
pageWidth: this._toUnits(this.pageWidth),
|
||||
pageHeight: this._toUnits(this.pageHeight),
|
||||
fontSize: this._toUnits(this.fontSize),
|
||||
};
|
||||
}
|
||||
|
||||
get columnGapWidth(): number {
|
||||
return this.columnGap;
|
||||
}
|
||||
|
||||
get labelSizeWithMargins(): number {
|
||||
return (this.labelSize + (this.marginSize * 2));
|
||||
}
|
||||
|
||||
get pageWidth(): number {
|
||||
return (this.labelSizeWithMargins * this.numCols) + (this.columnGap * this.numCols - 1);
|
||||
}
|
||||
|
||||
get pageHeight(): number {
|
||||
return (this.labelSizeWithMargins * this.numCopies);
|
||||
}
|
||||
|
||||
get fontSize(): number {
|
||||
return this.fontSizePt * this.pointsPerUnit;
|
||||
}
|
||||
|
||||
private _toUnits(num: number) {
|
||||
return `${num}${this.units}`;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
export interface TestingLocation {
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
<div class="label-layout">
|
||||
<div class="date">{{dateCreated | date:'yyyyMMdd'}}</div>
|
||||
<div class="time">
|
||||
T<br />
|
||||
{{dateCreated | date:'HH'}}<br />
|
||||
{{dateCreated | date:'mm'}}
|
||||
</div>
|
||||
<qrcode-svg
|
||||
[value]="qrCodeValue"
|
||||
errorCorrectionLevel="H"
|
||||
></qrcode-svg>
|
||||
<div class="location">
|
||||
L<br />
|
||||
{{locationId.slice(0, 2)}}<br />
|
||||
{{locationId.slice(2, 4)}}
|
||||
</div>
|
||||
<div class="barcode">#{{barCode}}</div>
|
||||
</div>
|
|
@ -0,0 +1,51 @@
|
|||
.date,
|
||||
.time,
|
||||
.location,
|
||||
.barcode {
|
||||
position: absolute;
|
||||
font-family: monospace;
|
||||
font-weight: bolder;
|
||||
text-align: center;
|
||||
font-size: 6pt;
|
||||
}
|
||||
|
||||
.label-layout {
|
||||
position: relative;
|
||||
width: 24.6mm;
|
||||
height: 24.6mm;
|
||||
border: 2mm solid white;
|
||||
border-radius: 100%;
|
||||
background-color: white;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
.date {
|
||||
top: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.barcode {
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.time {
|
||||
top: calc(50% - 3mm);
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.location {
|
||||
top: calc(50% - 3mm);
|
||||
right: 0;
|
||||
}
|
||||
|
||||
qrcode-svg {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
margin-left: -11mm;
|
||||
margin-top: -11mm;
|
||||
width: 22mm;
|
||||
height: 22mm;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { LabelLayoutComponent } from './label-layout.component';
|
||||
|
||||
describe('LabelLayoutComponent', () => {
|
||||
let component: LabelLayoutComponent;
|
||||
let fixture: ComponentFixture<LabelLayoutComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ LabelLayoutComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(LabelLayoutComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,32 @@
|
|||
import {formatDate} from '@angular/common';
|
||||
import {Component, Input, OnInit} from '@angular/core';
|
||||
import {defaults} from '../config/defaults';
|
||||
|
||||
@Component({
|
||||
selector: 'app-label-layout',
|
||||
templateUrl: './label-layout.component.html',
|
||||
styleUrls: ['./label-layout.component.scss']
|
||||
})
|
||||
export class LabelLayoutComponent implements OnInit {
|
||||
@Input() dateCreated: Date;
|
||||
@Input() barCode: string;
|
||||
@Input() initials: string;
|
||||
locationId = defaults.locationId;
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
get qrCodeValue(): string {
|
||||
const valArray = [
|
||||
this.barCode,
|
||||
this.initials,
|
||||
formatDate(this.dateCreated, 'yyyyMMddHHmm', 'en-us'),
|
||||
defaults.locationId,
|
||||
];
|
||||
return valArray.join('-');
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,8 @@
|
|||
<mat-toolbar color="primary">
|
||||
<mat-toolbar-row>
|
||||
<button mat-button routerLink="/" class="logo">BeSAFE</button>
|
||||
<button mat-button routerLink="/settings">{{testingLocation.name}}</button>
|
||||
<span fxFlex></span>
|
||||
<button mat-icon-button routerLink="/"><mat-icon>home</mat-icon></button>
|
||||
<button mat-icon-button routerLink="/settings"><mat-icon>settings</mat-icon></button>
|
||||
</mat-toolbar-row>
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
.logo {
|
||||
font-weight: bolder;
|
||||
font-size: 2rem;
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import {Component, Input, OnInit} from '@angular/core';
|
||||
import {TestingLocation} from '../interfaces/testingLocation.interface';
|
||||
|
||||
@Component({
|
||||
selector: 'app-navbar',
|
||||
|
@ -6,6 +7,7 @@ import { Component, OnInit } from '@angular/core';
|
|||
styleUrls: ['./navbar.component.scss']
|
||||
})
|
||||
export class NavbarComponent implements OnInit {
|
||||
@Input() testingLocation: TestingLocation;
|
||||
|
||||
constructor() { }
|
||||
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
<div
|
||||
id="screen"
|
||||
class="full-height bg-primary"
|
||||
fxLayout="row"
|
||||
fxLayoutAlign="center center"
|
||||
fxLayoutGap="40px"
|
||||
>
|
||||
<mat-card fxFlex="50%">
|
||||
<mat-card-header>
|
||||
<h1>Print Labels</h1>
|
||||
</mat-card-header>
|
||||
|
||||
<mat-card-content fxLayout="column" fxLayoutAlign="center center">
|
||||
<app-label-layout
|
||||
[barCode]="barCode"
|
||||
[initials]="initials"
|
||||
[dateCreated]="dateCreated"
|
||||
></app-label-layout>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
|
||||
|
||||
<div
|
||||
id="print"
|
||||
[style]="{width: pageWidth, height: pageHeight}"
|
||||
[gdRows]="pagesToGridFractions"
|
||||
gdGap="1.5mm"
|
||||
gdAlignColumns="center"
|
||||
gdAlignRows="center"
|
||||
>
|
||||
<div
|
||||
*ngFor="let page of pages"
|
||||
[gdColumns]="colsToGridFractions"
|
||||
gdAlignColumns="center"
|
||||
gdAlignRows="center"
|
||||
gdGap="3mm"
|
||||
>
|
||||
<app-label-layout
|
||||
*ngFor="let col of columns"
|
||||
[barCode]="barCode"
|
||||
[initials]="initials"
|
||||
[dateCreated]="dateCreated"
|
||||
></app-label-layout>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,53 @@
|
|||
@media screen {
|
||||
#print { display: none !important; }
|
||||
#screen { display: flex !important; }
|
||||
}
|
||||
|
||||
@media print {
|
||||
@page {
|
||||
size: 64mm 32mm;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
::ng-deep html,
|
||||
::ng-deep body {
|
||||
width: 64mm;
|
||||
height: 32mm;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
::ng-deep .no-print,
|
||||
::ng-deep mat-card,
|
||||
::ng-deep app-navbar,
|
||||
::ng-deep app-footer {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#print {
|
||||
display: grid !important;
|
||||
background-color: transparent;
|
||||
width: 64mm;
|
||||
height: 32mm;
|
||||
padding-top: 2mm;
|
||||
padding-bottom: 2mm;
|
||||
|
||||
.page {
|
||||
padding-top: 2mm;
|
||||
padding-bottom: 2mm;
|
||||
}
|
||||
|
||||
.column {
|
||||
padding: 1mm;
|
||||
}
|
||||
}
|
||||
#screen { display: none !important; }
|
||||
}
|
||||
|
||||
.mat-card-content {
|
||||
background-color: #6C799C;
|
||||
height: 500px;
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { PrintComponent } from './print.component';
|
||||
|
||||
describe('PrintComponent', () => {
|
||||
let component: PrintComponent;
|
||||
let fixture: ComponentFixture<PrintComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ PrintComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(PrintComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,52 @@
|
|||
import {Component, OnInit} from '@angular/core';
|
||||
import {ActivatedRoute} from '@angular/router';
|
||||
import {defaults} from '../config/defaults';
|
||||
|
||||
@Component({
|
||||
selector: 'app-print',
|
||||
templateUrl: './print.component.html',
|
||||
styleUrls: ['./print.component.scss']
|
||||
})
|
||||
export class PrintComponent implements OnInit {
|
||||
barCode: string;
|
||||
initials: string;
|
||||
dateCreated: Date;
|
||||
|
||||
get pagesToGridFractions(): string {
|
||||
const what = this.pages.map(() => '1fr').join(' ');
|
||||
console.log('what', what);
|
||||
return what;
|
||||
}
|
||||
|
||||
get colsToGridFractions(): string {
|
||||
return this.columns.map(() => '1fr').join(' ');
|
||||
}
|
||||
|
||||
get pageHeight(): string {
|
||||
return `${this.pages.length * 32}mm`;
|
||||
}
|
||||
|
||||
get pageWidth(): string {
|
||||
return `${this.columns.length * 32}mm`;
|
||||
}
|
||||
|
||||
constructor(private route: ActivatedRoute) {
|
||||
this.dateCreated = new Date();
|
||||
this.route.queryParamMap.subscribe(queryParamMap => {
|
||||
this.barCode = queryParamMap.get('barCode');
|
||||
this.initials = queryParamMap.get('initials');
|
||||
});
|
||||
}
|
||||
|
||||
get pages() {
|
||||
return Array(defaults.numCopies).fill('');
|
||||
}
|
||||
|
||||
get columns() {
|
||||
return Array(defaults.labelLayout === 'round_32mm_2up' ? 2 : 1).fill('');
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
<div
|
||||
class="full-height bg-primary"
|
||||
fxLayout="row"
|
||||
fxLayoutAlign="center center"
|
||||
fxLayoutGap="40px"
|
||||
>
|
||||
<mat-card fxFlex="50%">
|
||||
<mat-card-header>
|
||||
<h1>Scan Barcode</h1>
|
||||
</mat-card-header>
|
||||
|
||||
<mat-card-content fxLayout="row wrap" fxLayoutAlign="center center">
|
||||
<mat-form-field class="barcode-input" fxFlex="95%">
|
||||
<mat-label>Barcode ID #</mat-label>
|
||||
<input
|
||||
#barCodeInput="matInput"
|
||||
matInput
|
||||
type="text"
|
||||
[formControl]="barCodeFormControl"
|
||||
>
|
||||
<button
|
||||
mat-button
|
||||
*ngIf="barCodeValue"
|
||||
matSuffix
|
||||
mat-icon-button
|
||||
aria-label="Clear"
|
||||
(click)="barCodeFormControl.patchValue('')"
|
||||
>
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
<mat-error *ngIf="barCodeFormControl.hasError('required')">This field is required.</mat-error>
|
||||
<mat-error *ngIf="barCodeFormControl.hasError('pattern')">Please enter exactly 9 or 14 digits.</mat-error>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="initials-input" fxFlex="95%">
|
||||
<mat-label>Initials</mat-label>
|
||||
<input
|
||||
#initialsInput="matInput"
|
||||
matInput
|
||||
type="text"
|
||||
[formControl]="initialsFormControl"
|
||||
>
|
||||
<button
|
||||
mat-button
|
||||
*ngIf="initialsValue"
|
||||
matSuffix
|
||||
mat-icon-button
|
||||
aria-label="Clear"
|
||||
(click)="initialsFormControl.patchValue('')"
|
||||
>
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
<mat-error *ngIf="initialsFormControl.hasError('required')">This field is required.</mat-error>
|
||||
<mat-error *ngIf="initialsFormControl.hasError('pattern')">Please enter only letters.</mat-error>
|
||||
</mat-form-field>
|
||||
</mat-card-content>
|
||||
<mat-card-actions>
|
||||
<button
|
||||
mat-flat-button
|
||||
class="btn-xl"
|
||||
color="accent"
|
||||
fxFlex="50%"
|
||||
[disabled]="!hasInfo"
|
||||
routerLink="/print"
|
||||
[queryParams]="queryParams"
|
||||
>Next</button>
|
||||
<button mat-flat-button class="btn-xl" fxFlex="50%" routerLink="/">Cancel</button>
|
||||
</mat-card-actions>
|
||||
</mat-card>
|
||||
|
||||
</div>
|
|
@ -0,0 +1,2 @@
|
|||
.barcode-input {
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { SampleComponent } from './sample.component';
|
||||
|
||||
describe('SampleComponent', () => {
|
||||
let component: SampleComponent;
|
||||
let fixture: ComponentFixture<SampleComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ SampleComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(SampleComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,84 @@
|
|||
import {AfterViewInit, ChangeDetectorRef, Component, OnInit, ViewChild} from '@angular/core';
|
||||
import {FormControl, Validators} from '@angular/forms';
|
||||
import {MatInput} from '@angular/material/input';
|
||||
import {Params} from '@angular/router';
|
||||
import {defaults} from '../config/defaults';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-sample',
|
||||
templateUrl: './sample.component.html',
|
||||
styleUrls: ['./sample.component.scss']
|
||||
})
|
||||
export class SampleComponent implements AfterViewInit {
|
||||
barCodeErrorMessage = '';
|
||||
initialsErrorMessage = '';
|
||||
barCodeFormControl = new FormControl('', [
|
||||
Validators.required,
|
||||
Validators.pattern(defaults.barCodeRegex),
|
||||
]);
|
||||
initialsFormControl = new FormControl('', [
|
||||
Validators.required,
|
||||
Validators.pattern(defaults.initialsRegex),
|
||||
]);
|
||||
@ViewChild('barCodeInput') barCodeInput: MatInput;
|
||||
@ViewChild('initialsInput') initialsInput: MatInput;
|
||||
|
||||
get queryParams(): Params {
|
||||
return {
|
||||
barCode: this.barCodeValue,
|
||||
initials: this.initialsValue,
|
||||
};
|
||||
}
|
||||
|
||||
constructor(private changeDetector: ChangeDetectorRef) {
|
||||
this.barCodeFormControl.registerOnChange(() => {
|
||||
this.checkBarCodeValue();
|
||||
});
|
||||
this.initialsFormControl.registerOnChange(() => this.checkInitialsValue());
|
||||
}
|
||||
|
||||
get barCodeValue(): string {
|
||||
return this.barCodeFormControl.value;
|
||||
}
|
||||
|
||||
get initialsValue(): string {
|
||||
return this.initialsFormControl.value;
|
||||
}
|
||||
|
||||
get hasBarCode(): boolean {
|
||||
return defaults.barCodeRegex.test(this.barCodeValue);
|
||||
}
|
||||
|
||||
get hasInitials(): boolean {
|
||||
return defaults.initialsRegex.test(this.initialsValue);
|
||||
}
|
||||
|
||||
get hasInfo(): boolean {
|
||||
return this.hasBarCode && this.hasInitials;
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.barCodeInput.focus();
|
||||
this.changeDetector.detectChanges();
|
||||
}
|
||||
|
||||
checkBarCodeValue() {
|
||||
console.log('--- checkBarCodeValue ---');
|
||||
if (this.hasBarCode) {
|
||||
this.barCodeErrorMessage = '';
|
||||
this.initialsInput.focus();
|
||||
this.changeDetector.detectChanges();
|
||||
} else {
|
||||
this.barCodeErrorMessage = 'Wrong barcode.';
|
||||
}
|
||||
}
|
||||
|
||||
checkInitialsValue() {
|
||||
if (this.hasInitials) {
|
||||
this.initialsErrorMessage = '';
|
||||
} else {
|
||||
this.initialsErrorMessage = 'Wrong barcode.';
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
<p>settings works!</p>
|
|
@ -0,0 +1,25 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { SettingsComponent } from './settings.component';
|
||||
|
||||
describe('SettingsComponent', () => {
|
||||
let component: SettingsComponent;
|
||||
let fixture: ComponentFixture<SettingsComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ SettingsComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(SettingsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,15 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-settings',
|
||||
templateUrl: './settings.component.html',
|
||||
styleUrls: ['./settings.component.scss']
|
||||
})
|
||||
export class SettingsComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
}
|
|
@ -16,6 +16,14 @@
|
|||
padding-top: $header-height;
|
||||
}
|
||||
|
||||
app-navbar {
|
||||
@include mat-elevation(4);
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.mat-display-4 {
|
||||
color: $brand-primary;
|
||||
border-bottom: 1px solid $brand-gray-light;
|
||||
|
@ -120,6 +128,10 @@
|
|||
}
|
||||
|
||||
button {
|
||||
&:focus {
|
||||
outline: 4px solid white;
|
||||
}
|
||||
|
||||
&.btn-xl {
|
||||
font-size: 24px;
|
||||
padding-left: 24px;
|
||||
|
@ -195,6 +207,9 @@
|
|||
}
|
||||
}
|
||||
|
||||
.bg-primary { background-color: $brand-primary; }
|
||||
.bg-accent { background-color: $brand-accent; }
|
||||
|
||||
.pad-0 {
|
||||
padding: 0px;
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
"declaration": false,
|
||||
"downlevelIteration": true,
|
||||
"experimentalDecorators": true,
|
||||
"module": "esnext",
|
||||
"module": "es2020",
|
||||
"moduleResolution": "node",
|
||||
"importHelpers": true,
|
||||
"target": "es2015",
|
||||
|
|
66
tslint.json
66
tslint.json
|
@ -1,13 +1,21 @@
|
|||
{
|
||||
"extends": "tslint:recommended",
|
||||
"rules": {
|
||||
"align": {
|
||||
"options": [
|
||||
"parameters",
|
||||
"statements"
|
||||
]
|
||||
},
|
||||
"array-type": false,
|
||||
"arrow-parens": false,
|
||||
"arrow-return-shorthand": true,
|
||||
"deprecation": {
|
||||
"severity": "warning"
|
||||
},
|
||||
"component-class-suffix": true,
|
||||
"contextual-lifecycle": true,
|
||||
"curly": true,
|
||||
"directive-class-suffix": true,
|
||||
"directive-selector": [
|
||||
true,
|
||||
|
@ -21,10 +29,17 @@
|
|||
"app",
|
||||
"kebab-case"
|
||||
],
|
||||
"eofline": true,
|
||||
"import-blacklist": [
|
||||
true,
|
||||
"rxjs/Rx"
|
||||
],
|
||||
"import-spacing": true,
|
||||
"indent": {
|
||||
"options": [
|
||||
"spaces"
|
||||
]
|
||||
},
|
||||
"interface-name": false,
|
||||
"max-classes-per-file": false,
|
||||
"max-line-length": [
|
||||
|
@ -79,11 +94,60 @@
|
|||
"no-output-native": true,
|
||||
"no-output-on-prefix": true,
|
||||
"no-output-rename": true,
|
||||
"semicolon": {
|
||||
"options": [
|
||||
"always"
|
||||
]
|
||||
},
|
||||
"space-before-function-paren": {
|
||||
"options": {
|
||||
"anonymous": "never",
|
||||
"asyncArrow": "always",
|
||||
"constructor": "never",
|
||||
"method": "never",
|
||||
"named": "never"
|
||||
}
|
||||
},
|
||||
"no-outputs-metadata-property": true,
|
||||
"template-banana-in-box": true,
|
||||
"template-no-negated-async": true,
|
||||
"typedef-whitespace": {
|
||||
"options": [
|
||||
{
|
||||
"call-signature": "nospace",
|
||||
"index-signature": "nospace",
|
||||
"parameter": "nospace",
|
||||
"property-declaration": "nospace",
|
||||
"variable-declaration": "nospace"
|
||||
},
|
||||
{
|
||||
"call-signature": "onespace",
|
||||
"index-signature": "onespace",
|
||||
"parameter": "onespace",
|
||||
"property-declaration": "onespace",
|
||||
"variable-declaration": "onespace"
|
||||
}
|
||||
]
|
||||
},
|
||||
"use-lifecycle-interface": true,
|
||||
"use-pipe-transform-interface": true
|
||||
"use-pipe-transform-interface": true,
|
||||
"variable-name": {
|
||||
"options": [
|
||||
"ban-keywords",
|
||||
"check-format",
|
||||
"allow-pascal-case"
|
||||
]
|
||||
},
|
||||
"whitespace": {
|
||||
"options": [
|
||||
"check-branch",
|
||||
"check-decl",
|
||||
"check-operator",
|
||||
"check-separator",
|
||||
"check-type",
|
||||
"check-typecast"
|
||||
]
|
||||
}
|
||||
},
|
||||
"rulesDirectory": [
|
||||
"codelyzer"
|
||||
|
|
Loading…
Reference in New Issue