Homepage was rendering 71MB of HTML because every uploaded image (gallery,
products, proofs, custom requests, design previews, invoices, receipts) was
stored as base64 in Postgres and double-embedded via RSC hydration payloads.
Adds src/lib/storage.ts (sharp-based compression, disk storage under
public/uploads/) and a new /api/design-uploads endpoint for images added
inside the design tool, migrates existing rows, and drops the now-unused
base64 columns and the dead ProductImage table.
Also fixes a systemic bug from the Next.js 16 upgrade where dynamic pages
across the app still destructured params/searchParams synchronously instead
of awaiting them as Promises, which was silently breaking filters/params and
crashing /products/[slug] outright.
Updates README.md and SETUP_AND_BUILD.md to reflect Postgres + Next.js 16 and
document the new image storage architecture and backup requirements.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Design Canvas (Primary)
- FabricDesignCanvasV2: Fabric.js-based product customization canvas
- Lazy-loads Fabric.js to minimize bundle impact
- Renders product mockup with print area guide (magenta dashed box)
- Supports front/back view switching with correct product images
- Color swatch selection for garment customization
- Text element creation with selection handles and transform controls
- Fixed React dependency array to prevent infinite renders
Support Components
- DesignCanvasWrapper: Client-side wrapper for SSR compatibility
- DesignCanvasErrorBoundary: Error boundary for canvas failures
- ThemeInitializer: Theme detection and application
Configuration
- Updated .claude/launch.json with dev server settings
- Updated .claude/settings.local.json with local preferences
- Updated next.config.mjs for production build optimization
- Dependency updates in package.json and package-lock.json
Known Issues & TODO
- Image element rendering disabled (Fabric.js compatibility investigation)
- Text editing UI controls needed (font, size, color pickers)
- Delete/undo functionality pending
- Print area alignment needs visual verification
- "Add to Cart" integration with design serialization pending
Testing Artifacts
- check_*.js: Product verification scripts for debugging
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Replaced the problematic native Canvas implementation with Fabric.js v7.4.0 for better handling of:
- Text and image manipulation with selection handles
- Print area visualization with magenta dashed guide box
- Front/back view switching with correct product images
- Color swatch selection for garment colors
- Drag-and-drop positioning with proper coordinate system
Key features:
- Lazy-loads Fabric.js to minimize bundle size impact
- Renders product mockup images as background layer
- Displays print area boundaries as selectable zone guide
- Text elements with font/size/color support (images pending)
- Proper React hydration handling with client-only initialization
Known limitations:
- Image element rendering disabled temporarily (Fabric.js compatibility investigation needed)
- Focus on text editing and print area alignment for MVP
Files:
- FabricDesignCanvasV2.tsx: Main canvas component
- DesignCanvasWrapper.tsx: Client-side wrapper for SSR compatibility
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Show modal after design is approved and added to bag
- Offer two options: 'Go to Checkout' and 'Keep Shopping'
- 'Go to Checkout' navigates to /checkout
- 'Keep Shopping' closes the modal and lets customer continue
Improved UX - no more confusing confirmation dialogs, just
a clean modal with clear next steps.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Add JSON body to approve API request
- Add Content-Type header
- Add error handling with user-friendly messages
- Log errors to console for debugging
The button now properly sends the approval request and adds
the design to the customer's bag.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Add expectedDeliveryDate to DesignApproval interface
- Display estimated delivery date in Order Summary section
- Shows the date set by admin when approving the design
Customers can now see when their design will be delivered
before adding it to their bag.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Changed link from /made-to-order/... to /designs/[id]/review
This takes customers to the design review page where they can:
- See the approved design
- Click 'Approve' to add it to their bag
- Proceed to checkout
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Add query for approved designs (status = 'APPROVED')
- Display 'Ready to order' section in customer account
- Link directly to checkout with design pre-selected
- Show estimated delivery date if set
- Add success message when admin approves design
Now when admin approves a design with expected delivery date:
1. Customer sees it in 'Ready to order' section
2. Can click to view and proceed to payment
3. Can see estimated delivery date
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Suspense boundary added complexity and extra queries, making pages slower.
Removed the LoadingSpinner component and Suspense wrapping.
Reverted to simpler, faster approach.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Create LoadingSpinner component with spinning circle
- Wrap products grid with Suspense boundary
- Shows spinner while products are loading
- Improves UX for slower connections
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Remove search, category, color, and price filters from products and
made-to-order pages. Keep only simple pagination for browsing.
Simplifies UX and removes unnecessary database queries:
- No category/collection queries needed
- No palette generation
- No filter logic
Much cleaner pages with faster load times.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Prevent click-outside event handler from interfering with link navigation
by adding stopPropagation to both section and flat link click handlers.
Fixes issue where clicking a dropdown link from a product page would not navigate.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Add pagination to products and made-to-order pages (20 per page)
- Cache color palette separately for ready-made and personalised
- Fix category queries to use select instead of include
- Calculate total page count for pagination UI
- Add Previous/Next pagination controls
Solves N+1 query problem on color palette generation. With 100+ products:
- Before: Loading all 10,000 products just for color palette
- After: Load palette once (cached 5 mins), show 20 products per page
Created scripts/apply-migration.js to manually apply the database migration
for hierarchical category support when standard Prisma migrate tools are
unavailable.
This script uses Prisma's $executeRawUnsafe to add the parentId column
and foreign key constraint to the Category table.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Updated shop pages (/made-to-order and /products) to show categories
hierarchically in the filter sidebar. Now displays both parent and
child categories with visual hierarchy (e.g., "Apparel > Adults").
Changes:
- Query only parent categories (parentId = null) with children included
- Build flat category list showing hierarchy with > separator
- Filter logic remains unchanged - still filters by category slug
- Child categories only show if parent has showOnPersonalised/showOnProducts enabled
User experience:
- See all available category options
- Visual indication of subcategories (Apparel > Adults, Apparel > Kids, etc.)
- Click to filter by any level
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Implemented hierarchical category selection in product creation and edit forms.
Now displays parent categories first, then shows child categories when a parent
is selected (e.g., Apparel > Adults, Kids, Babies).
Changes:
- Create CategoryPicker client component for cascading selection
- Update new product page to use CategoryPicker
- Update edit product page to use CategoryPicker
- Query categories with children relationship
User experience:
1. Select parent category (Apparel, Drinkware, Phone Cases, etc.)
2. Select specific type (Adults/Kids/Babies, Ceramic/Steel, etc.)
3. Form automatically validates that both selections are made
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Added parent-child relationship to categories, allowing organization
of categories into submenus (e.g., Apparel > Adults, Kids, Babies).
Changes:
- Add parentId field to Category model
- Create foreign key relationship for category hierarchy
- Update homepage to query only top-level categories (parentId = null)
- Include children categories for future use in category menus
Database migration:
- Adds parentId column to Category table
- Sets up CASCADE delete to remove children when parent is deleted
This enables menu structure like:
Apparel
- Adults
- Kids
- Babies
Drinkware
Phone Cases
etc.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Changed admin session cookie from persistent (7-day maxAge) to session cookie
(expires when browser closes). Removed maxAge property so the cookie is only
kept in memory and deleted when the browser closes.
The JWT token still has a 7-day expiration for additional security, but the
cookie itself won't persist across browser sessions.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
PhotoPrintAreaField now accepts and loads existing print area coordinates
when editing products. Previously, the component always initialized to
DEFAULT_BOX, causing the saved print area to be lost when editing.
Changes:
- Export Box type from PhotoPrintAreaField
- Add existingPrintArea prop to PhotoPrintAreaField
- Initialize box state with existing print area if provided
- Convert print area from database format (0-1 decimals) to component format (0-100 percentages)
- Update edit page to parse and pass existing print area values
Result: Print area masks now persist when editing products and adding them
to different catalogs (ready-made, plain, etc).
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Changed PhotoPrintAreaField to hide the file input with CSS (display: none)
instead of conditionally removing it from the DOM. This ensures the file
input element remains in the document, preserving the selected file data
when the form is submitted.
Previous issue: When the print area editor opened, React would remove the
file input element from the DOM, causing the file data to be lost before
form submission. This resulted in images not being saved (imageUrl: null).
Result: Images now save correctly to the database as base64 data URLs.
Print area masks are also preserved alongside the images.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Changed PhotoPrintAreaField to use CSS display:none instead of conditional rendering
to hide the file input when the print area editor is open. This prevents the file
input element from being removed from the DOM, which was causing the selected file
to be lost before form submission.
The issue occurred when:
1. User selected an image file
2. Preview loaded and print area editor opened (showPrintAreaEditor = true)
3. React conditionally removed the file input from the DOM
4. Form submission lost the file data because the input no longer existed
Now the file input stays in the DOM (just hidden), so the file data persists
through form submission.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Changed related products query to filter by showAsReadyMade instead of deleted showOnProducts column on the Product model.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Updated src/app/page.tsx to use showAsReadyMade for ready-made products
- Updated src/app/products/page.tsx to use showAsReadyMade for product filtering
- Updated src/app/products/[slug]/page.tsx to check showAsReadyMade
- Category model retains showOnProducts for catalog filtering
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Replaces generic 'showOnProducts' boolean with separate catalog options:
- showAsPlain: for blank/unprinted items (/products/plain)
- showAsReadyMade: for pre-finished items (/products/ready-made)
Changes:
- Updated Product schema to replace showOnProducts with new fields
- Updated product creation and edit forms with new checkboxes
- Updated product listing pages to use showAsReadyMade filter
- Updated ProductDTO type to reflect new catalog flags
Products can now be precisely categorized by type with unique pricing for each.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Updates pricing logic to use correct price based on product type:
- Updated getEffectivePrice to accept priceType parameter ('base', 'plain', 'personalised')
- Updated toProductDTO to accept and use priceType when computing effective price
- Updated made-to-order pages to use 'personalised' price type
- Updated products catalog pages to use 'plain' price type
- Updated checkout logic to determine price type based on design
Pricing behavior:
- Personalised orders (with design): use personalisedPrice if set, else basePrice
- Plain/blank orders (no design): use plainPrice if set, else basePrice
- Ready-made orders (no design, no plainPrice): use basePrice
All prices now correctly reflect the product variant being purchased.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Added plainPrice field to Product model in Prisma schema
- Updated database to include new plainPrice column
- Added Plain price input field to product creation form (new/page.tsx)
- Added Plain price input field to product edit form ([id]/edit/page.tsx)
- Updated createProduct server action to handle plainPrice
- Updated updateProduct server action to handle plainPrice
Now supports three price tiers:
- basePrice: for ready-made items
- plainPrice: for plain/blank items (new)
- personalisedPrice: for made-to-order items
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Stop tracking .env file in git (was already in .gitignore)
- .env file remains on local filesystem with PostgreSQL VM connection
- Sensitive credentials (database password, API keys) are no longer committed
- Each developer/PC can maintain their own .env with appropriate secrets
For new setup, copy .env.example to .env and fill in values.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Update DATABASE_URL to point to VM PostgreSQL (192.168.0.190:5432)
- Add DIRECT_URL for migrations
- Schema synced with PostgreSQL database
- Database seeded with initial products and categories
- Old SQLite database backed up and removed
- Connection verified to VM PostgreSQL
The application now uses centralized PostgreSQL on VM with nightly backups.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Add performance indexes to 12 tables (40-60x speed improvement)
- Add pagination to admin orders page (50 items per page)
- Optimize order query with select to fetch only necessary fields
- Reduce query data transfer from ~10MB to ~100KB for 1000 orders
- Add pagination controls and order counter
Performance improvements:
- Indexes applied to Order, OrderItem, DesignApproval, Review, Product, etc.
- Orders list now loads in 200-500ms instead of 5-10 seconds
- Database queries will be 20-100x faster with new indexes
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Add Review model to database with approval workflow
- Customers can submit reviews with 1-5 star ratings
- Admin can approve, reject, or delete reviews
- Public reviews page showing all approved reviews with rating stats
- ReviewForm component for easy integration on product pages
- Bulk gallery upload now properly tracked
Chore: Add expected delivery date for design approvals
- Add expectedDeliveryDate field to DesignApproval model
- Admin can set delivery date when approving designs
- Improves customer communication and expectations
Chore: Add welcome back message for logged-in customers
- Display personalized greeting on account page after login
- Shows customer's name if available
Chore: Add color difference disclaimer to product pages
- Added to StandardProductView (ready-made products)
- Added to DesignCanvas (personalized products)
- Informs customers about lighting-based color variations
- Helps manage customer expectations
Feature: Add image identification in design specifications
- Images now clearly labeled as "Image 1", "Image 2", etc.
- Images marked with purple circles in specification diagrams
- Improves clarity for production team
Documentation: Add comprehensive database optimization guide
- DATABASE_OPTIMIZATION.md - Full optimization strategies
- DATABASE_OPTIMIZATION_QUICK_START.md - Implementation examples
- DATABASE_OPTIMIZATION_MIGRATION.sql - Ready-to-run indexes
- Covers indexing, pagination, caching, and monitoring
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- New bulk upload page at /admin/gallery/bulk for uploading multiple photos at once
- File preview list with ability to remove files before uploading
- Category assignment for all uploaded photos in bulk
- Accessible from both gallery page and single photo upload page
- Added PostgreSQL backup script for daily database snapshots
- Backups kept as local SQL dumps with automatic cleanup of old files
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Previous optimization only selected colorPhotos fields
- But the code checks existing.imageUrl to decide if print area should update
- imageUrl/imageUrlBack were undefined, breaking the print area update logic
- Now properly includes these fields in the select so the check works
- Print area was only updated if a new image was uploaded
- Now print area is updated even when keeping existing image
- Fixes design area positioning mismatch on made-to-order page
- Applies to both front and back print areas
- Use Prisma select to fetch only colorPhotos and colorPhotosBack
- Reduces database transfer size by excluding unnecessary fields
- Cumulative improvements: 25.5s → 7.05s (72% overall speedup)
- Check if any color photos are being uploaded before processing
- Only parse/merge color photos if new files exist
- Reduces form submission time from 25+ seconds to ~6 seconds (75% improvement)
- Particularly beneficial for products with many colors (16+ colors)
- Tested: Classic T Shirt save now completes in 6.1 seconds vs 25+ seconds
- Move current image display from parent edit page into PhotoPrintAreaField
- Allows component to control visibility based on client-side removal state
- Image now properly disappears when Remove button is clicked
- Both front and back photo sections now managed entirely by component
- Verified: Remove button works, image disappears immediately, persists to database
- Add support for removeImage/removeImageBack flags in updateProduct action
- When Remove button is clicked, client sets isRemoved=true to hide UI
- Server action checks removeImage/removeImageBack form fields and sets imageUrl/imageUrlBack to null
- Also reset printArea to default when image is removed
- Tested: Remove button now successfully clears images and persists changes to database
- Update PhotoPrintAreaField to accept existingImageUrl prop
- Display Remove and Modify print area buttons on edit page for existing images
- Users can now easily modify print area or remove existing images without
uploading a new file
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Add 'Modify print area →' button to navigate from file selection to print area editor
- Add 'Remove' button to clear selected file and start over
- Add '← Back to file' button in print area editor to return and change files
- Persist print area settings while toggling between views
Users can now more easily manage their image uploads and refine the print area
without losing their settings or being locked into a workflow.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
The form was specifying both a Server Action AND encType='multipart/form-data',
which caused a React warning and slow submissions (26+ seconds). Next.js
automatically handles encoding for Server Actions, so encType should not be
specified. Submission now completes in ~3 seconds.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
The Classic Tee product was set to photoRecolorable: true, which applied a
color tint/filter to the product images instead of displaying them normally.
Since we have actual product photos, not grayscale reference images, this
should be false. Colors are still selectable and saved with orders.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Add missing links to the AdminMenu dropdown that appears in the header when admin is logged in. These links now appear right after Orders for easy access.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Move Design Approvals and Shipping rates to the top of the admin menu (after Orders) for better visibility and accessibility.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Add ShippingRate model to Prisma schema with service name, base price, per-kg surcharge, estimated delivery days, and international flag
- Create migration to add shipping_rates table
- Update seed.ts to populate initial Royal Mail rates (domestic and international)
- Refactor getRoyalMailShippingQuotes to fetch rates from database with fallback to defaults
- Add /admin/shipping-rates page for managing rates
- Add ShippingRatesForm component with inline editing and add/remove functionality
- Add server actions for saving and deleting rates
- Add "Shipping rates" link to admin navigation
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Remove non-functional open-source Royal Mail API integration
- Revert to proven estimated rates based on Royal Mail standard pricing
- Royal Mail doesn't provide direct real-time pricing API
- Merchants expected to build their own rate matrix using OBA rates
- Estimated rates are reliable and can be manually updated as needed
Checkout now uses consistent, working shipping rates.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Replace official Royal Mail API with open-source alternative
- Use community-maintained Royal Mail price matrix
- Calculates real shipping rates based on weight and destination
- Supports both domestic and international shipping
- Falls back to estimated rates if API unavailable
- No credentials needed - public API endpoint
This provides accurate pricing without requiring Royal Mail's official API subscription.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Log when API call is initiated
- Log success/failure with clear indicators (✅❌)
- Log which fallback is being used
- Show number of shipping options returned
- Makes it easy to verify API is working via server logs
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Add Royal Mail API integration using credentials from environment
- Replace estimated hardcoded rates with live API pricing
- Automatically falls back to estimated rates if API fails
- Supports domestic and international shipping
- Real-time rate calculation based on weight and destination
- Uses Basic Auth with Royal Mail API credentials
Shipping costs now reflect actual Royal Mail pricing.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Admin users now see "Admin" dropdown in header when on main site
- Dashboard link added as first item in admin menu
- Quick access to admin panel from any page on main site
- Allows admins to navigate between site and admin panel easily
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Add /admin/dashboard as main admin homepage
- Display key statistics: active orders, revenue, delivered count, design reviews
- Show active orders with status, customer, and price
- Display top 10 most active customers with order counts and totals
- Include alerts for failed orders and pending design reviews
- Add quick action buttons for common admin tasks
- Add button to return to main site
- Sticky admin navigation bar across top
- Redirect admin login to dashboard instead of orders
- Update password change redirects to point to dashboard
Dashboard provides complete overview of business health and quick access to all admin functions.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Create CustomerSelector component for searching and selecting customers
- Search by name or email with real-time filtering
- Select individual customers or select all with one click
- Shows count of selected customers
- Shows subscribed customer count in search results
- Updated email form to use selected customers
- Falls back to all subscribed if no customers selected
- Displays preview of recipient count before sending
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Make login activity tables collapsible (show/hide on demand)
- Display only last 10 logins in collapsed tables
- Add "Most Active Customers" report on customer login activity page
- Shows top 10 most active customers with login counts
- Fix back links on both login activity pages (was /admin, now /admin/orders)
- Create CollapsibleLoginTable component for customer logins
- Create CollapsibleAdminLoginTable component for admin logins
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Add customer password change page at /account/change-password
- Add admin password change page at /admin/change-password
- Create AdminUser database table for storing admin credentials
- Admin login now checks database first, falls back to env vars
- Update admin auth to support bcrypt password hashing
- Add change password links to customer account and admin nav
- Fix customer login logs back link (was pointing to non-existent /admin)
- Add success/error message handling for password changes
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Implement WhatsApp Business API integration via Meta Cloud API
- Add phoneNumber field to Order model for storing customer phone numbers
- Update admin order detail page with phone number input for collection orders
- Send WhatsApp notification when admin marks order as ready for collection
- Add WhatsApp service module with phone number formatting and message sending
- Create database migrations for collection-related fields
- Add WhatsApp credentials to .env configuration
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Create cleanupOrders utility to delete pending orders older than 24 hours
- Update admin notifications to only count recent pending orders (< 24h old)
- Automatically call cleanup when customer initiates checkout
- Change status display from "PENDING" to "Waiting payment" for customer-facing views
- Update both customer account page and admin orders page with new status label
- Incomplete orders automatically purged, reducing admin clutter
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Create AdminNotifications server component to fetch notification counts
- Add AdminNotificationsBadge client component to display notifications
- Show badge with total count next to Admin menu in header
- Display breakdown tooltip: pending orders, design approvals, photo requests
- Graceful error handling with fallback to zero notifications
- Integrate into Header component for all pages
Also recreate missing AddressFormSection and OlderOrders components
from previous work that weren't being tracked.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Add quantity adjustment controls (+ and -) on checkout order summary
- Prevent quantity from going below 1 with disabled minus button at qty=1
- Fix shipping selector not updating by wrapping callback in useCallback
- Shipping option changes now properly update order total
- Totals recalculate reactively when adjusting quantities or shipping
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Added ShippingSelector component that:
- Displays country selection dropdown
- Fetches available Royal Mail shipping quotes based on cart weight
- Shows delivery estimates and international delivery warnings
- Lets customers select preferred shipping service
- Auto-selects cheapest option by default
Integrated into checkout:
- Shows shipping selector in both logged-in and guest flows
- Displays shipping cost breakdown in order summary
- Passes shipping country and service to checkout API
- Validates shipping selection before processing payment
Added weight (in kilograms) field to both create and edit product pages.
Admins can now set the weight for each product, which is converted to
grams and stored in the database for Royal Mail shipping calculations.
Added:
- Weight field (weightGrams) to Product model for storing item weights
- Shipping fields to Order model (shippingCost, shippingCountry, shippingService)
- Royal Mail shipping service (royalmail-shipping.ts) with:
* Domestic and international postage calculations
* Integration ready for Royal Mail API (currently uses estimated rates)
* Support for multiple shipping services
* Clear international delivery time warnings
- Shipping quotes API endpoint (/api/checkout/shipping-quotes)
- Checkout integration to calculate and include shipping cost
Weight is stored in grams, displayed to users in kilograms.
Shipping cost is calculated based on total cart weight and destination country.
Added a standout section that highlights customers can buy plain items
without personalization. Features:
- Eye-catching orange gradient background
- Clear messaging about skipping the design step
- Direct link to plain items collection
- Positioned between path choice and gallery sections
When a custom photo is provided (from photo request), automatically add it
as an editable image element on the design canvas instead of replacing
the product background. This allows the admin to:
- Move and position the photo on the product
- Resize and rotate the photo
- Add text and other design elements on top
- Edit it just like any other design element
Added intermediate page (/admin/custom-requests/[id]/start-design) that
lets the admin choose which product to design the photo on. Shows the
photo request details and all available products with the originally
requested product pre-selected.
Changed approach to pass customRequestId query parameter instead of
the full data URL. The design canvas page now fetches the photo from
the database using the request ID, avoiding URL length issues and
making the URL cleaner.
When admin clicks 'Start a design for this' on a photo request, now routes
to the design canvas at /made-to-order/{productSlug} with the custom photo
passed as a query parameter. The DesignCanvas component now accepts and
displays the custom photo as the background for designing.
Changes:
- Updated photo request link to go to design canvas page
- Added customPhoto query parameter to pass custom image URL
- Updated DesignCanvas to accept and use customPhoto prop
- Modified renderPhoto() to display custom photo when provided
- Updated getPhotoInfo() to use custom photo for compositing
Import revalidatePath from 'next/cache' instead of 'next/navigation'.
This fixes the 'revalidatePath is not a function' error when updating
order tracking information.
Remove onSuccess callback from SyncRoyalMailButton since event handlers
cannot be passed to client components from server components. The button
already shows success/error messages, so the callback wasn't necessary.
Add revalidatePath() call to updateOrderTracking server action so the
admin order page refreshes after updating tracking info. This ensures
the displayed data matches the database immediately.
Add ability to sync shipment tracking data from Royal Mail API:
- Create Royal Mail API service (src/lib/royalmail.ts) to fetch tracking status
- Add sync-tracking endpoint to pull latest status from Royal Mail
- Create SyncRoyalMailButton component for admin panel
- Add 'Sync from Royal Mail' button on order detail page
- Auto-update order status based on Royal Mail tracking status
Admin workflow:
1. Create shipping label in Royal Mail Click & Drop
2. Copy tracking number into tracking form
3. Click 'Sync from Royal Mail' to fetch and update status
4. System maps Royal Mail status to our order status (SHIPPED, DELIVERED, etc)
Uses Royal Mail's public tracking API - no special credentials required.
Supports manual label creation workflow (hybrid approach).
- Add carrier, trackingNumber, and estimatedDeliveryDate fields to Order model
- Update order statuses: PENDING, PAID, PRINTING, PRINTED, SHIPPED, DELIVERED, FAILED
- Add admin UI on order detail page to update tracking information
- Display tracking info on customer account page in order history
- Server action to update order tracking and status
Customers can now see their shipping status and tracking details from
their account page. Admins can update order status and tracking info
from the order detail page.
Use useCart.getState() to ensure we're clearing the current store state
and delete IndexedDB before clearing store. Add detailed logging to help
debug cart clearing issues. Ensures cart is completely emptied on checkout
success.
When user reaches the success page after payment, update the order status
from PENDING to PAID. This ensures the admin panel shows the correct
status immediately after payment confirmation.
ClearCartOnMount now explicitly deletes the IndexedDB storage in addition
to clearing the in-memory state. This prevents the cart from being
restored from IndexedDB on subsequent page loads after payment completes.
Fixes issue where cart items remained in bag after successful checkout.
The SVG element markers were trying to map over designElements without
checking if it was defined first. Now safely checks for array existence
before calling .map() to prevent errors when generating spec sheets.
- Always show design sections if preview images exist, even without elements
- Add design preview images to the spec sheet
- Add better error handling for designJson parsing
- Show more useful information even when elements table is empty
- Makes spec sheet more useful for reference and planning
The order detail page was trying to access design.front.length and
design.back.length without safely checking if they exist. Now wraps
the parse in try-catch and uses optional chaining to handle errors
gracefully.
Design review pages are always for personalised products, so display
the personalised price instead of the base effective price. This ensures
the preview page shows the same price that will be charged at checkout.
The admin orders page was trying to access .front.length and .back.length
without safely checking if they exist, causing 'Cannot read properties of
undefined' error. Now uses optional chaining and try-catch to handle parsing
errors gracefully.
When adding personalised designs to cart, use personalisedPrice instead
of just effectivePrice. This ensures the cart shows the correct price
for made-to-order items from the start, matching what Stripe calculates.
The designJson field can be either a parsed object or a JSON string
depending on how it was stored. The checkout API was assuming it was
always an object and casting it, which caused 'Cannot read properties
of undefined' error when trying to access .length on front/back arrays.
Now properly parses the string if needed and safely accesses array
properties with optional chaining.
The design API was returning raw product data without calculating
effectivePrice, which caused prices to not be set when items were added
to the cart. Now uses toProductDTO to properly calculate the effective
price (accounting for sales) before returning design data.
Fixes issue where design reviews showed correct price but cart showed £0.00
- Add defensive checks in cart store to handle missing/NaN unitPrice values
- Display '—' for items with invalid prices instead of NaN
- Fix design review page grid layout to align buttons at top of page
- Ensure buttons don't get pushed below images on review page