Partner Cover Image Self-Serve — Frontend Spec (Rough Draft)
Companion to
Partner_Cover_Image_SelfServe_20260909000000.md(the product PRD). This document captures the frontend side of the feature in book-bite (partner portal). Updated Sep 09, 2026 with the actual Figma design.
| Owner | Frontend (book-bite — partner portal) |
| PRD | Partner_Cover_Image_SelfServe_20260909000000.md |
| Design | Figma — Add: Package Image Self-Service |
| Glossary | Glossary in PM PRD |
| Status | Rough draft — to be grilled by FE team. Design covers cover-image flows only; menu-item image edit (Flow 2) has no design yet. |
1. Scope
In scope (this spec)
- Flow 1 — Cover image Add/Edit/Remove UI on the Main Package list (design covers this)
- Flow 4 — Toggle / edit-other-fields permission-driven controls (read
can_toggle/can_edit_other_fieldsfrom backend) - Flow 5 — “Created by Admin” badge + tooltip on package list rows
Design gap (no Figma yet)
- Flow 2 — Menu item image edit UI on package Menu tab — no design. FE needs a follow-up screen before building this. Do not start until design lands.
Out of scope
- Diner-facing changes (not applicable — partner-portal only)
- The existing whole-package edit flow (Flow 3) — stays unchanged
2. Component Strategy (from Figma)
2.1 Package List row action (Flow 1 entry point)
The design puts the entry point on the Main Package list table, as a row action, alongside View Menu / Print Menu / Edit Package.
| Row condition | Action label shown |
|---|---|
| Package has a cover image | Edit Cover Image |
| Package has no cover image | Add Cover Image |
| Status is Pending Review | Row shows no image/edit actions (View Menu + Print Menu only) |
| Status is Rejected | Row shows no image/edit actions (View Menu + Print Menu only) |
Confirm with FE/PM: per PRD text, the affordance should also exist on the package detail screen. Design only covers the list row. Determine whether detail screen gets it too, and whether it reuses the same modal.
2.2 Add/Edit Cover Image modal
Single shared modal, titled by state:
- “Add Cover Image” (no image yet)
- “Edit Cover Image” (image present)
Contents (from Figma):
| Element | Design |
|---|---|
| Field label | Cover Image for Marketing (Optional) |
| Dropzone (empty) | “Drop image here or click to upload” — light blue bg rgba(241,248,255,1) |
| Image present | “Change Image” (white text over image — fix designer camelCase “change Image”) + “Remove image” link (red rgba(223,37,42,1)) |
| Helper text | “Recommended dimensions: 420x240px (Max size: 10 MB)” |
| Buttons | Cancel (white bg, radius 5) · Save (red gradient rgba(223,37,42,1)→rgba(162,0,4,1); gray rgba(222,226,228,1) when disabled) |
| Save disabled | Until an image is selected (drawn disabled in 4 of 7 design copies — confirm intended rule) |
2.3 Remove image confirm modal
“Remove image” opens a confirm:
| Element | Design |
|---|---|
| Question | “Are you sure you want to remove this cover image?” (red) |
| Buttons | Back (white bg) · Remove (red gradient) |
Design wobble: the mock reuses a “Reject this booking” component — cosmetic only, build it fresh.
2.4 Success toast
“Great success!” / “Your cover image is updated.” (with smiley + close icon).
2.5 Error states (inline on the modal)
| Error | Copy |
|---|---|
| File too large | “File too large (Max 10MB). Please upload a smaller image.” |
| Unsupported format | “Unsupported format. Please upload a supported image (JPEG, JPG, PNG, HEIC, TIFF, WEBP).” |
| Upload failed | “Upload failed. Please check your file or network, then try again.” |
2.6 “Created by Admin” badge (Flow 5)
- Renders on the package list row only (never on menu-item cards).
- Hover tooltip: “This package was set up by the Hungry Hub team. You can still update its photo — turning it on/off or changing its other details isn’t available here. Contact your Account Manager if you need those changed.”
2.7 Proposed structure
Rough draft — exact placement TBD. The modal + badge are the two genuinely new components.
src/pages/packages/
├── MainPackageList.vue # existing — add row action buttons + badge
├── components/
│ ├── CoverImageModal.vue # NEW: Add/Edit/Remove cover image (single shared modal)
│ ├── RemoveCoverImageModal.vue# NEW: confirm "Are you sure..." (or folded into CoverImageModal)
│ ├── AdminBadge.vue # NEW: "Created by Admin" + tooltip
│ └── (reuse) existing image uploader widget from package creation
3. State Machines
Cover image modal (Flow 1)
[ idle ] package list, image action visible (status Active/Inactive)
│ tap "Add Cover Image" / "Edit Cover Image"
▼
[ modal_open ]
├─ no image yet → [ selecting / dropzone ]
├─ image present → [ change_image / remove_image ]
│ │ pick/change image
│ ▼
│ [ validating ] ← client-side: ≤10MB, {jpeg,jpg,png,heic,tif,tiff,webp}
│ │ pass
│ ▼
│ [ preview_ready ] ← Save enabled
│ │ error
│ ▼
│ [ inline_error ] ← retry, Save stays disabled
▼
[ saving ] ← Save tapped, backend pending
│ success
▼
[ success ] ← toast "Great success! / Your cover image is updated." + close modal, row updated
│
▼
[ idle ]
Remove path:
[ modal_open ] → "Remove image" → [ confirm_modal ] → Remove → [ removing ] → success → [ idle ]
4. Form Behavior & Validation
Cover image rules (client mirrors server; server is authority)
| Field | Rule | Error message |
|---|---|---|
| Cover image | ≤ 10MB | File too large (Max 10MB). Please upload a smaller image. |
| Format | {jpeg, jpg, png, heic, tif, tiff, webp} | Unsupported format. Please upload a supported image (JPEG, JPG, PNG, HEIC, TIFF, WEBP). |
| Network/upload failure | — | Upload failed. Please check your file or network, then try again. |
| Not owned by restaurant | 403 → generic error | (shouldn’t happen — UI only lists own packages) |
Menu item image rules (Flow 2 — design pending, note the format difference)
| Field | Rule | Error message |
|---|---|---|
| Menu item image | ≤ 10MB | File too large (Max 10MB). Please upload a smaller file. |
| Format | {jpg, jpeg, png, pdf, heic} — differs from cover (allows PDF, no tif/tiff/webp) | Unsupported format. Please upload a supported file (JPG, JPEG, PNG, PDF, HEIC). |
Don’t reuse the cover-image format list for menu images — they differ on purpose. Confirm which shared uploader/constant to use at implementation time.
5. Analytics Events (v1)
| Event | When fired | Payload |
|---|---|---|
partner_cover_image_updated | Successful cover image change (after backend confirms) | restaurant_id, package_id, package_type, created_by_admin |
partner_cover_image_removed | Successful cover image removal (after backend confirms) | restaurant_id, package_id, package_type, created_by_admin |
partner_menu_image_updated | Successful menu item image update (Flow 2, after backend confirms) | restaurant_id, package_id, package_menu_id, created_by_admin |
partner_created_by_admin_badge_viewed | Partner views a package with the badge (hover) | restaurant_id, package_id, package_type |
6. i18n — Copy + Keys
Rough draft — Localization to fill TH/SG/MY. Copied verbatim from Figma design.
| Key | EN |
|---|---|
partnerCoverImage.rowAction.edit | Edit Cover Image |
partnerCoverImage.rowAction.add | Add Cover Image |
partnerCoverImage.modal.title.edit | Edit Cover Image |
partnerCoverImage.modal.title.add | Add Cover Image |
partnerCoverImage.modal.fieldLabel | Cover Image for Marketing (Optional) |
partnerCoverImage.modal.dropzone | Drop image here or click to upload |
partnerCoverImage.modal.changeImage | Change Image |
partnerCoverImage.modal.removeImage | Remove image |
partnerCoverImage.modal.helper | Recommended dimensions: 420x240px (Max size: 10 MB) |
partnerCoverImage.modal.save | Save |
partnerCoverImage.modal.cancel | Cancel |
partnerCoverImage.removeConfirm.title | Are you sure you want to remove this cover image? |
partnerCoverImage.removeConfirm.back | Back |
partnerCoverImage.removeConfirm.remove | Remove |
partnerCoverImage.success.title | Great success! |
partnerCoverImage.success.body | Your cover image is updated. |
partnerCoverImage.error.fileTooLarge | File too large (Max 10MB). Please upload a smaller image. |
partnerCoverImage.error.unsupportedFormat | Unsupported format. Please upload a supported image (JPEG, JPG, PNG, HEIC, TIFF, WEBP). |
partnerCoverImage.error.uploadFailed | Upload failed. Please check your file or network, then try again. |
partnerMenuImage.edit | Edit Photo |
partnerMenuImage.success | Menu photo updated. |
partnerMenuImage.error.fileTooLarge | File too large (Max 10MB). Please upload a smaller file. |
partnerMenuImage.error.unsupportedFormat | Unsupported format. Please upload a supported file (JPG, JPEG, PNG, PDF, HEIC). |
partnerAdminBadge.label | Created by Admin |
partnerAdminBadge.tooltip | This package was set up by the Hungry Hub team. You can still update its photo — turning it on/off or changing its other details isn’t available here. Contact your Account Manager if you need those changed. |
partnerPackage.toggleBlocked | This package was created by Admin and can’t be turned on/off here. |
partnerPackage.editBlocked | This package was created by Admin, only the Hungry Hub team can update its other details here. |
7. Open Questions for FE Team
These are the branches worth re-grilling once implementation begins:
- Menu-item image edit (Flow 2) — no Figma design. Blocked on design; don’t build UI until it lands.
- Detail-screen entry point — design only shows list row action; PRD mentions detail screen. Confirm whether both.
- Save disabled rule — design draws Save gray in 4 of 7 modal copies. Is Save disabled until a new image is selected, or only while uploading? (Note: in Edit mode with an image present, is Save re-enabled on any change?)
- Remove flow scope — is removing the cover image in v1, or only add/edit? Design includes it; confirm.
- Existing image-uploader reuse — confirm exact props/events of the package-creation uploader before reusing in the modal.
- Badge placement — badge sits on the list row in the design; does the detail screen also show it?
- Concurrent edit handling — optimistic update or wait for confirmation?
- Pagination/list API — does the list response include
has_cover_image(to choose Add vs Edit label) or does the row need the raw image URL?
8. Test Strategy (FE-side, rough)
- Component tests: modal open (add vs edit title), dropzone, change image, remove-image confirm flow, validation errors (size/format), Save disabled state, success toast, badge render + tooltip, row-action visibility by status (Active/Inactive show; Pending Review/Rejected hide).
- E2E tests: add → save → toast → row updated; edit → save; remove → confirm → row label returns to “Add Cover Image”; Pending Review / Rejected rows show no image action.
- Visual regression (if set up): modal empty / image-present / error states.
This section is rough — QA team to refine with full test matrix (see QA spec).