diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 471b557..d61aeda 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -95,4 +95,4 @@ jobs: action: 'upload' app_location: '/' # App source code path api_location: '' # Api source code path - optional - output_location: 'dist/' # Built app content directory - adjust to match your app’s dist folder + output_location: './dist' # Built app content directory - adjust to match your app’s dist folder diff --git a/src/app/components/auth/auth.interceptor.ts b/src/app/components/auth/auth.interceptor.ts index 03b46c3..77b8c87 100644 --- a/src/app/components/auth/auth.interceptor.ts +++ b/src/app/components/auth/auth.interceptor.ts @@ -16,8 +16,9 @@ export class AuthInterceptor implements HttpInterceptor { next: HttpHandler ): Observable> { // Retrieve the token from local storage - const authdata = JSON.parse(localStorage.getItem('authData') || '{}'); - const token = authdata?.token; + const authDataStr = localStorage.getItem('authData'); + const authdata = authDataStr ? JSON.parse(authDataStr) : {}; + const token = authdata?.accessToken; if (token) { // Clone the request to add the new header diff --git a/src/app/components/auth/auth.service.ts b/src/app/components/auth/auth.service.ts index 2a1a62f..13855c0 100644 --- a/src/app/components/auth/auth.service.ts +++ b/src/app/components/auth/auth.service.ts @@ -25,8 +25,7 @@ export class AuthService { return this.http.post(registerUrl, form).pipe( tap((response: AuthResponse) => { // Store authentication data in local storage - const authData = JSON.stringify(response); - localStorage.setItem('authData', authData); + localStorage.setItem('authData', JSON.stringify(response)); this.userRoleSubject.next(response.user.role); // Update user role this.isAuthenticated.next(true); this.router.navigate(['/dashboard']); diff --git a/src/app/pages/inventory/components/inventory-items-table/inventory-items-table.component.html b/src/app/pages/inventory/components/inventory-items-table/inventory-items-table.component.html index 7bf0246..656fcb8 100644 --- a/src/app/pages/inventory/components/inventory-items-table/inventory-items-table.component.html +++ b/src/app/pages/inventory/components/inventory-items-table/inventory-items-table.component.html @@ -1,13 +1,3 @@ - -
-

View Inventory

-
- - - -
-
-
diff --git a/src/app/pages/inventory/components/inventory-items-table/inventory-items-table.component.ts b/src/app/pages/inventory/components/inventory-items-table/inventory-items-table.component.ts index 97b5ac8..3c6b1bb 100644 --- a/src/app/pages/inventory/components/inventory-items-table/inventory-items-table.component.ts +++ b/src/app/pages/inventory/components/inventory-items-table/inventory-items-table.component.ts @@ -23,7 +23,7 @@ export class InventoryItemsTableComponent implements OnInit, AfterViewInit { // Sample Table Data rawMaterials = [ { - picture: 'assets/ascorbicAcid.png', + picture: 'assets/default-product.png', materialId: 'RM001', name: 'Ascorbic Acid (Vitamin C)', supplier: 'HealthPro Labs', @@ -46,7 +46,7 @@ export class InventoryItemsTableComponent implements OnInit, AfterViewInit { priceLastUpdated: new Date('2024-01-25'), }, { - picture: 'assets/manganeseSulfate.png', + picture: 'assets/default-product.png', materialId: 'RM002', name: 'Manganese Sulfate (Manganese)', supplier: 'Mineral Essentials Co.', @@ -69,7 +69,7 @@ export class InventoryItemsTableComponent implements OnInit, AfterViewInit { priceLastUpdated: new Date('2024-01-05'), }, { - picture: 'assets/riboflavin.png', + picture: 'assets/default-product.png', materialId: 'RM003', name: 'Riboflavin (Vitamin B2)', supplier: 'VitalSource Pharma', @@ -92,7 +92,7 @@ export class InventoryItemsTableComponent implements OnInit, AfterViewInit { priceLastUpdated: new Date('2024-02-01'), }, { - picture: 'assets/calciferol.png', + picture: 'assets/default-product.png', materialId: 'RM004', name: 'Ergocalciferol (Vitamin D2)', supplier: 'Sunshine Extracts', @@ -117,7 +117,7 @@ export class InventoryItemsTableComponent implements OnInit, AfterViewInit { ]; components = [ { - picture: 'assets/bottleCap.png', + picture: 'assets/default-product.png', componentId: 'CMP001', name: 'Plastic Bottle Cap', supplier: 'CapIt Industries', @@ -138,7 +138,7 @@ export class InventoryItemsTableComponent implements OnInit, AfterViewInit { status: 'In Stock', }, { - picture: 'assets/labels.png', + picture: 'assets/default-product.png', componentId: 'CMP002', name: 'Pill Bottle Labels', supplier: 'LabelPro Supplies', @@ -159,7 +159,7 @@ export class InventoryItemsTableComponent implements OnInit, AfterViewInit { status: 'Backordered', }, { - picture: 'assets/silicaGel.png', + picture: 'assets/default-product.png', componentId: 'CMP003', name: 'Silica Gel Packets', supplier: 'DryGuard Corp', @@ -180,7 +180,7 @@ export class InventoryItemsTableComponent implements OnInit, AfterViewInit { status: 'In Stock', }, { - picture: 'assets/cottonBalls.png', + picture: 'assets/default-product.png', componentId: 'CMP004', name: 'Cotton Balls', supplier: 'PureSoft Materials', @@ -201,7 +201,7 @@ export class InventoryItemsTableComponent implements OnInit, AfterViewInit { status: 'In Stock', }, { - picture: 'assets/bottles.png', + picture: 'assets/default-product.png', componentId: 'CMP005', name: 'Plastic Pill Bottles', supplier: 'PharmaContainer Ltd.', @@ -225,7 +225,7 @@ export class InventoryItemsTableComponent implements OnInit, AfterViewInit { wips = [ { - picture: 'assets/probioticCapsules.png', // Path to image + picture: 'assets/default-product.png', // Path to image wipId: 'WIP001', productName: 'Probiotic Capsules', sku: 'PROB-CAP-001', @@ -246,7 +246,7 @@ export class InventoryItemsTableComponent implements OnInit, AfterViewInit { status: 'In Progress', }, { - picture: 'assets/vitaminDPowder.png', // Path to image + picture: 'assets/default-product.png', // Path to image wipId: 'WIP002', productName: 'Vitamin D Powder', sku: 'VITD-PWD-001', @@ -267,7 +267,7 @@ export class InventoryItemsTableComponent implements OnInit, AfterViewInit { status: 'Delayed', }, { - picture: 'assets/fishOilLiquid.png', // Path to image + picture: 'assets/default-product.png', // Path to image wipId: 'WIP003', productName: 'Omega-3 Fish Oil', sku: 'FISH-OIL-001', @@ -290,7 +290,7 @@ export class InventoryItemsTableComponent implements OnInit, AfterViewInit { ]; finishedGoods = [ { - picture: 'assets/probioticCapsules.png', // Path to image + picture: 'assets/default-product.png', // Path to image productName: 'Probiotic Capsules', sku: 'PROB-CAP-001', batchIds: 'BATCHC123, BATCHC124', @@ -309,7 +309,7 @@ export class InventoryItemsTableComponent implements OnInit, AfterViewInit { status: 'In Stock', }, { - picture: 'assets/vitaminDPowder.png', // Path to image + picture: 'assets/default-product.png', // Path to image productName: 'Vitamin D Powder', sku: 'VITD-PWD-001', batchIds: 'BATCHD456', @@ -328,7 +328,7 @@ export class InventoryItemsTableComponent implements OnInit, AfterViewInit { status: 'Backordered', }, { - picture: 'assets/fishOilLiquid.png', // Path to image + picture: 'assets/default-product.png', // Path to image productName: 'Omega-3 Fish Oil', sku: 'FISH-OIL-001', batchIds: 'BATCHF789', diff --git a/src/app/pages/inventory/components/new-inventory-dialog/new-inventory-dialog.component.html b/src/app/pages/inventory/components/new-inventory-dialog/new-inventory-dialog.component.html index e9fcb16..d1a87a8 100644 --- a/src/app/pages/inventory/components/new-inventory-dialog/new-inventory-dialog.component.html +++ b/src/app/pages/inventory/components/new-inventory-dialog/new-inventory-dialog.component.html @@ -3,258 +3,321 @@

- -
- Vendor Name is required. -
- Vendor Name - - Vendor - - - - {{ vendor.displayName }} - - - + +
+

Basic Information

- -
- Display Name is required. + + Vendor * + + -- Select Vendor -- + + {{ vendor.displayName }} + + + +
-
- - Display Name - - + Vendor is required. +
- -
- SKU is required. + + Display Name * + + +
-
- - SKU - - + Display Name is required. +
- -
- Description is required. + + SKU * + + +
-
- - Description - - + SKU is required. +
- -
- Inventory Category is required. + + Description * + + +
+ Description is required. +
- - Inventory Category - - Manufacturing - Customer Supplied - Research Lab - Ancillary - - - -
- Type is required. -
- - Type - - Raw Materials - Components - Work in Progress - Finished Goods - - + +
+

Classification

- -
- Lot Code is required. -
- - Lot Code - - +
+ + + Category * + + Manufacturing + Customer Supplied + Research Lab + Ancillary + + - -
- Unit of Measurement is required. + + + Type * + + Raw Materials + Components + Work in Progress + Finished Goods + + +
+
+
+
+ Category is required. +
+
+
+
+ Type is required. +
+
+
- - Unit of Measurement - - kg - g - mg - lb - oz - - - -
- Price Per Unit is required. + +
+

Unit & Lot Details

+ +
+ + + Lot Code * + + + + + + Unit of Measurement * + + kg + g + mg + lb + oz + + +
+
+
+
+ Lot Code is required. +
+
+
+
+ Unit of Measurement is required. +
+
+
- - Price Per Unit - - - -
- - In Stock - - + +
+

Pricing

+ - Minimum Restock Quantity - + Price Per Unit * + + USD -
- - -
- Available Quantity is required. + Price Per Unit is required. +
- - Available Quantity - - -
- On Hold Quantity is required. -
- - On Hold Quantity - - + +
+

Inventory Quantities

-
- Quarantined Quantity is required. +
+ + + In Stock * + + + + + + Minimum Restock * + + +
+ +
+ + + Available Quantity * + + + + + + On Hold Quantity * + + +
+ +
+ + + Quarantined Quantity * + + +
- - Quarantined Quantity - - diff --git a/src/app/pages/inventory/components/new-inventory-dialog/new-inventory-dialog.component.scss b/src/app/pages/inventory/components/new-inventory-dialog/new-inventory-dialog.component.scss index 0af6f06..b188e64 100644 --- a/src/app/pages/inventory/components/new-inventory-dialog/new-inventory-dialog.component.scss +++ b/src/app/pages/inventory/components/new-inventory-dialog/new-inventory-dialog.component.scss @@ -1,12 +1,18 @@ mat-dialog-content { - padding: 20px; + padding: 0; + max-height: 70vh; + overflow-y: auto; display: flex; flex-direction: column; + background-color: #ffffff; + color: #1a1a1a; form { display: flex; flex-direction: column; - gap: 16px; + gap: 0; + padding: 24px; + color: #1a1a1a; .full-width { width: 100%; @@ -14,61 +20,295 @@ mat-dialog-content { mat-form-field { width: 100%; + margin-bottom: 12px; .mat-form-field-infix { - padding: 8px 12px; + padding: 10px 12px; } } mat-label { font-weight: 500; + color: #1a1a1a; + } + + input, + textarea, + select { + color: #1a1a1a; } } +} - table { - width: 100%; - border-collapse: collapse; - margin-top: 16px; +// Form Sections +.form-section { + margin-bottom: 28px; + padding-bottom: 20px; + border-bottom: 2px solid #e0e0e0; - th, - td { - padding: 8px; - text-align: left; - border-bottom: 1px solid #ddd; + &:last-child { + border-bottom: none; + margin-bottom: 0; + padding-bottom: 0; + } + + .section-title { + font-size: 13px; + font-weight: 700; + color: #1a1a1a; + margin: 0 0 16px 0; + text-transform: uppercase; + letter-spacing: 0.5px; + display: flex; + align-items: center; + gap: 10px; + + &::before { + content: ''; + width: 4px; + height: 18px; + background: linear-gradient(180deg, #0d47a1 0%, #1565c0 100%); + border-radius: 2px; + flex-shrink: 0; } + } +} - th { - background-color: #f2f2f2; +// Form Row for Two-Column Layout +.form-row { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 16px; + margin-bottom: 8px; + + @media (max-width: 600px) { + grid-template-columns: 1fr; + } + + mat-form-field { + width: 100%; + margin-bottom: 0; + } + + &.error-row { + gap: 16px; + margin-top: -4px; + + > div { + flex: 1; } } } +// Required indicator +.required { + color: #d32f2f; + font-weight: bold; + margin-left: 2px; +} + +// Error Message Styling .error-message { font-size: 0.8em; - margin-bottom: 5px; + color: #c62828; + margin-top: 4px; + margin-bottom: 8px; + font-weight: 600; + display: flex; + align-items: center; + gap: 6px; + + span { + &::before { + content: '⚠ '; + font-size: 1.1em; + font-weight: bold; + } + } } +// Enhanced field styling for invalid state +::ng-deep { + // Override Material Design theme variables for outline + .mat-mdc-form-field { + --mdc-theme-primary: #1976d2; + --mat-mdc-form-field-bottom-line-color: #9e9e9e; + } + + // Default state - make outline visible grey + .mat-form-field .mdc-notched-outline__leading, + .mat-form-field .mdc-notched-outline__notch, + .mat-form-field .mdc-notched-outline__trailing { + border-color: #9e9e9e !important; + border-top-color: #9e9e9e !important; + } + + .mat-form-field { + .mat-form-field-label { + color: #424242; + } + + .mat-input-element { + color: #1a1a1a; + caret-color: #1976d2; + } + + // Ensure selected value is visible when dropdown is closed + .mat-select-value { + color: #1a1a1a !important; + opacity: 1 !important; + display: flex !important; + align-items: center; + } + + .mat-select-value-text { + color: #1a1a1a !important; + } + + .mat-mdc-select-min-line { + color: #1a1a1a !important; + } + + .mat-select-trigger { + color: #1a1a1a; + } + } + + // Make mat-select options visible - white background + .mat-mdc-option { + background-color: #ffffff !important; + color: #1a1a1a !important; + + &.mat-selected { + background-color: #ffffff !important; + color: #000000 !important; + font-weight: 500; + } + + &:hover { + background-color: #f5f5f5 !important; + } + } + + // Focused state - blue outline + .mat-form-field.mat-focused .mdc-notched-outline__leading, + .mat-form-field.mat-focused .mdc-notched-outline__notch, + .mat-form-field.mat-focused .mdc-notched-outline__trailing { + border-color: #1976d2 !important; + border-top-color: #1976d2 !important; + } + + .mat-form-field.mat-focused { + .mat-form-field-label { + color: #1976d2 !important; + } + } + + // Invalid state - red outline + .mat-form-field.mat-form-field-invalid .mdc-notched-outline__leading, + .mat-form-field.mat-form-field-invalid .mdc-notched-outline__notch, + .mat-form-field.mat-form-field-invalid .mdc-notched-outline__trailing { + border-color: #c62828 !important; + border-top-color: #c62828 !important; + } + + .mat-form-field.mat-form-field-invalid { + .mat-form-field-label { + color: #c62828 !important; + } + + .mat-input-element { + color: #1a1a1a; + } + } + + // Invalid and focused - keep red + .mat-form-field.mat-focused.mat-form-field-invalid + .mdc-notched-outline__leading, + .mat-form-field.mat-focused.mat-form-field-invalid + .mdc-notched-outline__notch, + .mat-form-field.mat-focused.mat-form-field-invalid + .mdc-notched-outline__trailing { + border-color: #c62828 !important; + border-top-color: #c62828 !important; + } + + .mat-form-field.mat-focused.mat-form-field-invalid { + .mat-form-field-label { + color: #c62828 !important; + } + } +} + +// Hint styling +::ng-deep .mat-form-field-hint { + font-size: 0.75rem; + color: rgba(0, 0, 0, 0.6); + margin-top: 4px; +} + +// Textarea styling +::ng-deep textarea.mat-input-element { + font-family: 'Roboto', sans-serif; + resize: vertical; + min-height: 80px; +} + +// Dialog actions styling mat-dialog-actions { - padding: 16px; + padding: 16px 20px; + border-top: 2px solid #e0e0e0; + margin: 24px 0 0 0; + background-color: #fafafa; display: flex; justify-content: flex-end; gap: 8px; + flex-wrap: wrap; + overflow: visible; + width: 100%; + box-sizing: border-box; button { - min-width: 120px; - } + margin-left: 0; + min-width: 90px; + padding: 8px 16px; + font-weight: 500; + text-transform: uppercase; + font-size: 12px; + letter-spacing: 0.5px; + flex-shrink: 0; - button:first-of-type { - background: transparent; - color: #333; - } + &:first-of-type { + background: transparent; + color: #1a1a1a; + border: 2px solid #bdbdbd; + font-weight: 600; - button:last-of-type { - background-color: #3f51b5; - color: #fff; + &:hover { + background-color: #eeeeee; + border-color: #9e9e9e; + } - &:hover { - background-color: #303f9f; + &:active { + background-color: #e0e0e0; + } + } + + &[color='primary'] { + background: linear-gradient(135deg, #1976d2 0%, #1565c0 100%); + color: white; + box-shadow: 0 2px 4px rgba(25, 118, 210, 0.3); + border: none; + + &:hover { + box-shadow: 0 4px 8px rgba(25, 118, 210, 0.4); + transform: translateY(-1px); + } + + &:disabled { + opacity: 0.5; + box-shadow: none; + } } } } diff --git a/src/app/pages/inventory/components/new-inventory-dialog/new-inventory-dialog.component.ts b/src/app/pages/inventory/components/new-inventory-dialog/new-inventory-dialog.component.ts index 8cb93c4..d418135 100644 --- a/src/app/pages/inventory/components/new-inventory-dialog/new-inventory-dialog.component.ts +++ b/src/app/pages/inventory/components/new-inventory-dialog/new-inventory-dialog.component.ts @@ -16,6 +16,45 @@ export class NewInventoryDialogComponent implements OnInit { isSubmitting: boolean = false; filteredVendors: Vendor[] = []; + // Mock vendors for development + mockVendors: Vendor[] = [ + { + _id: 'vendor-001', + displayName: 'Acme Supplies Inc.', + email: 'contact@acmesupplies.com', + phone: '+1-800-123-4567', + address: '123 Industrial Ave, New York, NY', + } as Vendor, + { + _id: 'vendor-002', + displayName: 'Global Materials LLC', + email: 'sales@globalmaterials.com', + phone: '+1-888-555-0123', + address: '456 Commerce St, Los Angeles, CA', + } as Vendor, + { + _id: 'vendor-003', + displayName: 'Premium Components Co.', + email: 'info@premiumcomponents.com', + phone: '+1-866-777-0456', + address: '789 Tech Boulevard, Austin, TX', + } as Vendor, + { + _id: 'vendor-004', + displayName: 'Quality Imports Ltd.', + email: 'ordering@qualityimports.com', + phone: '+1-855-888-0789', + address: '321 Import Blvd, Chicago, IL', + } as Vendor, + { + _id: 'vendor-005', + displayName: 'Direct Wholesale Corp.', + email: 'wholesale@directwholesale.com', + phone: '+1-844-999-0234', + address: '654 Wholesale Pkwy, Houston, TX', + } as Vendor, + ]; + constructor( private dialogRef: MatDialogRef, private fb: FormBuilder, @@ -46,6 +85,18 @@ export class NewInventoryDialogComponent implements OnInit { } ngOnInit() { + // Try to load vendors from service, fall back to mock data + this.vendorService.getVendors().subscribe( + (vendors) => { + this.filteredVendors = + vendors && vendors.length > 0 ? vendors : this.mockVendors; + }, + (error) => { + console.warn('Error loading vendors, using mock data:', error); + this.filteredVendors = this.mockVendors; + } + ); + // If the data has an inventory item, populate the form for editing if (this.data.inventoryItem) { console.log('inventory data: ' + this.data.inventoryItem); @@ -54,41 +105,6 @@ export class NewInventoryDialogComponent implements OnInit { console.log('No Data'); } - // Subscribe to the vendor input value changes - console.log('Value Change'); - this.inventoryForm - .get('vendor') - ?.valueChanges.pipe( - debounceTime(300), - switchMap((searchTerm) => { - if (searchTerm) { - return this.vendorService.getVendors().pipe( - switchMap((response) => { - if (response) { - console.log(response); - // Filter vendors based on the search term - return of( - response.filter((vendor) => - vendor.displayName - .toLowerCase() - .includes(searchTerm.toLowerCase()) - ) - ); - } else { - console.log('No Vendor Data: ' + JSON.stringify(response)); - } - return of([]); - }) - ); - } else { - return of([]); - } - }) - ) - .subscribe((filteredVendors: Vendor[]) => { - this.filteredVendors = filteredVendors; - }); - // Add SKU duplicate check this.inventoryForm .get('sku') diff --git a/src/app/pages/inventory/inventory.component.scss b/src/app/pages/inventory/inventory.component.scss index 8d82012..6d5ea3c 100644 --- a/src/app/pages/inventory/inventory.component.scss +++ b/src/app/pages/inventory/inventory.component.scss @@ -1,3 +1,4 @@ +/* General Styles for the Inventory Component */ .dashboard { display: flex; flex-direction: column; @@ -10,17 +11,48 @@ margin-bottom: 20px; padding: 20px; border-radius: 8px; + background-color: #ffffff; + border: 1px solid #e0e0e0; h3 { - font-size: 24px; - color: #ffffff; + font-size: 20px; + color: #333; + margin: 0 0 16px 0; + font-weight: 600; + } +} + +/* Mat-Raised-Button Styling */ +::ng-deep .mat-raised-button { + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.12); + text-transform: uppercase; + font-weight: 600; + letter-spacing: 0.5px; + transition: all 0.3s ease; + min-width: 120px; + height: 40px; + + &:hover { + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.18); + transform: translateY(-2px); } - button { - margin-top: 10px; + &:active { + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.12); + transform: translateY(0); } } +::ng-deep .mat-raised-button[color='primary'] { + background-color: #1976d2; + color: #ffffff; + + &:hover { + background-color: #1565c0; + } +} + +/* Responsive adjustments */ @media (max-width: 1024px) { .dashboard { flex-direction: column; @@ -38,5 +70,15 @@ .summary-card { padding: 10px; + + h3 { + font-size: 18px; + } + } + + ::ng-deep .mat-raised-button { + min-width: 100px; + height: 36px; + font-size: 12px; } } diff --git a/src/app/pages/inventory/inventory.component.ts b/src/app/pages/inventory/inventory.component.ts index ff687cc..bb3842c 100644 --- a/src/app/pages/inventory/inventory.component.ts +++ b/src/app/pages/inventory/inventory.component.ts @@ -35,7 +35,9 @@ export class InventoryComponent implements OnInit { ngOnInit(): void { this.authService.userRole.subscribe((role: string | null) => { - this.isAdminOrManager = role === 'admin' || role === 'manager'; + // Allow admin, manager, and User roles + this.isAdminOrManager = + role === 'admin' || role === 'manager' || role === 'User'; }); this.refreshInventory(); } diff --git a/src/assets/default-product.png b/src/assets/default-product.png new file mode 100644 index 0000000..9806567 Binary files /dev/null and b/src/assets/default-product.png differ diff --git a/src/styles.scss b/src/styles.scss index 4314ebe..ed6c93e 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -1,5 +1,41 @@ /* You can add global styles to this file, and also import other style files */ +// Material Select value text color +.mat-mdc-select-min-line, +.mat-select-value-text { + color: #1a1a1a !important; +} + +// Material Form Field outline color override +.mat-mdc-form-field { + .mdc-notched-outline__leading, + .mdc-notched-outline__notch, + .mdc-notched-outline__trailing { + border-color: #9e9e9e !important; + border-top-color: #9e9e9e !important; + } +} + +// Focused state - blue outline +.mat-mdc-form-field.mat-focused { + .mdc-notched-outline__leading, + .mdc-notched-outline__notch, + .mdc-notched-outline__trailing { + border-color: #1976d2 !important; + border-top-color: #1976d2 !important; + } +} + +// Invalid state - red outline +.mat-mdc-form-field.mat-form-field-invalid { + .mdc-notched-outline__leading, + .mdc-notched-outline__notch, + .mdc-notched-outline__trailing { + border-color: #c62828 !important; + border-top-color: #c62828 !important; + } +} + body, html { height: 100%; diff --git a/vercel.json b/vercel.json new file mode 100644 index 0000000..a7b844e --- /dev/null +++ b/vercel.json @@ -0,0 +1,11 @@ +{ + "version": 2, + "buildCommand": "npm run build", + "outputDirectory": "dist/nufacturing", + "routes": [ + { + "src": "^/(?!api).*", + "dest": "index.html" + } + ] +}