@@ -76,7 +76,8 @@ export class ExampleComponent implements OnInit, OnDestroy {
7676- ** Cart State** : Managed by ` CartStateService ` with signals (e.g., ` cartCount() ` , ` cartTotal() ` )
7777- ** Search State** : ` SearchStateService ` shares search query across components
7878- ** User State** : ` AuthService.getCurrentUser() ` returns current user or null
79- - ** Register State** : ` RegisterService ` manages active register (cashiers must open register)
79+ - ** Register State** : ` RegisterService ` manages active register with device binding (cashiers must open register)
80+ - ** Device Identification** : ` DeviceService ` generates unique device fingerprints for register binding
8081
8182## Common Workflows
8283
@@ -89,6 +90,49 @@ export class ExampleComponent implements OnInit, OnDestroy {
89905 . ** Add route** in ` src/app/app.routes.ts ` if needed
90916 . ** Apply theme styles** using mixins from ` _theme.scss `
9192
93+ ### Creating Reusable Modal Components
94+
95+ ** Pattern Example: OpenRegisterComponent**
96+
97+ 1 . ** Create component** with ` @Output() ` events for parent communication:
98+
99+ ``` typescript
100+ @Output () registerOpened = new EventEmitter <void >();
101+ @Output () cancelled = new EventEmitter <void >();
102+ ```
103+
104+ 2 . ** Add to parent component imports** :
105+
106+ ``` typescript
107+ imports : [OpenRegisterComponent , ... ]
108+ ```
109+
110+ 3 . ** Use signals for modal state** :
111+
112+ ``` typescript
113+ showOpenRegisterModal = signal <boolean >(false );
114+ ```
115+
116+ 4 . ** Template usage** :
117+
118+ ``` html
119+ <app-open-register
120+ *ngIf =" showOpenRegisterModal()"
121+ (registerOpened) =" onRegisterOpened()"
122+ (cancelled) =" closeRegisterModal()"
123+ >
124+ </app-open-register >
125+ ```
126+
127+ 5 . ** Handle events in parent** :
128+
129+ ``` typescript
130+ onRegisterOpened (): void {
131+ this .showOpenRegisterModal .set (false );
132+ // Additional logic after register opens
133+ }
134+ ```
135+
92136### Adding Backend API Endpoint
93137
941381 . ** Create/update Mongoose model** in ` server/models/{Model}.js `
@@ -111,13 +155,56 @@ export class ExampleComponent implements OnInit, OnDestroy {
111155- Dashboard shows incomplete products card for follow-up editing
112156- Always set ` active: true ` and ` available: true ` for newly created products
113157
158+ ### QR Code Generation & Thermal Printing
159+
160+ - ** QR Badge Generation** : ` settings.component.ts ` handles employee QR badge creation
161+ - ** Display Size** : 150x150 pixels for on-screen preview (` generateQrCode() ` )
162+ - ** Print Size** : 120x120 pixels optimized for 58mm/80mm thermal printers (` printQrBadge() ` )
163+ - ** Badge Layout** : Simplified HTML/CSS with monospace fonts, minimal padding, no shadows for thermal printing
164+ - ** QZ Tray Integration** : Uses QZ Tray service for direct thermal printer communication
165+
114166### Scale Integration
115167
116168- ` ScaleService.connectScale() ` uses Web Serial API (Chrome/Edge only)
117169- Products with ` requiresScale: true ` prompt for weight entry
118170- Weight modal displays current scale reading in real-time
119171- Manual weight entry fallback if scale not connected
120172
173+ ### Register Management & Device Binding
174+
175+ ** OpenRegisterComponent** (` open-register/ ` ) - Dedicated component for opening registers with smart device binding:
176+
177+ - ** Device Auto-Selection** : Automatically selects register bound to current device using ` DeviceService `
178+ - ** Role-Based Access** :
179+ - Admins/Managers: Can select any register, create new registers, manage all devices
180+ - Cashiers/Employees: Can only open registers bound to their device or unbound registers
181+ - ** Device Binding** : Registers are automatically bound to devices when opened (stored in ` deviceId ` and ` deviceName ` )
182+ - ** Visual Indicators** : Shows which registers are linked to current device (⭐) or other devices (🔒)
183+ - ** Used in** : POS component and Cashier component
184+ - ** Backend API** : ` /api/registers/available ` , ` /api/registers/device/:deviceId `
185+
186+ ** Implementation Pattern:**
187+
188+ ``` typescript
189+ // In parent component
190+ showOpenRegisterModal = signal <boolean >(false );
191+
192+ openRegisterModal (): void {
193+ this .showOpenRegisterModal .set (true );
194+ }
195+
196+ onRegisterOpened (): void {
197+ this .showOpenRegisterModal .set (false );
198+ // Register opened successfully, component auto-focuses input
199+ }
200+
201+ // In template
202+ < app - open - register
203+ (registerOpened )= " onRegisterOpened()"
204+ (cancelled )= " closeRegisterModal()"
205+ > </app -open -register >
206+ ```
207+
121208## Important Patterns
122209
123210### ViewChild References
@@ -146,7 +233,7 @@ confirmAdd(): void {
146233
147234### Calculator Component (Keyboard Support)
148235
149- The calculator component supports full keyboard input for faster data entry:
236+ The calculator component ( ` calculator/ ` ) supports full keyboard input for faster data entry with signals :
150237
151238** Keyboard Shortcuts:**
152239
@@ -165,28 +252,13 @@ The calculator component supports full keyboard input for faster data entry:
165252- Multiply button spans 2 columns, styled with ` $warning ` color
166253- Add button spans 2 columns, styled with ` $success ` color
167254
168- ** Implementation Pattern :**
255+ ** Signals Usage :**
169256
170257``` typescript
171- // Add keyboard handler to container
172- < div #calculatorContainer class = " calculator" tabindex = " -1" (keydown )= " onKeydown($event)" >
173-
174- // Handle keyboard events
175- onKeydown (event : KeyboardEvent ): void {
176- if (event .key >= ' 0' && event .key <= ' 9' ) {
177- event .preventDefault ();
178- this .appendNumber (event .key );
179- }
180- else if (event .key === ' Enter' || event .key === ' +' ) {
181- event .preventDefault ();
182- this .handleEnter (); // Adds item or confirms multiply
183- }
184- else if (event .key === ' *' ) {
185- event .preventDefault ();
186- this .multiplyItem ();
187- }
188- // ... other key handlers
189- }
258+ display = signal <string >(" 0" );
259+ isMultiplying = signal <boolean >(false );
260+ multiplyMode = signal <" add" | " update" | null >(null );
261+ pendingMultiplyValue = signal <number | null >(null );
190262```
191263
192264### RxJS Cleanup
@@ -220,7 +292,7 @@ this.toastService.show("Warning", "warning");
220292- ** Sale** : ` saleNumber ` , ` items[] ` , ` subtotal ` , ` discount ` , ` tax ` , ` total ` , ` paymentMethod ` , ` cashier ` , ` register ` , ` status ` , ` isInternal `
221293- ** Cart** : ` user ` , ` items[] ` , ` register ` (carts are session-specific)
222294- ** User** : ` username ` , ` fullName ` , ` role ` , ` permissions[] ` , ` active `
223- - ** Register** : ` name ` , ` location ` , ` status ` ('open', 'closed'), ` openedBy ` , ` openingBalance ` , ` currentBalance `
295+ - ** Register** : ` name ` , ` location ` , ` status ` ('open', 'closed'), ` openedBy ` , ` openingBalance ` , ` currentBalance ` , ` deviceId ` , ` deviceName ` (device binding)
224296
225297## Security & Permissions
226298
0 commit comments