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 => { 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 } }, }, })