From 4c5aafe591ca42c6b6e2997abe4db61f34a28c18 Mon Sep 17 00:00:00 2001 From: trent Date: Wed, 12 Aug 2026 05:45:12 +0800 Subject: [PATCH] Fix responsiveness --- PlayWrightAsStyleQA.md | 32 ++++++ QATesting.md | 84 ++++++++++++++ .../src/__tests__/views/IntakeView.test.ts | 2 +- .../src/__tests__/views/UsersView.test.ts | 10 +- vigilcare-records-web/src/assets/main.css | 11 +- .../src/components/AppHeader.vue | 26 ++++- .../src/components/AppShell.vue | 107 ++++++++++++++---- .../src/components/ApprovalForm.vue | 18 +-- .../src/components/BatchList.vue | 2 +- .../src/components/EntryForm.vue | 2 +- .../src/components/ObservationRow.vue | 55 +++++---- .../src/components/ScanViewer.vue | 4 +- .../src/components/VerificationForm.vue | 36 +++++- .../src/components/WorkstationActionBar.vue | 10 +- vigilcare-records-web/src/stores/batches.ts | 12 +- vigilcare-records-web/src/types/index.ts | 4 + .../src/views/ApprovalView.vue | 4 +- .../src/views/CoverSheetView.vue | 14 +-- vigilcare-records-web/src/views/EntryView.vue | 4 +- .../src/views/FhirExplorerView.vue | 14 +-- .../src/views/IntakeView.vue | 14 +-- .../src/views/LiveCaptureView.vue | 14 +-- vigilcare-records-web/src/views/LoginView.vue | 14 +-- .../src/views/PatientHistoryView.vue | 14 +-- .../src/views/QueueDashboardView.vue | 44 +++---- vigilcare-records-web/src/views/UsersView.vue | 36 +++--- .../src/views/VerificationView.vue | 13 ++- 27 files changed, 414 insertions(+), 186 deletions(-) create mode 100644 PlayWrightAsStyleQA.md create mode 100644 QATesting.md diff --git a/PlayWrightAsStyleQA.md b/PlayWrightAsStyleQA.md new file mode 100644 index 0000000..88c6c3d --- /dev/null +++ b/PlayWrightAsStyleQA.md @@ -0,0 +1,32 @@ +Use Playwright MCP as a visual QA and frontend polish tool for this page. + +Inspect the page at mobile, tablet, and desktop breakpoints, identify styling/layout issues, and fix them directly in the code. + +Focus on: +- spacing +- sizing +- alignment +- element positions +- typography scaling +- card proportions +- image/text balance +- overflow/clipping +- responsiveness + +Requirements: +- keep Tailwind CSS +- preserve the current design intent +- improve the page until it looks polished and production-ready +- verify each fix visually with Playwright MCP +- iterate until no obvious visual issues remain + + +Test at: +- 375x812 +- 768x1024 +- 1280x800 + +Use VigilCareRecordsAPI/Data/Seed/DataSeeder.cs to get the logins + +Do not only report problems. +Make the fixes, re-test, and then provide a short summary of what was improved. \ No newline at end of file diff --git a/QATesting.md b/QATesting.md new file mode 100644 index 0000000..cfd2781 --- /dev/null +++ b/QATesting.md @@ -0,0 +1,84 @@ +Here's the updated prompt: + +--- + +## Role +Act as a senior QA engineer testing a Vue 3 + Node.js web application for logic errors, bugs, and edge cases. + +## Output Format +A plain text report of all issues found, grouped by file or feature domain, with severity level per issue (Critical / High / Medium / Low). + +## Goal +Test the provided functionality, section, or domain by reading the code and mentally executing it across normal, boundary, and failure scenarios. Report every defect found. When testing a view or feature, trace execution downward through all underlying components, composables, and backend routes and controllers that the feature depends on. + +## Grounding Rules +- Stay within the confines of the provided code — do not invent features, routes, or behaviors that are not present. +- Do not hallucinate API responses, database states, or UI interactions not inferable from the code. +- Do not suggest third-party testing tools or libraries unless already present in the codebase. +- If a behavior is ambiguous, flag it as a question rather than assuming intent. +- When a view or component calls a composable, follow that composable's logic as part of the same test pass. +- When a composable or service makes an API call, follow the corresponding backend route, middleware, and controller as part of the same test pass. + +## Instructions +Test each provided file or domain in this order of priority: + +1. **Logic correctness** — Does the code do what it is clearly intended to do? +2. **Edge cases** — Empty inputs, null/undefined values, empty arrays, zero, negative numbers, max-length strings, concurrent calls. +3. **Error handling** — Are errors caught? Are failure states handled gracefully? Do error messages leak sensitive data? +4. **Reactivity correctness** (frontend) — Does state update when it should? Can stale state be observed? +5. **Data flow** — Are values passed, transformed, or mutated in ways that could produce unexpected results downstream? Trace data from the frontend input all the way to the database query and back. +6. **Boundary conditions** — Off-by-one errors, pagination limits, permission boundaries, rate limits. +7. **Race conditions** — Async operations that could resolve out of order or leave state inconsistent. +8. **Contract mismatches** — Does the frontend expect a response shape the backend does not guarantee? Are required fields missing, optional fields assumed present, or error codes unhandled? +9. **Login/Auth Requirements** - If auth or login is required use the following credentials email: bradleystorm.sevt@mockinbox.com and password: Password123! + +**Conflict resolution:** If a behavior could be either a bug or an intentional design choice, report it as a flagged ambiguity rather than a confirmed defect. Do not silently assume either way. + +**Priority hierarchy:** Logic correctness > Error handling > Edge cases > Data flow > Contract mismatches > Boundary conditions > Race conditions > Reactivity. + +## Trace Depth +When a file is provided as the entry point for testing, automatically include in scope: +- All composables imported and called by that file +- All child components rendered by that file +- All backend routes, middleware, and controllers called by those composables or services +- All database queries executed by those controllers + +Report issues at the layer where they originate, not just where their effect is observed. + +## Examples + +**Bad output (do not produce this):** +``` +- The login form might have issues. +- Consider adding more validation. +``` + +**Good output (produce this):** +``` +FILE: src/composables/useAuth.js +SEVERITY: Critical +ISSUE: If `refreshToken()` is called while a refresh is already in flight, two concurrent requests are fired. The second response overwrites the token set by the first, leaving the app in a potentially invalid auth state. +REPRODUCTION: Trigger two API calls simultaneously on a near-expired token. +FIX RECOMMENDATION: Guard the refresh call with an in-flight flag or return the existing promise if one is pending. + +FILE: backend/controllers/authController.js +SEVERITY: High +ISSUE: The refresh token is not invalidated after use. A leaked token can be replayed indefinitely until expiry. +REPRODUCTION: Capture the refresh token from a valid session and reuse it after the session has been refreshed. +FIX RECOMMENDATION: Implement refresh token rotation — invalidate the used token and issue a new one on each refresh. +``` + +## Context / Input +Paste files in this order, highest reliability first: +1. Backend routes, middleware, and controllers +2. Composables and services +3. Components and views + +## Final Reminder +- Do not fabricate bugs. Every reported issue must be traceable to a specific line or code path in the provided files. +- Do not skip files because they look simple — shallow files are common sources of silent failures. +- Ambiguity is a valid finding. Flag it rather than resolve it silently. +- Always trace execution through the full stack — frontend to composable to backend to database — before closing a test pass on any feature. + +## Output +Plain text only. No markdown formatting, no bullet symbols, no headers with hashes. Group findings by file. For each issue state: FILE, SEVERITY, ISSUE, REPRODUCTION STEPS, FIX RECOMMENDATION. If a file has no issues, write the filename followed by "No issues found." Restate this format requirement if the session resets mid-task. diff --git a/vigilcare-records-web/src/__tests__/views/IntakeView.test.ts b/vigilcare-records-web/src/__tests__/views/IntakeView.test.ts index 6ccdd67..95daee8 100644 --- a/vigilcare-records-web/src/__tests__/views/IntakeView.test.ts +++ b/vigilcare-records-web/src/__tests__/views/IntakeView.test.ts @@ -98,7 +98,7 @@ describe('IntakeView cover sheet upload', () => { const input = wrapper.find('input[placeholder="VCR-CS-XXXXXXXX"]') expect(wrapper.text()).toContain('Cover Sheet Code') - expect(wrapper.text()).toContain('Upload Scanned Document') + expect(wrapper.text()).toContain('New Batch') expect(wrapper.find('.upload-dropzone').exists()).toBe(true) expect(input.exists()).toBe(true) expect(input.attributes('autofocus')).toBeDefined() diff --git a/vigilcare-records-web/src/__tests__/views/UsersView.test.ts b/vigilcare-records-web/src/__tests__/views/UsersView.test.ts index 34dc313..edc8d01 100644 --- a/vigilcare-records-web/src/__tests__/views/UsersView.test.ts +++ b/vigilcare-records-web/src/__tests__/views/UsersView.test.ts @@ -19,7 +19,15 @@ vi.mock('@/composables/useToast', () => ({ })) vi.mock('@/components/AppHeader.vue', () => ({ - default: { template: '
' }, + default: { + props: ['title', 'description'], + template: ` +
+ + +
+ `, + }, })) vi.mock('@/components/EmptyState.vue', () => ({ diff --git a/vigilcare-records-web/src/assets/main.css b/vigilcare-records-web/src/assets/main.css index 4f1cdf3..09efd55 100644 --- a/vigilcare-records-web/src/assets/main.css +++ b/vigilcare-records-web/src/assets/main.css @@ -60,14 +60,14 @@ @apply p-4 sm:p-6 lg:p-8 max-w-4xl mx-auto; } .app-header { - @apply flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between - px-4 py-3 sm:px-6 h-auto min-h-16 bg-surface border-b border-line; + @apply flex flex-row items-start justify-between gap-3 + px-4 py-3 sm:px-6 sm:items-center min-h-14 sm:min-h-16 bg-surface border-b border-line; } .app-header-title { - @apply flex flex-col gap-2 sm:flex-row sm:items-center sm:gap-4 min-w-0; + @apply flex flex-col gap-1 sm:flex-row sm:items-center sm:gap-4 min-w-0; } .app-header-actions { - @apply flex flex-wrap items-center gap-2 sm:gap-4; + @apply flex flex-wrap items-center justify-end gap-2 sm:gap-4 shrink-0; } .card { @apply bg-surface rounded-card border border-line p-4 sm:p-6 shadow-card; @@ -92,7 +92,8 @@ @apply flex flex-col min-h-0 overflow-hidden bg-surface; } .workstation-scan { - @apply flex flex-col min-h-[40vh] xl:min-h-0 p-3 xl:p-4 bg-canvas border-b xl:border-b-0 xl:border-r border-line; + @apply flex flex-col min-h-[13rem] sm:min-h-[18rem] xl:min-h-0 + p-3 xl:p-4 bg-canvas border-b xl:border-b-0 xl:border-r border-line; } .workstation-form { @apply flex flex-col min-h-0 overflow-hidden bg-surface; diff --git a/vigilcare-records-web/src/components/AppHeader.vue b/vigilcare-records-web/src/components/AppHeader.vue index 4a5b019..0689351 100644 --- a/vigilcare-records-web/src/components/AppHeader.vue +++ b/vigilcare-records-web/src/components/AppHeader.vue @@ -1,15 +1,31 @@ diff --git a/vigilcare-records-web/src/components/AppShell.vue b/vigilcare-records-web/src/components/AppShell.vue index e04cf70..a721461 100644 --- a/vigilcare-records-web/src/components/AppShell.vue +++ b/vigilcare-records-web/src/components/AppShell.vue @@ -1,33 +1,54 @@ \ No newline at end of file + diff --git a/vigilcare-records-web/src/components/ScanViewer.vue b/vigilcare-records-web/src/components/ScanViewer.vue index 10d0479..4abb276 100644 --- a/vigilcare-records-web/src/components/ScanViewer.vue +++ b/vigilcare-records-web/src/components/ScanViewer.vue @@ -5,7 +5,7 @@ >
-
+
@@ -117,7 +118,10 @@ -
+
Encounter Context
@@ -145,11 +149,20 @@
-
+
Observations ({{ observations.length }}) -
+

+ No observations recorded. +

+
fieldReqs.value?.showAllergies ?? false) const showMedications = computed(() => fieldReqs.value?.showMedications ?? false) const showEncounterSummary = computed(() => fieldReqs.value?.showEncounterSummaryFields ?? false) +const showEncounterContext = computed(() => fieldReqs.value?.showEncounterContext ?? false) +const showObservations = computed(() => fieldReqs.value?.showObservations ?? false) + +const enteredByDisplayName = computed(() => { + const name = props.batch?.enteredByUserName?.trim() + if (name) return name + const fromQueue = batchStore.batches.find((b) => b.id === props.batchId) + return fromQueue?.enteredByUserName?.trim() || null +}) watch( () => batchStore.currentDraft, @@ -385,7 +407,7 @@ watch( } } - if (draft.encounter) { + if (draft.encounter && showEncounterContext.value) { encounterFields.value = [ { path: 'encounter.admissionDate', label: 'Admission Date', value: draft.encounter.admissionDate ?? '' }, { path: 'encounter.department', label: 'Department', value: draft.encounter.department ?? '' }, @@ -398,6 +420,12 @@ watch( { path: 'encounter.dischargeDiagnosis', label: 'Discharge Diagnosis', value: draft.encounter.dischargeDiagnosis ?? '' }, ) } + } else { + encounterFields.value = [] + } + + if (!showObservations.value) { + observations.value = [] } fieldChecks.value = {} diff --git a/vigilcare-records-web/src/components/WorkstationActionBar.vue b/vigilcare-records-web/src/components/WorkstationActionBar.vue index c839dd1..bc26e84 100644 --- a/vigilcare-records-web/src/components/WorkstationActionBar.vue +++ b/vigilcare-records-web/src/components/WorkstationActionBar.vue @@ -1,18 +1,18 @@