851 lines
30 KiB
TypeScript
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: '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 (
|
|
<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
|