@aggdirect/coolmap 5.0.8 → 5.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Component, inject, input, EventEmitter, Output, signal, HostListener, effect, Input, computed, DestroyRef, ChangeDetectorRef, viewChild, CUSTOM_ELEMENTS_SCHEMA, ViewChild, ElementRef } from '@angular/core';
2
+ import { Component, inject, input, EventEmitter, Output, signal, effect, HostListener, Input, computed, DestroyRef, ChangeDetectorRef, viewChild, CUSTOM_ELEMENTS_SCHEMA, ViewChild, ElementRef } from '@angular/core';
3
3
  import * as i2$2 from '@angular/forms';
4
4
  import { FormGroup, FormControl, Validators, ReactiveFormsModule } from '@angular/forms';
5
5
  import * as i2 from '@angular/common';
@@ -201,8 +201,18 @@ class JobDetailsComponent {
201
201
  dragStartY = 0;
202
202
  dragInitialX = 0;
203
203
  dragInitialY = 0;
204
+ constructor() {
205
+ effect(() => {
206
+ if (!this.modalOpen()) {
207
+ this.dragX.set(0);
208
+ this.dragY.set(0);
209
+ }
210
+ });
211
+ }
204
212
  close() {
205
213
  this.modalOpenChange.emit(false);
214
+ this.dragX.set(0);
215
+ this.dragY.set(0);
206
216
  }
207
217
  icons = {
208
218
  X,
@@ -229,12 +239,12 @@ class JobDetailsComponent {
229
239
  this.isDragging = false;
230
240
  }
231
241
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: JobDetailsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
232
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: JobDetailsComponent, isStandalone: true, selector: "lib-job-details", inputs: { modalOpen: { classPropertyName: "modalOpen", publicName: "modalOpen", isSignal: true, isRequired: false, transformFunction: null }, routeData: { classPropertyName: "routeData", publicName: "routeData", isSignal: true, isRequired: false, transformFunction: null }, noBackdrop: { classPropertyName: "noBackdrop", publicName: "noBackdrop", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { modalOpenChange: "modalOpenChange" }, host: { listeners: { "document:mousemove": "onMouseMove($event)", "document:mouseup": "onMouseUp()" } }, ngImport: i0, template: "@if (modalOpen()) {\n<div \n class=\"z-[11] xl:z-[80] bottom-0 lg:left-[350px] fixed lg:absolute inset-0 overflow-y-auto\"\n [class.pointer-events-none]=\"noBackdrop()\"\n>\n @if (!noBackdrop()) {\n <div class=\"fixed inset-0 bg-black/50\" (click)=\"close()\"></div>\n }\n <div class=\"flex min-h-full lg:items-end lg:justify-start items-center justify-center p-3\">\n <div\n class=\"relative bg-white dark:bg-slate-800 rounded-lg shadow-xl w-[350px] pointer-events-auto\"\n [style.transform]=\"'translate(' + dragX() + 'px, ' + dragY() + 'px)'\"\n [style.will-change]=\"'transform'\"\n (click)=\"$event.stopPropagation()\"\n (mousedown)=\"startDrag($event)\"\n >\n <div\n class=\"flex items-center justify-between px-[12px] py-[10px] border-b cursor-move border-gray-200 dark:border-slate-700 dark:bg-slate-900 rounded-t-lg select-none\"\n >\n <h3 class=\"flex items-center gap-1 font-medium text-gray-900 dark:text-white text-[13px]\">\n Job Details\n </h3>\n <button\n (click)=\"close()\"\n class=\"p-2 hover:bg-gray-100 dark:hover:bg-slate-700 rounded-lg transition-colors text-gray-500\"\n >\n <lucide-icon [img]=\"icons.X\" [size]=\"20\"></lucide-icon>\n </button>\n </div>\n <div class=\"max-h-[50vh] overflow-y-auto p-2\">\n <div class=\"stats-row\">\n <div class=\"stat-item completed\">\n <span class=\"stat-count\">{{ routeData()?.values?.Done || 0 }}</span>\n <span class=\"stat-label\">Done</span>\n </div>\n\n <div class=\"stat-item pending\">\n <span class=\"stat-count\">{{ routeData()?.values?.Ongoing || 0 }}</span>\n <span class=\"stat-label\">Ongoing</span>\n </div>\n\n <div class=\"stat-item active\">\n <span class=\"stat-count\">{{ routeData()?.values?.Open || 0 }}</span>\n <span class=\"stat-label\">Open</span>\n </div>\n </div>\n <div\n class=\"location-flow bg-gray-100 dark:bg-slate-900 border border-gray-300 dark:border-slate-700 px-2 py-2 rounded-lg mt-4\"\n >\n <span class=\"pickup truncate block\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n class=\"inline mr-1 text-green-500\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"8\" />\n </svg>\n Pickup: {{ routeData()?.pickup_location || 'N/A' }}\n </span>\n <span class=\"delivery truncate block mt-1\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n class=\"inline mr-1 text-blue-500\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"8\" />\n </svg>\n Delivery: {{ routeData()?.delivery_location || 'N/A' }}\n </span>\n </div>\n <div class=\"device-info mt-2\">\n <div\n class=\"flex justify-between py-2 border-b border-gray-200 dark:border-slate-600 text-xs\"\n >\n <span class=\"text-gray-500 dark:text-slate-500\">Jobcode</span>\n <span class=\"font-medium truncate max-w-[65%] text-right\">{{ routeData()?.order_number || 'N/A' }}</span>\n </div>\n <div\n class=\"flex justify-between py-2 border-b border-gray-200 dark:border-slate-600 text-xs\"\n >\n <span class=\"text-gray-500 dark:text-slate-500\">Customer</span>\n <span class=\"font-medium truncate max-w-[65%] text-right\">{{ routeData()?.customer_name || 'N/A' }}</span>\n </div>\n <div\n class=\"flex justify-between py-2 border-b border-gray-200 dark:border-slate-600 text-xs\"\n >\n <span class=\"text-gray-500 dark:text-slate-500\">Project Name</span>\n <span class=\"font-medium truncate max-w-[65%] text-right\">{{ routeData()?.project || 'N/A' }}</span>\n </div>\n <div\n class=\"flex justify-between py-2 border-b border-gray-200 dark:border-slate-600 text-xs\"\n >\n <span class=\"text-gray-500 dark:text-slate-500\">Job Type</span>\n <span class=\"font-medium truncate max-w-[65%] text-right\">{{ routeData()?.unit || 'N/A' }}</span>\n </div>\n <div\n class=\"flex justify-between py-2 border-b border-gray-200 dark:border-slate-600 text-xs\"\n >\n <span class=\"text-gray-500 dark:text-slate-500\">Material</span>\n <span class=\"font-medium truncate max-w-[65%] text-right\">{{ routeData()?.material || 'General Freight' }}</span>\n </div>\n <div\n class=\"flex justify-between py-2 border-b border-gray-200 dark:border-slate-600 text-xs\"\n >\n <span class=\"text-gray-500 dark:text-slate-500\">Customer Contact</span>\n <span class=\"font-medium\">{{ routeData()?.customer_contact || 'None' }}</span>\n </div>\n <div class=\"flex justify-between py-2 text-xs\">\n <span class=\"text-gray-500 dark:text-slate-500\">Delivery Contact</span>\n <span class=\"font-medium\">{{ routeData()?.delivery_contact || 'None' }}</span>\n </div>\n </div>\n </div>\n </div>\n </div>\n</div>\n}\n", styles: [".stats-row{display:flex;align-items:center;gap:30px;font-size:12px;margin:0 10px 0 60px}.stat-item{display:flex;align-items:center;gap:6px;cursor:default}.stat-count{font-size:15px;font-weight:700;line-height:1}.stat-item.active .stat-count{color:#60a5fa}.stat-item.completed .stat-count{color:#4ade80}.stat-item.declined .stat-count{color:#f87171}.stat-item.scheduled .stat-count{color:#a78bfa}.stat-item.pending .stat-count{color:#fbbf24}.location-flow{display:flex;flex-direction:column;align-items:flex-start;gap:4px;font-size:11px;color:var(--text-secondary, #64748b);margin-bottom:6px}.location-flow .pickup{display:flex;align-items:center;gap:3px;color:#22c55e}.location-flow .pickup svg{width:8px;height:8px}.location-flow .delivery{display:flex;align-items:center;gap:3px;color:#ef4444}.location-flow .delivery svg{width:8px;height:8px}@keyframes slide-up{0%{opacity:0;transform:translateY(10px) scale(.95)}to{opacity:1;transform:translateY(0) scale(1)}}.animate-fade-in{animation:fade-in .2s ease-out}.animate-slide-up{animation:slide-up .2s ease-out}\n"], dependencies: [{ kind: "ngmodule", type: LucideAngularModule }, { kind: "component", type: i1.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }] });
242
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: JobDetailsComponent, isStandalone: true, selector: "lib-job-details", inputs: { modalOpen: { classPropertyName: "modalOpen", publicName: "modalOpen", isSignal: true, isRequired: false, transformFunction: null }, routeData: { classPropertyName: "routeData", publicName: "routeData", isSignal: true, isRequired: false, transformFunction: null }, noBackdrop: { classPropertyName: "noBackdrop", publicName: "noBackdrop", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { modalOpenChange: "modalOpenChange" }, host: { listeners: { "document:mousemove": "onMouseMove($event)", "document:mouseup": "onMouseUp()" } }, ngImport: i0, template: "@if (modalOpen()) {\n<div \n class=\"z-[11] xl:z-[100] bottom-0 lg:left-[350px] fixed lg:absolute inset-0 overflow-y-auto\"\n [class.pointer-events-none]=\"noBackdrop()\"\n>\n @if (!noBackdrop()) {\n <div class=\"fixed inset-0 bg-black/50\" (click)=\"close()\"></div>\n }\n <div class=\"flex min-h-full lg:items-end lg:justify-start items-center justify-center p-3\">\n <div\n class=\"relative bg-white dark:bg-slate-800 rounded-lg shadow-xl w-[350px] pointer-events-auto\"\n [style.transform]=\"'translate(' + dragX() + 'px, ' + dragY() + 'px)'\"\n [style.will-change]=\"'transform'\"\n (click)=\"$event.stopPropagation()\"\n \n >\n <div\n class=\"flex items-center justify-between px-[12px] py-[10px] border-b cursor-move border-gray-200 dark:border-slate-700 dark:bg-slate-900 rounded-t-lg select-none\" (mousedown)=\"startDrag($event)\"\n >\n <h3 class=\"flex items-center gap-1 font-medium text-gray-900 dark:text-white text-[13px]\">\n Job Details\n </h3>\n <button\n (click)=\"close()\"\n class=\"p-2 hover:bg-gray-100 dark:hover:bg-slate-700 rounded-lg transition-colors text-gray-500\"\n >\n <lucide-icon [img]=\"icons.X\" [size]=\"20\"></lucide-icon>\n </button>\n </div>\n <div class=\"max-h-[50vh] overflow-y-auto p-2\">\n <div class=\"stats-row\">\n <div class=\"stat-item completed\">\n <span class=\"stat-count\">{{ routeData()?.values?.Done || 0 }}</span>\n <span class=\"stat-label\">Done</span>\n </div>\n\n <div class=\"stat-item pending\">\n <span class=\"stat-count\">{{ routeData()?.values?.Ongoing || 0 }}</span>\n <span class=\"stat-label\">Ongoing</span>\n </div>\n\n <div class=\"stat-item active\">\n <span class=\"stat-count\">{{ routeData()?.values?.Open || 0 }}</span>\n <span class=\"stat-label\">Open</span>\n </div>\n </div>\n <div\n class=\"location-flow bg-gray-100 dark:bg-slate-900 border border-gray-300 dark:border-slate-700 px-2 py-2 rounded-lg mt-4\"\n >\n <span class=\"pickup truncate block\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n class=\"inline mr-1 text-green-500\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"8\" />\n </svg>\n Pickup: {{ routeData()?.pickup_location || 'N/A' }}\n </span>\n <span class=\"delivery truncate block mt-1\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n class=\"inline mr-1 text-blue-500\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"8\" />\n </svg>\n Delivery: {{ routeData()?.delivery_location || 'N/A' }}\n </span>\n </div>\n <div class=\"device-info mt-2\">\n <div\n class=\"flex justify-between py-2 border-b border-gray-200 dark:border-slate-600 text-xs\"\n >\n <span class=\"text-gray-500 dark:text-slate-500\">Jobcode</span>\n <span class=\"font-medium truncate max-w-[65%] text-right\">{{ routeData()?.order_number || 'N/A' }}</span>\n </div>\n <div\n class=\"flex justify-between py-2 border-b border-gray-200 dark:border-slate-600 text-xs\"\n >\n <span class=\"text-gray-500 dark:text-slate-500\">Customer</span>\n <span class=\"font-medium truncate max-w-[65%] text-right\">{{ routeData()?.customer_name || 'N/A' }}</span>\n </div>\n <div\n class=\"flex justify-between py-2 border-b border-gray-200 dark:border-slate-600 text-xs\"\n >\n <span class=\"text-gray-500 dark:text-slate-500\">Project Name</span>\n <span class=\"font-medium truncate max-w-[65%] text-right\">{{ routeData()?.project || 'N/A' }}</span>\n </div>\n <div\n class=\"flex justify-between py-2 border-b border-gray-200 dark:border-slate-600 text-xs\"\n >\n <span class=\"text-gray-500 dark:text-slate-500\">Job Type</span>\n <span class=\"font-medium truncate max-w-[65%] text-right\">{{ routeData()?.unit || 'N/A' }}</span>\n </div>\n <div\n class=\"flex justify-between py-2 border-b border-gray-200 dark:border-slate-600 text-xs\"\n >\n <span class=\"text-gray-500 dark:text-slate-500\">Material</span>\n <span class=\"font-medium truncate max-w-[65%] text-right\">{{ routeData()?.material || 'General Freight' }}</span>\n </div>\n <div\n class=\"flex justify-between py-2 border-b border-gray-200 dark:border-slate-600 text-xs\"\n >\n <span class=\"text-gray-500 dark:text-slate-500\">Customer Contact</span>\n <span class=\"font-medium\">{{ routeData()?.customer_contact || 'None' }}</span>\n </div>\n <div class=\"flex justify-between py-2 text-xs\">\n <span class=\"text-gray-500 dark:text-slate-500\">Delivery Contact</span>\n <span class=\"font-medium\">{{ routeData()?.delivery_contact || 'None' }}</span>\n </div>\n </div>\n </div>\n </div>\n </div>\n</div>\n}\n", styles: [".stats-row{display:flex;align-items:center;gap:30px;font-size:12px;margin:0 10px 0 60px}.stat-item{display:flex;align-items:center;gap:6px;cursor:default}.stat-count{font-size:15px;font-weight:700;line-height:1}.stat-item.active .stat-count{color:#60a5fa}.stat-item.completed .stat-count{color:#4ade80}.stat-item.declined .stat-count{color:#f87171}.stat-item.scheduled .stat-count{color:#a78bfa}.stat-item.pending .stat-count{color:#fbbf24}.location-flow{display:flex;flex-direction:column;align-items:flex-start;gap:4px;font-size:11px;color:var(--text-secondary, #64748b);margin-bottom:6px}.location-flow .pickup{display:flex;align-items:center;gap:3px;color:#22c55e}.location-flow .pickup svg{width:8px;height:8px}.location-flow .delivery{display:flex;align-items:center;gap:3px;color:#ef4444}.location-flow .delivery svg{width:8px;height:8px}@keyframes slide-up{0%{opacity:0;transform:translateY(10px) scale(.95)}to{opacity:1;transform:translateY(0) scale(1)}}.animate-fade-in{animation:fade-in .2s ease-out}.animate-slide-up{animation:slide-up .2s ease-out}\n"], dependencies: [{ kind: "ngmodule", type: LucideAngularModule }, { kind: "component", type: i1.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }] });
233
243
  }
234
244
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: JobDetailsComponent, decorators: [{
235
245
  type: Component,
236
- args: [{ selector: 'lib-job-details', standalone: true, imports: [LucideAngularModule, NgClass], template: "@if (modalOpen()) {\n<div \n class=\"z-[11] xl:z-[80] bottom-0 lg:left-[350px] fixed lg:absolute inset-0 overflow-y-auto\"\n [class.pointer-events-none]=\"noBackdrop()\"\n>\n @if (!noBackdrop()) {\n <div class=\"fixed inset-0 bg-black/50\" (click)=\"close()\"></div>\n }\n <div class=\"flex min-h-full lg:items-end lg:justify-start items-center justify-center p-3\">\n <div\n class=\"relative bg-white dark:bg-slate-800 rounded-lg shadow-xl w-[350px] pointer-events-auto\"\n [style.transform]=\"'translate(' + dragX() + 'px, ' + dragY() + 'px)'\"\n [style.will-change]=\"'transform'\"\n (click)=\"$event.stopPropagation()\"\n (mousedown)=\"startDrag($event)\"\n >\n <div\n class=\"flex items-center justify-between px-[12px] py-[10px] border-b cursor-move border-gray-200 dark:border-slate-700 dark:bg-slate-900 rounded-t-lg select-none\"\n >\n <h3 class=\"flex items-center gap-1 font-medium text-gray-900 dark:text-white text-[13px]\">\n Job Details\n </h3>\n <button\n (click)=\"close()\"\n class=\"p-2 hover:bg-gray-100 dark:hover:bg-slate-700 rounded-lg transition-colors text-gray-500\"\n >\n <lucide-icon [img]=\"icons.X\" [size]=\"20\"></lucide-icon>\n </button>\n </div>\n <div class=\"max-h-[50vh] overflow-y-auto p-2\">\n <div class=\"stats-row\">\n <div class=\"stat-item completed\">\n <span class=\"stat-count\">{{ routeData()?.values?.Done || 0 }}</span>\n <span class=\"stat-label\">Done</span>\n </div>\n\n <div class=\"stat-item pending\">\n <span class=\"stat-count\">{{ routeData()?.values?.Ongoing || 0 }}</span>\n <span class=\"stat-label\">Ongoing</span>\n </div>\n\n <div class=\"stat-item active\">\n <span class=\"stat-count\">{{ routeData()?.values?.Open || 0 }}</span>\n <span class=\"stat-label\">Open</span>\n </div>\n </div>\n <div\n class=\"location-flow bg-gray-100 dark:bg-slate-900 border border-gray-300 dark:border-slate-700 px-2 py-2 rounded-lg mt-4\"\n >\n <span class=\"pickup truncate block\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n class=\"inline mr-1 text-green-500\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"8\" />\n </svg>\n Pickup: {{ routeData()?.pickup_location || 'N/A' }}\n </span>\n <span class=\"delivery truncate block mt-1\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n class=\"inline mr-1 text-blue-500\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"8\" />\n </svg>\n Delivery: {{ routeData()?.delivery_location || 'N/A' }}\n </span>\n </div>\n <div class=\"device-info mt-2\">\n <div\n class=\"flex justify-between py-2 border-b border-gray-200 dark:border-slate-600 text-xs\"\n >\n <span class=\"text-gray-500 dark:text-slate-500\">Jobcode</span>\n <span class=\"font-medium truncate max-w-[65%] text-right\">{{ routeData()?.order_number || 'N/A' }}</span>\n </div>\n <div\n class=\"flex justify-between py-2 border-b border-gray-200 dark:border-slate-600 text-xs\"\n >\n <span class=\"text-gray-500 dark:text-slate-500\">Customer</span>\n <span class=\"font-medium truncate max-w-[65%] text-right\">{{ routeData()?.customer_name || 'N/A' }}</span>\n </div>\n <div\n class=\"flex justify-between py-2 border-b border-gray-200 dark:border-slate-600 text-xs\"\n >\n <span class=\"text-gray-500 dark:text-slate-500\">Project Name</span>\n <span class=\"font-medium truncate max-w-[65%] text-right\">{{ routeData()?.project || 'N/A' }}</span>\n </div>\n <div\n class=\"flex justify-between py-2 border-b border-gray-200 dark:border-slate-600 text-xs\"\n >\n <span class=\"text-gray-500 dark:text-slate-500\">Job Type</span>\n <span class=\"font-medium truncate max-w-[65%] text-right\">{{ routeData()?.unit || 'N/A' }}</span>\n </div>\n <div\n class=\"flex justify-between py-2 border-b border-gray-200 dark:border-slate-600 text-xs\"\n >\n <span class=\"text-gray-500 dark:text-slate-500\">Material</span>\n <span class=\"font-medium truncate max-w-[65%] text-right\">{{ routeData()?.material || 'General Freight' }}</span>\n </div>\n <div\n class=\"flex justify-between py-2 border-b border-gray-200 dark:border-slate-600 text-xs\"\n >\n <span class=\"text-gray-500 dark:text-slate-500\">Customer Contact</span>\n <span class=\"font-medium\">{{ routeData()?.customer_contact || 'None' }}</span>\n </div>\n <div class=\"flex justify-between py-2 text-xs\">\n <span class=\"text-gray-500 dark:text-slate-500\">Delivery Contact</span>\n <span class=\"font-medium\">{{ routeData()?.delivery_contact || 'None' }}</span>\n </div>\n </div>\n </div>\n </div>\n </div>\n</div>\n}\n", styles: [".stats-row{display:flex;align-items:center;gap:30px;font-size:12px;margin:0 10px 0 60px}.stat-item{display:flex;align-items:center;gap:6px;cursor:default}.stat-count{font-size:15px;font-weight:700;line-height:1}.stat-item.active .stat-count{color:#60a5fa}.stat-item.completed .stat-count{color:#4ade80}.stat-item.declined .stat-count{color:#f87171}.stat-item.scheduled .stat-count{color:#a78bfa}.stat-item.pending .stat-count{color:#fbbf24}.location-flow{display:flex;flex-direction:column;align-items:flex-start;gap:4px;font-size:11px;color:var(--text-secondary, #64748b);margin-bottom:6px}.location-flow .pickup{display:flex;align-items:center;gap:3px;color:#22c55e}.location-flow .pickup svg{width:8px;height:8px}.location-flow .delivery{display:flex;align-items:center;gap:3px;color:#ef4444}.location-flow .delivery svg{width:8px;height:8px}@keyframes slide-up{0%{opacity:0;transform:translateY(10px) scale(.95)}to{opacity:1;transform:translateY(0) scale(1)}}.animate-fade-in{animation:fade-in .2s ease-out}.animate-slide-up{animation:slide-up .2s ease-out}\n"] }]
237
- }], propDecorators: { modalOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "modalOpen", required: false }] }], routeData: [{ type: i0.Input, args: [{ isSignal: true, alias: "routeData", required: false }] }], noBackdrop: [{ type: i0.Input, args: [{ isSignal: true, alias: "noBackdrop", required: false }] }], modalOpenChange: [{
246
+ args: [{ selector: 'lib-job-details', standalone: true, imports: [LucideAngularModule], template: "@if (modalOpen()) {\n<div \n class=\"z-[11] xl:z-[100] bottom-0 lg:left-[350px] fixed lg:absolute inset-0 overflow-y-auto\"\n [class.pointer-events-none]=\"noBackdrop()\"\n>\n @if (!noBackdrop()) {\n <div class=\"fixed inset-0 bg-black/50\" (click)=\"close()\"></div>\n }\n <div class=\"flex min-h-full lg:items-end lg:justify-start items-center justify-center p-3\">\n <div\n class=\"relative bg-white dark:bg-slate-800 rounded-lg shadow-xl w-[350px] pointer-events-auto\"\n [style.transform]=\"'translate(' + dragX() + 'px, ' + dragY() + 'px)'\"\n [style.will-change]=\"'transform'\"\n (click)=\"$event.stopPropagation()\"\n \n >\n <div\n class=\"flex items-center justify-between px-[12px] py-[10px] border-b cursor-move border-gray-200 dark:border-slate-700 dark:bg-slate-900 rounded-t-lg select-none\" (mousedown)=\"startDrag($event)\"\n >\n <h3 class=\"flex items-center gap-1 font-medium text-gray-900 dark:text-white text-[13px]\">\n Job Details\n </h3>\n <button\n (click)=\"close()\"\n class=\"p-2 hover:bg-gray-100 dark:hover:bg-slate-700 rounded-lg transition-colors text-gray-500\"\n >\n <lucide-icon [img]=\"icons.X\" [size]=\"20\"></lucide-icon>\n </button>\n </div>\n <div class=\"max-h-[50vh] overflow-y-auto p-2\">\n <div class=\"stats-row\">\n <div class=\"stat-item completed\">\n <span class=\"stat-count\">{{ routeData()?.values?.Done || 0 }}</span>\n <span class=\"stat-label\">Done</span>\n </div>\n\n <div class=\"stat-item pending\">\n <span class=\"stat-count\">{{ routeData()?.values?.Ongoing || 0 }}</span>\n <span class=\"stat-label\">Ongoing</span>\n </div>\n\n <div class=\"stat-item active\">\n <span class=\"stat-count\">{{ routeData()?.values?.Open || 0 }}</span>\n <span class=\"stat-label\">Open</span>\n </div>\n </div>\n <div\n class=\"location-flow bg-gray-100 dark:bg-slate-900 border border-gray-300 dark:border-slate-700 px-2 py-2 rounded-lg mt-4\"\n >\n <span class=\"pickup truncate block\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n class=\"inline mr-1 text-green-500\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"8\" />\n </svg>\n Pickup: {{ routeData()?.pickup_location || 'N/A' }}\n </span>\n <span class=\"delivery truncate block mt-1\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n class=\"inline mr-1 text-blue-500\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"8\" />\n </svg>\n Delivery: {{ routeData()?.delivery_location || 'N/A' }}\n </span>\n </div>\n <div class=\"device-info mt-2\">\n <div\n class=\"flex justify-between py-2 border-b border-gray-200 dark:border-slate-600 text-xs\"\n >\n <span class=\"text-gray-500 dark:text-slate-500\">Jobcode</span>\n <span class=\"font-medium truncate max-w-[65%] text-right\">{{ routeData()?.order_number || 'N/A' }}</span>\n </div>\n <div\n class=\"flex justify-between py-2 border-b border-gray-200 dark:border-slate-600 text-xs\"\n >\n <span class=\"text-gray-500 dark:text-slate-500\">Customer</span>\n <span class=\"font-medium truncate max-w-[65%] text-right\">{{ routeData()?.customer_name || 'N/A' }}</span>\n </div>\n <div\n class=\"flex justify-between py-2 border-b border-gray-200 dark:border-slate-600 text-xs\"\n >\n <span class=\"text-gray-500 dark:text-slate-500\">Project Name</span>\n <span class=\"font-medium truncate max-w-[65%] text-right\">{{ routeData()?.project || 'N/A' }}</span>\n </div>\n <div\n class=\"flex justify-between py-2 border-b border-gray-200 dark:border-slate-600 text-xs\"\n >\n <span class=\"text-gray-500 dark:text-slate-500\">Job Type</span>\n <span class=\"font-medium truncate max-w-[65%] text-right\">{{ routeData()?.unit || 'N/A' }}</span>\n </div>\n <div\n class=\"flex justify-between py-2 border-b border-gray-200 dark:border-slate-600 text-xs\"\n >\n <span class=\"text-gray-500 dark:text-slate-500\">Material</span>\n <span class=\"font-medium truncate max-w-[65%] text-right\">{{ routeData()?.material || 'General Freight' }}</span>\n </div>\n <div\n class=\"flex justify-between py-2 border-b border-gray-200 dark:border-slate-600 text-xs\"\n >\n <span class=\"text-gray-500 dark:text-slate-500\">Customer Contact</span>\n <span class=\"font-medium\">{{ routeData()?.customer_contact || 'None' }}</span>\n </div>\n <div class=\"flex justify-between py-2 text-xs\">\n <span class=\"text-gray-500 dark:text-slate-500\">Delivery Contact</span>\n <span class=\"font-medium\">{{ routeData()?.delivery_contact || 'None' }}</span>\n </div>\n </div>\n </div>\n </div>\n </div>\n</div>\n}\n", styles: [".stats-row{display:flex;align-items:center;gap:30px;font-size:12px;margin:0 10px 0 60px}.stat-item{display:flex;align-items:center;gap:6px;cursor:default}.stat-count{font-size:15px;font-weight:700;line-height:1}.stat-item.active .stat-count{color:#60a5fa}.stat-item.completed .stat-count{color:#4ade80}.stat-item.declined .stat-count{color:#f87171}.stat-item.scheduled .stat-count{color:#a78bfa}.stat-item.pending .stat-count{color:#fbbf24}.location-flow{display:flex;flex-direction:column;align-items:flex-start;gap:4px;font-size:11px;color:var(--text-secondary, #64748b);margin-bottom:6px}.location-flow .pickup{display:flex;align-items:center;gap:3px;color:#22c55e}.location-flow .pickup svg{width:8px;height:8px}.location-flow .delivery{display:flex;align-items:center;gap:3px;color:#ef4444}.location-flow .delivery svg{width:8px;height:8px}@keyframes slide-up{0%{opacity:0;transform:translateY(10px) scale(.95)}to{opacity:1;transform:translateY(0) scale(1)}}.animate-fade-in{animation:fade-in .2s ease-out}.animate-slide-up{animation:slide-up .2s ease-out}\n"] }]
247
+ }], ctorParameters: () => [], propDecorators: { modalOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "modalOpen", required: false }] }], routeData: [{ type: i0.Input, args: [{ isSignal: true, alias: "routeData", required: false }] }], noBackdrop: [{ type: i0.Input, args: [{ isSignal: true, alias: "noBackdrop", required: false }] }], modalOpenChange: [{
238
248
  type: Output
239
249
  }], onMouseMove: [{
240
250
  type: HostListener,
@@ -262,7 +272,7 @@ class JobCodeComponent {
262
272
  collapsible = true;
263
273
  routes = [];
264
274
  selectedRouteIds = [];
265
- isLoading = false;
275
+ isLoading = true;
266
276
  routeSelect = new EventEmitter();
267
277
  collapsed = false;
268
278
  // New Signal States
@@ -327,11 +337,11 @@ class JobCodeComponent {
327
337
  }
328
338
  }
329
339
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: JobCodeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
330
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: JobCodeComponent, isStandalone: true, selector: "lib-job-code", inputs: { listMode: "listMode", collapsible: "collapsible", routes: "routes", selectedRouteIds: "selectedRouteIds", isLoading: "isLoading" }, outputs: { routeSelect: "routeSelect" }, host: { listeners: { "document:keydown.escape": "icons()" } }, ngImport: i0, template: "<div\n class=\"cards-list-container\"\n [class.floating]=\"listMode === 'floating'\"\n [class.sidebar]=\"listMode === 'sidebar'\"\n [class.inline]=\"listMode === 'inline'\"\n [class.collapsed]=\"collapsed\"\n>\n <div class=\"list-header\">\n <div class=\"header-title\">\n <span class=\"title-text\">Routes</span>\n <span class=\"routes-count\">({{ routes.length || 0 }})</span>\n </div>\n <button\n class=\"collapse-btn\"\n (click)=\"toggleCollapse()\"\n [title]=\"collapsed ? 'Expand' : 'Collapse'\"\n >\n @if (collapsed) {\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n >\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n } @else {\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n >\n <path d=\"m15 18-6-6 6-6\" />\n </svg>\n }\n </button>\n </div>\n @if (!collapsed) {\n <div class=\"cards-scroll-container\" #scrollContainer>\n @if (routes.length && isLoading) {\n <div class=\"list-loader\">\n <lucide-icon [img]=\"icons.LoaderCircle\" [size]=\"32\" class=\"animate-spin text-amber-500\"></lucide-icon>\n </div>\n }\n @if(routes.length){\n <div class=\"cards-list\">\n @for (route of routes; track $index) {\n <div class=\"card-wrapper\" (click)=\"toggleRouteSelection(route)\">\n <div\n class=\"route-card bg-white dark:bg-slate-800 border transition-all duration-200\"\n [class.border-brand-blue]=\"selectedRouteIds.includes(route.job_id || route.route_id || route.route_details_id || '')\"\n [class.border-gray-300]=\"!selectedRouteIds.includes(route.job_id || route.route_id || route.route_details_id || '')\"\n [class.dark:border-slate-700]=\"!selectedRouteIds.includes(route.job_id || route.route_id || route.route_details_id || '')\"\n [class.selected]=\"selectedRouteIds.includes(route.job_id || route.route_id || route.route_details_id || '')\"\n >\n <div class=\"task-header justify-between\">\n <span class=\"job-code\">{{ route.order_number || 'N/A' }}</span>\n <div class=\"flex gap-2\">\n <div class=\"statusunit text-white\" [ngClass]=\"route.unit || ''\">{{ route.unit?.charAt(0) || 'U' }}</div>\n @if (config.repository !== 'customer') {\n <div\n class=\"statusunit bg-slate-900 dark:bg-white text-white dark:text-black flex items-center justify-center cursor-pointer hover:opacity-80\"\n (click)=\"showDriverModal = true; toggleCollapse(); $event.stopPropagation()\"\n >\n <lucide-icon [img]=\"icons.CarFront\" [size]=\"15\"></lucide-icon>\n </div>\n }\n <div\n class=\"text-black dark:text-white flex items-center justify-center cursor-pointer hover:opacity-80\"\n (click)=\"openDetail(route, true); $event.stopPropagation()\"\n (mouseenter)=\"openDetail(route, false)\"\n (mouseleave)=\"closeDetail(true)\"\n >\n <lucide-icon [img]=\"icons.Info\" [size]=\"20\"></lucide-icon>\n </div>\n </div>\n </div>\n <div class=\"customer-name font-semibold truncate\">{{ route.customer_name }}</div>\n <div class=\"material-info truncate text-gray-600 dark:text-gray-300\">{{ route.project || 'No Project' }}</div>\n <div class=\"location-flow mt-2 text-sm flex items-center gap-2\">\n <span class=\"pickup flex items-center gap-1 truncate max-w-[40%] text-green-600 dark:text-green-400\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <circle cx=\"12\" cy=\"12\" r=\"8\" />\n </svg>\n {{ (route.pickup_location || '').split('|')[0] || 'Unknown' }}\n </span>\n <span class=\"arrow text-gray-400\">\u2192</span>\n <span class=\"delivery truncate max-w-[40%] text-brand-blue\">{{ (route.delivery_location || '').split('|')[0] || 'Unknown' }}</span>\n </div>\n <div class=\"material-info mt-2 truncate font-medium\">{{ route.material || '' }}</div>\n <div class=\"driver-row-4 mt-3 flex items-center gap-2\">\n <div class=\"progress-bar flex-1 h-1.5 bg-gray-200 dark:bg-slate-700 rounded-full overflow-hidden flex\">\n <div class=\"progress-segment completed h-full bg-green-500 transition-all duration-300\" [style.width.%]=\"calculateStatusPercentage('done', route)\"></div>\n <div class=\"progress-segment ongoing h-full transition-all duration-300\" [style.backgroundColor]=\"'#fc0'\" [style.width.%]=\"calculateStatusPercentage('ongoing', route)\"></div>\n <div class=\"progress-segment open h-full bg-gray-300 dark:bg-slate-600 transition-all duration-300\" [style.width.%]=\"calculateStatusPercentage('open', route)\"></div>\n </div>\n </div>\n </div>\n </div>\n }\n </div>\n } @else {\n <div class=\"empty-state\">\n <div class=\"text-gray-600 dark:text-gray-400 mt-2 text-center\">No Job code found.</div>\n </div>\n }\n </div>\n }\n</div>\n<lib-driver-list\n [(modalOpen)]=\"showDriverModal\"\n [driverListcollapse]=\"driverListcollapse()\"\n></lib-driver-list>\n<lib-job-details \n [modalOpen]=\"showDetailModal\" \n (modalOpenChange)=\"$event ? null : closeDetail(false)\" \n [routeData]=\"selectedJobDetail()\" \n [noBackdrop]=\"!isClickTriggered\"\n></lib-job-details>\n", styles: [":host{display:block}.cards-list-container{display:flex;flex-direction:column;height:100%;background:var(--bg-primary, white)}.cards-list-container.floating{position:absolute;top:12px;left:12px;width:280px;max-height:calc(100% - 24px);border-radius:12px;box-shadow:0 4px 24px #00000026;z-index:100;overflow:hidden}.cards-list-container.floating.collapsed{width:48px}.cards-list-container.sidebar{width:100%;border-right:1px solid var(--border-color, #e2e8f0)}.cards-list-container.inline{width:160px;min-width:160px;border-right:1px solid var(--border-color, #e2e8f0)}:host-context(.dark) .cards-list-container{background-color:#1e293b}:host-context(.dark) .cards-list-container.sidebar,:host-context(.dark) .cards-list-container.inline{border-color:#334155}.list-header{display:flex;align-items:center;justify-content:space-between;padding:12px;border-bottom:1px solid var(--border-color, #e2e8f0);background:var(--bg-secondary, #f8fafc)}:host-context(.dark) .list-header{background-color:#0f172a;border-color:#334155}.collapsed .list-header{padding:12px 8px;justify-content:center}.header-title{display:flex;align-items:center;gap:6px}.collapsed .header-title{display:none}.title-text{font-size:13px;font-weight:600;color:var(--text-primary, #1e293b)}:host-context(.dark) .title-text{color:#f1f5f9}.routes-count{font-size:12px;color:var(--text-secondary, #64748b)}.collapse-btn{display:flex;align-items:center;justify-content:center;width:28px;height:28px;border:none;background:transparent;color:var(--text-secondary, #64748b);cursor:pointer;border-radius:6px;transition:all .15s ease}.collapse-btn:hover{background:var(--hover-bg, #e2e8f0);color:var(--text-primary, #1e293b)}:host-context(.dark) .collapse-btn:hover{background-color:#334155;color:#f1f5f9}.cards-scroll-container{flex:1;overflow-y:auto;overflow-x:hidden}.cards-list{display:flex;flex-direction:column;gap:8px;padding:8px}.card-wrapper{border-radius:8px;transition:all .2s ease}.route-card{position:relative;padding:6px 10px;display:flex;flex-direction:column;gap:2px;border-radius:8px;cursor:pointer;transition:all .15s ease;min-height:72px}.route-card:hover{border-color:var(--accent-color, #3b82f6);box-shadow:0 2px 8px #00000014}.route-card.selected{border-color:var(--accent-color, #3b82f6);background:#3b82f60d}.task-header{display:flex;align-items:center;gap:6px;margin-bottom:4px}.job-code{font-size:13px;font-weight:600;color:var(--text-primary, #1e293b)}:host-context(.dark) .job-code{color:#f1f5f9}.customer-name{font-size:12px;color:var(--text-secondary, #64748b);margin-bottom:4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.material-info{font-size:11px;color:var(--text-tertiary, #94a3b8);margin-bottom:6px;font-weight:500}.location-flow{display:flex;align-items:center;gap:4px;font-size:11px;color:var(--text-secondary, #64748b);margin-bottom:6px}.location-flow .pickup{display:flex;align-items:center;gap:3px;color:#22c55e}.location-flow .pickup svg{width:8px;height:8px}.location-flow .arrow{color:var(--text-tertiary, #94a3b8)}.location-flow .delivery{color:#ef4444}.driver-row-4{display:flex;align-items:center;gap:4px;margin-top:2px}.progress-bar{display:flex;gap:2px}.progress-segment{height:6px;border-radius:2px;position:relative;cursor:pointer}.progress-segment.completed{background:#22c55e}.progress-segment.in_progress{background:#f59e0b}.progress-segment.pending{background:#cbd5e1}.progress-segment.incomplete{background:#ef4444}.progress-segment:after{content:attr(data-tooltip);position:absolute;bottom:calc(100% + 8px);left:50%;transform:translate(-50%);background:#1e293b;color:#fff;padding:6px 10px;border-radius:6px;font-size:10px;white-space:pre-line;min-width:120px;max-width:180px;box-shadow:0 3px 10px #0003;z-index:1000;opacity:0;visibility:hidden;transition:opacity .15s ease;pointer-events:none}.progress-segment:hover:after{opacity:1;visibility:visible}.task-count{font-size:10px;font-weight:600;color:var(--text-secondary, #64748b);min-width:24px;text-align:right}.on-time-indicator{font-size:10px;color:#22c55e}.on-time-indicator.late{color:#ef4444}.statusunit{border-radius:30px;font-size:12px;text-transform:capitalize;font-weight:600;width:20px;height:20px;text-align:center;line-height:20px}.statusunit.Ton{background:#22c55e}.statusunit.Load{background:#3b82f6}.statusunit.Hourly{background:#f59e0b}.list-loader{position:absolute;inset:0;background:#fff6;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);display:flex;align-items:center;justify-content:center;z-index:50;border-radius:0 0 12px 12px}:host-context(.dark) .list-loader{background:#0f172a66}.animate-spin{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"], dependencies: [{ kind: "ngmodule", type: LucideAngularModule }, { kind: "component", type: i1.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }, { kind: "component", type: DriverListComponent, selector: "lib-driver-list", inputs: ["modalOpen", "driverListcollapse"], outputs: ["modalOpenChange"] }, { kind: "component", type: JobDetailsComponent, selector: "lib-job-details", inputs: ["modalOpen", "routeData", "noBackdrop"], outputs: ["modalOpenChange"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
340
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: JobCodeComponent, isStandalone: true, selector: "lib-job-code", inputs: { listMode: "listMode", collapsible: "collapsible", routes: "routes", selectedRouteIds: "selectedRouteIds", isLoading: "isLoading" }, outputs: { routeSelect: "routeSelect" }, host: { listeners: { "document:keydown.escape": "icons()" } }, ngImport: i0, template: "<div\n class=\"cards-list-container\"\n [class.floating]=\"listMode === 'floating'\"\n [class.sidebar]=\"listMode === 'sidebar'\"\n [class.inline]=\"listMode === 'inline'\"\n [class.collapsed]=\"collapsed\"\n>\n <div class=\"list-header\">\n <div class=\"header-title\">\n <span class=\"title-text\">Routes</span>\n <span class=\"routes-count\">({{ routes.length || 0 }})</span>\n </div>\n <button\n class=\"collapse-btn\"\n (click)=\"toggleCollapse()\"\n [title]=\"collapsed ? 'Expand' : 'Collapse'\"\n >\n @if (collapsed) {\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n >\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n } @else {\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n >\n <path d=\"m15 18-6-6 6-6\" />\n </svg>\n }\n </button>\n </div>\n @if (!collapsed) {\n <div class=\"cards-scroll-container\" #scrollContainer>\n @if (isLoading) {\n <div class=\"list-loader\">\n <lucide-icon [img]=\"icons.LoaderCircle\" [size]=\"32\" class=\"animate-spin text-amber-500\"></lucide-icon>\n </div>\n }\n @if(!isLoading && routes && routes.length){\n <div class=\"cards-list\">\n @for (route of routes; track $index) {\n <div class=\"card-wrapper\" (click)=\"toggleRouteSelection(route)\">\n <div\n class=\"route-card bg-white dark:bg-slate-800 border transition-all duration-200\"\n [class.border-brand-blue]=\"selectedRouteIds.includes(route.job_id || route.route_id || route.route_details_id || '')\"\n [class.border-gray-300]=\"!selectedRouteIds.includes(route.job_id || route.route_id || route.route_details_id || '')\"\n [class.dark:border-slate-700]=\"!selectedRouteIds.includes(route.job_id || route.route_id || route.route_details_id || '')\"\n [class.selected]=\"selectedRouteIds.includes(route.job_id || route.route_id || route.route_details_id || '')\"\n >\n <div class=\"task-header justify-between\">\n <span class=\"job-code\">{{ route.order_number || 'N/A' }}</span>\n <div class=\"flex gap-2\">\n <div class=\"statusunit text-white\" [ngClass]=\"route.unit || ''\">{{ route.unit?.charAt(0) || 'U' }}</div>\n @if (config.repository !== 'customer') {\n <div\n class=\"statusunit bg-slate-900 dark:bg-white text-white dark:text-black flex items-center justify-center cursor-pointer hover:opacity-80\"\n (click)=\"showDriverModal = true; toggleCollapse(); $event.stopPropagation()\"\n >\n <lucide-icon [img]=\"icons.CarFront\" [size]=\"15\"></lucide-icon>\n </div>\n }\n <div\n class=\"text-black dark:text-white flex items-center justify-center cursor-pointer hover:opacity-80\"\n (click)=\"openDetail(route, true); $event.stopPropagation()\"\n (mouseenter)=\"openDetail(route, false)\"\n (mouseleave)=\"closeDetail(true)\"\n >\n <lucide-icon [img]=\"icons.Info\" [size]=\"20\"></lucide-icon>\n </div>\n </div>\n </div>\n <div class=\"customer-name font-semibold truncate\">{{ route.customer_name }}</div>\n <div class=\"material-info truncate text-gray-600 dark:text-gray-300\">{{ route.project || 'No Project' }}</div>\n <div class=\"location-flow mt-2 text-sm flex items-center gap-2\">\n <span class=\"pickup flex items-center gap-1 truncate max-w-[40%] text-green-600 dark:text-green-400\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <circle cx=\"12\" cy=\"12\" r=\"8\" />\n </svg>\n {{ (route.pickup_location || '').split('|')[0] || 'Unknown' }}\n </span>\n <span class=\"arrow text-gray-400\">\u2192</span>\n <span class=\"delivery truncate max-w-[40%] text-brand-blue\">{{ (route.delivery_location || '').split('|')[0] || 'Unknown' }}</span>\n </div>\n <div class=\"material-info mt-2 truncate font-medium\">{{ route.material || '' }}</div>\n <div class=\"driver-row-4 mt-3 flex items-center gap-2\">\n <div class=\"progress-bar flex-1 h-1.5 bg-gray-200 dark:bg-slate-700 rounded-full overflow-hidden flex\">\n <div class=\"progress-segment completed h-full bg-green-500 transition-all duration-300\" [style.width.%]=\"calculateStatusPercentage('done', route)\"></div>\n <div class=\"progress-segment ongoing h-full transition-all duration-300\" [style.backgroundColor]=\"'#fc0'\" [style.width.%]=\"calculateStatusPercentage('ongoing', route)\"></div>\n <div class=\"progress-segment open h-full bg-gray-300 dark:bg-slate-600 transition-all duration-300\" [style.width.%]=\"calculateStatusPercentage('open', route)\"></div>\n </div>\n </div>\n </div>\n </div>\n }\n </div>\n } @else if(!isLoading && coolmapService.isDataFetched() && (!routes || routes.length === 0)) {\n <div class=\"empty-state\">\n <div class=\"text-gray-600 dark:text-gray-400 mt-2 text-center\">No Job code found.</div>\n </div>\n }\n </div>\n }\n</div>\n<lib-driver-list\n [(modalOpen)]=\"showDriverModal\"\n [driverListcollapse]=\"driverListcollapse()\"\n></lib-driver-list>\n<lib-job-details \n [modalOpen]=\"showDetailModal\" \n (modalOpenChange)=\"$event ? null : closeDetail(false)\" \n [routeData]=\"selectedJobDetail()\" \n [noBackdrop]=\"!isClickTriggered\"\n></lib-job-details>\n", styles: [":host{display:block}.cards-list-container{display:flex;flex-direction:column;height:100%;background:var(--bg-primary, white)}.cards-list-container.floating{position:absolute;top:12px;left:12px;width:280px;max-height:calc(100% - 24px);border-radius:12px;box-shadow:0 4px 24px #00000026;z-index:100;overflow:hidden}.cards-list-container.floating.collapsed{width:48px}.cards-list-container.sidebar{width:100%;border-right:1px solid var(--border-color, #e2e8f0)}.cards-list-container.inline{width:160px;min-width:160px;border-right:1px solid var(--border-color, #e2e8f0)}:host-context(.dark) .cards-list-container{background-color:#1e293b}:host-context(.dark) .cards-list-container.sidebar,:host-context(.dark) .cards-list-container.inline{border-color:#334155}.list-header{display:flex;align-items:center;justify-content:space-between;padding:12px;border-bottom:1px solid var(--border-color, #e2e8f0);background:var(--bg-secondary, #f8fafc)}:host-context(.dark) .list-header{background-color:#0f172a;border-color:#334155}.collapsed .list-header{padding:12px 8px;justify-content:center}.header-title{display:flex;align-items:center;gap:6px}.collapsed .header-title{display:none}.title-text{font-size:13px;font-weight:600;color:var(--text-primary, #1e293b)}:host-context(.dark) .title-text{color:#f1f5f9}.routes-count{font-size:12px;color:var(--text-secondary, #64748b)}.collapse-btn{display:flex;align-items:center;justify-content:center;width:28px;height:28px;border:none;background:transparent;color:var(--text-secondary, #64748b);cursor:pointer;border-radius:6px;transition:all .15s ease}.collapse-btn:hover{background:var(--hover-bg, #e2e8f0);color:var(--text-primary, #1e293b)}:host-context(.dark) .collapse-btn:hover{background-color:#334155;color:#f1f5f9}.cards-scroll-container{flex:1;overflow-y:auto;overflow-x:hidden}.cards-list{display:flex;flex-direction:column;gap:8px;padding:8px}.card-wrapper{border-radius:8px;transition:all .2s ease}.route-card{position:relative;padding:6px 10px;display:flex;flex-direction:column;gap:2px;border-radius:8px;cursor:pointer;transition:all .15s ease;min-height:72px}.route-card:hover{border-color:var(--accent-color, #3b82f6);box-shadow:0 2px 8px #00000014}.route-card.selected{border-color:var(--accent-color, #3b82f6);background:#3b82f60d}.task-header{display:flex;align-items:center;gap:6px;margin-bottom:4px}.job-code{font-size:13px;font-weight:600;color:var(--text-primary, #1e293b)}:host-context(.dark) .job-code{color:#f1f5f9}.customer-name{font-size:12px;color:var(--text-secondary, #64748b);margin-bottom:4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.material-info{font-size:11px;color:var(--text-tertiary, #94a3b8);margin-bottom:6px;font-weight:500}.location-flow{display:flex;align-items:center;gap:4px;font-size:11px;color:var(--text-secondary, #64748b);margin-bottom:6px}.location-flow .pickup{display:flex;align-items:center;gap:3px;color:#22c55e}.location-flow .pickup svg{width:8px;height:8px}.location-flow .arrow{color:var(--text-tertiary, #94a3b8)}.location-flow .delivery{color:#ef4444}.driver-row-4{display:flex;align-items:center;gap:4px;margin-top:2px}.progress-bar{display:flex;gap:2px}.progress-segment{height:6px;border-radius:2px;position:relative;cursor:pointer}.progress-segment.completed{background:#22c55e}.progress-segment.in_progress{background:#f59e0b}.progress-segment.pending{background:#cbd5e1}.progress-segment.incomplete{background:#ef4444}.progress-segment:after{content:attr(data-tooltip);position:absolute;bottom:calc(100% + 8px);left:50%;transform:translate(-50%);background:#1e293b;color:#fff;padding:6px 10px;border-radius:6px;font-size:10px;white-space:pre-line;min-width:120px;max-width:180px;box-shadow:0 3px 10px #0003;z-index:1000;opacity:0;visibility:hidden;transition:opacity .15s ease;pointer-events:none}.progress-segment:hover:after{opacity:1;visibility:visible}.task-count{font-size:10px;font-weight:600;color:var(--text-secondary, #64748b);min-width:24px;text-align:right}.on-time-indicator{font-size:10px;color:#22c55e}.on-time-indicator.late{color:#ef4444}.statusunit{border-radius:30px;font-size:12px;text-transform:capitalize;font-weight:600;width:20px;height:20px;text-align:center;line-height:20px}.statusunit.Ton{background:#22c55e}.statusunit.Load{background:#3b82f6}.statusunit.Hourly{background:#f59e0b}.list-loader{position:absolute;inset:0;background:#fff6;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);display:flex;align-items:center;justify-content:center;z-index:50;border-radius:0 0 12px 12px}:host-context(.dark) .list-loader{background:#0f172a66}.animate-spin{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"], dependencies: [{ kind: "ngmodule", type: LucideAngularModule }, { kind: "component", type: i1.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }, { kind: "component", type: DriverListComponent, selector: "lib-driver-list", inputs: ["modalOpen", "driverListcollapse"], outputs: ["modalOpenChange"] }, { kind: "component", type: JobDetailsComponent, selector: "lib-job-details", inputs: ["modalOpen", "routeData", "noBackdrop"], outputs: ["modalOpenChange"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
331
341
  }
332
342
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: JobCodeComponent, decorators: [{
333
343
  type: Component,
334
- args: [{ selector: 'lib-job-code', standalone: true, imports: [LucideAngularModule, DriverListComponent, JobDetailsComponent, NgClass], template: "<div\n class=\"cards-list-container\"\n [class.floating]=\"listMode === 'floating'\"\n [class.sidebar]=\"listMode === 'sidebar'\"\n [class.inline]=\"listMode === 'inline'\"\n [class.collapsed]=\"collapsed\"\n>\n <div class=\"list-header\">\n <div class=\"header-title\">\n <span class=\"title-text\">Routes</span>\n <span class=\"routes-count\">({{ routes.length || 0 }})</span>\n </div>\n <button\n class=\"collapse-btn\"\n (click)=\"toggleCollapse()\"\n [title]=\"collapsed ? 'Expand' : 'Collapse'\"\n >\n @if (collapsed) {\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n >\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n } @else {\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n >\n <path d=\"m15 18-6-6 6-6\" />\n </svg>\n }\n </button>\n </div>\n @if (!collapsed) {\n <div class=\"cards-scroll-container\" #scrollContainer>\n @if (routes.length && isLoading) {\n <div class=\"list-loader\">\n <lucide-icon [img]=\"icons.LoaderCircle\" [size]=\"32\" class=\"animate-spin text-amber-500\"></lucide-icon>\n </div>\n }\n @if(routes.length){\n <div class=\"cards-list\">\n @for (route of routes; track $index) {\n <div class=\"card-wrapper\" (click)=\"toggleRouteSelection(route)\">\n <div\n class=\"route-card bg-white dark:bg-slate-800 border transition-all duration-200\"\n [class.border-brand-blue]=\"selectedRouteIds.includes(route.job_id || route.route_id || route.route_details_id || '')\"\n [class.border-gray-300]=\"!selectedRouteIds.includes(route.job_id || route.route_id || route.route_details_id || '')\"\n [class.dark:border-slate-700]=\"!selectedRouteIds.includes(route.job_id || route.route_id || route.route_details_id || '')\"\n [class.selected]=\"selectedRouteIds.includes(route.job_id || route.route_id || route.route_details_id || '')\"\n >\n <div class=\"task-header justify-between\">\n <span class=\"job-code\">{{ route.order_number || 'N/A' }}</span>\n <div class=\"flex gap-2\">\n <div class=\"statusunit text-white\" [ngClass]=\"route.unit || ''\">{{ route.unit?.charAt(0) || 'U' }}</div>\n @if (config.repository !== 'customer') {\n <div\n class=\"statusunit bg-slate-900 dark:bg-white text-white dark:text-black flex items-center justify-center cursor-pointer hover:opacity-80\"\n (click)=\"showDriverModal = true; toggleCollapse(); $event.stopPropagation()\"\n >\n <lucide-icon [img]=\"icons.CarFront\" [size]=\"15\"></lucide-icon>\n </div>\n }\n <div\n class=\"text-black dark:text-white flex items-center justify-center cursor-pointer hover:opacity-80\"\n (click)=\"openDetail(route, true); $event.stopPropagation()\"\n (mouseenter)=\"openDetail(route, false)\"\n (mouseleave)=\"closeDetail(true)\"\n >\n <lucide-icon [img]=\"icons.Info\" [size]=\"20\"></lucide-icon>\n </div>\n </div>\n </div>\n <div class=\"customer-name font-semibold truncate\">{{ route.customer_name }}</div>\n <div class=\"material-info truncate text-gray-600 dark:text-gray-300\">{{ route.project || 'No Project' }}</div>\n <div class=\"location-flow mt-2 text-sm flex items-center gap-2\">\n <span class=\"pickup flex items-center gap-1 truncate max-w-[40%] text-green-600 dark:text-green-400\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <circle cx=\"12\" cy=\"12\" r=\"8\" />\n </svg>\n {{ (route.pickup_location || '').split('|')[0] || 'Unknown' }}\n </span>\n <span class=\"arrow text-gray-400\">\u2192</span>\n <span class=\"delivery truncate max-w-[40%] text-brand-blue\">{{ (route.delivery_location || '').split('|')[0] || 'Unknown' }}</span>\n </div>\n <div class=\"material-info mt-2 truncate font-medium\">{{ route.material || '' }}</div>\n <div class=\"driver-row-4 mt-3 flex items-center gap-2\">\n <div class=\"progress-bar flex-1 h-1.5 bg-gray-200 dark:bg-slate-700 rounded-full overflow-hidden flex\">\n <div class=\"progress-segment completed h-full bg-green-500 transition-all duration-300\" [style.width.%]=\"calculateStatusPercentage('done', route)\"></div>\n <div class=\"progress-segment ongoing h-full transition-all duration-300\" [style.backgroundColor]=\"'#fc0'\" [style.width.%]=\"calculateStatusPercentage('ongoing', route)\"></div>\n <div class=\"progress-segment open h-full bg-gray-300 dark:bg-slate-600 transition-all duration-300\" [style.width.%]=\"calculateStatusPercentage('open', route)\"></div>\n </div>\n </div>\n </div>\n </div>\n }\n </div>\n } @else {\n <div class=\"empty-state\">\n <div class=\"text-gray-600 dark:text-gray-400 mt-2 text-center\">No Job code found.</div>\n </div>\n }\n </div>\n }\n</div>\n<lib-driver-list\n [(modalOpen)]=\"showDriverModal\"\n [driverListcollapse]=\"driverListcollapse()\"\n></lib-driver-list>\n<lib-job-details \n [modalOpen]=\"showDetailModal\" \n (modalOpenChange)=\"$event ? null : closeDetail(false)\" \n [routeData]=\"selectedJobDetail()\" \n [noBackdrop]=\"!isClickTriggered\"\n></lib-job-details>\n", styles: [":host{display:block}.cards-list-container{display:flex;flex-direction:column;height:100%;background:var(--bg-primary, white)}.cards-list-container.floating{position:absolute;top:12px;left:12px;width:280px;max-height:calc(100% - 24px);border-radius:12px;box-shadow:0 4px 24px #00000026;z-index:100;overflow:hidden}.cards-list-container.floating.collapsed{width:48px}.cards-list-container.sidebar{width:100%;border-right:1px solid var(--border-color, #e2e8f0)}.cards-list-container.inline{width:160px;min-width:160px;border-right:1px solid var(--border-color, #e2e8f0)}:host-context(.dark) .cards-list-container{background-color:#1e293b}:host-context(.dark) .cards-list-container.sidebar,:host-context(.dark) .cards-list-container.inline{border-color:#334155}.list-header{display:flex;align-items:center;justify-content:space-between;padding:12px;border-bottom:1px solid var(--border-color, #e2e8f0);background:var(--bg-secondary, #f8fafc)}:host-context(.dark) .list-header{background-color:#0f172a;border-color:#334155}.collapsed .list-header{padding:12px 8px;justify-content:center}.header-title{display:flex;align-items:center;gap:6px}.collapsed .header-title{display:none}.title-text{font-size:13px;font-weight:600;color:var(--text-primary, #1e293b)}:host-context(.dark) .title-text{color:#f1f5f9}.routes-count{font-size:12px;color:var(--text-secondary, #64748b)}.collapse-btn{display:flex;align-items:center;justify-content:center;width:28px;height:28px;border:none;background:transparent;color:var(--text-secondary, #64748b);cursor:pointer;border-radius:6px;transition:all .15s ease}.collapse-btn:hover{background:var(--hover-bg, #e2e8f0);color:var(--text-primary, #1e293b)}:host-context(.dark) .collapse-btn:hover{background-color:#334155;color:#f1f5f9}.cards-scroll-container{flex:1;overflow-y:auto;overflow-x:hidden}.cards-list{display:flex;flex-direction:column;gap:8px;padding:8px}.card-wrapper{border-radius:8px;transition:all .2s ease}.route-card{position:relative;padding:6px 10px;display:flex;flex-direction:column;gap:2px;border-radius:8px;cursor:pointer;transition:all .15s ease;min-height:72px}.route-card:hover{border-color:var(--accent-color, #3b82f6);box-shadow:0 2px 8px #00000014}.route-card.selected{border-color:var(--accent-color, #3b82f6);background:#3b82f60d}.task-header{display:flex;align-items:center;gap:6px;margin-bottom:4px}.job-code{font-size:13px;font-weight:600;color:var(--text-primary, #1e293b)}:host-context(.dark) .job-code{color:#f1f5f9}.customer-name{font-size:12px;color:var(--text-secondary, #64748b);margin-bottom:4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.material-info{font-size:11px;color:var(--text-tertiary, #94a3b8);margin-bottom:6px;font-weight:500}.location-flow{display:flex;align-items:center;gap:4px;font-size:11px;color:var(--text-secondary, #64748b);margin-bottom:6px}.location-flow .pickup{display:flex;align-items:center;gap:3px;color:#22c55e}.location-flow .pickup svg{width:8px;height:8px}.location-flow .arrow{color:var(--text-tertiary, #94a3b8)}.location-flow .delivery{color:#ef4444}.driver-row-4{display:flex;align-items:center;gap:4px;margin-top:2px}.progress-bar{display:flex;gap:2px}.progress-segment{height:6px;border-radius:2px;position:relative;cursor:pointer}.progress-segment.completed{background:#22c55e}.progress-segment.in_progress{background:#f59e0b}.progress-segment.pending{background:#cbd5e1}.progress-segment.incomplete{background:#ef4444}.progress-segment:after{content:attr(data-tooltip);position:absolute;bottom:calc(100% + 8px);left:50%;transform:translate(-50%);background:#1e293b;color:#fff;padding:6px 10px;border-radius:6px;font-size:10px;white-space:pre-line;min-width:120px;max-width:180px;box-shadow:0 3px 10px #0003;z-index:1000;opacity:0;visibility:hidden;transition:opacity .15s ease;pointer-events:none}.progress-segment:hover:after{opacity:1;visibility:visible}.task-count{font-size:10px;font-weight:600;color:var(--text-secondary, #64748b);min-width:24px;text-align:right}.on-time-indicator{font-size:10px;color:#22c55e}.on-time-indicator.late{color:#ef4444}.statusunit{border-radius:30px;font-size:12px;text-transform:capitalize;font-weight:600;width:20px;height:20px;text-align:center;line-height:20px}.statusunit.Ton{background:#22c55e}.statusunit.Load{background:#3b82f6}.statusunit.Hourly{background:#f59e0b}.list-loader{position:absolute;inset:0;background:#fff6;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);display:flex;align-items:center;justify-content:center;z-index:50;border-radius:0 0 12px 12px}:host-context(.dark) .list-loader{background:#0f172a66}.animate-spin{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"] }]
344
+ args: [{ selector: 'lib-job-code', standalone: true, imports: [LucideAngularModule, DriverListComponent, JobDetailsComponent, NgClass], template: "<div\n class=\"cards-list-container\"\n [class.floating]=\"listMode === 'floating'\"\n [class.sidebar]=\"listMode === 'sidebar'\"\n [class.inline]=\"listMode === 'inline'\"\n [class.collapsed]=\"collapsed\"\n>\n <div class=\"list-header\">\n <div class=\"header-title\">\n <span class=\"title-text\">Routes</span>\n <span class=\"routes-count\">({{ routes.length || 0 }})</span>\n </div>\n <button\n class=\"collapse-btn\"\n (click)=\"toggleCollapse()\"\n [title]=\"collapsed ? 'Expand' : 'Collapse'\"\n >\n @if (collapsed) {\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n >\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n } @else {\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n >\n <path d=\"m15 18-6-6 6-6\" />\n </svg>\n }\n </button>\n </div>\n @if (!collapsed) {\n <div class=\"cards-scroll-container\" #scrollContainer>\n @if (isLoading) {\n <div class=\"list-loader\">\n <lucide-icon [img]=\"icons.LoaderCircle\" [size]=\"32\" class=\"animate-spin text-amber-500\"></lucide-icon>\n </div>\n }\n @if(!isLoading && routes && routes.length){\n <div class=\"cards-list\">\n @for (route of routes; track $index) {\n <div class=\"card-wrapper\" (click)=\"toggleRouteSelection(route)\">\n <div\n class=\"route-card bg-white dark:bg-slate-800 border transition-all duration-200\"\n [class.border-brand-blue]=\"selectedRouteIds.includes(route.job_id || route.route_id || route.route_details_id || '')\"\n [class.border-gray-300]=\"!selectedRouteIds.includes(route.job_id || route.route_id || route.route_details_id || '')\"\n [class.dark:border-slate-700]=\"!selectedRouteIds.includes(route.job_id || route.route_id || route.route_details_id || '')\"\n [class.selected]=\"selectedRouteIds.includes(route.job_id || route.route_id || route.route_details_id || '')\"\n >\n <div class=\"task-header justify-between\">\n <span class=\"job-code\">{{ route.order_number || 'N/A' }}</span>\n <div class=\"flex gap-2\">\n <div class=\"statusunit text-white\" [ngClass]=\"route.unit || ''\">{{ route.unit?.charAt(0) || 'U' }}</div>\n @if (config.repository !== 'customer') {\n <div\n class=\"statusunit bg-slate-900 dark:bg-white text-white dark:text-black flex items-center justify-center cursor-pointer hover:opacity-80\"\n (click)=\"showDriverModal = true; toggleCollapse(); $event.stopPropagation()\"\n >\n <lucide-icon [img]=\"icons.CarFront\" [size]=\"15\"></lucide-icon>\n </div>\n }\n <div\n class=\"text-black dark:text-white flex items-center justify-center cursor-pointer hover:opacity-80\"\n (click)=\"openDetail(route, true); $event.stopPropagation()\"\n (mouseenter)=\"openDetail(route, false)\"\n (mouseleave)=\"closeDetail(true)\"\n >\n <lucide-icon [img]=\"icons.Info\" [size]=\"20\"></lucide-icon>\n </div>\n </div>\n </div>\n <div class=\"customer-name font-semibold truncate\">{{ route.customer_name }}</div>\n <div class=\"material-info truncate text-gray-600 dark:text-gray-300\">{{ route.project || 'No Project' }}</div>\n <div class=\"location-flow mt-2 text-sm flex items-center gap-2\">\n <span class=\"pickup flex items-center gap-1 truncate max-w-[40%] text-green-600 dark:text-green-400\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <circle cx=\"12\" cy=\"12\" r=\"8\" />\n </svg>\n {{ (route.pickup_location || '').split('|')[0] || 'Unknown' }}\n </span>\n <span class=\"arrow text-gray-400\">\u2192</span>\n <span class=\"delivery truncate max-w-[40%] text-brand-blue\">{{ (route.delivery_location || '').split('|')[0] || 'Unknown' }}</span>\n </div>\n <div class=\"material-info mt-2 truncate font-medium\">{{ route.material || '' }}</div>\n <div class=\"driver-row-4 mt-3 flex items-center gap-2\">\n <div class=\"progress-bar flex-1 h-1.5 bg-gray-200 dark:bg-slate-700 rounded-full overflow-hidden flex\">\n <div class=\"progress-segment completed h-full bg-green-500 transition-all duration-300\" [style.width.%]=\"calculateStatusPercentage('done', route)\"></div>\n <div class=\"progress-segment ongoing h-full transition-all duration-300\" [style.backgroundColor]=\"'#fc0'\" [style.width.%]=\"calculateStatusPercentage('ongoing', route)\"></div>\n <div class=\"progress-segment open h-full bg-gray-300 dark:bg-slate-600 transition-all duration-300\" [style.width.%]=\"calculateStatusPercentage('open', route)\"></div>\n </div>\n </div>\n </div>\n </div>\n }\n </div>\n } @else if(!isLoading && coolmapService.isDataFetched() && (!routes || routes.length === 0)) {\n <div class=\"empty-state\">\n <div class=\"text-gray-600 dark:text-gray-400 mt-2 text-center\">No Job code found.</div>\n </div>\n }\n </div>\n }\n</div>\n<lib-driver-list\n [(modalOpen)]=\"showDriverModal\"\n [driverListcollapse]=\"driverListcollapse()\"\n></lib-driver-list>\n<lib-job-details \n [modalOpen]=\"showDetailModal\" \n (modalOpenChange)=\"$event ? null : closeDetail(false)\" \n [routeData]=\"selectedJobDetail()\" \n [noBackdrop]=\"!isClickTriggered\"\n></lib-job-details>\n", styles: [":host{display:block}.cards-list-container{display:flex;flex-direction:column;height:100%;background:var(--bg-primary, white)}.cards-list-container.floating{position:absolute;top:12px;left:12px;width:280px;max-height:calc(100% - 24px);border-radius:12px;box-shadow:0 4px 24px #00000026;z-index:100;overflow:hidden}.cards-list-container.floating.collapsed{width:48px}.cards-list-container.sidebar{width:100%;border-right:1px solid var(--border-color, #e2e8f0)}.cards-list-container.inline{width:160px;min-width:160px;border-right:1px solid var(--border-color, #e2e8f0)}:host-context(.dark) .cards-list-container{background-color:#1e293b}:host-context(.dark) .cards-list-container.sidebar,:host-context(.dark) .cards-list-container.inline{border-color:#334155}.list-header{display:flex;align-items:center;justify-content:space-between;padding:12px;border-bottom:1px solid var(--border-color, #e2e8f0);background:var(--bg-secondary, #f8fafc)}:host-context(.dark) .list-header{background-color:#0f172a;border-color:#334155}.collapsed .list-header{padding:12px 8px;justify-content:center}.header-title{display:flex;align-items:center;gap:6px}.collapsed .header-title{display:none}.title-text{font-size:13px;font-weight:600;color:var(--text-primary, #1e293b)}:host-context(.dark) .title-text{color:#f1f5f9}.routes-count{font-size:12px;color:var(--text-secondary, #64748b)}.collapse-btn{display:flex;align-items:center;justify-content:center;width:28px;height:28px;border:none;background:transparent;color:var(--text-secondary, #64748b);cursor:pointer;border-radius:6px;transition:all .15s ease}.collapse-btn:hover{background:var(--hover-bg, #e2e8f0);color:var(--text-primary, #1e293b)}:host-context(.dark) .collapse-btn:hover{background-color:#334155;color:#f1f5f9}.cards-scroll-container{flex:1;overflow-y:auto;overflow-x:hidden}.cards-list{display:flex;flex-direction:column;gap:8px;padding:8px}.card-wrapper{border-radius:8px;transition:all .2s ease}.route-card{position:relative;padding:6px 10px;display:flex;flex-direction:column;gap:2px;border-radius:8px;cursor:pointer;transition:all .15s ease;min-height:72px}.route-card:hover{border-color:var(--accent-color, #3b82f6);box-shadow:0 2px 8px #00000014}.route-card.selected{border-color:var(--accent-color, #3b82f6);background:#3b82f60d}.task-header{display:flex;align-items:center;gap:6px;margin-bottom:4px}.job-code{font-size:13px;font-weight:600;color:var(--text-primary, #1e293b)}:host-context(.dark) .job-code{color:#f1f5f9}.customer-name{font-size:12px;color:var(--text-secondary, #64748b);margin-bottom:4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.material-info{font-size:11px;color:var(--text-tertiary, #94a3b8);margin-bottom:6px;font-weight:500}.location-flow{display:flex;align-items:center;gap:4px;font-size:11px;color:var(--text-secondary, #64748b);margin-bottom:6px}.location-flow .pickup{display:flex;align-items:center;gap:3px;color:#22c55e}.location-flow .pickup svg{width:8px;height:8px}.location-flow .arrow{color:var(--text-tertiary, #94a3b8)}.location-flow .delivery{color:#ef4444}.driver-row-4{display:flex;align-items:center;gap:4px;margin-top:2px}.progress-bar{display:flex;gap:2px}.progress-segment{height:6px;border-radius:2px;position:relative;cursor:pointer}.progress-segment.completed{background:#22c55e}.progress-segment.in_progress{background:#f59e0b}.progress-segment.pending{background:#cbd5e1}.progress-segment.incomplete{background:#ef4444}.progress-segment:after{content:attr(data-tooltip);position:absolute;bottom:calc(100% + 8px);left:50%;transform:translate(-50%);background:#1e293b;color:#fff;padding:6px 10px;border-radius:6px;font-size:10px;white-space:pre-line;min-width:120px;max-width:180px;box-shadow:0 3px 10px #0003;z-index:1000;opacity:0;visibility:hidden;transition:opacity .15s ease;pointer-events:none}.progress-segment:hover:after{opacity:1;visibility:visible}.task-count{font-size:10px;font-weight:600;color:var(--text-secondary, #64748b);min-width:24px;text-align:right}.on-time-indicator{font-size:10px;color:#22c55e}.on-time-indicator.late{color:#ef4444}.statusunit{border-radius:30px;font-size:12px;text-transform:capitalize;font-weight:600;width:20px;height:20px;text-align:center;line-height:20px}.statusunit.Ton{background:#22c55e}.statusunit.Load{background:#3b82f6}.statusunit.Hourly{background:#f59e0b}.list-loader{position:absolute;inset:0;background:#fff6;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);display:flex;align-items:center;justify-content:center;z-index:50;border-radius:0 0 12px 12px}:host-context(.dark) .list-loader{background:#0f172a66}.animate-spin{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"] }]
335
345
  }], ctorParameters: () => [], propDecorators: { listMode: [{
336
346
  type: Input
337
347
  }], collapsible: [{
@@ -372,11 +382,11 @@ class RouteInfoCardComponent {
372
382
  X,
373
383
  };
374
384
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: RouteInfoCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
375
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: RouteInfoCardComponent, isStandalone: true, selector: "lib-route-info-card", inputs: { modalOpen: { classPropertyName: "modalOpen", publicName: "modalOpen", isSignal: true, isRequired: false, transformFunction: null }, routeData: { classPropertyName: "routeData", publicName: "routeData", isSignal: true, isRequired: false, transformFunction: null }, repository: { classPropertyName: "repository", publicName: "repository", isSignal: true, isRequired: false, transformFunction: null }, displayMode: { classPropertyName: "displayMode", publicName: "displayMode", isSignal: true, isRequired: false, transformFunction: null }, noBackdrop: { classPropertyName: "noBackdrop", publicName: "noBackdrop", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { modalOpenChange: "modalOpenChange", edit: "edit" }, ngImport: i0, template: "@if (modalOpen()) {\n<div \n class=\"z-[112] bottom-0 fixed lg:absolute inset-0 overflow-y-auto\"\n [ngClass]=\"displayMode() === 'catalog' ? 'lg:left-[350px]' : 'lg:right-[350px]'\"\n [class.pointer-events-none]=\"noBackdrop()\"\n>\n <div \n class=\"flex min-h-full lg:items-end items-center justify-center p-3\"\n [ngClass]=\"displayMode() === 'catalog' ? 'lg:justify-start' : 'lg:justify-end'\"\n >\n <div\n class=\"relative bg-white dark:bg-slate-800 rounded-lg shadow-xl animate-slide-up w-[350px] pointer-events-auto\"\n (click)=\"$event.stopPropagation()\"\n >\n <div\n class=\"flex items-center justify-between px-[12px] py-[10px] border-b border-gray-200 dark:border-slate-700 dark:bg-slate-900 rounded-t-lg\"\n >\n <h3 class=\"flex items-center gap-1 font-medium text-gray-900 dark:text-white text-[13px]\">\n Route Info\n </h3>\n <button\n (click)=\"close()\"\n class=\"p-2 hover:bg-gray-100 dark:hover:bg-slate-700 rounded-lg transition-colors\"\n >\n <lucide-icon [img]=\"icons.X\" [size]=\"20\"></lucide-icon>\n </button>\n </div>\n <div class=\"max-h-[60vh] overflow-y-auto p-3\">\n <div class=\"space-y-2 bg-gray-50 dark:bg-slate-900/50 border border-gray-200 dark:border-slate-700 p-3 rounded-lg mb-4\">\n <p class=\"text-xs\">\n <b class=\"text-gray-900 dark:text-white\">Pickup:</b> \n <span class=\"text-gray-600 dark:text-gray-400\">\n {{ (routeData()?.pickup_location || '').split('|')[1] || routeData()?.pickup_location || 'N/A' }}\n </span>\n </p>\n <p class=\"text-xs\">\n <b class=\"text-gray-900 dark:text-white\">Delivery:</b> \n <span class=\"text-gray-600 dark:text-gray-400\">\n {{ (routeData()?.delivery_location || '').split('|')[1] || routeData()?.delivery_location || 'N/A' }}\n </span>\n </p>\n </div>\n\n <div class=\"space-y-2.5\">\n <div class=\"flex justify-between items-start text-xs border-b border-gray-100 dark:border-slate-700/50 pb-2\">\n <b class=\"text-gray-900 dark:text-white whitespace-nowrap\">Name:</b>\n <span class=\"text-gray-600 dark:text-gray-400 text-right ml-4\">{{ routeData()?.route_name || 'N/A' }}</span>\n </div>\n <div class=\"flex justify-between items-start text-xs border-b border-gray-100 dark:border-slate-700/50 pb-2\">\n <b class=\"text-gray-900 dark:text-white whitespace-nowrap\">Customer:</b>\n <span class=\"text-gray-600 dark:text-gray-400 text-right ml-4\">{{ routeData()?.customer_name || 'N/A' }}</span>\n </div>\n <div class=\"flex justify-between items-start text-xs border-b border-gray-100 dark:border-slate-700/50 pb-2\">\n <b class=\"text-gray-900 dark:text-white whitespace-nowrap\">Type:</b>\n <span class=\"text-gray-600 dark:text-gray-400 text-right ml-4\">{{ routeData()?.unit || 'N/A' }}</span>\n </div>\n <div class=\"flex justify-between items-start text-xs border-b border-gray-100 dark:border-slate-700/50 pb-2\">\n <b class=\"text-gray-900 dark:text-white whitespace-nowrap\">Distance:</b>\n <span class=\"text-gray-600 dark:text-gray-400 text-right ml-4\">{{ routeData()?.estimated_distance || '0' }} Miles</span>\n </div>\n <div class=\"flex justify-between items-start text-xs border-b border-gray-100 dark:border-slate-700/50 pb-2\">\n <b class=\"text-gray-900 dark:text-white whitespace-nowrap\">Travel Time:</b>\n <span class=\"text-gray-600 dark:text-gray-400 text-right ml-4\">{{ routeData()?.estimated_time || '0' }} Min</span>\n </div>\n\n @if (repository() !== 'customer') {\n <div class=\"flex justify-between items-start text-xs border-b border-gray-100 dark:border-slate-700/50 pb-2\">\n <b class=\"text-gray-900 dark:text-white whitespace-nowrap\">Trucker Pay Estimate:</b>\n <span class=\"text-brand-blue font-medium text-right ml-4\">{{ routeData()?.trucker_pay_estimate | currency }}</span>\n </div>\n }\n\n <div class=\"flex justify-between items-start text-xs border-b border-gray-100 dark:border-slate-700/50 pb-2\">\n <b class=\"text-gray-900 dark:text-white whitespace-nowrap\">Customer Price Estimate:</b>\n <span class=\"text-brand-blue font-medium text-right ml-4\">{{ routeData()?.customer_price_estimate | currency }}</span>\n </div>\n\n <div class=\"flex justify-between items-start text-xs dark:border-slate-700/50 pb-2\">\n <b class=\"text-gray-900 dark:text-white whitespace-nowrap\">Notes:</b>\n <span class=\"text-gray-600 dark:text-gray-400 text-right ml-4 italic\">{{ routeData()?.note || 'None' }}</span>\n </div>\n </div>\n\n <div class=\"mt-4 pt-3 border-t border-gray-100 dark:border-slate-700 flex justify-between items-center\">\n <p class=\"text-[10px] text-gray-400 italic\">\n Created by {{ routeData()?.created_by_name || routeData()?.user || 'System' }} on {{ formattedDate() }}\n </p>\n @if (displayMode() === 'catalog') {\n <button \n type=\"button\"\n (click)=\"edit.emit(); close()\"\n class=\"px-3 py-1 text-[11px] font-bold uppercase tracking-wider bg-orange-500 hover:bg-orange-600 text-white rounded transition-colors\"\n >\n Edit\n </button>\n }\n </div>\n </div>\n </div>\n </div>\n</div>\n}", styles: [".location-flow{display:flex;flex-direction:column;align-items:flex-start;gap:4px;font-size:11px;color:var(--text-secondary, #64748b);margin-bottom:6px}.location-flow .pickup{display:flex;align-items:flex-start;gap:3px;color:#22c55e}.location-flow .pickup svg{width:8px;height:8px;margin-top:4px}.location-flow .delivery{display:flex;align-items:flex-start;gap:3px;color:#ef4444}.location-flow .delivery svg{width:8px;height:8px;margin-top:4px}@keyframes slide-up{0%{opacity:0;transform:translateY(10px) scale(.95)}to{opacity:1;transform:translateY(0) scale(1)}}.animate-fade-in{animation:fade-in .2s ease-out}.animate-slide-up{animation:slide-up .2s ease-out}\n"], dependencies: [{ kind: "ngmodule", type: LucideAngularModule }, { kind: "component", type: i1.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "pipe", type: i2.CurrencyPipe, name: "currency" }] });
385
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: RouteInfoCardComponent, isStandalone: true, selector: "lib-route-info-card", inputs: { modalOpen: { classPropertyName: "modalOpen", publicName: "modalOpen", isSignal: true, isRequired: false, transformFunction: null }, routeData: { classPropertyName: "routeData", publicName: "routeData", isSignal: true, isRequired: false, transformFunction: null }, repository: { classPropertyName: "repository", publicName: "repository", isSignal: true, isRequired: false, transformFunction: null }, displayMode: { classPropertyName: "displayMode", publicName: "displayMode", isSignal: true, isRequired: false, transformFunction: null }, noBackdrop: { classPropertyName: "noBackdrop", publicName: "noBackdrop", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { modalOpenChange: "modalOpenChange", edit: "edit" }, ngImport: i0, template: "@if (modalOpen()) {\n<div \n class=\"z-[112] bottom-0 fixed lg:absolute inset-0 overflow-y-auto\"\n [ngClass]=\"displayMode() === 'catalog' ? 'lg:left-[350px]' : 'lg:right-[350px]'\"\n [class.pointer-events-none]=\"noBackdrop()\"\n>\n <div \n class=\"flex min-h-full lg:items-end items-center justify-center p-3\"\n [ngClass]=\"displayMode() === 'catalog' ? 'lg:justify-start' : 'lg:justify-end'\"\n >\n <div\n class=\"relative bg-white dark:bg-slate-800 rounded-lg shadow-xl animate-slide-up w-[350px] pointer-events-auto\"\n (click)=\"$event.stopPropagation()\"\n >\n <div\n class=\"flex items-center justify-between px-[12px] py-[10px] border-b border-gray-200 dark:border-slate-700 dark:bg-slate-900 rounded-t-lg\"\n >\n <h3 class=\"flex items-center gap-1 font-medium text-gray-900 dark:text-white text-[13px]\">\n Route Info\n </h3>\n <button\n (click)=\"close()\"\n class=\"p-2 hover:bg-gray-100 dark:hover:bg-slate-700 rounded-lg transition-colors\"\n >\n <lucide-icon [img]=\"icons.X\" [size]=\"20\"></lucide-icon>\n </button>\n </div>\n <div class=\"max-h-[60vh] overflow-y-auto p-3\">\n <div class=\"space-y-2 bg-gray-50 dark:bg-slate-900/50 border border-gray-200 dark:border-slate-700 p-3 rounded-lg mb-4\">\n <p class=\"text-xs\">\n <b class=\"text-gray-900 dark:text-white\">Pickup:</b> \n <span class=\"text-gray-600 dark:text-gray-400\">\n {{ (routeData()?.pickup_location || '').split('|')[1] || routeData()?.pickup_location || 'N/A' }}\n </span>\n </p>\n <p class=\"text-xs\">\n <b class=\"text-gray-900 dark:text-white\">Delivery:</b> \n <span class=\"text-gray-600 dark:text-gray-400\">\n {{ (routeData()?.delivery_location || '').split('|')[1] || routeData()?.delivery_location || 'N/A' }}\n </span>\n </p>\n </div>\n\n <div class=\"space-y-2.5\">\n <div class=\"flex justify-between items-start text-xs border-b border-gray-100 dark:border-slate-700/50 pb-2\">\n <b class=\"text-gray-900 dark:text-white whitespace-nowrap\">Name:</b>\n <span class=\"text-gray-600 dark:text-gray-400 text-right ml-4\">{{ routeData()?.route_name || 'N/A' }}</span>\n </div>\n <div class=\"flex justify-between items-start text-xs border-b border-gray-100 dark:border-slate-700/50 pb-2\">\n <b class=\"text-gray-900 dark:text-white whitespace-nowrap\">Customer:</b>\n <span class=\"text-gray-600 dark:text-gray-400 text-right ml-4\">{{ routeData()?.customer_name || 'N/A' }}</span>\n </div>\n <div class=\"flex justify-between items-start text-xs border-b border-gray-100 dark:border-slate-700/50 pb-2\">\n <b class=\"text-gray-900 dark:text-white whitespace-nowrap\">Type:</b>\n <span class=\"text-gray-600 dark:text-gray-400 text-right ml-4\">{{ routeData()?.unit || 'N/A' }}</span>\n </div>\n <div class=\"flex justify-between items-start text-xs border-b border-gray-100 dark:border-slate-700/50 pb-2\">\n <b class=\"text-gray-900 dark:text-white whitespace-nowrap\">Distance:</b>\n <span class=\"text-gray-600 dark:text-gray-400 text-right ml-4\">{{ routeData()?.estimated_distance || '0' }} Miles</span>\n </div>\n <div class=\"flex justify-between items-start text-xs border-b border-gray-100 dark:border-slate-700/50 pb-2\">\n <b class=\"text-gray-900 dark:text-white whitespace-nowrap\">Travel Time:</b>\n <span class=\"text-gray-600 dark:text-gray-400 text-right ml-4\">{{ routeData()?.estimated_time || '0' }} Min</span>\n </div>\n\n @if (repository() !== 'customer') {\n <div class=\"flex justify-between items-start text-xs border-b border-gray-100 dark:border-slate-700/50 pb-2\">\n <b class=\"text-gray-900 dark:text-white whitespace-nowrap\">Trucker Pay Estimate:</b>\n <span class=\"text-gray-600 dark:text-gray-400 font-medium text-right ml-4\">{{ routeData()?.trucker_pay_estimate | currency }}</span>\n </div>\n }\n\n <div class=\"flex justify-between items-start text-xs border-b border-gray-100 dark:border-slate-700/50 pb-2\">\n <b class=\"text-gray-900 dark:text-white whitespace-nowrap\">Customer Price Estimate:</b>\n <span class=\"text-gray-600 dark:text-gray-400 font-medium text-right ml-4\">{{ routeData()?.customer_price_estimate | currency }}</span>\n </div>\n\n <div class=\"flex justify-between items-start text-xs dark:border-slate-700/50 pb-2\">\n <b class=\"text-gray-900 dark:text-white whitespace-nowrap\">Notes:</b>\n <span class=\"text-gray-600 dark:text-gray-400 text-right ml-4 italic\">{{ routeData()?.note || 'None' }}</span>\n </div>\n </div>\n\n <div class=\"mt-4 pt-3 border-t border-gray-100 dark:border-slate-700 flex justify-between items-center\">\n <p class=\"text-[10px] text-gray-400 italic\">\n Created by {{ routeData()?.created_by_name || routeData()?.user || 'System' }} on {{ formattedDate() }}\n </p>\n @if (displayMode() === 'catalog') {\n <button \n type=\"button\"\n (click)=\"edit.emit(); close()\"\n class=\"px-3 py-1 text-[11px] font-bold uppercase tracking-wider bg-orange-500 hover:bg-orange-600 text-white rounded transition-colors\"\n >\n Edit\n </button>\n }\n </div>\n </div>\n </div>\n </div>\n</div>\n}", styles: [".location-flow{display:flex;flex-direction:column;align-items:flex-start;gap:4px;font-size:11px;color:var(--text-secondary, #64748b);margin-bottom:6px}.location-flow .pickup{display:flex;align-items:flex-start;gap:3px;color:#22c55e}.location-flow .pickup svg{width:8px;height:8px;margin-top:4px}.location-flow .delivery{display:flex;align-items:flex-start;gap:3px;color:#ef4444}.location-flow .delivery svg{width:8px;height:8px;margin-top:4px}@keyframes slide-up{0%{opacity:0;transform:translateY(10px) scale(.95)}to{opacity:1;transform:translateY(0) scale(1)}}.animate-fade-in{animation:fade-in .2s ease-out}.animate-slide-up{animation:slide-up .2s ease-out}\n"], dependencies: [{ kind: "ngmodule", type: LucideAngularModule }, { kind: "component", type: i1.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "pipe", type: i2.CurrencyPipe, name: "currency" }] });
376
386
  }
377
387
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: RouteInfoCardComponent, decorators: [{
378
388
  type: Component,
379
- args: [{ selector: 'lib-route-info-card', standalone: true, imports: [LucideAngularModule, CommonModule, CurrencyPipe], template: "@if (modalOpen()) {\n<div \n class=\"z-[112] bottom-0 fixed lg:absolute inset-0 overflow-y-auto\"\n [ngClass]=\"displayMode() === 'catalog' ? 'lg:left-[350px]' : 'lg:right-[350px]'\"\n [class.pointer-events-none]=\"noBackdrop()\"\n>\n <div \n class=\"flex min-h-full lg:items-end items-center justify-center p-3\"\n [ngClass]=\"displayMode() === 'catalog' ? 'lg:justify-start' : 'lg:justify-end'\"\n >\n <div\n class=\"relative bg-white dark:bg-slate-800 rounded-lg shadow-xl animate-slide-up w-[350px] pointer-events-auto\"\n (click)=\"$event.stopPropagation()\"\n >\n <div\n class=\"flex items-center justify-between px-[12px] py-[10px] border-b border-gray-200 dark:border-slate-700 dark:bg-slate-900 rounded-t-lg\"\n >\n <h3 class=\"flex items-center gap-1 font-medium text-gray-900 dark:text-white text-[13px]\">\n Route Info\n </h3>\n <button\n (click)=\"close()\"\n class=\"p-2 hover:bg-gray-100 dark:hover:bg-slate-700 rounded-lg transition-colors\"\n >\n <lucide-icon [img]=\"icons.X\" [size]=\"20\"></lucide-icon>\n </button>\n </div>\n <div class=\"max-h-[60vh] overflow-y-auto p-3\">\n <div class=\"space-y-2 bg-gray-50 dark:bg-slate-900/50 border border-gray-200 dark:border-slate-700 p-3 rounded-lg mb-4\">\n <p class=\"text-xs\">\n <b class=\"text-gray-900 dark:text-white\">Pickup:</b> \n <span class=\"text-gray-600 dark:text-gray-400\">\n {{ (routeData()?.pickup_location || '').split('|')[1] || routeData()?.pickup_location || 'N/A' }}\n </span>\n </p>\n <p class=\"text-xs\">\n <b class=\"text-gray-900 dark:text-white\">Delivery:</b> \n <span class=\"text-gray-600 dark:text-gray-400\">\n {{ (routeData()?.delivery_location || '').split('|')[1] || routeData()?.delivery_location || 'N/A' }}\n </span>\n </p>\n </div>\n\n <div class=\"space-y-2.5\">\n <div class=\"flex justify-between items-start text-xs border-b border-gray-100 dark:border-slate-700/50 pb-2\">\n <b class=\"text-gray-900 dark:text-white whitespace-nowrap\">Name:</b>\n <span class=\"text-gray-600 dark:text-gray-400 text-right ml-4\">{{ routeData()?.route_name || 'N/A' }}</span>\n </div>\n <div class=\"flex justify-between items-start text-xs border-b border-gray-100 dark:border-slate-700/50 pb-2\">\n <b class=\"text-gray-900 dark:text-white whitespace-nowrap\">Customer:</b>\n <span class=\"text-gray-600 dark:text-gray-400 text-right ml-4\">{{ routeData()?.customer_name || 'N/A' }}</span>\n </div>\n <div class=\"flex justify-between items-start text-xs border-b border-gray-100 dark:border-slate-700/50 pb-2\">\n <b class=\"text-gray-900 dark:text-white whitespace-nowrap\">Type:</b>\n <span class=\"text-gray-600 dark:text-gray-400 text-right ml-4\">{{ routeData()?.unit || 'N/A' }}</span>\n </div>\n <div class=\"flex justify-between items-start text-xs border-b border-gray-100 dark:border-slate-700/50 pb-2\">\n <b class=\"text-gray-900 dark:text-white whitespace-nowrap\">Distance:</b>\n <span class=\"text-gray-600 dark:text-gray-400 text-right ml-4\">{{ routeData()?.estimated_distance || '0' }} Miles</span>\n </div>\n <div class=\"flex justify-between items-start text-xs border-b border-gray-100 dark:border-slate-700/50 pb-2\">\n <b class=\"text-gray-900 dark:text-white whitespace-nowrap\">Travel Time:</b>\n <span class=\"text-gray-600 dark:text-gray-400 text-right ml-4\">{{ routeData()?.estimated_time || '0' }} Min</span>\n </div>\n\n @if (repository() !== 'customer') {\n <div class=\"flex justify-between items-start text-xs border-b border-gray-100 dark:border-slate-700/50 pb-2\">\n <b class=\"text-gray-900 dark:text-white whitespace-nowrap\">Trucker Pay Estimate:</b>\n <span class=\"text-brand-blue font-medium text-right ml-4\">{{ routeData()?.trucker_pay_estimate | currency }}</span>\n </div>\n }\n\n <div class=\"flex justify-between items-start text-xs border-b border-gray-100 dark:border-slate-700/50 pb-2\">\n <b class=\"text-gray-900 dark:text-white whitespace-nowrap\">Customer Price Estimate:</b>\n <span class=\"text-brand-blue font-medium text-right ml-4\">{{ routeData()?.customer_price_estimate | currency }}</span>\n </div>\n\n <div class=\"flex justify-between items-start text-xs dark:border-slate-700/50 pb-2\">\n <b class=\"text-gray-900 dark:text-white whitespace-nowrap\">Notes:</b>\n <span class=\"text-gray-600 dark:text-gray-400 text-right ml-4 italic\">{{ routeData()?.note || 'None' }}</span>\n </div>\n </div>\n\n <div class=\"mt-4 pt-3 border-t border-gray-100 dark:border-slate-700 flex justify-between items-center\">\n <p class=\"text-[10px] text-gray-400 italic\">\n Created by {{ routeData()?.created_by_name || routeData()?.user || 'System' }} on {{ formattedDate() }}\n </p>\n @if (displayMode() === 'catalog') {\n <button \n type=\"button\"\n (click)=\"edit.emit(); close()\"\n class=\"px-3 py-1 text-[11px] font-bold uppercase tracking-wider bg-orange-500 hover:bg-orange-600 text-white rounded transition-colors\"\n >\n Edit\n </button>\n }\n </div>\n </div>\n </div>\n </div>\n</div>\n}", styles: [".location-flow{display:flex;flex-direction:column;align-items:flex-start;gap:4px;font-size:11px;color:var(--text-secondary, #64748b);margin-bottom:6px}.location-flow .pickup{display:flex;align-items:flex-start;gap:3px;color:#22c55e}.location-flow .pickup svg{width:8px;height:8px;margin-top:4px}.location-flow .delivery{display:flex;align-items:flex-start;gap:3px;color:#ef4444}.location-flow .delivery svg{width:8px;height:8px;margin-top:4px}@keyframes slide-up{0%{opacity:0;transform:translateY(10px) scale(.95)}to{opacity:1;transform:translateY(0) scale(1)}}.animate-fade-in{animation:fade-in .2s ease-out}.animate-slide-up{animation:slide-up .2s ease-out}\n"] }]
389
+ args: [{ selector: 'lib-route-info-card', standalone: true, imports: [LucideAngularModule, CommonModule, CurrencyPipe], template: "@if (modalOpen()) {\n<div \n class=\"z-[112] bottom-0 fixed lg:absolute inset-0 overflow-y-auto\"\n [ngClass]=\"displayMode() === 'catalog' ? 'lg:left-[350px]' : 'lg:right-[350px]'\"\n [class.pointer-events-none]=\"noBackdrop()\"\n>\n <div \n class=\"flex min-h-full lg:items-end items-center justify-center p-3\"\n [ngClass]=\"displayMode() === 'catalog' ? 'lg:justify-start' : 'lg:justify-end'\"\n >\n <div\n class=\"relative bg-white dark:bg-slate-800 rounded-lg shadow-xl animate-slide-up w-[350px] pointer-events-auto\"\n (click)=\"$event.stopPropagation()\"\n >\n <div\n class=\"flex items-center justify-between px-[12px] py-[10px] border-b border-gray-200 dark:border-slate-700 dark:bg-slate-900 rounded-t-lg\"\n >\n <h3 class=\"flex items-center gap-1 font-medium text-gray-900 dark:text-white text-[13px]\">\n Route Info\n </h3>\n <button\n (click)=\"close()\"\n class=\"p-2 hover:bg-gray-100 dark:hover:bg-slate-700 rounded-lg transition-colors\"\n >\n <lucide-icon [img]=\"icons.X\" [size]=\"20\"></lucide-icon>\n </button>\n </div>\n <div class=\"max-h-[60vh] overflow-y-auto p-3\">\n <div class=\"space-y-2 bg-gray-50 dark:bg-slate-900/50 border border-gray-200 dark:border-slate-700 p-3 rounded-lg mb-4\">\n <p class=\"text-xs\">\n <b class=\"text-gray-900 dark:text-white\">Pickup:</b> \n <span class=\"text-gray-600 dark:text-gray-400\">\n {{ (routeData()?.pickup_location || '').split('|')[1] || routeData()?.pickup_location || 'N/A' }}\n </span>\n </p>\n <p class=\"text-xs\">\n <b class=\"text-gray-900 dark:text-white\">Delivery:</b> \n <span class=\"text-gray-600 dark:text-gray-400\">\n {{ (routeData()?.delivery_location || '').split('|')[1] || routeData()?.delivery_location || 'N/A' }}\n </span>\n </p>\n </div>\n\n <div class=\"space-y-2.5\">\n <div class=\"flex justify-between items-start text-xs border-b border-gray-100 dark:border-slate-700/50 pb-2\">\n <b class=\"text-gray-900 dark:text-white whitespace-nowrap\">Name:</b>\n <span class=\"text-gray-600 dark:text-gray-400 text-right ml-4\">{{ routeData()?.route_name || 'N/A' }}</span>\n </div>\n <div class=\"flex justify-between items-start text-xs border-b border-gray-100 dark:border-slate-700/50 pb-2\">\n <b class=\"text-gray-900 dark:text-white whitespace-nowrap\">Customer:</b>\n <span class=\"text-gray-600 dark:text-gray-400 text-right ml-4\">{{ routeData()?.customer_name || 'N/A' }}</span>\n </div>\n <div class=\"flex justify-between items-start text-xs border-b border-gray-100 dark:border-slate-700/50 pb-2\">\n <b class=\"text-gray-900 dark:text-white whitespace-nowrap\">Type:</b>\n <span class=\"text-gray-600 dark:text-gray-400 text-right ml-4\">{{ routeData()?.unit || 'N/A' }}</span>\n </div>\n <div class=\"flex justify-between items-start text-xs border-b border-gray-100 dark:border-slate-700/50 pb-2\">\n <b class=\"text-gray-900 dark:text-white whitespace-nowrap\">Distance:</b>\n <span class=\"text-gray-600 dark:text-gray-400 text-right ml-4\">{{ routeData()?.estimated_distance || '0' }} Miles</span>\n </div>\n <div class=\"flex justify-between items-start text-xs border-b border-gray-100 dark:border-slate-700/50 pb-2\">\n <b class=\"text-gray-900 dark:text-white whitespace-nowrap\">Travel Time:</b>\n <span class=\"text-gray-600 dark:text-gray-400 text-right ml-4\">{{ routeData()?.estimated_time || '0' }} Min</span>\n </div>\n\n @if (repository() !== 'customer') {\n <div class=\"flex justify-between items-start text-xs border-b border-gray-100 dark:border-slate-700/50 pb-2\">\n <b class=\"text-gray-900 dark:text-white whitespace-nowrap\">Trucker Pay Estimate:</b>\n <span class=\"text-gray-600 dark:text-gray-400 font-medium text-right ml-4\">{{ routeData()?.trucker_pay_estimate | currency }}</span>\n </div>\n }\n\n <div class=\"flex justify-between items-start text-xs border-b border-gray-100 dark:border-slate-700/50 pb-2\">\n <b class=\"text-gray-900 dark:text-white whitespace-nowrap\">Customer Price Estimate:</b>\n <span class=\"text-gray-600 dark:text-gray-400 font-medium text-right ml-4\">{{ routeData()?.customer_price_estimate | currency }}</span>\n </div>\n\n <div class=\"flex justify-between items-start text-xs dark:border-slate-700/50 pb-2\">\n <b class=\"text-gray-900 dark:text-white whitespace-nowrap\">Notes:</b>\n <span class=\"text-gray-600 dark:text-gray-400 text-right ml-4 italic\">{{ routeData()?.note || 'None' }}</span>\n </div>\n </div>\n\n <div class=\"mt-4 pt-3 border-t border-gray-100 dark:border-slate-700 flex justify-between items-center\">\n <p class=\"text-[10px] text-gray-400 italic\">\n Created by {{ routeData()?.created_by_name || routeData()?.user || 'System' }} on {{ formattedDate() }}\n </p>\n @if (displayMode() === 'catalog') {\n <button \n type=\"button\"\n (click)=\"edit.emit(); close()\"\n class=\"px-3 py-1 text-[11px] font-bold uppercase tracking-wider bg-orange-500 hover:bg-orange-600 text-white rounded transition-colors\"\n >\n Edit\n </button>\n }\n </div>\n </div>\n </div>\n </div>\n</div>\n}", styles: [".location-flow{display:flex;flex-direction:column;align-items:flex-start;gap:4px;font-size:11px;color:var(--text-secondary, #64748b);margin-bottom:6px}.location-flow .pickup{display:flex;align-items:flex-start;gap:3px;color:#22c55e}.location-flow .pickup svg{width:8px;height:8px;margin-top:4px}.location-flow .delivery{display:flex;align-items:flex-start;gap:3px;color:#ef4444}.location-flow .delivery svg{width:8px;height:8px;margin-top:4px}@keyframes slide-up{0%{opacity:0;transform:translateY(10px) scale(.95)}to{opacity:1;transform:translateY(0) scale(1)}}.animate-fade-in{animation:fade-in .2s ease-out}.animate-slide-up{animation:slide-up .2s ease-out}\n"] }]
380
390
  }], propDecorators: { modalOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "modalOpen", required: false }] }], routeData: [{ type: i0.Input, args: [{ isSignal: true, alias: "routeData", required: false }] }], repository: [{ type: i0.Input, args: [{ isSignal: true, alias: "repository", required: false }] }], displayMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "displayMode", required: false }] }], noBackdrop: [{ type: i0.Input, args: [{ isSignal: true, alias: "noBackdrop", required: false }] }], modalOpenChange: [{
381
391
  type: Output
382
392
  }], edit: [{
@@ -585,11 +595,11 @@ class JobRouteListComponent {
585
595
  LoaderCircle
586
596
  };
587
597
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: JobRouteListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
588
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: JobRouteListComponent, isStandalone: true, selector: "lib-job-route-list", inputs: { customerRepoDetails: { classPropertyName: "customerRepoDetails", publicName: "customerRepoDetails", isSignal: false, isRequired: false, transformFunction: null }, selectedRouteIds: { classPropertyName: "selectedRouteIds", publicName: "selectedRouteIds", isSignal: true, isRequired: false, transformFunction: null }, modalOpen: { classPropertyName: "modalOpen", publicName: "modalOpen", isSignal: true, isRequired: false, transformFunction: null }, initialRoutes: { classPropertyName: "initialRoutes", publicName: "initialRoutes", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { modalOpenChange: "modalOpenChange", routeSelect: "routeSelect", masterToggleEvent: "masterToggleEvent", shareRoute: "shareRoute" }, ngImport: i0, template: "@if (modalOpen()) {\n<div class=\"fixed z-[111] route-list\">\n <!-- <div class=\"fixed inset-0 bg-black/50\" (click)=\"close()\"></div> -->\n <aside class=\"detail-drawer top-[0] sm:top-[115px]\" (click)=\"$event.stopPropagation()\">\n <div\n class=\"flex items-center justify-between px-[12px] py-[10px] border-b border-gray-200 dark:border-slate-700 dark:bg-slate-900\"\n >\n <h3 class=\"flex items-center gap-1 font-semibold text-gray-900 dark:text-white text-[14px]\">\n List of Routes\n <span class=\"text-xs font-normal text-gray-400\">({{ filteredRoutes().length }})</span>\n </h3>\n <button\n type=\"button\"\n (click)=\"onMasterToggle()\"\n [disabled]=\"isAnyPlotting()\"\n class=\"inline-flex items-center justify-center gap-2 px-3 sm:px-4 py-1.5 bg-brand-blue hover:bg-blue-700 disabled:opacity-50 text-white font-medium rounded-md transition-colors text-[12px]\"\n >\n {{ allSelected() ? 'Uncheck All' : 'Check All' }}\n </button>\n <button\n (click)=\"close()\"\n class=\"p-1.5 hover:bg-gray-100 dark:hover:bg-slate-700 rounded-lg transition-colors\"\n >\n <lucide-icon [img]=\"icons.X\" [size]=\"18\"></lucide-icon>\n </button>\n </div>\n <div class=\"p-2\">\n <div class=\"relative w-full\">\n <div class=\"absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none\">\n <lucide-icon [img]=\"hasFilter ? icons.Info : icons.Search\" class=\"text-gray-400\" [size]=\"18\"></lucide-icon>\n </div>\n <input\n type=\"text\"\n #searchinput\n [value]=\"searchTerm()\"\n (input)=\"handleSearchInput(searchinput.value)\"\n (focus)=\"showSuggestions.set(true)\"\n (blur)=\"onSearchBlur()\"\n placeholder=\"Search...\"\n class=\"w-full pl-10 pr-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-white placeholder-gray-400 focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n />\n\n <!-- Autocomplete Suggestions Dropdown -->\n @if (showSuggestions() && suggestions().length > 0) {\n <div class=\"absolute z-50 w-full mt-1 bg-white dark:bg-gray-800 rounded-lg shadow-xl border border-gray-200 dark:border-gray-700 max-h-60 overflow-y-auto\">\n <ul class=\"py-1 text-sm text-gray-700 dark:text-gray-200\">\n @for (option of suggestions(); track option.label + option.type) {\n <li (click)=\"addFilter(option)\"\n class=\"px-4 py-2 hover:bg-brand-blue/10 dark:hover:bg-brand-blue/20 cursor-pointer flex justify-between items-center group\">\n <span>\n <span class=\"capitalize\">{{option.type}}:</span> \n {{option.label}}\n </span>\n <lucide-icon [img]=\"icons.CheckCircle\" class=\"opacity-0 group-hover:opacity-100 text-brand-blue transition-opacity\" [size]=\"16\"></lucide-icon>\n </li>\n }\n </ul>\n </div>\n }\n </div>\n\n <!-- Active Filter Chips -->\n @if (hasFilter) {\n <div class=\"flex flex-wrap gap-2 mt-2 px-1\">\n @for (filter of filters(); track filter.name + filter.type) {\n <div class=\"inline-flex items-center gap-1.5 px-3 py-1 bg-brand-blue/10 border border-brand-blue/20 text-black dark:text-white rounded-full text-xs font-medium\">\n <span class=\"capitalize\">{{filter.type}}:</span>\n <span class=\"truncate max-w-[150px]\">{{filter.name}}</span>\n <button (click)=\"removeFilter()\" class=\"hover:text-red-500 transition-colors\">\n <lucide-icon [img]=\"icons.X\" [size]=\"14\"></lucide-icon>\n </button>\n </div>\n }\n </div>\n }\n </div>\n <div class=\"overflow-y-auto p-2 drawer-listing-box\">\n <cdk-virtual-scroll-viewport itemSize=\"60\" class=\"routeList-viewport h-[calc(100vh-230px)]\">\n @if (filteredRoutes().length > 0) {\n <ul class=\"route-list-ul gap-2 flex flex-col\">\n @for (route of filteredRoutes(); track getRouteId(route)) {\n <li \n class=\"route-li-v1 bg-white dark:bg-slate-800 border border-gray-300 dark:border-slate-700\" \n [class.selected]=\"isRouteSelected(route)\" \n [class.pointer-events-none]=\"isAnyPlotting()\"\n [class.opacity-60]=\"isAnyPlotting()\"\n (click)=\"toggleRoute(route)\">\n <div class=\"task-header justify-between\">\n <span class=\"job-code\"> {{route.route_name || route.order_number}} </span>\n @if (config.repository === 'coolmap') {\n <span class=\"job-code\">{{route.customer_name}}</span>\n }\n <div class=\"iconprt\">\n @if (isPlotting(route)) {\n <div class=\"plotting-spinner\">\n <lucide-icon [img]=\"icons.LoaderCircle\" class=\"animate-spin text-black dark:text-white flex items-center justify-center relative z-10\" [size]=\"18\"></lucide-icon>\n </div>\n }\n <div class=\"statusunit text-white\" [ngClass]=\"route.unit || ''\">\n {{ route.unit?.charAt(0) || 'U' }}\n </div>\n <div class=\"infoicon\" \n (click)=\"$event.stopPropagation(); openDetail(route, true)\"\n (mouseenter)=\"openDetail(route, false)\"\n (mouseleave)=\"closeDetail(true)\">\n <lucide-icon [img]=\"icons.Info\" [size]=\"18\" class=\"text-gray-400\"></lucide-icon>\n </div>\n @if (config.repository === 'customer') {\n <div class=\"infoicon hover:opacity-80\" (click)=\"$event.stopPropagation(); shareRoute.emit(route)\">\n <lucide-icon [img]=\"icons.Share2\" [size]=\"16\" class=\"text-gray-400\"></lucide-icon>\n </div>\n }\n </div>\n </div>\n \n <div class=\"location-flow bg-gray-100 dark:bg-slate-900 px-2 py-2 pb-3 rounded-lg\">\n <span class=\"pickup\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"8\" />\n </svg>\n {{ (route.pickup_location || '').split('|')[1] ? (route.pickup_location || '').split('|')[1] : (route.pickup_location || '') }}\n </span>\n <span class=\"delivery\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"8\" />\n </svg>\n {{ (route.delivery_location || '').split('|')[1] ? (route.delivery_location || '').split('|')[1] : (route.delivery_location || '') }}\n </span>\n </div>\n </li>\n }\n </ul>\n } @else if (routes().length === 0) {\n <div class=\"p-8 text-center text-gray-400\">\n No routes available for this perspective.\n </div>\n }\n </cdk-virtual-scroll-viewport>\n </div>\n </aside>\n</div>\n}\n<lib-route-info-card [modalOpen]=\"showRouteModal\" (modalOpenChange)=\"$event ? null : closeDetail(false)\" [routeData]=\"selectedRoute()\" [repository]=\"config.repository\" displayMode=\"dispatch\" [noBackdrop]=\"!isClickTriggered\"></lib-route-info-card>\n", styles: [".detail-drawer{position:fixed;right:0;bottom:36px;width:280px;background:var(--bg-primary, white);border-left:1px solid var(--border-color, #e2e8f0);display:flex;flex-direction:column;z-index:501;animation:slideIn .2s ease;height:100vh}:host-context(.dark) .detail-drawer{background-color:#1e293b;border-color:#334155}.drawer-listing-box{flex:1;overflow:hidden;padding:0!important}.routeList-viewport{width:100%}.route-list-ul{list-style:none;padding:10px;margin:0}.route-li-v1{position:relative;padding:6px 10px;display:flex;flex-direction:column;gap:2px;border-radius:8px;cursor:pointer;transition:all .15s ease;min-height:72px}.route-li-v1:hover{background:#ffffff0d}.route-li-v1.selected{border:1px solid #3b82f6}.task-header{display:flex;align-items:center;gap:6px;margin-bottom:4px}.job-code{font-size:13px;font-weight:600;color:var(--text-primary, #1e293b);white-space:nowrap;text-overflow:ellipsis;max-width:190px;overflow:hidden}:host-context(.dark) .job-code{color:#f1f5f9}.iconprt{display:flex;flex-shrink:0;gap:5px}.plotting-spinner{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;background:#1e293bb3;border-radius:4px;z-index:10}.animate-spin{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.statusunit{border-radius:30px;font-size:11px;text-transform:capitalize;font-weight:600;width:18px;height:18px;text-align:center;line-height:18px}.statusunit.Ton{background:#ff7272}.statusunit.Load{background:#a3c52e}.statusunit.Hourly{background:#ae23d1}.pickprtbox{flex:1;min-width:0}.pickprtbox h2{font-size:14px;font-weight:600;color:#fff;margin:0;line-height:1.2}.pickprtbox h3{font-size:12px;color:#94a3b8;margin:2px 0 6px;font-weight:400}.pickdropprt{display:flex;flex-direction:column;gap:4px}.pickdropprt .pickprt,.pickdropprt .dropprt{color:#cbd5e1;font-size:11px}.pickdropprt .pickprt h4,.pickdropprt .dropprt h4{margin:0;font-weight:500;color:#94a3b8}.pickdropprt .pickprt.pickprt h4,.pickdropprt .dropprt.pickprt h4{color:#22c55e}.pickdropprt .pickprt.dropprt h4,.pickdropprt .dropprt.dropprt h4{color:#3b82f6}.infoicon{cursor:pointer}.infoicon:hover lucide-icon{color:#fff}@keyframes slideIn{0%{transform:translate(100%)}to{transform:translate(0)}}.animate-slide-in{animation:slideIn .2s ease}.location-flow{display:flex;flex-direction:column;align-items:flex-start;gap:2px;font-size:11px;color:var(--text-secondary, #64748b);margin-bottom:6px}.location-flow .pickup{display:inline;align-items:center;gap:3px;color:#22c55e;white-space:nowrap;text-overflow:ellipsis;max-width:200px;overflow:hidden;position:relative;padding-left:15px}.location-flow .pickup svg{width:8px;height:8px;position:absolute;left:0;top:5px}.location-flow .delivery{display:inline;align-items:center;gap:3px;color:#ef4444;white-space:nowrap;text-overflow:ellipsis;max-width:200px;overflow:hidden;position:relative;padding-left:15px;top:5px}.location-flow .delivery svg{width:8px;height:8px;position:absolute;left:0;top:5px}\n"], dependencies: [{ kind: "ngmodule", type: LucideAngularModule }, { kind: "component", type: i1.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }, { kind: "component", type: RouteInfoCardComponent, selector: "lib-route-info-card", inputs: ["modalOpen", "routeData", "repository", "displayMode", "noBackdrop"], outputs: ["modalOpenChange", "edit"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i2$1.CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "component", type: i2$1.CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }] });
598
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: JobRouteListComponent, isStandalone: true, selector: "lib-job-route-list", inputs: { customerRepoDetails: { classPropertyName: "customerRepoDetails", publicName: "customerRepoDetails", isSignal: false, isRequired: false, transformFunction: null }, selectedRouteIds: { classPropertyName: "selectedRouteIds", publicName: "selectedRouteIds", isSignal: true, isRequired: false, transformFunction: null }, modalOpen: { classPropertyName: "modalOpen", publicName: "modalOpen", isSignal: true, isRequired: false, transformFunction: null }, initialRoutes: { classPropertyName: "initialRoutes", publicName: "initialRoutes", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { modalOpenChange: "modalOpenChange", routeSelect: "routeSelect", masterToggleEvent: "masterToggleEvent", shareRoute: "shareRoute" }, ngImport: i0, template: "@if (modalOpen()) {\n<div class=\"fixed z-[11] route-list\">\n <!-- <div class=\"fixed inset-0 bg-black/50\" (click)=\"close()\"></div> -->\n <aside class=\"detail-drawer top-[0] sm:top-[115px]\" (click)=\"$event.stopPropagation()\">\n <div\n class=\"flex items-center justify-between px-[12px] py-[10px] border-b border-gray-200 dark:border-slate-700 dark:bg-slate-900\"\n >\n <h3 class=\"flex items-center gap-1 font-semibold text-gray-900 dark:text-white text-[14px]\">\n List of Routes\n <span class=\"text-xs font-normal text-gray-400\">({{ filteredRoutes().length }})</span>\n </h3>\n <button\n type=\"button\"\n (click)=\"onMasterToggle()\"\n [disabled]=\"isAnyPlotting()\"\n class=\"inline-flex items-center justify-center gap-2 px-3 sm:px-4 py-1.5 bg-brand-blue hover:bg-blue-700 disabled:opacity-50 text-white font-medium rounded-md transition-colors text-[12px]\"\n >\n {{ allSelected() ? 'Uncheck All' : 'Check All' }}\n </button>\n <button\n (click)=\"close()\"\n class=\"p-1.5 hover:bg-gray-100 dark:hover:bg-slate-700 rounded-lg transition-colors\"\n >\n <lucide-icon [img]=\"icons.X\" [size]=\"18\"></lucide-icon>\n </button>\n </div>\n <div class=\"p-2\">\n <div class=\"relative w-full\">\n <div class=\"absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none\">\n <lucide-icon [img]=\"hasFilter ? icons.Info : icons.Search\" class=\"text-gray-400\" [size]=\"18\"></lucide-icon>\n </div>\n <input\n type=\"text\"\n #searchinput\n [value]=\"searchTerm()\"\n (input)=\"handleSearchInput(searchinput.value)\"\n (focus)=\"showSuggestions.set(true)\"\n (blur)=\"onSearchBlur()\"\n placeholder=\"Search...\"\n class=\"w-full pl-10 pr-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-white placeholder-gray-400 focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n />\n\n <!-- Autocomplete Suggestions Dropdown -->\n @if (showSuggestions() && suggestions().length > 0) {\n <div class=\"absolute z-50 w-full mt-1 bg-white dark:bg-gray-800 rounded-lg shadow-xl border border-gray-200 dark:border-gray-700 max-h-60 overflow-y-auto\">\n <ul class=\"py-1 text-sm text-gray-700 dark:text-gray-200\">\n @for (option of suggestions(); track option.label + option.type) {\n <li (click)=\"addFilter(option)\"\n class=\"px-4 py-2 hover:bg-brand-blue/10 dark:hover:bg-brand-blue/20 cursor-pointer flex justify-between items-center group\">\n <span>\n <span class=\"capitalize\">{{option.type}}:</span> \n {{option.label}}\n </span>\n <lucide-icon [img]=\"icons.CheckCircle\" class=\"opacity-0 group-hover:opacity-100 text-brand-blue transition-opacity\" [size]=\"16\"></lucide-icon>\n </li>\n }\n </ul>\n </div>\n }\n </div>\n\n <!-- Active Filter Chips -->\n @if (hasFilter) {\n <div class=\"flex flex-wrap gap-2 mt-2 px-1\">\n @for (filter of filters(); track filter.name + filter.type) {\n <div class=\"inline-flex items-center gap-1.5 px-3 py-1 bg-slate-200 dark:bg-slate-700 border border-brand-blue/20 text-black dark:text-white rounded-full text-xs font-medium\">\n <span class=\"capitalize\">{{filter.type}}:</span>\n <span class=\"truncate max-w-[150px]\">{{filter.name}}</span>\n <button (click)=\"removeFilter()\" class=\"hover:text-red-500 transition-colors\">\n <lucide-icon [img]=\"icons.X\" [size]=\"14\"></lucide-icon>\n </button>\n </div>\n }\n </div>\n }\n </div>\n <div class=\"overflow-y-auto p-2 drawer-listing-box\">\n <cdk-virtual-scroll-viewport itemSize=\"60\" class=\"routeList-viewport h-[calc(100vh-230px)]\">\n @if (filteredRoutes().length > 0) {\n <ul class=\"route-list-ul gap-2 flex flex-col\">\n @for (route of filteredRoutes(); track getRouteId(route)) {\n <li \n class=\"route-li-v1 bg-white dark:bg-slate-800 border border-gray-300 dark:border-slate-700\" \n [class.selected]=\"isRouteSelected(route)\" \n [class.pointer-events-none]=\"isAnyPlotting()\"\n [class.opacity-60]=\"isAnyPlotting()\"\n (click)=\"toggleRoute(route)\">\n <div class=\"task-header justify-between\">\n <span class=\"job-code\"> {{route.route_name || route.order_number}} </span>\n @if (config.repository === 'coolmap') {\n <span class=\"job-code\">{{route.customer_name}}</span>\n }\n <div class=\"iconprt\">\n @if (isPlotting(route)) {\n <div class=\"plotting-spinner\">\n <lucide-icon [img]=\"icons.LoaderCircle\" class=\"animate-spin text-black dark:text-white flex items-center justify-center relative z-10\" [size]=\"18\"></lucide-icon>\n </div>\n }\n <div class=\"statusunit text-white\" [ngClass]=\"route.unit || ''\">\n {{ route.unit?.charAt(0) || 'U' }}\n </div>\n <div class=\"infoicon\" \n (click)=\"$event.stopPropagation(); openDetail(route, true)\"\n (mouseenter)=\"openDetail(route, false)\"\n (mouseleave)=\"closeDetail(true)\">\n <lucide-icon [img]=\"icons.Info\" [size]=\"18\" class=\"text-gray-400\"></lucide-icon>\n </div>\n @if (config.repository === 'customer') {\n <div class=\"infoicon hover:opacity-80\" (click)=\"$event.stopPropagation(); shareRoute.emit(route)\">\n <lucide-icon [img]=\"icons.Share2\" [size]=\"16\" class=\"text-gray-400\"></lucide-icon>\n </div>\n }\n </div>\n </div>\n \n <div class=\"location-flow bg-gray-100 dark:bg-slate-900 px-2 py-2 pb-3 rounded-lg\">\n <span class=\"pickup\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"8\" />\n </svg>\n {{ (route.pickup_location || '').split('|')[1] ? (route.pickup_location || '').split('|')[1] : (route.pickup_location || '') }}\n </span>\n <span class=\"delivery\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"8\" />\n </svg>\n {{ (route.delivery_location || '').split('|')[1] ? (route.delivery_location || '').split('|')[1] : (route.delivery_location || '') }}\n </span>\n </div>\n </li>\n }\n </ul>\n } @else if (routes().length === 0) {\n <div class=\"p-8 text-center text-gray-400\">\n No routes available for this perspective.\n </div>\n }\n </cdk-virtual-scroll-viewport>\n </div>\n </aside>\n</div>\n}\n<lib-route-info-card [modalOpen]=\"showRouteModal\" (modalOpenChange)=\"$event ? null : closeDetail(false)\" [routeData]=\"selectedRoute()\" [repository]=\"config.repository\" displayMode=\"dispatch\" [noBackdrop]=\"!isClickTriggered\"></lib-route-info-card>\n", styles: [".detail-drawer{position:fixed;right:0;bottom:36px;width:280px;background:var(--bg-primary, white);border-left:1px solid var(--border-color, #e2e8f0);display:flex;flex-direction:column;z-index:501;animation:slideIn .2s ease;height:100vh}:host-context(.dark) .detail-drawer{background-color:#1e293b;border-color:#334155}.drawer-listing-box{flex:1;overflow:hidden;padding:0!important}.routeList-viewport{width:100%}.route-list-ul{list-style:none;padding:10px;margin:0}.route-li-v1{position:relative;padding:6px 10px;display:flex;flex-direction:column;gap:2px;border-radius:8px;cursor:pointer;transition:all .15s ease;min-height:72px}.route-li-v1:hover{background:#ffffff0d}.route-li-v1.selected{border:1px solid #3b82f6}.task-header{display:flex;align-items:center;gap:6px;margin-bottom:4px}.job-code{font-size:13px;font-weight:600;color:var(--text-primary, #1e293b);white-space:nowrap;text-overflow:ellipsis;max-width:190px;overflow:hidden}:host-context(.dark) .job-code{color:#f1f5f9}.iconprt{display:flex;flex-shrink:0;gap:5px}.plotting-spinner{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;background:#1e293bb3;border-radius:4px;z-index:10}.animate-spin{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.statusunit{border-radius:30px;font-size:11px;text-transform:capitalize;font-weight:600;width:18px;height:18px;text-align:center;line-height:18px}.statusunit.Ton{background:#ff7272}.statusunit.Load{background:#a3c52e}.statusunit.Hourly{background:#ae23d1}.pickprtbox{flex:1;min-width:0}.pickprtbox h2{font-size:14px;font-weight:600;color:#fff;margin:0;line-height:1.2}.pickprtbox h3{font-size:12px;color:#94a3b8;margin:2px 0 6px;font-weight:400}.pickdropprt{display:flex;flex-direction:column;gap:4px}.pickdropprt .pickprt,.pickdropprt .dropprt{color:#cbd5e1;font-size:11px}.pickdropprt .pickprt h4,.pickdropprt .dropprt h4{margin:0;font-weight:500;color:#94a3b8}.pickdropprt .pickprt.pickprt h4,.pickdropprt .dropprt.pickprt h4{color:#22c55e}.pickdropprt .pickprt.dropprt h4,.pickdropprt .dropprt.dropprt h4{color:#3b82f6}.infoicon{cursor:pointer}.infoicon:hover lucide-icon{color:#fff}@keyframes slideIn{0%{transform:translate(100%)}to{transform:translate(0)}}.animate-slide-in{animation:slideIn .2s ease}.location-flow{display:flex;flex-direction:column;align-items:flex-start;gap:2px;font-size:11px;color:var(--text-secondary, #64748b);margin-bottom:6px}.location-flow .pickup{display:inline;align-items:center;gap:3px;color:#22c55e;white-space:nowrap;text-overflow:ellipsis;max-width:200px;overflow:hidden;position:relative;padding-left:15px}.location-flow .pickup svg{width:8px;height:8px;position:absolute;left:0;top:5px}.location-flow .delivery{display:inline;align-items:center;gap:3px;color:#ef4444;white-space:nowrap;text-overflow:ellipsis;max-width:200px;overflow:hidden;position:relative;padding-left:15px;top:5px}.location-flow .delivery svg{width:8px;height:8px;position:absolute;left:0;top:5px}\n"], dependencies: [{ kind: "ngmodule", type: LucideAngularModule }, { kind: "component", type: i1.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }, { kind: "component", type: RouteInfoCardComponent, selector: "lib-route-info-card", inputs: ["modalOpen", "routeData", "repository", "displayMode", "noBackdrop"], outputs: ["modalOpenChange", "edit"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i2$1.CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "component", type: i2$1.CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }] });
589
599
  }
590
600
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: JobRouteListComponent, decorators: [{
591
601
  type: Component,
592
- args: [{ selector: 'lib-job-route-list', standalone: true, imports: [LucideAngularModule, RouteInfoCardComponent, NgClass, ScrollingModule], template: "@if (modalOpen()) {\n<div class=\"fixed z-[111] route-list\">\n <!-- <div class=\"fixed inset-0 bg-black/50\" (click)=\"close()\"></div> -->\n <aside class=\"detail-drawer top-[0] sm:top-[115px]\" (click)=\"$event.stopPropagation()\">\n <div\n class=\"flex items-center justify-between px-[12px] py-[10px] border-b border-gray-200 dark:border-slate-700 dark:bg-slate-900\"\n >\n <h3 class=\"flex items-center gap-1 font-semibold text-gray-900 dark:text-white text-[14px]\">\n List of Routes\n <span class=\"text-xs font-normal text-gray-400\">({{ filteredRoutes().length }})</span>\n </h3>\n <button\n type=\"button\"\n (click)=\"onMasterToggle()\"\n [disabled]=\"isAnyPlotting()\"\n class=\"inline-flex items-center justify-center gap-2 px-3 sm:px-4 py-1.5 bg-brand-blue hover:bg-blue-700 disabled:opacity-50 text-white font-medium rounded-md transition-colors text-[12px]\"\n >\n {{ allSelected() ? 'Uncheck All' : 'Check All' }}\n </button>\n <button\n (click)=\"close()\"\n class=\"p-1.5 hover:bg-gray-100 dark:hover:bg-slate-700 rounded-lg transition-colors\"\n >\n <lucide-icon [img]=\"icons.X\" [size]=\"18\"></lucide-icon>\n </button>\n </div>\n <div class=\"p-2\">\n <div class=\"relative w-full\">\n <div class=\"absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none\">\n <lucide-icon [img]=\"hasFilter ? icons.Info : icons.Search\" class=\"text-gray-400\" [size]=\"18\"></lucide-icon>\n </div>\n <input\n type=\"text\"\n #searchinput\n [value]=\"searchTerm()\"\n (input)=\"handleSearchInput(searchinput.value)\"\n (focus)=\"showSuggestions.set(true)\"\n (blur)=\"onSearchBlur()\"\n placeholder=\"Search...\"\n class=\"w-full pl-10 pr-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-white placeholder-gray-400 focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n />\n\n <!-- Autocomplete Suggestions Dropdown -->\n @if (showSuggestions() && suggestions().length > 0) {\n <div class=\"absolute z-50 w-full mt-1 bg-white dark:bg-gray-800 rounded-lg shadow-xl border border-gray-200 dark:border-gray-700 max-h-60 overflow-y-auto\">\n <ul class=\"py-1 text-sm text-gray-700 dark:text-gray-200\">\n @for (option of suggestions(); track option.label + option.type) {\n <li (click)=\"addFilter(option)\"\n class=\"px-4 py-2 hover:bg-brand-blue/10 dark:hover:bg-brand-blue/20 cursor-pointer flex justify-between items-center group\">\n <span>\n <span class=\"capitalize\">{{option.type}}:</span> \n {{option.label}}\n </span>\n <lucide-icon [img]=\"icons.CheckCircle\" class=\"opacity-0 group-hover:opacity-100 text-brand-blue transition-opacity\" [size]=\"16\"></lucide-icon>\n </li>\n }\n </ul>\n </div>\n }\n </div>\n\n <!-- Active Filter Chips -->\n @if (hasFilter) {\n <div class=\"flex flex-wrap gap-2 mt-2 px-1\">\n @for (filter of filters(); track filter.name + filter.type) {\n <div class=\"inline-flex items-center gap-1.5 px-3 py-1 bg-brand-blue/10 border border-brand-blue/20 text-black dark:text-white rounded-full text-xs font-medium\">\n <span class=\"capitalize\">{{filter.type}}:</span>\n <span class=\"truncate max-w-[150px]\">{{filter.name}}</span>\n <button (click)=\"removeFilter()\" class=\"hover:text-red-500 transition-colors\">\n <lucide-icon [img]=\"icons.X\" [size]=\"14\"></lucide-icon>\n </button>\n </div>\n }\n </div>\n }\n </div>\n <div class=\"overflow-y-auto p-2 drawer-listing-box\">\n <cdk-virtual-scroll-viewport itemSize=\"60\" class=\"routeList-viewport h-[calc(100vh-230px)]\">\n @if (filteredRoutes().length > 0) {\n <ul class=\"route-list-ul gap-2 flex flex-col\">\n @for (route of filteredRoutes(); track getRouteId(route)) {\n <li \n class=\"route-li-v1 bg-white dark:bg-slate-800 border border-gray-300 dark:border-slate-700\" \n [class.selected]=\"isRouteSelected(route)\" \n [class.pointer-events-none]=\"isAnyPlotting()\"\n [class.opacity-60]=\"isAnyPlotting()\"\n (click)=\"toggleRoute(route)\">\n <div class=\"task-header justify-between\">\n <span class=\"job-code\"> {{route.route_name || route.order_number}} </span>\n @if (config.repository === 'coolmap') {\n <span class=\"job-code\">{{route.customer_name}}</span>\n }\n <div class=\"iconprt\">\n @if (isPlotting(route)) {\n <div class=\"plotting-spinner\">\n <lucide-icon [img]=\"icons.LoaderCircle\" class=\"animate-spin text-black dark:text-white flex items-center justify-center relative z-10\" [size]=\"18\"></lucide-icon>\n </div>\n }\n <div class=\"statusunit text-white\" [ngClass]=\"route.unit || ''\">\n {{ route.unit?.charAt(0) || 'U' }}\n </div>\n <div class=\"infoicon\" \n (click)=\"$event.stopPropagation(); openDetail(route, true)\"\n (mouseenter)=\"openDetail(route, false)\"\n (mouseleave)=\"closeDetail(true)\">\n <lucide-icon [img]=\"icons.Info\" [size]=\"18\" class=\"text-gray-400\"></lucide-icon>\n </div>\n @if (config.repository === 'customer') {\n <div class=\"infoicon hover:opacity-80\" (click)=\"$event.stopPropagation(); shareRoute.emit(route)\">\n <lucide-icon [img]=\"icons.Share2\" [size]=\"16\" class=\"text-gray-400\"></lucide-icon>\n </div>\n }\n </div>\n </div>\n \n <div class=\"location-flow bg-gray-100 dark:bg-slate-900 px-2 py-2 pb-3 rounded-lg\">\n <span class=\"pickup\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"8\" />\n </svg>\n {{ (route.pickup_location || '').split('|')[1] ? (route.pickup_location || '').split('|')[1] : (route.pickup_location || '') }}\n </span>\n <span class=\"delivery\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"8\" />\n </svg>\n {{ (route.delivery_location || '').split('|')[1] ? (route.delivery_location || '').split('|')[1] : (route.delivery_location || '') }}\n </span>\n </div>\n </li>\n }\n </ul>\n } @else if (routes().length === 0) {\n <div class=\"p-8 text-center text-gray-400\">\n No routes available for this perspective.\n </div>\n }\n </cdk-virtual-scroll-viewport>\n </div>\n </aside>\n</div>\n}\n<lib-route-info-card [modalOpen]=\"showRouteModal\" (modalOpenChange)=\"$event ? null : closeDetail(false)\" [routeData]=\"selectedRoute()\" [repository]=\"config.repository\" displayMode=\"dispatch\" [noBackdrop]=\"!isClickTriggered\"></lib-route-info-card>\n", styles: [".detail-drawer{position:fixed;right:0;bottom:36px;width:280px;background:var(--bg-primary, white);border-left:1px solid var(--border-color, #e2e8f0);display:flex;flex-direction:column;z-index:501;animation:slideIn .2s ease;height:100vh}:host-context(.dark) .detail-drawer{background-color:#1e293b;border-color:#334155}.drawer-listing-box{flex:1;overflow:hidden;padding:0!important}.routeList-viewport{width:100%}.route-list-ul{list-style:none;padding:10px;margin:0}.route-li-v1{position:relative;padding:6px 10px;display:flex;flex-direction:column;gap:2px;border-radius:8px;cursor:pointer;transition:all .15s ease;min-height:72px}.route-li-v1:hover{background:#ffffff0d}.route-li-v1.selected{border:1px solid #3b82f6}.task-header{display:flex;align-items:center;gap:6px;margin-bottom:4px}.job-code{font-size:13px;font-weight:600;color:var(--text-primary, #1e293b);white-space:nowrap;text-overflow:ellipsis;max-width:190px;overflow:hidden}:host-context(.dark) .job-code{color:#f1f5f9}.iconprt{display:flex;flex-shrink:0;gap:5px}.plotting-spinner{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;background:#1e293bb3;border-radius:4px;z-index:10}.animate-spin{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.statusunit{border-radius:30px;font-size:11px;text-transform:capitalize;font-weight:600;width:18px;height:18px;text-align:center;line-height:18px}.statusunit.Ton{background:#ff7272}.statusunit.Load{background:#a3c52e}.statusunit.Hourly{background:#ae23d1}.pickprtbox{flex:1;min-width:0}.pickprtbox h2{font-size:14px;font-weight:600;color:#fff;margin:0;line-height:1.2}.pickprtbox h3{font-size:12px;color:#94a3b8;margin:2px 0 6px;font-weight:400}.pickdropprt{display:flex;flex-direction:column;gap:4px}.pickdropprt .pickprt,.pickdropprt .dropprt{color:#cbd5e1;font-size:11px}.pickdropprt .pickprt h4,.pickdropprt .dropprt h4{margin:0;font-weight:500;color:#94a3b8}.pickdropprt .pickprt.pickprt h4,.pickdropprt .dropprt.pickprt h4{color:#22c55e}.pickdropprt .pickprt.dropprt h4,.pickdropprt .dropprt.dropprt h4{color:#3b82f6}.infoicon{cursor:pointer}.infoicon:hover lucide-icon{color:#fff}@keyframes slideIn{0%{transform:translate(100%)}to{transform:translate(0)}}.animate-slide-in{animation:slideIn .2s ease}.location-flow{display:flex;flex-direction:column;align-items:flex-start;gap:2px;font-size:11px;color:var(--text-secondary, #64748b);margin-bottom:6px}.location-flow .pickup{display:inline;align-items:center;gap:3px;color:#22c55e;white-space:nowrap;text-overflow:ellipsis;max-width:200px;overflow:hidden;position:relative;padding-left:15px}.location-flow .pickup svg{width:8px;height:8px;position:absolute;left:0;top:5px}.location-flow .delivery{display:inline;align-items:center;gap:3px;color:#ef4444;white-space:nowrap;text-overflow:ellipsis;max-width:200px;overflow:hidden;position:relative;padding-left:15px;top:5px}.location-flow .delivery svg{width:8px;height:8px;position:absolute;left:0;top:5px}\n"] }]
602
+ args: [{ selector: 'lib-job-route-list', standalone: true, imports: [LucideAngularModule, RouteInfoCardComponent, NgClass, ScrollingModule], template: "@if (modalOpen()) {\n<div class=\"fixed z-[11] route-list\">\n <!-- <div class=\"fixed inset-0 bg-black/50\" (click)=\"close()\"></div> -->\n <aside class=\"detail-drawer top-[0] sm:top-[115px]\" (click)=\"$event.stopPropagation()\">\n <div\n class=\"flex items-center justify-between px-[12px] py-[10px] border-b border-gray-200 dark:border-slate-700 dark:bg-slate-900\"\n >\n <h3 class=\"flex items-center gap-1 font-semibold text-gray-900 dark:text-white text-[14px]\">\n List of Routes\n <span class=\"text-xs font-normal text-gray-400\">({{ filteredRoutes().length }})</span>\n </h3>\n <button\n type=\"button\"\n (click)=\"onMasterToggle()\"\n [disabled]=\"isAnyPlotting()\"\n class=\"inline-flex items-center justify-center gap-2 px-3 sm:px-4 py-1.5 bg-brand-blue hover:bg-blue-700 disabled:opacity-50 text-white font-medium rounded-md transition-colors text-[12px]\"\n >\n {{ allSelected() ? 'Uncheck All' : 'Check All' }}\n </button>\n <button\n (click)=\"close()\"\n class=\"p-1.5 hover:bg-gray-100 dark:hover:bg-slate-700 rounded-lg transition-colors\"\n >\n <lucide-icon [img]=\"icons.X\" [size]=\"18\"></lucide-icon>\n </button>\n </div>\n <div class=\"p-2\">\n <div class=\"relative w-full\">\n <div class=\"absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none\">\n <lucide-icon [img]=\"hasFilter ? icons.Info : icons.Search\" class=\"text-gray-400\" [size]=\"18\"></lucide-icon>\n </div>\n <input\n type=\"text\"\n #searchinput\n [value]=\"searchTerm()\"\n (input)=\"handleSearchInput(searchinput.value)\"\n (focus)=\"showSuggestions.set(true)\"\n (blur)=\"onSearchBlur()\"\n placeholder=\"Search...\"\n class=\"w-full pl-10 pr-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-white placeholder-gray-400 focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n />\n\n <!-- Autocomplete Suggestions Dropdown -->\n @if (showSuggestions() && suggestions().length > 0) {\n <div class=\"absolute z-50 w-full mt-1 bg-white dark:bg-gray-800 rounded-lg shadow-xl border border-gray-200 dark:border-gray-700 max-h-60 overflow-y-auto\">\n <ul class=\"py-1 text-sm text-gray-700 dark:text-gray-200\">\n @for (option of suggestions(); track option.label + option.type) {\n <li (click)=\"addFilter(option)\"\n class=\"px-4 py-2 hover:bg-brand-blue/10 dark:hover:bg-brand-blue/20 cursor-pointer flex justify-between items-center group\">\n <span>\n <span class=\"capitalize\">{{option.type}}:</span> \n {{option.label}}\n </span>\n <lucide-icon [img]=\"icons.CheckCircle\" class=\"opacity-0 group-hover:opacity-100 text-brand-blue transition-opacity\" [size]=\"16\"></lucide-icon>\n </li>\n }\n </ul>\n </div>\n }\n </div>\n\n <!-- Active Filter Chips -->\n @if (hasFilter) {\n <div class=\"flex flex-wrap gap-2 mt-2 px-1\">\n @for (filter of filters(); track filter.name + filter.type) {\n <div class=\"inline-flex items-center gap-1.5 px-3 py-1 bg-slate-200 dark:bg-slate-700 border border-brand-blue/20 text-black dark:text-white rounded-full text-xs font-medium\">\n <span class=\"capitalize\">{{filter.type}}:</span>\n <span class=\"truncate max-w-[150px]\">{{filter.name}}</span>\n <button (click)=\"removeFilter()\" class=\"hover:text-red-500 transition-colors\">\n <lucide-icon [img]=\"icons.X\" [size]=\"14\"></lucide-icon>\n </button>\n </div>\n }\n </div>\n }\n </div>\n <div class=\"overflow-y-auto p-2 drawer-listing-box\">\n <cdk-virtual-scroll-viewport itemSize=\"60\" class=\"routeList-viewport h-[calc(100vh-230px)]\">\n @if (filteredRoutes().length > 0) {\n <ul class=\"route-list-ul gap-2 flex flex-col\">\n @for (route of filteredRoutes(); track getRouteId(route)) {\n <li \n class=\"route-li-v1 bg-white dark:bg-slate-800 border border-gray-300 dark:border-slate-700\" \n [class.selected]=\"isRouteSelected(route)\" \n [class.pointer-events-none]=\"isAnyPlotting()\"\n [class.opacity-60]=\"isAnyPlotting()\"\n (click)=\"toggleRoute(route)\">\n <div class=\"task-header justify-between\">\n <span class=\"job-code\"> {{route.route_name || route.order_number}} </span>\n @if (config.repository === 'coolmap') {\n <span class=\"job-code\">{{route.customer_name}}</span>\n }\n <div class=\"iconprt\">\n @if (isPlotting(route)) {\n <div class=\"plotting-spinner\">\n <lucide-icon [img]=\"icons.LoaderCircle\" class=\"animate-spin text-black dark:text-white flex items-center justify-center relative z-10\" [size]=\"18\"></lucide-icon>\n </div>\n }\n <div class=\"statusunit text-white\" [ngClass]=\"route.unit || ''\">\n {{ route.unit?.charAt(0) || 'U' }}\n </div>\n <div class=\"infoicon\" \n (click)=\"$event.stopPropagation(); openDetail(route, true)\"\n (mouseenter)=\"openDetail(route, false)\"\n (mouseleave)=\"closeDetail(true)\">\n <lucide-icon [img]=\"icons.Info\" [size]=\"18\" class=\"text-gray-400\"></lucide-icon>\n </div>\n @if (config.repository === 'customer') {\n <div class=\"infoicon hover:opacity-80\" (click)=\"$event.stopPropagation(); shareRoute.emit(route)\">\n <lucide-icon [img]=\"icons.Share2\" [size]=\"16\" class=\"text-gray-400\"></lucide-icon>\n </div>\n }\n </div>\n </div>\n \n <div class=\"location-flow bg-gray-100 dark:bg-slate-900 px-2 py-2 pb-3 rounded-lg\">\n <span class=\"pickup\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"8\" />\n </svg>\n {{ (route.pickup_location || '').split('|')[1] ? (route.pickup_location || '').split('|')[1] : (route.pickup_location || '') }}\n </span>\n <span class=\"delivery\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"10\"\n height=\"10\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"8\" />\n </svg>\n {{ (route.delivery_location || '').split('|')[1] ? (route.delivery_location || '').split('|')[1] : (route.delivery_location || '') }}\n </span>\n </div>\n </li>\n }\n </ul>\n } @else if (routes().length === 0) {\n <div class=\"p-8 text-center text-gray-400\">\n No routes available for this perspective.\n </div>\n }\n </cdk-virtual-scroll-viewport>\n </div>\n </aside>\n</div>\n}\n<lib-route-info-card [modalOpen]=\"showRouteModal\" (modalOpenChange)=\"$event ? null : closeDetail(false)\" [routeData]=\"selectedRoute()\" [repository]=\"config.repository\" displayMode=\"dispatch\" [noBackdrop]=\"!isClickTriggered\"></lib-route-info-card>\n", styles: [".detail-drawer{position:fixed;right:0;bottom:36px;width:280px;background:var(--bg-primary, white);border-left:1px solid var(--border-color, #e2e8f0);display:flex;flex-direction:column;z-index:501;animation:slideIn .2s ease;height:100vh}:host-context(.dark) .detail-drawer{background-color:#1e293b;border-color:#334155}.drawer-listing-box{flex:1;overflow:hidden;padding:0!important}.routeList-viewport{width:100%}.route-list-ul{list-style:none;padding:10px;margin:0}.route-li-v1{position:relative;padding:6px 10px;display:flex;flex-direction:column;gap:2px;border-radius:8px;cursor:pointer;transition:all .15s ease;min-height:72px}.route-li-v1:hover{background:#ffffff0d}.route-li-v1.selected{border:1px solid #3b82f6}.task-header{display:flex;align-items:center;gap:6px;margin-bottom:4px}.job-code{font-size:13px;font-weight:600;color:var(--text-primary, #1e293b);white-space:nowrap;text-overflow:ellipsis;max-width:190px;overflow:hidden}:host-context(.dark) .job-code{color:#f1f5f9}.iconprt{display:flex;flex-shrink:0;gap:5px}.plotting-spinner{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;background:#1e293bb3;border-radius:4px;z-index:10}.animate-spin{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.statusunit{border-radius:30px;font-size:11px;text-transform:capitalize;font-weight:600;width:18px;height:18px;text-align:center;line-height:18px}.statusunit.Ton{background:#ff7272}.statusunit.Load{background:#a3c52e}.statusunit.Hourly{background:#ae23d1}.pickprtbox{flex:1;min-width:0}.pickprtbox h2{font-size:14px;font-weight:600;color:#fff;margin:0;line-height:1.2}.pickprtbox h3{font-size:12px;color:#94a3b8;margin:2px 0 6px;font-weight:400}.pickdropprt{display:flex;flex-direction:column;gap:4px}.pickdropprt .pickprt,.pickdropprt .dropprt{color:#cbd5e1;font-size:11px}.pickdropprt .pickprt h4,.pickdropprt .dropprt h4{margin:0;font-weight:500;color:#94a3b8}.pickdropprt .pickprt.pickprt h4,.pickdropprt .dropprt.pickprt h4{color:#22c55e}.pickdropprt .pickprt.dropprt h4,.pickdropprt .dropprt.dropprt h4{color:#3b82f6}.infoicon{cursor:pointer}.infoicon:hover lucide-icon{color:#fff}@keyframes slideIn{0%{transform:translate(100%)}to{transform:translate(0)}}.animate-slide-in{animation:slideIn .2s ease}.location-flow{display:flex;flex-direction:column;align-items:flex-start;gap:2px;font-size:11px;color:var(--text-secondary, #64748b);margin-bottom:6px}.location-flow .pickup{display:inline;align-items:center;gap:3px;color:#22c55e;white-space:nowrap;text-overflow:ellipsis;max-width:200px;overflow:hidden;position:relative;padding-left:15px}.location-flow .pickup svg{width:8px;height:8px;position:absolute;left:0;top:5px}.location-flow .delivery{display:inline;align-items:center;gap:3px;color:#ef4444;white-space:nowrap;text-overflow:ellipsis;max-width:200px;overflow:hidden;position:relative;padding-left:15px;top:5px}.location-flow .delivery svg{width:8px;height:8px;position:absolute;left:0;top:5px}\n"] }]
593
603
  }], ctorParameters: () => [], propDecorators: { customerRepoDetails: [{
594
604
  type: Input
595
605
  }], selectedRouteIds: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedRouteIds", required: false }] }], modalOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "modalOpen", required: false }] }], initialRoutes: [{
@@ -620,13 +630,15 @@ class ViewRouteListComponent {
620
630
  collapsible = true;
621
631
  routes = [];
622
632
  selectedRouteIds = [];
633
+ isLoading = true;
623
634
  routeSelect = new EventEmitter();
624
635
  editRoute = new EventEmitter();
625
636
  collapsed = false;
626
637
  icons = {
627
638
  Info,
628
639
  ChevronRight,
629
- ChevronLeft
640
+ ChevronLeft,
641
+ LoaderCircle
630
642
  };
631
643
  toggleCollapse() {
632
644
  if (this.collapsible) {
@@ -663,11 +675,11 @@ class ViewRouteListComponent {
663
675
  }
664
676
  }
665
677
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: ViewRouteListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
666
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: ViewRouteListComponent, isStandalone: true, selector: "lib-view-route-list", inputs: { listMode: "listMode", collapsible: "collapsible", routes: "routes", selectedRouteIds: "selectedRouteIds" }, outputs: { routeSelect: "routeSelect", editRoute: "editRoute" }, ngImport: i0, template: "<div\n class=\"cards-list-container\"\n [class.floating]=\"listMode === 'floating'\"\n [class.sidebar]=\"listMode === 'sidebar'\"\n [class.inline]=\"listMode === 'inline'\"\n [class.collapsed]=\"collapsed\"\n>\n @if (listMode !== 'inline') {\n <div class=\"list-header\">\n <div class=\"header-title\">\n <span class=\"title-text\">View Route</span>\n <span class=\"routes-count\">({{ routes.length || 0 }})</span>\n </div>\n <button\n class=\"collapse-btn\"\n (click)=\"toggleCollapse()\"\n [title]=\"collapsed ? 'Expand' : 'Collapse'\"\n >\n @if (collapsed) {\n <lucide-icon [img]=\"icons.ChevronRight\" [size]=\"16\"></lucide-icon>\n } @else {\n <lucide-icon [img]=\"icons.ChevronLeft\" [size]=\"16\"></lucide-icon>\n }\n </button>\n </div>\n } \n \n @if (!collapsed) {\n <div class=\"cards-scroll-container\" #scrollContainer>\n <div class=\"cards-list\">\n @for (route of routes; track getRouteId(route)) {\n <div class=\"card-wrapper\">\n <div\n class=\"route-card bg-white dark:bg-slate-800 border transition-all duration-200\"\n [class.border-brand-blue]=\"selectedRouteIds.includes(getRouteId(route))\"\n [class.border-gray-200]=\"!selectedRouteIds.includes(getRouteId(route))\"\n [class.dark:border-slate-700]=\"!selectedRouteIds.includes(getRouteId(route))\"\n [class.selected]=\"selectedRouteIds.includes(getRouteId(route))\"\n >\n <div class=\"task-header justify-between items-start mb-1\">\n <h2 class=\"text-sm font-semibold text-gray-900 dark:text-white truncate max-w-[80%]\">\n {{ route.route_name || route.order_number || 'Unnamed Route' }}\n </h2>\n <div class=\"flex gap-2 shrink-0\">\n <div class=\"statusunit text-white\" [ngClass]=\"route.unit || ''\">\n {{ route.unit?.charAt(0) || 'U' }}\n </div>\n <button\n type=\"button\"\n class=\"text-gray-400 hover:text-brand-blue transition-colors\"\n (mouseenter)=\"openDetail(route, false)\"\n (mouseleave)=\"closeDetail(true)\"\n (click)=\"$event.stopPropagation(); openDetail(route, true)\"\n >\n <lucide-icon [img]=\"icons.Info\" [size]=\"18\"></lucide-icon>\n </button>\n </div>\n </div>\n \n @if (config.repository === 'coolmap' && route.customer_name) {\n <div class=\"text-[10px] text-gray-500 dark:text-slate-500 mb-2 uppercase tracking-wider font-medium truncate\">\n {{ route.customer_name }}\n </div>\n }\n\n <div class=\"location-flow bg-gray-50 dark:bg-slate-900/50 border border-gray-100 dark:border-slate-700/50 p-2 rounded-lg\">\n <div class=\"text-[11px] flex items-start gap-1.5 text-gray-600 dark:text-gray-400\">\n <div class=\"w-1.5 h-1.5 rounded-full bg-green-500 shrink-0 bullet mt-1\"></div>\n {{ (route.pickup_location || '').split('|')[1] || route.pickup_location || 'N/A' }}\n </div>\n <div class=\"text-[11px] flex items-start gap-1.5 mt-1 text-gray-600 dark:text-gray-400\">\n <div class=\"w-1.5 h-1.5 rounded-full bg-blue-500 shrink-0 bullet mt-1\"></div>\n {{ (route.delivery_location || '').split('|')[1] || route.delivery_location || 'N/A' }}\n </div>\n </div>\n </div>\n </div>\n } @empty {\n <div class=\"p-8 text-center text-gray-400 text-sm italic\">\n No routes found in this catalog.\n </div>\n }\n </div>\n </div>\n }\n</div>\n\n<lib-route-info-card \n [modalOpen]=\"showRouteModal\" \n (modalOpenChange)=\"$event ? (showRouteModal = true) : closeDetail(false)\"\n [routeData]=\"selectedRoute()\" \n [repository]=\"config.repository\" \n displayMode=\"catalog\"\n [noBackdrop]=\"true\"\n (edit)=\"editRoute.emit(selectedRoute()!)\"\n></lib-route-info-card>\n", styles: [":host{display:block}.cards-list-container{display:flex;flex-direction:column;height:100%;background:var(--bg-primary, white)}.cards-list-container.floating{position:absolute;top:12px;left:12px;width:280px;max-height:calc(100% - 24px);border-radius:12px;box-shadow:0 4px 24px #00000026;z-index:100;overflow:hidden}.cards-list-container.floating.collapsed{width:48px}.cards-list-container.sidebar{width:100%;border-right:1px solid var(--border-color, #e2e8f0)}.cards-list-container.inline{width:160px;min-width:160px;border-right:1px solid var(--border-color, #e2e8f0)}:host-context(.dark) .cards-list-container{background-color:#1e293b}:host-context(.dark) .cards-list-container.sidebar,:host-context(.dark) .cards-list-container.inline{border-color:#334155}.list-header{display:flex;align-items:center;justify-content:space-between;padding:12px;border-bottom:1px solid var(--border-color, #e2e8f0);background:var(--bg-secondary, #f8fafc)}:host-context(.dark) .list-header{background-color:#0f172a;border-color:#334155}.collapsed .list-header{padding:12px 8px;justify-content:center}.header-title{display:flex;align-items:center;gap:6px}.collapsed .header-title{display:none}.title-text{font-size:13px;font-weight:600;color:var(--text-primary, #1e293b)}:host-context(.dark) .title-text{color:#f1f5f9}.cards-scroll-container{flex:1;overflow-y:auto;overflow-x:hidden}.cards-list{display:flex;flex-direction:column;gap:8px;padding:8px}.card-wrapper{border-radius:8px;transition:all .2s ease}.route-card{position:relative;padding:6px 10px;display:flex;flex-direction:column;gap:2px;border-radius:8px;cursor:pointer;transition:all .15s ease;min-height:72px}.route-card:hover{border-color:var(--accent-color, #3b82f6);box-shadow:0 2px 8px #00000014}.task-header{display:flex;align-items:center;gap:6px;margin-bottom:4px}.job-code{font-size:13px;font-weight:600;color:var(--text-primary, #1e293b);white-space:nowrap;text-overflow:ellipsis;max-width:190px;overflow:hidden}:host-context(.dark) .job-code{color:#f1f5f9}.statusunit{border-radius:30px;font-size:12px;text-transform:capitalize;font-weight:600;width:20px;height:20px;text-align:center;line-height:20px}.statusunit.Ton{background:#ff7272}.statusunit.Load{background:#a3c52e}.statusunit.Hourly{background:#ae23d1}.location-flow{display:flex;flex-direction:column;align-items:flex-start;gap:2px;font-size:11px;color:var(--text-secondary, #64748b);margin-bottom:6px}.location-flow .pickup{display:inline;align-items:center;gap:3px;color:#22c55e;white-space:nowrap;text-overflow:ellipsis;max-width:200px;overflow:hidden;position:relative;padding-left:15px}.location-flow .pickup svg{width:8px;height:8px;position:absolute;left:0;top:5px}.location-flow .delivery{display:inline;align-items:center;gap:3px;color:#ef4444;white-space:nowrap;text-overflow:ellipsis;max-width:200px;overflow:hidden;position:relative;padding-left:15px;top:5px}.location-flow .delivery svg{width:8px;height:8px;position:absolute;left:0;top:5px}\n"], dependencies: [{ kind: "ngmodule", type: LucideAngularModule }, { kind: "component", type: i1.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }, { kind: "component", type: RouteInfoCardComponent, selector: "lib-route-info-card", inputs: ["modalOpen", "routeData", "repository", "displayMode", "noBackdrop"], outputs: ["modalOpenChange", "edit"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
678
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: ViewRouteListComponent, isStandalone: true, selector: "lib-view-route-list", inputs: { listMode: "listMode", collapsible: "collapsible", routes: "routes", selectedRouteIds: "selectedRouteIds", isLoading: "isLoading" }, outputs: { routeSelect: "routeSelect", editRoute: "editRoute" }, ngImport: i0, template: "<div\n class=\"cards-list-container\"\n [class.floating]=\"listMode === 'floating'\"\n [class.sidebar]=\"listMode === 'sidebar'\"\n [class.inline]=\"listMode === 'inline'\"\n [class.collapsed]=\"collapsed\"\n>\n @if (listMode !== 'inline') {\n <div class=\"list-header\">\n <div class=\"header-title\">\n <span class=\"title-text\">View Route</span>\n <span class=\"routes-count\">({{ routes.length || 0 }})</span>\n </div>\n <button\n class=\"collapse-btn\"\n (click)=\"toggleCollapse()\"\n [title]=\"collapsed ? 'Expand' : 'Collapse'\"\n >\n @if (collapsed) {\n <lucide-icon [img]=\"icons.ChevronRight\" [size]=\"16\"></lucide-icon>\n } @else {\n <lucide-icon [img]=\"icons.ChevronLeft\" [size]=\"16\"></lucide-icon>\n }\n </button>\n </div>\n } \n \n @if (!collapsed) {\n <div class=\"cards-scroll-container\" #scrollContainer>\n @if (isLoading) {\n <div class=\"list-loader\">\n <lucide-icon [img]=\"icons.LoaderCircle\" [size]=\"32\" class=\"animate-spin text-amber-500\"></lucide-icon>\n </div>\n }\n @if(!isLoading && routes && routes.length){\n <div class=\"cards-list\">\n @for (route of routes; track getRouteId(route)) {\n <div class=\"card-wrapper\">\n <div\n class=\"route-card bg-white dark:bg-slate-800 border transition-all duration-200\"\n [class.border-brand-blue]=\"selectedRouteIds.includes(getRouteId(route))\"\n [class.border-gray-200]=\"!selectedRouteIds.includes(getRouteId(route))\"\n [class.dark:border-slate-700]=\"!selectedRouteIds.includes(getRouteId(route))\"\n [class.selected]=\"selectedRouteIds.includes(getRouteId(route))\"\n >\n <div class=\"task-header justify-between items-start mb-1\">\n <h2 class=\"text-sm font-semibold text-gray-900 dark:text-white truncate max-w-[80%]\">\n {{ route.route_name || route.order_number || 'Unnamed Route' }}\n </h2>\n <div class=\"flex gap-2 shrink-0\">\n <div class=\"statusunit text-white\" [ngClass]=\"route.unit || ''\">\n {{ route.unit?.charAt(0) || 'U' }}\n </div>\n <button\n type=\"button\"\n class=\"text-gray-400 hover:text-brand-blue transition-colors\"\n (mouseenter)=\"openDetail(route, false)\"\n (mouseleave)=\"closeDetail(true)\"\n (click)=\"$event.stopPropagation(); openDetail(route, true)\"\n >\n <lucide-icon [img]=\"icons.Info\" [size]=\"18\"></lucide-icon>\n </button>\n </div>\n </div>\n \n @if (config.repository === 'coolmap' && route.customer_name) {\n <div class=\"text-[10px] text-gray-500 dark:text-slate-500 mb-2 uppercase tracking-wider font-medium truncate\">\n {{ route.customer_name }}\n </div>\n }\n\n <div class=\"location-flow bg-gray-50 dark:bg-slate-900/50 border border-gray-100 dark:border-slate-700/50 p-2 rounded-lg\">\n <div class=\"text-[11px] flex items-start gap-1.5 text-gray-600 dark:text-gray-400\">\n <div class=\"w-1.5 h-1.5 rounded-full bg-green-500 shrink-0 bullet mt-1\"></div>\n {{ (route.pickup_location || '').split('|')[1] || route.pickup_location || 'N/A' }}\n </div>\n <div class=\"text-[11px] flex items-start gap-1.5 mt-1 text-gray-600 dark:text-gray-400\">\n <div class=\"w-1.5 h-1.5 rounded-full bg-blue-500 shrink-0 bullet mt-1\"></div>\n {{ (route.delivery_location || '').split('|')[1] || route.delivery_location || 'N/A' }}\n </div>\n </div>\n </div>\n </div>\n }\n </div>\n } @else if (!isLoading && coolmapService.isDataFetched() && (!routes || routes.length === 0)) {\n <div class=\"p-8 text-center text-gray-400 text-sm\">\n No routes found.\n </div>\n }\n </div>\n }\n</div>\n\n<lib-route-info-card \n [modalOpen]=\"showRouteModal\" \n (modalOpenChange)=\"$event ? (showRouteModal = true) : closeDetail(false)\"\n [routeData]=\"selectedRoute()\" \n [repository]=\"config.repository\" \n displayMode=\"catalog\"\n [noBackdrop]=\"true\"\n (edit)=\"editRoute.emit(selectedRoute()!)\"\n></lib-route-info-card>\n", styles: [":host{display:block}.cards-list-container{display:flex;flex-direction:column;height:100%;background:var(--bg-primary, white)}.cards-list-container.floating{position:absolute;top:12px;left:12px;width:280px;max-height:calc(100% - 24px);border-radius:12px;box-shadow:0 4px 24px #00000026;z-index:100;overflow:hidden}.cards-list-container.floating.collapsed{width:48px}.cards-list-container.sidebar{width:100%;border-right:1px solid var(--border-color, #e2e8f0)}.cards-list-container.inline{width:160px;min-width:160px;border-right:1px solid var(--border-color, #e2e8f0)}:host-context(.dark) .cards-list-container{background-color:#1e293b}:host-context(.dark) .cards-list-container.sidebar,:host-context(.dark) .cards-list-container.inline{border-color:#334155}.list-header{display:flex;align-items:center;justify-content:space-between;padding:12px;border-bottom:1px solid var(--border-color, #e2e8f0);background:var(--bg-secondary, #f8fafc)}:host-context(.dark) .list-header{background-color:#0f172a;border-color:#334155}.collapsed .list-header{padding:12px 8px;justify-content:center}.header-title{display:flex;align-items:center;gap:6px}.collapsed .header-title{display:none}.title-text{font-size:13px;font-weight:600;color:var(--text-primary, #1e293b)}:host-context(.dark) .title-text{color:#f1f5f9}.cards-scroll-container{flex:1;overflow-y:auto;overflow-x:hidden}.cards-list{display:flex;flex-direction:column;gap:8px;padding:8px}.card-wrapper{border-radius:8px;transition:all .2s ease}.route-card{position:relative;padding:6px 10px;display:flex;flex-direction:column;gap:2px;border-radius:8px;cursor:pointer;transition:all .15s ease;min-height:72px}.route-card:hover{border-color:var(--accent-color, #3b82f6);box-shadow:0 2px 8px #00000014}.task-header{display:flex;align-items:center;gap:6px;margin-bottom:4px}.job-code{font-size:13px;font-weight:600;color:var(--text-primary, #1e293b);white-space:nowrap;text-overflow:ellipsis;max-width:190px;overflow:hidden}:host-context(.dark) .job-code{color:#f1f5f9}.statusunit{border-radius:30px;font-size:12px;text-transform:capitalize;font-weight:600;width:20px;height:20px;text-align:center;line-height:20px}.statusunit.Ton{background:#ff7272}.statusunit.Load{background:#a3c52e}.statusunit.Hourly{background:#ae23d1}.location-flow{display:flex;flex-direction:column;align-items:flex-start;gap:2px;font-size:11px;color:var(--text-secondary, #64748b);margin-bottom:6px}.location-flow .pickup{display:inline;align-items:center;gap:3px;color:#22c55e;white-space:nowrap;text-overflow:ellipsis;max-width:200px;overflow:hidden;position:relative;padding-left:15px}.location-flow .pickup svg{width:8px;height:8px;position:absolute;left:0;top:5px}.location-flow .delivery{display:inline;align-items:center;gap:3px;color:#ef4444;white-space:nowrap;text-overflow:ellipsis;max-width:200px;overflow:hidden;position:relative;padding-left:15px;top:5px}.location-flow .delivery svg{width:8px;height:8px;position:absolute;left:0;top:5px}.list-loader{position:absolute;inset:0;background:#fff6;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);display:flex;align-items:center;justify-content:center;z-index:50;border-radius:0 0 12px 12px}:host-context(.dark) .list-loader{background:#0f172a66}\n"], dependencies: [{ kind: "ngmodule", type: LucideAngularModule }, { kind: "component", type: i1.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }, { kind: "component", type: RouteInfoCardComponent, selector: "lib-route-info-card", inputs: ["modalOpen", "routeData", "repository", "displayMode", "noBackdrop"], outputs: ["modalOpenChange", "edit"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
667
679
  }
668
680
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: ViewRouteListComponent, decorators: [{
669
681
  type: Component,
670
- args: [{ selector: 'lib-view-route-list', standalone: true, imports: [LucideAngularModule, RouteInfoCardComponent, NgClass], template: "<div\n class=\"cards-list-container\"\n [class.floating]=\"listMode === 'floating'\"\n [class.sidebar]=\"listMode === 'sidebar'\"\n [class.inline]=\"listMode === 'inline'\"\n [class.collapsed]=\"collapsed\"\n>\n @if (listMode !== 'inline') {\n <div class=\"list-header\">\n <div class=\"header-title\">\n <span class=\"title-text\">View Route</span>\n <span class=\"routes-count\">({{ routes.length || 0 }})</span>\n </div>\n <button\n class=\"collapse-btn\"\n (click)=\"toggleCollapse()\"\n [title]=\"collapsed ? 'Expand' : 'Collapse'\"\n >\n @if (collapsed) {\n <lucide-icon [img]=\"icons.ChevronRight\" [size]=\"16\"></lucide-icon>\n } @else {\n <lucide-icon [img]=\"icons.ChevronLeft\" [size]=\"16\"></lucide-icon>\n }\n </button>\n </div>\n } \n \n @if (!collapsed) {\n <div class=\"cards-scroll-container\" #scrollContainer>\n <div class=\"cards-list\">\n @for (route of routes; track getRouteId(route)) {\n <div class=\"card-wrapper\">\n <div\n class=\"route-card bg-white dark:bg-slate-800 border transition-all duration-200\"\n [class.border-brand-blue]=\"selectedRouteIds.includes(getRouteId(route))\"\n [class.border-gray-200]=\"!selectedRouteIds.includes(getRouteId(route))\"\n [class.dark:border-slate-700]=\"!selectedRouteIds.includes(getRouteId(route))\"\n [class.selected]=\"selectedRouteIds.includes(getRouteId(route))\"\n >\n <div class=\"task-header justify-between items-start mb-1\">\n <h2 class=\"text-sm font-semibold text-gray-900 dark:text-white truncate max-w-[80%]\">\n {{ route.route_name || route.order_number || 'Unnamed Route' }}\n </h2>\n <div class=\"flex gap-2 shrink-0\">\n <div class=\"statusunit text-white\" [ngClass]=\"route.unit || ''\">\n {{ route.unit?.charAt(0) || 'U' }}\n </div>\n <button\n type=\"button\"\n class=\"text-gray-400 hover:text-brand-blue transition-colors\"\n (mouseenter)=\"openDetail(route, false)\"\n (mouseleave)=\"closeDetail(true)\"\n (click)=\"$event.stopPropagation(); openDetail(route, true)\"\n >\n <lucide-icon [img]=\"icons.Info\" [size]=\"18\"></lucide-icon>\n </button>\n </div>\n </div>\n \n @if (config.repository === 'coolmap' && route.customer_name) {\n <div class=\"text-[10px] text-gray-500 dark:text-slate-500 mb-2 uppercase tracking-wider font-medium truncate\">\n {{ route.customer_name }}\n </div>\n }\n\n <div class=\"location-flow bg-gray-50 dark:bg-slate-900/50 border border-gray-100 dark:border-slate-700/50 p-2 rounded-lg\">\n <div class=\"text-[11px] flex items-start gap-1.5 text-gray-600 dark:text-gray-400\">\n <div class=\"w-1.5 h-1.5 rounded-full bg-green-500 shrink-0 bullet mt-1\"></div>\n {{ (route.pickup_location || '').split('|')[1] || route.pickup_location || 'N/A' }}\n </div>\n <div class=\"text-[11px] flex items-start gap-1.5 mt-1 text-gray-600 dark:text-gray-400\">\n <div class=\"w-1.5 h-1.5 rounded-full bg-blue-500 shrink-0 bullet mt-1\"></div>\n {{ (route.delivery_location || '').split('|')[1] || route.delivery_location || 'N/A' }}\n </div>\n </div>\n </div>\n </div>\n } @empty {\n <div class=\"p-8 text-center text-gray-400 text-sm italic\">\n No routes found in this catalog.\n </div>\n }\n </div>\n </div>\n }\n</div>\n\n<lib-route-info-card \n [modalOpen]=\"showRouteModal\" \n (modalOpenChange)=\"$event ? (showRouteModal = true) : closeDetail(false)\"\n [routeData]=\"selectedRoute()\" \n [repository]=\"config.repository\" \n displayMode=\"catalog\"\n [noBackdrop]=\"true\"\n (edit)=\"editRoute.emit(selectedRoute()!)\"\n></lib-route-info-card>\n", styles: [":host{display:block}.cards-list-container{display:flex;flex-direction:column;height:100%;background:var(--bg-primary, white)}.cards-list-container.floating{position:absolute;top:12px;left:12px;width:280px;max-height:calc(100% - 24px);border-radius:12px;box-shadow:0 4px 24px #00000026;z-index:100;overflow:hidden}.cards-list-container.floating.collapsed{width:48px}.cards-list-container.sidebar{width:100%;border-right:1px solid var(--border-color, #e2e8f0)}.cards-list-container.inline{width:160px;min-width:160px;border-right:1px solid var(--border-color, #e2e8f0)}:host-context(.dark) .cards-list-container{background-color:#1e293b}:host-context(.dark) .cards-list-container.sidebar,:host-context(.dark) .cards-list-container.inline{border-color:#334155}.list-header{display:flex;align-items:center;justify-content:space-between;padding:12px;border-bottom:1px solid var(--border-color, #e2e8f0);background:var(--bg-secondary, #f8fafc)}:host-context(.dark) .list-header{background-color:#0f172a;border-color:#334155}.collapsed .list-header{padding:12px 8px;justify-content:center}.header-title{display:flex;align-items:center;gap:6px}.collapsed .header-title{display:none}.title-text{font-size:13px;font-weight:600;color:var(--text-primary, #1e293b)}:host-context(.dark) .title-text{color:#f1f5f9}.cards-scroll-container{flex:1;overflow-y:auto;overflow-x:hidden}.cards-list{display:flex;flex-direction:column;gap:8px;padding:8px}.card-wrapper{border-radius:8px;transition:all .2s ease}.route-card{position:relative;padding:6px 10px;display:flex;flex-direction:column;gap:2px;border-radius:8px;cursor:pointer;transition:all .15s ease;min-height:72px}.route-card:hover{border-color:var(--accent-color, #3b82f6);box-shadow:0 2px 8px #00000014}.task-header{display:flex;align-items:center;gap:6px;margin-bottom:4px}.job-code{font-size:13px;font-weight:600;color:var(--text-primary, #1e293b);white-space:nowrap;text-overflow:ellipsis;max-width:190px;overflow:hidden}:host-context(.dark) .job-code{color:#f1f5f9}.statusunit{border-radius:30px;font-size:12px;text-transform:capitalize;font-weight:600;width:20px;height:20px;text-align:center;line-height:20px}.statusunit.Ton{background:#ff7272}.statusunit.Load{background:#a3c52e}.statusunit.Hourly{background:#ae23d1}.location-flow{display:flex;flex-direction:column;align-items:flex-start;gap:2px;font-size:11px;color:var(--text-secondary, #64748b);margin-bottom:6px}.location-flow .pickup{display:inline;align-items:center;gap:3px;color:#22c55e;white-space:nowrap;text-overflow:ellipsis;max-width:200px;overflow:hidden;position:relative;padding-left:15px}.location-flow .pickup svg{width:8px;height:8px;position:absolute;left:0;top:5px}.location-flow .delivery{display:inline;align-items:center;gap:3px;color:#ef4444;white-space:nowrap;text-overflow:ellipsis;max-width:200px;overflow:hidden;position:relative;padding-left:15px;top:5px}.location-flow .delivery svg{width:8px;height:8px;position:absolute;left:0;top:5px}\n"] }]
682
+ args: [{ selector: 'lib-view-route-list', standalone: true, imports: [LucideAngularModule, RouteInfoCardComponent, NgClass], template: "<div\n class=\"cards-list-container\"\n [class.floating]=\"listMode === 'floating'\"\n [class.sidebar]=\"listMode === 'sidebar'\"\n [class.inline]=\"listMode === 'inline'\"\n [class.collapsed]=\"collapsed\"\n>\n @if (listMode !== 'inline') {\n <div class=\"list-header\">\n <div class=\"header-title\">\n <span class=\"title-text\">View Route</span>\n <span class=\"routes-count\">({{ routes.length || 0 }})</span>\n </div>\n <button\n class=\"collapse-btn\"\n (click)=\"toggleCollapse()\"\n [title]=\"collapsed ? 'Expand' : 'Collapse'\"\n >\n @if (collapsed) {\n <lucide-icon [img]=\"icons.ChevronRight\" [size]=\"16\"></lucide-icon>\n } @else {\n <lucide-icon [img]=\"icons.ChevronLeft\" [size]=\"16\"></lucide-icon>\n }\n </button>\n </div>\n } \n \n @if (!collapsed) {\n <div class=\"cards-scroll-container\" #scrollContainer>\n @if (isLoading) {\n <div class=\"list-loader\">\n <lucide-icon [img]=\"icons.LoaderCircle\" [size]=\"32\" class=\"animate-spin text-amber-500\"></lucide-icon>\n </div>\n }\n @if(!isLoading && routes && routes.length){\n <div class=\"cards-list\">\n @for (route of routes; track getRouteId(route)) {\n <div class=\"card-wrapper\">\n <div\n class=\"route-card bg-white dark:bg-slate-800 border transition-all duration-200\"\n [class.border-brand-blue]=\"selectedRouteIds.includes(getRouteId(route))\"\n [class.border-gray-200]=\"!selectedRouteIds.includes(getRouteId(route))\"\n [class.dark:border-slate-700]=\"!selectedRouteIds.includes(getRouteId(route))\"\n [class.selected]=\"selectedRouteIds.includes(getRouteId(route))\"\n >\n <div class=\"task-header justify-between items-start mb-1\">\n <h2 class=\"text-sm font-semibold text-gray-900 dark:text-white truncate max-w-[80%]\">\n {{ route.route_name || route.order_number || 'Unnamed Route' }}\n </h2>\n <div class=\"flex gap-2 shrink-0\">\n <div class=\"statusunit text-white\" [ngClass]=\"route.unit || ''\">\n {{ route.unit?.charAt(0) || 'U' }}\n </div>\n <button\n type=\"button\"\n class=\"text-gray-400 hover:text-brand-blue transition-colors\"\n (mouseenter)=\"openDetail(route, false)\"\n (mouseleave)=\"closeDetail(true)\"\n (click)=\"$event.stopPropagation(); openDetail(route, true)\"\n >\n <lucide-icon [img]=\"icons.Info\" [size]=\"18\"></lucide-icon>\n </button>\n </div>\n </div>\n \n @if (config.repository === 'coolmap' && route.customer_name) {\n <div class=\"text-[10px] text-gray-500 dark:text-slate-500 mb-2 uppercase tracking-wider font-medium truncate\">\n {{ route.customer_name }}\n </div>\n }\n\n <div class=\"location-flow bg-gray-50 dark:bg-slate-900/50 border border-gray-100 dark:border-slate-700/50 p-2 rounded-lg\">\n <div class=\"text-[11px] flex items-start gap-1.5 text-gray-600 dark:text-gray-400\">\n <div class=\"w-1.5 h-1.5 rounded-full bg-green-500 shrink-0 bullet mt-1\"></div>\n {{ (route.pickup_location || '').split('|')[1] || route.pickup_location || 'N/A' }}\n </div>\n <div class=\"text-[11px] flex items-start gap-1.5 mt-1 text-gray-600 dark:text-gray-400\">\n <div class=\"w-1.5 h-1.5 rounded-full bg-blue-500 shrink-0 bullet mt-1\"></div>\n {{ (route.delivery_location || '').split('|')[1] || route.delivery_location || 'N/A' }}\n </div>\n </div>\n </div>\n </div>\n }\n </div>\n } @else if (!isLoading && coolmapService.isDataFetched() && (!routes || routes.length === 0)) {\n <div class=\"p-8 text-center text-gray-400 text-sm\">\n No routes found.\n </div>\n }\n </div>\n }\n</div>\n\n<lib-route-info-card \n [modalOpen]=\"showRouteModal\" \n (modalOpenChange)=\"$event ? (showRouteModal = true) : closeDetail(false)\"\n [routeData]=\"selectedRoute()\" \n [repository]=\"config.repository\" \n displayMode=\"catalog\"\n [noBackdrop]=\"true\"\n (edit)=\"editRoute.emit(selectedRoute()!)\"\n></lib-route-info-card>\n", styles: [":host{display:block}.cards-list-container{display:flex;flex-direction:column;height:100%;background:var(--bg-primary, white)}.cards-list-container.floating{position:absolute;top:12px;left:12px;width:280px;max-height:calc(100% - 24px);border-radius:12px;box-shadow:0 4px 24px #00000026;z-index:100;overflow:hidden}.cards-list-container.floating.collapsed{width:48px}.cards-list-container.sidebar{width:100%;border-right:1px solid var(--border-color, #e2e8f0)}.cards-list-container.inline{width:160px;min-width:160px;border-right:1px solid var(--border-color, #e2e8f0)}:host-context(.dark) .cards-list-container{background-color:#1e293b}:host-context(.dark) .cards-list-container.sidebar,:host-context(.dark) .cards-list-container.inline{border-color:#334155}.list-header{display:flex;align-items:center;justify-content:space-between;padding:12px;border-bottom:1px solid var(--border-color, #e2e8f0);background:var(--bg-secondary, #f8fafc)}:host-context(.dark) .list-header{background-color:#0f172a;border-color:#334155}.collapsed .list-header{padding:12px 8px;justify-content:center}.header-title{display:flex;align-items:center;gap:6px}.collapsed .header-title{display:none}.title-text{font-size:13px;font-weight:600;color:var(--text-primary, #1e293b)}:host-context(.dark) .title-text{color:#f1f5f9}.cards-scroll-container{flex:1;overflow-y:auto;overflow-x:hidden}.cards-list{display:flex;flex-direction:column;gap:8px;padding:8px}.card-wrapper{border-radius:8px;transition:all .2s ease}.route-card{position:relative;padding:6px 10px;display:flex;flex-direction:column;gap:2px;border-radius:8px;cursor:pointer;transition:all .15s ease;min-height:72px}.route-card:hover{border-color:var(--accent-color, #3b82f6);box-shadow:0 2px 8px #00000014}.task-header{display:flex;align-items:center;gap:6px;margin-bottom:4px}.job-code{font-size:13px;font-weight:600;color:var(--text-primary, #1e293b);white-space:nowrap;text-overflow:ellipsis;max-width:190px;overflow:hidden}:host-context(.dark) .job-code{color:#f1f5f9}.statusunit{border-radius:30px;font-size:12px;text-transform:capitalize;font-weight:600;width:20px;height:20px;text-align:center;line-height:20px}.statusunit.Ton{background:#ff7272}.statusunit.Load{background:#a3c52e}.statusunit.Hourly{background:#ae23d1}.location-flow{display:flex;flex-direction:column;align-items:flex-start;gap:2px;font-size:11px;color:var(--text-secondary, #64748b);margin-bottom:6px}.location-flow .pickup{display:inline;align-items:center;gap:3px;color:#22c55e;white-space:nowrap;text-overflow:ellipsis;max-width:200px;overflow:hidden;position:relative;padding-left:15px}.location-flow .pickup svg{width:8px;height:8px;position:absolute;left:0;top:5px}.location-flow .delivery{display:inline;align-items:center;gap:3px;color:#ef4444;white-space:nowrap;text-overflow:ellipsis;max-width:200px;overflow:hidden;position:relative;padding-left:15px;top:5px}.location-flow .delivery svg{width:8px;height:8px;position:absolute;left:0;top:5px}.list-loader{position:absolute;inset:0;background:#fff6;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);display:flex;align-items:center;justify-content:center;z-index:50;border-radius:0 0 12px 12px}:host-context(.dark) .list-loader{background:#0f172a66}\n"] }]
671
683
  }], ctorParameters: () => [], propDecorators: { listMode: [{
672
684
  type: Input
673
685
  }], collapsible: [{
@@ -676,6 +688,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
676
688
  type: Input
677
689
  }], selectedRouteIds: [{
678
690
  type: Input
691
+ }], isLoading: [{
692
+ type: Input
679
693
  }], routeSelect: [{
680
694
  type: Output
681
695
  }], editRoute: [{
@@ -762,6 +776,7 @@ class AddRouteComponent {
762
776
  // ElementRefs for Google Maps integration
763
777
  filterPickup = viewChild('filterPickup', ...(ngDevMode ? [{ debugName: "filterPickup" }] : []));
764
778
  filterDelivery = viewChild('filterDelivery', ...(ngDevMode ? [{ debugName: "filterDelivery" }] : []));
779
+ unitDropdownWrapper = viewChild('unitDropdownWrapper', ...(ngDevMode ? [{ debugName: "unitDropdownWrapper" }] : []));
765
780
  get isSystemPickup() {
766
781
  return this.addRouteForm.get('pickUpSearchOption')?.value === 'system';
767
782
  }
@@ -771,9 +786,9 @@ class AddRouteComponent {
771
786
  get selectedUnitName() {
772
787
  const unitId = this.addRouteForm.value.unit_id;
773
788
  if (!unitId)
774
- return 'Select Unit/Driver';
789
+ return 'Select Unit';
775
790
  const unit = this.unitsList().find(u => u.id === unitId);
776
- return unit ? unit.type : 'Select Unit/Driver';
791
+ return unit ? unit.type : 'Select Unit';
777
792
  }
778
793
  constructor() {
779
794
  effect(() => {
@@ -1168,6 +1183,8 @@ class AddRouteComponent {
1168
1183
  });
1169
1184
  }
1170
1185
  close() {
1186
+ this.dragX.set(0);
1187
+ this.dragY.set(0);
1171
1188
  const isCoolmap = this.config.repository === 'coolmap';
1172
1189
  this.addRouteForm.reset({
1173
1190
  pickUpSearchOption: isCoolmap ? 'system' : 'google',
@@ -1181,9 +1198,24 @@ class AddRouteComponent {
1181
1198
  };
1182
1199
  // Dynamic dropdown state logic
1183
1200
  dropdownOpen = signal(false, ...(ngDevMode ? [{ debugName: "dropdownOpen" }] : []));
1201
+ dropdownDirection = signal('down', ...(ngDevMode ? [{ debugName: "dropdownDirection" }] : []));
1184
1202
  selectedUnitDriver = signal(null, ...(ngDevMode ? [{ debugName: "selectedUnitDriver" }] : []));
1185
1203
  toggleDropdown() {
1186
- this.dropdownOpen.update(v => !v);
1204
+ this.dropdownOpen.update(v => {
1205
+ if (!v) {
1206
+ this.updateDropdownDirection();
1207
+ }
1208
+ return !v;
1209
+ });
1210
+ }
1211
+ updateDropdownDirection() {
1212
+ const el = this.unitDropdownWrapper()?.nativeElement;
1213
+ if (el) {
1214
+ const rect = el.getBoundingClientRect();
1215
+ const spaceBelow = window.innerHeight - rect.bottom;
1216
+ // If less than 250px space below, open upwards
1217
+ this.dropdownDirection.set(spaceBelow < 150 ? 'up' : 'down');
1218
+ }
1187
1219
  }
1188
1220
  selectOption(opt) {
1189
1221
  this.selectedUnitDriver.set(opt);
@@ -1228,23 +1260,26 @@ class AddRouteComponent {
1228
1260
  return;
1229
1261
  this.dragX.set(this.dragInitialX + (event.clientX - this.dragStartX));
1230
1262
  this.dragY.set(this.dragInitialY + (event.clientY - this.dragStartY));
1263
+ if (this.dropdownOpen()) {
1264
+ this.updateDropdownDirection();
1265
+ }
1231
1266
  }
1232
1267
  onMouseUp() {
1233
1268
  this.isDragging = false;
1234
1269
  }
1235
1270
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: AddRouteComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1236
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: AddRouteComponent, isStandalone: true, selector: "lib-add-route", inputs: { modalOpen: { classPropertyName: "modalOpen", publicName: "modalOpen", isSignal: true, isRequired: false, transformFunction: null }, routeData: { classPropertyName: "routeData", publicName: "routeData", isSignal: true, isRequired: false, transformFunction: null }, customerRepoDetails: { classPropertyName: "customerRepoDetails", publicName: "customerRepoDetails", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { modalOpenChange: "modalOpenChange", routeDeleted: "routeDeleted", routeSaved: "routeSaved" }, host: { listeners: { "document:click": "closeDropdowns($event)", "document:mousemove": "onMouseMove($event)", "document:mouseup": "onMouseUp()" } }, viewQueries: [{ propertyName: "filterPickup", first: true, predicate: ["filterPickup"], descendants: true, isSignal: true }, { propertyName: "filterDelivery", first: true, predicate: ["filterDelivery"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (modalOpen()) {\n<div class=\"fixed inset-0 z-[112] pointer-events-none overflow-y-auto\" id=\"add-route-modal\">\n <div class=\"flex min-h-full items-center justify-center p-4\">\n <form\n [formGroup]=\"addRouteForm\"\n (ngSubmit)=\"saveRoute()\"\n class=\"pointer-events-auto relative bg-white dark:bg-slate-800 rounded-lg shadow-xl animate-slide-up w-[1000px]\"\n [style.transform]=\"'translate(' + dragX() + 'px, ' + dragY() + 'px)'\"\n tabindex=\"-1\"\n >\n <div\n class=\"flex items-center justify-between p-4 border-b border-gray-200 dark:border-slate-700 cursor-move\"\n (mousedown)=\"startDrag($event)\"\n >\n <h3 class=\"flex items-center gap-1 text-lg font-semibold text-gray-900 dark:text-white\">\n {{ routeId() ? 'Edit Route' : 'Add Route' }}\n </h3>\n <div class=\"flex items-center gap-4\">\n <button\n type=\"submit\"\n [disabled]=\"(routeId() ? (addRouteForm.invalid || !addRouteForm.dirty) : addRouteForm.invalid) || !pickupSelected() || !deliverySelected() || showLoader()\"\n class=\"inline-flex items-center justify-center gap-2 px-4 py-2 bg-amber-500 hover:bg-amber-600 disabled:opacity-50 text-white font-medium rounded-lg transition-colors text-sm\">\n @if (showLoader()) {\n <lucide-icon [img]=\"icons.LoaderCircle\" class=\"animate-spin\" [size]=\"18\"></lucide-icon>\n } @else {\n {{ routeId() ? 'Update' : 'Save' }}\n }\n </button>\n @if (routeId()) {\n <button\n type=\"button\"\n (click)=\"promptDelete()\"\n class=\"inline-flex items-center gap-2 px-4 py-2 bg-red-600 text-white hover:bg-red-700 font-medium rounded-lg transition-colors text-sm\"\n >\n Delete\n </button>\n }\n <button\n type=\"button\"\n class=\"inline-flex items-center gap-2 px-4 py-2 bg-gray-600 text-white hover:bg-gray-700 font-medium rounded-lg transition-colors text-sm\"\n (click)=\"close()\"\n >\n Close\n </button>\n </div>\n </div>\n <div class=\"p-4\">\n <div class=\"grid grid-cols-2 mb-[1rem] gap-4\">\n <div>\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Route Name</label\n >\n <input\n type=\"text\"\n formControlName=\"route_name\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n />\n </div>\n <div class=\"relative\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Customer Name</label>\n <div class=\"relative\">\n <input\n type=\"text\"\n formControlName=\"customer_name\"\n (focus)=\"showCustomerDropdown.set(true)\"\n (blur)=\"hideDropdown('customer')\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-300 dark:border-slate-700 bg-gray-100 dark:bg-slate-900 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm pr-10\"\n />\n @if (loadingCustomers()) {\n <div class=\"absolute right-3 top-1/2 -translate-y-1/2\">\n <lucide-icon [img]=\"icons.LoaderCircle\" [size]=\"18\" class=\"animate-spin text-blue-500\"></lucide-icon>\n </div>\n }\n </div>\n @if (showCustomerDropdown() && customerOptions().length > 0) {\n <div class=\"absolute z-50 w-full mt-1 bg-white dark:bg-slate-800 border border-gray-200 dark:border-slate-700 rounded-lg shadow-lg max-h-48 overflow-y-auto\">\n @for (cust of customerOptions(); track cust.customer_id) {\n <div \n (mousedown)=\"addRouteForm.patchValue({customer_name: cust.customer_name}); addRouteForm.markAsDirty()\"\n class=\"px-4 py-2 hover:bg-gray-100 dark:hover:bg-slate-700 cursor-pointer text-sm text-gray-900 dark:text-white\">\n {{ cust.customer_name }}\n </div>\n }\n </div>\n }\n </div>\n </div>\n <div class=\"grid grid-cols-1 mb-[1rem]\">\n <div class=\"location-flow rounded-lg\">\n @if (config.repository === 'coolmap') {\n <div class=\"flex gap-2 mb-2\">\n <div class=\"radio w-100 md:w-auto\">\n <input\n type=\"radio\"\n formControlName=\"pickUpSearchOption\"\n value=\"system\"\n class=\"shrink-0 size-4 bg-transparent border-line-3 rounded-full shadow-2xs text-primary focus:ring-0 focus:ring-offset-0 checked:bg-primary-checked checked:border-primary-checked\"\n />\n <label\n class=\"border-solid border-1 border-grey dark:border-slate-400 block shadow-md rounded-lg lg:whitespace-nowrap w-full\"\n >\n <div class=\"flex justify-between items-center px-4 py-2 text-xs lg:text-base\">\n <div class=\"tracking-wide text-xs\">System Search</div>\n </div>\n </label>\n </div>\n <div class=\"radio w-100 md:w-auto ml-2\">\n <input\n type=\"radio\"\n formControlName=\"pickUpSearchOption\"\n value=\"google\"\n class=\"shrink-0 size-4 bg-transparent border-line-3 rounded-full shadow-2xs text-primary focus:ring-0 focus:ring-offset-0 checked:bg-primary-checked checked:border-primary-checked\"\n />\n <label\n class=\"border-solid border-1 border-grey dark:border-slate-400 block shadow-md rounded-lg lg:whitespace-nowrap w-full\"\n >\n <div class=\"flex justify-between items-center px-4 py-2 text-xs lg:text-base\">\n <div class=\"tracking-wide text-xs\">Google Search</div>\n </div>\n </label>\n </div>\n </div>\n }\n <div class=\"relative autocomplete-field\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Pickup Location</label>\n <input\n #filterPickup\n type=\"text\"\n formControlName=\"pickup_location\"\n placeholder=\"Pickup\"\n (input)=\"!isSystemPickup ? onInputChange($event, 'pickup') : null\"\n (focus)=\"onFocus('pickup')\"\n (blur)=\"isSystemPickup ? hideDropdown('pickup') : null\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm pr-10\"\n />\n @if (loadingLocations()) {\n <div class=\"absolute right-3 top-1/2 -translate-y-1/2\">\n <lucide-icon [img]=\"icons.LoaderCircle\" [size]=\"18\" class=\"animate-spin text-blue-500\"></lucide-icon>\n </div>\n }\n \n <!-- System Suggestions -->\n @if (isSystemPickup && showPickupDropdown() && pickupOptions().length > 0) {\n <div class=\"absolute z-50 w-full mt-1 bg-white dark:bg-slate-800 border border-gray-200 dark:border-slate-700 rounded-lg shadow-lg max-h-48 overflow-y-auto pickup-system-dropdown\">\n @for (loc of pickupOptions(); track loc.formatted_address) {\n <div \n (mousedown)=\"patchAddressValue(loc, 'pickup')\"\n class=\"px-4 py-2 hover:bg-gray-100 dark:hover:bg-slate-700 cursor-pointer text-sm text-gray-900 dark:text-white border-b border-gray-50 dark:border-slate-700 last:border-0\">\n {{ loc.formatted_address }}\n </div>\n }\n </div>\n }\n\n <!-- Google Suggestions -->\n @if (!isSystemPickup && showPickupSuggestions() && pickupSuggestions().length > 0) {\n <div class=\"absolute z-50 w-full mt-1 bg-white dark:bg-slate-800 border border-gray-200 dark:border-slate-700 rounded-lg shadow-lg max-h-48 overflow-y-auto pickup-suggestions\">\n @for (suggestion of pickupSuggestions(); track suggestion.placePrediction?.text?.toString() || $index) {\n <div \n (click)=\"onSuggestionClick(suggestion, 'pickup')\"\n class=\"px-4 py-2.5 hover:bg-amber-50 dark:hover:bg-amber-900/20 cursor-pointer text-sm text-gray-700 dark:text-gray-300 border-b border-gray-100 dark:border-slate-700 last:border-0 transition-colors\">\n {{ suggestion.placePrediction?.text?.toString() }}\n </div>\n }\n </div>\n }\n @if ((saveAttempted() || addRouteForm.get('pickup_location')?.dirty) && !pickupSelected() && addRouteForm.get('pickup_location')?.value) {\n <div class=\"text-red-500 text-[10px] mt-1 font-medium italic flex items-center gap-1\">\n Please select a valid pickup location from suggestions\n </div>\n }\n </div>\n </div>\n </div>\n <div class=\"grid grid-cols-1 mb-[1rem]\">\n <div class=\"location-flow rounded-lg\">\n @if (config.repository === 'coolmap') {\n <div class=\"flex gap-2 mb-2\">\n <div class=\"radio w-100 md:w-auto\">\n <input\n type=\"radio\"\n formControlName=\"deliverySearchOtption\"\n value=\"system\"\n class=\"shrink-0 size-4 bg-transparent border-line-3 rounded-full shadow-2xs text-primary focus:ring-0 focus:ring-offset-0 checked:bg-primary-checked checked:border-primary-checked\"/>\n <label\n class=\"border-solid border-1 border-grey dark:border-slate-400 block shadow-md rounded-lg lg:whitespace-nowrap w-full\">\n <div class=\"flex justify-between items-center px-4 py-2 text-xs lg:text-base\">\n <div class=\"tracking-wide text-xs\">System Search</div>\n </div>\n </label>\n </div>\n <div class=\"radio w-100 md:w-auto ml-2\">\n <input\n type=\"radio\"\n formControlName=\"deliverySearchOtption\"\n value=\"google\"\n class=\"shrink-0 size-4 bg-transparent border-line-3 rounded-full shadow-2xs text-primary focus:ring-0 focus:ring-offset-0 checked:bg-primary-checked checked:border-primary-checked\"/>\n <label\n class=\"border-solid border-1 border-grey dark:border-slate-400 block shadow-md rounded-lg lg:whitespace-nowrap w-full ml-2\">\n <div class=\"flex justify-between items-center px-4 py-2 text-xs lg:text-base\">\n <div class=\"tracking-wide text-xs\">Google Search</div>\n </div>\n </label>\n </div>\n </div>\n }\n <div class=\"relative autocomplete-field\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Delivery Location</label>\n <input\n #filterDelivery\n type=\"text\"\n formControlName=\"delivery_location\"\n placeholder=\"Delivery\"\n (input)=\"!isSystemDelivery ? onInputChange($event, 'delivery') : null\"\n (focus)=\"onFocus('delivery')\"\n (blur)=\"isSystemDelivery ? hideDropdown('delivery') : null\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm pr-10\"\n />\n @if (loadingLocations()) {\n <div class=\"absolute right-3 top-1/2 -translate-y-1/2\">\n <lucide-icon [img]=\"icons.LoaderCircle\" [size]=\"18\" class=\"animate-spin text-blue-500\"></lucide-icon>\n </div>\n }\n\n <!-- System Suggestions -->\n @if (isSystemDelivery && showDeliveryDropdown() && deliveryOptions().length > 0) {\n <div class=\"absolute z-50 w-full mt-1 bg-white dark:bg-slate-800 border border-gray-200 dark:border-slate-700 rounded-lg shadow-lg max-h-48 overflow-y-auto delivery-system-dropdown\">\n @for (loc of deliveryOptions(); track loc.formatted_address) {\n <div \n (mousedown)=\"patchAddressValue(loc, 'delivery')\"\n class=\"px-4 py-2 hover:bg-gray-100 dark:hover:bg-slate-700 cursor-pointer text-sm text-gray-900 dark:text-white border-b border-gray-50 dark:border-slate-700 last:border-0\">\n {{ loc.formatted_address }}\n </div>\n }\n </div>\n }\n\n <!-- Google Suggestions -->\n @if (!isSystemDelivery && showDeliverySuggestions() && deliverySuggestions().length > 0) {\n <div class=\"absolute z-50 w-full mt-1 bg-white dark:bg-slate-800 border border-gray-200 dark:border-slate-700 rounded-lg shadow-lg max-h-48 overflow-y-auto delivery-suggestions\">\n @for (suggestion of deliverySuggestions(); track suggestion.placePrediction?.text?.toString() || $index) {\n <div \n (click)=\"onSuggestionClick(suggestion, 'delivery')\"\n class=\"px-4 py-2.5 hover:bg-amber-50 dark:hover:bg-amber-900/20 cursor-pointer text-sm text-gray-700 dark:text-gray-300 border-b border-gray-100 dark:border-slate-700 last:border-0 transition-colors\">\n {{ suggestion.placePrediction?.text?.toString() }}\n </div>\n }\n </div>\n }\n @if ((saveAttempted() || addRouteForm.get('delivery_location')?.dirty) && !deliverySelected() && addRouteForm.get('delivery_location')?.value) {\n <div class=\"text-red-500 text-[10px] mt-1 font-medium italic flex items-center gap-1\">\n Please select a valid delivery location from suggestions\n </div>\n }\n </div>\n </div>\n </div>\n <div class=\"flex gap-4 flex-col md:flex-row\">\n <div class=\"w-full md:w-[70%]\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Notes</label\n >\n <textarea\n formControlName=\"note\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm h-[46px]\"\n ></textarea>\n </div>\n <div class=\"w-full md:w-[30%]\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Unit Type</label\n >\n <div class=\"relative w-full\">\n <button\n type=\"button\"\n (click)=\"toggleDropdown(); $event.stopPropagation()\"\n class=\"w-full flex justify-between items-center px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm text-left\"\n >\n <span>{{ selectedUnitName }}</span>\n <lucide-icon [img]=\"icons.ChevronDown\" [size]=\"16\" class=\"text-gray-400\"></lucide-icon>\n </button>\n @if (dropdownOpen()) {\n <div class=\"absolute z-10 mt-1 w-full bg-white dark:bg-slate-800 rounded-lg shadow-lg border border-gray-200 dark:border-slate-700 py-1 max-h-60 overflow-auto\">\n @for (opt of unitsList(); track opt.id) {\n <button\n type=\"button\"\n (click)=\"addRouteForm.patchValue({unit_id: opt.id}); addRouteForm.markAsDirty(); checkAndFetchRouteInformation(); dropdownOpen.set(false)\"\n class=\"w-full flex items-center justify-between px-4 py-2 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-slate-700 transition\"\n >\n <span>{{ opt.type }}</span>\n @if (addRouteForm.value.unit_id === opt.id) {\n <lucide-icon [img]=\"icons.Check\" [size]=\"16\" class=\"text-blue-500\"></lucide-icon>\n }\n </button>\n }\n </div>\n }\n </div>\n </div>\n </div>\n <div class=\"grid grid-cols-2 mt-2 gap-4\">\n <div class=\"flex flex-col lg:flex-row gap-2\">\n @if(addRouteForm.value.estimated_distance){\n <span\n class=\"text-[10px] text-gray-500 dark:text-slate-400 mb-1 whitespace-nowrap italic\">\n Estimation of miles - <b>{{ addRouteForm.value.estimated_distance }}</b>\n </span>\n }\n\n @if(addRouteForm.value.estimated_time){\n <span\n class=\"text-[10px] text-gray-500 dark:text-slate-400 mb-1 whitespace-nowrap italic\">\n Estimation of time - <b>{{ addRouteForm.value.estimated_time }}</b>\n </span>\n }\n </div>\n <div class=\"flex flex-col lg:flex-row gap-2 justify-end\">\n @if (config.repository !== 'customer' && addRouteForm.value.trucker_pay_estimate) {\n <span\n class=\"text-[10px] text-gray-500 dark:text-slate-400 mb-1 whitespace-nowrap italic\">\n Trucker Pay Estimate - <b>{{ addRouteForm.value.trucker_pay_estimate | currency }}</b>\n </span>\n }\n @if(addRouteForm.value.customer_price_estimate){\n <span\n class=\"text-[10px] text-gray-500 dark:text-slate-400 mb-1 whitespace-nowrap italic\">\n Customer Price Estimate - <b>{{ addRouteForm.value.customer_price_estimate | currency }}</b>\n </span>\n }\n </div>\n </div>\n </div>\n </form>\n\n @if (showDeleteModal()) {\n <div class=\"fixed inset-0 z-[120] flex items-center justify-center bg-black/60 backdrop-blur-sm animate-fade-in pointer-events-auto\">\n <div class=\"bg-white dark:bg-slate-900 rounded-xl shadow-2xl p-6 max-w-sm w-full mx-4 border border-gray-200 dark:border-slate-800\" (click)=\"$event.stopPropagation()\">\n <h3 class=\"text-lg font-bold text-gray-900 dark:text-white mb-2 text-center\">Delete Route?</h3>\n <p class=\"text-gray-600 dark:text-gray-400 text-sm mb-6 text-center\">\n Are you sure you want to delete this route?\n </p>\n <div class=\"flex justify-center gap-3\">\n <button\n type=\"button\"\n (click)=\"showDeleteModal.set(false)\"\n class=\"px-4 py-2 text-sm font-medium text-gray-700 bg-gray-100 hover:bg-gray-200 dark:text-gray-300 dark:bg-slate-800 dark:hover:bg-slate-700 rounded-lg transition-colors\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n (click)=\"confirmDelete()\"\n class=\"px-4 py-2 text-sm font-medium text-white bg-red-600 hover:bg-red-700 rounded-lg shadow-sm transition-colors\"\n >\n Delete\n </button>\n </div>\n </div>\n </div>\n }\n </div>\n</div>\n}\n", styles: ["@keyframes slide-up{0%{opacity:0;transform:translateY(10px) scale(.95)}to{opacity:1;transform:translateY(0) scale(1)}}.animate-fade-in{animation:fade-in .2s ease-out}.animate-slide-up{animation:slide-up .2s ease-out}.radio{position:relative}.radio input{position:absolute;top:50%;transform:translateY(-50%);left:0;opacity:0;width:100%;height:100%;cursor:pointer}.radio svg{opacity:.5}.radio label{height:auto;border-width:1px;border-color:#334155}.radio input:checked+label{border-color:#3b558e;background-color:#334155;color:#fff}.radio input:checked+label svg{opacity:1}.radio label:hover{cursor:pointer}.grid-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:10px}\n"], dependencies: [{ kind: "ngmodule", type: LucideAngularModule }, { kind: "component", type: i1.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2$2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$2.RadioControlValueAccessor, selector: "input[type=radio][formControlName],input[type=radio][formControl],input[type=radio][ngModel]", inputs: ["name", "formControlName", "value"] }, { kind: "directive", type: i2$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i2.CurrencyPipe, name: "currency" }] });
1271
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: AddRouteComponent, isStandalone: true, selector: "lib-add-route", inputs: { modalOpen: { classPropertyName: "modalOpen", publicName: "modalOpen", isSignal: true, isRequired: false, transformFunction: null }, routeData: { classPropertyName: "routeData", publicName: "routeData", isSignal: true, isRequired: false, transformFunction: null }, customerRepoDetails: { classPropertyName: "customerRepoDetails", publicName: "customerRepoDetails", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { modalOpenChange: "modalOpenChange", routeDeleted: "routeDeleted", routeSaved: "routeSaved" }, host: { listeners: { "document:click": "closeDropdowns($event)", "document:mousemove": "onMouseMove($event)", "document:mouseup": "onMouseUp()" } }, viewQueries: [{ propertyName: "filterPickup", first: true, predicate: ["filterPickup"], descendants: true, isSignal: true }, { propertyName: "filterDelivery", first: true, predicate: ["filterDelivery"], descendants: true, isSignal: true }, { propertyName: "unitDropdownWrapper", first: true, predicate: ["unitDropdownWrapper"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (modalOpen()) {\n<div class=\"fixed inset-0 z-[112] pointer-events-none overflow-y-auto\" id=\"add-route-modal\">\n <div class=\"flex min-h-full items-end justify-center p-4 pb-12 customer-add-route\">\n <div class=\"pointer-events-auto animate-slide-up ml-[300px]\">\n <form\n [formGroup]=\"addRouteForm\"\n (ngSubmit)=\"saveRoute()\"\n class=\"relative bg-white dark:bg-slate-800 rounded-lg shadow-xl w-[1000px]\"\n [style.transform]=\"'translate(' + dragX() + 'px, ' + dragY() + 'px)'\"\n tabindex=\"-1\"\n >\n <div\n class=\"flex items-center justify-between p-4 border-b border-gray-200 dark:border-slate-700 cursor-move\"\n (mousedown)=\"startDrag($event)\"\n >\n <h3 class=\"flex items-center gap-1 text-lg font-semibold text-gray-900 dark:text-white\">\n {{ routeId() ? 'Edit Route' : 'Add Route' }}\n </h3>\n <div class=\"flex items-center gap-4\">\n <button\n type=\"submit\"\n [disabled]=\"(routeId() ? (addRouteForm.invalid || !addRouteForm.dirty) : addRouteForm.invalid) || !pickupSelected() || !deliverySelected() || showLoader()\"\n class=\"inline-flex items-center justify-center gap-2 px-4 py-2 bg-amber-500 hover:bg-amber-600 disabled:opacity-50 text-white font-medium rounded-lg transition-colors text-sm\">\n @if (showLoader()) {\n <lucide-icon [img]=\"icons.LoaderCircle\" class=\"animate-spin\" [size]=\"18\"></lucide-icon>\n } @else {\n {{ routeId() ? 'Update' : 'Save' }}\n }\n </button>\n @if (routeId()) {\n <button\n type=\"button\"\n (click)=\"promptDelete()\"\n class=\"inline-flex items-center gap-2 px-4 py-2 bg-red-600 text-white hover:bg-red-700 font-medium rounded-lg transition-colors text-sm\"\n >\n Delete\n </button>\n }\n <button\n type=\"button\"\n class=\"inline-flex items-center gap-2 px-4 py-2 bg-gray-600 text-white hover:bg-gray-700 font-medium rounded-lg transition-colors text-sm\"\n (click)=\"close()\"\n >\n Close\n </button>\n </div>\n </div>\n <div class=\"p-4\">\n <div class=\"grid grid-cols-2 mb-[1rem] gap-4\">\n <div>\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Route Name</label\n >\n <input\n type=\"text\"\n formControlName=\"route_name\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n />\n </div>\n <div class=\"relative\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Customer Name</label>\n <div class=\"relative\">\n <input\n type=\"text\"\n formControlName=\"customer_name\"\n (focus)=\"showCustomerDropdown.set(true)\"\n (blur)=\"hideDropdown('customer')\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-300 dark:border-slate-700 bg-gray-100 dark:bg-slate-900 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm pr-10\"\n />\n @if (loadingCustomers()) {\n <div class=\"absolute right-3 top-1/2 -translate-y-1/2\">\n <lucide-icon [img]=\"icons.LoaderCircle\" [size]=\"18\" class=\"animate-spin text-blue-500\"></lucide-icon>\n </div>\n }\n </div>\n @if (showCustomerDropdown() && customerOptions().length > 0) {\n <div class=\"absolute z-50 w-full mt-1 bg-white dark:bg-slate-800 border border-gray-200 dark:border-slate-700 rounded-lg shadow-lg max-h-48 overflow-y-auto\">\n @for (cust of customerOptions(); track cust.customer_id) {\n <div \n (mousedown)=\"addRouteForm.patchValue({customer_name: cust.customer_name}); addRouteForm.markAsDirty()\"\n class=\"px-4 py-2 hover:bg-gray-100 dark:hover:bg-slate-700 cursor-pointer text-sm text-gray-900 dark:text-white\">\n {{ cust.customer_name }}\n </div>\n }\n </div>\n }\n </div>\n </div>\n <div class=\"grid grid-cols-1 mb-[1rem]\">\n <div class=\"location-flow rounded-lg\">\n @if (config.repository === 'coolmap') {\n <div class=\"flex gap-2 mb-2\">\n <div class=\"radio w-100 md:w-auto\">\n <input\n type=\"radio\"\n formControlName=\"pickUpSearchOption\"\n value=\"system\"\n class=\"shrink-0 size-4 bg-transparent border-line-3 rounded-full shadow-2xs text-primary focus:ring-0 focus:ring-offset-0 checked:bg-primary-checked checked:border-primary-checked\"\n />\n <label\n class=\"border-solid border-1 border-grey dark:border-slate-400 block shadow-md rounded-lg lg:whitespace-nowrap w-full\"\n >\n <div class=\"flex justify-between items-center px-4 py-2 text-xs lg:text-base\">\n <div class=\"tracking-wide text-xs\">System Search</div>\n </div>\n </label>\n </div>\n <div class=\"radio w-100 md:w-auto ml-2\">\n <input\n type=\"radio\"\n formControlName=\"pickUpSearchOption\"\n value=\"google\"\n class=\"shrink-0 size-4 bg-transparent border-line-3 rounded-full shadow-2xs text-primary focus:ring-0 focus:ring-offset-0 checked:bg-primary-checked checked:border-primary-checked\"\n />\n <label\n class=\"border-solid border-1 border-grey dark:border-slate-400 block shadow-md rounded-lg lg:whitespace-nowrap w-full\"\n >\n <div class=\"flex justify-between items-center px-4 py-2 text-xs lg:text-base\">\n <div class=\"tracking-wide text-xs\">Google Search</div>\n </div>\n </label>\n </div>\n </div>\n }\n <div class=\"relative autocomplete-field\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Pickup Location</label>\n <input\n #filterPickup\n type=\"text\"\n formControlName=\"pickup_location\"\n placeholder=\"Pickup\"\n (input)=\"!isSystemPickup ? onInputChange($event, 'pickup') : null\"\n (focus)=\"onFocus('pickup')\"\n (blur)=\"isSystemPickup ? hideDropdown('pickup') : null\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm pr-10\"\n />\n @if (loadingLocations()) {\n <div class=\"absolute right-3 top-1/2 -translate-y-1/2\">\n <lucide-icon [img]=\"icons.LoaderCircle\" [size]=\"18\" class=\"animate-spin text-blue-500\"></lucide-icon>\n </div>\n }\n \n <!-- System Suggestions -->\n @if (isSystemPickup && showPickupDropdown() && pickupOptions().length > 0) {\n <div class=\"absolute z-50 w-full mt-1 bg-white dark:bg-slate-800 border border-gray-200 dark:border-slate-700 rounded-lg shadow-lg max-h-48 overflow-y-auto pickup-system-dropdown\">\n @for (loc of pickupOptions(); track loc.formatted_address) {\n <div \n (mousedown)=\"patchAddressValue(loc, 'pickup')\"\n class=\"px-4 py-2 hover:bg-gray-100 dark:hover:bg-slate-700 cursor-pointer text-sm text-gray-900 dark:text-white border-b border-gray-50 dark:border-slate-700 last:border-0\">\n {{ loc.formatted_address }}\n </div>\n }\n </div>\n }\n\n <!-- Google Suggestions -->\n @if (!isSystemPickup && showPickupSuggestions() && pickupSuggestions().length > 0) {\n <div class=\"absolute z-50 w-full mt-1 bg-white dark:bg-slate-800 border border-gray-200 dark:border-slate-700 rounded-lg shadow-lg max-h-48 overflow-y-auto pickup-suggestions\">\n @for (suggestion of pickupSuggestions(); track suggestion.placePrediction?.text?.toString() || $index) {\n <div \n (click)=\"onSuggestionClick(suggestion, 'pickup')\"\n class=\"px-4 py-2.5 hover:bg-amber-50 dark:hover:bg-amber-900/20 cursor-pointer text-sm text-gray-700 dark:text-gray-300 border-b border-gray-100 dark:border-slate-700 last:border-0 transition-colors\">\n {{ suggestion.placePrediction?.text?.toString() }}\n </div>\n }\n </div>\n }\n @if ((saveAttempted() || addRouteForm.get('pickup_location')?.dirty) && !pickupSelected() && addRouteForm.get('pickup_location')?.value) {\n <div class=\"text-red-500 text-[10px] mt-1 font-medium italic flex items-center gap-1\">\n Please select a valid pickup location from suggestions\n </div>\n }\n </div>\n </div>\n </div>\n <div class=\"grid grid-cols-1 mb-[1rem]\">\n <div class=\"location-flow rounded-lg\">\n @if (config.repository === 'coolmap') {\n <div class=\"flex gap-2 mb-2\">\n <div class=\"radio w-100 md:w-auto\">\n <input\n type=\"radio\"\n formControlName=\"deliverySearchOtption\"\n value=\"system\"\n class=\"shrink-0 size-4 bg-transparent border-line-3 rounded-full shadow-2xs text-primary focus:ring-0 focus:ring-offset-0 checked:bg-primary-checked checked:border-primary-checked\"/>\n <label\n class=\"border-solid border-1 border-grey dark:border-slate-400 block shadow-md rounded-lg lg:whitespace-nowrap w-full\">\n <div class=\"flex justify-between items-center px-4 py-2 text-xs lg:text-base\">\n <div class=\"tracking-wide text-xs\">System Search</div>\n </div>\n </label>\n </div>\n <div class=\"radio w-100 md:w-auto ml-2\">\n <input\n type=\"radio\"\n formControlName=\"deliverySearchOtption\"\n value=\"google\"\n class=\"shrink-0 size-4 bg-transparent border-line-3 rounded-full shadow-2xs text-primary focus:ring-0 focus:ring-offset-0 checked:bg-primary-checked checked:border-primary-checked\"/>\n <label\n class=\"border-solid border-1 border-grey dark:border-slate-400 block shadow-md rounded-lg lg:whitespace-nowrap w-full ml-2\">\n <div class=\"flex justify-between items-center px-4 py-2 text-xs lg:text-base\">\n <div class=\"tracking-wide text-xs\">Google Search</div>\n </div>\n </label>\n </div>\n </div>\n }\n <div class=\"relative autocomplete-field\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Delivery Location</label>\n <input\n #filterDelivery\n type=\"text\"\n formControlName=\"delivery_location\"\n placeholder=\"Delivery\"\n (input)=\"!isSystemDelivery ? onInputChange($event, 'delivery') : null\"\n (focus)=\"onFocus('delivery')\"\n (blur)=\"isSystemDelivery ? hideDropdown('delivery') : null\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm pr-10\"\n />\n @if (loadingLocations()) {\n <div class=\"absolute right-3 top-1/2 -translate-y-1/2\">\n <lucide-icon [img]=\"icons.LoaderCircle\" [size]=\"18\" class=\"animate-spin text-blue-500\"></lucide-icon>\n </div>\n }\n\n <!-- System Suggestions -->\n @if (isSystemDelivery && showDeliveryDropdown() && deliveryOptions().length > 0) {\n <div class=\"absolute z-50 w-full mt-1 bg-white dark:bg-slate-800 border border-gray-200 dark:border-slate-700 rounded-lg shadow-lg max-h-48 overflow-y-auto delivery-system-dropdown\">\n @for (loc of deliveryOptions(); track loc.formatted_address) {\n <div \n (mousedown)=\"patchAddressValue(loc, 'delivery')\"\n class=\"px-4 py-2 hover:bg-gray-100 dark:hover:bg-slate-700 cursor-pointer text-sm text-gray-900 dark:text-white border-b border-gray-50 dark:border-slate-700 last:border-0\">\n {{ loc.formatted_address }}\n </div>\n }\n </div>\n }\n\n <!-- Google Suggestions -->\n @if (!isSystemDelivery && showDeliverySuggestions() && deliverySuggestions().length > 0) {\n <div class=\"absolute z-50 w-full mt-1 bg-white dark:bg-slate-800 border border-gray-200 dark:border-slate-700 rounded-lg shadow-lg max-h-48 overflow-y-auto delivery-suggestions\">\n @for (suggestion of deliverySuggestions(); track suggestion.placePrediction?.text?.toString() || $index) {\n <div \n (click)=\"onSuggestionClick(suggestion, 'delivery')\"\n class=\"px-4 py-2.5 hover:bg-amber-50 dark:hover:bg-amber-900/20 cursor-pointer text-sm text-gray-700 dark:text-gray-300 border-b border-gray-100 dark:border-slate-700 last:border-0 transition-colors\">\n {{ suggestion.placePrediction?.text?.toString() }}\n </div>\n }\n </div>\n }\n @if ((saveAttempted() || addRouteForm.get('delivery_location')?.dirty) && !deliverySelected() && addRouteForm.get('delivery_location')?.value) {\n <div class=\"text-red-500 text-[10px] mt-1 font-medium italic flex items-center gap-1\">\n Please select a valid delivery location from suggestions\n </div>\n }\n </div>\n </div>\n </div>\n <div class=\"flex gap-4 flex-col md:flex-row\">\n <div class=\"w-full md:w-[70%]\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Notes</label\n >\n <textarea\n formControlName=\"note\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm h-[46px]\"\n ></textarea>\n </div>\n <div class=\"w-full md:w-[30%]\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Unit Type</label\n >\n <div #unitDropdownWrapper class=\"relative w-full\">\n <button\n type=\"button\"\n (click)=\"toggleDropdown(); $event.stopPropagation()\"\n class=\"w-full flex justify-between items-center px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm text-left\"\n >\n <span>{{ selectedUnitName }}</span>\n <lucide-icon [img]=\"icons.ChevronDown\" [size]=\"16\" class=\"text-gray-400\"></lucide-icon>\n </button>\n @if (dropdownOpen()) {\n <div \n [class.mt-1]=\"dropdownDirection() === 'down'\"\n [class.bottom-full]=\"dropdownDirection() === 'up'\"\n [class.mb-1]=\"dropdownDirection() === 'up'\"\n class=\"absolute z-10 w-full bg-white dark:bg-slate-800 rounded-lg shadow-lg border border-gray-200 dark:border-slate-700 py-1 max-h-60 overflow-auto\"\n >\n @for (opt of unitsList(); track opt.id) {\n <button\n type=\"button\"\n (click)=\"addRouteForm.patchValue({unit_id: opt.id}); addRouteForm.markAsDirty(); checkAndFetchRouteInformation(); dropdownOpen.set(false)\"\n class=\"w-full flex items-center justify-between px-4 py-2 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-slate-700 transition\"\n >\n <span>{{ opt.type }}</span>\n @if (addRouteForm.value.unit_id === opt.id) {\n <lucide-icon [img]=\"icons.Check\" [size]=\"16\" class=\"text-blue-500\"></lucide-icon>\n }\n </button>\n }\n </div>\n }\n </div>\n </div>\n </div>\n <div class=\"grid grid-cols-2 mt-2 gap-4\">\n <div class=\"flex flex-col lg:flex-row gap-2\">\n @if(addRouteForm.value.estimated_distance){\n <span\n class=\"text-[10px] text-gray-500 dark:text-slate-400 mb-1 whitespace-nowrap italic\">\n Estimation of miles - <b>{{ addRouteForm.value.estimated_distance }}</b>\n </span>\n }\n\n @if(addRouteForm.value.estimated_time){\n <span\n class=\"text-[10px] text-gray-500 dark:text-slate-400 mb-1 whitespace-nowrap italic\">\n Estimation of time - <b>{{ addRouteForm.value.estimated_time }}</b>\n </span>\n }\n </div>\n <div class=\"flex flex-col lg:flex-row gap-2 justify-end\">\n @if (config.repository !== 'customer' && addRouteForm.value.trucker_pay_estimate) {\n <span\n class=\"text-[10px] text-gray-500 dark:text-slate-400 mb-1 whitespace-nowrap italic\">\n Trucker Pay Estimate - <b>{{ addRouteForm.value.trucker_pay_estimate | currency }}</b>\n </span>\n }\n @if(addRouteForm.value.customer_price_estimate){\n <span\n class=\"text-[10px] text-gray-500 dark:text-slate-400 mb-1 whitespace-nowrap italic\">\n Customer Price Estimate - <b>{{ addRouteForm.value.customer_price_estimate | currency }}</b>\n </span>\n }\n </div>\n </div>\n </div>\n </form>\n </div>\n\n @if (showDeleteModal()) {\n <div class=\"fixed inset-0 z-[120] flex items-center justify-center bg-black/60 backdrop-blur-sm animate-fade-in pointer-events-auto\">\n <div class=\"bg-white dark:bg-slate-900 rounded-xl shadow-2xl p-6 max-w-sm w-full mx-4 border border-gray-200 dark:border-slate-800\" (click)=\"$event.stopPropagation()\">\n <h3 class=\"text-lg font-bold text-gray-900 dark:text-white mb-2 text-center\">Delete Route?</h3>\n <p class=\"text-gray-600 dark:text-gray-400 text-sm mb-6 text-center\">\n Are you sure you want to delete this route?\n </p>\n <div class=\"flex justify-center gap-3\">\n <button\n type=\"button\"\n (click)=\"showDeleteModal.set(false)\"\n class=\"px-4 py-2 text-sm font-medium text-gray-700 bg-gray-100 hover:bg-gray-200 dark:text-gray-300 dark:bg-slate-800 dark:hover:bg-slate-700 rounded-lg transition-colors\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n (click)=\"confirmDelete()\"\n class=\"px-4 py-2 text-sm font-medium text-white bg-red-600 hover:bg-red-700 rounded-lg shadow-sm transition-colors\"\n >\n Delete\n </button>\n </div>\n </div>\n </div>\n }\n </div>\n</div>\n}\n", styles: ["@keyframes slide-up{0%{opacity:0;transform:translateY(10px) scale(.95)}to{opacity:1;transform:translateY(0) scale(1)}}.animate-fade-in{animation:fade-in .2s ease-out}.animate-slide-up{animation:slide-up .2s ease-out}.radio{position:relative}.radio input{position:absolute;top:50%;transform:translateY(-50%);left:0;opacity:0;width:100%;height:100%;cursor:pointer}.radio svg{opacity:.5}.radio label{height:auto;border-width:1px;border-color:#334155}.radio input:checked+label{border-color:#3b558e;background-color:#334155;color:#fff}.radio input:checked+label svg{opacity:1}.radio label:hover{cursor:pointer}.grid-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:10px}\n"], dependencies: [{ kind: "ngmodule", type: LucideAngularModule }, { kind: "component", type: i1.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2$2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$2.RadioControlValueAccessor, selector: "input[type=radio][formControlName],input[type=radio][formControl],input[type=radio][ngModel]", inputs: ["name", "formControlName", "value"] }, { kind: "directive", type: i2$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i2.CurrencyPipe, name: "currency" }] });
1237
1272
  }
1238
1273
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: AddRouteComponent, decorators: [{
1239
1274
  type: Component,
1240
- args: [{ selector: 'lib-add-route', standalone: true, imports: [LucideAngularModule, ReactiveFormsModule, CommonModule], schemas: [CUSTOM_ELEMENTS_SCHEMA], template: "@if (modalOpen()) {\n<div class=\"fixed inset-0 z-[112] pointer-events-none overflow-y-auto\" id=\"add-route-modal\">\n <div class=\"flex min-h-full items-center justify-center p-4\">\n <form\n [formGroup]=\"addRouteForm\"\n (ngSubmit)=\"saveRoute()\"\n class=\"pointer-events-auto relative bg-white dark:bg-slate-800 rounded-lg shadow-xl animate-slide-up w-[1000px]\"\n [style.transform]=\"'translate(' + dragX() + 'px, ' + dragY() + 'px)'\"\n tabindex=\"-1\"\n >\n <div\n class=\"flex items-center justify-between p-4 border-b border-gray-200 dark:border-slate-700 cursor-move\"\n (mousedown)=\"startDrag($event)\"\n >\n <h3 class=\"flex items-center gap-1 text-lg font-semibold text-gray-900 dark:text-white\">\n {{ routeId() ? 'Edit Route' : 'Add Route' }}\n </h3>\n <div class=\"flex items-center gap-4\">\n <button\n type=\"submit\"\n [disabled]=\"(routeId() ? (addRouteForm.invalid || !addRouteForm.dirty) : addRouteForm.invalid) || !pickupSelected() || !deliverySelected() || showLoader()\"\n class=\"inline-flex items-center justify-center gap-2 px-4 py-2 bg-amber-500 hover:bg-amber-600 disabled:opacity-50 text-white font-medium rounded-lg transition-colors text-sm\">\n @if (showLoader()) {\n <lucide-icon [img]=\"icons.LoaderCircle\" class=\"animate-spin\" [size]=\"18\"></lucide-icon>\n } @else {\n {{ routeId() ? 'Update' : 'Save' }}\n }\n </button>\n @if (routeId()) {\n <button\n type=\"button\"\n (click)=\"promptDelete()\"\n class=\"inline-flex items-center gap-2 px-4 py-2 bg-red-600 text-white hover:bg-red-700 font-medium rounded-lg transition-colors text-sm\"\n >\n Delete\n </button>\n }\n <button\n type=\"button\"\n class=\"inline-flex items-center gap-2 px-4 py-2 bg-gray-600 text-white hover:bg-gray-700 font-medium rounded-lg transition-colors text-sm\"\n (click)=\"close()\"\n >\n Close\n </button>\n </div>\n </div>\n <div class=\"p-4\">\n <div class=\"grid grid-cols-2 mb-[1rem] gap-4\">\n <div>\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Route Name</label\n >\n <input\n type=\"text\"\n formControlName=\"route_name\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n />\n </div>\n <div class=\"relative\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Customer Name</label>\n <div class=\"relative\">\n <input\n type=\"text\"\n formControlName=\"customer_name\"\n (focus)=\"showCustomerDropdown.set(true)\"\n (blur)=\"hideDropdown('customer')\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-300 dark:border-slate-700 bg-gray-100 dark:bg-slate-900 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm pr-10\"\n />\n @if (loadingCustomers()) {\n <div class=\"absolute right-3 top-1/2 -translate-y-1/2\">\n <lucide-icon [img]=\"icons.LoaderCircle\" [size]=\"18\" class=\"animate-spin text-blue-500\"></lucide-icon>\n </div>\n }\n </div>\n @if (showCustomerDropdown() && customerOptions().length > 0) {\n <div class=\"absolute z-50 w-full mt-1 bg-white dark:bg-slate-800 border border-gray-200 dark:border-slate-700 rounded-lg shadow-lg max-h-48 overflow-y-auto\">\n @for (cust of customerOptions(); track cust.customer_id) {\n <div \n (mousedown)=\"addRouteForm.patchValue({customer_name: cust.customer_name}); addRouteForm.markAsDirty()\"\n class=\"px-4 py-2 hover:bg-gray-100 dark:hover:bg-slate-700 cursor-pointer text-sm text-gray-900 dark:text-white\">\n {{ cust.customer_name }}\n </div>\n }\n </div>\n }\n </div>\n </div>\n <div class=\"grid grid-cols-1 mb-[1rem]\">\n <div class=\"location-flow rounded-lg\">\n @if (config.repository === 'coolmap') {\n <div class=\"flex gap-2 mb-2\">\n <div class=\"radio w-100 md:w-auto\">\n <input\n type=\"radio\"\n formControlName=\"pickUpSearchOption\"\n value=\"system\"\n class=\"shrink-0 size-4 bg-transparent border-line-3 rounded-full shadow-2xs text-primary focus:ring-0 focus:ring-offset-0 checked:bg-primary-checked checked:border-primary-checked\"\n />\n <label\n class=\"border-solid border-1 border-grey dark:border-slate-400 block shadow-md rounded-lg lg:whitespace-nowrap w-full\"\n >\n <div class=\"flex justify-between items-center px-4 py-2 text-xs lg:text-base\">\n <div class=\"tracking-wide text-xs\">System Search</div>\n </div>\n </label>\n </div>\n <div class=\"radio w-100 md:w-auto ml-2\">\n <input\n type=\"radio\"\n formControlName=\"pickUpSearchOption\"\n value=\"google\"\n class=\"shrink-0 size-4 bg-transparent border-line-3 rounded-full shadow-2xs text-primary focus:ring-0 focus:ring-offset-0 checked:bg-primary-checked checked:border-primary-checked\"\n />\n <label\n class=\"border-solid border-1 border-grey dark:border-slate-400 block shadow-md rounded-lg lg:whitespace-nowrap w-full\"\n >\n <div class=\"flex justify-between items-center px-4 py-2 text-xs lg:text-base\">\n <div class=\"tracking-wide text-xs\">Google Search</div>\n </div>\n </label>\n </div>\n </div>\n }\n <div class=\"relative autocomplete-field\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Pickup Location</label>\n <input\n #filterPickup\n type=\"text\"\n formControlName=\"pickup_location\"\n placeholder=\"Pickup\"\n (input)=\"!isSystemPickup ? onInputChange($event, 'pickup') : null\"\n (focus)=\"onFocus('pickup')\"\n (blur)=\"isSystemPickup ? hideDropdown('pickup') : null\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm pr-10\"\n />\n @if (loadingLocations()) {\n <div class=\"absolute right-3 top-1/2 -translate-y-1/2\">\n <lucide-icon [img]=\"icons.LoaderCircle\" [size]=\"18\" class=\"animate-spin text-blue-500\"></lucide-icon>\n </div>\n }\n \n <!-- System Suggestions -->\n @if (isSystemPickup && showPickupDropdown() && pickupOptions().length > 0) {\n <div class=\"absolute z-50 w-full mt-1 bg-white dark:bg-slate-800 border border-gray-200 dark:border-slate-700 rounded-lg shadow-lg max-h-48 overflow-y-auto pickup-system-dropdown\">\n @for (loc of pickupOptions(); track loc.formatted_address) {\n <div \n (mousedown)=\"patchAddressValue(loc, 'pickup')\"\n class=\"px-4 py-2 hover:bg-gray-100 dark:hover:bg-slate-700 cursor-pointer text-sm text-gray-900 dark:text-white border-b border-gray-50 dark:border-slate-700 last:border-0\">\n {{ loc.formatted_address }}\n </div>\n }\n </div>\n }\n\n <!-- Google Suggestions -->\n @if (!isSystemPickup && showPickupSuggestions() && pickupSuggestions().length > 0) {\n <div class=\"absolute z-50 w-full mt-1 bg-white dark:bg-slate-800 border border-gray-200 dark:border-slate-700 rounded-lg shadow-lg max-h-48 overflow-y-auto pickup-suggestions\">\n @for (suggestion of pickupSuggestions(); track suggestion.placePrediction?.text?.toString() || $index) {\n <div \n (click)=\"onSuggestionClick(suggestion, 'pickup')\"\n class=\"px-4 py-2.5 hover:bg-amber-50 dark:hover:bg-amber-900/20 cursor-pointer text-sm text-gray-700 dark:text-gray-300 border-b border-gray-100 dark:border-slate-700 last:border-0 transition-colors\">\n {{ suggestion.placePrediction?.text?.toString() }}\n </div>\n }\n </div>\n }\n @if ((saveAttempted() || addRouteForm.get('pickup_location')?.dirty) && !pickupSelected() && addRouteForm.get('pickup_location')?.value) {\n <div class=\"text-red-500 text-[10px] mt-1 font-medium italic flex items-center gap-1\">\n Please select a valid pickup location from suggestions\n </div>\n }\n </div>\n </div>\n </div>\n <div class=\"grid grid-cols-1 mb-[1rem]\">\n <div class=\"location-flow rounded-lg\">\n @if (config.repository === 'coolmap') {\n <div class=\"flex gap-2 mb-2\">\n <div class=\"radio w-100 md:w-auto\">\n <input\n type=\"radio\"\n formControlName=\"deliverySearchOtption\"\n value=\"system\"\n class=\"shrink-0 size-4 bg-transparent border-line-3 rounded-full shadow-2xs text-primary focus:ring-0 focus:ring-offset-0 checked:bg-primary-checked checked:border-primary-checked\"/>\n <label\n class=\"border-solid border-1 border-grey dark:border-slate-400 block shadow-md rounded-lg lg:whitespace-nowrap w-full\">\n <div class=\"flex justify-between items-center px-4 py-2 text-xs lg:text-base\">\n <div class=\"tracking-wide text-xs\">System Search</div>\n </div>\n </label>\n </div>\n <div class=\"radio w-100 md:w-auto ml-2\">\n <input\n type=\"radio\"\n formControlName=\"deliverySearchOtption\"\n value=\"google\"\n class=\"shrink-0 size-4 bg-transparent border-line-3 rounded-full shadow-2xs text-primary focus:ring-0 focus:ring-offset-0 checked:bg-primary-checked checked:border-primary-checked\"/>\n <label\n class=\"border-solid border-1 border-grey dark:border-slate-400 block shadow-md rounded-lg lg:whitespace-nowrap w-full ml-2\">\n <div class=\"flex justify-between items-center px-4 py-2 text-xs lg:text-base\">\n <div class=\"tracking-wide text-xs\">Google Search</div>\n </div>\n </label>\n </div>\n </div>\n }\n <div class=\"relative autocomplete-field\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Delivery Location</label>\n <input\n #filterDelivery\n type=\"text\"\n formControlName=\"delivery_location\"\n placeholder=\"Delivery\"\n (input)=\"!isSystemDelivery ? onInputChange($event, 'delivery') : null\"\n (focus)=\"onFocus('delivery')\"\n (blur)=\"isSystemDelivery ? hideDropdown('delivery') : null\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm pr-10\"\n />\n @if (loadingLocations()) {\n <div class=\"absolute right-3 top-1/2 -translate-y-1/2\">\n <lucide-icon [img]=\"icons.LoaderCircle\" [size]=\"18\" class=\"animate-spin text-blue-500\"></lucide-icon>\n </div>\n }\n\n <!-- System Suggestions -->\n @if (isSystemDelivery && showDeliveryDropdown() && deliveryOptions().length > 0) {\n <div class=\"absolute z-50 w-full mt-1 bg-white dark:bg-slate-800 border border-gray-200 dark:border-slate-700 rounded-lg shadow-lg max-h-48 overflow-y-auto delivery-system-dropdown\">\n @for (loc of deliveryOptions(); track loc.formatted_address) {\n <div \n (mousedown)=\"patchAddressValue(loc, 'delivery')\"\n class=\"px-4 py-2 hover:bg-gray-100 dark:hover:bg-slate-700 cursor-pointer text-sm text-gray-900 dark:text-white border-b border-gray-50 dark:border-slate-700 last:border-0\">\n {{ loc.formatted_address }}\n </div>\n }\n </div>\n }\n\n <!-- Google Suggestions -->\n @if (!isSystemDelivery && showDeliverySuggestions() && deliverySuggestions().length > 0) {\n <div class=\"absolute z-50 w-full mt-1 bg-white dark:bg-slate-800 border border-gray-200 dark:border-slate-700 rounded-lg shadow-lg max-h-48 overflow-y-auto delivery-suggestions\">\n @for (suggestion of deliverySuggestions(); track suggestion.placePrediction?.text?.toString() || $index) {\n <div \n (click)=\"onSuggestionClick(suggestion, 'delivery')\"\n class=\"px-4 py-2.5 hover:bg-amber-50 dark:hover:bg-amber-900/20 cursor-pointer text-sm text-gray-700 dark:text-gray-300 border-b border-gray-100 dark:border-slate-700 last:border-0 transition-colors\">\n {{ suggestion.placePrediction?.text?.toString() }}\n </div>\n }\n </div>\n }\n @if ((saveAttempted() || addRouteForm.get('delivery_location')?.dirty) && !deliverySelected() && addRouteForm.get('delivery_location')?.value) {\n <div class=\"text-red-500 text-[10px] mt-1 font-medium italic flex items-center gap-1\">\n Please select a valid delivery location from suggestions\n </div>\n }\n </div>\n </div>\n </div>\n <div class=\"flex gap-4 flex-col md:flex-row\">\n <div class=\"w-full md:w-[70%]\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Notes</label\n >\n <textarea\n formControlName=\"note\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm h-[46px]\"\n ></textarea>\n </div>\n <div class=\"w-full md:w-[30%]\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Unit Type</label\n >\n <div class=\"relative w-full\">\n <button\n type=\"button\"\n (click)=\"toggleDropdown(); $event.stopPropagation()\"\n class=\"w-full flex justify-between items-center px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm text-left\"\n >\n <span>{{ selectedUnitName }}</span>\n <lucide-icon [img]=\"icons.ChevronDown\" [size]=\"16\" class=\"text-gray-400\"></lucide-icon>\n </button>\n @if (dropdownOpen()) {\n <div class=\"absolute z-10 mt-1 w-full bg-white dark:bg-slate-800 rounded-lg shadow-lg border border-gray-200 dark:border-slate-700 py-1 max-h-60 overflow-auto\">\n @for (opt of unitsList(); track opt.id) {\n <button\n type=\"button\"\n (click)=\"addRouteForm.patchValue({unit_id: opt.id}); addRouteForm.markAsDirty(); checkAndFetchRouteInformation(); dropdownOpen.set(false)\"\n class=\"w-full flex items-center justify-between px-4 py-2 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-slate-700 transition\"\n >\n <span>{{ opt.type }}</span>\n @if (addRouteForm.value.unit_id === opt.id) {\n <lucide-icon [img]=\"icons.Check\" [size]=\"16\" class=\"text-blue-500\"></lucide-icon>\n }\n </button>\n }\n </div>\n }\n </div>\n </div>\n </div>\n <div class=\"grid grid-cols-2 mt-2 gap-4\">\n <div class=\"flex flex-col lg:flex-row gap-2\">\n @if(addRouteForm.value.estimated_distance){\n <span\n class=\"text-[10px] text-gray-500 dark:text-slate-400 mb-1 whitespace-nowrap italic\">\n Estimation of miles - <b>{{ addRouteForm.value.estimated_distance }}</b>\n </span>\n }\n\n @if(addRouteForm.value.estimated_time){\n <span\n class=\"text-[10px] text-gray-500 dark:text-slate-400 mb-1 whitespace-nowrap italic\">\n Estimation of time - <b>{{ addRouteForm.value.estimated_time }}</b>\n </span>\n }\n </div>\n <div class=\"flex flex-col lg:flex-row gap-2 justify-end\">\n @if (config.repository !== 'customer' && addRouteForm.value.trucker_pay_estimate) {\n <span\n class=\"text-[10px] text-gray-500 dark:text-slate-400 mb-1 whitespace-nowrap italic\">\n Trucker Pay Estimate - <b>{{ addRouteForm.value.trucker_pay_estimate | currency }}</b>\n </span>\n }\n @if(addRouteForm.value.customer_price_estimate){\n <span\n class=\"text-[10px] text-gray-500 dark:text-slate-400 mb-1 whitespace-nowrap italic\">\n Customer Price Estimate - <b>{{ addRouteForm.value.customer_price_estimate | currency }}</b>\n </span>\n }\n </div>\n </div>\n </div>\n </form>\n\n @if (showDeleteModal()) {\n <div class=\"fixed inset-0 z-[120] flex items-center justify-center bg-black/60 backdrop-blur-sm animate-fade-in pointer-events-auto\">\n <div class=\"bg-white dark:bg-slate-900 rounded-xl shadow-2xl p-6 max-w-sm w-full mx-4 border border-gray-200 dark:border-slate-800\" (click)=\"$event.stopPropagation()\">\n <h3 class=\"text-lg font-bold text-gray-900 dark:text-white mb-2 text-center\">Delete Route?</h3>\n <p class=\"text-gray-600 dark:text-gray-400 text-sm mb-6 text-center\">\n Are you sure you want to delete this route?\n </p>\n <div class=\"flex justify-center gap-3\">\n <button\n type=\"button\"\n (click)=\"showDeleteModal.set(false)\"\n class=\"px-4 py-2 text-sm font-medium text-gray-700 bg-gray-100 hover:bg-gray-200 dark:text-gray-300 dark:bg-slate-800 dark:hover:bg-slate-700 rounded-lg transition-colors\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n (click)=\"confirmDelete()\"\n class=\"px-4 py-2 text-sm font-medium text-white bg-red-600 hover:bg-red-700 rounded-lg shadow-sm transition-colors\"\n >\n Delete\n </button>\n </div>\n </div>\n </div>\n }\n </div>\n</div>\n}\n", styles: ["@keyframes slide-up{0%{opacity:0;transform:translateY(10px) scale(.95)}to{opacity:1;transform:translateY(0) scale(1)}}.animate-fade-in{animation:fade-in .2s ease-out}.animate-slide-up{animation:slide-up .2s ease-out}.radio{position:relative}.radio input{position:absolute;top:50%;transform:translateY(-50%);left:0;opacity:0;width:100%;height:100%;cursor:pointer}.radio svg{opacity:.5}.radio label{height:auto;border-width:1px;border-color:#334155}.radio input:checked+label{border-color:#3b558e;background-color:#334155;color:#fff}.radio input:checked+label svg{opacity:1}.radio label:hover{cursor:pointer}.grid-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:10px}\n"] }]
1275
+ args: [{ selector: 'lib-add-route', standalone: true, imports: [LucideAngularModule, ReactiveFormsModule, CommonModule], schemas: [CUSTOM_ELEMENTS_SCHEMA], template: "@if (modalOpen()) {\n<div class=\"fixed inset-0 z-[112] pointer-events-none overflow-y-auto\" id=\"add-route-modal\">\n <div class=\"flex min-h-full items-end justify-center p-4 pb-12 customer-add-route\">\n <div class=\"pointer-events-auto animate-slide-up ml-[300px]\">\n <form\n [formGroup]=\"addRouteForm\"\n (ngSubmit)=\"saveRoute()\"\n class=\"relative bg-white dark:bg-slate-800 rounded-lg shadow-xl w-[1000px]\"\n [style.transform]=\"'translate(' + dragX() + 'px, ' + dragY() + 'px)'\"\n tabindex=\"-1\"\n >\n <div\n class=\"flex items-center justify-between p-4 border-b border-gray-200 dark:border-slate-700 cursor-move\"\n (mousedown)=\"startDrag($event)\"\n >\n <h3 class=\"flex items-center gap-1 text-lg font-semibold text-gray-900 dark:text-white\">\n {{ routeId() ? 'Edit Route' : 'Add Route' }}\n </h3>\n <div class=\"flex items-center gap-4\">\n <button\n type=\"submit\"\n [disabled]=\"(routeId() ? (addRouteForm.invalid || !addRouteForm.dirty) : addRouteForm.invalid) || !pickupSelected() || !deliverySelected() || showLoader()\"\n class=\"inline-flex items-center justify-center gap-2 px-4 py-2 bg-amber-500 hover:bg-amber-600 disabled:opacity-50 text-white font-medium rounded-lg transition-colors text-sm\">\n @if (showLoader()) {\n <lucide-icon [img]=\"icons.LoaderCircle\" class=\"animate-spin\" [size]=\"18\"></lucide-icon>\n } @else {\n {{ routeId() ? 'Update' : 'Save' }}\n }\n </button>\n @if (routeId()) {\n <button\n type=\"button\"\n (click)=\"promptDelete()\"\n class=\"inline-flex items-center gap-2 px-4 py-2 bg-red-600 text-white hover:bg-red-700 font-medium rounded-lg transition-colors text-sm\"\n >\n Delete\n </button>\n }\n <button\n type=\"button\"\n class=\"inline-flex items-center gap-2 px-4 py-2 bg-gray-600 text-white hover:bg-gray-700 font-medium rounded-lg transition-colors text-sm\"\n (click)=\"close()\"\n >\n Close\n </button>\n </div>\n </div>\n <div class=\"p-4\">\n <div class=\"grid grid-cols-2 mb-[1rem] gap-4\">\n <div>\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Route Name</label\n >\n <input\n type=\"text\"\n formControlName=\"route_name\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n />\n </div>\n <div class=\"relative\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Customer Name</label>\n <div class=\"relative\">\n <input\n type=\"text\"\n formControlName=\"customer_name\"\n (focus)=\"showCustomerDropdown.set(true)\"\n (blur)=\"hideDropdown('customer')\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-300 dark:border-slate-700 bg-gray-100 dark:bg-slate-900 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm pr-10\"\n />\n @if (loadingCustomers()) {\n <div class=\"absolute right-3 top-1/2 -translate-y-1/2\">\n <lucide-icon [img]=\"icons.LoaderCircle\" [size]=\"18\" class=\"animate-spin text-blue-500\"></lucide-icon>\n </div>\n }\n </div>\n @if (showCustomerDropdown() && customerOptions().length > 0) {\n <div class=\"absolute z-50 w-full mt-1 bg-white dark:bg-slate-800 border border-gray-200 dark:border-slate-700 rounded-lg shadow-lg max-h-48 overflow-y-auto\">\n @for (cust of customerOptions(); track cust.customer_id) {\n <div \n (mousedown)=\"addRouteForm.patchValue({customer_name: cust.customer_name}); addRouteForm.markAsDirty()\"\n class=\"px-4 py-2 hover:bg-gray-100 dark:hover:bg-slate-700 cursor-pointer text-sm text-gray-900 dark:text-white\">\n {{ cust.customer_name }}\n </div>\n }\n </div>\n }\n </div>\n </div>\n <div class=\"grid grid-cols-1 mb-[1rem]\">\n <div class=\"location-flow rounded-lg\">\n @if (config.repository === 'coolmap') {\n <div class=\"flex gap-2 mb-2\">\n <div class=\"radio w-100 md:w-auto\">\n <input\n type=\"radio\"\n formControlName=\"pickUpSearchOption\"\n value=\"system\"\n class=\"shrink-0 size-4 bg-transparent border-line-3 rounded-full shadow-2xs text-primary focus:ring-0 focus:ring-offset-0 checked:bg-primary-checked checked:border-primary-checked\"\n />\n <label\n class=\"border-solid border-1 border-grey dark:border-slate-400 block shadow-md rounded-lg lg:whitespace-nowrap w-full\"\n >\n <div class=\"flex justify-between items-center px-4 py-2 text-xs lg:text-base\">\n <div class=\"tracking-wide text-xs\">System Search</div>\n </div>\n </label>\n </div>\n <div class=\"radio w-100 md:w-auto ml-2\">\n <input\n type=\"radio\"\n formControlName=\"pickUpSearchOption\"\n value=\"google\"\n class=\"shrink-0 size-4 bg-transparent border-line-3 rounded-full shadow-2xs text-primary focus:ring-0 focus:ring-offset-0 checked:bg-primary-checked checked:border-primary-checked\"\n />\n <label\n class=\"border-solid border-1 border-grey dark:border-slate-400 block shadow-md rounded-lg lg:whitespace-nowrap w-full\"\n >\n <div class=\"flex justify-between items-center px-4 py-2 text-xs lg:text-base\">\n <div class=\"tracking-wide text-xs\">Google Search</div>\n </div>\n </label>\n </div>\n </div>\n }\n <div class=\"relative autocomplete-field\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Pickup Location</label>\n <input\n #filterPickup\n type=\"text\"\n formControlName=\"pickup_location\"\n placeholder=\"Pickup\"\n (input)=\"!isSystemPickup ? onInputChange($event, 'pickup') : null\"\n (focus)=\"onFocus('pickup')\"\n (blur)=\"isSystemPickup ? hideDropdown('pickup') : null\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm pr-10\"\n />\n @if (loadingLocations()) {\n <div class=\"absolute right-3 top-1/2 -translate-y-1/2\">\n <lucide-icon [img]=\"icons.LoaderCircle\" [size]=\"18\" class=\"animate-spin text-blue-500\"></lucide-icon>\n </div>\n }\n \n <!-- System Suggestions -->\n @if (isSystemPickup && showPickupDropdown() && pickupOptions().length > 0) {\n <div class=\"absolute z-50 w-full mt-1 bg-white dark:bg-slate-800 border border-gray-200 dark:border-slate-700 rounded-lg shadow-lg max-h-48 overflow-y-auto pickup-system-dropdown\">\n @for (loc of pickupOptions(); track loc.formatted_address) {\n <div \n (mousedown)=\"patchAddressValue(loc, 'pickup')\"\n class=\"px-4 py-2 hover:bg-gray-100 dark:hover:bg-slate-700 cursor-pointer text-sm text-gray-900 dark:text-white border-b border-gray-50 dark:border-slate-700 last:border-0\">\n {{ loc.formatted_address }}\n </div>\n }\n </div>\n }\n\n <!-- Google Suggestions -->\n @if (!isSystemPickup && showPickupSuggestions() && pickupSuggestions().length > 0) {\n <div class=\"absolute z-50 w-full mt-1 bg-white dark:bg-slate-800 border border-gray-200 dark:border-slate-700 rounded-lg shadow-lg max-h-48 overflow-y-auto pickup-suggestions\">\n @for (suggestion of pickupSuggestions(); track suggestion.placePrediction?.text?.toString() || $index) {\n <div \n (click)=\"onSuggestionClick(suggestion, 'pickup')\"\n class=\"px-4 py-2.5 hover:bg-amber-50 dark:hover:bg-amber-900/20 cursor-pointer text-sm text-gray-700 dark:text-gray-300 border-b border-gray-100 dark:border-slate-700 last:border-0 transition-colors\">\n {{ suggestion.placePrediction?.text?.toString() }}\n </div>\n }\n </div>\n }\n @if ((saveAttempted() || addRouteForm.get('pickup_location')?.dirty) && !pickupSelected() && addRouteForm.get('pickup_location')?.value) {\n <div class=\"text-red-500 text-[10px] mt-1 font-medium italic flex items-center gap-1\">\n Please select a valid pickup location from suggestions\n </div>\n }\n </div>\n </div>\n </div>\n <div class=\"grid grid-cols-1 mb-[1rem]\">\n <div class=\"location-flow rounded-lg\">\n @if (config.repository === 'coolmap') {\n <div class=\"flex gap-2 mb-2\">\n <div class=\"radio w-100 md:w-auto\">\n <input\n type=\"radio\"\n formControlName=\"deliverySearchOtption\"\n value=\"system\"\n class=\"shrink-0 size-4 bg-transparent border-line-3 rounded-full shadow-2xs text-primary focus:ring-0 focus:ring-offset-0 checked:bg-primary-checked checked:border-primary-checked\"/>\n <label\n class=\"border-solid border-1 border-grey dark:border-slate-400 block shadow-md rounded-lg lg:whitespace-nowrap w-full\">\n <div class=\"flex justify-between items-center px-4 py-2 text-xs lg:text-base\">\n <div class=\"tracking-wide text-xs\">System Search</div>\n </div>\n </label>\n </div>\n <div class=\"radio w-100 md:w-auto ml-2\">\n <input\n type=\"radio\"\n formControlName=\"deliverySearchOtption\"\n value=\"google\"\n class=\"shrink-0 size-4 bg-transparent border-line-3 rounded-full shadow-2xs text-primary focus:ring-0 focus:ring-offset-0 checked:bg-primary-checked checked:border-primary-checked\"/>\n <label\n class=\"border-solid border-1 border-grey dark:border-slate-400 block shadow-md rounded-lg lg:whitespace-nowrap w-full ml-2\">\n <div class=\"flex justify-between items-center px-4 py-2 text-xs lg:text-base\">\n <div class=\"tracking-wide text-xs\">Google Search</div>\n </div>\n </label>\n </div>\n </div>\n }\n <div class=\"relative autocomplete-field\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Delivery Location</label>\n <input\n #filterDelivery\n type=\"text\"\n formControlName=\"delivery_location\"\n placeholder=\"Delivery\"\n (input)=\"!isSystemDelivery ? onInputChange($event, 'delivery') : null\"\n (focus)=\"onFocus('delivery')\"\n (blur)=\"isSystemDelivery ? hideDropdown('delivery') : null\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm pr-10\"\n />\n @if (loadingLocations()) {\n <div class=\"absolute right-3 top-1/2 -translate-y-1/2\">\n <lucide-icon [img]=\"icons.LoaderCircle\" [size]=\"18\" class=\"animate-spin text-blue-500\"></lucide-icon>\n </div>\n }\n\n <!-- System Suggestions -->\n @if (isSystemDelivery && showDeliveryDropdown() && deliveryOptions().length > 0) {\n <div class=\"absolute z-50 w-full mt-1 bg-white dark:bg-slate-800 border border-gray-200 dark:border-slate-700 rounded-lg shadow-lg max-h-48 overflow-y-auto delivery-system-dropdown\">\n @for (loc of deliveryOptions(); track loc.formatted_address) {\n <div \n (mousedown)=\"patchAddressValue(loc, 'delivery')\"\n class=\"px-4 py-2 hover:bg-gray-100 dark:hover:bg-slate-700 cursor-pointer text-sm text-gray-900 dark:text-white border-b border-gray-50 dark:border-slate-700 last:border-0\">\n {{ loc.formatted_address }}\n </div>\n }\n </div>\n }\n\n <!-- Google Suggestions -->\n @if (!isSystemDelivery && showDeliverySuggestions() && deliverySuggestions().length > 0) {\n <div class=\"absolute z-50 w-full mt-1 bg-white dark:bg-slate-800 border border-gray-200 dark:border-slate-700 rounded-lg shadow-lg max-h-48 overflow-y-auto delivery-suggestions\">\n @for (suggestion of deliverySuggestions(); track suggestion.placePrediction?.text?.toString() || $index) {\n <div \n (click)=\"onSuggestionClick(suggestion, 'delivery')\"\n class=\"px-4 py-2.5 hover:bg-amber-50 dark:hover:bg-amber-900/20 cursor-pointer text-sm text-gray-700 dark:text-gray-300 border-b border-gray-100 dark:border-slate-700 last:border-0 transition-colors\">\n {{ suggestion.placePrediction?.text?.toString() }}\n </div>\n }\n </div>\n }\n @if ((saveAttempted() || addRouteForm.get('delivery_location')?.dirty) && !deliverySelected() && addRouteForm.get('delivery_location')?.value) {\n <div class=\"text-red-500 text-[10px] mt-1 font-medium italic flex items-center gap-1\">\n Please select a valid delivery location from suggestions\n </div>\n }\n </div>\n </div>\n </div>\n <div class=\"flex gap-4 flex-col md:flex-row\">\n <div class=\"w-full md:w-[70%]\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Notes</label\n >\n <textarea\n formControlName=\"note\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm h-[46px]\"\n ></textarea>\n </div>\n <div class=\"w-full md:w-[30%]\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Unit Type</label\n >\n <div #unitDropdownWrapper class=\"relative w-full\">\n <button\n type=\"button\"\n (click)=\"toggleDropdown(); $event.stopPropagation()\"\n class=\"w-full flex justify-between items-center px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm text-left\"\n >\n <span>{{ selectedUnitName }}</span>\n <lucide-icon [img]=\"icons.ChevronDown\" [size]=\"16\" class=\"text-gray-400\"></lucide-icon>\n </button>\n @if (dropdownOpen()) {\n <div \n [class.mt-1]=\"dropdownDirection() === 'down'\"\n [class.bottom-full]=\"dropdownDirection() === 'up'\"\n [class.mb-1]=\"dropdownDirection() === 'up'\"\n class=\"absolute z-10 w-full bg-white dark:bg-slate-800 rounded-lg shadow-lg border border-gray-200 dark:border-slate-700 py-1 max-h-60 overflow-auto\"\n >\n @for (opt of unitsList(); track opt.id) {\n <button\n type=\"button\"\n (click)=\"addRouteForm.patchValue({unit_id: opt.id}); addRouteForm.markAsDirty(); checkAndFetchRouteInformation(); dropdownOpen.set(false)\"\n class=\"w-full flex items-center justify-between px-4 py-2 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-slate-700 transition\"\n >\n <span>{{ opt.type }}</span>\n @if (addRouteForm.value.unit_id === opt.id) {\n <lucide-icon [img]=\"icons.Check\" [size]=\"16\" class=\"text-blue-500\"></lucide-icon>\n }\n </button>\n }\n </div>\n }\n </div>\n </div>\n </div>\n <div class=\"grid grid-cols-2 mt-2 gap-4\">\n <div class=\"flex flex-col lg:flex-row gap-2\">\n @if(addRouteForm.value.estimated_distance){\n <span\n class=\"text-[10px] text-gray-500 dark:text-slate-400 mb-1 whitespace-nowrap italic\">\n Estimation of miles - <b>{{ addRouteForm.value.estimated_distance }}</b>\n </span>\n }\n\n @if(addRouteForm.value.estimated_time){\n <span\n class=\"text-[10px] text-gray-500 dark:text-slate-400 mb-1 whitespace-nowrap italic\">\n Estimation of time - <b>{{ addRouteForm.value.estimated_time }}</b>\n </span>\n }\n </div>\n <div class=\"flex flex-col lg:flex-row gap-2 justify-end\">\n @if (config.repository !== 'customer' && addRouteForm.value.trucker_pay_estimate) {\n <span\n class=\"text-[10px] text-gray-500 dark:text-slate-400 mb-1 whitespace-nowrap italic\">\n Trucker Pay Estimate - <b>{{ addRouteForm.value.trucker_pay_estimate | currency }}</b>\n </span>\n }\n @if(addRouteForm.value.customer_price_estimate){\n <span\n class=\"text-[10px] text-gray-500 dark:text-slate-400 mb-1 whitespace-nowrap italic\">\n Customer Price Estimate - <b>{{ addRouteForm.value.customer_price_estimate | currency }}</b>\n </span>\n }\n </div>\n </div>\n </div>\n </form>\n </div>\n\n @if (showDeleteModal()) {\n <div class=\"fixed inset-0 z-[120] flex items-center justify-center bg-black/60 backdrop-blur-sm animate-fade-in pointer-events-auto\">\n <div class=\"bg-white dark:bg-slate-900 rounded-xl shadow-2xl p-6 max-w-sm w-full mx-4 border border-gray-200 dark:border-slate-800\" (click)=\"$event.stopPropagation()\">\n <h3 class=\"text-lg font-bold text-gray-900 dark:text-white mb-2 text-center\">Delete Route?</h3>\n <p class=\"text-gray-600 dark:text-gray-400 text-sm mb-6 text-center\">\n Are you sure you want to delete this route?\n </p>\n <div class=\"flex justify-center gap-3\">\n <button\n type=\"button\"\n (click)=\"showDeleteModal.set(false)\"\n class=\"px-4 py-2 text-sm font-medium text-gray-700 bg-gray-100 hover:bg-gray-200 dark:text-gray-300 dark:bg-slate-800 dark:hover:bg-slate-700 rounded-lg transition-colors\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n (click)=\"confirmDelete()\"\n class=\"px-4 py-2 text-sm font-medium text-white bg-red-600 hover:bg-red-700 rounded-lg shadow-sm transition-colors\"\n >\n Delete\n </button>\n </div>\n </div>\n </div>\n }\n </div>\n</div>\n}\n", styles: ["@keyframes slide-up{0%{opacity:0;transform:translateY(10px) scale(.95)}to{opacity:1;transform:translateY(0) scale(1)}}.animate-fade-in{animation:fade-in .2s ease-out}.animate-slide-up{animation:slide-up .2s ease-out}.radio{position:relative}.radio input{position:absolute;top:50%;transform:translateY(-50%);left:0;opacity:0;width:100%;height:100%;cursor:pointer}.radio svg{opacity:.5}.radio label{height:auto;border-width:1px;border-color:#334155}.radio input:checked+label{border-color:#3b558e;background-color:#334155;color:#fff}.radio input:checked+label svg{opacity:1}.radio label:hover{cursor:pointer}.grid-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:10px}\n"] }]
1241
1276
  }], ctorParameters: () => [], propDecorators: { modalOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "modalOpen", required: false }] }], routeData: [{ type: i0.Input, args: [{ isSignal: true, alias: "routeData", required: false }] }], customerRepoDetails: [{ type: i0.Input, args: [{ isSignal: true, alias: "customerRepoDetails", required: false }] }], modalOpenChange: [{
1242
1277
  type: Output
1243
1278
  }], routeDeleted: [{
1244
1279
  type: Output
1245
1280
  }], routeSaved: [{
1246
1281
  type: Output
1247
- }], filterPickup: [{ type: i0.ViewChild, args: ['filterPickup', { isSignal: true }] }], filterDelivery: [{ type: i0.ViewChild, args: ['filterDelivery', { isSignal: true }] }], closeDropdowns: [{
1282
+ }], filterPickup: [{ type: i0.ViewChild, args: ['filterPickup', { isSignal: true }] }], filterDelivery: [{ type: i0.ViewChild, args: ['filterDelivery', { isSignal: true }] }], unitDropdownWrapper: [{ type: i0.ViewChild, args: ['unitDropdownWrapper', { isSignal: true }] }], closeDropdowns: [{
1248
1283
  type: HostListener,
1249
1284
  args: ['document:click', ['$event']]
1250
1285
  }], onMouseMove: [{
@@ -1274,6 +1309,7 @@ class ShareRouteComponent {
1274
1309
  dragInitialY = 0;
1275
1310
  filterPickup;
1276
1311
  filterDelivery;
1312
+ unitDropdownWrapper;
1277
1313
  pickupSuggestions = signal([], ...(ngDevMode ? [{ debugName: "pickupSuggestions" }] : []));
1278
1314
  deliverySuggestions = signal([], ...(ngDevMode ? [{ debugName: "deliverySuggestions" }] : []));
1279
1315
  showPickupSuggestions = signal(false, ...(ngDevMode ? [{ debugName: "showPickupSuggestions" }] : []));
@@ -1307,8 +1343,33 @@ class ShareRouteComponent {
1307
1343
  DollarSign,
1308
1344
  Info,
1309
1345
  LoaderCircle,
1310
- Check
1346
+ Check,
1347
+ ChevronDown
1311
1348
  };
1349
+ dropdownOpen = signal(false, ...(ngDevMode ? [{ debugName: "dropdownOpen" }] : []));
1350
+ dropdownDirection = signal('down', ...(ngDevMode ? [{ debugName: "dropdownDirection" }] : []));
1351
+ get selectedUnitName() {
1352
+ const unitValue = this.shareRouteForm.get('units')?.value;
1353
+ if (!unitValue)
1354
+ return 'Select Unit';
1355
+ return unitValue;
1356
+ }
1357
+ toggleDropdown() {
1358
+ this.dropdownOpen.update(v => {
1359
+ if (!v) {
1360
+ this.updateDropdownDirection();
1361
+ }
1362
+ return !v;
1363
+ });
1364
+ }
1365
+ updateDropdownDirection() {
1366
+ const el = this.unitDropdownWrapper?.nativeElement;
1367
+ if (el) {
1368
+ const rect = el.getBoundingClientRect();
1369
+ const spaceBelow = window.innerHeight - rect.bottom;
1370
+ this.dropdownDirection.set(spaceBelow < 250 ? 'up' : 'down');
1371
+ }
1372
+ }
1312
1373
  constructor() {
1313
1374
  this.shareRouteForm = new FormGroup({
1314
1375
  uuid: new FormControl('', [Validators.required]),
@@ -1398,6 +1459,9 @@ class ShareRouteComponent {
1398
1459
  if (!isDeliveryArea) {
1399
1460
  this.showDeliverySuggestions.set(false);
1400
1461
  }
1462
+ if (!target.closest('.relative')) {
1463
+ this.dropdownOpen.set(false);
1464
+ }
1401
1465
  }
1402
1466
  async fetchAutocompleteSuggestions(input, type) {
1403
1467
  if (!this.placesLibrary || !input.trim() || !this.sessionToken)
@@ -1606,16 +1670,19 @@ class ShareRouteComponent {
1606
1670
  return;
1607
1671
  this.dragX.set(this.dragInitialX + (event.clientX - this.dragStartX));
1608
1672
  this.dragY.set(this.dragInitialY + (event.clientY - this.dragStartY));
1673
+ if (this.dropdownOpen()) {
1674
+ this.updateDropdownDirection();
1675
+ }
1609
1676
  }
1610
1677
  onMouseUp() {
1611
1678
  this.isDragging = false;
1612
1679
  }
1613
1680
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: ShareRouteComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1614
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: ShareRouteComponent, isStandalone: true, selector: "lib-share-route", inputs: { openShareRouteDetails: { classPropertyName: "openShareRouteDetails", publicName: "openShareRouteDetails", isSignal: true, isRequired: false, transformFunction: null }, userDetails: { classPropertyName: "userDetails", publicName: "userDetails", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closePopupEmit: "closePopupEmit" }, host: { listeners: { "document:click": "onDocumentClick($event)", "document:mousemove": "onMouseMove($event)", "document:mouseup": "onMouseUp()" } }, viewQueries: [{ propertyName: "filterPickup", first: true, predicate: ["filterPickup"], descendants: true }, { propertyName: "filterDelivery", first: true, predicate: ["filterDelivery"], descendants: true }], ngImport: i0, template: "<div\n class=\"fixed inset-0 z-[120] flex items-end justify-center p-4 w-full pointer-events-none\"\n \n>\n <div class=\"flex lg:items-start lg:justify-start items-center justify-center p-3\">\n <form\n [formGroup]=\"shareRouteForm\"\n (ngSubmit)=\"saveShareRoute()\"\n class=\"relative bg-white dark:bg-slate-800 rounded-lg shadow-xl w-[1000px] pointer-events-auto\"\n [style.transform]=\"'translate(' + dragX() + 'px, ' + dragY() + 'px)'\"\n [style.will-change]=\"'transform'\"\n (click)=\"$event.stopPropagation()\"\n >\n <div\n class=\"flex items-center justify-between p-4 border-b border-gray-200 dark:border-slate-700 cursor-move\"\n (mousedown)=\"startDrag($event)\"\n >\n <h3 class=\"flex items-center gap-1 text-lg font-semibold text-gray-900 dark:text-white\">\n Share Route\n </h3>\n <div class=\"flex items-center gap-4\">\n <button\n type=\"submit\"\n [disabled]=\"shareRouteForm.invalid || showLoader()\"\n class=\"flex items-center gap-2 px-4 py-2.5 rounded-lg bg-amber-500 hover:bg-amber-600 disabled:opacity-50 disabled:cursor-not-allowed text-white font-bold text-sm shadow-lg shadow-amber-500/20 transition-all active:scale-95\"\n >\n @if (showLoader()) {\n <lucide-icon [img]=\"icons.LoaderCircle\" class=\"animate-spin\" [size]=\"18\"></lucide-icon> } @else { Send }\n </button>\n <button\n type=\"button\"\n class=\"inline-flex items-center gap-2 px-4 py-2.5 bg-gray-600 text-white hover:bg-gray-700 font-medium rounded-lg transition-colors text-sm\"\n (click)=\"closePopup()\"\n >\n Close\n </button>\n </div>\n </div>\n\n <div class=\"p-4 overflow-y-auto max-h-[50vh]\">\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <!-- Route Name -->\n <div>\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Route Name\n </label>\n <input\n formControlName=\"routeName\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n placeholder=\"Enter route name\"\n />\n </div>\n\n <!-- Unit Type -->\n <div>\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Unit Type\n </label>\n <select\n formControlName=\"units\"\n (change)=\"checkAndFetchRouteInformation()\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n >\n <option value=\"\" disabled>Select Unit</option>\n @for (unit of unitsList(); track unit.type) {\n <option [value]=\"unit.type\">{{ unit.type }}</option>\n }\n </select>\n </div>\n\n <!-- Pickup Location -->\n <div class=\"relative autocomplete-field\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Pickup\n </label>\n <input\n formControlName=\"pickupLocation\"\n #filterPickup\n (input)=\"onInputChange($event, 'pickup')\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n placeholder=\"Search pickup location...\"\n autocomplete=\"off\"\n />\n @if (showPickupSuggestions() && pickupSuggestions().length > 0) {\n <div\n class=\"absolute z-[110] w-full mt-1 bg-white dark:bg-slate-800 border border-gray-200 dark:border-slate-700 rounded-lg shadow-xl max-h-48 overflow-y-auto\"\n >\n @for (suggestion of pickupSuggestions(); track\n suggestion.placePrediction?.text?.toString() || $index) {\n <div\n class=\"px-4 py-2.5 hover:bg-amber-50 dark:hover:bg-amber-900/20 cursor-pointer text-sm text-gray-700 dark:text-gray-300 border-b border-gray-100 dark:border-slate-700 last:border-0 transition-colors\"\n (click)=\"onSuggestionClick(suggestion, 'pickup')\"\n >\n {{ suggestion.placePrediction?.text?.toString() }}\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Delivery Location -->\n <div class=\"relative autocomplete-field\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Delivery\n </label>\n <input\n formControlName=\"deliveryLocation\"\n #filterDelivery\n (input)=\"onInputChange($event, 'delivery')\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n placeholder=\"Search delivery location...\"\n autocomplete=\"off\"\n />\n @if (showDeliverySuggestions() && deliverySuggestions().length > 0) {\n <div\n class=\"absolute z-[110] w-full mt-1 bg-white dark:bg-slate-800 border border-gray-200 dark:border-slate-700 rounded-lg shadow-xl max-h-48 overflow-y-auto\"\n >\n @for (suggestion of deliverySuggestions(); track\n suggestion.placePrediction?.text?.toString() || $index) {\n <div\n class=\"px-4 py-2.5 hover:bg-amber-50 dark:hover:bg-amber-900/20 cursor-pointer text-sm text-gray-700 dark:text-gray-300 border-b border-gray-100 dark:border-slate-700 last:border-0 transition-colors\"\n (click)=\"onSuggestionClick(suggestion, 'delivery')\"\n >\n {{ suggestion.placePrediction?.text?.toString() }}\n </div>\n }\n </div>\n }\n </div>\n </div>\n <div class=\"grid grid-cols-1 md:grid-cols-1 gap-4 mb-[1rem] mt-[1rem]\">\n <!-- Notes -->\n <div>\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\"\n >Notes</label\n >\n <textarea\n formControlName=\"routeNotes\"\n rows=\"2\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm resize-none\"\n placeholder=\"List Material and Details\"\n ></textarea>\n </div>\n </div>\n\n <div class=\"grid grid-cols-2 gap-4 mb-[1rem]\">\n <!-- Date Requested -->\n <div class=\"relative\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Date Requested\n </label>\n <div class=\"relative group\">\n <input\n type=\"text\"\n readonly\n [value]=\"displayDate()\"\n (click)=\"dateInput.showPicker()\"\n placeholder=\"MM/DD/YYYY\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n />\n <input\n #dateInput\n type=\"date\"\n [value]=\"dateValue()\"\n (change)=\"onDateChange($event)\"\n class=\"absolute inset-0 w-0 h-0 opacity-0 pointer-events-none\"\n />\n </div>\n </div>\n\n <!-- Quantity Requested -->\n <div>\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Quantity Requested\n </label>\n <input\n type=\"number\"\n formControlName=\"quantity\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n placeholder=\"0\"\n />\n </div>\n\n <!-- Price -->\n <div class=\"relative -top-[20px]\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Customer Haul Price\n </label>\n <div class=\"relative\">\n <input\n formControlName=\"price\"\n readonly\n class=\"w-full px-3 py-3 pl-[47px] rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n />\n <lucide-icon\n [img]=\"icons.DollarSign\"\n class=\"absolute left-3 top-1/2 -translate-y-1/2 text-gray-400\"\n [size]=\"16\"\n ></lucide-icon>\n </div>\n </div>\n\n <!-- Unit Type Display -->\n <div class=\"relative -top-[20px]\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Unit type\n </label>\n <div\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n >\n {{ shareRouteForm.value.units || 'N/A' }}\n </div>\n </div>\n\n <!-- Contact Info Section Title -->\n <div class=\"md:col-span-2 border-t border-gray-100 dark:border-slate-800\">\n <h3 class=\"flex items-center gap-1 text-md font-semibold text-gray-900 dark:text-white\">\n Customer Information\n </h3>\n </div>\n\n <!-- Contact Name -->\n <div>\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Contact Name\n </label>\n <input\n formControlName=\"contactName\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n />\n </div>\n\n <!-- Contact Phone -->\n <div>\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Contact Phone\n </label>\n <input\n formControlName=\"contactPhone\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n />\n </div>\n\n <!-- Contact Email -->\n <div class=\"space-y-1.5 md:col-span-2\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Contact Email\n </label>\n <input\n formControlName=\"contactEmail\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n />\n </div>\n\n <!-- Special Pricing Checkbox -->\n <div class=\"md:col-span-2 pt-2 flex items-center gap-3\">\n <label class=\"relative flex h-5 w-5 cursor-pointer\">\n <input\n type=\"checkbox\"\n formControlName=\"special_price\"\n (change)=\"setValidators(shareRouteForm.value.special_price)\"\n class=\"h-full w-full appearance-none rounded-md border border-gray-300 dark:border-slate-700 transition-all checked:bg-amber-500 checked:border-amber-500 outline-none cursor-pointer\"\n />\n <lucide-icon\n [img]=\"icons.Check\"\n [size]=\"14\"\n [class.opacity-100]=\"shareRouteForm.get('special_price')?.value\"\n [class.opacity-0]=\"!shareRouteForm.get('special_price')?.value\"\n class=\"absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 text-white transition-opacity pointer-events-none\"\n ></lucide-icon>\n </label>\n <span class=\"text-sm font-medium text-gray-700 dark:text-gray-300\"\n >Request special pricing</span\n >\n </div>\n\n <!-- Special Price Input (Conditional) -->\n @if (shareRouteForm.value.special_price) {\n <div class=\"space-y-1.5 animate-fade-in md:col-span-1\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Requested Price\n </label>\n <div class=\"relative\">\n <input\n formControlName=\"customerEstimatedPrice\"\n class=\"w-full px-3 py-3 pl-[47px] rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n />\n <lucide-icon\n [img]=\"icons.DollarSign\"\n class=\"absolute left-3 top-1/2 -translate-y-1/2 text-amber-500\"\n [size]=\"16\"\n ></lucide-icon>\n </div>\n </div>\n }\n </div>\n </div>\n </form>\n </div>\n</div>\n", styles: ["@keyframes slide-up{0%{opacity:0;transform:translateY(20px) scale(.98)}to{opacity:1;transform:translateY(0) scale(1)}}@keyframes fade-in{0%{opacity:0}to{opacity:1}}.animate-slide-up{animation:slide-up .3s cubic-bezier(.16,1,.3,1) forwards}.animate-fade-in{animation:fade-in .2s ease-out forwards}:host{display:block}input[type=date]::-webkit-calendar-picker-indicator{filter:invert(.5);cursor:pointer}.dark input[type=date]::-webkit-calendar-picker-indicator{filter:invert(1)}form::-webkit-scrollbar{width:6px}form::-webkit-scrollbar-track{background:transparent}form::-webkit-scrollbar-thumb{background:#e2e8f0;border-radius:10px}.dark form::-webkit-scrollbar-thumb{background:#334155}\n"], dependencies: [{ kind: "ngmodule", type: LucideAngularModule }, { kind: "component", type: i1.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2$2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2$2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2$2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i2$2.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i2$2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }] });
1681
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: ShareRouteComponent, isStandalone: true, selector: "lib-share-route", inputs: { openShareRouteDetails: { classPropertyName: "openShareRouteDetails", publicName: "openShareRouteDetails", isSignal: true, isRequired: false, transformFunction: null }, userDetails: { classPropertyName: "userDetails", publicName: "userDetails", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closePopupEmit: "closePopupEmit" }, host: { listeners: { "document:click": "onDocumentClick($event)", "document:mousemove": "onMouseMove($event)", "document:mouseup": "onMouseUp()" } }, viewQueries: [{ propertyName: "filterPickup", first: true, predicate: ["filterPickup"], descendants: true }, { propertyName: "filterDelivery", first: true, predicate: ["filterDelivery"], descendants: true }, { propertyName: "unitDropdownWrapper", first: true, predicate: ["unitDropdownWrapper"], descendants: true }], ngImport: i0, template: "<div\n class=\"fixed inset-0 z-[120] flex items-end justify-center p-4 w-full pointer-events-none\"\n \n>\n <div class=\"flex lg:items-start lg:justify-start items-center justify-center p-3\">\n <form\n [formGroup]=\"shareRouteForm\"\n (ngSubmit)=\"saveShareRoute()\"\n class=\"relative bg-white dark:bg-slate-800 rounded-lg shadow-xl w-[1000px] pointer-events-auto\"\n [style.transform]=\"'translate(' + dragX() + 'px, ' + dragY() + 'px)'\"\n [style.will-change]=\"'transform'\"\n (click)=\"$event.stopPropagation()\"\n >\n <div\n class=\"flex items-center justify-between p-4 border-b border-gray-200 dark:border-slate-700 cursor-move\"\n (mousedown)=\"startDrag($event)\"\n >\n <h3 class=\"flex items-center gap-1 text-lg font-semibold text-gray-900 dark:text-white\">\n Share Route\n </h3>\n <div class=\"flex items-center gap-4\">\n <button\n type=\"submit\"\n [disabled]=\"shareRouteForm.invalid || showLoader()\"\n class=\"flex items-center gap-2 px-4 py-2.5 rounded-lg bg-amber-500 hover:bg-amber-600 disabled:opacity-50 disabled:cursor-not-allowed text-white font-bold text-sm shadow-lg shadow-amber-500/20 transition-all active:scale-95\"\n >\n @if (showLoader()) {\n <lucide-icon [img]=\"icons.LoaderCircle\" class=\"animate-spin\" [size]=\"18\"></lucide-icon> } @else { Send }\n </button>\n <button\n type=\"button\"\n class=\"inline-flex items-center gap-2 px-4 py-2.5 bg-gray-600 text-white hover:bg-gray-700 font-medium rounded-lg transition-colors text-sm\"\n (click)=\"closePopup()\"\n >\n Close\n </button>\n </div>\n </div>\n\n <div class=\"p-4 overflow-y-auto max-h-[50vh]\">\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <!-- Route Name -->\n <div>\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Route Name\n </label>\n <input\n formControlName=\"routeName\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n placeholder=\"Enter route name\"\n />\n </div>\n\n <div>\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Unit Type\n </label>\n <div #unitDropdownWrapper class=\"relative w-full\">\n <button\n type=\"button\"\n (click)=\"toggleDropdown(); $event.stopPropagation()\"\n class=\"w-full flex justify-between items-center px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm text-left\"\n >\n <span>{{ selectedUnitName }}</span>\n <lucide-icon [img]=\"icons.ChevronDown\" [size]=\"16\" class=\"text-gray-400\"></lucide-icon>\n </button>\n @if (dropdownOpen()) {\n <div \n [class.mt-1]=\"dropdownDirection() === 'down'\"\n [class.bottom-full]=\"dropdownDirection() === 'up'\"\n [class.mb-1]=\"dropdownDirection() === 'up'\"\n class=\"absolute z-50 w-full bg-white dark:bg-slate-800 rounded-lg shadow-lg border border-gray-200 dark:border-slate-700 py-1 max-h-60 overflow-auto\"\n >\n @for (unit of unitsList(); track unit.type) {\n <button\n type=\"button\"\n (click)=\"shareRouteForm.patchValue({units: unit.type}); shareRouteForm.markAsDirty(); checkAndFetchRouteInformation(); dropdownOpen.set(false)\"\n class=\"w-full flex items-center justify-between px-4 py-2 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-slate-700 transition\"\n >\n <span>{{ unit.type }}</span>\n @if (shareRouteForm.value.units === unit.type) {\n <lucide-icon [img]=\"icons.Check\" [size]=\"16\" class=\"text-blue-500\"></lucide-icon>\n }\n </button>\n }\n </div>\n }\n </div>\n </div>\n\n <!-- Pickup Location -->\n <div class=\"relative autocomplete-field\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Pickup\n </label>\n <input\n formControlName=\"pickupLocation\"\n #filterPickup\n (input)=\"onInputChange($event, 'pickup')\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n placeholder=\"Search pickup location...\"\n autocomplete=\"off\"\n />\n @if (showPickupSuggestions() && pickupSuggestions().length > 0) {\n <div\n class=\"absolute z-[110] w-full mt-1 bg-white dark:bg-slate-800 border border-gray-200 dark:border-slate-700 rounded-lg shadow-xl max-h-48 overflow-y-auto\"\n >\n @for (suggestion of pickupSuggestions(); track\n suggestion.placePrediction?.text?.toString() || $index) {\n <div\n class=\"px-4 py-2.5 hover:bg-amber-50 dark:hover:bg-amber-900/20 cursor-pointer text-sm text-gray-700 dark:text-gray-300 border-b border-gray-100 dark:border-slate-700 last:border-0 transition-colors\"\n (click)=\"onSuggestionClick(suggestion, 'pickup')\"\n >\n {{ suggestion.placePrediction?.text?.toString() }}\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Delivery Location -->\n <div class=\"relative autocomplete-field\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Delivery\n </label>\n <input\n formControlName=\"deliveryLocation\"\n #filterDelivery\n (input)=\"onInputChange($event, 'delivery')\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n placeholder=\"Search delivery location...\"\n autocomplete=\"off\"\n />\n @if (showDeliverySuggestions() && deliverySuggestions().length > 0) {\n <div\n class=\"absolute z-[110] w-full mt-1 bg-white dark:bg-slate-800 border border-gray-200 dark:border-slate-700 rounded-lg shadow-xl max-h-48 overflow-y-auto\"\n >\n @for (suggestion of deliverySuggestions(); track\n suggestion.placePrediction?.text?.toString() || $index) {\n <div\n class=\"px-4 py-2.5 hover:bg-amber-50 dark:hover:bg-amber-900/20 cursor-pointer text-sm text-gray-700 dark:text-gray-300 border-b border-gray-100 dark:border-slate-700 last:border-0 transition-colors\"\n (click)=\"onSuggestionClick(suggestion, 'delivery')\"\n >\n {{ suggestion.placePrediction?.text?.toString() }}\n </div>\n }\n </div>\n }\n </div>\n </div>\n <div class=\"grid grid-cols-1 md:grid-cols-1 gap-4 mb-[1rem] mt-[1rem]\">\n <!-- Notes -->\n <div>\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\"\n >Notes</label\n >\n <textarea\n formControlName=\"routeNotes\"\n rows=\"2\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm resize-none\"\n placeholder=\"List Material and Details\"\n ></textarea>\n </div>\n </div>\n\n <div class=\"grid grid-cols-2 gap-4 mb-[1rem]\">\n <!-- Date Requested -->\n <div class=\"relative\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Date Requested\n </label>\n <div class=\"relative group\">\n <input\n type=\"text\"\n readonly\n [value]=\"displayDate()\"\n (click)=\"dateInput.showPicker()\"\n placeholder=\"MM/DD/YYYY\"\n class=\"w-full pl-3 pr-10 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm cursor-pointer\"\n />\n <lucide-icon\n [img]=\"icons.Calendar\" \n [size]=\"18\" \n (click)=\"dateInput.showPicker()\"\n class=\"absolute right-3 top-[7px] text-gray-400 group-hover:text-brand-blue transition-colors cursor-pointer\"\n ></lucide-icon>\n <input\n #dateInput\n type=\"date\"\n [value]=\"dateValue()\"\n (change)=\"onDateChange($event)\"\n class=\"absolute inset-0 w-0 h-0 opacity-0 pointer-events-none\"\n />\n </div>\n </div>\n\n <!-- Quantity Requested -->\n <div>\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Quantity Requested\n </label>\n <input\n type=\"number\"\n formControlName=\"quantity\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n placeholder=\"0\"\n />\n </div>\n\n <!-- Price -->\n <div class=\"relative -top-[20px]\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Customer Haul Price\n </label>\n <div class=\"relative\">\n <input\n formControlName=\"price\"\n readonly\n class=\"w-full px-3 py-3 pl-[47px] rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n />\n <lucide-icon\n [img]=\"icons.DollarSign\"\n class=\"absolute left-3 top-1/2 -translate-y-1/2 text-gray-400\"\n [size]=\"16\"\n ></lucide-icon>\n </div>\n </div>\n\n <!-- Unit Type Display -->\n <div class=\"relative -top-[20px]\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Unit type\n </label>\n <div\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n >\n {{ shareRouteForm.value.units || 'N/A' }}\n </div>\n </div>\n\n <!-- Contact Info Section Title -->\n <div class=\"md:col-span-2 border-t border-gray-100 dark:border-slate-800\">\n <h3 class=\"flex items-center gap-1 text-md font-semibold text-gray-900 dark:text-white\">\n Customer Information\n </h3>\n </div>\n\n <!-- Contact Name -->\n <div>\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Contact Name\n </label>\n <input\n formControlName=\"contactName\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n />\n </div>\n\n <!-- Contact Phone -->\n <div>\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Contact Phone\n </label>\n <input\n formControlName=\"contactPhone\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n />\n </div>\n\n <!-- Contact Email -->\n <div class=\"space-y-1.5 md:col-span-2\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Contact Email\n </label>\n <input\n formControlName=\"contactEmail\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n />\n </div>\n\n <!-- Special Pricing Checkbox -->\n <div class=\"md:col-span-2 pt-2 flex items-center gap-3\">\n <label class=\"relative flex h-5 w-5 cursor-pointer\">\n <input\n type=\"checkbox\"\n formControlName=\"special_price\"\n (change)=\"setValidators(shareRouteForm.value.special_price)\"\n class=\"h-full w-full appearance-none rounded-md border border-gray-300 dark:border-slate-700 transition-all checked:bg-amber-500 checked:border-amber-500 outline-none cursor-pointer\"\n />\n <lucide-icon\n [img]=\"icons.Check\"\n [size]=\"14\"\n [class.opacity-100]=\"shareRouteForm.get('special_price')?.value\"\n [class.opacity-0]=\"!shareRouteForm.get('special_price')?.value\"\n class=\"absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 text-white transition-opacity pointer-events-none\"\n ></lucide-icon>\n </label>\n <span class=\"text-sm font-medium text-gray-700 dark:text-gray-300\"\n >Request special pricing</span\n >\n </div>\n\n <!-- Special Price Input (Conditional) -->\n @if (shareRouteForm.value.special_price) {\n <div class=\"space-y-1.5 animate-fade-in md:col-span-1\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Requested Price\n </label>\n <div class=\"relative\">\n <input\n formControlName=\"customerEstimatedPrice\"\n class=\"w-full px-3 py-3 pl-[47px] rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n />\n <lucide-icon\n [img]=\"icons.DollarSign\"\n class=\"absolute left-3 top-1/2 -translate-y-1/2 text-amber-500\"\n [size]=\"16\"\n ></lucide-icon>\n </div>\n </div>\n <div class=\"relative\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Unit type\n </label>\n <div\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n >\n {{ shareRouteForm.value.units || 'N/A' }}\n </div>\n </div>\n }\n </div>\n </div>\n </form>\n </div>\n</div>\n", styles: ["@keyframes slide-up{0%{opacity:0;transform:translateY(20px) scale(.98)}to{opacity:1;transform:translateY(0) scale(1)}}@keyframes fade-in{0%{opacity:0}to{opacity:1}}.animate-slide-up{animation:slide-up .3s cubic-bezier(.16,1,.3,1) forwards}.animate-fade-in{animation:fade-in .2s ease-out forwards}:host{display:block}input[type=date]::-webkit-calendar-picker-indicator{filter:invert(.5);cursor:pointer}.dark input[type=date]::-webkit-calendar-picker-indicator{filter:invert(1)}form::-webkit-scrollbar{width:6px}form::-webkit-scrollbar-track{background:transparent}form::-webkit-scrollbar-thumb{background:#e2e8f0;border-radius:10px}.dark form::-webkit-scrollbar-thumb{background:#334155}\n"], dependencies: [{ kind: "ngmodule", type: LucideAngularModule }, { kind: "component", type: i1.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2$2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i2$2.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i2$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }] });
1615
1682
  }
1616
1683
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: ShareRouteComponent, decorators: [{
1617
1684
  type: Component,
1618
- args: [{ selector: 'lib-share-route', standalone: true, imports: [LucideAngularModule, ReactiveFormsModule, NgClass, CurrencyPipe], schemas: [CUSTOM_ELEMENTS_SCHEMA], template: "<div\n class=\"fixed inset-0 z-[120] flex items-end justify-center p-4 w-full pointer-events-none\"\n \n>\n <div class=\"flex lg:items-start lg:justify-start items-center justify-center p-3\">\n <form\n [formGroup]=\"shareRouteForm\"\n (ngSubmit)=\"saveShareRoute()\"\n class=\"relative bg-white dark:bg-slate-800 rounded-lg shadow-xl w-[1000px] pointer-events-auto\"\n [style.transform]=\"'translate(' + dragX() + 'px, ' + dragY() + 'px)'\"\n [style.will-change]=\"'transform'\"\n (click)=\"$event.stopPropagation()\"\n >\n <div\n class=\"flex items-center justify-between p-4 border-b border-gray-200 dark:border-slate-700 cursor-move\"\n (mousedown)=\"startDrag($event)\"\n >\n <h3 class=\"flex items-center gap-1 text-lg font-semibold text-gray-900 dark:text-white\">\n Share Route\n </h3>\n <div class=\"flex items-center gap-4\">\n <button\n type=\"submit\"\n [disabled]=\"shareRouteForm.invalid || showLoader()\"\n class=\"flex items-center gap-2 px-4 py-2.5 rounded-lg bg-amber-500 hover:bg-amber-600 disabled:opacity-50 disabled:cursor-not-allowed text-white font-bold text-sm shadow-lg shadow-amber-500/20 transition-all active:scale-95\"\n >\n @if (showLoader()) {\n <lucide-icon [img]=\"icons.LoaderCircle\" class=\"animate-spin\" [size]=\"18\"></lucide-icon> } @else { Send }\n </button>\n <button\n type=\"button\"\n class=\"inline-flex items-center gap-2 px-4 py-2.5 bg-gray-600 text-white hover:bg-gray-700 font-medium rounded-lg transition-colors text-sm\"\n (click)=\"closePopup()\"\n >\n Close\n </button>\n </div>\n </div>\n\n <div class=\"p-4 overflow-y-auto max-h-[50vh]\">\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <!-- Route Name -->\n <div>\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Route Name\n </label>\n <input\n formControlName=\"routeName\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n placeholder=\"Enter route name\"\n />\n </div>\n\n <!-- Unit Type -->\n <div>\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Unit Type\n </label>\n <select\n formControlName=\"units\"\n (change)=\"checkAndFetchRouteInformation()\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n >\n <option value=\"\" disabled>Select Unit</option>\n @for (unit of unitsList(); track unit.type) {\n <option [value]=\"unit.type\">{{ unit.type }}</option>\n }\n </select>\n </div>\n\n <!-- Pickup Location -->\n <div class=\"relative autocomplete-field\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Pickup\n </label>\n <input\n formControlName=\"pickupLocation\"\n #filterPickup\n (input)=\"onInputChange($event, 'pickup')\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n placeholder=\"Search pickup location...\"\n autocomplete=\"off\"\n />\n @if (showPickupSuggestions() && pickupSuggestions().length > 0) {\n <div\n class=\"absolute z-[110] w-full mt-1 bg-white dark:bg-slate-800 border border-gray-200 dark:border-slate-700 rounded-lg shadow-xl max-h-48 overflow-y-auto\"\n >\n @for (suggestion of pickupSuggestions(); track\n suggestion.placePrediction?.text?.toString() || $index) {\n <div\n class=\"px-4 py-2.5 hover:bg-amber-50 dark:hover:bg-amber-900/20 cursor-pointer text-sm text-gray-700 dark:text-gray-300 border-b border-gray-100 dark:border-slate-700 last:border-0 transition-colors\"\n (click)=\"onSuggestionClick(suggestion, 'pickup')\"\n >\n {{ suggestion.placePrediction?.text?.toString() }}\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Delivery Location -->\n <div class=\"relative autocomplete-field\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Delivery\n </label>\n <input\n formControlName=\"deliveryLocation\"\n #filterDelivery\n (input)=\"onInputChange($event, 'delivery')\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n placeholder=\"Search delivery location...\"\n autocomplete=\"off\"\n />\n @if (showDeliverySuggestions() && deliverySuggestions().length > 0) {\n <div\n class=\"absolute z-[110] w-full mt-1 bg-white dark:bg-slate-800 border border-gray-200 dark:border-slate-700 rounded-lg shadow-xl max-h-48 overflow-y-auto\"\n >\n @for (suggestion of deliverySuggestions(); track\n suggestion.placePrediction?.text?.toString() || $index) {\n <div\n class=\"px-4 py-2.5 hover:bg-amber-50 dark:hover:bg-amber-900/20 cursor-pointer text-sm text-gray-700 dark:text-gray-300 border-b border-gray-100 dark:border-slate-700 last:border-0 transition-colors\"\n (click)=\"onSuggestionClick(suggestion, 'delivery')\"\n >\n {{ suggestion.placePrediction?.text?.toString() }}\n </div>\n }\n </div>\n }\n </div>\n </div>\n <div class=\"grid grid-cols-1 md:grid-cols-1 gap-4 mb-[1rem] mt-[1rem]\">\n <!-- Notes -->\n <div>\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\"\n >Notes</label\n >\n <textarea\n formControlName=\"routeNotes\"\n rows=\"2\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm resize-none\"\n placeholder=\"List Material and Details\"\n ></textarea>\n </div>\n </div>\n\n <div class=\"grid grid-cols-2 gap-4 mb-[1rem]\">\n <!-- Date Requested -->\n <div class=\"relative\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Date Requested\n </label>\n <div class=\"relative group\">\n <input\n type=\"text\"\n readonly\n [value]=\"displayDate()\"\n (click)=\"dateInput.showPicker()\"\n placeholder=\"MM/DD/YYYY\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n />\n <input\n #dateInput\n type=\"date\"\n [value]=\"dateValue()\"\n (change)=\"onDateChange($event)\"\n class=\"absolute inset-0 w-0 h-0 opacity-0 pointer-events-none\"\n />\n </div>\n </div>\n\n <!-- Quantity Requested -->\n <div>\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Quantity Requested\n </label>\n <input\n type=\"number\"\n formControlName=\"quantity\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n placeholder=\"0\"\n />\n </div>\n\n <!-- Price -->\n <div class=\"relative -top-[20px]\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Customer Haul Price\n </label>\n <div class=\"relative\">\n <input\n formControlName=\"price\"\n readonly\n class=\"w-full px-3 py-3 pl-[47px] rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n />\n <lucide-icon\n [img]=\"icons.DollarSign\"\n class=\"absolute left-3 top-1/2 -translate-y-1/2 text-gray-400\"\n [size]=\"16\"\n ></lucide-icon>\n </div>\n </div>\n\n <!-- Unit Type Display -->\n <div class=\"relative -top-[20px]\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Unit type\n </label>\n <div\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n >\n {{ shareRouteForm.value.units || 'N/A' }}\n </div>\n </div>\n\n <!-- Contact Info Section Title -->\n <div class=\"md:col-span-2 border-t border-gray-100 dark:border-slate-800\">\n <h3 class=\"flex items-center gap-1 text-md font-semibold text-gray-900 dark:text-white\">\n Customer Information\n </h3>\n </div>\n\n <!-- Contact Name -->\n <div>\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Contact Name\n </label>\n <input\n formControlName=\"contactName\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n />\n </div>\n\n <!-- Contact Phone -->\n <div>\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Contact Phone\n </label>\n <input\n formControlName=\"contactPhone\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n />\n </div>\n\n <!-- Contact Email -->\n <div class=\"space-y-1.5 md:col-span-2\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Contact Email\n </label>\n <input\n formControlName=\"contactEmail\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n />\n </div>\n\n <!-- Special Pricing Checkbox -->\n <div class=\"md:col-span-2 pt-2 flex items-center gap-3\">\n <label class=\"relative flex h-5 w-5 cursor-pointer\">\n <input\n type=\"checkbox\"\n formControlName=\"special_price\"\n (change)=\"setValidators(shareRouteForm.value.special_price)\"\n class=\"h-full w-full appearance-none rounded-md border border-gray-300 dark:border-slate-700 transition-all checked:bg-amber-500 checked:border-amber-500 outline-none cursor-pointer\"\n />\n <lucide-icon\n [img]=\"icons.Check\"\n [size]=\"14\"\n [class.opacity-100]=\"shareRouteForm.get('special_price')?.value\"\n [class.opacity-0]=\"!shareRouteForm.get('special_price')?.value\"\n class=\"absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 text-white transition-opacity pointer-events-none\"\n ></lucide-icon>\n </label>\n <span class=\"text-sm font-medium text-gray-700 dark:text-gray-300\"\n >Request special pricing</span\n >\n </div>\n\n <!-- Special Price Input (Conditional) -->\n @if (shareRouteForm.value.special_price) {\n <div class=\"space-y-1.5 animate-fade-in md:col-span-1\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Requested Price\n </label>\n <div class=\"relative\">\n <input\n formControlName=\"customerEstimatedPrice\"\n class=\"w-full px-3 py-3 pl-[47px] rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n />\n <lucide-icon\n [img]=\"icons.DollarSign\"\n class=\"absolute left-3 top-1/2 -translate-y-1/2 text-amber-500\"\n [size]=\"16\"\n ></lucide-icon>\n </div>\n </div>\n }\n </div>\n </div>\n </form>\n </div>\n</div>\n", styles: ["@keyframes slide-up{0%{opacity:0;transform:translateY(20px) scale(.98)}to{opacity:1;transform:translateY(0) scale(1)}}@keyframes fade-in{0%{opacity:0}to{opacity:1}}.animate-slide-up{animation:slide-up .3s cubic-bezier(.16,1,.3,1) forwards}.animate-fade-in{animation:fade-in .2s ease-out forwards}:host{display:block}input[type=date]::-webkit-calendar-picker-indicator{filter:invert(.5);cursor:pointer}.dark input[type=date]::-webkit-calendar-picker-indicator{filter:invert(1)}form::-webkit-scrollbar{width:6px}form::-webkit-scrollbar-track{background:transparent}form::-webkit-scrollbar-thumb{background:#e2e8f0;border-radius:10px}.dark form::-webkit-scrollbar-thumb{background:#334155}\n"] }]
1685
+ args: [{ selector: 'lib-share-route', standalone: true, imports: [LucideAngularModule, ReactiveFormsModule], schemas: [CUSTOM_ELEMENTS_SCHEMA], template: "<div\n class=\"fixed inset-0 z-[120] flex items-end justify-center p-4 w-full pointer-events-none\"\n \n>\n <div class=\"flex lg:items-start lg:justify-start items-center justify-center p-3\">\n <form\n [formGroup]=\"shareRouteForm\"\n (ngSubmit)=\"saveShareRoute()\"\n class=\"relative bg-white dark:bg-slate-800 rounded-lg shadow-xl w-[1000px] pointer-events-auto\"\n [style.transform]=\"'translate(' + dragX() + 'px, ' + dragY() + 'px)'\"\n [style.will-change]=\"'transform'\"\n (click)=\"$event.stopPropagation()\"\n >\n <div\n class=\"flex items-center justify-between p-4 border-b border-gray-200 dark:border-slate-700 cursor-move\"\n (mousedown)=\"startDrag($event)\"\n >\n <h3 class=\"flex items-center gap-1 text-lg font-semibold text-gray-900 dark:text-white\">\n Share Route\n </h3>\n <div class=\"flex items-center gap-4\">\n <button\n type=\"submit\"\n [disabled]=\"shareRouteForm.invalid || showLoader()\"\n class=\"flex items-center gap-2 px-4 py-2.5 rounded-lg bg-amber-500 hover:bg-amber-600 disabled:opacity-50 disabled:cursor-not-allowed text-white font-bold text-sm shadow-lg shadow-amber-500/20 transition-all active:scale-95\"\n >\n @if (showLoader()) {\n <lucide-icon [img]=\"icons.LoaderCircle\" class=\"animate-spin\" [size]=\"18\"></lucide-icon> } @else { Send }\n </button>\n <button\n type=\"button\"\n class=\"inline-flex items-center gap-2 px-4 py-2.5 bg-gray-600 text-white hover:bg-gray-700 font-medium rounded-lg transition-colors text-sm\"\n (click)=\"closePopup()\"\n >\n Close\n </button>\n </div>\n </div>\n\n <div class=\"p-4 overflow-y-auto max-h-[50vh]\">\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <!-- Route Name -->\n <div>\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Route Name\n </label>\n <input\n formControlName=\"routeName\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n placeholder=\"Enter route name\"\n />\n </div>\n\n <div>\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Unit Type\n </label>\n <div #unitDropdownWrapper class=\"relative w-full\">\n <button\n type=\"button\"\n (click)=\"toggleDropdown(); $event.stopPropagation()\"\n class=\"w-full flex justify-between items-center px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm text-left\"\n >\n <span>{{ selectedUnitName }}</span>\n <lucide-icon [img]=\"icons.ChevronDown\" [size]=\"16\" class=\"text-gray-400\"></lucide-icon>\n </button>\n @if (dropdownOpen()) {\n <div \n [class.mt-1]=\"dropdownDirection() === 'down'\"\n [class.bottom-full]=\"dropdownDirection() === 'up'\"\n [class.mb-1]=\"dropdownDirection() === 'up'\"\n class=\"absolute z-50 w-full bg-white dark:bg-slate-800 rounded-lg shadow-lg border border-gray-200 dark:border-slate-700 py-1 max-h-60 overflow-auto\"\n >\n @for (unit of unitsList(); track unit.type) {\n <button\n type=\"button\"\n (click)=\"shareRouteForm.patchValue({units: unit.type}); shareRouteForm.markAsDirty(); checkAndFetchRouteInformation(); dropdownOpen.set(false)\"\n class=\"w-full flex items-center justify-between px-4 py-2 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-slate-700 transition\"\n >\n <span>{{ unit.type }}</span>\n @if (shareRouteForm.value.units === unit.type) {\n <lucide-icon [img]=\"icons.Check\" [size]=\"16\" class=\"text-blue-500\"></lucide-icon>\n }\n </button>\n }\n </div>\n }\n </div>\n </div>\n\n <!-- Pickup Location -->\n <div class=\"relative autocomplete-field\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Pickup\n </label>\n <input\n formControlName=\"pickupLocation\"\n #filterPickup\n (input)=\"onInputChange($event, 'pickup')\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n placeholder=\"Search pickup location...\"\n autocomplete=\"off\"\n />\n @if (showPickupSuggestions() && pickupSuggestions().length > 0) {\n <div\n class=\"absolute z-[110] w-full mt-1 bg-white dark:bg-slate-800 border border-gray-200 dark:border-slate-700 rounded-lg shadow-xl max-h-48 overflow-y-auto\"\n >\n @for (suggestion of pickupSuggestions(); track\n suggestion.placePrediction?.text?.toString() || $index) {\n <div\n class=\"px-4 py-2.5 hover:bg-amber-50 dark:hover:bg-amber-900/20 cursor-pointer text-sm text-gray-700 dark:text-gray-300 border-b border-gray-100 dark:border-slate-700 last:border-0 transition-colors\"\n (click)=\"onSuggestionClick(suggestion, 'pickup')\"\n >\n {{ suggestion.placePrediction?.text?.toString() }}\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Delivery Location -->\n <div class=\"relative autocomplete-field\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Delivery\n </label>\n <input\n formControlName=\"deliveryLocation\"\n #filterDelivery\n (input)=\"onInputChange($event, 'delivery')\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n placeholder=\"Search delivery location...\"\n autocomplete=\"off\"\n />\n @if (showDeliverySuggestions() && deliverySuggestions().length > 0) {\n <div\n class=\"absolute z-[110] w-full mt-1 bg-white dark:bg-slate-800 border border-gray-200 dark:border-slate-700 rounded-lg shadow-xl max-h-48 overflow-y-auto\"\n >\n @for (suggestion of deliverySuggestions(); track\n suggestion.placePrediction?.text?.toString() || $index) {\n <div\n class=\"px-4 py-2.5 hover:bg-amber-50 dark:hover:bg-amber-900/20 cursor-pointer text-sm text-gray-700 dark:text-gray-300 border-b border-gray-100 dark:border-slate-700 last:border-0 transition-colors\"\n (click)=\"onSuggestionClick(suggestion, 'delivery')\"\n >\n {{ suggestion.placePrediction?.text?.toString() }}\n </div>\n }\n </div>\n }\n </div>\n </div>\n <div class=\"grid grid-cols-1 md:grid-cols-1 gap-4 mb-[1rem] mt-[1rem]\">\n <!-- Notes -->\n <div>\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\"\n >Notes</label\n >\n <textarea\n formControlName=\"routeNotes\"\n rows=\"2\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm resize-none\"\n placeholder=\"List Material and Details\"\n ></textarea>\n </div>\n </div>\n\n <div class=\"grid grid-cols-2 gap-4 mb-[1rem]\">\n <!-- Date Requested -->\n <div class=\"relative\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Date Requested\n </label>\n <div class=\"relative group\">\n <input\n type=\"text\"\n readonly\n [value]=\"displayDate()\"\n (click)=\"dateInput.showPicker()\"\n placeholder=\"MM/DD/YYYY\"\n class=\"w-full pl-3 pr-10 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm cursor-pointer\"\n />\n <lucide-icon\n [img]=\"icons.Calendar\" \n [size]=\"18\" \n (click)=\"dateInput.showPicker()\"\n class=\"absolute right-3 top-[7px] text-gray-400 group-hover:text-brand-blue transition-colors cursor-pointer\"\n ></lucide-icon>\n <input\n #dateInput\n type=\"date\"\n [value]=\"dateValue()\"\n (change)=\"onDateChange($event)\"\n class=\"absolute inset-0 w-0 h-0 opacity-0 pointer-events-none\"\n />\n </div>\n </div>\n\n <!-- Quantity Requested -->\n <div>\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Quantity Requested\n </label>\n <input\n type=\"number\"\n formControlName=\"quantity\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n placeholder=\"0\"\n />\n </div>\n\n <!-- Price -->\n <div class=\"relative -top-[20px]\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Customer Haul Price\n </label>\n <div class=\"relative\">\n <input\n formControlName=\"price\"\n readonly\n class=\"w-full px-3 py-3 pl-[47px] rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n />\n <lucide-icon\n [img]=\"icons.DollarSign\"\n class=\"absolute left-3 top-1/2 -translate-y-1/2 text-gray-400\"\n [size]=\"16\"\n ></lucide-icon>\n </div>\n </div>\n\n <!-- Unit Type Display -->\n <div class=\"relative -top-[20px]\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Unit type\n </label>\n <div\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n >\n {{ shareRouteForm.value.units || 'N/A' }}\n </div>\n </div>\n\n <!-- Contact Info Section Title -->\n <div class=\"md:col-span-2 border-t border-gray-100 dark:border-slate-800\">\n <h3 class=\"flex items-center gap-1 text-md font-semibold text-gray-900 dark:text-white\">\n Customer Information\n </h3>\n </div>\n\n <!-- Contact Name -->\n <div>\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Contact Name\n </label>\n <input\n formControlName=\"contactName\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n />\n </div>\n\n <!-- Contact Phone -->\n <div>\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Contact Phone\n </label>\n <input\n formControlName=\"contactPhone\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n />\n </div>\n\n <!-- Contact Email -->\n <div class=\"space-y-1.5 md:col-span-2\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Contact Email\n </label>\n <input\n formControlName=\"contactEmail\"\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n />\n </div>\n\n <!-- Special Pricing Checkbox -->\n <div class=\"md:col-span-2 pt-2 flex items-center gap-3\">\n <label class=\"relative flex h-5 w-5 cursor-pointer\">\n <input\n type=\"checkbox\"\n formControlName=\"special_price\"\n (change)=\"setValidators(shareRouteForm.value.special_price)\"\n class=\"h-full w-full appearance-none rounded-md border border-gray-300 dark:border-slate-700 transition-all checked:bg-amber-500 checked:border-amber-500 outline-none cursor-pointer\"\n />\n <lucide-icon\n [img]=\"icons.Check\"\n [size]=\"14\"\n [class.opacity-100]=\"shareRouteForm.get('special_price')?.value\"\n [class.opacity-0]=\"!shareRouteForm.get('special_price')?.value\"\n class=\"absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 text-white transition-opacity pointer-events-none\"\n ></lucide-icon>\n </label>\n <span class=\"text-sm font-medium text-gray-700 dark:text-gray-300\"\n >Request special pricing</span\n >\n </div>\n\n <!-- Special Price Input (Conditional) -->\n @if (shareRouteForm.value.special_price) {\n <div class=\"space-y-1.5 animate-fade-in md:col-span-1\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Requested Price\n </label>\n <div class=\"relative\">\n <input\n formControlName=\"customerEstimatedPrice\"\n class=\"w-full px-3 py-3 pl-[47px] rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n />\n <lucide-icon\n [img]=\"icons.DollarSign\"\n class=\"absolute left-3 top-1/2 -translate-y-1/2 text-amber-500\"\n [size]=\"16\"\n ></lucide-icon>\n </div>\n </div>\n <div class=\"relative\">\n <label class=\"block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1\">\n Unit type\n </label>\n <div\n class=\"w-full px-3 py-3 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm\"\n >\n {{ shareRouteForm.value.units || 'N/A' }}\n </div>\n </div>\n }\n </div>\n </div>\n </form>\n </div>\n</div>\n", styles: ["@keyframes slide-up{0%{opacity:0;transform:translateY(20px) scale(.98)}to{opacity:1;transform:translateY(0) scale(1)}}@keyframes fade-in{0%{opacity:0}to{opacity:1}}.animate-slide-up{animation:slide-up .3s cubic-bezier(.16,1,.3,1) forwards}.animate-fade-in{animation:fade-in .2s ease-out forwards}:host{display:block}input[type=date]::-webkit-calendar-picker-indicator{filter:invert(.5);cursor:pointer}.dark input[type=date]::-webkit-calendar-picker-indicator{filter:invert(1)}form::-webkit-scrollbar{width:6px}form::-webkit-scrollbar-track{background:transparent}form::-webkit-scrollbar-thumb{background:#e2e8f0;border-radius:10px}.dark form::-webkit-scrollbar-thumb{background:#334155}\n"] }]
1619
1686
  }], ctorParameters: () => [], propDecorators: { openShareRouteDetails: [{ type: i0.Input, args: [{ isSignal: true, alias: "openShareRouteDetails", required: false }] }], userDetails: [{ type: i0.Input, args: [{ isSignal: true, alias: "userDetails", required: false }] }], closePopupEmit: [{
1620
1687
  type: Output
1621
1688
  }], filterPickup: [{
@@ -1624,6 +1691,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
1624
1691
  }], filterDelivery: [{
1625
1692
  type: ViewChild,
1626
1693
  args: ['filterDelivery']
1694
+ }], unitDropdownWrapper: [{
1695
+ type: ViewChild,
1696
+ args: ['unitDropdownWrapper']
1627
1697
  }], onDocumentClick: [{
1628
1698
  type: HostListener,
1629
1699
  args: ['document:click', ['$event']]
@@ -1746,6 +1816,7 @@ class CoolmapComponent {
1746
1816
  LoaderCircle,
1747
1817
  Calendar
1748
1818
  };
1819
+ dataSubscription;
1749
1820
  constructor() {
1750
1821
  this.filterForm.get('search')?.valueChanges.pipe(takeUntilDestroyed()).subscribe(value => {
1751
1822
  if (value && typeof value === 'string') {
@@ -1804,6 +1875,7 @@ class CoolmapComponent {
1804
1875
  }
1805
1876
  }
1806
1877
  ngOnInit() {
1878
+ this.coolmapService.isLoading.set(true);
1807
1879
  this.loadData(this.dateValue());
1808
1880
  }
1809
1881
  getUnitList() {
@@ -1849,8 +1921,12 @@ class CoolmapComponent {
1849
1921
  }
1850
1922
  }
1851
1923
  loadData(value, isRefresh = false) {
1924
+ this.dataSubscription?.unsubscribe();
1852
1925
  this.dateValue.set(value);
1853
1926
  this.coolmapService.isLoading.set(true);
1927
+ if (!isRefresh) {
1928
+ this.coolmapService.isDataFetched.set(false);
1929
+ }
1854
1930
  // Clear selection when the base list changes (date/repo switch)
1855
1931
  if (!isRefresh) {
1856
1932
  this.selectedRouteIds.set([]);
@@ -1880,7 +1956,7 @@ class CoolmapComponent {
1880
1956
  else {
1881
1957
  dataSet = { date: value };
1882
1958
  }
1883
- this.utils.postdata('jobs_report_v2', dataSet).subscribe({
1959
+ this.dataSubscription = this.utils.postdata('jobs_report_v2', dataSet).subscribe({
1884
1960
  next: (res) => {
1885
1961
  if (res && res.data && typeof res.data !== 'string') {
1886
1962
  const list = res.data.map((ele) => {
@@ -1898,16 +1974,20 @@ class CoolmapComponent {
1898
1974
  this.routesList.set([]);
1899
1975
  }
1900
1976
  this.coolmapService.isLoading.set(false);
1977
+ this.coolmapService.isDataFetched.set(true);
1901
1978
  },
1902
1979
  error: () => {
1903
1980
  this.routesList.set([]);
1904
1981
  this.coolmapService.isLoading.set(false);
1982
+ this.coolmapService.isDataFetched.set(true);
1905
1983
  }
1906
1984
  });
1907
1985
  }
1908
1986
  loadViewRoutes(isRefresh = false) {
1987
+ this.dataSubscription?.unsubscribe();
1909
1988
  this.coolmapService.isLoading.set(true);
1910
1989
  if (!isRefresh) {
1990
+ this.coolmapService.isDataFetched.set(false);
1911
1991
  this.selectedRouteIds.set([]);
1912
1992
  this.filters.set([]);
1913
1993
  this.filterForm.controls['search'].setValue('');
@@ -1928,7 +2008,7 @@ class CoolmapComponent {
1928
2008
  executeViewRoutesFetch() {
1929
2009
  if (this.config.repository === 'customer') {
1930
2010
  const dataSet = { customer_id: this.customerRepoDetails?.customer?.id || '' };
1931
- this.utils.postdata('routes/all', dataSet).subscribe({
2011
+ this.dataSubscription = this.utils.postdata('routes/all', dataSet).subscribe({
1932
2012
  next: (res) => {
1933
2013
  this.handleViewRoutesResponse(res);
1934
2014
  },
@@ -1939,7 +2019,7 @@ class CoolmapComponent {
1939
2019
  });
1940
2020
  }
1941
2021
  else {
1942
- this.utils.getData('routes/all').subscribe({
2022
+ this.dataSubscription = this.utils.getData('routes/all').subscribe({
1943
2023
  next: (res) => {
1944
2024
  this.handleViewRoutesResponse(res);
1945
2025
  },
@@ -1966,6 +2046,7 @@ class CoolmapComponent {
1966
2046
  this.viewRoutesList.set([]);
1967
2047
  }
1968
2048
  this.coolmapService.isLoading.set(false);
2049
+ this.coolmapService.isDataFetched.set(true);
1969
2050
  }
1970
2051
  getUnitName(data) {
1971
2052
  let unitName = '';
@@ -2183,7 +2264,7 @@ class CoolmapComponent {
2183
2264
  this.showShareModal.set(true);
2184
2265
  }
2185
2266
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: CoolmapComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2186
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: CoolmapComponent, isStandalone: true, selector: "lib-coolmap", inputs: { mobileMode: { classPropertyName: "mobileMode", publicName: "mobileMode", isSignal: false, isRequired: false, transformFunction: null }, activeSection: { classPropertyName: "activeSection", publicName: "activeSection", isSignal: true, isRequired: false, transformFunction: null }, customerRepoDetails: { classPropertyName: "customerRepoDetails", publicName: "customerRepoDetails", isSignal: false, isRequired: false, transformFunction: null }, userDetails: { classPropertyName: "userDetails", publicName: "userDetails", isSignal: false, isRequired: false, transformFunction: null }, darkMode: { classPropertyName: "darkMode", publicName: "darkMode", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "document:click": "onClick($event)" } }, viewQueries: [{ propertyName: "mapContainer", first: true, predicate: ["mapContainer"], descendants: true }, { propertyName: "searchContainer", first: true, predicate: ["searchContainer"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"center-area\">\n <div [formGroup]=\"filterForm\" class=\"toolbar flex flex-col sm:flex-row md:h-[55px] h-auto py-2 px-2 gap-3 items-center\">\n <div class=\"toolbar-left flex items-center gap-3 flex-1\">\n @if (activeSection() === 'Jobcode') {\n <div class=\"relative w-full sm:w-auto group mt-[25px]\">\n <input\n type=\"text\"\n [value]=\"displayDate()\"\n readonly\n [disabled]=\"coolmapService.isLoading()\"\n (click)=\"dateInput.showPicker()\"\n class=\"w-full pl-3 pr-10 py-2 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm disabled:opacity-50 disabled:cursor-not-allowed cursor-pointer\"\n />\n <lucide-icon \n [img]=\"icons.Calendar\" \n [size]=\"18\" \n (click)=\"!coolmapService.isLoading() && dateInput.showPicker()\"\n [class.pointer-events-none]=\"coolmapService.isLoading()\"\n [class.opacity-50]=\"coolmapService.isLoading()\"\n class=\"absolute right-[6px] top-[5px] text-white-400 group-hover:text-brand-blue transition-colors cursor-pointer\"\n ></lucide-icon>\n <input\n #dateInput\n type=\"date\"\n [value]=\"dateValue()\"\n (change)=\"onDateChange($event)\"\n [disabled]=\"coolmapService.isLoading()\"\n class=\"absolute inset-0 w-0 h-0 opacity-0 pointer-events-none\"\n />\n </div>\n <span class=\"toolbar-divider hidden sm:flex h-6 w-[1px] bg-gray-200 dark:bg-slate-700\"></span>\n }\n <div #searchContainer class=\"relative items-center flex-1\">\n <lucide-icon [img]=\"icons.Search\" [size]=\"18\" class=\"absolute left-[0.55rem] top-[50%] -translate-y-1/2 text-gray-400\"></lucide-icon>\n <input\n type=\"text\"\n formControlName=\"search\"\n [attr.disabled]=\"coolmapService.isLoading() ? true : null\"\n placeholder=\"Search routes...\"\n class=\"w-full pl-10 pr-10 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-white placeholder-gray-400 focus:ring-2 focus:ring-amber-500 focus:border-transparent text-sm disabled:opacity-50 disabled:cursor-not-allowed\"\n (focus)=\"onSearchFocus()\"\n />\n\n @if (filterForm.value.search) {\n <button (click)=\"filterForm.controls.search.setValue('')\" class=\"absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600\">\n <lucide-icon [img]=\"icons.X\" [size]=\"16\"></lucide-icon>\n </button>\n }\n\n <!-- Autocomplete Dropdown -->\n @if (dropdownOpen() && filteredOptions().length > 0) {\n <div class=\"absolute z-70 left-0 right-0 top-full mt-1 max-h-60 overflow-y-auto bg-white dark:bg-slate-800 border border-gray-200 dark:border-slate-600 rounded shadow-lg\">\n @for (option of filteredOptions(); track option.value + option.type) {\n <div (click)=\"selectFilter(option)\" class=\"px-4 py-2 hover:bg-gray-100 dark:hover:bg-slate-700 cursor-pointer text-xs font-medium border-b border-gray-100 dark:border-slate-700 last:border-0 dark:text-white\">\n <span class=\"capitalize\">{{ option.type }}:</span>\n {{ option.label }}\n </div>\n }\n </div>\n }\n </div>\n\n @if (filters().length > 0) {\n <div class=\"flex flex-wrap gap-2 ml-2\">\n @for (filter of filters(); track filter.value + filter.type) {\n <div class=\"inline-flex items-center gap-1 px-2 py-1 rounded bg-slate-200 dark:bg-slate-700 text-gray-800 dark:text-gray-200 text-xs font-medium border border-gray-300 dark:border-slate-600\">\n <span class=\"capitalize opacity-80\">{{ filter.type }}:</span> {{ filter.name }}\n <button type=\"button\" (click)=\"removeFilter(filter)\" class=\"hover:opacity-75 transition-opacity ml-1\">\n <lucide-icon [img]=\"icons.X\" [size]=\"12\"></lucide-icon>\n </button>\n </div>\n }\n </div>\n }\n </div>\n <div class=\"toolbar-right\">\n @if (selectedRouteIds().length > 0) {\n <button\n type=\"button\"\n (click)=\"clearSelection()\"\n [disabled]=\"coolmapService.isLoading()\"\n class=\"inline-flex items-center justify-center gap-2 px-5 sm:px-6 py-2 bg-amber-500 hover:bg-amber-600 disabled:opacity-50 disabled:cursor-not-allowed text-white font-medium rounded-lg transition-colors text-xs md:text-sm\"\n >\n Show all routes ({{ selectedRouteIds().length }})\n </button>\n }\n @if (activeSection() === 'ViewRoute') {\n <button\n type=\"button\"\n class=\"inline-flex items-center justify-center gap-2 px-5 sm:px-6 py-2 bg-amber-500 hover:bg-amber-600 disabled:opacity-50 disabled:cursor-not-allowed text-white font-medium rounded-lg transition-colors text-xs md:text-sm\"\n [disabled]=\"coolmapService.isLoading()\"\n (click)=\"openAddRouteModal()\">\n <svg class=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M12 4v16m8-8H4\"\n />\n </svg>\n Add Route\n </button>\n }\n\n @if(activeSection() === 'Jobcode'){\n <button\n class=\"inline-flex items-center gap-2 px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed relative group\"\n (click)=\"showRouteList = true\"\n [disabled]=\"coolmapService.isLoading()\">\n <lucide-icon [img]=\"icons.Route\" [size]=\"20\"></lucide-icon>\n <div\n class=\"absolute top-full right-0 mt-2 group-hover:block hidden bg-gray-800 dark:bg-white text-white dark:text-black text-[10px] rounded py-1 px-2 whitespace-nowrap\">\n Show Route List\n <div\n class=\"absolute -top-[8px] left-[60px] border-4 border-transparent border-b-gray-800 dark:border-b-white\">\n </div>\n </div>\n </button>}\n </div>\n </div>\n <div class=\"view-content\">\n <div class=\"full-view\">\n <div class=\"map-container\">\n <div class=\"mapbox-container\" #mapContainer></div>\n </div>\n </div>\n\n <!-- FOR JOBCODE -->\n @if (activeSection() === 'Jobcode') {\n <lib-job-code \n listMode=\"floating\" \n [routes]=\"activeFilteredRoutes()\"\n [selectedRouteIds]=\"selectedRouteIds()\"\n [isLoading]=\"coolmapService.isLoading()\"\n (routeSelect)=\"toggleSelection($event)\">\n </lib-job-code>\n }\n\n <!-- FOR VIEWROUTE -->\n @if (activeSection() === 'ViewRoute') {\n <lib-view-route-list \n listMode=\"floating\" \n [routes]=\"activeFilteredRoutes()\"\n [selectedRouteIds]=\"selectedRouteIds()\"\n (routeSelect)=\"toggleSelection($event)\"\n (editRoute)=\"openEditModal($event)\"\n ></lib-view-route-list>\n }\n </div>\n @if (config.repository === 'coolmap') {\n <div class=\"status-bar\">\n <div class=\"stats-row\">\n <div class=\"stat-item active\" title=\"Active routes (assigned + in progress)\">\n <span class=\"stat-count\">{{ masterStats().Done }}</span>\n <span class=\"stat-label\">Done</span>\n </div>\n\n <div class=\"stat-item completed\" title=\"Completed tasks\">\n <span class=\"stat-count\">{{ masterStats().Incomplete }}</span>\n <span class=\"stat-label\">Incomplete</span>\n </div>\n\n <div class=\"stat-item declined\" title=\"Declined routes - needs attention\">\n <span class=\"stat-count\">{{ masterStats().Ongoing }}</span>\n <span class=\"stat-label\">Ongoing</span>\n </div>\n\n <div class=\"stat-item scheduled\" title=\"Scheduled jobs for today\">\n <span class=\"stat-count\">{{ masterStats().Open }}</span>\n <span class=\"stat-label\">Open</span>\n </div>\n </div>\n </div>\n }\n</div>\n<lib-job-route-list \n [initialRoutes]=\"viewRoutesList()\"\n [(modalOpen)]=\"showRouteList\"\n [selectedRouteIds]=\"modalPlottedIds()\"\n (routeSelect)=\"toggleModalRoute($event)\"\n (masterToggleEvent)=\"modalMasterToggle($event)\"\n [customerRepoDetails]=\"customerRepoDetails\"\n (shareRoute)=\"handleShareRoute($event)\"\n></lib-job-route-list>\n<lib-add-route \n [modalOpen]=\"addRouteModal\"\n (modalOpenChange)=\"onAddRouteModalChange($event)\"\n (routeSaved)=\"onRouteSaved($event)\"\n (routeDeleted)=\"onRouteDeleted($event)\"\n [customerRepoDetails]=\"customerRepoDetails\"\n [routeData]=\"selectedRouteForEdit()\"\n></lib-add-route>\n\n@if (showShareModal()) {\n <lib-share-route\n [openShareRouteDetails]=\"shareRouteData()\"\n [userDetails]=\"userDetails\"\n (closePopupEmit)=\"showShareModal.set(false)\" class=\"relative\"\n ></lib-share-route>\n}\n\n<ag-toast-container></ag-toast-container>\n", styles: [":host{display:block;width:100%;height:100%;min-height:400px}.center-area{height:100%;display:flex;flex-direction:column;overflow:hidden}.view-content{flex:1;position:relative;overflow:hidden;z-index:10}.full-view{position:absolute;inset:0}.map-container,.mapbox-container{width:100%;height:100%}.toolbar{align-items:center;justify-content:space-between;background:var(--bg-primary, white);border-bottom:1px solid var(--border-color, #e2e8f0);flex-shrink:0;gap:8px;position:relative;z-index:12}:host-context(.dark) .toolbar{background:var(--bg-dark-primary, #1e293b);border-color:var(--border-dark, #334155);box-shadow:0 1px 3px #0000004d}.toolbar-left{display:flex;align-items:center;gap:12px;flex-shrink:0}.toolbar-divider{width:1px;height:20px;background:var(--border-color, #e2e8f0);margin:0 2px;flex-shrink:0}:host-context(.dark) .toolbar-divider{background:#475569}.toolbar-right{display:flex;align-items:center;gap:10px;flex-shrink:0}.status-bar{display:flex;align-items:center;height:100%;padding:0 16px;background:var(--status-bar-bg, #1e293b);color:#fff;font-size:12px;gap:20px;flex-shrink:0;height:36px}.stats-row{display:flex;align-items:center;gap:20px}.stat-item{display:flex;align-items:center;gap:6px;cursor:default}.stat-count{font-size:15px;font-weight:700;line-height:1}.stat-item.active .stat-count{color:#60a5fa}.stat-item.completed .stat-count{color:#4ade80}.stat-item.declined .stat-count{color:#f87171}.stat-item.scheduled .stat-count{color:#a78bfa}.stat-item.pending .stat-count{color:#fbbf24}.route-list-wrapper{position:absolute;top:10px;left:10px;bottom:10px;width:380px;z-index:20;pointer-events:none;display:flex;flex-direction:column}@media (max-width: 1024px){.route-list-wrapper{width:320px}}.route-list-wrapper>*{pointer-events:auto}.list-loader{position:absolute;inset:0;background:#fff6;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);display:flex;align-items:center;justify-content:center;z-index:100;border-radius:12px;border:1px solid rgba(255,255,255,.2);box-shadow:0 8px 32px #1f268712}:host-context(.dark) .list-loader{background:#0f172a66;border-color:#ffffff1a}.animate-spin{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: LucideAngularModule }, { kind: "component", type: i1.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }, { kind: "component", type: JobCodeComponent, selector: "lib-job-code", inputs: ["listMode", "collapsible", "routes", "selectedRouteIds", "isLoading"], outputs: ["routeSelect"] }, { kind: "component", type: ViewRouteListComponent, selector: "lib-view-route-list", inputs: ["listMode", "collapsible", "routes", "selectedRouteIds"], outputs: ["routeSelect", "editRoute"] }, { kind: "component", type: JobRouteListComponent, selector: "lib-job-route-list", inputs: ["customerRepoDetails", "selectedRouteIds", "modalOpen", "initialRoutes"], outputs: ["modalOpenChange", "routeSelect", "masterToggleEvent", "shareRoute"] }, { kind: "component", type: AddRouteComponent, selector: "lib-add-route", inputs: ["modalOpen", "routeData", "customerRepoDetails"], outputs: ["modalOpenChange", "routeDeleted", "routeSaved"] }, { kind: "component", type: ShareRouteComponent, selector: "lib-share-route", inputs: ["openShareRouteDetails", "userDetails"], outputs: ["closePopupEmit"] }, { kind: "component", type: AgToastContainerComponent, selector: "ag-toast-container" }] });
2267
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: CoolmapComponent, isStandalone: true, selector: "lib-coolmap", inputs: { mobileMode: { classPropertyName: "mobileMode", publicName: "mobileMode", isSignal: false, isRequired: false, transformFunction: null }, activeSection: { classPropertyName: "activeSection", publicName: "activeSection", isSignal: true, isRequired: false, transformFunction: null }, customerRepoDetails: { classPropertyName: "customerRepoDetails", publicName: "customerRepoDetails", isSignal: false, isRequired: false, transformFunction: null }, userDetails: { classPropertyName: "userDetails", publicName: "userDetails", isSignal: false, isRequired: false, transformFunction: null }, darkMode: { classPropertyName: "darkMode", publicName: "darkMode", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "document:click": "onClick($event)" } }, viewQueries: [{ propertyName: "mapContainer", first: true, predicate: ["mapContainer"], descendants: true }, { propertyName: "searchContainer", first: true, predicate: ["searchContainer"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"center-area\">\n <div [formGroup]=\"filterForm\" class=\"toolbar flex flex-col sm:flex-row md:h-[55px] h-auto py-2 px-2 gap-3 items-center\">\n <div class=\"toolbar-left flex items-center gap-3 flex-1\">\n @if (activeSection() === 'Jobcode') {\n <div class=\"relative w-full sm:w-auto group mt-[25px]\">\n <input\n type=\"text\"\n [value]=\"displayDate()\"\n readonly\n [disabled]=\"coolmapService.isLoading()\"\n (click)=\"dateInput.showPicker()\"\n class=\"w-full pl-3 pr-10 py-2 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm disabled:opacity-50 disabled:cursor-not-allowed cursor-pointer\"\n />\n <lucide-icon \n [img]=\"icons.Calendar\" \n [size]=\"18\" \n (click)=\"!coolmapService.isLoading() && dateInput.showPicker()\"\n [class.pointer-events-none]=\"coolmapService.isLoading()\"\n [class.opacity-50]=\"coolmapService.isLoading()\"\n class=\"absolute right-[6px] top-[5px] text-white-400 group-hover:text-brand-blue transition-colors cursor-pointer\"\n ></lucide-icon>\n <input\n #dateInput\n type=\"date\"\n [value]=\"dateValue()\"\n (change)=\"onDateChange($event)\"\n [disabled]=\"coolmapService.isLoading()\"\n class=\"absolute inset-0 w-0 h-0 opacity-0 pointer-events-none\"\n />\n </div>\n <span class=\"toolbar-divider hidden sm:flex h-6 w-[1px] bg-gray-200 dark:bg-slate-700\"></span>\n }\n @if (filters() && filters().length > 0) {\n <div class=\"flex flex-wrap gap-2 ml-2\">\n @for (filter of filters(); track filter.value + filter.type) {\n <div class=\"inline-flex items-center gap-1 px-2 py-2.5 rounded-xl bg-slate-200 dark:bg-slate-700 text-gray-800 dark:text-gray-200 text-xs font-medium border border-gray-300 dark:border-slate-600\">\n <span class=\"capitalize opacity-80\">{{ filter.type }}:</span> {{ filter.name }}\n <button type=\"button\" (click)=\"removeFilter(filter)\" class=\"hover:opacity-75 transition-opacity ml-1\">\n <lucide-icon [img]=\"icons.X\" [size]=\"12\"></lucide-icon>\n </button>\n </div>\n }\n </div>\n }\n <div #searchContainer class=\"relative items-center flex-1\">\n <lucide-icon [img]=\"icons.Search\" [size]=\"18\" class=\"absolute left-[0.55rem] top-[50%] -translate-y-1/2 text-gray-400\"></lucide-icon>\n <input\n type=\"text\"\n formControlName=\"search\"\n [attr.disabled]=\"coolmapService.isLoading() ? true : null\"\n placeholder=\"Search routes...\"\n class=\"w-full pl-10 pr-10 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-white placeholder-gray-400 focus:ring-2 focus:ring-amber-500 focus:border-transparent text-sm disabled:opacity-50 disabled:cursor-not-allowed\"\n (focus)=\"onSearchFocus()\"\n />\n\n @if (filterForm.value.search) {\n <button (click)=\"filterForm.controls.search.setValue('')\" class=\"absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600\">\n <lucide-icon [img]=\"icons.X\" [size]=\"16\"></lucide-icon>\n </button>\n }\n\n <!-- Autocomplete Dropdown -->\n @if (dropdownOpen() && filteredOptions().length > 0) {\n <div class=\"absolute z-70 left-0 right-0 top-full mt-1 max-h-60 overflow-y-auto bg-white dark:bg-slate-800 border border-gray-200 dark:border-slate-600 rounded shadow-lg\">\n @for (option of filteredOptions(); track option.value + option.type) {\n <div (click)=\"selectFilter(option)\" class=\"px-4 py-2 hover:bg-gray-100 dark:hover:bg-slate-700 cursor-pointer text-xs font-normal border-b border-gray-100 dark:border-slate-700 last:border-0 dark:text-white\">\n <span class=\"capitalize\">{{ option.type }}:</span>\n {{ option.label }}\n </div>\n }\n </div>\n } @else if (!coolmapService.isLoading() && (!filteredOptions() || filteredOptions().length === 0) && filterForm.value.search) {\n <div class=\"absolute z-70 left-0 right-0 top-full mt-1 p-4 text-center text-gray-400 text-sm bg-white dark:bg-slate-800 border border-gray-200 dark:border-slate-600 rounded shadow-lg\">\n No results found.\n </div>\n }\n\n \n </div>\n </div>\n <div class=\"toolbar-right\">\n @if (selectedRouteIds().length > 0) {\n <button\n type=\"button\"\n (click)=\"clearSelection()\"\n [disabled]=\"coolmapService.isLoading()\"\n class=\"inline-flex items-center justify-center gap-2 px-5 sm:px-6 py-2 bg-amber-500 hover:bg-amber-600 disabled:opacity-50 disabled:cursor-not-allowed text-white font-medium rounded-lg transition-colors text-xs md:text-sm\"\n >\n Show all routes ({{ selectedRouteIds().length }})\n </button>\n }\n @if (activeSection() === 'ViewRoute') {\n <button\n type=\"button\"\n class=\"inline-flex items-center justify-center gap-2 px-4 py-2 bg-amber-500 hover:bg-amber-600 disabled:opacity-50 disabled:cursor-not-allowed text-white font-medium rounded-lg transition-colors text-xs md:text-sm\"\n [disabled]=\"coolmapService.isLoading()\"\n (click)=\"openAddRouteModal()\">\n <svg class=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M12 4v16m8-8H4\"\n />\n </svg>\n Add Route\n </button>\n }\n\n @if(activeSection() === 'Jobcode'){\n <button\n class=\"inline-flex items-center gap-2 px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed relative group\"\n (click)=\"showRouteList = true\"\n [disabled]=\"coolmapService.isLoading()\">\n <lucide-icon [img]=\"icons.Route\" [size]=\"20\"></lucide-icon>\n <div\n class=\"absolute top-full right-0 mt-2 group-hover:block hidden bg-gray-800 dark:bg-white text-white dark:text-black text-[10px] rounded py-1 px-2 whitespace-nowrap\">\n Show Route List\n <div\n class=\"absolute -top-[8px] left-[60px] border-4 border-transparent border-b-gray-800 dark:border-b-white\">\n </div>\n </div>\n </button>}\n </div>\n </div>\n <div class=\"view-content\">\n <div class=\"full-view\">\n <div class=\"map-container\">\n <div class=\"mapbox-container\" #mapContainer></div>\n </div>\n </div>\n\n <!-- FOR JOBCODE -->\n @if (activeSection() === 'Jobcode') {\n <lib-job-code \n listMode=\"floating\" \n [routes]=\"activeFilteredRoutes()\"\n [selectedRouteIds]=\"selectedRouteIds()\"\n [isLoading]=\"coolmapService.isLoading()\"\n (routeSelect)=\"toggleSelection($event)\">\n </lib-job-code>\n }\n\n <!-- FOR VIEWROUTE -->\n @if (activeSection() === 'ViewRoute') {\n <lib-view-route-list \n listMode=\"floating\" \n [routes]=\"activeFilteredRoutes()\"\n [selectedRouteIds]=\"selectedRouteIds()\"\n [isLoading]=\"coolmapService.isLoading()\"\n (routeSelect)=\"toggleSelection($event)\"\n (editRoute)=\"openEditModal($event)\"\n ></lib-view-route-list>\n }\n </div>\n @if (config.repository === 'coolmap') {\n <div class=\"status-bar\">\n <div class=\"stats-row\">\n <div class=\"stat-item active\" title=\"Active routes (assigned + in progress)\">\n <span class=\"stat-count\">{{ masterStats().Done }}</span>\n <span class=\"stat-label\">Done</span>\n </div>\n\n <div class=\"stat-item completed\" title=\"Completed tasks\">\n <span class=\"stat-count\">{{ masterStats().Incomplete }}</span>\n <span class=\"stat-label\">Incomplete</span>\n </div>\n\n <div class=\"stat-item declined\" title=\"Declined routes - needs attention\">\n <span class=\"stat-count\">{{ masterStats().Ongoing }}</span>\n <span class=\"stat-label\">Ongoing</span>\n </div>\n\n <div class=\"stat-item scheduled\" title=\"Scheduled jobs for today\">\n <span class=\"stat-count\">{{ masterStats().Open }}</span>\n <span class=\"stat-label\">Open</span>\n </div>\n </div>\n </div>\n }\n</div>\n<lib-job-route-list \n [initialRoutes]=\"viewRoutesList()\"\n [(modalOpen)]=\"showRouteList\"\n [selectedRouteIds]=\"modalPlottedIds()\"\n (routeSelect)=\"toggleModalRoute($event)\"\n (masterToggleEvent)=\"modalMasterToggle($event)\"\n [customerRepoDetails]=\"customerRepoDetails\"\n (shareRoute)=\"handleShareRoute($event)\"\n></lib-job-route-list>\n<lib-add-route \n [modalOpen]=\"addRouteModal\"\n (modalOpenChange)=\"onAddRouteModalChange($event)\"\n (routeSaved)=\"onRouteSaved($event)\"\n (routeDeleted)=\"onRouteDeleted($event)\"\n [customerRepoDetails]=\"customerRepoDetails\"\n [routeData]=\"selectedRouteForEdit()\"\n></lib-add-route>\n\n@if (showShareModal()) {\n <lib-share-route\n [openShareRouteDetails]=\"shareRouteData()\"\n [userDetails]=\"userDetails\"\n (closePopupEmit)=\"showShareModal.set(false)\" class=\"relative\"\n ></lib-share-route>\n}\n\n<ag-toast-container></ag-toast-container>\n", styles: [":host{display:block;width:100%;height:100%;min-height:400px}.center-area{height:100%;display:flex;flex-direction:column;overflow:hidden}.view-content{flex:1;position:relative;overflow:hidden;z-index:10}.full-view{position:absolute;inset:0}.map-container,.mapbox-container{width:100%;height:100%}.toolbar{align-items:center;justify-content:space-between;background:var(--bg-primary, white);border-bottom:1px solid var(--border-color, #e2e8f0);flex-shrink:0;gap:8px;position:relative;z-index:12}:host-context(.dark) .toolbar{background:var(--bg-dark-primary, #1e293b);border-color:var(--border-dark, #334155);box-shadow:0 1px 3px #0000004d}.toolbar-left{display:flex;align-items:center;gap:12px;flex-shrink:0}.toolbar-divider{width:1px;height:20px;background:var(--border-color, #e2e8f0);margin:0 2px;flex-shrink:0}:host-context(.dark) .toolbar-divider{background:#475569}.toolbar-right{display:flex;align-items:center;gap:10px;flex-shrink:0}.status-bar{display:flex;align-items:center;height:100%;padding:0 16px;background:var(--status-bar-bg, #1e293b);color:#fff;font-size:12px;gap:20px;flex-shrink:0;height:36px}.stats-row{display:flex;align-items:center;gap:20px}.stat-item{display:flex;align-items:center;gap:6px;cursor:default}.stat-count{font-size:15px;font-weight:700;line-height:1}.stat-item.active .stat-count{color:#60a5fa}.stat-item.completed .stat-count{color:#4ade80}.stat-item.declined .stat-count{color:#f87171}.stat-item.scheduled .stat-count{color:#a78bfa}.stat-item.pending .stat-count{color:#fbbf24}.route-list-wrapper{position:absolute;top:10px;left:10px;bottom:10px;width:380px;z-index:20;pointer-events:none;display:flex;flex-direction:column}@media (max-width: 1024px){.route-list-wrapper{width:320px}}.route-list-wrapper>*{pointer-events:auto}.list-loader{position:absolute;inset:0;background:#fff6;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);display:flex;align-items:center;justify-content:center;z-index:100;border-radius:12px;border:1px solid rgba(255,255,255,.2);box-shadow:0 8px 32px #1f268712}:host-context(.dark) .list-loader{background:#0f172a66;border-color:#ffffff1a}.animate-spin{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: LucideAngularModule }, { kind: "component", type: i1.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }, { kind: "component", type: JobCodeComponent, selector: "lib-job-code", inputs: ["listMode", "collapsible", "routes", "selectedRouteIds", "isLoading"], outputs: ["routeSelect"] }, { kind: "component", type: ViewRouteListComponent, selector: "lib-view-route-list", inputs: ["listMode", "collapsible", "routes", "selectedRouteIds", "isLoading"], outputs: ["routeSelect", "editRoute"] }, { kind: "component", type: JobRouteListComponent, selector: "lib-job-route-list", inputs: ["customerRepoDetails", "selectedRouteIds", "modalOpen", "initialRoutes"], outputs: ["modalOpenChange", "routeSelect", "masterToggleEvent", "shareRoute"] }, { kind: "component", type: AddRouteComponent, selector: "lib-add-route", inputs: ["modalOpen", "routeData", "customerRepoDetails"], outputs: ["modalOpenChange", "routeDeleted", "routeSaved"] }, { kind: "component", type: ShareRouteComponent, selector: "lib-share-route", inputs: ["openShareRouteDetails", "userDetails"], outputs: ["closePopupEmit"] }, { kind: "component", type: AgToastContainerComponent, selector: "ag-toast-container" }] });
2187
2268
  }
2188
2269
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: CoolmapComponent, decorators: [{
2189
2270
  type: Component,
@@ -2197,7 +2278,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
2197
2278
  AddRouteComponent,
2198
2279
  ShareRouteComponent,
2199
2280
  AgToastContainerComponent,
2200
- ], template: "<div class=\"center-area\">\n <div [formGroup]=\"filterForm\" class=\"toolbar flex flex-col sm:flex-row md:h-[55px] h-auto py-2 px-2 gap-3 items-center\">\n <div class=\"toolbar-left flex items-center gap-3 flex-1\">\n @if (activeSection() === 'Jobcode') {\n <div class=\"relative w-full sm:w-auto group mt-[25px]\">\n <input\n type=\"text\"\n [value]=\"displayDate()\"\n readonly\n [disabled]=\"coolmapService.isLoading()\"\n (click)=\"dateInput.showPicker()\"\n class=\"w-full pl-3 pr-10 py-2 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm disabled:opacity-50 disabled:cursor-not-allowed cursor-pointer\"\n />\n <lucide-icon \n [img]=\"icons.Calendar\" \n [size]=\"18\" \n (click)=\"!coolmapService.isLoading() && dateInput.showPicker()\"\n [class.pointer-events-none]=\"coolmapService.isLoading()\"\n [class.opacity-50]=\"coolmapService.isLoading()\"\n class=\"absolute right-[6px] top-[5px] text-white-400 group-hover:text-brand-blue transition-colors cursor-pointer\"\n ></lucide-icon>\n <input\n #dateInput\n type=\"date\"\n [value]=\"dateValue()\"\n (change)=\"onDateChange($event)\"\n [disabled]=\"coolmapService.isLoading()\"\n class=\"absolute inset-0 w-0 h-0 opacity-0 pointer-events-none\"\n />\n </div>\n <span class=\"toolbar-divider hidden sm:flex h-6 w-[1px] bg-gray-200 dark:bg-slate-700\"></span>\n }\n <div #searchContainer class=\"relative items-center flex-1\">\n <lucide-icon [img]=\"icons.Search\" [size]=\"18\" class=\"absolute left-[0.55rem] top-[50%] -translate-y-1/2 text-gray-400\"></lucide-icon>\n <input\n type=\"text\"\n formControlName=\"search\"\n [attr.disabled]=\"coolmapService.isLoading() ? true : null\"\n placeholder=\"Search routes...\"\n class=\"w-full pl-10 pr-10 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-white placeholder-gray-400 focus:ring-2 focus:ring-amber-500 focus:border-transparent text-sm disabled:opacity-50 disabled:cursor-not-allowed\"\n (focus)=\"onSearchFocus()\"\n />\n\n @if (filterForm.value.search) {\n <button (click)=\"filterForm.controls.search.setValue('')\" class=\"absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600\">\n <lucide-icon [img]=\"icons.X\" [size]=\"16\"></lucide-icon>\n </button>\n }\n\n <!-- Autocomplete Dropdown -->\n @if (dropdownOpen() && filteredOptions().length > 0) {\n <div class=\"absolute z-70 left-0 right-0 top-full mt-1 max-h-60 overflow-y-auto bg-white dark:bg-slate-800 border border-gray-200 dark:border-slate-600 rounded shadow-lg\">\n @for (option of filteredOptions(); track option.value + option.type) {\n <div (click)=\"selectFilter(option)\" class=\"px-4 py-2 hover:bg-gray-100 dark:hover:bg-slate-700 cursor-pointer text-xs font-medium border-b border-gray-100 dark:border-slate-700 last:border-0 dark:text-white\">\n <span class=\"capitalize\">{{ option.type }}:</span>\n {{ option.label }}\n </div>\n }\n </div>\n }\n </div>\n\n @if (filters().length > 0) {\n <div class=\"flex flex-wrap gap-2 ml-2\">\n @for (filter of filters(); track filter.value + filter.type) {\n <div class=\"inline-flex items-center gap-1 px-2 py-1 rounded bg-slate-200 dark:bg-slate-700 text-gray-800 dark:text-gray-200 text-xs font-medium border border-gray-300 dark:border-slate-600\">\n <span class=\"capitalize opacity-80\">{{ filter.type }}:</span> {{ filter.name }}\n <button type=\"button\" (click)=\"removeFilter(filter)\" class=\"hover:opacity-75 transition-opacity ml-1\">\n <lucide-icon [img]=\"icons.X\" [size]=\"12\"></lucide-icon>\n </button>\n </div>\n }\n </div>\n }\n </div>\n <div class=\"toolbar-right\">\n @if (selectedRouteIds().length > 0) {\n <button\n type=\"button\"\n (click)=\"clearSelection()\"\n [disabled]=\"coolmapService.isLoading()\"\n class=\"inline-flex items-center justify-center gap-2 px-5 sm:px-6 py-2 bg-amber-500 hover:bg-amber-600 disabled:opacity-50 disabled:cursor-not-allowed text-white font-medium rounded-lg transition-colors text-xs md:text-sm\"\n >\n Show all routes ({{ selectedRouteIds().length }})\n </button>\n }\n @if (activeSection() === 'ViewRoute') {\n <button\n type=\"button\"\n class=\"inline-flex items-center justify-center gap-2 px-5 sm:px-6 py-2 bg-amber-500 hover:bg-amber-600 disabled:opacity-50 disabled:cursor-not-allowed text-white font-medium rounded-lg transition-colors text-xs md:text-sm\"\n [disabled]=\"coolmapService.isLoading()\"\n (click)=\"openAddRouteModal()\">\n <svg class=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M12 4v16m8-8H4\"\n />\n </svg>\n Add Route\n </button>\n }\n\n @if(activeSection() === 'Jobcode'){\n <button\n class=\"inline-flex items-center gap-2 px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed relative group\"\n (click)=\"showRouteList = true\"\n [disabled]=\"coolmapService.isLoading()\">\n <lucide-icon [img]=\"icons.Route\" [size]=\"20\"></lucide-icon>\n <div\n class=\"absolute top-full right-0 mt-2 group-hover:block hidden bg-gray-800 dark:bg-white text-white dark:text-black text-[10px] rounded py-1 px-2 whitespace-nowrap\">\n Show Route List\n <div\n class=\"absolute -top-[8px] left-[60px] border-4 border-transparent border-b-gray-800 dark:border-b-white\">\n </div>\n </div>\n </button>}\n </div>\n </div>\n <div class=\"view-content\">\n <div class=\"full-view\">\n <div class=\"map-container\">\n <div class=\"mapbox-container\" #mapContainer></div>\n </div>\n </div>\n\n <!-- FOR JOBCODE -->\n @if (activeSection() === 'Jobcode') {\n <lib-job-code \n listMode=\"floating\" \n [routes]=\"activeFilteredRoutes()\"\n [selectedRouteIds]=\"selectedRouteIds()\"\n [isLoading]=\"coolmapService.isLoading()\"\n (routeSelect)=\"toggleSelection($event)\">\n </lib-job-code>\n }\n\n <!-- FOR VIEWROUTE -->\n @if (activeSection() === 'ViewRoute') {\n <lib-view-route-list \n listMode=\"floating\" \n [routes]=\"activeFilteredRoutes()\"\n [selectedRouteIds]=\"selectedRouteIds()\"\n (routeSelect)=\"toggleSelection($event)\"\n (editRoute)=\"openEditModal($event)\"\n ></lib-view-route-list>\n }\n </div>\n @if (config.repository === 'coolmap') {\n <div class=\"status-bar\">\n <div class=\"stats-row\">\n <div class=\"stat-item active\" title=\"Active routes (assigned + in progress)\">\n <span class=\"stat-count\">{{ masterStats().Done }}</span>\n <span class=\"stat-label\">Done</span>\n </div>\n\n <div class=\"stat-item completed\" title=\"Completed tasks\">\n <span class=\"stat-count\">{{ masterStats().Incomplete }}</span>\n <span class=\"stat-label\">Incomplete</span>\n </div>\n\n <div class=\"stat-item declined\" title=\"Declined routes - needs attention\">\n <span class=\"stat-count\">{{ masterStats().Ongoing }}</span>\n <span class=\"stat-label\">Ongoing</span>\n </div>\n\n <div class=\"stat-item scheduled\" title=\"Scheduled jobs for today\">\n <span class=\"stat-count\">{{ masterStats().Open }}</span>\n <span class=\"stat-label\">Open</span>\n </div>\n </div>\n </div>\n }\n</div>\n<lib-job-route-list \n [initialRoutes]=\"viewRoutesList()\"\n [(modalOpen)]=\"showRouteList\"\n [selectedRouteIds]=\"modalPlottedIds()\"\n (routeSelect)=\"toggleModalRoute($event)\"\n (masterToggleEvent)=\"modalMasterToggle($event)\"\n [customerRepoDetails]=\"customerRepoDetails\"\n (shareRoute)=\"handleShareRoute($event)\"\n></lib-job-route-list>\n<lib-add-route \n [modalOpen]=\"addRouteModal\"\n (modalOpenChange)=\"onAddRouteModalChange($event)\"\n (routeSaved)=\"onRouteSaved($event)\"\n (routeDeleted)=\"onRouteDeleted($event)\"\n [customerRepoDetails]=\"customerRepoDetails\"\n [routeData]=\"selectedRouteForEdit()\"\n></lib-add-route>\n\n@if (showShareModal()) {\n <lib-share-route\n [openShareRouteDetails]=\"shareRouteData()\"\n [userDetails]=\"userDetails\"\n (closePopupEmit)=\"showShareModal.set(false)\" class=\"relative\"\n ></lib-share-route>\n}\n\n<ag-toast-container></ag-toast-container>\n", styles: [":host{display:block;width:100%;height:100%;min-height:400px}.center-area{height:100%;display:flex;flex-direction:column;overflow:hidden}.view-content{flex:1;position:relative;overflow:hidden;z-index:10}.full-view{position:absolute;inset:0}.map-container,.mapbox-container{width:100%;height:100%}.toolbar{align-items:center;justify-content:space-between;background:var(--bg-primary, white);border-bottom:1px solid var(--border-color, #e2e8f0);flex-shrink:0;gap:8px;position:relative;z-index:12}:host-context(.dark) .toolbar{background:var(--bg-dark-primary, #1e293b);border-color:var(--border-dark, #334155);box-shadow:0 1px 3px #0000004d}.toolbar-left{display:flex;align-items:center;gap:12px;flex-shrink:0}.toolbar-divider{width:1px;height:20px;background:var(--border-color, #e2e8f0);margin:0 2px;flex-shrink:0}:host-context(.dark) .toolbar-divider{background:#475569}.toolbar-right{display:flex;align-items:center;gap:10px;flex-shrink:0}.status-bar{display:flex;align-items:center;height:100%;padding:0 16px;background:var(--status-bar-bg, #1e293b);color:#fff;font-size:12px;gap:20px;flex-shrink:0;height:36px}.stats-row{display:flex;align-items:center;gap:20px}.stat-item{display:flex;align-items:center;gap:6px;cursor:default}.stat-count{font-size:15px;font-weight:700;line-height:1}.stat-item.active .stat-count{color:#60a5fa}.stat-item.completed .stat-count{color:#4ade80}.stat-item.declined .stat-count{color:#f87171}.stat-item.scheduled .stat-count{color:#a78bfa}.stat-item.pending .stat-count{color:#fbbf24}.route-list-wrapper{position:absolute;top:10px;left:10px;bottom:10px;width:380px;z-index:20;pointer-events:none;display:flex;flex-direction:column}@media (max-width: 1024px){.route-list-wrapper{width:320px}}.route-list-wrapper>*{pointer-events:auto}.list-loader{position:absolute;inset:0;background:#fff6;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);display:flex;align-items:center;justify-content:center;z-index:100;border-radius:12px;border:1px solid rgba(255,255,255,.2);box-shadow:0 8px 32px #1f268712}:host-context(.dark) .list-loader{background:#0f172a66;border-color:#ffffff1a}.animate-spin{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"] }]
2281
+ ], template: "<div class=\"center-area\">\n <div [formGroup]=\"filterForm\" class=\"toolbar flex flex-col sm:flex-row md:h-[55px] h-auto py-2 px-2 gap-3 items-center\">\n <div class=\"toolbar-left flex items-center gap-3 flex-1\">\n @if (activeSection() === 'Jobcode') {\n <div class=\"relative w-full sm:w-auto group mt-[25px]\">\n <input\n type=\"text\"\n [value]=\"displayDate()\"\n readonly\n [disabled]=\"coolmapService.isLoading()\"\n (click)=\"dateInput.showPicker()\"\n class=\"w-full pl-3 pr-10 py-2 rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-brand-blue focus:border-transparent text-sm disabled:opacity-50 disabled:cursor-not-allowed cursor-pointer\"\n />\n <lucide-icon \n [img]=\"icons.Calendar\" \n [size]=\"18\" \n (click)=\"!coolmapService.isLoading() && dateInput.showPicker()\"\n [class.pointer-events-none]=\"coolmapService.isLoading()\"\n [class.opacity-50]=\"coolmapService.isLoading()\"\n class=\"absolute right-[6px] top-[5px] text-white-400 group-hover:text-brand-blue transition-colors cursor-pointer\"\n ></lucide-icon>\n <input\n #dateInput\n type=\"date\"\n [value]=\"dateValue()\"\n (change)=\"onDateChange($event)\"\n [disabled]=\"coolmapService.isLoading()\"\n class=\"absolute inset-0 w-0 h-0 opacity-0 pointer-events-none\"\n />\n </div>\n <span class=\"toolbar-divider hidden sm:flex h-6 w-[1px] bg-gray-200 dark:bg-slate-700\"></span>\n }\n @if (filters() && filters().length > 0) {\n <div class=\"flex flex-wrap gap-2 ml-2\">\n @for (filter of filters(); track filter.value + filter.type) {\n <div class=\"inline-flex items-center gap-1 px-2 py-2.5 rounded-xl bg-slate-200 dark:bg-slate-700 text-gray-800 dark:text-gray-200 text-xs font-medium border border-gray-300 dark:border-slate-600\">\n <span class=\"capitalize opacity-80\">{{ filter.type }}:</span> {{ filter.name }}\n <button type=\"button\" (click)=\"removeFilter(filter)\" class=\"hover:opacity-75 transition-opacity ml-1\">\n <lucide-icon [img]=\"icons.X\" [size]=\"12\"></lucide-icon>\n </button>\n </div>\n }\n </div>\n }\n <div #searchContainer class=\"relative items-center flex-1\">\n <lucide-icon [img]=\"icons.Search\" [size]=\"18\" class=\"absolute left-[0.55rem] top-[50%] -translate-y-1/2 text-gray-400\"></lucide-icon>\n <input\n type=\"text\"\n formControlName=\"search\"\n [attr.disabled]=\"coolmapService.isLoading() ? true : null\"\n placeholder=\"Search routes...\"\n class=\"w-full pl-10 pr-10 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-white placeholder-gray-400 focus:ring-2 focus:ring-amber-500 focus:border-transparent text-sm disabled:opacity-50 disabled:cursor-not-allowed\"\n (focus)=\"onSearchFocus()\"\n />\n\n @if (filterForm.value.search) {\n <button (click)=\"filterForm.controls.search.setValue('')\" class=\"absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600\">\n <lucide-icon [img]=\"icons.X\" [size]=\"16\"></lucide-icon>\n </button>\n }\n\n <!-- Autocomplete Dropdown -->\n @if (dropdownOpen() && filteredOptions().length > 0) {\n <div class=\"absolute z-70 left-0 right-0 top-full mt-1 max-h-60 overflow-y-auto bg-white dark:bg-slate-800 border border-gray-200 dark:border-slate-600 rounded shadow-lg\">\n @for (option of filteredOptions(); track option.value + option.type) {\n <div (click)=\"selectFilter(option)\" class=\"px-4 py-2 hover:bg-gray-100 dark:hover:bg-slate-700 cursor-pointer text-xs font-normal border-b border-gray-100 dark:border-slate-700 last:border-0 dark:text-white\">\n <span class=\"capitalize\">{{ option.type }}:</span>\n {{ option.label }}\n </div>\n }\n </div>\n } @else if (!coolmapService.isLoading() && (!filteredOptions() || filteredOptions().length === 0) && filterForm.value.search) {\n <div class=\"absolute z-70 left-0 right-0 top-full mt-1 p-4 text-center text-gray-400 text-sm bg-white dark:bg-slate-800 border border-gray-200 dark:border-slate-600 rounded shadow-lg\">\n No results found.\n </div>\n }\n\n \n </div>\n </div>\n <div class=\"toolbar-right\">\n @if (selectedRouteIds().length > 0) {\n <button\n type=\"button\"\n (click)=\"clearSelection()\"\n [disabled]=\"coolmapService.isLoading()\"\n class=\"inline-flex items-center justify-center gap-2 px-5 sm:px-6 py-2 bg-amber-500 hover:bg-amber-600 disabled:opacity-50 disabled:cursor-not-allowed text-white font-medium rounded-lg transition-colors text-xs md:text-sm\"\n >\n Show all routes ({{ selectedRouteIds().length }})\n </button>\n }\n @if (activeSection() === 'ViewRoute') {\n <button\n type=\"button\"\n class=\"inline-flex items-center justify-center gap-2 px-4 py-2 bg-amber-500 hover:bg-amber-600 disabled:opacity-50 disabled:cursor-not-allowed text-white font-medium rounded-lg transition-colors text-xs md:text-sm\"\n [disabled]=\"coolmapService.isLoading()\"\n (click)=\"openAddRouteModal()\">\n <svg class=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M12 4v16m8-8H4\"\n />\n </svg>\n Add Route\n </button>\n }\n\n @if(activeSection() === 'Jobcode'){\n <button\n class=\"inline-flex items-center gap-2 px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed relative group\"\n (click)=\"showRouteList = true\"\n [disabled]=\"coolmapService.isLoading()\">\n <lucide-icon [img]=\"icons.Route\" [size]=\"20\"></lucide-icon>\n <div\n class=\"absolute top-full right-0 mt-2 group-hover:block hidden bg-gray-800 dark:bg-white text-white dark:text-black text-[10px] rounded py-1 px-2 whitespace-nowrap\">\n Show Route List\n <div\n class=\"absolute -top-[8px] left-[60px] border-4 border-transparent border-b-gray-800 dark:border-b-white\">\n </div>\n </div>\n </button>}\n </div>\n </div>\n <div class=\"view-content\">\n <div class=\"full-view\">\n <div class=\"map-container\">\n <div class=\"mapbox-container\" #mapContainer></div>\n </div>\n </div>\n\n <!-- FOR JOBCODE -->\n @if (activeSection() === 'Jobcode') {\n <lib-job-code \n listMode=\"floating\" \n [routes]=\"activeFilteredRoutes()\"\n [selectedRouteIds]=\"selectedRouteIds()\"\n [isLoading]=\"coolmapService.isLoading()\"\n (routeSelect)=\"toggleSelection($event)\">\n </lib-job-code>\n }\n\n <!-- FOR VIEWROUTE -->\n @if (activeSection() === 'ViewRoute') {\n <lib-view-route-list \n listMode=\"floating\" \n [routes]=\"activeFilteredRoutes()\"\n [selectedRouteIds]=\"selectedRouteIds()\"\n [isLoading]=\"coolmapService.isLoading()\"\n (routeSelect)=\"toggleSelection($event)\"\n (editRoute)=\"openEditModal($event)\"\n ></lib-view-route-list>\n }\n </div>\n @if (config.repository === 'coolmap') {\n <div class=\"status-bar\">\n <div class=\"stats-row\">\n <div class=\"stat-item active\" title=\"Active routes (assigned + in progress)\">\n <span class=\"stat-count\">{{ masterStats().Done }}</span>\n <span class=\"stat-label\">Done</span>\n </div>\n\n <div class=\"stat-item completed\" title=\"Completed tasks\">\n <span class=\"stat-count\">{{ masterStats().Incomplete }}</span>\n <span class=\"stat-label\">Incomplete</span>\n </div>\n\n <div class=\"stat-item declined\" title=\"Declined routes - needs attention\">\n <span class=\"stat-count\">{{ masterStats().Ongoing }}</span>\n <span class=\"stat-label\">Ongoing</span>\n </div>\n\n <div class=\"stat-item scheduled\" title=\"Scheduled jobs for today\">\n <span class=\"stat-count\">{{ masterStats().Open }}</span>\n <span class=\"stat-label\">Open</span>\n </div>\n </div>\n </div>\n }\n</div>\n<lib-job-route-list \n [initialRoutes]=\"viewRoutesList()\"\n [(modalOpen)]=\"showRouteList\"\n [selectedRouteIds]=\"modalPlottedIds()\"\n (routeSelect)=\"toggleModalRoute($event)\"\n (masterToggleEvent)=\"modalMasterToggle($event)\"\n [customerRepoDetails]=\"customerRepoDetails\"\n (shareRoute)=\"handleShareRoute($event)\"\n></lib-job-route-list>\n<lib-add-route \n [modalOpen]=\"addRouteModal\"\n (modalOpenChange)=\"onAddRouteModalChange($event)\"\n (routeSaved)=\"onRouteSaved($event)\"\n (routeDeleted)=\"onRouteDeleted($event)\"\n [customerRepoDetails]=\"customerRepoDetails\"\n [routeData]=\"selectedRouteForEdit()\"\n></lib-add-route>\n\n@if (showShareModal()) {\n <lib-share-route\n [openShareRouteDetails]=\"shareRouteData()\"\n [userDetails]=\"userDetails\"\n (closePopupEmit)=\"showShareModal.set(false)\" class=\"relative\"\n ></lib-share-route>\n}\n\n<ag-toast-container></ag-toast-container>\n", styles: [":host{display:block;width:100%;height:100%;min-height:400px}.center-area{height:100%;display:flex;flex-direction:column;overflow:hidden}.view-content{flex:1;position:relative;overflow:hidden;z-index:10}.full-view{position:absolute;inset:0}.map-container,.mapbox-container{width:100%;height:100%}.toolbar{align-items:center;justify-content:space-between;background:var(--bg-primary, white);border-bottom:1px solid var(--border-color, #e2e8f0);flex-shrink:0;gap:8px;position:relative;z-index:12}:host-context(.dark) .toolbar{background:var(--bg-dark-primary, #1e293b);border-color:var(--border-dark, #334155);box-shadow:0 1px 3px #0000004d}.toolbar-left{display:flex;align-items:center;gap:12px;flex-shrink:0}.toolbar-divider{width:1px;height:20px;background:var(--border-color, #e2e8f0);margin:0 2px;flex-shrink:0}:host-context(.dark) .toolbar-divider{background:#475569}.toolbar-right{display:flex;align-items:center;gap:10px;flex-shrink:0}.status-bar{display:flex;align-items:center;height:100%;padding:0 16px;background:var(--status-bar-bg, #1e293b);color:#fff;font-size:12px;gap:20px;flex-shrink:0;height:36px}.stats-row{display:flex;align-items:center;gap:20px}.stat-item{display:flex;align-items:center;gap:6px;cursor:default}.stat-count{font-size:15px;font-weight:700;line-height:1}.stat-item.active .stat-count{color:#60a5fa}.stat-item.completed .stat-count{color:#4ade80}.stat-item.declined .stat-count{color:#f87171}.stat-item.scheduled .stat-count{color:#a78bfa}.stat-item.pending .stat-count{color:#fbbf24}.route-list-wrapper{position:absolute;top:10px;left:10px;bottom:10px;width:380px;z-index:20;pointer-events:none;display:flex;flex-direction:column}@media (max-width: 1024px){.route-list-wrapper{width:320px}}.route-list-wrapper>*{pointer-events:auto}.list-loader{position:absolute;inset:0;background:#fff6;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);display:flex;align-items:center;justify-content:center;z-index:100;border-radius:12px;border:1px solid rgba(255,255,255,.2);box-shadow:0 8px 32px #1f268712}:host-context(.dark) .list-loader{background:#0f172a66;border-color:#ffffff1a}.animate-spin{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"] }]
2201
2282
  }], ctorParameters: () => [], propDecorators: { mobileMode: [{
2202
2283
  type: Input
2203
2284
  }], activeSection: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeSection", required: false }] }], customerRepoDetails: [{