diff --git a/src/components/home/HomeBusinessCard.vue b/src/components/home/HomeBusinessCard.vue index 93c25a4..0c24a91 100644 --- a/src/components/home/HomeBusinessCard.vue +++ b/src/components/home/HomeBusinessCard.vue @@ -1,11 +1,11 @@ diff --git a/src/components/home/HomeBusinessList.vue b/src/components/home/HomeBusinessList.vue index a35f3bc..10c716f 100644 --- a/src/components/home/HomeBusinessList.vue +++ b/src/components/home/HomeBusinessList.vue @@ -17,7 +17,7 @@ v-else :class=" variant === 'featured' - ? 'grid grid-cols-1 gap-6 md:grid-cols-2 xl:grid-cols-3' + ? 'grid grid-cols-1 gap-4 sm:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4' : 'grid grid-cols-1 gap-2' " > diff --git a/src/components/home/HomeHeroSection.vue b/src/components/home/HomeHeroSection.vue index 0f36615..77dd1ed 100644 --- a/src/components/home/HomeHeroSection.vue +++ b/src/components/home/HomeHeroSection.vue @@ -72,7 +72,7 @@
(); const tenant = useTenantStore(); -const { singleBusiness } = storeToRefs(tenant); +const { landingBusiness } = storeToRefs(tenant); -const heroTitle = computed(() => singleBusiness.value?.title ?? ''); +const heroTitle = computed(() => landingBusiness.value?.title ?? ''); -const heroSubtitle = computed(() => singleBusiness.value?.subtitle?.trim() ?? ''); +const heroSubtitle = computed(() => landingBusiness.value?.subtitle?.trim() ?? ''); -const heroDescription = computed(() => singleBusiness.value?.description?.trim() ?? ''); +const heroDescription = computed(() => landingBusiness.value?.description?.trim() ?? ''); const highlights: { label: string; icon: AppIconName }[] = [ { label: 'رضایت مشتریان', icon: 'shield' }, diff --git a/src/components/home/HomeServicesSection.vue b/src/components/home/HomeServicesSection.vue index a0bf5db..09028a3 100644 --- a/src/components/home/HomeServicesSection.vue +++ b/src/components/home/HomeServicesSection.vue @@ -71,7 +71,7 @@ const gridClass = computed(() => { function serviceLink(item: LandingServiceItem) { if (!props.bookingEnabled) return '#services'; return { - name: 'app-business-detail', + name: 'app-business-book', params: { id: item.businessId }, hash: 'services', }; diff --git a/src/components/landing/DesktopLandingPage.vue b/src/components/landing/DesktopLandingPage.vue index 1a49edb..af41365 100644 --- a/src/components/landing/DesktopLandingPage.vue +++ b/src/components/landing/DesktopLandingPage.vue @@ -42,7 +42,7 @@ const props = withDefaults( const router = useRouter(); const auth = useAuthStore(); const tenant = useTenantStore(); -const { singleBusinessId } = storeToRefs(tenant); +const { landingBusinessId } = storeToRefs(tenant); function scrollToServices() { const el = document.getElementById('services'); @@ -55,7 +55,7 @@ function goToBooking() { return; } - const id = singleBusinessId.value; + const id = landingBusinessId.value; if (!id) { scrollToServices(); return; diff --git a/src/components/landing/MobileBusinessLanding.vue b/src/components/landing/MobileBusinessLanding.vue index 6c78197..b379a60 100644 --- a/src/components/landing/MobileBusinessLanding.vue +++ b/src/components/landing/MobileBusinessLanding.vue @@ -18,7 +18,7 @@ class="overflow-hidden rounded-2xl bg-slate-100 shadow-[0_8px_30px_rgba(15,23,42,0.12)] dark:bg-surface-2 dark:shadow-black/30" > @@ -132,11 +132,11 @@ const emit = defineEmits<{ }>(); const tenant = useTenantStore(); -const { singleBusiness } = storeToRefs(tenant); +const { landingBusiness } = storeToRefs(tenant); -const businessTitle = computed(() => singleBusiness.value?.title ?? ''); -const businessSubtitle = computed(() => singleBusiness.value?.subtitle?.trim() ?? ''); -const aboutText = computed(() => singleBusiness.value?.description?.trim() ?? ''); +const businessTitle = computed(() => landingBusiness.value?.title ?? ''); +const businessSubtitle = computed(() => landingBusiness.value?.subtitle?.trim() ?? ''); +const aboutText = computed(() => landingBusiness.value?.description?.trim() ?? ''); const quickActions: { id: string; diff --git a/src/components/shell/SiteFooter.vue b/src/components/shell/SiteFooter.vue index d65d731..63eb44b 100644 --- a/src/components/shell/SiteFooter.vue +++ b/src/components/shell/SiteFooter.vue @@ -80,23 +80,23 @@ import AppIcon from '@/components/ui/AppIcon.vue'; import { useTenantStore } from '@/stores/tenant'; const tenant = useTenantStore(); -const { brand, singleBusiness, isSingleBusiness } = storeToRefs(tenant); +const { brand, landingBusiness } = storeToRefs(tenant); const contactPhone = computed(() => { - if (isSingleBusiness.value && singleBusiness.value?.contactPhone) { - return singleBusiness.value.contactPhone; + if (landingBusiness.value?.contactPhone) { + return landingBusiness.value.contactPhone; } return '021-12345678'; }); const contactMobile = computed(() => { - if (isSingleBusiness.value) return null; + if (landingBusiness.value) return null; return '0912-123-4567'; }); const address = computed(() => { - if (isSingleBusiness.value && singleBusiness.value?.address) { - return singleBusiness.value.address; + if (landingBusiness.value?.address) { + return landingBusiness.value.address; } return 'تهران، خیابان ولیعصر، پلاک ۱۲۳'; }); diff --git a/src/router/index.ts b/src/router/index.ts index 9e942cd..0d62599 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -30,6 +30,11 @@ const router = createRouter({ name: 'app-business-detail', component: () => import('@/views/app/AppBusinessDetailView.vue'), }, + { + path: '/app/businesses/:id/book', + name: 'app-business-book', + component: () => import('@/views/app/AppBusinessBookingView.vue'), + }, { path: '/app/bookings', name: 'app-bookings', @@ -86,7 +91,10 @@ router.beforeEach(async (to) => { return auth.isBusinessOwner ? { name: 'app-owner' } : { name: 'app-home' }; } - if (to.name === 'app-business-detail' && auth.isBusinessOwner) { + if ( + (to.name === 'app-business-detail' || to.name === 'app-business-book') && + auth.isBusinessOwner + ) { const { ensureLoaded, isOwnBusiness } = useOwnedBusiness(); await ensureLoaded(); if (isOwnBusiness(String(to.params.id))) { diff --git a/src/stores/tenant.ts b/src/stores/tenant.ts index d676ef4..39f7bbb 100644 --- a/src/stores/tenant.ts +++ b/src/stores/tenant.ts @@ -10,22 +10,28 @@ export const useTenantStore = defineStore('tenant', () => { const loading = ref(false); const isSingleBusiness = ref(false); const singleBusiness = ref(null); + /** Business landing opened from multi-tenant discovery (not platform-wide single-business mode). */ + const focusedBusiness = ref(null); + + const landingBusiness = computed(() => + isSingleBusiness.value ? singleBusiness.value : focusedBusiness.value, + ); + + const landingBusinessId = computed(() => landingBusiness.value?.id ?? null); const brand = computed(() => { - const base = isSingleBusiness.value ? NIVASH_BRAND : MONTIME_BRAND; - - if (isSingleBusiness.value && singleBusiness.value) { + const biz = landingBusiness.value; + if (biz) { return { - ...base, - name: singleBusiness.value.title, - shortName: singleBusiness.value.title, - copyrightName: singleBusiness.value.title, - aboutText: - singleBusiness.value.description?.trim() || base.aboutText, + ...NIVASH_BRAND, + name: biz.title, + shortName: biz.title, + copyrightName: biz.title, + aboutText: biz.description?.trim() || NIVASH_BRAND.aboutText, }; } - return base; + return MONTIME_BRAND; }); const singleBusinessId = computed(() => singleBusiness.value?.id ?? null); @@ -35,6 +41,10 @@ export const useTenantStore = defineStore('tenant', () => { singleBusiness.value = business; } + function setFocusedBusiness(business: Business | null) { + focusedBusiness.value = business; + } + async function bootstrap() { if (loaded.value || loading.value) return; loading.value = true; @@ -68,8 +78,12 @@ export const useTenantStore = defineStore('tenant', () => { isSingleBusiness, singleBusiness, singleBusinessId, + focusedBusiness, + landingBusiness, + landingBusinessId, brand, bootstrap, syncSingleBusiness, + setFocusedBusiness, }; }); diff --git a/src/utils/auth-redirect.ts b/src/utils/auth-redirect.ts index afda856..bf49c84 100644 --- a/src/utils/auth-redirect.ts +++ b/src/utils/auth-redirect.ts @@ -20,7 +20,7 @@ export function loginRouteWithRedirect(redirectPath: string) { export function businessBookingPath(businessId: string, hash?: string) { const normalizedHash = hash?.replace(/^#/, ''); - const base = `/app/businesses/${businessId}`; + const base = `/app/businesses/${businessId}/book`; return normalizedHash ? `${base}#${normalizedHash}` : base; } @@ -35,7 +35,7 @@ export function bookingDestination( const normalizedHash = hash?.replace(/^#/, ''); return { - name: 'app-business-detail' as const, + name: 'app-business-book' as const, params: { id: businessId }, ...(normalizedHash ? { hash: normalizedHash } : {}), }; diff --git a/src/views/app/AppBusinessBookingView.vue b/src/views/app/AppBusinessBookingView.vue new file mode 100644 index 0000000..9f17c9b --- /dev/null +++ b/src/views/app/AppBusinessBookingView.vue @@ -0,0 +1,117 @@ + + + diff --git a/src/views/app/AppBusinessDetailView.vue b/src/views/app/AppBusinessDetailView.vue index cb77c97..dbe654f 100644 --- a/src/views/app/AppBusinessDetailView.vue +++ b/src/views/app/AppBusinessDetailView.vue @@ -1,114 +1,141 @@