Contractor service catalog management inspired by Square, ServiceTitan, and Booksy — good-better-best pricing, bundled packages, coverage maps, and per-service analytics.
ServicesDashboard with drag-to-reorder category cards
useQuery(api.services.categories.list) · useMutation(api.services.categories.reorder)
ServiceEditor form with pricing mode segment control
useMutation(api.services.services.upsert) · useQuery(api.services.categories.list)
PricingTiers with ServiceTitan-inspired good/better/best layout
useQuery(api.services.tiers.byService) · useMutation(api.services.tiers.upsert)
ServicePackages with Booksy-inspired bundle discount display
useQuery(api.services.packages.list) · useMutation(api.services.packages.create)
ServiceAreaMap with Thumbtack-inspired radius & zip selection
useQuery(api.services.areas.get) · useMutation(api.services.areas.update)
CategoryManager with marketplace sync & match-rate indicator
useQuery(api.services.categories.withMatches) · useMutation(api.services.categories.syncMarketplace)
ServicePortfolio with before/after photos & linked testimonials
useQuery(api.services.portfolio.list) · useMutation(api.services.portfolio.importFromJobs)
ServiceAnalytics with funnel, rankings & market comparison
useQuery(api.services.analytics.dashboard) · useQuery(api.services.analytics.marketComparison)
serviceCategories // Plumbing, Electrical, etc.
serviceSubcategories // Water Heaters, Drains
services // Individual service listings
serviceTiers // Good/Better/Best per service
servicePackages // Bundled service groups
servicePackageItems // Package-service junction
serviceAreas // Coverage zones + travel fees
serviceAreaZips // Included/excluded zips
servicePortfolio // Project examples + photos
serviceAnalytics // Daily view/inquiry/booking
categories.list // With sub-count + status
categories.withMatches // Marketplace sync %
services.byCategory // Filtered service list
services.detail // Single service + tiers
tiers.byService // Good/Better/Best config
packages.list // All packages + savings
areas.get // Coverage + travel fees
portfolio.list // Projects + testimonials
analytics.dashboard // Metrics + funnel
analytics.marketComparison // Price vs avg
services.upsert
args: name, categoryId, description, pricing
categories.reorder
args: orderedIds[] // Drag-and-drop
tiers.upsert
args: serviceId, tiers[]{name, price, features}
packages.create
args: name, serviceIds[], discount%
areas.update
args: radius, freeWithin, perMile, zips[]
portfolio.importFromJobs
args: jobIds[] // Auto-populate
ServicesDashboard // FlatList + metrics
ServiceEditor // Full form + pricing mode
PricingTiers // Good/Better/Best cards
ServicePackages // Bundle list + savings
ServiceAreaMap // Leaflet + radius slider
CategoryManager // Tree view + sync
ServicePortfolio // Gallery + testimonials
ServiceAnalytics // Charts + funnel
useServiceCategories() // Cached category list
useServiceDetail(id) // Service + tiers
useServiceArea() // Coverage + zip state
useServiceAnalytics(range) // Time-filtered
useMarketComparison() // Price benchmarks
useDragReorder(list) // Reorder gesture
draft // Not yet published
→ active // Visible on marketplace
→ inactive // Hidden, keep data
→ archived // Soft-deleted
Package Statuses
active | seasonal | expired | draft