729 lines
26 KiB
Markdown
729 lines
26 KiB
Markdown
# Handoff
|
|
|
|
Project: `ina-trading-web`
|
|
Current branch: `main`
|
|
Latest verified commit: `f090ba7`
|
|
|
|
## Summary
|
|
|
|
This codebase has recent updates around auth/onboarding, help/privacy pages, dashboard search, product creation/edit/review/detail, admin review/detail, stock/price editing, seller in-review listing, backend request logging, expired-session redirects, product keyword limits, sanitized backend error display, AddProductRequest validation, and 10 MB upload limits.
|
|
|
|
Latest local verification before the newest push:
|
|
|
|
```bash
|
|
npm run build
|
|
```
|
|
|
|
The latest build was verified successfully with:
|
|
|
|
```bash
|
|
npm run build
|
|
```
|
|
|
|
Latest TypeScript verification after the validation/upload changes:
|
|
|
|
```bash
|
|
npx tsc --noEmit
|
|
```
|
|
|
|
## Latest Codex Changes After `4e28ccd`
|
|
|
|
### Admin review image dedupe
|
|
|
|
File:
|
|
- `src/app/admin/review/[productId]/page.tsx`
|
|
|
|
Behavior:
|
|
- Admin product review now deduplicates product images before rendering.
|
|
- The dedupe applies to both:
|
|
- update compare section (`Gambar Produk`)
|
|
- normal admin review gallery (`Galeri`)
|
|
- Root `imageId` / `image` and entries inside `productImages` are merged and sorted by `sequence`.
|
|
- Duplicate images are removed by `imageId`, with URL as a fallback key.
|
|
- This prevents the main image from appearing twice when backend sends it both as root `imageId` and inside `productImages`.
|
|
|
|
Verification:
|
|
|
|
```bash
|
|
npm run build
|
|
```
|
|
|
|
The local production server was restarted on `http://localhost:3000` for manual admin review testing.
|
|
|
|
## Previous Codex Changes After `2cfff02`
|
|
|
|
### Product edit image payload preservation
|
|
|
|
File:
|
|
- `src/app/(dashboard)/products/[productId]/edit/page.tsx`
|
|
|
|
Behavior:
|
|
- Edit-product save keeps `imageId` as the main image field.
|
|
- If the main image already exists inside `productImages`, the save payload preserves it at the same sequence.
|
|
- If the main image is replaced, the old main image entry inside `productImages` is replaced with the new `imageId` at the same sequence.
|
|
- The edit gallery UI hides duplicate thumbnails where `form.imageId` is also present in `form.productImages`, but the underlying array is preserved for payload sequence.
|
|
|
|
Expected image payload shape:
|
|
|
|
```json
|
|
{
|
|
"imageId": "imageBaru.jpg",
|
|
"productImages": [
|
|
{ "imageId": "gallery-0.jpg", "sequence": 1 },
|
|
{ "imageId": "imageBaru.jpg", "sequence": 2 },
|
|
{ "imageId": "gallery-2.jpg", "sequence": 3 }
|
|
]
|
|
}
|
|
```
|
|
|
|
### Product detail image gallery
|
|
|
|
Files:
|
|
- `src/app/(dashboard)/products/[productId]/detail/page.tsx`
|
|
- `src/components/product-variant-showcase.tsx`
|
|
- `src/lib/product-variants.ts`
|
|
|
|
Behavior:
|
|
- Product detail image thumbnails are deduplicated between root `imageId` and `productImages`.
|
|
- Thumbnail strip is horizontally scrollable when there are many images.
|
|
- Clicking a thumbnail updates the large preview image.
|
|
- The active thumbnail receives a visible selected state.
|
|
|
|
### Product submenu click lock fix
|
|
|
|
Files:
|
|
- `src/app/(dashboard)/layout.tsx`
|
|
- `src/app/(dashboard)/products/page.tsx`
|
|
- `src/components/product-submenu-nav.tsx`
|
|
|
|
Behavior:
|
|
- Product submenu items now use Next `<Link>` instead of manual `button` + `router.push`.
|
|
- `All Product` now navigates to `/products?tab=all`, matching the query-based pattern used by the other submenu tabs.
|
|
- Product API already normalizes `tab=all` to the all-product backend endpoint.
|
|
- Sidebar z-index was raised above product modals so submenu clicks are not blocked by stale overlays.
|
|
- Product list clears action-menu and modal state when tab/page changes.
|
|
- Delete/unpublish/stock-price-load errors now close the related modal after showing the error, preventing a full-screen overlay from trapping sidebar clicks.
|
|
|
|
## Latest Codex Changes After `76fb4f3`
|
|
|
|
### Product create preorder and warranty submit rules
|
|
|
|
Files:
|
|
- `src/app/(dashboard)/products/new/details/page.tsx`
|
|
- `src/app/(dashboard)/products/new/specifications/page.tsx`
|
|
- `src/app/(dashboard)/products/new/review/page.tsx`
|
|
- `src/lib/product-draft.tsx`
|
|
- `src/lib/use-product-submit.ts`
|
|
- `src/lib/product-request-validation.ts`
|
|
|
|
Behavior:
|
|
- Pre-order day placeholder is now `0`, not `14`, so an empty/unfilled value is visually obvious.
|
|
- If pre-order is checked, the Details step blocks Next unless `preOrderDay` is a valid number greater than or equal to 1.
|
|
- Warranty now has an On/Off switch in the Specifications step.
|
|
- When warranty is On:
|
|
- warranty type is required
|
|
- warranty duration must be greater than or equal to 1
|
|
- the review page shows warranty information
|
|
- submit payload sends the filled `warrantyInformation` object
|
|
- When warranty is Off:
|
|
- warranty inputs are disabled and dimmed
|
|
- the review page hides warranty information
|
|
- submit payload still sends `warrantyInformation` as an object required by the backend, with:
|
|
|
|
```json
|
|
{
|
|
"type": null,
|
|
"duration": null,
|
|
"durationType": "MONTH"
|
|
}
|
|
```
|
|
|
|
- Frontend payload validation treats the above null-valued warranty object as warranty Off, so it does not block submit with warranty type/duration errors.
|
|
- Local test server was rebuilt and restarted against `https://api-dev.inatrading.co.id` in `.env.local`; `.env.local` is not committed.
|
|
|
|
### AddProductRequest validation
|
|
|
|
Files:
|
|
- `src/lib/product-request-validation.ts`
|
|
- `src/lib/use-product-submit.ts`
|
|
- `src/app/(dashboard)/products/[productId]/edit/page.tsx`
|
|
- `src/app/(dashboard)/products/new/details/page.tsx`
|
|
- `src/app/(dashboard)/products/new/pricing/page.tsx`
|
|
- `src/app/(dashboard)/products/new/specifications/page.tsx`
|
|
- `src/lib/product-draft.tsx`
|
|
|
|
Behavior:
|
|
- Added a shared validator for create/edit product payloads before requests are sent to backend.
|
|
- Validates the backend `AddProductRequest` limits for:
|
|
- basic product fields
|
|
- image/file IDs
|
|
- keywords max 3 and features max 5
|
|
- model fields, currencies, SKU, package fields
|
|
- numeric weight/dimension/package fields max 9 digits plus 1 decimal
|
|
- warehouse IDs max 50 and stock minimal 1
|
|
- measurement fields, measurement warehouses, and measurement stock
|
|
- product/category information param name/value limits
|
|
- compliance information limits
|
|
- warranty type max 50 and duration minimal 1 when warranty is filled
|
|
- Existing wizard drafts normalize keywords to max 3 and features to max 5.
|
|
- Create-product UI now shows visible validation-limit panels on:
|
|
- Details
|
|
- Pricing
|
|
- Specifications
|
|
- Relevant inputs also received direct hints/limits such as max product name length, keyword/feature limits, pre-order minimum, warranty minimum, and upload limit text.
|
|
|
|
### Upload file size limit
|
|
|
|
Files:
|
|
- `src/lib/upload-limits.ts`
|
|
- `src/app/api/upload/route.ts`
|
|
- `src/components/upload-field.tsx`
|
|
- `src/app/(dashboard)/products/new/specifications/page.tsx`
|
|
- `src/app/(dashboard)/products/[productId]/edit/page.tsx`
|
|
- `src/app/(onboarding)/onboarding/business/page.tsx`
|
|
|
|
Behavior:
|
|
- Uploads are limited to 10 MB per file.
|
|
- Client-side checks reject oversized files before upload in shared upload fields, product create/edit document uploads, and onboarding legal document upload.
|
|
- Server-side `/api/upload` rejects oversized files with HTTP `413` and a safe `responseDesc`.
|
|
- User-facing helper text now mentions the 10 MB limit for document uploads.
|
|
|
|
## Previous Codex Changes After `aa406f5`
|
|
|
|
### Backend URL
|
|
|
|
Local `.env.local` now points to:
|
|
|
|
```bash
|
|
NEXT_PUBLIC_API_URL=https://api.inatrading.co.id
|
|
```
|
|
|
|
The previous local value was `https://be.inatrading.co.id`.
|
|
|
|
### Expired session / access denied handling
|
|
|
|
Files:
|
|
- `src/components/auth-session-guard.tsx`
|
|
- `src/app/layout.tsx`
|
|
|
|
Behavior:
|
|
- A global client guard wraps local `/api/*` fetch calls, excluding `/api/auth/*`.
|
|
- If a response is `401`, `403`, or contains auth-style error text such as:
|
|
- `access denied`
|
|
- `unauthorized`
|
|
- `session expired`
|
|
- `token expired`
|
|
- `invalid token`
|
|
- It clears `token` and `role` from `localStorage` and `sessionStorage`, then redirects to `/login`.
|
|
|
|
### Product create keyword limit
|
|
|
|
Files:
|
|
- `src/app/(dashboard)/products/new/details/page.tsx`
|
|
- `src/lib/product-draft.tsx`
|
|
- `src/lib/use-product-submit.ts`
|
|
- `src/lib/translations/id.ts`
|
|
- `src/lib/translations/en.ts`
|
|
|
|
Behavior:
|
|
- Create-product search keywords are limited to 3.
|
|
- The keyword input and add button are disabled after 3 keywords.
|
|
- Existing saved wizard drafts are normalized to a maximum of 3 keywords when loaded from `sessionStorage`.
|
|
- Submit payload uses only the first 3 keywords as a backend guard.
|
|
|
|
### Sanitized backend error display
|
|
|
|
Files:
|
|
- `src/lib/error-message.ts`
|
|
- `src/lib/use-product-submit.ts`
|
|
- `src/components/upload-field.tsx`
|
|
- `src/app/(dashboard)/products/new/review/page.tsx`
|
|
- `src/app/(dashboard)/products/[productId]/edit/page.tsx`
|
|
- plus updated callers across dashboard, admin, settings, onboarding, upload, news, places, categories, and warehouse forms
|
|
|
|
Behavior:
|
|
- Raw JSON request/response error logs are no longer shown to users.
|
|
- `Copy Error Log` UI was removed from create-product review and edit-product save errors.
|
|
- `getBackendErrorMessage()` extracts a user-safe message from:
|
|
- `responseDesc`
|
|
- `message`
|
|
- `error`
|
|
- `details`
|
|
- nested `data`
|
|
- JSON-looking strings are parsed for a useful message; if none is found, the UI falls back to the local generic error.
|
|
- Long text messages are capped to avoid large raw dumps in the UI.
|
|
|
|
### Verification notes
|
|
|
|
- `npx tsc --noEmit` passed after the latest changes.
|
|
- `npm run lint` still has pre-existing unrelated errors in:
|
|
- `src/app/(dashboard)/dashboard/page.tsx`
|
|
- `src/app/(dashboard)/layout.tsx`
|
|
- Local dev server was running at `http://localhost:3000`.
|
|
|
|
## Current Local Changes After `7e6446b`
|
|
|
|
These are the important local changes made after the last recorded commit. The latest local build was verified successfully with `npm run build`, and the production local server was restarted on `http://localhost:3000`.
|
|
|
|
### Admin review compare flow
|
|
|
|
File:
|
|
- `src/app/admin/review/[productId]/page.tsx`
|
|
|
|
Behavior:
|
|
- Product update review now uses the compare API as the source of truth:
|
|
- frontend proxy: `GET /api/admin/review/{productId}/compare`
|
|
- backend: `GET /api/v1.0/product/compare/{productId}`
|
|
- The compare payload is parsed from rows like:
|
|
- `productImages[id=...].image`
|
|
- `productFiles[id=...].fileId`
|
|
- `productModels[sku=...].price`
|
|
- `categoryInformations[paramName=Design].paramValue`
|
|
- `productFeatures[3]`
|
|
- nested objects such as `complianceInformation.safetyWarning`
|
|
- The page reconstructs:
|
|
- `oldProduct` from `oldValue`
|
|
- `newProduct` from `newValue`
|
|
- The compare layout is now section-paired, not product-paired:
|
|
- `Gambar Produk (Diajukan)`
|
|
- `Gambar Produk (Live Saat Ini)`
|
|
- `Detail Produk (Diajukan)`
|
|
- `Detail Produk (Live Saat Ini)`
|
|
- and so on for features, keywords, info, files, models, compliance, warranty
|
|
- Empty section pairs are hidden. If both proposed and live sections have no displayable content, nothing is rendered.
|
|
- `Status` is not shown in the compare `Detail Produk` section and no longer marks the section as updated.
|
|
- Compare image thumbnails are rendered as small square thumbnails with `object-contain`, so images are visible in full instead of cropped into wide banners.
|
|
- Approve/reject for update reviews uses the resolved review/action id from compare, when available.
|
|
|
|
Reference test data:
|
|
- `/Users/wirabasalamah/Downloads/json compare.txt`
|
|
- Example compare API:
|
|
- `/api/v1.0/product/compare/ba70a8e3-2342-4cd3-a7c7-a0f1b58689ab`
|
|
|
|
### Image URL handling
|
|
|
|
Files:
|
|
- `src/lib/image-url.ts`
|
|
- `src/components/product-variant-showcase.tsx`
|
|
- `src/app/(dashboard)/products/[productId]/detail/page.tsx`
|
|
- `src/app/admin/products/[productId]/page.tsx`
|
|
- `src/app/admin/review/[productId]/page.tsx`
|
|
- `src/app/admin/review/page.tsx`
|
|
- `src/app/admin/news/new/page.tsx`
|
|
- `src/app/admin/news/[newsId]/edit/page.tsx`
|
|
- `src/app/admin/places/PlaceForm.tsx`
|
|
|
|
Behavior:
|
|
- Added shared image URL helper:
|
|
- if backend already provides an image URL, use it as-is
|
|
- otherwise build a fallback URL from `imageId`
|
|
- default fallback uses `/api/v1.0/file/image/tmp/{imageId}`
|
|
- Seller/admin product details and admin review now use backend `image` fields before building URLs.
|
|
- Product variant showcase now supports `image` on product images and model images.
|
|
|
|
### Product create/edit thumbnail persistence
|
|
|
|
Files:
|
|
- `src/app/(dashboard)/products/new/details/page.tsx`
|
|
- `src/app/(dashboard)/products/new/pricing/page.tsx`
|
|
- `src/app/(dashboard)/products/new/review/page.tsx`
|
|
- `src/app/api/file/image/[...path]/route.ts`
|
|
|
|
Behavior:
|
|
- Added local API proxy for images:
|
|
- `GET /api/file/image/{path}`
|
|
- forwards to backend `/api/v1.0/file/image/{path}` with auth headers
|
|
- Create product step 2 and step 3 reload thumbnails from saved file ids when navigating forward/back.
|
|
- Create product final review shows real thumbnails for visual identity and model images.
|
|
- Review page was made full width and now displays model image and measurement details more completely.
|
|
|
|
### Product create submit debug logging
|
|
|
|
File:
|
|
- `src/app/api/products/create/route.ts`
|
|
|
|
Behavior:
|
|
- When `DEBUG_BACKEND_PROXY=true`, create product submit writes `product-create-submit-log.json`.
|
|
- The log captures:
|
|
- local endpoint
|
|
- backend endpoint
|
|
- redacted headers
|
|
- full request payload
|
|
- backend response
|
|
|
|
Current known finding from latest capture:
|
|
- Payload sent top-level `imageId` and separate `productImages`.
|
|
- Backend review detail returned top-level `imageId` from `productImages[0]`, not from request top-level `imageId`.
|
|
- Payload sent `productFiles`, but review detail returned `productFiles: []` in the checked response.
|
|
|
|
### Dashboard seller metrics
|
|
|
|
File:
|
|
- `src/app/api/dashboard/seller/route.ts`
|
|
|
|
Behavior:
|
|
- Fixed parsing of scalar metrics from backend payloads where `data` is an object like `{ total: 96 }`.
|
|
- Verified for Pendopo account that dashboard total products can resolve to non-zero.
|
|
|
|
### Admin product list/detail
|
|
|
|
Files:
|
|
- `src/app/admin/products/page.tsx`
|
|
- `src/app/admin/products/[productId]/page.tsx`
|
|
- `src/app/api/admin/products/route.ts`
|
|
|
|
Behavior:
|
|
- Admin product list now renders product thumbnails in `All Product` and `Deleted` tabs.
|
|
- Thumbnail uses the shared image URL helper.
|
|
- Admin product detail now resolves main category by looking up categories/subcategories when backend omits `subCategory.category.name`.
|
|
- Admin All Product endpoint was tested with:
|
|
- `GET /api/v1.0/admin/product?page=1&size=20`
|
|
- Backend returned:
|
|
- HTTP `400`
|
|
- body `{"responseCode":"000001","data":null,"responseDesc":"Bad Request"}`
|
|
- Current proxy behavior:
|
|
- tries `/api/v1.0/admin/product`
|
|
- if non-deleted tab and the admin endpoint fails, falls back to `/api/v1.0/product`
|
|
- Deleted endpoint remains:
|
|
- `GET /api/v1.0/admin/deleted/product?page={page}&size={size}`
|
|
- Server log showed request reached backend with admin token and failed in about 3 ms, suggesting request validation/contract mismatch rather than auth or DB latency.
|
|
|
|
### Seller profile save flow
|
|
|
|
Files:
|
|
- `src/app/(dashboard)/settings/page.tsx`
|
|
- `src/app/api/seller/profile/route.ts`
|
|
|
|
Behavior:
|
|
- Seller profile edit saves via:
|
|
- frontend: `PUT /api/seller/profile`
|
|
- backend: `PUT /api/v1.0/seller/store`
|
|
- Payload:
|
|
- `storeName`
|
|
- `storeBiography`
|
|
- optional `imageId` when seller avatar was uploaded
|
|
- optional `storeImageId` when store image was uploaded
|
|
|
|
Example payload:
|
|
|
|
```json
|
|
{
|
|
"storeName": "...",
|
|
"storeBiography": "...",
|
|
"imageId": "optional-file-id",
|
|
"storeImageId": "optional-file-id"
|
|
}
|
|
```
|
|
|
|
## Recent Commits
|
|
|
|
- `7e6446b` `Refine seller onboarding and product review flows`
|
|
- `e9a0cd0` `Update product review, measurement, and backend logging flows`
|
|
- `b266047` `Fix TypeScript build errors in product detail and admin review`
|
|
|
|
## Main Changes
|
|
|
|
### 1. Auth, help, and onboarding
|
|
|
|
Files:
|
|
- `next.config.ts`
|
|
- `src/app/(onboarding)/layout.tsx`
|
|
- `src/app/(auth)/login/page.tsx`
|
|
- `src/app/(auth)/register/verify/page.tsx`
|
|
- `src/app/(auth)/forgot-password/page.tsx`
|
|
- `src/app/(auth)/account-not-found/page.tsx`
|
|
- `src/app/help/page.tsx`
|
|
- `src/app/privacy/page.tsx`
|
|
- `src/app/terms/page.tsx`
|
|
|
|
Behavior:
|
|
- Seller onboarding is enabled again
|
|
- Seller login redirects incomplete seller profiles to onboarding
|
|
- Register verify flow redirects seller to onboarding instead of dashboard
|
|
- Forgot password support link opens default mail app to `admin@inatrading.co.id`
|
|
- Forgot password `?` button links to public `/help`
|
|
- Account-not-found `Bantuan`, `Kebijakan Privasi`, and `Syarat & Ketentuan` link to public pages
|
|
- Login `Remember me` now stores email and password in localStorage
|
|
|
|
### 2. Onboarding seller final submit flow
|
|
|
|
Files:
|
|
- `src/app/(onboarding)/onboarding/business/page.tsx`
|
|
- `src/app/(onboarding)/onboarding/store-detail/page.tsx`
|
|
- `src/app/api/seller/route.ts`
|
|
- `src/app/api/seller/store/route.ts`
|
|
- `src/app/api/warehouses/route.ts`
|
|
|
|
Behavior:
|
|
- Plan step was removed from seller onboarding UI flow
|
|
- `Warehouse Type` is hidden in UI and forced to `INA`
|
|
- Final onboarding submit is not a single endpoint. It calls, in order:
|
|
1. `POST /api/seller` -> host `POST /api/v1.0/seller`
|
|
2. `PUT /api/seller/store` -> host `PUT /api/v1.0/seller/store`
|
|
3. `GET /api/products/warehouses?page=1&size=100`
|
|
4. `PUT /api/warehouses/{id}` or `POST /api/warehouses`
|
|
- Frontend tries to reuse backend autogenerated warehouse if found, to avoid duplicate warehouse creation
|
|
|
|
### 3. Backend proxy logging
|
|
|
|
Files:
|
|
- `src/lib/backend-fetch-logger.ts`
|
|
- `src/instrumentation.ts`
|
|
- `.env.local` uses `DEBUG_BACKEND_PROXY=true` locally
|
|
|
|
Behavior:
|
|
- Logs server-side `fetch` requests to backend
|
|
- Logs request method, URL, headers, body preview
|
|
- Logs response status, duration, headers, body preview
|
|
- Redacts authorization header
|
|
|
|
Use this when tracing frontend-to-backend failures in local dev.
|
|
|
|
## 4. Product measurement mode on add product
|
|
|
|
Files:
|
|
- `src/app/(dashboard)/products/new/pricing/page.tsx`
|
|
- `src/lib/use-product-submit.ts`
|
|
- `src/app/(dashboard)/products/new/review/page.tsx`
|
|
|
|
Behavior:
|
|
- Each model has a `Product Measurement` switch
|
|
- When enabled:
|
|
- nested measurements are shown
|
|
- model-level price, currency, weight, dimensions, promotion, packaging, and warehouse stock are disabled
|
|
- at least 1 measurement row is required
|
|
- Submit payload uses `model.hasMeasurements`
|
|
- When measurement mode is active, model-level numeric fields are zeroed and model warehouses are omitted
|
|
|
|
## 5. Product measurement mode on edit product
|
|
|
|
File:
|
|
- `src/app/(dashboard)/products/[productId]/edit/page.tsx`
|
|
|
|
Behavior:
|
|
- Matches add-product measurement behavior
|
|
- Uses explicit `hasMeasurements` state instead of guessing from array length
|
|
- Disables model-level fields when measurement mode is on
|
|
|
|
## 6. Seller product review page improvements
|
|
|
|
File:
|
|
- `src/app/(dashboard)/products/new/review/page.tsx`
|
|
|
|
Behavior:
|
|
- Review now renders actual product thumbnails using backend file URLs
|
|
- Previously it only showed image indicators, which was confusing
|
|
- Review also reflects measurement-based pricing correctly
|
|
|
|
## 7. Product list page improvements
|
|
|
|
File:
|
|
- `src/app/(dashboard)/products/page.tsx`
|
|
- `src/lib/product-variants.ts`
|
|
|
|
Behavior:
|
|
- Edit stock/price modal supports:
|
|
- choosing model
|
|
- choosing measurement if present
|
|
- choosing warehouse
|
|
- Warehouse labels use warehouse names from master warehouse API, not raw UUIDs
|
|
- Product row status badges now show explicit state like active, draft, review, unpublished, deleted, rejected
|
|
- Seller `In Review` listing now uses host endpoint `/api/v1.0/seller/product/review`
|
|
- If list API returns `minPrice = 0` and `maxPrice = 0`, frontend hydrates that row by fetching product detail and calculating effective price from model/measurement data
|
|
|
|
Important:
|
|
- This fallback exists because some list rows from backend do not include valid min/max price for measurement-based products
|
|
- Example verified case: product `Pembersih Mobil` returned `0/0` in list but `IDR 50.000` in detail measurement
|
|
|
|
## 8. Product detail page improvements
|
|
|
|
File:
|
|
- `src/app/(dashboard)/products/[productId]/detail/page.tsx`
|
|
- `src/components/product-variant-showcase.tsx`
|
|
- `src/lib/product-variants.ts`
|
|
|
|
Behavior:
|
|
- Main category now resolves even when backend omits `subCategory.category.name`
|
|
- Warehouse display now uses warehouse master names instead of UUID slices
|
|
- TypeScript nullability issue for category resolution was fixed here
|
|
- Seller detail, admin detail, and admin review now share the same variant presentation logic
|
|
- Effective price rules:
|
|
- no measurement: use model price
|
|
- with measurement: use measurement price
|
|
- multiple measurements: show min-max from measurements
|
|
- multiple models: show min-max from effective model prices
|
|
- Variant showcase now supports:
|
|
- product-level summary price/weight/dimension
|
|
- model selector
|
|
- measurement selector
|
|
- selected variant detail
|
|
- model image thumbnail switching
|
|
|
|
## 9. Admin review page improvements
|
|
|
|
File:
|
|
- `src/app/admin/review/[productId]/page.tsx`
|
|
|
|
Behavior:
|
|
- Review supports model + measurement structures
|
|
- New product review and compare review now handle measurement-driven price/weight/dimension/promo/stock
|
|
- Compare view highlights updated sections using backend compare response and `isUpdate`
|
|
- Product images are rendered using main image + gallery images
|
|
- TypeScript issue around `row.field` nullability was fixed here
|
|
- Single-product review view now follows admin product detail layout more closely
|
|
- Compare view stays separate only for product update review
|
|
- Approve/reject action flow:
|
|
- UI `POST /api/admin/review/{productId}`
|
|
- new create accept -> host `POST /api/v1.0/product/accept/{productId}` with `{ "state": "PUBLISHED" }`
|
|
- update accept -> host `PUT /api/v1.0/product/accept/{productId}` with `{ "state": "PUBLISHED" }`
|
|
- create reject -> host `POST /api/v1.0/product/reject/{productId}`
|
|
- update reject -> host `PUT /api/v1.0/product/reject/{productId}`
|
|
- Review approve does not resubmit full product payload. It only submits action and state.
|
|
|
|
## 10. Dashboard shell and search
|
|
|
|
Files:
|
|
- `src/app/(dashboard)/layout.tsx`
|
|
- `src/app/(dashboard)/dashboard/page.tsx`
|
|
|
|
Behavior:
|
|
- Bell and message icons are intentionally grayed/disabled because no backend function exists yet
|
|
- Dashboard search now resolves query results across dashboard content instead of behaving like a dead input
|
|
|
|
## 11. Sidebar submenu reliability
|
|
|
|
Files:
|
|
- `src/components/product-submenu-nav.tsx`
|
|
- `src/components/admin-product-submenu-nav.tsx`
|
|
|
|
Behavior:
|
|
- Click behavior was hardened because submenu items were sometimes not navigating
|
|
- Navigation is explicit via `router.push(...)`
|
|
|
|
## Translation Files Touched
|
|
|
|
- `src/lib/translations/id.ts`
|
|
- `src/lib/translations/en.ts`
|
|
|
|
These include labels added for statuses and stock/price modal UI.
|
|
|
|
## Important Findings
|
|
|
|
### Product image inconsistency on `Pembersih Mobil`
|
|
|
|
Verified seller account:
|
|
- `Pendopo@Pendopo.com`
|
|
- password: `password`
|
|
|
|
Product:
|
|
- `Pembersih Mobil`
|
|
- ID: `92a8fae0-d067-4c90-be24-da31012aeaf9`
|
|
|
|
Verified backend behavior:
|
|
- list endpoint row returned `minPrice: 0`, `maxPrice: 0`
|
|
- detail endpoint returned one measurement priced at `IDR 50.000`
|
|
- detail endpoint currently returns:
|
|
- `imageId: null`
|
|
- `productImages: []`
|
|
- `model.imageId: null`
|
|
|
|
Implication:
|
|
- product images are currently absent in backend detail payload for this product
|
|
- if user reports image visible in older browser tab, suspect stale tab state before assuming frontend regression
|
|
|
|
### Admin review image issue
|
|
|
|
For at least one reviewed product, backend review payload returned:
|
|
|
|
- `image: null`
|
|
- `imageId: null`
|
|
- `productImages: []`
|
|
|
|
In that case frontend cannot render images. If an image is missing in review, verify backend review payload before debugging frontend.
|
|
|
|
### Edit product empty main image behavior
|
|
|
|
In edit product submit flow, empty `imageId` is currently sent as `undefined`, which means the field is omitted from JSON payload, not sent as `null` and not sent as empty string.
|
|
|
|
If backend requires explicit image removal via `null`, this behavior will need to be changed.
|
|
|
|
### Seller in-review API note
|
|
|
|
Postman latest collection contains:
|
|
- seller review listing: `/api/v1.0/seller/product/review`
|
|
- generic review detail: `/api/v1.0/product/review/{productId}`
|
|
|
|
Current app matches this for listing and still uses generic review detail endpoint for product review detail.
|
|
|
|
## Local Dev Notes
|
|
|
|
Run local dev:
|
|
|
|
```bash
|
|
npm run dev
|
|
```
|
|
|
|
Build verification:
|
|
|
|
```bash
|
|
npm run build
|
|
```
|
|
|
|
## Dev Server Update Guide
|
|
|
|
Based on current deployment notes, dev server update flow is:
|
|
|
|
```bash
|
|
sudo -iu inadev
|
|
cd ~/apps/ina-trading-web
|
|
git fetch origin
|
|
git checkout main
|
|
git pull --ff-only origin main
|
|
npm ci
|
|
npm run build
|
|
pm2 restart ina-trading-dev
|
|
pm2 save
|
|
sudo -iu inadev pm2 status
|
|
```
|
|
|
|
Current expected deployed commit after latest push is the latest `origin/main` commit from this handoff update. Verify short hash with:
|
|
|
|
```bash
|
|
git rev-parse --short HEAD
|
|
```
|
|
|
|
Verify full commit on server:
|
|
|
|
```bash
|
|
git rev-parse HEAD
|
|
```
|
|
|
|
Optional logs:
|
|
|
|
```bash
|
|
sudo -iu inadev pm2 logs ina-trading-dev --lines 100
|
|
```
|
|
|
|
## Suggested Next Checks
|
|
|
|
- Verify whether backend expects `null` when main image is intentionally removed during edit
|
|
- Verify seller and admin review payload consistency for image fields
|
|
- Verify warehouse master API always contains all warehouse IDs referenced in product payloads
|
|
- Verify whether seller in-review detail also has a seller-specific detail endpoint in backend/Postman, to align with seller-specific listing endpoint
|
|
- Investigate when product images were lost for `Pembersih Mobil` and whether edit/update flow can preserve old image ids more defensively
|
|
- If submenu click issue still appears, inspect layout overlays with browser tooling
|
|
- Consider adding field-level compare highlighting, not only section-level highlighting, in admin review compare page
|
|
|
|
## Files Most Likely To Be Relevant Next
|
|
|
|
- `src/app/(dashboard)/products/new/pricing/page.tsx`
|
|
- `src/app/(dashboard)/products/[productId]/edit/page.tsx`
|
|
- `src/app/(dashboard)/products/new/review/page.tsx`
|
|
- `src/app/(dashboard)/products/[productId]/detail/page.tsx`
|
|
- `src/app/(dashboard)/products/page.tsx`
|
|
- `src/app/admin/review/[productId]/page.tsx`
|
|
- `src/components/product-variant-showcase.tsx`
|
|
- `src/lib/product-variants.ts`
|
|
- `src/lib/use-product-submit.ts`
|
|
- `src/lib/backend-fetch-logger.ts`
|