2c1b3cfca6
Build & Push Docker Images / test-backend (push) Successful in 24s
Build & Push Docker Images / test-frontend (push) Successful in 23s
Build & Push Docker Images / build-backend (push) Successful in 2m22s
Build & Push Docker Images / build-frontend (push) Successful in 57s
8.1 KiB
8.1 KiB
FarmaFinder — TSI Barcode Scanning + Capacitor 8 Upgrade
Overview
Two sequential phases:
- Phase A — Upgrade Capacitor 6 → 8 (prerequisite for latest barcode scanner plugin)
- Phase B — Implement real TSI barcode scanning with manual CIP entry fallback
Phase A: Upgrade Capacitor 6 → 8
A1. Upgrade Capacitor packages (root)
npm install @capacitor/cli@latest @capacitor/core@latest \
@capacitor/android@latest @capacitor/ios@latest \
@capacitor/app@latest @capacitor/splash-screen@latest \
@capacitor/status-bar@latest
This bumps all @capacitor/* from ^6.x to ^8.x in package.json.
A2. Update android/variables.gradle
Replace all 13 version variables to meet Capacitor 8 minimums:
| Variable | Current | New |
|---|---|---|
minSdkVersion |
22 | 24 |
compileSdkVersion |
34 | 36 |
targetSdkVersion |
34 | 36 |
androidxActivityVersion |
1.8.0 | 1.11.0 |
androidxAppCompatVersion |
1.6.1 | 1.7.1 |
androidxCoordinatorLayoutVersion |
1.2.0 | 1.3.0 |
androidxCoreVersion |
1.12.0 | 1.17.0 |
androidxFragmentVersion |
1.6.2 | 1.8.9 |
coreSplashScreenVersion |
1.0.1 | 1.2.0 |
androidxWebkitVersion |
1.9.0 | 1.14.0 |
junitVersion |
4.13.2 | 4.13.2 (same) |
androidxJunitVersion |
1.1.5 | 1.3.0 |
androidxEspressoCoreVersion |
3.5.1 | 3.7.0 |
cordovaAndroidVersion |
10.1.1 | 14.0.1 |
A3. Update ios/App/Podfile
- Line 3: Change
platform :ios, '13.0'→platform :ios, '15.0'
A4. Update android/app/src/main/AndroidManifest.xml
- Add
densitytoandroid:configChangeson line 13:android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode|density"
A5. Update android/build.gradle (Gradle plugin)
- Update Android Gradle Plugin from
8.2.1→8.13.0 - Update Google Services plugin from
4.4.0→4.4.4 - Update Gradle wrapper to
8.14.3inandroid/gradle/wrapper/gradle-wrapper.properties
A6. Run Capacitor sync
npx cap sync
A7. Verify build
- Open
android/in Android Studio — confirm Gradle sync succeeds - Open
ios/Appin Xcode — confirm pod install succeeds and build compiles
Phase B: Real TSI Barcode Scanning
B1. Install barcode scanning plugin
From frontend/:
npm install @capacitor-mlkit/barcode-scanning@^8.1.0
npm install barcode-detector # web polyfill for PWA browser fallback
From root:
npx cap sync
Plugin: @capacitor-mlkit/barcode-scanning v8.1.0 — Google ML Kit engine, 91K+ weekly npm downloads, supports Code 128 (TSI physical card barcode) and QR Code (virtual TSI card).
B2. Native manifest verification (no changes expected)
| Platform | File | Required | Status |
|---|---|---|---|
| Android | AndroidManifest.xml:44 |
CAMERA permission |
Already present |
| iOS | Info.plist:52-53 |
NSCameraUsageDescription |
Already present |
B3. Rewrite frontend/src/views/ScannerView.jsx
Remove:
MOCK_TSI_CARDSarray and all mock card state/UInavigator.mediaDevices.getUserMedia()camera logic (lines 40-73)- Auto-scan
setTimeoutsimulation (lines 98-105) - Simulated scan fallback panel (lines 170-198)
selectedMockCardstate
Add:
- Import
BarcodeScanner,BarcodeFormat,LensFacingfrom@capacitor-mlkit/barcode-scanning - Import
Capacitorfrom@capacitor/core(platform detection) - Import
barcode-detector/polyfillat top (web fallback)
New scan flow:
1. Component mounts → show "Start Scanning" button + manual CIP input
2. User taps "Start Scanning":
a. Check BarcodeScanner.isSupported() → error if not
b. Check/request camera permission via BarcodeScanner.checkPermissions() / requestPermissions()
c. Call BarcodeScanner.scan({ formats: [BarcodeFormat.Code128, BarcodeFormat.QrCode], autoZoom: true })
d. Extract barcodes[0].rawValue (NOTE: can be undefined per v8 breaking change — handle gracefully)
e. Validate CIP format: /^[A-Z0-9]{16}$/i
f. If valid → fetchPrescriptions(cip) → show prescriptions
g. If invalid → show error "Invalid card barcode. Try manual entry."
3. Manual CIP input:
- Text input field with placeholder "Enter CIP code manually"
- "Submit" button → validates format → fetchPrescriptions(cip)
4. PWA/browser fallback:
- Detect: !Capacitor.isNativePlatform()
- Show message: "Barcode scanning requires the mobile app. Enter your CIP code manually below."
- Show only the manual CIP input (no scan button)
Phases (simplified):
idle— initial state, scan button + manual input visiblescanning— ML Kit native UI active (camera takes over)prescriptions— results display (keep existing prescription card UI)error— permission denied / unsupported / invalid barcode
Keep unchanged:
playBeep()functionfetchPrescriptions(cip)functionhandlePickPrescription(rx)functionhandleBack()function- Prescription display UI (lines 201-249)
onSelectMedicinecallback prop
B4. Rewrite frontend/src/views/ScannerView.css
Remove:
.scanner-viewport-wrap,.scanner-camera-container,.scanner-video,.scanner-frame,.scanner-laser,.scanner-hint(old camera overlay).scanner-simulate-panel,.mock-cards-list,.mock-card-btn,.simulate-scan-btn,.simulate-label,.mock-card-icon,.mock-card-info(mock card panel).scanner-placeholderwith spinner (old loading state)
Add:
.scan-start-btn— large centered button with camera icon, teal background (#0f766e), full-width.manual-cip-section— input group with text field + submit button.cip-input— text input styled to match existing dark theme, monospace font.cip-submit-btn— teal button matching scan button style.pwa-notice— info banner for browser users.scan-error-panel— error state with icon and retry button
B5. No changes to other files
HomeView.jsx— "Scan TSI Card" button still navigates to ScannerViewPublicView.jsx— screen routing andonSelectMedicinehandoff unchangedbackend/server.js— user handles/api/tsi/:cip/prescriptionscapacitor.config.json— no scanner-specific config needed
Files Modified (summary)
| File | Phase | Change |
|---|---|---|
package.json |
A1 | Bump all @capacitor/* to ^8.x |
frontend/package.json |
B1 | Add @capacitor-mlkit/barcode-scanning@^8.1.0 + barcode-detector |
android/variables.gradle |
A2 | Update all 13 SDK/library versions |
ios/App/Podfile |
A3 | iOS deployment target 13.0 → 15.0 |
android/app/src/main/AndroidManifest.xml |
A4 | Add density to configChanges |
android/build.gradle |
A5 | AGP 8.2.1 → 8.13.0, Google Services 4.4.0 → 4.4.4 |
android/gradle/wrapper/gradle-wrapper.properties |
A5 | Gradle wrapper → 8.14.3 |
frontend/src/views/ScannerView.jsx |
B3 | Full rewrite — real barcode scanning + manual input |
frontend/src/views/ScannerView.css |
B4 | Remove old camera/mock styles, add new scan UI |
Known Issues
- Android NullPointerException bug (GitHub capawesome-team/capacitor-mlkit #160/#324) — affects
startScan()in v8.0.1. Workaround: usescan()method (built-in native UI) instead ofstartScan()(custom WebView mode). Plan usesscan(), so this shouldn't hit us. rawValuecan be undefined in v8.x — handle with null check before CIP validation.- Capacitor 8 requires Xcode 26+ — must have latest Xcode installed.
- Gradle 8.14.3 requires JDK 21+ — confirm JDK 21 is available.
@capacitor-mlkit/barcode-scanningv6.x.x is deprecated — this is why we upgrade to Capacitor 8 first (v8.x.x plugin requires Cap 8).
Implementation Order
| Step | Phase | Estimated Time |
|---|---|---|
| A1-A6 | Capacitor upgrade | ~30 min |
| A7 | Verify build (Android + iOS) | ~30 min |
| B1 | Install barcode plugin | ~5 min |
| B3 | Rewrite ScannerView.jsx | ~2 hrs |
| B4 | Update ScannerView.css | ~30 min |
| B5 | Test on Android device | ~30 min |
| B5 | Test on iOS device | ~30 min |
Total: ~4-5 hours