sozsoft-platform/ui/src/views/public/Contact.tsx
Sedat ÖZTÜRK 9cd49f3f66 bottom-end
2026-07-08 15:34:13 +03:00

851 lines
30 KiB
TypeScript

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<ContactDto>()
const initialContent = !loading ? buildContactContent(contact, translate) : null
const {
content,
isDesignMode,
selectedBlockId,
selectedLanguage,
supportedLanguages,
setContent,
setSelectedBlockId,
resetContent,
} = useDesignerState<ContactContent>('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(
<Notification type="success" duration={2000}>
{translate('::ListForms.FormBilgileriKaydedildi')}
</Notification>,
{
placement: 'bottom-end',
},
)
} 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 (
<div className="flex items-center justify-center min-h-screen bg-gray-50 dark:bg-gray-950">
<div className="text-center">
<Loading loading={loading} />
</div>
</div>
)
}
return (
<div className={`min-h-screen bg-gray-50 dark:bg-gray-950 ${isDesignMode && isPanelVisible ? 'xl:pr-[420px]' : ''}`}>
<Helmet
titleTemplate={`%s | ${APP_NAME}`}
title={translate('::App.Contact')}
defaultTitle={APP_NAME}
></Helmet>
{isDesignMode && (
<div className="fixed bottom-6 left-6 z-40 rounded-full bg-slate-900 px-4 py-2 text-sm font-medium text-white shadow-xl">
Contact designer aktif
</div>
)}
{isDesignMode && !isPanelVisible && (
<Button
type="button"
onClick={() => setIsPanelVisible(true)}
className="fixed right-4 top-1/2 z-40 -translate-y-1/2 rounded-full bg-slate-900 px-4 py-2 text-sm font-semibold text-white shadow-xl"
>
{translate('::Public.designer.showPanel')}
</Button>
)}
<SelectableBlock
id="hero"
isActive={selectedBlockId === 'hero'}
isDesignMode={isDesignMode}
onSelect={handleSelectBlock}
>
<div className={`${content?.heroSectionStyleClass || 'relative bg-blue-900 py-12 text-white'} dark:bg-gray-950`}>
<div
className="absolute inset-0 opacity-20 dark:opacity-35"
style={{
backgroundImage: `url("${content?.heroImage || CONTACT_HERO_IMAGE_DEFAULT}")`,
backgroundSize: 'cover',
backgroundPosition: 'center',
}}
></div>
<div className="absolute inset-0 bg-blue-950/25 dark:bg-gray-950/45"></div>
<div className="container relative mx-auto pt-20">
<h1 className={content?.heroTitleStyleClass || 'ml-4 mb-2 mt-3 text-5xl font-bold text-white'}>{content?.heroTitle}</h1>
<p className={content?.heroSubtitleStyleClass || 'ml-4 max-w-3xl text-xl'}>{content?.heroSubtitle}</p>
</div>
</div>
</SelectableBlock>
<div className="py-6">
<div className="container mx-auto px-4">
<div className="grid grid-cols-1 gap-12 lg:grid-cols-2">
<div className="space-y-4">
<SelectableBlock
id="contact-info"
isActive={selectedBlockId === 'contact-info'}
isDesignMode={isDesignMode}
onSelect={handleSelectBlock}
>
<div className={`${content?.contactInfoCardStyleClass || 'rounded-xl bg-white p-8 shadow-lg'} dark:bg-gray-900 dark:shadow-gray-950/40`}>
<h2 className={`${content?.contactInfoTitleStyleClass || 'mb-6 text-2xl font-bold text-gray-900'} dark:text-gray-100`}>{content?.contactInfoTitle}</h2>
<div className="space-y-4">
<div className="flex items-start space-x-2">
<FaMapMarkerAlt className="mt-1 h-5 w-5 flex-shrink-0 text-blue-600 dark:text-blue-400" />
<div>
<p className="text-gray-600 dark:text-gray-300">{content?.address}</p>
</div>
</div>
<div className="flex items-start space-x-2">
<FaPhone className="h-5 w-5 flex-shrink-0 text-blue-600 dark:text-blue-400" />
<div>
<p className="text-gray-600 dark:text-gray-300">{content?.phoneNumber}</p>
</div>
</div>
<div className="flex items-start space-x-2">
<FaEnvelope className="h-5 w-5 flex-shrink-0 text-blue-600 dark:text-blue-400" />
<div>
<p className="text-gray-600 dark:text-gray-300">
<a href={`mailto:${content?.email}`} className="text-blue-600 hover:underline dark:text-blue-400">
{content?.email}
</a>
</p>
</div>
</div>
<div className="flex items-start space-x-2">
<FaBuilding className="h-5 w-5 flex-shrink-0 text-blue-600 dark:text-blue-400" />
<div>
<p className="text-gray-600 dark:text-gray-300">{content?.location}</p>
</div>
</div>
<div className="flex items-start space-x-2">
<FaIdCard className="h-5 w-5 flex-shrink-0 text-blue-600 dark:text-blue-400" />
<div>
<p className="text-gray-600 dark:text-gray-300">{content?.taxNumber}</p>
</div>
</div>
</div>
</div>
</SelectableBlock>
<SelectableBlock
id="bank"
isActive={selectedBlockId === 'bank'}
isDesignMode={isDesignMode}
onSelect={handleSelectBlock}
>
<div className={`${content?.bankStyleClass || 'rounded-xl bg-white p-8 shadow-lg'} dark:bg-gray-900 dark:shadow-gray-950/40`}>
<h2 className="mb-6 text-2xl font-bold text-gray-900 dark:text-gray-100">{content?.bankTitle}</h2>
<div className="mb-2">
<img
src="/img/enpara.svg"
alt="Enpara Logo"
className="mt-1 w-24 flex-shrink-0 object-contain"
/>
<div>
<h3 className="mb-1 font-semibold text-gray-900 dark:text-gray-100">{content?.bankAccountHolder}</h3>
<p className="mb-1 ml-1 text-gray-600 dark:text-gray-300">{content?.bankBranch}</p>
<p className="mb-1 ml-1 text-gray-600 dark:text-gray-300">{content?.bankAccountNumber}</p>
<p className="mb-1 ml-1 text-gray-600 dark:text-gray-300">{content?.bankIban}</p>
</div>
</div>
</div>
</SelectableBlock>
<SelectableBlock
id="work-hours"
isActive={selectedBlockId === 'work-hours'}
isDesignMode={isDesignMode}
onSelect={handleSelectBlock}
>
<div className={`${content?.workHoursStyleClass || 'rounded-xl bg-white p-8 shadow-lg'} dark:bg-gray-900 dark:shadow-gray-950/40`}>
<h2 className="mb-6 text-2xl font-bold text-gray-900 dark:text-gray-100">{content?.workHoursTitle}</h2>
<div className="space-y-2">
<div className="flex items-center space-x-2">
<FaCalendarAlt className="h-5 w-5 text-blue-500 dark:text-blue-400" />
<p className="text-gray-600 dark:text-gray-300">{content?.workWeekday}</p>
</div>
<div className="flex items-center space-x-2">
<FaCalendarCheck className="h-5 w-5 text-blue-500 dark:text-blue-400" />
<p className="text-gray-600 dark:text-gray-300">{content?.workWeekend}</p>
</div>
<div className="flex items-center space-x-2">
<FaRegComment className="h-5 w-5 text-green-500 dark:text-green-400" />
<p className="text-gray-600 dark:text-gray-300">{content?.workWhatsapp}</p>
</div>
</div>
</div>
</SelectableBlock>
</div>
<SelectableBlock
id="map"
isActive={selectedBlockId === 'map'}
isDesignMode={isDesignMode}
onSelect={handleSelectBlock}
>
<div className={`${content?.mapContainerStyleClass || 'rounded-xl bg-white p-8 shadow-lg'} dark:bg-gray-900 dark:shadow-gray-950/40`}>
<h2 className="mb-2 text-center text-2xl font-bold text-gray-900 dark:text-gray-100">{content?.mapTitle}</h2>
<div className={`${content?.mapFrameStyleClass || 'aspect-w-16 aspect-h-9 overflow-hidden rounded-xl bg-gray-200'} dark:bg-gray-800`}>
<iframe
src={content?.mapSrc}
width={content?.mapWidth}
style={{ border: 0 }}
height={content?.mapHeight}
allowFullScreen={(content?.mapAllowFullScreen || '').toLowerCase() === 'true'}
loading={content?.mapLoading as 'lazy' | 'eager' | undefined}
referrerPolicy={content?.mapReferrerPolicy as React.HTMLAttributeReferrerPolicy | undefined}
></iframe>
</div>
</div>
</SelectableBlock>
</div>
</div>
</div>
<DesignerDrawer
isOpen={isDesignMode && isPanelVisible}
selection={selectedSelection}
pageTitle="Contact"
selectedLanguage={selectedLanguage}
languages={
languageOptions.length > 0
? languageOptions
: supportedLanguages.map((language) => ({
key: language,
cultureName: language,
displayName: language.toUpperCase(),
}))
}
onClose={() => setIsPanelVisible(false)}
onSave={handleSaveAndExit}
onLanguageChange={handleLanguageChange}
onReset={resetContent}
onFieldChange={handleFieldChange}
/>
</div>
)
}
export default Contact