---
description: 
globs: 
alwaysApply: true
---
# QR Code Implementation Guide

## Directory Structure

```
src/
├── components/
│   └── QRScanner/
│       ├── types.ts
│       ├── factory.ts
│       ├── CapacitorScanner.ts
│       ├── WebDialogScanner.ts
│       └── QRScannerDialog.vue
├── services/
│   └── QRScanner/
│       ├── types.ts
│       ├── QRScannerFactory.ts
│       ├── CapacitorQRScanner.ts
│       └── WebDialogQRScanner.ts
```

## Core Interfaces

```typescript
// types.ts
export interface ScanListener {
  onScan: (result: string) => void;
  onError?: (error: Error) => void;
}

export interface QRScannerService {
  checkPermissions(): Promise<boolean>;
  requestPermissions(): Promise<boolean>;
  isSupported(): Promise<boolean>;
  startScan(): Promise<void>;
  stopScan(): Promise<void>;
  addListener(listener: ScanListener): void;
  cleanup(): Promise<void>;
}
```

## Configuration Files

### Vite Configuration
```typescript
// vite.config.ts
export default defineConfig({
  define: {
    __USE_QR_READER__: JSON.stringify(!isMobile),
    __IS_MOBILE__: JSON.stringify(isMobile),
  },
  build: {
    rollupOptions: {
      external: isMobile ? ['vue-qrcode-reader'] : [],
    }
  }
});
```

### Capacitor Configuration
```typescript
// capacitor.config.ts
const config: CapacitorConfig = {
  plugins: {
    MLKitBarcodeScanner: {
      formats: ['QR_CODE'],
      detectorSize: 1.0,
      lensFacing: 'back',
      googleBarcodeScannerModuleInstallState: true
    }
  }
};
```

## Implementation Steps

1. **Install Dependencies**
```bash
npm install @capacitor-mlkit/barcode-scanning vue-qrcode-reader
```

2. **Create Core Types**
Create the interface files as shown above.

3. **Implement Factory**
```typescript
// QRScannerFactory.ts
export class QRScannerFactory {
  private static instance: QRScannerService | null = null;

  static getInstance(): QRScannerService {
    if (!this.instance) {
      if (__IS_MOBILE__ || Capacitor.isNativePlatform()) {
        this.instance = new CapacitorQRScanner();
      } else if (__USE_QR_READER__) {
        this.instance = new WebDialogQRScanner();
      } else {
        throw new Error('No QR scanner implementation available');
      }
    }
    return this.instance;
  }

  static async cleanup() {
    if (this.instance) {
      await this.instance.cleanup();
      this.instance = null;
    }
  }
}
```

4. **Implement Mobile Scanner**
```typescript
// CapacitorQRScanner.ts
export class CapacitorQRScanner implements QRScannerService {
  private scanListener: ScanListener | null = null;
  private isScanning = false;
  private listenerHandles: Array<() => Promise<void>> = [];

  async checkPermissions() {
    try {
      const { camera } = await BarcodeScanner.checkPermissions();
      return camera === 'granted';
    } catch (error) {
      logger.error('Error checking camera permissions:', error);
      return false;
    }
  }

  // Implement other interface methods...
}
```

5. **Implement Web Scanner**
```typescript
// WebDialogQRScanner.ts
export class WebDialogQRScanner implements QRScannerService {
  private dialogInstance: App | null = null;
  private dialogComponent: InstanceType<typeof QRScannerDialog> | null = null;
  private scanListener: ScanListener | null = null;
  async checkPermissions(): Promise<boolean> {
    try {
      const permissions = await navigator.permissions.query({
        name: 'camera' as PermissionName
      });
      return permissions.state === 'granted';
    } catch (error) {
      logger.error('Error checking camera permissions:', error);
      return false;
    }
  }

  // Implement other interface methods...
}
```

6. **Create Dialog Component**
```vue
<!-- QRScannerDialog.vue -->
<template>
  <div v-if="visible" class="dialog-overlay z-[60]">
    <div class="dialog relative">
      <!-- Dialog content -->
      <div v-if="useQRReader">
        <qrcode-stream
          class="w-full max-w-lg mx-auto"
          @detect="onScanDetect"
          @error="onScanError"
        />
      </div>
      <div v-else>
        <!-- Mobile camera button -->
      </div>
    </div>
  </div>
</template>

<script lang="ts">
@Component({
  components: { QrcodeStream }
})
export default class QRScannerDialog extends Vue {
  // Implementation...
}
</script>
```

## Usage Example

```typescript
// In your component
async function scanQRCode() {
  const scanner = QRScannerFactory.getInstance();
  
  if (!(await scanner.checkPermissions())) {
    const granted = await scanner.requestPermissions();
    if (!granted) {
      throw new Error('Camera permission denied');
    }
  }

  scanner.addListener({
    onScan: (result) => {
      console.log('Scanned:', result);
    },
    onError: (error) => {
      console.error('Scan error:', error);
    }
  });

  await scanner.startScan();
}

// Cleanup when done
onUnmounted(() => {
  QRScannerFactory.cleanup();
});
```

## Platform-Specific Notes

### Mobile (Capacitor)
- Uses MLKit for optimal performance
- Handles native permissions
- Supports both iOS and Android
- Uses back camera by default
- Handles device rotation

### Web
- Uses MediaDevices API
- Requires HTTPS for camera access
- Handles browser compatibility
- Manages memory and resources
- Provides fallback UI

## Testing

1. **Unit Tests**
- Test factory pattern
- Test platform detection
- Test error handling
- Test cleanup procedures

2. **Integration Tests**
- Test permission flows
- Test camera access
- Test QR code detection
- Test cross-platform behavior

3. **E2E Tests**
- Test full scanning workflow
- Test UI feedback
- Test error scenarios
- Test platform differences

## Common Issues and Solutions

1. **Permission Handling**
- Always check permissions first
- Provide clear user feedback
- Handle denial gracefully
- Implement retry logic

2. **Resource Management**
- Clean up after scanning
- Handle component unmounting
- Release camera resources
- Clear event listeners

3. **Error Handling**
- Log errors appropriately
- Provide user feedback
- Implement fallbacks
- Handle edge cases

4. **Performance**
- Optimize camera preview
- Handle memory usage
- Manage battery impact
- Consider device capabilities

# QR Code Implementation Guide

## Directory Structure

```
src/
├── components/
│   └── QRScanner/
│       ├── types.ts
│       ├── factory.ts
│       ├── CapacitorScanner.ts
│       ├── WebDialogScanner.ts
│       └── QRScannerDialog.vue
├── services/
│   └── QRScanner/
│       ├── types.ts
│       ├── QRScannerFactory.ts
│       ├── CapacitorQRScanner.ts
│       └── WebDialogQRScanner.ts
```

## Core Interfaces

```typescript
// types.ts
export interface ScanListener {
  onScan: (result: string) => void;
  onError?: (error: Error) => void;
}

export interface QRScannerService {
  checkPermissions(): Promise<boolean>;
  requestPermissions(): Promise<boolean>;
  isSupported(): Promise<boolean>;
  startScan(): Promise<void>;
  stopScan(): Promise<void>;
  addListener(listener: ScanListener): void;
  cleanup(): Promise<void>;
}
```

## Configuration Files

### Vite Configuration
```typescript
// vite.config.ts
export default defineConfig({
  define: {
    __USE_QR_READER__: JSON.stringify(!isMobile),
    __IS_MOBILE__: JSON.stringify(isMobile),
  },
  build: {
    rollupOptions: {
      external: isMobile ? ['vue-qrcode-reader'] : [],
    }
  }
});
```

### Capacitor Configuration
```typescript
// capacitor.config.ts
const config: CapacitorConfig = {
  plugins: {
    MLKitBarcodeScanner: {
      formats: ['QR_CODE'],
      detectorSize: 1.0,
      lensFacing: 'back',
      googleBarcodeScannerModuleInstallState: true
    }
  }
};
```

## Implementation Steps

1. **Install Dependencies**
```bash
npm install @capacitor-mlkit/barcode-scanning vue-qrcode-reader
```

2. **Create Core Types**
Create the interface files as shown above.

3. **Implement Factory**
```typescript
// QRScannerFactory.ts
export class QRScannerFactory {
  private static instance: QRScannerService | null = null;

  static getInstance(): QRScannerService {
    if (!this.instance) {
      if (__IS_MOBILE__ || Capacitor.isNativePlatform()) {
        this.instance = new CapacitorQRScanner();
      } else if (__USE_QR_READER__) {
        this.instance = new WebDialogQRScanner();
      } else {
        throw new Error('No QR scanner implementation available');
      }
    }
    return this.instance;
  }

  static async cleanup() {
    if (this.instance) {
      await this.instance.cleanup();
      this.instance = null;
    }
  }
}
```

4. **Implement Mobile Scanner**
```typescript
// CapacitorQRScanner.ts
export class CapacitorQRScanner implements QRScannerService {
  private scanListener: ScanListener | null = null;
  private isScanning = false;
  private listenerHandles: Array<() => Promise<void>> = [];

  async checkPermissions() {
    try {
      const { camera } = await BarcodeScanner.checkPermissions();
      return camera === 'granted';
    } catch (error) {
      logger.error('Error checking camera permissions:', error);
      return false;
    }
  }

  // Implement other interface methods...
}
```

5. **Implement Web Scanner**
```typescript
// WebDialogQRScanner.ts
export class WebDialogQRScanner implements QRScannerService {
  private dialogInstance: App | null = null;
  private dialogComponent: InstanceType<typeof QRScannerDialog> | null = null;
  private scanListener: ScanListener | null = null;
  async checkPermissions(): Promise<boolean> {
    try {
      const permissions = await navigator.permissions.query({
        name: 'camera' as PermissionName
      });
      return permissions.state === 'granted';
    } catch (error) {
      logger.error('Error checking camera permissions:', error);
      return false;
    }
  }

  // Implement other interface methods...
}
```

6. **Create Dialog Component**
```vue
<!-- QRScannerDialog.vue -->
<template>
  <div v-if="visible" class="dialog-overlay z-[60]">
    <div class="dialog relative">
      <!-- Dialog content -->
      <div v-if="useQRReader">
        <qrcode-stream
          class="w-full max-w-lg mx-auto"
          @detect="onScanDetect"
          @error="onScanError"
        />
      </div>
      <div v-else>
        <!-- Mobile camera button -->
      </div>
    </div>
  </div>
</template>

<script lang="ts">
@Component({
  components: { QrcodeStream }
})
export default class QRScannerDialog extends Vue {
  // Implementation...
}
</script>
```

## Usage Example

```typescript
// In your component
async function scanQRCode() {
  const scanner = QRScannerFactory.getInstance();
  
  if (!(await scanner.checkPermissions())) {
    const granted = await scanner.requestPermissions();
    if (!granted) {
      throw new Error('Camera permission denied');
    }
  }

  scanner.addListener({
    onScan: (result) => {
      console.log('Scanned:', result);
    },
    onError: (error) => {
      console.error('Scan error:', error);
    }
  });

  await scanner.startScan();
}

// Cleanup when done
onUnmounted(() => {
  QRScannerFactory.cleanup();
});
```

## Platform-Specific Notes

### Mobile (Capacitor)
- Uses MLKit for optimal performance
- Handles native permissions
- Supports both iOS and Android
- Uses back camera by default
- Handles device rotation

### Web
- Uses MediaDevices API
- Requires HTTPS for camera access
- Handles browser compatibility
- Manages memory and resources
- Provides fallback UI

## Testing

1. **Unit Tests**
- Test factory pattern
- Test platform detection
- Test error handling
- Test cleanup procedures

2. **Integration Tests**
- Test permission flows
- Test camera access
- Test QR code detection
- Test cross-platform behavior

3. **E2E Tests**
- Test full scanning workflow
- Test UI feedback
- Test error scenarios
- Test platform differences

## Common Issues and Solutions

1. **Permission Handling**
- Always check permissions first
- Provide clear user feedback
- Handle denial gracefully
- Implement retry logic

2. **Resource Management**
- Clean up after scanning
- Handle component unmounting
- Release camera resources
- Clear event listeners

3. **Error Handling**
- Log errors appropriately
- Provide user feedback
- Implement fallbacks
- Handle edge cases

4. **Performance**
- Optimize camera preview
- Handle memory usage
- Manage battery impact
- Consider device capabilities