Преглед изворни кода

textos e imagem dinamicas via cadastro no layout adm do serprati_digital

Gustavo Zanatta пре 5 часа
родитељ
комит
afcfd7e94e
4 измењених фајлова са 111 додато и 53 уклоњено
  1. 8 6
      app/components/AppFooter.vue
  2. 76 0
      app/composables/useCompanyData.ts
  3. 23 47
      app/pages/index.vue
  4. 4 0
      nuxt.config.ts

+ 8 - 6
app/components/AppFooter.vue

@@ -39,17 +39,17 @@
             Contato
           </h4>
           <ul class="space-y-3">
-            <li class="flex items-center gap-2" style="color: rgba(254,254,254,0.65);">
+            <li v-if="settings.contact_email" class="flex items-center gap-2" style="color: rgba(254,254,254,0.65);">
               <span class="material-icons text-lg leading-none">email</span>
-              <span class="text-sm">serprati@serprati.com.br</span>
+              <span class="text-sm">{{ settings.contact_email }}</span>
             </li>
-            <li class="flex items-center gap-2" style="color: rgba(254,254,254,0.65);">
+            <li v-if="settings.contact_phone" class="flex items-center gap-2" style="color: rgba(254,254,254,0.65);">
               <span class="material-icons text-lg leading-none">phone</span>
-              <span class="text-sm">45 99126-6531</span>
+              <span class="text-sm">{{ settings.contact_phone }}</span>
             </li>
-            <li class="flex items-center gap-2" style="color: rgba(254,254,254,0.65);">
+            <li v-if="settings.contact_location" class="flex items-center gap-2" style="color: rgba(254,254,254,0.65);">
               <span class="material-icons text-lg leading-none">location_on</span>
-              <span class="text-sm">Toledo - PR</span>
+              <span class="text-sm">{{ settings.contact_location }}</span>
             </li>
           </ul>
         </div>
@@ -68,6 +68,8 @@
 </template>
 
 <script setup lang="ts">
+const { settings } = useCompanyData()
+
 const scrollTo = (id: string) => {
   document.getElementById(id)?.scrollIntoView({ behavior: 'smooth' })
 }

+ 76 - 0
app/composables/useCompanyData.ts

@@ -0,0 +1,76 @@
+interface CompanySettings {
+  hero_background_url: string | null
+  hero_title: string | null
+  hero_subtitle: string | null
+  stat1_value: string | null
+  stat1_label: string | null
+  stat2_value: string | null
+  stat2_label: string | null
+  stat3_value: string | null
+  stat3_label: string | null
+  contact_email: string | null
+  contact_phone: string | null
+  contact_location: string | null
+}
+
+interface CompanyBenefit {
+  id: number
+  title: string
+  icon: string
+  description: string | null
+  order: number
+}
+
+interface ApiResponse<T> {
+  payload: T
+}
+
+const FALLBACK_SETTINGS: CompanySettings = {
+  hero_background_url: null,
+  hero_title: 'Serprati é fazer parte de algo maior',
+  hero_subtitle: 'Benefícios exclusivos, parceiros de qualidade e uma comunidade que cuida de você e sua família.',
+  stat1_value: '1.000+',
+  stat1_label: 'Associados',
+  stat2_value: '50+',
+  stat2_label: 'Parceiros',
+  stat3_value: '30+',
+  stat3_label: 'Anos de História',
+  contact_email: 'serprati@serprati.com.br',
+  contact_phone: '45 99126-6531',
+  contact_location: 'Toledo - PR',
+}
+
+const FALLBACK_BENEFITS: CompanyBenefit[] = [
+  { id: 1, title: 'Descontos Exclusivos', icon: 'mdi-tag', description: 'Até 50% de desconto em parceiros selecionados.', order: 1 },
+  { id: 2, title: 'Convênios Médicos', icon: 'mdi-hospital-box-outline', description: 'Planos de saúde com condições especiais.', order: 2 },
+  { id: 3, title: 'Loja do Associado', icon: 'mdi-store-outline', description: 'Produtos com preços diferenciados.', order: 3 },
+  { id: 4, title: 'Carteirinha Digital', icon: 'mdi-card-account-details-outline', description: 'Acesso rápido aos benefícios pelo celular.', order: 4 },
+  { id: 5, title: 'Notificações', icon: 'mdi-bell-outline', description: 'Fique por dentro das novidades e promoções.', order: 5 },
+  { id: 6, title: 'Dependentes', icon: 'mdi-human-male-female-child', description: 'Inclua sua família nos benefícios.', order: 6 },
+]
+
+export const useCompanyData = () => {
+  const { apiUrl } = useRuntimeConfig().public
+
+  const { data: settingsData } = useAsyncData('company-settings', () =>
+    $fetch<ApiResponse<CompanySettings>>(`${apiUrl}/api/company-settings`).catch(() => null),
+  )
+
+  const { data: benefitsData } = useAsyncData('company-benefits', () =>
+    $fetch<ApiResponse<CompanyBenefit[]>>(`${apiUrl}/api/company-benefits`).catch(() => null),
+  )
+
+  const settings = computed<CompanySettings>(() => {
+    const payload = settingsData.value?.payload
+    if (!payload) return FALLBACK_SETTINGS
+    return { ...FALLBACK_SETTINGS, ...payload }
+  })
+
+  const benefits = computed<CompanyBenefit[]>(() => {
+    const payload = benefitsData.value?.payload
+    if (!Array.isArray(payload) || payload.length === 0) return FALLBACK_BENEFITS
+    return payload
+  })
+
+  return { settings, benefits }
+}

+ 23 - 47
app/pages/index.vue

@@ -4,7 +4,7 @@
     <section
       id="quem-somos"
       class="relative min-h-screen flex flex-col bg-cover lg:bg-left"
-      :style="{ backgroundImage: `url(${heroBg})` }"
+      :style="{ backgroundImage: `url(${heroBackground})` }"
     >
       <div class="absolute inset-0 bg-violet-normal/45"/>
 
@@ -12,17 +12,16 @@
         <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 w-full pt-8 pb-20 lg:py-18">
           <div class="flex flex-col lg:flex-row gap-4 lg:gap-12">
 
-            <div class="max-w-2xl">
+            <div class="max-w-2xl justifyBetween">
               <h1
                 class="reveal text-h2 text-white font-black mb-10"
                 style="font-size: clamp(2rem, 5vw, 3.75rem); font-weight: 900;"
               >
-                Serprati é fazer parte de algo maior
+                {{ settings.hero_title }}
               </h1>
 
               <p class="reveal reveal-delay-1 text-white/90 mb-6 leading-relaxed" style="font-size: clamp(1rem, 1.5vw, 1.125rem); font-weight: 600;">
-                Benefícios exclusivos, parceiros de qualidade e uma comunidade
-                que cuida de você e sua família.
+                {{ settings.hero_subtitle }}
               </p>
 
               <div class="reveal reveal-delay-2 flex flex-col sm:flex-row gap-4">
@@ -45,20 +44,20 @@
 
               <div class="flex flex-col items-start gap-1">
                 <span class="material-icons text-white/90 text-3xl lg:text-4xl">group</span>
-                <span class="text-white font-bold" style="font-size: clamp(1.25rem, 2.5vw, 1.75rem);">1.000+</span>
-                <span class="text-white/80 text-sm">Associados</span>
+                <span class="text-white font-bold" style="font-size: clamp(1.25rem, 2.5vw, 1.75rem);">{{ settings.stat1_value }}</span>
+                <span class="text-white/80 text-sm">{{ settings.stat1_label }}</span>
               </div>
 
               <div class="flex flex-col items-start gap-1">
                 <span class="material-icons text-white/90 text-3xl lg:text-4xl">handshake</span>
-                <span class="text-white font-bold" style="font-size: clamp(1.25rem, 2.5vw, 1.75rem);">50+</span>
-                <span class="text-white/80 text-sm">Parceiros</span>
+                <span class="text-white font-bold" style="font-size: clamp(1.25rem, 2.5vw, 1.75rem);">{{ settings.stat2_value }}</span>
+                <span class="text-white/80 text-sm">{{ settings.stat2_label }}</span>
               </div>
 
               <div class="flex flex-col items-start gap-1">
                 <span class="material-icons text-white/90 text-3xl lg:text-4xl">favorite_border</span>
-                <span class="text-white font-bold" style="font-size: clamp(1.25rem, 2.5vw, 1.75rem);">30+</span>
-                <span class="text-white/80 text-sm">Anos de História</span>
+                <span class="text-white font-bold" style="font-size: clamp(1.25rem, 2.5vw, 1.75rem);">{{ settings.stat3_value }}</span>
+                <span class="text-white/80 text-sm">{{ settings.stat3_label }}</span>
               </div>
 
             </div>
@@ -81,12 +80,12 @@
 
           <div
             v-for="(benefit, index) in benefits"
-            :key="benefit.title"
+            :key="benefit.id"
             :class="`reveal reveal-delay-${index + 1}`"
             class="benefit-card"
           >
             <div class="benefit-icon-wrap">
-              <span class="material-icons text-violet-normal text-2xl">{{ benefit.icon }}</span>
+              <i :class="`mdi ${benefit.icon} text-violet-normal`" style="font-size: 1.5rem;" />
             </div>
             <h3 class="text-subtitle-1 font-semibold text-text mt-4 mb-2">
               {{ benefit.title }}
@@ -245,48 +244,19 @@
 </template>
 
 <script setup lang="ts">
-import heroBg from '~/assets/images/imagem_fundo.png'
+import heroBgFallback from '~/assets/images/imagem_fundo.png'
 
 useHead({ title: 'Serprati' })
 definePageMeta({ layout: 'default' })
 
+const { settings, benefits } = useCompanyData()
+
+const heroBackground = computed(() => settings.value.hero_background_url ?? heroBgFallback)
+
 const scrollTo = (id: string) => {
   document.getElementById(id)?.scrollIntoView({ behavior: 'smooth' })
 }
 
-const benefits = [
-  {
-    icon: 'local_offer',
-    title: 'Descontos Exclusivos',
-    description: 'Até 50% de desconto em parceiros selecionados.',
-  },
-  {
-    icon: 'health_and_safety',
-    title: 'Convênios Médicos',
-    description: 'Planos de saúde com condições especiais.',
-  },
-  {
-    icon: 'store',
-    title: 'Loja do Associado',
-    description: 'Produtos com preços diferenciados.',
-  },
-  {
-    icon: 'badge',
-    title: 'Carteirinha Digital',
-    description: 'Acesso rápido aos benefícios pelo celular.',
-  },
-  {
-    icon: 'notifications',
-    title: 'Notificações',
-    description: 'Fique por dentro das novidades e promoções.',
-  },
-  {
-    icon: 'family_restroom',
-    title: 'Dependentes',
-    description: 'Inclua sua família nos benefícios.',
-  },
-]
-
 const form = reactive({
   nomeCompleto: '',
   cpf: '',
@@ -564,4 +534,10 @@ onMounted(() => {
   opacity: 0;
   transform: translateY(12px);
 }
+
+.justifyBetween {
+  display: flex;
+  flex-direction: column;
+  justify-content: space-between;
+}
 </style>

+ 4 - 0
nuxt.config.ts

@@ -33,6 +33,10 @@ export default defineNuxtConfig({
         {
           rel: 'stylesheet',
           href: 'https://fonts.googleapis.com/icon?family=Material+Icons'
+        },
+        {
+          rel: 'stylesheet',
+          href: 'https://cdn.jsdelivr.net/npm/@mdi/font@7/css/materialdesignicons.min.css'
         }
       ]
     }