2025-07-04 17:51:43 +02:00

473 lines
14 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { defineStore } from 'pinia'
import { useRuntimeConfig } from '#app'
interface CompanyLogo {
url: string
alternativeText?: string
}
interface CompanyInfo {
company: string
street: string
postalcode: string
city: string
phone: string
email: string
contact: string
district?: string
latitude?: number
longitude?: number
web: string
invertlogo?: {
data?: {
attributes?: CompanyLogo
}
}
}
interface SEO {
pageTitle: string
seoDescription: string
seoKeywords: string
type: string
seoImage?: CompanyLogo | null
}
interface PageSection {
id: number
sectionText: string
sectionImage?: CompanyLogo | null
}
interface FAQ {
question: string
answer: string
locale: string
}
interface Page {
id: number
pageName: string
pageLink: string
header_image?: CompanyLogo | null
SEO?: SEO | null
faqs: FAQ[]
pageSections: PageSection[]
}
interface PageContent {
id: number
section: string
content: any // Strapi Blocks ggf. präzisieren, wenn du eine feste Struktur nutzt
locale: string
}
interface CustomerProject {
id: number
projectTitle: string
launchDate?: string
projectDescription?: string
link?: string
webpage?: string
technologies: { titel: string; icon?: string }[]
projectImages: CompanyLogo[]
customer?: {
id: number
company: string
city: string
} | null
}
interface Customer {
id: number
company: string
city: string
logo?: CompanyLogo | null
invertLogo?: CompanyLogo | null
projects: CustomerProject[]
}
interface NewsArticle {
id: number
header: string
teaser: string
content: any
slug: string
image?: CompanyLogo | null
createdAt: string
SEO?: SEO | null
author?: {
id: number
name: string
// optional: weitere Felder aus dem Team-Modell
} | null
categories?: {
id: number
name: string
}[]
}
interface ContactData {
name: string;
email?: string;
phone?: string;
company?: string;
message: string;
language: string;
}
export const useMainStore = defineStore('main', {
state: () => ({
locale: 'de',
menuOpen: false,
contactBoxOpen: false,
scrollPosition: 0,
screenWidth: 1440,
heroBoxHeight: 0,
darkHeroBack: false,
companyinfo: null as CompanyInfo | null,
pages: [] as Page[],
pagecontents: [] as PageContent[],
customers: [] as Customer[],
projects: [] as CustomerProject[],
articles: [] as NewsArticle[],
categories: [] as { id: number; name: string }[],
dataFetched: false,
loading: false,
error: null as { message: string; stack?: string } | null,
}),
getters: {
invertLogoUrl: (state) => {
const runtimeConfig = useRuntimeConfig()
const logoUrl = state.companyinfo?.invertlogo?.data?.attributes?.url
return logoUrl
? `${runtimeConfig.public.cmsBaseUrl}${logoUrl}`
: '/uploads/dummy_Image_4abc3f04dd.webp'
},
isMobile: (state) => state.screenWidth < 768,
getPageByLink: (state) => (link: string) =>
state.pages.find((p) => p.pageLink === link),
getCustomerById: (state) => (id: number) =>
state.customers.find((c) => c.id === id),
getFaqsByPageId: (state) => (pageId: number) =>
state.pages.find((p) => p.id === pageId)?.faqs ?? [],
getFaqsByPageLink: (state) => (link: string, locale = state.locale) => {
const page = state.pages.find(p => p.pageLink === link && p.locale === locale)
return page?.faqs ?? []
},
getProjectByLink: (state) => (link: string) =>
state.projects.find(project => project.link === link),
getArticleBySlug: (state) => (slug: string) =>
state.articles.find((a) => a.slug === slug),
getRecommendedArticles: (state) => (article: NewsArticle) => {
if (!article?.categories || !Array.isArray(state.articles)) return []
const categoryIds = article.categories.map(c => c.id)
return state.articles.filter(a => {
if (a.id === article.id) return false // sich selbst ausschließen
if (!a.categories) return false
return a.categories.some(cat => categoryIds.includes(cat.id))
})
},
getArticlesByCategoryIds: (state) => (categoryIds: number[]) => {
if (!Array.isArray(categoryIds)) return []
return state.articles.filter(article =>
article.categories?.some(cat => categoryIds.includes(cat.id))
)
},
getPageContentBySection: (state) => (section: string): PageContent | undefined =>
state.pagecontents.find((pc) => pc.section === section),
getAllPageContentsBySection: (state) => (section: string): PageContent[] =>
state.pagecontents.filter((pc) => pc.section === section),
},
actions: {
toggleMenu() {
this.menuOpen = !this.menuOpen
},
closeMenu() {
this.menuOpen = false
},
toggleContactBubble() {
this.contactBoxOpen = !this.contactBoxOpen
},
setScrollPosition(pos: number) {
this.scrollPosition = pos
},
setScreenWidth(width: number) {
this.screenWidth = width
},
setHeroBoxHeight(height: number) {
this.heroBoxHeight = height
},
setDarkHeroBack(value: boolean) {
this.darkHeroBack = value
},
syncLocaleWithI18n() {
const { locale } = useI18n()
this.locale = locale.value
watch(locale, (newLocale) => {
this.locale = newLocale
})
},
// SEND CONTACT REQUEST TO STRAPI
sendContactRequestToCMS: async (contactData: ContactData): Promise<void> => {
const router = useRouter()
const config = useRuntimeConfig()
try {
await $fetch(`${config.public.cmsBaseUrl}/api/contacts`, {
method: 'POST',
headers: {
Authorization: `Bearer ${config.public.cmsToken}`,
'Content-Type': 'application/json',
},
body: {
data: {
name: contactData.name,
email: contactData.email,
phone: contactData.phone,
company: contactData.company,
text: contactData.message,
page: router.currentRoute.value.fullPath,
language: contactData.language,
},
},
})
} catch (error) {
console.error('Fehler beim Senden der Kontaktanfrage:', error)
throw error
}
},
// FETCH ALL THE DATA FROM STRAPI
async fetchInitialData() {
if (this.dataFetched) return
this.loading = true
const { public: cfg } = useRuntimeConfig()
try {
const [companyRes, pagesRes, customersRes, projectsRes, articlesRes, categoriesRes, pageContentsRes] = await Promise.all([
$fetch(`${cfg.cmsBaseUrl}/api/companyinfo?populate=*`, {
headers: { Authorization: `Bearer ${cfg.cmsToken}` },
}),
/* $fetch(`${cfg.cmsBaseUrl}/api/pages?populate=*`, {
headers: { Authorization: `Bearer ${cfg.cmsToken}` },
}), */
$fetch(`${cfg.cmsBaseUrl}/api/pages`, {
headers: { Authorization: `Bearer ${cfg.cmsToken}` },
params: {
locale: 'all',
populate: [
'header_image',
'SEO',
'SEO.seoImage',
'faqs',
'faqs.localizations',
'pageSections',
'pageSections.sectionImage',
'pageContents',
'pageContents.content',
].join(','),
}
}),
$fetch(`${cfg.cmsBaseUrl}/api/customers?populate=*`, {
headers: { Authorization: `Bearer ${cfg.cmsToken}` },
}),
$fetch(`${cfg.cmsBaseUrl}/api/references?populate=projectImages,Technologien,customer&sort=launchDate:desc`, {
headers: { Authorization: `Bearer ${cfg.cmsToken}` },
}),
$fetch(`${cfg.cmsBaseUrl}/api/newsarticels?populate=image,SEO,categories,author&locale=all&sort=createdAt:desc`, {
headers: { Authorization: `Bearer ${cfg.cmsToken}` },
}),
/* $fetch(`${cfg.cmsBaseUrl}/api/magazin-cats?populate=*&locale=all`, {
headers: { Authorization: `Bearer ${cfg.cmsToken}` },
}),
$fetch(`${cfg.cmsBaseUrl}/api/pagecontents?populate=*&locale=all`, {
headers: { Authorization: `Bearer ${cfg.cmsToken}` },
}), */
$fetch(`${cfg.cmsBaseUrl}/api/magazin-cats`, {
headers: { Authorization: `Bearer ${cfg.cmsToken}` },
params: {
locale: 'all',
populate: '*',
},
}),
$fetch(`${cfg.cmsBaseUrl}/api/pagecontents`, {
headers: { Authorization: `Bearer ${cfg.cmsToken}` },
params: {
locale: 'all',
// Falls `content` ein RichText-Feld ist und evtl. weitere Relationen,
// solltest du die Felder explizit nennen, nicht nur '*'
populate: {
content: '*',
},
'pagination[limit]': 3000,
},
}),
])
this.companyinfo = companyRes.data?.attributes ?? companyRes
this.pages = pagesRes.data.map((item: any) => {
const a = item.attributes
return {
id: item.id,
locale: a.locale,
pageName: a.pageName,
pageLink: a.pageLink,
header_image: a.header_image?.data
? {
url: a.header_image.data.attributes.url,
alternativeText: a.header_image.data.attributes.alternativeText,
}
: null,
SEO: a.SEO
? {
pageTitle: a.SEO.pageTitle,
seoDescription: a.SEO.seoDesicription, // absichtlicher Fehler
seoKeywords: a.SEO.seoKeywords,
type: a.SEO.type,
seoImage: a.SEO.seoImage?.data
? {
url: a.SEO.seoImage.data.attributes.url,
alternativeText: a.SEO.seoImage.data.attributes.alternativeText,
}
: null,
}
: null,
faqs: a.faqs?.data?.map((f: any) => ({
question: f.attributes.question,
answer: f.attributes.answer,
locale: f.attributes.locale,
})) ?? [],
pageSections: a.pageSections?.map((s: any) => ({
id: s.id,
sectionText: s.sectionText,
sectionImage: s.sectionImage?.data
? {
url: s.sectionImage.data.attributes.url,
alternativeText: s.sectionImage.data.attributes.alternativeText,
}
: null,
})) ?? [],
}
})
this.pagecontents = pageContentsRes.data.map((item: any) => ({
id: item.id,
section: item.attributes.section,
content: item.attributes.content,
locale: item.attributes.locale
}))
this.customers = customersRes.data.map((item: any) => {
const a = item.attributes
return {
id: item.id,
company: a.company,
city: a.city,
logo: a.logo?.data?.attributes ?? null,
invertLogo: a.invertLogo?.data?.attributes ?? null,
projects: [], // Wird durch references geladen
}
})
this.projects = projectsRes.data.map((item: any) => {
const a = item.attributes
return {
id: item.id,
projectTitle: a.projectTitle,
launchDate: a.launchDate,
projectDescription: a.projectDescription,
link: a.link,
webpage: a.webpage,
technologies: a.Technologien?.data?.map((t: any) => ({
titel: t.attributes.titel,
icon: t.attributes.icon,
})) ?? [],
projectImages: a.projectImages?.data?.map((img: any) => ({
url: img.attributes.url,
alternativeText: img.attributes.alternativeText,
})) ?? [],
customer: a.customer?.data
? {
id: a.customer.data.id,
company: a.customer.data.attributes.company,
city: a.customer.data.attributes.city,
}
: null,
}
})
this.articles = articlesRes.data.map((item: any) => {
const a = item.attributes
return {
id: item.id,
header: a.header,
teaser: a.teaser,
content: a.content,
slug: a.slug,
createdAt: a.createdAt,
image: a.image?.data
? {
url: a.image.data.attributes.url,
alternativeText: a.image.data.attributes.alternativeText,
}
: null,
SEO: a.SEO
? {
pageTitle: a.SEO.pageTitle,
seoDescription: a.SEO.seoDesicription,
seoKeywords: a.SEO.seoKeywords,
type: a.SEO.type,
seoImage: a.SEO.seoImage?.data
? {
url: a.SEO.seoImage.data.attributes.url,
alternativeText: a.SEO.seoImage.data.attributes.alternativeText,
}
: null,
}
: null,
author: a.author?.data
? {
id: a.author.data.id,
name: a.author.data.attributes.name,
}
: null,
categories: a.categories?.data?.map((c: any) => ({
id: c.id,
name: c.attributes.category,
})) ?? [],
}
})
this.categories = categoriesRes.data.map((item: any) => ({
id: item.id,
name: item.attributes.category,
}))
this.dataFetched = true
} catch (err) {
const e = err as Error
this.error = { message: e.message, stack: e.stack }
console.error('Fetch-Fehler:', e)
} finally {
this.loading = false
}
},
},
})