178 lines
5.6 KiB
Vue
178 lines
5.6 KiB
Vue
<script setup>
|
|
import { ref, computed, onMounted } from 'vue';
|
|
import axios from 'axios';
|
|
import { useNavigate } from '../../../composables/Core/useNavigate.js';
|
|
|
|
// Core Components
|
|
import ServiceButtonGrid from '../../../Components/Core/Services/ServiceButtonGrid.vue';
|
|
import SideTextButtonList from '../../../Components/Core/Services/SideTextButtonList.vue';
|
|
import CardSimple from '../../../Components/Core/CardSimple.vue';
|
|
import GlobalAnnouncement from '../../../Components/GlobalAnnouncement.vue';
|
|
|
|
import { useUIStore } from '../../../stores/ui';
|
|
|
|
const { navigate } = useNavigate();
|
|
const uiStore = useUIStore();
|
|
|
|
const landingPageHtml = ref(null);
|
|
const hasLandingPage = ref(false);
|
|
const loadingLanding = ref(true);
|
|
|
|
// Fetch the active landing page
|
|
const fetchLandingPage = async () => {
|
|
loadingLanding.value = true;
|
|
try {
|
|
const res = await axios.get('/api/public/landing-page');
|
|
if (res.data.success && res.data.has_landing_page && res.data.data) {
|
|
landingPageHtml.value = res.data.data.html_content;
|
|
hasLandingPage.value = true;
|
|
uiStore.setFullWidth(true);
|
|
|
|
// Hide global app UI for a clean landing page experience
|
|
uiStore.setHeaderVisibility(false);
|
|
uiStore.setBottomNavVisibility(false);
|
|
} else {
|
|
hasLandingPage.value = false;
|
|
uiStore.setFullWidth(false);
|
|
uiStore.setHeaderVisibility(true);
|
|
uiStore.setBottomNavVisibility(true);
|
|
}
|
|
} catch (err) {
|
|
hasLandingPage.value = false;
|
|
uiStore.setFullWidth(false);
|
|
uiStore.setHeaderVisibility(true);
|
|
uiStore.setBottomNavVisibility(true);
|
|
} finally {
|
|
loadingLanding.value = false;
|
|
}
|
|
};
|
|
|
|
// Also ensure we reset full width if this fragment is unmounted
|
|
import { onUnmounted, watch } from 'vue';
|
|
onUnmounted(() => {
|
|
uiStore.setFullWidth(false);
|
|
uiStore.setHeaderVisibility(true);
|
|
uiStore.setBottomNavVisibility(true);
|
|
});
|
|
|
|
// Watch for changes in hasLandingPage to update UI store
|
|
watch(hasLandingPage, (newVal) => {
|
|
uiStore.setFullWidth(newVal);
|
|
});
|
|
|
|
onMounted(() => {
|
|
fetchLandingPage();
|
|
});
|
|
|
|
// Services for public users (no auth required)
|
|
const services = computed(() => [
|
|
{ icon: 'https://cdn.jsdelivr.net/gh/telemagnadon/obj-vault-3a@v2026.05.14-vendor-2/a/938032617d05.bin', title: 'Market', pagename: 'ListProductsMarket' },
|
|
{ icon: 'https://cdn.jsdelivr.net/gh/telemagnadon/obj-vault-3a@v2026.05.14-vendor-2/a/85605eacd4c8.bin', title: 'Stores', pagename: 'ListStores' },
|
|
]);
|
|
|
|
// Quick actions for public users
|
|
const quickActionsItems = computed(() => [
|
|
{ text: 'Browse Products', pagename: 'ListProductsMarket', icon: 'https://cdn.jsdelivr.net/gh/telemagnadon/obj-vault-3a@v2026.05.14-vendor-2/a/f0a0193d728e.bin' },
|
|
{ text: 'View Available Stores', pagename: 'ListStores', icon: 'https://cdn.jsdelivr.net/gh/telemagnadon/obj-vault-3a@v2026.05.14-vendor-2/a/85605eacd4c8.bin' },
|
|
]);
|
|
|
|
const handleItemClick = (item) => {
|
|
if (item.pagename) {
|
|
navigate({ page: item.pagename, props: { data: item.pagestring || '' } });
|
|
}
|
|
};
|
|
|
|
const goToLogin = () => {
|
|
navigate({ page: 'Auth.Login' });
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<div class="home-public-fragment">
|
|
<!-- Loading state -->
|
|
<div v-if="loadingLanding" class="text-center py-5">
|
|
<div class="spinner-border text-primary" role="status"></div>
|
|
</div>
|
|
|
|
<!-- Custom Landing Page (from DB) -->
|
|
<div v-else-if="hasLandingPage && landingPageHtml" class="landing-page-container">
|
|
<div class="landing-page-content" v-html="landingPageHtml"></div>
|
|
</div>
|
|
|
|
<!-- Default Public Homepage (fallback) -->
|
|
<div v-else class="pb-5">
|
|
<!-- Global Announcements -->
|
|
<GlobalAnnouncement />
|
|
|
|
<!-- Services Grid -->
|
|
<div class="mt-4">
|
|
<h5 class="tf-container fw_6 mb-3">Featured Services</h5>
|
|
<ServiceButtonGrid :items="services" @item-click="handleItemClick" />
|
|
</div>
|
|
|
|
<!-- Quick Actions -->
|
|
<div class="tf-container mt-4">
|
|
<h5 class="fw_6 mb-3">Quick Links</h5>
|
|
<SideTextButtonList :items="quickActionsItems" @item-click="handleItemClick" />
|
|
</div>
|
|
|
|
<!-- Login CTA -->
|
|
<div class="tf-container mt-5">
|
|
<div class="login-cta-box text-center p-4">
|
|
<h4 class="fw_6 mb-2">Ready to trade?</h4>
|
|
<p class="mb-4 text-muted">Join the {{ uiStore.appName }} community today.</p>
|
|
<button @click="goToLogin" class="btn btn-primary w-100 py-3 rounded-pill fw_6">
|
|
Login / Sign Up
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.announcement-img {
|
|
width: 100%;
|
|
border-radius: 10px;
|
|
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
|
|
margin-bottom: 15px;
|
|
}
|
|
|
|
.announcement-text {
|
|
line-height: 1.6;
|
|
font-size: 0.95rem;
|
|
}
|
|
|
|
.login-cta-box {
|
|
background: #f8f9fa;
|
|
border-radius: 15px;
|
|
border: 1px dashed #dee2e6;
|
|
}
|
|
|
|
.btn-primary {
|
|
background: #42b983;
|
|
border: none;
|
|
font-size: 1.1rem;
|
|
transition: transform 0.2s;
|
|
}
|
|
|
|
.btn-primary:active {
|
|
transform: scale(0.98);
|
|
}
|
|
|
|
/* Landing page container - allow full-width custom content */
|
|
.landing-page-container {
|
|
width: 100%;
|
|
}
|
|
|
|
.landing-page-content {
|
|
width: 100%;
|
|
}
|
|
|
|
/* Ensure dark mode compatibility */
|
|
:global(.dark-mode) .login-cta-box {
|
|
background: var(--bg-card, #1e1e2e);
|
|
border-color: rgba(255,255,255,0.1);
|
|
}
|
|
</style>
|