Files
carmanagement/apps/api/src/modules/storefront/storefront.routes.ts
T
root 8aab968e09
Build & Deploy / Build & Push Docker Image (push) Successful in 1m2s
Test / Type Check (all packages) (push) Failing after 28s
Test / API Unit Tests (push) Has been skipped
Test / Homepage Unit Tests (push) Has been skipped
Test / Storefront Unit Tests (push) Has been skipped
Test / Admin Unit Tests (push) Has been skipped
Test / Dashboard Unit Tests (push) Has been skipped
Test / API Integration Tests (push) Has been skipped
Build & Deploy / Deploy to VPS (push) Successful in 3s
refactor: rename marketplace to storefront across the entire monorepo
Comprehensive rename of all marketplace references to storefront:
- API module: apps/api/src/modules/marketplace/ → storefront/
- Components: MarketplaceHeader → StorefrontHeader, MarketplaceShell →
  StorefrontShell, MarketplaceFooter → StorefrontFooter
- Types: marketplace-homepage.ts → storefront-homepage.ts
- Test files: employee-marketplace-* → employee-storefront-*
- All source code identifiers, imports, route paths, and strings
- Documentation (docs/), CI config (.gitlab-ci.yml), scripts
- Dashboard, admin, storefront workspace references
- Prisma field names preserved (isListedOnMarketplace, marketplaceRating,
  marketplaceFunnelEvent) as they map to database schema

Validation:
- API type-check: 0 errors
- Storefront type-check: 0 errors
- Dashboard type-check: 0 errors
- Full monorepo type-check: only pre-existing admin TS18046
2026-06-28 01:14:46 -04:00

177 lines
5.7 KiB
TypeScript

import { Router } from 'express'
import { optionalRenterAuth } from '../../middleware/requireRenterAuth'
import { parseBody, parseParams, parseQuery } from '../../http/validate'
import { ok, created } from '../../http/respond'
import { isDatabaseUnavailableError } from '../../lib/isDatabaseUnavailable'
import * as service from './storefront.service'
import {
paginationSchema, searchSchema, companiesQuerySchema, storefrontReservationSchema,
reviewBodySchema, slugParamSchema, vehicleParamSchema, reviewTokenSchema, offerCodeParamSchema,
vehicleAvailabilityQuerySchema, marketplaceFunnelEventSchema,
} from './storefront.schemas'
const router = Router()
router.use(optionalRenterAuth)
router.get('/offers', async (_req, res, next) => {
try {
ok(res, await service.getPublicOffers())
} catch (err) {
if (isDatabaseUnavailableError(err)) return res.json({ data: [] })
next(err)
}
})
router.get('/cities', async (_req, res, next) => {
try {
ok(res, await service.getCities())
} catch (err) {
if (isDatabaseUnavailableError(err)) return res.json({ data: [] })
next(err)
}
})
router.get('/companies', async (req, res, next) => {
try {
const { city, hasOffer } = parseQuery(companiesQuerySchema, req)
const { page, pageSize } = parseQuery(paginationSchema, req)
ok(res, await service.getListedCompanies({ city, hasOffer, page, pageSize }))
} catch (err) {
if (isDatabaseUnavailableError(err)) return res.json({ data: [] })
next(err)
}
})
router.get('/search', async (req, res, next) => {
try {
const filters = parseQuery(searchSchema, req)
const pagination = parseQuery(paginationSchema, req)
ok(res, await service.searchVehicles({ ...filters, ...pagination }))
} catch (err) {
if (isDatabaseUnavailableError(err)) return res.json({ data: [] })
next(err)
}
})
router.post('/reservations', async (req, res, next) => {
try {
const body = parseBody(storefrontReservationSchema, req)
const result = await service.createStorefrontReservation(body)
created(res, result)
} catch (err) {
if (isDatabaseUnavailableError(err)) {
return res.status(503).json({ error: 'database_unavailable', message: 'Service temporarily unavailable', statusCode: 503 })
}
next(err)
}
})
router.post('/events', async (req, res, next) => {
try {
const body = parseBody(marketplaceFunnelEventSchema, req)
ok(res, await service.trackStorefrontFunnelEvent(body, req.renterId))
} catch (err) {
if (isDatabaseUnavailableError(err)) {
return res.status(503).json({ error: 'database_unavailable', message: 'Analytics events are temporarily unavailable', statusCode: 503 })
}
next(err)
}
})
router.get('/review/:token', async (req, res, next) => {
try {
const { token } = parseParams(reviewTokenSchema, req)
ok(res, await service.getReviewContext(token))
} catch (err) { next(err) }
})
router.post('/review/:token', async (req, res, next) => {
try {
const { token } = parseParams(reviewTokenSchema, req)
const body = parseBody(reviewBodySchema, req)
const result = await service.submitReview(token, body)
created(res, result)
} catch (err) { next(err) }
})
router.post('/offers/:code/validate', async (req, res, next) => {
try {
const { code } = parseParams(offerCodeParamSchema, req)
ok(res, await service.validateOfferCode(code))
} catch (err) {
if (isDatabaseUnavailableError(err)) {
return res.status(503).json({ error: 'database_unavailable', message: 'Offer validation is temporarily unavailable', statusCode: 503 })
}
next(err)
}
})
router.get('/:slug', async (req, res, next) => {
try {
const { slug } = parseParams(slugParamSchema, req)
ok(res, await service.getCompanyPage(slug))
} catch (err) {
if (isDatabaseUnavailableError(err)) {
return res.status(503).json({ error: 'database_unavailable', message: 'Storefront data is temporarily unavailable', statusCode: 503 })
}
next(err)
}
})
router.get('/:slug/reviews', async (req, res, next) => {
try {
const { slug } = parseParams(slugParamSchema, req)
ok(res, await service.getCompanyReviews(slug))
} catch (err) {
if (isDatabaseUnavailableError(err)) return res.json({ data: [] })
next(err)
}
})
router.get('/:slug/vehicles', async (req, res, next) => {
try {
const { slug } = parseParams(slugParamSchema, req)
ok(res, await service.getCompanyVehicles(slug))
} catch (err) {
if (isDatabaseUnavailableError(err)) return res.json({ data: [] })
next(err)
}
})
router.get('/:slug/vehicles/:id', async (req, res, next) => {
try {
const { slug, id } = parseParams(vehicleParamSchema, req)
ok(res, await service.getVehicleDetail(slug, id))
} catch (err) {
if (isDatabaseUnavailableError(err)) {
return res.status(503).json({ error: 'database_unavailable', message: 'Vehicle details are temporarily unavailable', statusCode: 503 })
}
next(err)
}
})
router.get('/:slug/vehicles/:id/availability', async (req, res, next) => {
try {
const { slug, id } = parseParams(vehicleParamSchema, req)
const { startDate, endDate } = parseQuery(vehicleAvailabilityQuerySchema, req)
ok(res, await service.getStorefrontVehicleAvailability(slug, id, { startDate, endDate }))
} catch (err) {
if (isDatabaseUnavailableError(err)) {
return res.status(503).json({ error: 'database_unavailable', message: 'Availability checks are temporarily unavailable', statusCode: 503 })
}
next(err)
}
})
router.get('/:slug/offers', async (req, res, next) => {
try {
const { slug } = parseParams(slugParamSchema, req)
ok(res, await service.getCompanyOffers(slug))
} catch (err) {
if (isDatabaseUnavailableError(err)) return res.json({ data: [] })
next(err)
}
})
export default router