What I built.
Vaal Car Hire Website is part of my portfolio of websites and applications.
- Filterable fleet and vehicle detail views.
- Enquiry forms and WhatsApp contact paths.
- Authenticated CMS for fleet, categories, enquiries and settings.
- Page metadata, sitemap and structured data.
Under the hood.
Nuxt 4 / Vue
Public pages and staff interface
Supabase
Fleet data and authentication
Composables
Catalogue, listing, enquiries and SEO
Nuxt UI
Shared interface components
- Catalogue data
- Reactive category + filters
- Computed fleet list
- Vehicle details
- Enquiry
A closer look.
Finding the right vehicle
For a vehicle-hire business, a website needs to help someone answer a practical question: which vehicle suits my trip, and how do I get in touch? I approached Vaal Car Hire as a customer journey, from exploring the fleet to making an enquiry.
Inside useFleetListing
The fleet listing gets its source vehicles from useFleetCatalog. Filtering lives in utility functions, while computed values derive category counts, passenger bounds, price bounds and the visible vehicles. That keeps the page from becoming the place where every bit of fleet logic accumulates.
There is also a distinction between editing the filters and applying them. Until filtersApplied becomes true, the computed list clears the optional constraints before filtering. Sorting remains part of the filter state, with price_asc as the default.
A category should survive the URL
The category is synchronised with route.query.category. Changing it uses router.replace and preserves the other query parameters. The code maps the internal mini_bus category to minibuses in the URL, then normalises the incoming value when reading it back.
That is the kind of unglamorous detail I like discussing: internal identifiers, readable URLs and reactive state need to agree. The other filters are local reactive state in this composable; I would not describe the entire filter selection as shareable through the URL.
The customer is only half the audience
I treated content management as part of the product, rather than something to add after the public pages were finished. A fleet changes. Contact details change. The useful version of this website is one the business can keep current.
What I take from it
The lesson here is that a good business website has two audiences: the visitor trying to do something, and the person responsible for keeping it useful. Both deserve a clear interface.
