1- import { Component , OnInit , signal , inject } from "@angular/core" ;
1+ import { Component , OnInit , signal , inject , effect } from "@angular/core" ;
22
33import {
44 FormsModule ,
@@ -8,9 +8,11 @@ import {
88 Validators ,
99} from "@angular/forms" ;
1010import { DomSanitizer , SafeHtml } from "@angular/platform-browser" ;
11+ import { debounceTime } from "rxjs/operators" ;
1112import { PrintTemplateService } from "../../services/print-template.service" ;
1213import { ToastService } from "../../services/toast.service" ;
13- import { PrintTemplate } from "../../models" ;
14+ import { ReceiptGeneratorService } from "../../services/receipt-generator.service" ;
15+ import { PrintTemplate , Sale , SaleItem } from "../../models" ;
1416import { ToggleSwitchComponent } from "../toggle-switch/toggle-switch.component" ;
1517import { TranslatePipe } from "../../pipes/translate.pipe" ;
1618import { TranslationService } from "../../services/translation.service" ;
@@ -29,6 +31,7 @@ import { TranslationService } from "../../services/translation.service";
2931} )
3032export class TemplatesComponent implements OnInit {
3133 private printTemplateService = inject ( PrintTemplateService ) ;
34+ private receiptGeneratorService = inject ( ReceiptGeneratorService ) ;
3235 private fb = inject ( FormBuilder ) ;
3336 sanitizer = inject ( DomSanitizer ) ;
3437 private translationService = inject ( TranslationService ) ;
@@ -41,6 +44,7 @@ export class TemplatesComponent implements OnInit {
4144 showForm = signal < boolean > ( false ) ;
4245 previewMode = signal < "text" | "styled" > ( "styled" ) ;
4346 templateForm : FormGroup ;
47+ previewHtml = signal < string > ( "" ) ;
4448
4549 /** Inserted by Angular inject() migration for backwards compatibility */
4650 constructor ( ...args : unknown [ ] ) ;
@@ -98,13 +102,24 @@ export class TemplatesComponent implements OnInit {
98102 textAlign : [ "center" ] ,
99103 isDefault : [ false ] ,
100104 } ) ;
105+
106+ // Auto-regenerate preview when preview mode changes
107+ effect ( ( ) => {
108+ this . previewMode ( ) ; // Track signal
109+ if ( this . showForm ( ) ) {
110+ this . generatePreview ( ) ;
111+ }
112+ } ) ;
101113 }
102114
103115 ngOnInit ( ) : void {
104116 this . loadTemplates ( ) ;
105- // Subscribe to form changes for live preview
106- this . templateForm . valueChanges . subscribe ( ( ) => {
107- // This will trigger change detection for the preview
117+ // Generate initial preview
118+ this . generatePreview ( ) ;
119+
120+ // Subscribe to form changes for live preview with debounce
121+ this . templateForm . valueChanges . pipe ( debounceTime ( 300 ) ) . subscribe ( ( ) => {
122+ this . generatePreview ( ) ;
108123 } ) ;
109124 }
110125
@@ -386,13 +401,39 @@ export class TemplatesComponent implements OnInit {
386401 }
387402
388403 getSafePreview ( ) : SafeHtml {
389- return this . sanitizer . bypassSecurityTrustHtml ( this . generatePreview ( ) ) ;
404+ return this . sanitizer . bypassSecurityTrustHtml ( this . previewHtml ( ) ) ;
390405 }
391406
392- generatePreview ( ) : string {
407+ async generatePreview ( ) : Promise < void > {
393408 const formValue = this . templateForm . value ;
394409 const mode = this . previewMode ( ) ;
395410
411+ // Create sample sale data for preview
412+ const sampleSale = this . createSampleSale ( ) ;
413+
414+ // Convert form values to PrintTemplate format
415+ const template = this . formValueToTemplate ( formValue ) ;
416+
417+ try {
418+ // Use the real receipt generator service
419+ const html = await this . receiptGeneratorService . generateReceipt (
420+ sampleSale ,
421+ template ,
422+ {
423+ plainTextMode : mode === "text" ,
424+ }
425+ ) ;
426+
427+ this . previewHtml . set ( html ) ;
428+ } catch ( error ) {
429+ console . error ( "Error generating preview:" , error ) ;
430+ // Fallback to simple preview if generation fails
431+ this . previewHtml . set ( this . generateFallbackPreview ( formValue , mode ) ) ;
432+ }
433+ }
434+
435+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
436+ private generateFallbackPreview ( formValue : any , mode : string ) : string {
396437 // If text mode, generate text-only preview
397438 if ( mode === "text" ) {
398439 return this . generatePlainTextPreview ( formValue ) ;
@@ -402,9 +443,134 @@ export class TemplatesComponent implements OnInit {
402443 return this . generateStyledPreview ( formValue ) ;
403444 }
404445
446+ private createSampleSale ( ) : Sale {
447+ // Create sample sale data for preview
448+ const sampleItems : SaleItem [ ] = [
449+ {
450+ product : {
451+ _id : "1" ,
452+ product_id : "PROD-001" ,
453+ name : "Sample Product A" ,
454+ sku : "PROD-001" ,
455+ price : 15.99 ,
456+ stock : 100 ,
457+ category : "Sample" ,
458+ active : true ,
459+ available : true ,
460+ } ,
461+ quantity : 2 ,
462+ unitPrice : 15.99 ,
463+ discount : 0 ,
464+ subtotal : 31.98 ,
465+ total : 0 ,
466+ } ,
467+ {
468+ product : {
469+ _id : "2" ,
470+ product_id : "PROD-002" ,
471+ name : "Sample Product B" ,
472+ sku : "PROD-002" ,
473+ price : 24.5 ,
474+ stock : 50 ,
475+ category : "Sample" ,
476+ active : true ,
477+ available : true ,
478+ } ,
479+ quantity : 1 ,
480+ unitPrice : 24.5 ,
481+ discount : 0 ,
482+ subtotal : 24.5 ,
483+ total : 0 ,
484+ } ,
485+ ] ;
486+
487+ return {
488+ _id : "PREVIEW-001" ,
489+ saleNumber : "SALE-" + new Date ( ) . getTime ( ) ,
490+ items : sampleItems ,
491+ subtotal : 56.48 ,
492+ discount : 0 ,
493+ tax : 4.52 ,
494+ total : 61.0 ,
495+ paymentMethod : "cash" ,
496+ cashier : "Demo Cashier" ,
497+ register : "Register 1" ,
498+ status : "completed" ,
499+ createdAt : new Date ( ) ,
500+ updatedAt : new Date ( ) ,
501+ } as Sale ;
502+ }
503+
504+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
505+ private formValueToTemplate ( formValue : any ) : PrintTemplate {
506+ return {
507+ _id : "preview" ,
508+ name : formValue . name || "Preview" ,
509+ description : formValue . description || "" ,
510+ templateType : formValue . templateType ,
511+ paperSize : formValue . paperSize ,
512+ isDefault : false ,
513+ active : true ,
514+ header : {
515+ showLogo : formValue . showLogo ,
516+ showStoreName : formValue . showStoreName ,
517+ showStoreAddress : formValue . showStoreAddress ,
518+ showStorePhone : formValue . showStorePhone ,
519+ showStoreEmail : formValue . showStoreEmail ,
520+ storeName : formValue . storeName ,
521+ storeAddress : formValue . storeAddress ,
522+ storePhone : formValue . storePhone ,
523+ storeEmail : formValue . storeEmail ,
524+ storeNameSize : formValue . storeNameSize ,
525+ storeNameFont : formValue . storeNameFont ,
526+ storeNameBold : formValue . storeNameBold ,
527+ storeAddressSize : formValue . storeAddressSize ,
528+ storeAddressFont : formValue . storeAddressFont ,
529+ storeAddressBold : formValue . storeAddressBold ,
530+ storePhoneSize : formValue . storePhoneSize ,
531+ storePhoneFont : formValue . storePhoneFont ,
532+ storePhoneBold : formValue . storePhoneBold ,
533+ storeEmailSize : formValue . storeEmailSize ,
534+ storeEmailFont : formValue . storeEmailFont ,
535+ storeEmailBold : formValue . storeEmailBold ,
536+ } ,
537+ body : {
538+ showProductCode : formValue . showProductCode ,
539+ showBarcode : formValue . showBarcode ,
540+ showQuantity : formValue . showQuantity ,
541+ showUnitPrice : formValue . showUnitPrice ,
542+ showDiscount : formValue . showDiscount ,
543+ showTax : formValue . showTax ,
544+ showSubtotal : formValue . showSubtotal ,
545+ productSize : formValue . productSize ,
546+ productFont : formValue . productFont ,
547+ productBold : formValue . productBold ,
548+ fontSize : formValue . fontSize ,
549+ } ,
550+ footer : {
551+ showTotals : formValue . showTotals ,
552+ showPaymentMethod : formValue . showPaymentMethod ,
553+ showCashier : formValue . showCashier ,
554+ showDateTime : formValue . showDateTime ,
555+ showThankYou : formValue . showThankYou ,
556+ customMessage : formValue . customMessage ,
557+ totalSize : formValue . totalSize ,
558+ totalFont : formValue . totalFont ,
559+ totalBold : formValue . totalBold ,
560+ footerSize : formValue . footerSize ,
561+ footerFont : formValue . footerFont ,
562+ footerBold : formValue . footerBold ,
563+ } ,
564+ styles : {
565+ textAlign : formValue . textAlign ,
566+ } ,
567+ } as PrintTemplate ;
568+ }
569+
570+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
405571 private generatePlainTextPreview ( formValue : any ) : string {
406572 const width = formValue . paperSize === "58mm" ? 28 : 40 ;
407- let lines : string [ ] = [ ] ;
573+ const lines : string [ ] = [ ] ;
408574
409575 // Header
410576 if ( formValue . showLogo ) {
@@ -465,6 +631,7 @@ export class TemplatesComponent implements OnInit {
465631 return `<div style="font-family: 'Courier New', monospace; width: 280px; margin: 0 auto; padding: 8px; box-sizing: border-box; border: 1px solid #ddd; font-size: 12px; line-height: 1.4; background: white; white-space: pre-wrap; word-wrap: break-word;"><code>${ this . escapeHtml ( textContent ) } </code></div>` ;
466632 }
467633
634+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
468635 private generateStyledPreview ( formValue : any ) : string {
469636 const fontSize =
470637 formValue . fontSize === "small"
0 commit comments