# Photo Print Customization — High-Level Technical Document

## Context

This document explains the **Photo Print customization** feature located at
`angular/src/app/customization/photoprint/`. It is a read-only walkthrough of
what the feature does and how it works, produced so you can verify your
understanding against the actual code on the `main` branch. No code changes are
proposed.

## Component overview

| File | Role |
|------|------|
| `photoprint.component.ts` (~1680 lines) | All logic: upload, canvas creation, sizing, pricing, quantity, edit modal, cart data prep |
| `photoprint.component.html` | Upload UI, QR-code modal, and the image-edit modal (filters/effects/crop/flip) |
| `photoprint.component.scss` | (empty) |
| `photoprint.component.spec.ts` | Default Angular spec |

- Selector is an **attribute** selector: `selector: '[photoprint]'` — mounted as `<div photoprint></div>` in `app.component.html` (declared in `app.module.ts`), not routed. It is conditionally shown when the loaded product's `designerProductType === 'Photoprint'`.
- No `@Output()`s — the component talks outward only via the pub/sub event bus and shared service state.

## What the feature does (functionality)

1. **Image upload** — file picker + drag-and-drop, plus social-media / "my images" / QR-code-to-phone upload. Validates extension (config-driven allowed list, e.g. jpg/png/pdf/ai/eps) and min/max file size. Optional "upload agreement" checkbox gate before uploading.
2. **Per-image canvas** — each uploaded photo becomes its own Fabric.js canvas rendered as an `<li>` in `#canvasContainer`. Canvas shows the image with the chosen size.
3. **Per-image configuration** — for every canvas the user sets:
   - **Print size** (dropdown from server-fetched sizes, each with a price)
   - **Custom option / material** (dropdown from product custom options, each option can add price)
   - **Quantity** (– / number / + stepper)
4. **Per-image actions** — Duplicate, Edit, Delete (`createPrintAction`).
5. **Image editing modal** — double-click a canvas opens a modal (`#photoprintImage`) with filters, effects, opacity, crop, and flip tools; prev/next navigation across images.
6. **Live pricing** — total price and total quantity recomputed on any size/option/qty change and broadcast for the price bar.
7. **Add-more-photos** — button scrolls back to the uploader to add more.

## How it works (data & control flow)

### Initialization
- `ngOnInit` (`photoprint.component.ts:132`): `fetchimagesizes()`, subscribes to events, applies image config, and for non-admin polls `getProjectIdImages()` every 10s.
- `fetchimagesizes()` (`:152`): `GET photoprint/getimagesizes` via `mainService.getData`; flattens response into `canvasService.imageSizes` as `{image_id, image_height, image_width, image_price}`.
- Backend endpoints used across the feature: `photoprint/getimagesizes` (sizes+prices), `productdesigner/upload` (POST image), `productdesigner/delete`, `productdesigner/getcustomerimages` (logged-in library), `customization/getprojectidcustomerimages` (poll for phone/QR uploads), `customization/generateimageqrcode`.
- `setImageConfiguration()` (`:195`): pulls upload limits, allowed extensions, min/max size, and the confirmation-agreement text from `mainService.imgConfig`.

### Upload pipeline
- `drop()` (`:268`) handles both file-input change and drag-drop; enforces the agreement checkbox (`checkConfirmation()`), routes zip vs. image.
- `processImage()` (`:314`) recursively iterates the file list, validates extension and size, then:
  - vector/raster special types (ai/pdf/eps/svg/heic…) → uploaded as-is
  - normal raster → converted via `mainService.imageToDataUri`, given a unique id, pushed to `canvasService.uploadFile`, then uploaded (`imageUploadProcess`).

### Canvas + state model
- Central state: `canvasData` — a map keyed by canvas id (`photoprintCanvas-<index>`) holding `{ imageSize, customOption, customOptionName, quantity }` (`:28`).
- Canvases live in `fabricCanvases[]`; image objects in `imageObjects[]`.
- `createDropdown` (sizes), `createCustomOptionDiv` (`:1393`), `createInputQty` (`:1460`), `createPrintAction` (`:882`) build the per-canvas DOM controls imperatively and wire their change handlers to update `canvasData[canvasId]` and recalc price.
- `duplicateCanvas` (~`:1020`) clones the Fabric canvas, its objects, and filters; inserts a new `<li>` and copies the source canvas's config.
- `deleteCanvas` (`:827`) disposes the Fabric canvas, removes the DOM node, and re-indexes all remaining canvas ids and `canvasData`.

### Pricing
- `fetchImageSizesPriceCalc(size, canvasId)` (`:1610`): sets the canvas's size, then sums across all canvases:
  `finalPrice += (imagePrice + customOptionPrice) * quantity` and totals quantity.
- Custom-option price is parsed from a `₹`-prefixed string.
- Results written to `priceService.photoPrintPrice` / `photoPrintTotalQTY`; `photoPrintPrice` event published to refresh the UI price bar.
- It also snapshots state into `canvasService.photoprintcanvascontainer` (each item = canvasData entry + its fabricCanvas).

### Save / add-to-cart integration
- `designer.service.ts:947-975`: when `designerProductType === 'Photoprint'`, the save flow reads `canvasService.photoprintcanvascontainer` and builds:
  - `containerCanvasesJson` (fabricCanvas + imagesize + qty + customOption)
  - `photoprintDetails` — per-image `{ size: "HxW", customOption, customOptionName, quantity, SizePrice, TotalPrice }`
- `photoprintDetails` is sent in the save params (`designer.service.ts:1038`), which is how the per-photo configuration reaches the backend / cart.
- `override-cart.component.ts:62` subscribes to `photoprintOpenModal` to reopen the editor from cart.

## Key dependencies
- **Fabric.js** (`fabric`) — per-image canvases, cloning, rendering.
- **ngx-bootstrap** `BsModalService` — QR and edit modals.
- **SweetAlert2** — validation alerts.
- **@pscoped/ngx-pub-sub** — event bus (`photoPrintPrice`, `UploadDropImage`, `customerLoggedIn`, etc.).
- Shared services: `MainService`, `CanvasService`, `PriceService`, `CustomOptionsService`, `ImageEffectsService`, `LayoutsService`.

## How to verify
1. Open a product configured as `Photoprint`; confirm the upload panel renders (attribute directive `[photoprint]`).
2. Upload several images → each appears as its own canvas tile with Size / Option / Qty controls.
3. Change size, option, and quantity → confirm the total price/qty updates live (driven by `fetchImageSizesPriceCalc` + `photoPrintPrice` event).
4. Test Duplicate / Edit (double-click modal: filters, crop, flip) / Delete and re-check indexing and price.
5. Add to cart / save → inspect the save payload for `photoprintDetails` (`designer.service.ts:1038`) and confirm sizes, options, quantities, and prices match the UI.

> Note: This is a documentation/verification task. If you'd like, I can also produce this as a shareable visual Artifact or expand any section (e.g. the edit-modal effects pipeline).
