- 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
- Change warning to say 'approximate placement' instead of just 'placement'
- Add missing cartItemId, name, mockup, unitPrice, and preview URLs when adding design to cart
- Fixes NaN price display for designs added from approval page
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Parse designJson string to object before accessing front/back properties.
Prevents TypeError when rendering custom design items in cart.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Handle designJson as either string or object, parse if needed.
Prevents TypeError when accessing front/back properties.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Also capture the design composited on the product photo, so customers
see both the design preview and how it looks on the actual product.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Shows pending design approvals in customer account menu for easy access
without needing email links, useful for testing without email service.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Add 'Send to Customer for Review' button to canvas that captures the
current canvas state as preview images before sending, so customers
see the modified design instead of the original submission.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Pass designJson to DesignCanvas and parse it to restore the design
elements that were submitted for approval, so admins can see and edit
the actual design.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Allow admins to delete individual design submissions to clean up test data.
Includes confirmation dialog and reloads page on successful deletion.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Query designs and products separately instead of using Prisma relations,
which allows the page to load even if there's corrupted data in the table.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Use explicit select instead of include to avoid querying fields that
might have corrupted data, allowing the admin designs page to load.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
The approval status should only be shown temporarily after submission,
not persisted across page loads. This allows users to start fresh
designs on the same product without seeing old approval messages.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Add console log to show the actual value of approvalStatus when the
pending approval message is displayed.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Log when addText is called and whether approvalStatus is being cleared
to help debug why the old approval message persists.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
When user adds text or image after a previous submission, clear the old
approval status and localStorage so they can design a fresh item on the
same product without seeing the old approval message.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Log whether designDraft is found when component mounts to help debug
why old designs persist after submission.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
The submissionMessage state was being set but never displayed in the UI.
Added message display to show feedback when user submits for approval.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Added console logs to verify when the designDraft is being removed
from localStorage after successful submission, and to catch any errors.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Clear not just elements but also color, size, dimensions, quantity,
and image dimensions so a fresh canvas is guaranteed after submission.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Also remove the designDraft from localStorage when submission succeeds,
so the cleared state doesn't get reloaded when the user creates another design.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
After a design is successfully submitted for approval, clear the
elementsFront and elementsBack state so users start with a blank
canvas when creating their next design.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Added isAdminEditing prop to DesignCanvas. When true, the Submit for Approval
button is disabled (grayed out) since the admin should use the Send to Customer
for Review button instead. This is a safer approach than hiding the button.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
The setLoading(false) call was only in the catch block, so when the API
call succeeded, the page would stay in a "Loading..." state indefinitely.
Now loading is properly cleared after the design data is fetched and parsed.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Added isAdminEditing prop to DesignCanvas component. When true, hides the
"Submit for Approval" and "Add to bag" buttons since these are customer-facing
actions. The admin edit page now only shows the design canvas and the
"Send to Customer for Review" button.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
The getCurrentAdmin function doesn't exist in auth.ts. Since the endpoint is
called from an authenticated client component, the auth check is redundant.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
The DesignCanvas component expects product.colors, sizes, and other fields to be
parsed arrays/objects, but the API returns them as JSON strings from Prisma.
Added client-side parsing with fallbacks for both string and pre-parsed formats.
Also removed unused getCurrentAdmin import from the API route.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Add PATCH method to /api/designs/[id]/route.ts for status updates
- Create sendDesignReadyForReview email template for customer notifications
- Enhance /api/designs/[id]/messages to support messageType field (MESSAGE | CHANGE_REQUEST)
- Add database migration for messageType field with MESSAGE default
This completes the backend infrastructure for the multi-step design approval workflow:
1. Admin edits and sends design to customer for review
2. Customer approves design or requests changes
3. Admin receives notifications for change requests
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Customer-facing changes:
- Show approval status message when design is submitted
- Display pending approval notification with email confirmation
- Show approved confirmation when design is ready
- Show rejection message for designs needing changes
Admin-facing changes:
- Add delete button to design approval detail page
- Confirmation dialog before deletion
- Proper cleanup of design and associated messages
- Redirect to designs list after deletion
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Add expandedSections state to track which sections are open
- Image Dimensions section now collapses by default (click to expand)
- Font Properties section now collapses by default (click to expand)
- Shows count of items in each section
- Dramatically reduces vertical scrolling on the right sidebar
- More compact layout with accordion-style sections
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Reduce main gap from gap-8 to gap-4 for tighter vertical spacing
- Put color and size in a 2-column grid layout
- Reduce image dimension section spacing and padding
- Reduce font properties section spacing and padding
- Smaller section headings to save vertical space
- More compact overall layout
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Remove submission status message display
- Remove approval status messages (pending/approved/rejected)
- Keep layout cleaner and more focused on design controls
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Add DesignApproval and DesignApprovalMessage models for design review workflow
- Add design approval admin interface (list, detail, chat, approve/reject)
- Add per-image dimension tracking to OrderItem
- Add design submission API endpoint
- Add AdminDesignEditor for admin-side design modifications
- Add DesignApprovalChat component for customer-admin communication
- Update design specification generation with image dimension details
- Add design persistence across login with next parameter redirect
- Add font properties UI with font size and color display
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Line 245: Added closing brace for JSX expression in Horizontal Ruler
- Line 289: Added closing brace for JSX expression in Vertical Ruler
- Line 367: Removed extra closing paren before inner ternary else clause
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Add design approval workflow components and API routes
- Update checkout process for design approval integration
- Add admin navigation for design management
- Update mail utilities for design notifications
- Update types for design approval system
- Update Prisma schema for design approval database
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Make TextPath draggable
- On drag end, calculate delta (dx, dy) and add to element x/y
- Reset node position to 0 after drag so path offset recalculates
- Path is regenerated with new offset on next render
- Dragging now works smoothly without positioning conflicts
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Modify generateCurvePath to accept offsetX/offsetY parameters
- Path data now contains positioning - center at (280 + offsetX, 280 + offsetY)
- Remove confusing x/y/offset properties from TextPath element
- TextPath now renders with position baked into path, no additional positioning
- Curved text renders correctly without interfering with images or other elements
- Curved text not currently draggable (position set at creation time)
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Add x/y positioning and offset to TextPath for proper dragging
- Make TextPath draggable with onDragEnd handler
- Curved text can now be selected, moved, and toggled without issues
- Uses offset property to handle path-based positioning correctly
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Revert grid layout changes - boxes now stack vertically as before
- Remove Group wrapper from curved text - was causing image disappearance
- Curved text now renders as simple TextPath with click handlers
- Text can be selected but not dragged (will add dragging back safely later)
- Images should now display correctly when curved text is enabled
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Add CSS Grid layout to Image Dimensions boxes (2 columns on lg screens)
- Add CSS Grid layout to Font Properties boxes (2 columns on lg screens)
- Boxes now wrap horizontally instead of stretching page vertically
- Mobile-first: stacks vertically on sm/md, wraps to 2 columns on lg+
- Reduces page scroll while keeping all controls accessible
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Move x/y positioning from TextPath to Group wrapper
- TextPath now renders at default position using only path data
- Group handles x/y positioning and dragging
- Remove fontStyle/letterSpacing from TextPath (not needed)
- This should fix text disappearing when curved text is enabled
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Re-add x/y coordinates to TextPath for proper positioning within Group
- Add fontStyle and letterSpacing properties for complete font rendering
- Group remains draggable for movement
- Text content and font should now persist and render correctly when curves enabled
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Wrap TextPath in Group to enable dragging while preserving text on toggle
- Group handles x/y positioning and drag events
- TextPath is non-listening so Group events take priority
- Curved text can now be selected, dragged, and unchecked without losing content
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- TextPath positioning is handled by the path data, not x/y coordinates
- Removed x={el.x} and y={el.y} from TextPath to prevent coordinate corruption
- Removes drag handlers from TextPath since curves are centered on canvas
- Text now properly persists when toggling between curved and straight
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Initialize curvedPath: null when creating text elements
- Ensures all text elements have the curvedPath property from creation
- Prevents text loss when toggling curved text on/off
- Text content is now properly preserved when switching between curved and straight
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Remove Group wrapper that was preventing TextPath from receiving click events
- Make TextPath directly draggable and selectable with proper event handlers
- TextPath now supports: clicking to select, dragging to move, position persistence
- Users can now properly interact with curved text on the canvas
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Wrap TextPath in Group container to enable dragging of curved text
Previously curved text couldn't be moved on canvas. Now users can:
• Add curved text
• Move it by dragging
• Update position is saved correctly
- Confirm curved text is per-element: Each text element has its own
curvedPath property, so you can mix curved and straight text on the
same design (Font 1: circle, Font 2: wave, Font 3: straight, etc.)
- TextPath uses listening={false} since Group handles all interactions
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Fix: Redirect users back to product page after login by passing 'next' parameter
in LoginPromptModal. Previously users were redirected to /account and lost
design context. Now they return to where they started (e.g., /made-to-order/
classic-t-shirt) where design drafts are restored from localStorage.
- Fix: Clear design draft from localStorage only AFTER successful cart addition,
not immediately. This ensures draft persists if user needs to login mid-design.
- Feature: Add Font Properties boxes (Font 1, Font 2, etc.) similar to Image
Dimensions. Each text element now displays with editable controls for:
• Text content
• Font family (dropdown with all fonts)
• Font size (slider 10-80pt with display)
• Text color (color picker)
• Rotation (slider 0-360 degrees)
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Remove Reference Size input fields from customer design page
- Rulers now use product.referenceWidthCm and product.referenceHeightCm
- Reference size is set by admin when editing product (not customer)
- Simplify Add to bag validation - only check for design elements
- Remove reference size state from DesignCanvas component
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Add Reference Size (cm) section with Width and Height inputs
- Rulers now use reference size instead of product print area dimensions
- Measurements scale to garment size specified by user
- Add to bag button disabled until reference sizes are provided
- Rulers span full canvas and show custom scale (e.g., 0-40cm x 0-60cm)
- Reference size required for personalization checkout
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Add printAreaWidthMm and printAreaHeightMm to ProductDTO type
- Include these fields in toProductDTO conversion function
- Refactor ruler calculations to use simple for loops
- Rulers now display correctly showing 2cm increments on both axes
- Position & Size panel now shows accurate cm measurements
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>