import React, { useEffect, useState } from 'react' import { FaPhone, FaBuilding, FaCalendarAlt, FaCalendarCheck, FaRegComment, FaMapMarkerAlt, FaEnvelope, FaIdCard, } from 'react-icons/fa' import { useLocalization } from '@/utils/hooks/useLocalization' import { Helmet } from 'react-helmet' import { ContactDto } from '@/proxy/contact/models' import Loading from '@/components/shared/Loading' import { getContact, saveContactPage } from '@/services/contact.service' import { APP_NAME } from '@/constants/app.constant' import { useStoreActions, useStoreState } from '@/store' import DesignerDrawer from './designer/DesignerDrawer' import SelectableBlock from './designer/SelectableBlock' import { DesignerSelection } from './designer/types' import { useDesignerState } from './designer/useDesignerState' import { Button, Notification, toast } from '@/components/ui' interface ContactContent { heroTitle: string heroTitleKey: string heroSectionStyleClass: string heroSectionStyleClassKey: string heroTitleStyleClass: string heroTitleStyleClassKey: string heroSubtitle: string heroSubtitleKey: string heroSubtitleStyleClass: string heroSubtitleStyleClassKey: string heroImage: string heroImageKey: string contactInfoTitle: string contactInfoTitleKey: string contactInfoCardStyleClass: string contactInfoCardStyleClassKey: string contactInfoTitleStyleClass: string contactInfoTitleStyleClassKey: string address: string addressKey: string phoneNumber: string email: string location: string taxNumber: string bankTitle: string bankTitleKey: string bankAccountHolder: string bankBranch: string bankAccountNumber: string bankIban: string bankStyleClass: string workHoursTitle: string workHoursTitleKey: string workWeekday: string workWeekdayKey: string workWeekend: string workWeekendKey: string workWhatsapp: string workWhatsappKey: string workHoursStyleClass: string mapTitle: string mapTitleKey: string mapSrc: string mapWidth: string mapHeight: string mapAllowFullScreen: string mapLoading: string mapReferrerPolicy: string mapContainerStyleClass: string mapFrameStyleClass: string } const CONTACT_HERO_TITLE_KEY = 'App.Contact' const CONTACT_HERO_SUBTITLE_KEY = 'Public.contact.subtitle' const CONTACT_HERO_IMAGE_KEY = 'Public.contact.heroImage' const CONTACT_HERO_IMAGE_DEFAULT = 'https://images.pexels.com/photos/3183171/pexels-photo-3183171.jpeg?auto=compress&cs=tinysrgb&w=1920' const CONTACT_INFO_TITLE_KEY = 'Abp.Identity.User.UserInformation.ContactInformation' const CONTACT_BANK_TITLE_KEY = 'Public.contact.bank.title' const CONTACT_WORK_HOURS_TITLE_KEY = 'App.Definitions.WorkHour' const CONTACT_HERO_SECTION_STYLE_KEY = 'Public.contact.hero.sectionStyleClass' const CONTACT_HERO_TITLE_STYLE_KEY = 'Public.contact.hero.titleStyleClass' const CONTACT_HERO_SUBTITLE_STYLE_KEY = 'Public.contact.hero.subtitleStyleClass' const CONTACT_INFO_CARD_STYLE_KEY = 'Public.contact.info.cardStyleClass' const CONTACT_INFO_TITLE_STYLE_KEY = 'Public.contact.info.titleStyleClass' function isLikelyLocalizationKey(value?: string) { return Boolean(value && /^[A-Za-z0-9_.-]+$/.test(value) && value.includes('.')) } function resolveLocalizedValue( translate: (key: string) => string, keyOrValue: string | undefined, fallback = '', ) { if (!keyOrValue) { return fallback } if (!isLikelyLocalizationKey(keyOrValue)) { return keyOrValue } const translatedValue = translate('::' + keyOrValue) return translatedValue === keyOrValue ? fallback || keyOrValue : translatedValue } function buildContactContent( contact: ContactDto | undefined, translate: (key: string) => string, ): ContactContent { return { heroTitle: resolveLocalizedValue(translate, CONTACT_HERO_TITLE_KEY, 'Contact'), heroTitleKey: CONTACT_HERO_TITLE_KEY, heroSectionStyleClass: resolveLocalizedValue( translate, CONTACT_HERO_SECTION_STYLE_KEY, 'relative bg-blue-900 py-12 text-white dark:bg-gray-950', ), heroSectionStyleClassKey: CONTACT_HERO_SECTION_STYLE_KEY, heroTitleStyleClass: resolveLocalizedValue( translate, CONTACT_HERO_TITLE_STYLE_KEY, 'ml-4 mb-2 mt-3 text-5xl font-bold text-white', ), heroTitleStyleClassKey: CONTACT_HERO_TITLE_STYLE_KEY, heroSubtitle: resolveLocalizedValue(translate, CONTACT_HERO_SUBTITLE_KEY), heroSubtitleKey: CONTACT_HERO_SUBTITLE_KEY, heroSubtitleStyleClass: resolveLocalizedValue( translate, CONTACT_HERO_SUBTITLE_STYLE_KEY, 'ml-4 max-w-3xl text-xl', ), heroSubtitleStyleClassKey: CONTACT_HERO_SUBTITLE_STYLE_KEY, heroImage: resolveLocalizedValue(translate, CONTACT_HERO_IMAGE_KEY, CONTACT_HERO_IMAGE_DEFAULT), heroImageKey: CONTACT_HERO_IMAGE_KEY, contactInfoTitle: resolveLocalizedValue(translate, CONTACT_INFO_TITLE_KEY), contactInfoTitleKey: CONTACT_INFO_TITLE_KEY, contactInfoCardStyleClass: resolveLocalizedValue( translate, CONTACT_INFO_CARD_STYLE_KEY, 'rounded-xl bg-white p-8 shadow-lg dark:bg-gray-900 dark:shadow-gray-950/40', ), contactInfoCardStyleClassKey: CONTACT_INFO_CARD_STYLE_KEY, contactInfoTitleStyleClass: resolveLocalizedValue( translate, CONTACT_INFO_TITLE_STYLE_KEY, 'mb-6 text-2xl font-bold text-gray-900 dark:text-gray-100', ), contactInfoTitleStyleClassKey: CONTACT_INFO_TITLE_STYLE_KEY, address: resolveLocalizedValue(translate, contact?.address, ''), addressKey: contact?.address || '', phoneNumber: contact?.phoneNumber || '', email: contact?.email || '', location: contact?.location || '', taxNumber: contact?.taxNumber || '', bankTitle: resolveLocalizedValue(translate, CONTACT_BANK_TITLE_KEY), bankTitleKey: CONTACT_BANK_TITLE_KEY, bankAccountHolder: contact?.bankDto?.accountHolder || '', bankBranch: contact?.bankDto?.branch || '', bankAccountNumber: contact?.bankDto?.accountNumber || '', bankIban: contact?.bankDto?.iban || '', bankStyleClass: contact?.bankDto?.styleClass || 'rounded-xl bg-white p-8 shadow-lg dark:bg-gray-900 dark:shadow-gray-950/40', workHoursTitle: resolveLocalizedValue(translate, CONTACT_WORK_HOURS_TITLE_KEY), workHoursTitleKey: CONTACT_WORK_HOURS_TITLE_KEY, workWeekday: resolveLocalizedValue(translate, contact?.workHoursDto?.weekday, ''), workWeekdayKey: contact?.workHoursDto?.weekday || '', workWeekend: resolveLocalizedValue(translate, contact?.workHoursDto?.weekend, ''), workWeekendKey: contact?.workHoursDto?.weekend || '', workWhatsapp: resolveLocalizedValue(translate, contact?.workHoursDto?.whatsapp, ''), workWhatsappKey: contact?.workHoursDto?.whatsapp || '', workHoursStyleClass: contact?.workHoursDto?.styleClass || 'rounded-xl bg-white p-8 shadow-lg dark:bg-gray-900 dark:shadow-gray-950/40', mapTitle: resolveLocalizedValue(translate, contact?.mapDto?.title, ''), mapTitleKey: contact?.mapDto?.title || '', mapSrc: contact?.mapDto?.src || '', mapWidth: contact?.mapDto?.width || '100%', mapHeight: contact?.mapDto?.height || '700', mapAllowFullScreen: String(contact?.mapDto?.allowFullScreen ?? true), mapLoading: contact?.mapDto?.loading || 'lazy', mapReferrerPolicy: contact?.mapDto?.referrerPolicy || 'no-referrer-when-downgrade', mapContainerStyleClass: contact?.mapDto?.containerStyleClass || 'rounded-xl bg-white p-8 shadow-lg dark:bg-gray-900 dark:shadow-gray-950/40', mapFrameStyleClass: contact?.mapDto?.frameStyleClass || 'aspect-w-16 aspect-h-9 overflow-hidden rounded-xl bg-gray-200 dark:bg-gray-800', } } const Contact: React.FC = () => { const { translate } = useLocalization() const { setLang } = useStoreActions((actions) => actions.locale) const { getConfig } = useStoreActions((actions) => actions.abpConfig) const configCultureName = useStoreState( (state) => state.abpConfig.config?.localization.currentCulture.cultureName, ) const localeCurrentLang = useStoreState((state) => state.locale?.currentLang) const currentLanguage = configCultureName || localeCurrentLang || 'tr' const abpLanguages = useStoreState((state) => state.abpConfig.config?.localization.languages) || [] const languageOptions = abpLanguages .filter((language) => Boolean(language.cultureName)) .map((language) => { const cultureName = language.cultureName || 'tr' return { key: cultureName.toLowerCase().split('-')[0], cultureName, displayName: language.displayName || cultureName, } }) const languagesFromConfig = languageOptions.map((language) => language.key) const editorLanguages = Array.from( new Set((languagesFromConfig.length > 0 ? languagesFromConfig : [currentLanguage]).filter(Boolean)), ) const [loading, setLoading] = useState(true) const [isSaving, setIsSaving] = useState(false) const [isPanelVisible, setIsPanelVisible] = useState(true) const [contact, setContact] = useState() const initialContent = !loading ? buildContactContent(contact, translate) : null const { content, isDesignMode, selectedBlockId, selectedLanguage, supportedLanguages, setContent, setSelectedBlockId, resetContent, } = useDesignerState('contact', initialContent, { currentLanguage, supportedLanguages: editorLanguages, }) useEffect(() => { setLoading(true) const fetchContact = async () => { try { const result = await getContact() setContact(result.data) } catch (error) { console.error('Contact alinirken hata olustu:', error) } finally { setLoading(false) } } fetchContact() }, []) const updateContent = (updater: (current: ContactContent) => ContactContent) => { setContent((current) => { if (!current) { return current } return updater(current) }) } const handleFieldChange = (fieldKey: string, value: string | string[]) => { updateContent((current) => ({ ...current, [fieldKey]: value as string, })) } const selectedSelection: DesignerSelection | null = React.useMemo(() => { if (!content || !selectedBlockId) { return null } if (selectedBlockId === 'hero') { return { id: 'hero', title: 'Public.contact.hero.*', description: translate('::Public.designer.desc4'), fields: [ { key: 'heroTitle', label: content.heroTitleKey, type: 'text', value: content.heroTitle, }, { key: 'heroTitleStyleClass', label: content.heroTitleStyleClassKey, type: 'text', value: content.heroTitleStyleClass, }, { key: 'heroSubtitle', label: content.heroSubtitleKey, type: 'textarea', value: content.heroSubtitle, }, { key: 'heroSubtitleStyleClass', label: content.heroSubtitleStyleClassKey, type: 'text', value: content.heroSubtitleStyleClass, }, { key: 'heroImage', label: content.heroImageKey, type: 'image', value: content.heroImage, }, { key: 'heroSectionStyleClass', label: content.heroSectionStyleClassKey, type: 'text', value: content.heroSectionStyleClass, }, ], } } if (selectedBlockId === 'contact-info') { return { id: selectedBlockId, title: content.contactInfoTitleKey, description: translate('::Public.designer.desc5'), fields: [ { key: 'contactInfoTitle', label: content.contactInfoTitleKey, type: 'text', value: content.contactInfoTitle, }, { key: 'contactInfoTitleStyleClass', label: content.contactInfoTitleStyleClassKey, type: 'text', value: content.contactInfoTitleStyleClass, }, { key: 'contactInfoCardStyleClass', label: content.contactInfoCardStyleClassKey, type: 'text', value: content.contactInfoCardStyleClass, }, { key: 'address', label: content.addressKey, type: 'textarea', value: content.address, }, { key: 'phoneNumber', label: 'Public.contact.phone', type: 'text', value: content.phoneNumber, }, { key: 'email', label: 'Public.contact.email', type: 'text', value: content.email, }, { key: 'location', label: 'Public.contact.location.plain', type: 'text', value: content.location, }, { key: 'taxNumber', label: 'Public.contact.taxNumber', type: 'text', value: content.taxNumber, }, ], } } if (selectedBlockId === 'bank') { return { id: selectedBlockId, title: content.bankTitleKey, description: translate('::Public.designer.desc6'), fields: [ { key: 'bankTitle', label: content.bankTitleKey, type: 'text', value: content.bankTitle, }, { key: 'bankAccountHolder', label: 'Public.contact.bank.accountHolder', type: 'text', value: content.bankAccountHolder, }, { key: 'bankBranch', label: 'Public.contact.bank.branch', type: 'text', value: content.bankBranch, }, { key: 'bankAccountNumber', label: 'Public.contact.bank.accountNumber', type: 'text', value: content.bankAccountNumber, }, { key: 'bankIban', label: 'Public.contact.bank.iban', type: 'text', value: content.bankIban, }, { key: 'bankStyleClass', label: 'Public.contact.bank.styleClass', type: 'text', value: content.bankStyleClass, }, ], } } if (selectedBlockId === 'work-hours') { return { id: selectedBlockId, title: content.workHoursTitleKey, description: translate('::Public.designer.desc7'), fields: [ { key: 'workHoursTitle', label: content.workHoursTitleKey, type: 'text', value: content.workHoursTitle, }, { key: 'workWeekday', label: content.workWeekdayKey, type: 'text', value: content.workWeekday, }, { key: 'workWeekend', label: content.workWeekendKey, type: 'text', value: content.workWeekend, }, { key: 'workWhatsapp', label: content.workWhatsappKey, type: 'text', value: content.workWhatsapp, }, { key: 'workHoursStyleClass', label: 'Public.contact.workHours.styleClass', type: 'text', value: content.workHoursStyleClass, }, ], } } if (selectedBlockId === 'map') { return { id: selectedBlockId, title: content.mapTitleKey, description: translate('::Public.designer.desc8'), fields: [ { key: 'mapTitle', label: content.mapTitleKey, type: 'text', value: content.mapTitle, }, { key: 'mapSrc', label: 'Public.contact.map.src', type: 'textarea', value: content.mapSrc, }, { key: 'mapWidth', label: 'Public.contact.map.width', type: 'text', value: content.mapWidth, }, { key: 'mapHeight', label: 'Public.contact.map.height', type: 'text', value: content.mapHeight, }, { key: 'mapAllowFullScreen', label: 'Public.contact.map.allowFullScreen', type: 'text', value: content.mapAllowFullScreen, placeholder: 'true veya false', }, { key: 'mapLoading', label: 'Public.contact.map.loading', type: 'text', value: content.mapLoading, }, { key: 'mapReferrerPolicy', label: 'Public.contact.map.referrerPolicy', type: 'text', value: content.mapReferrerPolicy, }, { key: 'mapContainerStyleClass', label: 'Public.contact.map.containerStyleClass', type: 'text', value: content.mapContainerStyleClass, }, { key: 'mapFrameStyleClass', label: 'Public.contact.map.frameStyleClass', type: 'text', value: content.mapFrameStyleClass, }, ], } } return null }, [content, selectedBlockId]) const handleSaveAndExit = async () => { if (!content || isSaving) { return } setIsSaving(true) try { await saveContactPage({ cultureName: selectedLanguage, heroTitleKey: content.heroTitleKey, heroTitleValue: content.heroTitle, heroSubtitleKey: content.heroSubtitleKey, heroSubtitleValue: content.heroSubtitle, heroImageKey: content.heroImageKey, heroImageValue: content.heroImage, contactInfoTitleKey: content.contactInfoTitleKey, contactInfoTitleValue: content.contactInfoTitle, addressKey: content.addressKey, addressValue: content.address, phoneNumber: content.phoneNumber, email: content.email, location: content.location, taxNumber: content.taxNumber, bankTitleKey: content.bankTitleKey, bankTitleValue: content.bankTitle, bankAccountHolder: content.bankAccountHolder, bankBranch: content.bankBranch, bankAccountNumber: content.bankAccountNumber, bankIban: content.bankIban, bankStyleClass: content.bankStyleClass, workHoursTitleKey: content.workHoursTitleKey, workHoursTitleValue: content.workHoursTitle, workWeekdayKey: content.workWeekdayKey, workWeekdayValue: content.workWeekday, workWeekendKey: content.workWeekendKey, workWeekendValue: content.workWeekend, workWhatsappKey: content.workWhatsappKey, workWhatsappValue: content.workWhatsapp, workHoursStyleClass: content.workHoursStyleClass, mapTitleKey: content.mapTitleKey, mapTitleValue: content.mapTitle, mapSrc: content.mapSrc, mapWidth: content.mapWidth, mapHeight: content.mapHeight, mapAllowFullScreen: content.mapAllowFullScreen.toLowerCase() === 'true', mapLoading: content.mapLoading, mapReferrerPolicy: content.mapReferrerPolicy, mapContainerStyleClass: content.mapContainerStyleClass, mapFrameStyleClass: content.mapFrameStyleClass, styleTexts: [ { key: content.heroSectionStyleClassKey, value: content.heroSectionStyleClass, }, { key: content.heroTitleStyleClassKey, value: content.heroTitleStyleClass, }, { key: content.heroSubtitleStyleClassKey, value: content.heroSubtitleStyleClass, }, { key: content.contactInfoCardStyleClassKey, value: content.contactInfoCardStyleClass, }, { key: content.contactInfoTitleStyleClassKey, value: content.contactInfoTitleStyleClass, }, ], }) await getConfig(false) setSelectedBlockId(null) toast.push( {translate('::ListForms.FormBilgileriKaydedildi')} , { placement: 'top-center', }, ) } catch (error) { console.error('Contact tasarimi kaydedilemedi:', error) } finally { setIsSaving(false) } } const handleLanguageChange = (language: string) => { setLang(language) } const handleSelectBlock = (blockId: string) => { setSelectedBlockId(blockId) if (!isPanelVisible) { setIsPanelVisible(true) } } if (loading) { return (
) } return (
{isDesignMode && (
Contact designer aktif
)} {isDesignMode && !isPanelVisible && ( )}

{content?.heroTitle}

{content?.heroSubtitle}

{content?.contactInfoTitle}

{content?.address}

{content?.phoneNumber}

{content?.location}

{content?.taxNumber}

{content?.bankTitle}

Enpara Logo

{content?.bankAccountHolder}

{content?.bankBranch}

{content?.bankAccountNumber}

{content?.bankIban}

{content?.workHoursTitle}

{content?.workWeekday}

{content?.workWeekend}

{content?.workWhatsapp}

{content?.mapTitle}

0 ? languageOptions : supportedLanguages.map((language) => ({ key: language, cultureName: language, displayName: language.toUpperCase(), })) } onClose={() => setIsPanelVisible(false)} onSave={handleSaveAndExit} onLanguageChange={handleLanguageChange} onReset={resetContent} onFieldChange={handleFieldChange} />
) } export default Contact