The Quotes System is a comprehensive quote management platform that allows users to create quotes, add materials, submit quote requests, and track project timelines. Admins can manage quotes, add custom status tags, attach upsells/extras, and monitor project progress through an interactive timeline system.
✅ Multiple Quotes - Users can have multiple active quotes simultaneously ✅ Independent Quotes - Each quote is completely independent (not tied to a cart) ✅ Custom Requests - Support for text-based custom requests without products ✅ Auto-Expiration - Quotes expire after 30 days of inactivity ✅ Activity Tracking - Any activity extends the expiration by 30 days ✅ Source Tracking - Track where each material was added from ✅ Quote Requests - Convert quotes to formal quote requests ✅ Status Tags - Custom status tags with colors for quote organization ✅ Upsells/Extras - Admin-managed upsell items with customer acceptance tracking ✅ Project Timeline - Track project progress through predefined timeline steps ✅ Quote Acceptance - Customer quote acceptance with validation workflow ✅ Admin Management - Comprehensive admin interface for quote management
quotes TableStores core quote data. Key fields include: id, user_id, workspace_id, name (optional user-friendly name), status ('draft', 'submitted', 'quoted', 'accepted', 'rejected', 'expired'), status_tag_id, total_items, notes, custom_request_text, expires_at (defaults to 30 days), last_activity_at, created_at, updated_at, and submitted_at.
quote_items TableStores quote line items. Key fields include: id, quote_id, product_id, quantity, width, height, area, unit, notes, and added_from ('search', 'agent', '3d_generation', 'manual', 'product_page', 'moodboard'). A unique constraint prevents duplicate products in the same quote.
status_tags TableStores custom status tags. Fields include id, name, color (hex code), description, is_system (system tags cannot be deleted), and display_order. Default system tags are: pending, in_progress, quoted, accepted, rejected, and expired.
upsells TableAdmin-managed upsell items with id, name, description, price, is_active, and display_order.
quote_upsells Table (Junction)Links upsells to quotes. The customer_accepted field is null for pending, true for accepted, and false for rejected. A unique constraint prevents duplicate upsell entries per quote.
timeline_steps TableDefines the ordered steps in the project timeline: Quote Accepted, Materials Ordered, Materials Received, Production Started, Quality Check, Packaging, Shipped, Delivered, Project Completed.
quote_timeline TableTracks progress for each quote through the timeline steps. The status field can be 'pending', 'in_progress', 'completed', or 'skipped'. Includes notes, completed_at, and a unique constraint per quote/step combination.
expire_old_quotes() marks expired quotesThe system_settings table stores platform-wide configuration using a setting_key/setting_value JSONB pattern. The default setting for quote_expiration_days is 30.
Admins can update the expiration days via:
/admin/system-settingssystem_settings table where setting_key = 'quote_expiration_days'set_quote_expiration - Sets initial expiration when quote is created (uses current setting)update_quote_activity - Extends expiration when items are added/updated (uses current setting)update_quote_total_items - Keeps total_items count accurateget_quote_expiration_days() — Returns the current expiration days setting as an INTEGER (default: 30)expire_old_quotes() — Marks expired quotes; should be called daily; returns count of expired quotesQuotesService (src/services/quotes/QuotesService.ts)
Core Quote Operations:
createQuote() - Create new quotegetQuotes() - List user's quotesgetQuote() - Get quote with itemsupdateQuote() - Update quote details (including status)deleteQuote() - Delete draft quoteaddItem() - Add material to quoteupdateItem() - Update item quantity/notesremoveItem() - Remove item from quotesubmitQuote() - Convert to quote requestgetExpirationInfo() - Check expiration statusStatus Tags:
getStatusTags() - Get all status tagscreateStatusTag() - Create new status tagupdateQuoteStatusTag() - Assign status tag to quoteUpsells/Extras:
getUpsells() - Get all upsell itemscreateUpsell() - Create new upsell itemupdateUpsell() - Update upsell detailsdeleteUpsell() - Delete upsell itemgetQuoteUpsells() - Get upsells attached to quoteaddUpsellToQuote() - Attach upsell to quoteupdateUpsellAcceptance() - Customer accept/reject upsellremoveUpsellFromQuote() - Remove upsell from quoteProject Timeline:
getTimelineSteps() - Get all timeline stepscreateTimelineStep() - Create new timeline stepgetQuoteTimeline() - Get timeline for quoteinitializeQuoteTimeline() - Create timeline entries when quote acceptedupdateTimelineStep() - Update step status and notesAddToQuoteButton - Reusable button for adding materials
AddToQuoteModal - Quote selection/creation modal
QuoteManagementSidebar - Main quote management UI
QuoteBuilderView - Quote detail and material management
QuoteRequestModal - Customer quote view
QuoteDetailPage - Full-page admin quote management
QuoteRequestsAdmin - Admin quote list
StatusTagsManagement - Status tags admin page
UpsellsManagement - Upsells admin page
TimelineStepsManagement - Timeline steps admin page
ProjectTimelineModal - Project timeline viewer/editor
Use quotesService.createQuote() with an optional name and notes to create a new quote.
Either add specific products via quotesService.addItem() with quantity, dimensions, area, unit, notes, and source tracking — or add free-text custom requests via quotesService.updateQuote() with a custom_request_text field.
Call quotesService.submitQuote() with the quote ID and an optional message.
The system validates all extras are accepted or rejected, then changes quote status to 'accepted' and automatically initializes the project timeline.
/admin/quote-requestsUse quotesService.updateQuoteStatusTag() with the quote ID and status tag ID.
Use quotesService.addUpsellToQuote() with the quote ID and upsell ID.
Use quotesService.updateTimelineStep() with the timeline entry ID, status, and notes.
/admin/status-tags/admin/upsells/admin/timeline-stepsPlace AddToQuoteButton on product cards with productId, productName, productImage, and appropriate variant/size props.
Map over returned materials and render AddToQuoteButton for each with productId, productName, defaultQuantity, and added_from="agent".
Render AddToQuoteButton with added_from="3d_generation" on generated material cards.
Use quotesService.getExpirationInfo() to get days_until_expiration and is_expired for a given quote.
Any activity automatically extends expiration:
Create a Supabase Edge Function to run daily that calls the expire_old_quotes RPC and returns the count of expired quotes.
✅ Database Schema - All tables created
quotes - Core quote data with status and custom request supportquote_items - Quote items with dimensions and areastatus_tags - Custom status tags with 6 default system tagsupsells - Admin-managed upsell itemsquote_upsells - Junction table with customer acceptance trackingtimeline_steps - 9 predefined timeline stepsquote_timeline - Timeline progress trackingsystem_settings - Platform configuration✅ Migration Executed - All tables, triggers, functions, and RLS policies created
✅ QuotesService - Complete service with 30+ methods
✅ Customer Components
AddToQuoteButton - Reusable button componentAddToQuoteModal - Quote selection/creation modalQuoteManagementSidebar - Main quote management UIQuoteBuilderView - Quote detail and material managementQuoteRequestModal - Customer quote view with extras and timeline✅ Admin Components
QuoteDetailPage - Full-page admin quote management with tabsQuoteRequestsAdmin - Admin quote list with status filteringStatusTagsManagement - Status tags CRUD interfaceUpsellsManagement - Upsells CRUD interfaceTimelineStepsManagement - Timeline steps CRUD interfaceProjectTimelineModal - Timeline viewer/editor✅ Status Tags System
✅ Upsells/Extras System
✅ Project Timeline System
✅ Quote Acceptance Workflow
✅ Admin Configuration
✅ Custom Request Support
✅ Dimensions and Area Tracking
Quote Management:
/admin/quote-requests - View all quote requests with filtering/admin/quotes/:id - Full-page quote detail viewConfiguration:
/admin/status-tags - Manage custom status tags/admin/upsells - Manage upsell items/admin/timeline-steps - Manage timeline steps/admin/system-settings - Configure quote expiration daysAll quote operations are handled through the QuotesService which interfaces with Supabase:
Database Migrations:
supabase/migrations/20250106_quote_system_enhancements.sql - Status tags, upsells, timeline systemAll migrations have been executed and verified in production.
The quote items table includes FF&E (Furniture, Fixtures & Equipment) specification fields for interior design procurement workflows.
quote_items| Field | Type | Description |
|---|---|---|
room |
text | Room or area assignment (e.g., "Living Room", "Master Bedroom") |
dimensions |
text | Product dimensions in W×H×D format (e.g., "120×60×45") |
installation_requirements |
text | Installation notes (e.g., "Requires wall anchoring, electrical outlet within 1m") |
delivery_date |
date | Expected delivery date for procurement tracking |
QuotesService.addItem(), addCustomItem(), and updateItem() all accept the FF&E fields:
room?: stringdimensions?: stringinstallation_requirements?: stringdelivery_date?: string