Add dedicated /pricing page and lock launch tiers to Free/Daily/Smart
Consolidate pricing onto a single source. Pro is deferred from launch (left dormant: no Stripe price, no card), so the offered set is 3 tiers. - Extract the pricing grid and footer into shared components (PricingGrid.vue, landing/SiteFooter.vue); add a /pricing route rendering Pricing.vue; remove the pricing section from Home - Repoint every upgrade link to the /pricing route (LandingNav and SiteFooter via RouterLink, UpsellBanner CTA) — no more #pricing anchors - Bump Smart (plus) SMS daily limit 1 -> 3 (PlanSeeder + PlanFactory), update PlanFeaturesTest assertion - Rewrite /pricing card bullets to match real entitlements (drop unbuilt promises: multi-location tracking, 14-day trend, supermarket anchor) - Fix stale "1/day" SMS references in notifications.md, tiers.md, docs/tiers.md - Delete unused resources/views/components/pricing-card.blade.php Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
125
resources/js/components/PricingGrid.vue
Normal file
125
resources/js/components/PricingGrid.vue
Normal file
@@ -0,0 +1,125 @@
|
||||
<template>
|
||||
<!-- Pricing -->
|
||||
<section id="pricing" class="py-4 md:py-24 px-6 bg-zinc-50">
|
||||
<div class="max-w-7xl mx-auto">
|
||||
<div class="text-center mb-16">
|
||||
<h2 class="text-4xl md:text-5xl font-black font-display text-zinc-800 mb-4">Pricing for every driver</h2>
|
||||
<p class="text-zinc-500 text-lg mb-8">Save hundreds for less than the cost of a coffee.</p>
|
||||
<div class="inline-flex items-center gap-1 p-1 bg-white border border-zinc-300 rounded-full">
|
||||
<button
|
||||
:class="cadence === 'monthly' ? 'bg-accent text-white' : 'text-zinc-500'"
|
||||
class="px-5 py-2 rounded-full text-sm font-bold transition-colors"
|
||||
type="button"
|
||||
@click="cadence = 'monthly'"
|
||||
>
|
||||
Monthly
|
||||
</button>
|
||||
<button
|
||||
:class="cadence === 'annual' ? 'bg-accent text-white' : 'text-zinc-500'"
|
||||
class="px-5 py-2 rounded-full text-sm font-bold transition-colors"
|
||||
type="button"
|
||||
@click="cadence = 'annual'"
|
||||
>
|
||||
Annual <span class="text-[10px] opacity-80">(save 17%)</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid sm:grid-cols-2 lg:grid-cols-3 gap-6 max-w-5xl mx-auto">
|
||||
<!-- Free -->
|
||||
<div class="bg-white border border-zinc-300 p-8 rounded-3xl flex flex-col h-full">
|
||||
<div class="mb-8">
|
||||
<h4 class="text-xl font-bold font-display mb-2">Free</h4>
|
||||
<div class="flex items-baseline gap-1">
|
||||
<span class="text-4xl font-black">£0</span>
|
||||
<span class="text-zinc-500 text-sm">/mo</span>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="space-y-4 mb-8 flex-1">
|
||||
<li class="text-sm flex gap-2"><iconify-icon class="text-accent" icon="lucide:check"></iconify-icon> Local station price search</li>
|
||||
<li class="text-sm flex gap-2"><iconify-icon class="text-accent" icon="lucide:check"></iconify-icon> Buy-or-wait verdict</li>
|
||||
<li class="text-sm flex gap-2 text-zinc-500"><iconify-icon class="text-zinc-300" icon="lucide:x"></iconify-icon> No price alerts</li>
|
||||
</ul>
|
||||
<a :href="ctaHref('free')" class="w-full py-3 px-4 border border-zinc-300 rounded-xl text-center font-bold hover:bg-zinc-100 transition-colors">{{ ctaLabel('free') }}</a>
|
||||
</div>
|
||||
|
||||
<!-- Daily (backend: basic) -->
|
||||
<div class="bg-white border border-zinc-300 p-8 rounded-3xl flex flex-col h-full">
|
||||
<div class="mb-8">
|
||||
<h4 class="text-xl font-bold font-display mb-2">Daily</h4>
|
||||
<div class="flex items-baseline gap-1">
|
||||
<span class="text-4xl font-black">{{ PRICES[cadence].basic }}</span>
|
||||
<span class="text-zinc-500 text-sm">{{ PRICE_SUFFIX[cadence] }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="space-y-4 mb-8 flex-1">
|
||||
<li class="text-sm flex gap-2"><iconify-icon class="text-accent" icon="lucide:check"></iconify-icon> Buy-or-wait score + reason</li>
|
||||
<li class="text-sm flex gap-2"><iconify-icon class="text-accent" icon="lucide:check"></iconify-icon> Daily email, push & WhatsApp</li>
|
||||
<li class="text-sm flex gap-2"><iconify-icon class="text-accent" icon="lucide:check"></iconify-icon> Price-drop & score alerts</li>
|
||||
</ul>
|
||||
<a :href="ctaHref('basic')" class="w-full py-3 px-4 border border-zinc-300 rounded-xl text-center font-bold hover:bg-zinc-100 transition-colors">{{ ctaLabel('basic') }}</a>
|
||||
</div>
|
||||
|
||||
<!-- Smart (backend: plus) -->
|
||||
<div class="bg-white border-2 border-accent p-8 rounded-3xl flex flex-col h-full relative">
|
||||
<div class="absolute -top-4 left-1/2 -translate-x-1/2 bg-accent text-white px-4 py-1 rounded-full text-[10px] font-black uppercase tracking-widest whitespace-nowrap">Most pick this</div>
|
||||
<div class="mb-8">
|
||||
<h4 class="text-xl font-bold font-display mb-2">Smart</h4>
|
||||
<div class="flex items-baseline gap-1">
|
||||
<span class="text-4xl font-black text-accent">{{ PRICES[cadence].plus }}</span>
|
||||
<span class="text-zinc-500 text-sm">{{ PRICE_SUFFIX[cadence] }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="space-y-4 mb-8 flex-1">
|
||||
<li class="text-sm flex gap-2 font-bold"><iconify-icon class="text-accent" icon="lucide:check"></iconify-icon> AI fuel-price prediction</li>
|
||||
<li class="text-sm flex gap-2"><iconify-icon class="text-accent" icon="lucide:check"></iconify-icon> Real-time email, push & WhatsApp</li>
|
||||
<li class="text-sm flex gap-2"><iconify-icon class="text-accent" icon="lucide:check"></iconify-icon> SMS alerts (up to 3/day)</li>
|
||||
</ul>
|
||||
<a :href="ctaHref('plus')" class="w-full py-3 px-4 bg-accent text-white rounded-xl text-center font-bold shadow-lg hover:bg-primary-dark transition-all">{{ ctaLabel('plus') }}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { useAuth } from '../composables/useAuth.js'
|
||||
|
||||
const { isAuthenticated, userTier } = useAuth()
|
||||
|
||||
const cadence = ref('monthly')
|
||||
|
||||
const PRICES = {
|
||||
monthly: { basic: '£0.99', plus: '£2.49', pro: '£3.99' },
|
||||
annual: { basic: '£9.90', plus: '£24.90', pro: '£39.90' },
|
||||
}
|
||||
const PRICE_SUFFIX = { monthly: '/mo', annual: '/yr' }
|
||||
|
||||
function ctaHref(tier) {
|
||||
if (tier === 'free') {
|
||||
return isAuthenticated.value ? '/dashboard' : '/register'
|
||||
}
|
||||
if (!isAuthenticated.value) {
|
||||
return '/register?tier=' + tier + '&cadence=' + cadence.value
|
||||
}
|
||||
if (userTier.value === tier) {
|
||||
return '/billing/portal'
|
||||
}
|
||||
return '/billing/checkout/' + tier + '/' + cadence.value
|
||||
}
|
||||
|
||||
function ctaLabel(tier) {
|
||||
if (tier === 'free') {
|
||||
return isAuthenticated.value ? 'Go to dashboard' : 'Start free'
|
||||
}
|
||||
if (isAuthenticated.value && userTier.value === tier) {
|
||||
return 'Manage subscription'
|
||||
}
|
||||
return {
|
||||
basic: 'Choose Daily',
|
||||
plus: 'Choose Smart',
|
||||
pro: 'Choose Pro',
|
||||
}[tier]
|
||||
}
|
||||
</script>
|
||||
@@ -47,6 +47,6 @@ const stationCountLabel = computed(() => {
|
||||
return new Intl.NumberFormat('en-GB').format(props.stationCount)
|
||||
})
|
||||
|
||||
const ctaHref = computed(() => isAuthenticated.value ? '#pricing' : '/register?tier=plus&cadence=monthly')
|
||||
const ctaHref = computed(() => isAuthenticated.value ? '/pricing' : '/register?tier=plus&cadence=monthly')
|
||||
const ctaLabel = computed(() => isAuthenticated.value ? 'See plans' : 'Start saving')
|
||||
</script>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<div class="hidden lg:flex items-center gap-8 font-mono text-[11px] uppercase tracking-widest text-zinc-600">
|
||||
<a class="hover:text-accent transition-colors" href="#how-it-works">How it works</a>
|
||||
<a class="hover:text-accent transition-colors" href="#features">Why it works</a>
|
||||
<a class="hover:text-accent transition-colors" href="#pricing">Pricing</a>
|
||||
<RouterLink class="hover:text-accent transition-colors" to="/pricing">Pricing</RouterLink>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-3 md:gap-5">
|
||||
|
||||
66
resources/js/components/landing/SiteFooter.vue
Normal file
66
resources/js/components/landing/SiteFooter.vue
Normal file
@@ -0,0 +1,66 @@
|
||||
<template>
|
||||
<!-- Footer -->
|
||||
<footer class="bg-zinc-50 border-t border-zinc-300 pt-16 pb-8 px-6">
|
||||
<div class="max-w-7xl mx-auto grid grid-cols-2 md:grid-cols-4 gap-12 mb-12">
|
||||
<div class="col-span-2 md:col-span-1 space-y-4">
|
||||
<RouterLink class="flex items-center gap-2" to="/">
|
||||
<div class="w-8 h-8 rounded bg-accent flex items-center justify-center">
|
||||
<iconify-icon class="text-white" icon="lucide:fuel"></iconify-icon>
|
||||
</div>
|
||||
<span class="text-xl font-black font-display tracking-tighter text-accent">FuelAlert</span>
|
||||
</RouterLink>
|
||||
<p class="text-sm text-zinc-500 leading-relaxed">
|
||||
Helping UK drivers save money at the pump. Real-time data, smarter choices.
|
||||
</p>
|
||||
<p class="text-sm text-zinc-500">
|
||||
Questions? <a class="text-accent hover:underline" href="mailto:hello@fuel-alert.co.uk">hello@fuel-alert.co.uk</a>
|
||||
</p>
|
||||
<div class="flex gap-4">
|
||||
<iconify-icon class="text-2xl text-zinc-500 hover:text-accent cursor-pointer transition-colors" icon="mdi:twitter"></iconify-icon>
|
||||
<iconify-icon class="text-2xl text-zinc-500 hover:text-accent cursor-pointer transition-colors" icon="mdi:facebook"></iconify-icon>
|
||||
<iconify-icon class="text-2xl text-zinc-500 hover:text-accent cursor-pointer transition-colors" icon="mdi:instagram"></iconify-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-y-4">
|
||||
<h5 class="font-black text-xs text-zinc-800 tracking-widest">Product</h5>
|
||||
<ul class="space-y-2 text-sm text-zinc-500">
|
||||
<li><RouterLink class="hover:text-accent transition-colors" to="/pricing">Pricing</RouterLink></li>
|
||||
<li><a class="hover:text-accent transition-colors" href="#features">Features</a></li>
|
||||
<li><a class="hover:text-accent transition-colors" href="#">FuelAlert Pro</a></li>
|
||||
<li><a class="hover:text-accent transition-colors" href="#">Enterprise API</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="space-y-4">
|
||||
<h5 class="font-black text-xs text-zinc-800 tracking-widest">Resources</h5>
|
||||
<ul class="space-y-2 text-sm text-zinc-500">
|
||||
<li><a class="hover:text-accent transition-colors" href="#">Market Insights</a></li>
|
||||
<li><a class="hover:text-accent transition-colors" href="#">How We Track</a></li>
|
||||
<li><a class="hover:text-accent transition-colors" href="#">Help Center</a></li>
|
||||
<li><a class="hover:text-accent transition-colors" href="#">Driver Safety</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="space-y-4">
|
||||
<h5 class="font-black text-xs text-zinc-800 tracking-widest">Legal</h5>
|
||||
<ul class="space-y-2 text-sm text-zinc-500">
|
||||
<li><a class="hover:text-accent transition-colors" href="/legal/privacy">Privacy Policy</a></li>
|
||||
<li><a class="hover:text-accent transition-colors" href="/legal/terms">Terms of Service</a></li>
|
||||
<li><a class="hover:text-accent transition-colors" href="/legal/refund">Refund & Cancellation</a></li>
|
||||
<li><a class="hover:text-accent transition-colors" href="/legal/cookies">Cookie Policy</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="max-w-7xl mx-auto pt-8 border-t border-zinc-300 flex flex-col md:flex-row justify-between items-center gap-4 text-[10px] tracking-widest text-zinc-500">
|
||||
<p>© 2026 FuelAlert UK. FuelAlert is a trading name of Ovidiu Ungureanu, sole trader, based in Peterborough, UK.</p>
|
||||
<p>Data provided by official UK retail price transparency schemes.</p>
|
||||
<p>Postcode data from <a class="underline hover:text-accent" href="https://geoportal.statistics.gov.uk/datasets/ons::onspd-online-latest-centroids-1/about" rel="noopener" target="_blank">ONS Postcode Directory</a>: contains OS data © Crown copyright & database right, Royal Mail data © Royal Mail copyright & database right, and National Statistics data © Crown copyright & database right.</p>
|
||||
</div>
|
||||
</footer>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { RouterLink } from 'vue-router'
|
||||
</script>
|
||||
@@ -2,6 +2,7 @@ import { createRouter, createWebHistory } from 'vue-router'
|
||||
import Home from '../views/Home.vue'
|
||||
import { useAuth } from '../composables/useAuth.js'
|
||||
|
||||
const Pricing = () => import('../views/Pricing.vue')
|
||||
const DashboardLayout = () => import('../views/dashboard/DashboardLayout.vue')
|
||||
const Overview = () => import('../views/dashboard/Overview.vue')
|
||||
const SavedStations = () => import('../views/dashboard/SavedStations.vue')
|
||||
@@ -13,6 +14,7 @@ const Appearance = () => import('../views/dashboard/settings/Appearance.vue')
|
||||
|
||||
const routes = [
|
||||
{ path: '/', component: Home, name: 'home' },
|
||||
{ path: '/pricing', component: Pricing, name: 'pricing' },
|
||||
{
|
||||
path: '/logout',
|
||||
name: 'logout',
|
||||
|
||||
@@ -225,88 +225,6 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Pricing -->
|
||||
<section id="pricing" class="py-4 md:py-24 px-6 bg-zinc-50">
|
||||
<div class="max-w-7xl mx-auto">
|
||||
<div class="text-center mb-16">
|
||||
<h2 class="text-4xl md:text-5xl font-black font-display text-zinc-800 mb-4">Pricing for every driver</h2>
|
||||
<p class="text-zinc-500 text-lg mb-8">Save hundreds for less than the cost of a coffee.</p>
|
||||
<div class="inline-flex items-center gap-1 p-1 bg-white border border-zinc-300 rounded-full">
|
||||
<button
|
||||
:class="cadence === 'monthly' ? 'bg-accent text-white' : 'text-zinc-500'"
|
||||
class="px-5 py-2 rounded-full text-sm font-bold transition-colors"
|
||||
type="button"
|
||||
@click="cadence = 'monthly'"
|
||||
>
|
||||
Monthly
|
||||
</button>
|
||||
<button
|
||||
:class="cadence === 'annual' ? 'bg-accent text-white' : 'text-zinc-500'"
|
||||
class="px-5 py-2 rounded-full text-sm font-bold transition-colors"
|
||||
type="button"
|
||||
@click="cadence = 'annual'"
|
||||
>
|
||||
Annual <span class="text-[10px] opacity-80">(save 17%)</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid sm:grid-cols-2 lg:grid-cols-3 gap-6 max-w-5xl mx-auto">
|
||||
<!-- Free -->
|
||||
<div class="bg-white border border-zinc-300 p-8 rounded-3xl flex flex-col h-full">
|
||||
<div class="mb-8">
|
||||
<h4 class="text-xl font-bold font-display mb-2">Free</h4>
|
||||
<div class="flex items-baseline gap-1">
|
||||
<span class="text-4xl font-black">£0</span>
|
||||
<span class="text-zinc-500 text-sm">/mo</span>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="space-y-4 mb-8 flex-1">
|
||||
<li class="text-sm flex gap-2"><iconify-icon class="text-accent" icon="lucide:check"></iconify-icon> Basic Search</li>
|
||||
<li class="text-sm flex gap-2"><iconify-icon class="text-accent" icon="lucide:check"></iconify-icon> Daily Updates</li>
|
||||
<li class="text-sm flex gap-2 text-zinc-500"><iconify-icon class="text-zinc-300" icon="lucide:x"></iconify-icon> No Alerts</li>
|
||||
</ul>
|
||||
<a :href="ctaHref('free')" class="w-full py-3 px-4 border border-zinc-300 rounded-xl text-center font-bold hover:bg-zinc-100 transition-colors">{{ ctaLabel('free') }}</a>
|
||||
</div>
|
||||
|
||||
<!-- Daily (backend: basic) -->
|
||||
<div class="bg-white border border-zinc-300 p-8 rounded-3xl flex flex-col h-full">
|
||||
<div class="mb-8">
|
||||
<h4 class="text-xl font-bold font-display mb-2">Daily</h4>
|
||||
<div class="flex items-baseline gap-1">
|
||||
<span class="text-4xl font-black">{{ PRICES[cadence].basic }}</span>
|
||||
<span class="text-zinc-500 text-sm">{{ PRICE_SUFFIX[cadence] }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="space-y-4 mb-8 flex-1">
|
||||
<li class="text-sm flex gap-2"><iconify-icon class="text-accent" icon="lucide:check"></iconify-icon> Buy-or-Wait Score</li>
|
||||
<li class="text-sm flex gap-2"><iconify-icon class="text-accent" icon="lucide:check"></iconify-icon> 14-day Trend Data</li>
|
||||
<li class="text-sm flex gap-2"><iconify-icon class="text-accent" icon="lucide:check"></iconify-icon> 3 Daily Price Alerts</li>
|
||||
</ul>
|
||||
<a :href="ctaHref('basic')" class="w-full py-3 px-4 border border-zinc-300 rounded-xl text-center font-bold hover:bg-zinc-100 transition-colors">{{ ctaLabel('basic') }}</a>
|
||||
</div>
|
||||
|
||||
<!-- Smart (backend: plus) -->
|
||||
<div class="bg-white border-2 border-accent p-8 rounded-3xl flex flex-col h-full relative">
|
||||
<div class="absolute -top-4 left-1/2 -translate-x-1/2 bg-accent text-white px-4 py-1 rounded-full text-[10px] font-black uppercase tracking-widest whitespace-nowrap">Most pick this</div>
|
||||
<div class="mb-8">
|
||||
<h4 class="text-xl font-bold font-display mb-2">Smart</h4>
|
||||
<div class="flex items-baseline gap-1">
|
||||
<span class="text-4xl font-black text-accent">{{ PRICES[cadence].plus }}</span>
|
||||
<span class="text-zinc-500 text-sm">{{ PRICE_SUFFIX[cadence] }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="space-y-4 mb-8 flex-1">
|
||||
<li class="text-sm flex gap-2 font-bold"><iconify-icon class="text-accent" icon="lucide:check"></iconify-icon> Supermarket Anchor</li>
|
||||
<li class="text-sm flex gap-2"><iconify-icon class="text-accent" icon="lucide:check"></iconify-icon> Priority Price Alerts</li>
|
||||
<li class="text-sm flex gap-2"><iconify-icon class="text-accent" icon="lucide:check"></iconify-icon> Multi-location tracking</li>
|
||||
</ul>
|
||||
<a :href="ctaHref('plus')" class="w-full py-3 px-4 bg-accent text-white rounded-xl text-center font-bold shadow-lg hover:bg-primary-dark transition-all">{{ ctaLabel('plus') }}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Testimonials -->
|
||||
<!-- <section class="py-12 md:py-24 px-6">
|
||||
<div class="max-w-7xl mx-auto">
|
||||
@@ -360,72 +278,14 @@
|
||||
</section>
|
||||
|
||||
<!-- Footer -->
|
||||
<footer class="bg-zinc-50 border-t border-zinc-300 pt-16 pb-8 px-6">
|
||||
<div class="max-w-7xl mx-auto grid grid-cols-2 md:grid-cols-4 gap-12 mb-12">
|
||||
<div class="col-span-2 md:col-span-1 space-y-4">
|
||||
<RouterLink class="flex items-center gap-2" to="/">
|
||||
<div class="w-8 h-8 rounded bg-accent flex items-center justify-center">
|
||||
<iconify-icon class="text-white" icon="lucide:fuel"></iconify-icon>
|
||||
</div>
|
||||
<span class="text-xl font-black font-display tracking-tighter text-accent">FuelAlert</span>
|
||||
</RouterLink>
|
||||
<p class="text-sm text-zinc-500 leading-relaxed">
|
||||
Helping UK drivers save money at the pump. Real-time data, smarter choices.
|
||||
</p>
|
||||
<p class="text-sm text-zinc-500">
|
||||
Questions? <a class="text-accent hover:underline" href="mailto:hello@fuel-alert.co.uk">hello@fuel-alert.co.uk</a>
|
||||
</p>
|
||||
<div class="flex gap-4">
|
||||
<iconify-icon class="text-2xl text-zinc-500 hover:text-accent cursor-pointer transition-colors" icon="mdi:twitter"></iconify-icon>
|
||||
<iconify-icon class="text-2xl text-zinc-500 hover:text-accent cursor-pointer transition-colors" icon="mdi:facebook"></iconify-icon>
|
||||
<iconify-icon class="text-2xl text-zinc-500 hover:text-accent cursor-pointer transition-colors" icon="mdi:instagram"></iconify-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-y-4">
|
||||
<h5 class="font-black text-xs text-zinc-800 tracking-widest">Product</h5>
|
||||
<ul class="space-y-2 text-sm text-zinc-500">
|
||||
<li><a class="hover:text-accent transition-colors" href="#pricing">Pricing</a></li>
|
||||
<li><a class="hover:text-accent transition-colors" href="#features">Features</a></li>
|
||||
<li><a class="hover:text-accent transition-colors" href="#">FuelAlert Pro</a></li>
|
||||
<li><a class="hover:text-accent transition-colors" href="#">Enterprise API</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="space-y-4">
|
||||
<h5 class="font-black text-xs text-zinc-800 tracking-widest">Resources</h5>
|
||||
<ul class="space-y-2 text-sm text-zinc-500">
|
||||
<li><a class="hover:text-accent transition-colors" href="#">Market Insights</a></li>
|
||||
<li><a class="hover:text-accent transition-colors" href="#">How We Track</a></li>
|
||||
<li><a class="hover:text-accent transition-colors" href="#">Help Center</a></li>
|
||||
<li><a class="hover:text-accent transition-colors" href="#">Driver Safety</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="space-y-4">
|
||||
<h5 class="font-black text-xs text-zinc-800 tracking-widest">Legal</h5>
|
||||
<ul class="space-y-2 text-sm text-zinc-500">
|
||||
<li><a class="hover:text-accent transition-colors" href="/legal/privacy">Privacy Policy</a></li>
|
||||
<li><a class="hover:text-accent transition-colors" href="/legal/terms">Terms of Service</a></li>
|
||||
<li><a class="hover:text-accent transition-colors" href="/legal/refund">Refund & Cancellation</a></li>
|
||||
<li><a class="hover:text-accent transition-colors" href="/legal/cookies">Cookie Policy</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="max-w-7xl mx-auto pt-8 border-t border-zinc-300 flex flex-col md:flex-row justify-between items-center gap-4 text-[10px] tracking-widest text-zinc-500">
|
||||
<p>© 2026 FuelAlert UK. FuelAlert is a trading name of Ovidiu Ungureanu, sole trader, based in Peterborough, UK.</p>
|
||||
<p>Data provided by official UK retail price transparency schemes.</p>
|
||||
<p>Postcode data from <a class="underline hover:text-accent" href="https://geoportal.statistics.gov.uk/datasets/ons::onspd-online-latest-centroids-1/about" rel="noopener" target="_blank">ONS Postcode Directory</a>: contains OS data © Crown copyright & database right, Royal Mail data © Royal Mail copyright & database right, and National Statistics data © Crown copyright & database right.</p>
|
||||
</div>
|
||||
</footer>
|
||||
<SiteFooter />
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch, onMounted, nextTick, defineAsyncComponent } from 'vue'
|
||||
import { RouterLink, useRoute, useRouter } from 'vue-router'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { useAuth } from '../composables/useAuth.js'
|
||||
import { useStations } from '../composables/useStations.js'
|
||||
import api from '../axios.js'
|
||||
@@ -441,8 +301,9 @@ import LiveTicker from '../components/landing/LiveTicker.vue'
|
||||
import VerdictCard from '../components/landing/VerdictCard.vue'
|
||||
import HeroSearch from '../components/landing/HeroSearch.vue'
|
||||
import StatsRow from '../components/landing/StatsRow.vue'
|
||||
import SiteFooter from '../components/landing/SiteFooter.vue'
|
||||
|
||||
const { isAuthenticated, userTier } = useAuth()
|
||||
const { isAuthenticated } = useAuth()
|
||||
|
||||
const liveStats = ref({ stationCount: null, latestPriceAt: null })
|
||||
|
||||
@@ -458,40 +319,6 @@ onMounted(async () => {
|
||||
}
|
||||
})
|
||||
|
||||
const cadence = ref('monthly')
|
||||
|
||||
function ctaHref(tier) {
|
||||
if (tier === 'free') {
|
||||
return isAuthenticated.value ? '/dashboard' : '/register'
|
||||
}
|
||||
if (!isAuthenticated.value) {
|
||||
return '/register?tier=' + tier + '&cadence=' + cadence.value
|
||||
}
|
||||
if (userTier.value === tier) {
|
||||
return '/billing/portal'
|
||||
}
|
||||
return '/billing/checkout/' + tier + '/' + cadence.value
|
||||
}
|
||||
|
||||
function ctaLabel(tier) {
|
||||
if (tier === 'free') {
|
||||
return isAuthenticated.value ? 'Go to dashboard' : 'Start free'
|
||||
}
|
||||
if (isAuthenticated.value && userTier.value === tier) {
|
||||
return 'Manage subscription'
|
||||
}
|
||||
return {
|
||||
basic: 'Choose Daily',
|
||||
plus: 'Choose Smart',
|
||||
pro: 'Choose Pro',
|
||||
}[tier]
|
||||
}
|
||||
|
||||
const PRICES = {
|
||||
monthly: { basic: '£0.99', plus: '£2.49', pro: '£3.99' },
|
||||
annual: { basic: '£9.90', plus: '£24.90', pro: '£39.90' },
|
||||
}
|
||||
const PRICE_SUFFIX = { monthly: '/mo', annual: '/yr' }
|
||||
const { stations, meta, prediction, loading, error, search, reset } = useStations()
|
||||
const showFullPrediction = computed(() => Boolean(prediction.value) && !prediction.value.tier_locked)
|
||||
|
||||
|
||||
15
resources/js/views/Pricing.vue
Normal file
15
resources/js/views/Pricing.vue
Normal file
@@ -0,0 +1,15 @@
|
||||
<template>
|
||||
<div class="min-h-screen bg-zinc-50">
|
||||
<LandingNav />
|
||||
<main class="pt-20 md:pt-24">
|
||||
<PricingGrid />
|
||||
</main>
|
||||
<SiteFooter />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import LandingNav from '../components/landing/LandingNav.vue'
|
||||
import PricingGrid from '../components/PricingGrid.vue'
|
||||
import SiteFooter from '../components/landing/SiteFooter.vue'
|
||||
</script>
|
||||
@@ -1,55 +0,0 @@
|
||||
@props([
|
||||
'name',
|
||||
'price',
|
||||
'buttonText',
|
||||
'perks' => [],
|
||||
'featured' => false,
|
||||
'dark' => false,
|
||||
])
|
||||
|
||||
@php
|
||||
$cardClass = match(true) {
|
||||
$dark => 'bg-primary border border-primary text-white',
|
||||
$featured => 'bg-white border-2 border-primary',
|
||||
default => 'bg-white border border-zinc-300',
|
||||
};
|
||||
|
||||
$buttonClass = $dark
|
||||
? 'bg-white text-primary hover:bg-zinc-100'
|
||||
: 'bg-primary text-white hover:bg-primary-dark';
|
||||
@endphp
|
||||
|
||||
<div {{ $attributes->merge(['class' => "p-8 rounded-3xl flex flex-col relative $cardClass"]) }}>
|
||||
|
||||
@if ($featured)
|
||||
<div class="absolute -top-4 left-1/2 -translate-x-1/2 bg-primary text-white px-4 py-1 rounded-full text-[10px] font-black uppercase tracking-widest whitespace-nowrap">
|
||||
Most Popular
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="flex items-baseline justify-between mb-6">
|
||||
<h4 class="text-xl font-bold">{{ $name }}</h4>
|
||||
<div class="flex items-baseline gap-1">
|
||||
<span @class(['text-3xl font-black', 'text-primary' => $featured])>{{ $price }}</span>
|
||||
<span @class(['text-sm', 'text-zinc-500' => !$dark, 'text-zinc-400' => $dark])>/mo</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ul class="space-y-2 mb-6 flex-1">
|
||||
@foreach ($perks as $perk)
|
||||
<li @class(['text-sm flex gap-2 items-center', 'text-zinc-500' => !$perk['included'] && !$dark])>
|
||||
@if ($perk['included'])
|
||||
<iconify-icon icon="lucide:check" class="text-primary shrink-0"></iconify-icon>
|
||||
@else
|
||||
<iconify-icon icon="lucide:x" class="text-zinc-300 shrink-0"></iconify-icon>
|
||||
@endif
|
||||
{{ $perk['text'] }}
|
||||
</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
|
||||
<a href="{{ route('register') }}" class="w-full py-2.5 px-6 {{ $buttonClass }} rounded-full text-sm text-center font-bold shadow-lg transition-all hover:scale-105 active:scale-95">
|
||||
{{ $buttonText }}
|
||||
</a>
|
||||
|
||||
</div>
|
||||
Reference in New Issue
Block a user