142 lines
4.0 KiB
Vue
142 lines
4.0 KiB
Vue
<template>
|
|
<DesktopLandingPage
|
|
v-if="showDesktopLanding"
|
|
:services="landingServices"
|
|
:loading-services="loadingLandingServices"
|
|
:services-error="landingServicesError"
|
|
:booking-enabled="canBookSingleBusiness"
|
|
/>
|
|
|
|
<WebAppLayout v-else-if="showMobileLanding">
|
|
<HomeHeroSection
|
|
:show-book-button="canBookSingleBusiness"
|
|
@book="goToBooking"
|
|
@browse="scrollToServices"
|
|
/>
|
|
<HomeServicesSection
|
|
:items="landingServices"
|
|
:loading="loadingLandingServices"
|
|
:error="landingServicesError"
|
|
:booking-enabled="canBookSingleBusiness"
|
|
/>
|
|
<HomeFeatureBar />
|
|
</WebAppLayout>
|
|
|
|
<div
|
|
v-else-if="!tenant.loaded && isDesktop"
|
|
class="flex min-h-dvh items-center justify-center bg-white dark:bg-[#0d1117]"
|
|
>
|
|
<BusinessCardSkeleton class="w-full max-w-5xl px-8" />
|
|
</div>
|
|
|
|
<DesktopDiscoveryPage v-else-if="tenant.loaded && isDesktop" />
|
|
|
|
<WebAppLayout v-else>
|
|
<BusinessCardSkeleton v-if="!tenant.loaded" class="py-2" />
|
|
<HomeDiscoveryContent v-else />
|
|
</WebAppLayout>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { useMediaQuery } from '@vueuse/core';
|
|
import { computed, onMounted, ref, watch } from 'vue';
|
|
import { useRouter } from 'vue-router';
|
|
import HomeDiscoveryContent from '@/components/home/HomeDiscoveryContent.vue';
|
|
import HomeFeatureBar from '@/components/home/HomeFeatureBar.vue';
|
|
import HomeHeroSection from '@/components/home/HomeHeroSection.vue';
|
|
import HomeServicesSection from '@/components/home/HomeServicesSection.vue';
|
|
import DesktopDiscoveryPage from '@/components/landing/DesktopDiscoveryPage.vue';
|
|
import DesktopLandingPage from '@/components/landing/DesktopLandingPage.vue';
|
|
import BusinessCardSkeleton from '@/components/ui/BusinessCardSkeleton.vue';
|
|
import WebAppLayout from '@/layouts/WebAppLayout.vue';
|
|
import { useOwnedBusiness } from '@/composables/useOwnedBusiness';
|
|
import { useAuthStore } from '@/stores/auth';
|
|
import { useTenantStore } from '@/stores/tenant';
|
|
import type { LandingServiceItem } from '@/types/landing';
|
|
import { fetchLandingServices } from '@/utils/landing-services';
|
|
|
|
const isDesktop = useMediaQuery('(min-width: 1024px)');
|
|
const router = useRouter();
|
|
const auth = useAuthStore();
|
|
const tenant = useTenantStore();
|
|
const { ensureLoaded, isOwnBusiness } = useOwnedBusiness();
|
|
|
|
const landingServices = ref<LandingServiceItem[]>([]);
|
|
const loadingLandingServices = ref(false);
|
|
const landingServicesError = ref('');
|
|
|
|
const showDesktopLanding = computed(
|
|
() => tenant.loaded && tenant.isSingleBusiness && isDesktop.value,
|
|
);
|
|
|
|
const showMobileLanding = computed(
|
|
() => tenant.loaded && tenant.isSingleBusiness && !isDesktop.value,
|
|
);
|
|
|
|
const showSingleBusinessLanding = computed(
|
|
() => showDesktopLanding.value || showMobileLanding.value,
|
|
);
|
|
|
|
const canBookSingleBusiness = computed(() => {
|
|
const businessId = tenant.singleBusinessId;
|
|
if (!businessId) return true;
|
|
return !isOwnBusiness(businessId);
|
|
});
|
|
|
|
async function loadLandingServices() {
|
|
if (!tenant.singleBusinessId) return;
|
|
|
|
loadingLandingServices.value = true;
|
|
landingServicesError.value = '';
|
|
try {
|
|
landingServices.value = await fetchLandingServices(tenant.singleBusinessId);
|
|
} catch {
|
|
landingServices.value = [];
|
|
} finally {
|
|
loadingLandingServices.value = false;
|
|
}
|
|
}
|
|
|
|
function scrollToServices() {
|
|
const el = document.getElementById('services');
|
|
el?.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
}
|
|
|
|
function goToBooking() {
|
|
if (!canBookSingleBusiness.value) {
|
|
void router.push({ name: 'app-owner' });
|
|
return;
|
|
}
|
|
|
|
const id = tenant.singleBusinessId;
|
|
if (!id) {
|
|
scrollToServices();
|
|
return;
|
|
}
|
|
|
|
void router.push({
|
|
name: 'app-business-detail',
|
|
params: { id },
|
|
});
|
|
}
|
|
|
|
watch(showSingleBusinessLanding, (show) => {
|
|
if (show) {
|
|
void loadLandingServices();
|
|
}
|
|
});
|
|
|
|
onMounted(async () => {
|
|
if (auth.isLoggedIn) {
|
|
await auth.loadUser();
|
|
await ensureLoaded();
|
|
}
|
|
|
|
await tenant.bootstrap();
|
|
|
|
if (showSingleBusinessLanding.value) {
|
|
await loadLandingServices();
|
|
}
|
|
});
|
|
</script>
|