99 lines
4.2 KiB
Markdown
99 lines
4.2 KiB
Markdown
---
|
|
task: Fix "Similar products already exist" modal layout — match-row cards unreadable on mobile (flex row squishes info text to single characters, Import button overlaps content)
|
|
cycles: 5
|
|
context: true
|
|
private: false
|
|
started: 2026-05-28T16:30:42Z
|
|
finished: 2026-05-28T16:31:11Z
|
|
---
|
|
|
|
## files
|
|
- resources/js/Pages/CreateProductUltimate.vue [lines 534-560] — fuzzy match modal template: `.match-row` items with thumb, info, button
|
|
- resources/js/Pages/CreateProductUltimate.vue [lines 875-914] — scoped CSS: `.match-row`, `.match-thumb`, `.match-info` and dark mode overrides
|
|
|
|
## steps
|
|
1. In `CreateProductUltimate.vue` template (lines 534-560), wrap the `FileImage` + `.match-info` div in a new `<div class="match-row-top">` inner wrapper, leaving the `<button>` outside it so the layout becomes: outer `.match-row` (column) → `.match-row-top` (thumb + info, row) + button (full-width, below)
|
|
2. Add `w-100` class to the Import button so it spans the full card width on mobile
|
|
3. In the scoped CSS, change `.match-row` from `align-items: center` flex-row to a `flex-direction: column; gap: 10px` column layout. Add `.match-row-top { display: flex; align-items: center; gap: 12px; }` rule.
|
|
4. Remove `align-items: center` from `.match-row` (it now stacks vertically, not horizontally)
|
|
5. Verify `.match-info { flex: 1; min-width: 0; }` stays on `.match-info` (unchanged — still needed inside `.match-row-top`)
|
|
6. Build: `npm run build` then `docker restart bukidbountyapp`
|
|
|
|
## context
|
|
|
|
Current template structure (lines 534-560):
|
|
```html
|
|
<div v-for="m in fuzzyMatches" :key="m.hashkey" class="match-row">
|
|
<FileImage :src="..." class="match-thumb" fallback="..." />
|
|
<div class="match-info">
|
|
<div class="fw_6">{{ m.name }}</div>
|
|
<div class="text-muted small">
|
|
<span v-if="m.category">{{ m.category }}<span v-if="m.subcategory"> · {{ m.subcategory }}</span> · </span>
|
|
<span>₱{{ m.price }} / {{ m.unitname }}</span>
|
|
</div>
|
|
<div v-if="m.already_in_store" class="text-success smallest mt-1">...</div>
|
|
</div>
|
|
<button class="btn btn-sm btn-primary rounded-pill" :disabled="m.already_in_store || isImporting" @click="importExistingProduct(m)">
|
|
<span v-if="isImporting"><LoadingSpinner size="small" /></span>
|
|
<span v-else-if="m.already_in_store">In Store</span>
|
|
<span v-else>Import to Store</span>
|
|
</button>
|
|
</div>
|
|
```
|
|
|
|
Target template structure:
|
|
```html
|
|
<div v-for="m in fuzzyMatches" :key="m.hashkey" class="match-row">
|
|
<div class="match-row-top">
|
|
<FileImage :src="..." class="match-thumb" fallback="..." />
|
|
<div class="match-info">
|
|
<div class="fw_6">{{ m.name }}</div>
|
|
<div class="text-muted small">
|
|
<span v-if="m.category">{{ m.category }}<span v-if="m.subcategory"> · {{ m.subcategory }}</span> · </span>
|
|
<span>₱{{ m.price }} / {{ m.unitname }}</span>
|
|
</div>
|
|
<div v-if="m.already_in_store" class="text-success smallest mt-1">...</div>
|
|
</div>
|
|
</div>
|
|
<button class="btn btn-sm btn-primary rounded-pill w-100" :disabled="m.already_in_store || isImporting" @click="importExistingProduct(m)">
|
|
...
|
|
</button>
|
|
</div>
|
|
```
|
|
|
|
Current CSS (lines 875-890):
|
|
```css
|
|
.match-row {
|
|
display: flex;
|
|
align-items: center; /* ← causes single-column squish when button competes for width */
|
|
gap: 12px;
|
|
padding: 12px 0;
|
|
border-bottom: 1px solid #f1f5f9;
|
|
}
|
|
.match-thumb { width: 56px; height: 56px; border-radius: 10px; object-fit: cover; flex-shrink: 0; }
|
|
.match-info { flex: 1; min-width: 0; }
|
|
```
|
|
|
|
Target CSS additions/changes:
|
|
```css
|
|
.match-row {
|
|
display: flex;
|
|
flex-direction: column; /* vertical stack: top-row then button */
|
|
gap: 10px;
|
|
padding: 12px 0;
|
|
border-bottom: 1px solid #f1f5f9;
|
|
}
|
|
.match-row-top {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
}
|
|
/* .match-thumb and .match-info stay unchanged */
|
|
```
|
|
|
|
## notes
|
|
- dictionary: ai-docs/dictionary.md
|
|
- linters: none
|
|
- constraints: `.bb-modal*` styles are scoped to `CreateProductUltimate.vue` — do NOT touch global CSS. Dark mode override `:global(.dark-mode) .match-row` at line 914 only sets `border-bottom-color` — no changes needed there.
|
|
- build: `npm run build` then `docker restart bukidbountyapp` (see dictionary Build & Deployment Standards)
|