Home ve Contact Designer komponenti tasarlandı

This commit is contained in:
Sedat ÖZTÜRK 2026-03-17 14:27:30 +03:00
parent 4304229079
commit 42f20c224f
19 changed files with 2502 additions and 601 deletions

View file

@ -0,0 +1,92 @@
using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;
using Volo.Abp.Application.Dtos;
namespace Sozsoft.Platform.Public;
public class HomeDto : EntityDto<Guid>
{
public string HeroBackgroundImageKey { get; set; }
public string HeroPrimaryCtaKey { get; set; }
public string HeroSecondaryCtaKey { get; set; }
public string FeaturesTitleKey { get; set; }
public string FeaturesSubtitleKey { get; set; }
public string SolutionsTitleKey { get; set; }
public string SolutionsSubtitleKey { get; set; }
public string CtaTitleKey { get; set; }
public string CtaSubtitleKey { get; set; }
public string CtaButtonLabelKey { get; set; }
[JsonIgnore]
public string SlidesJson { get; set; }
public List<HomeSlideDto> SlidesDto
{
get
{
if (!string.IsNullOrEmpty(SlidesJson))
return JsonSerializer.Deserialize<List<HomeSlideDto>>(SlidesJson);
return [];
}
set { SlidesJson = JsonSerializer.Serialize(value); }
}
[JsonIgnore]
public string FeaturesJson { get; set; }
public List<HomeFeatureDto> FeaturesDto
{
get
{
if (!string.IsNullOrEmpty(FeaturesJson))
return JsonSerializer.Deserialize<List<HomeFeatureDto>>(FeaturesJson);
return [];
}
set { FeaturesJson = JsonSerializer.Serialize(value); }
}
[JsonIgnore]
public string SolutionsJson { get; set; }
public List<HomeSolutionDto> SolutionsDto
{
get
{
if (!string.IsNullOrEmpty(SolutionsJson))
return JsonSerializer.Deserialize<List<HomeSolutionDto>>(SolutionsJson);
return [];
}
set { SolutionsJson = JsonSerializer.Serialize(value); }
}
}
public class HomeSlideDto
{
public string TitleKey { get; set; }
public string SubtitleKey { get; set; }
public List<HomeSlideServiceDto> Services { get; set; } = [];
}
public class HomeSlideServiceDto
{
public string Icon { get; set; }
public string TitleKey { get; set; }
public string DescriptionKey { get; set; }
}
public class HomeFeatureDto
{
public string Icon { get; set; }
public string TitleKey { get; set; }
public string DescriptionKey { get; set; }
}
public class HomeSolutionDto
{
public string Icon { get; set; }
public string ColorClass { get; set; }
public string TitleKey { get; set; }
public string DescriptionKey { get; set; }
}

View file

@ -76,3 +76,114 @@ public class SaveLocalizedTextInput
public string Key { get; set; }
public string Value { get; set; }
}
public class SaveHomePageInput
{
public string CultureName { get; set; }
public string HeroBackgroundImageKey { get; set; }
public string HeroBackgroundImageValue { get; set; }
public string HeroPrimaryCtaKey { get; set; }
public string HeroPrimaryCtaValue { get; set; }
public string HeroSecondaryCtaKey { get; set; }
public string HeroSecondaryCtaValue { get; set; }
public string FeaturesTitleKey { get; set; }
public string FeaturesTitleValue { get; set; }
public string FeaturesSubtitleKey { get; set; }
public string FeaturesSubtitleValue { get; set; }
public string SolutionsTitleKey { get; set; }
public string SolutionsTitleValue { get; set; }
public string SolutionsSubtitleKey { get; set; }
public string SolutionsSubtitleValue { get; set; }
public string CtaTitleKey { get; set; }
public string CtaTitleValue { get; set; }
public string CtaSubtitleKey { get; set; }
public string CtaSubtitleValue { get; set; }
public string CtaButtonLabelKey { get; set; }
public string CtaButtonLabelValue { get; set; }
public List<SaveHomeSlideInput> Slides { get; set; } = [];
public List<SaveHomeFeatureInput> Features { get; set; } = [];
public List<SaveHomeSolutionInput> Solutions { get; set; } = [];
}
public class SaveHomeSlideInput
{
public string TitleKey { get; set; }
public string TitleValue { get; set; }
public string SubtitleKey { get; set; }
public string SubtitleValue { get; set; }
public List<SaveHomeSlideServiceInput> Services { get; set; } = [];
}
public class SaveHomeSlideServiceInput
{
public string Icon { get; set; }
public string TitleKey { get; set; }
public string TitleValue { get; set; }
public string DescriptionKey { get; set; }
public string DescriptionValue { get; set; }
}
public class SaveHomeFeatureInput
{
public string Icon { get; set; }
public string TitleKey { get; set; }
public string TitleValue { get; set; }
public string DescriptionKey { get; set; }
public string DescriptionValue { get; set; }
}
public class SaveHomeSolutionInput
{
public string Icon { get; set; }
public string ColorClass { get; set; }
public string TitleKey { get; set; }
public string TitleValue { get; set; }
public string DescriptionKey { get; set; }
public string DescriptionValue { get; set; }
}
public class SaveContactPageInput
{
public string CultureName { get; set; }
public string HeroTitleKey { get; set; }
public string HeroTitleValue { get; set; }
public string HeroSubtitleKey { get; set; }
public string HeroSubtitleValue { get; set; }
public string HeroImageKey { get; set; }
public string HeroImageValue { get; set; }
public string ContactInfoTitleKey { get; set; }
public string ContactInfoTitleValue { get; set; }
public string AddressKey { get; set; }
public string AddressValue { get; set; }
public string PhoneNumber { get; set; }
public string Email { get; set; }
public string Location { get; set; }
public string TaxNumber { get; set; }
public string BankTitleKey { get; set; }
public string BankTitleValue { get; set; }
public string BankAccountHolder { get; set; }
public string BankBranch { get; set; }
public string BankAccountNumber { get; set; }
public string BankIban { get; set; }
public string WorkHoursTitleKey { get; set; }
public string WorkHoursTitleValue { get; set; }
public string WorkWeekdayKey { get; set; }
public string WorkWeekdayValue { get; set; }
public string WorkWeekendKey { get; set; }
public string WorkWeekendValue { get; set; }
public string WorkWhatsappKey { get; set; }
public string WorkWhatsappValue { get; set; }
public string MapTitleKey { get; set; }
public string MapTitleValue { get; set; }
public string MapSrc { get; set; }
public string MapWidth { get; set; }
public string MapHeight { get; set; }
public bool MapAllowFullScreen { get; set; }
public string MapLoading { get; set; }
public string MapReferrerPolicy { get; set; }
}

View file

@ -31,6 +31,7 @@ public class PublicAppService : PlatformAppService
private readonly IRepository<InstallmentOption> _installmentOptionRepository;
private readonly IRepository<Order, Guid> _orderRepository;
private readonly IRepository<About, Guid> _aboutRepository;
private readonly IRepository<Home, Guid> _homeRepository;
private readonly IRepository<Contact, Guid> _contactRepository;
private readonly IIdentityUserRepository _identityUserRepository;
private readonly IRepository<LanguageKey, Guid> _languageKeyRepository;
@ -49,6 +50,7 @@ public class PublicAppService : PlatformAppService
IRepository<InstallmentOption> installmentOptionRepository,
IRepository<Order, Guid> orderRepository,
IRepository<About, Guid> aboutRepository,
IRepository<Home, Guid> homeRepository,
IRepository<Contact, Guid> contactRepository,
IIdentityUserRepository identityUserRepository,
IRepository<LanguageKey, Guid> languageKeyRepository,
@ -67,6 +69,7 @@ public class PublicAppService : PlatformAppService
_installmentOptionRepository = installmentOptionRepository;
_orderRepository = orderRepository;
_aboutRepository = aboutRepository;
_homeRepository = homeRepository;
_contactRepository = contactRepository;
_identityUserRepository = identityUserRepository;
_languageKeyRepository = languageKeyRepository;
@ -177,6 +180,109 @@ public class PublicAppService : PlatformAppService
await _languageTextAppService.ClearRedisCacheAsync();
}
public async Task<HomeDto> GetHomeAsync()
{
var entity = await _homeRepository.FirstOrDefaultAsync();
if (entity == null)
{
entity = await _homeRepository.InsertAsync(CreateDefaultHomeEntity(), autoSave: true);
}
return ObjectMapper.Map<Home, HomeDto>(entity);
}
public async Task SaveHomePageAsync(SaveHomePageInput input)
{
var entity = await _homeRepository.FirstOrDefaultAsync();
var isNewEntity = entity == null;
entity ??= CreateDefaultHomeEntity();
entity.HeroBackgroundImageKey = input.HeroBackgroundImageKey;
entity.HeroPrimaryCtaKey = input.HeroPrimaryCtaKey;
entity.HeroSecondaryCtaKey = input.HeroSecondaryCtaKey;
entity.FeaturesTitleKey = input.FeaturesTitleKey;
entity.FeaturesSubtitleKey = input.FeaturesSubtitleKey;
entity.SolutionsTitleKey = input.SolutionsTitleKey;
entity.SolutionsSubtitleKey = input.SolutionsSubtitleKey;
entity.CtaTitleKey = input.CtaTitleKey;
entity.CtaSubtitleKey = input.CtaSubtitleKey;
entity.CtaButtonLabelKey = input.CtaButtonLabelKey;
entity.SlidesJson = JsonSerializer.Serialize(input.Slides.Select(slide => new HomeSlideDto
{
TitleKey = slide.TitleKey,
SubtitleKey = slide.SubtitleKey,
Services = slide.Services.Select(service => new HomeSlideServiceDto
{
Icon = service.Icon,
TitleKey = service.TitleKey,
DescriptionKey = service.DescriptionKey,
}).ToList(),
}).ToList());
entity.FeaturesJson = JsonSerializer.Serialize(input.Features.Select(feature => new HomeFeatureDto
{
Icon = feature.Icon,
TitleKey = feature.TitleKey,
DescriptionKey = feature.DescriptionKey,
}).ToList());
entity.SolutionsJson = JsonSerializer.Serialize(input.Solutions.Select(solution => new HomeSolutionDto
{
Icon = solution.Icon,
ColorClass = solution.ColorClass,
TitleKey = solution.TitleKey,
DescriptionKey = solution.DescriptionKey,
}).ToList());
if (isNewEntity)
{
await _homeRepository.InsertAsync(entity, autoSave: false);
}
else
{
await _homeRepository.UpdateAsync(entity, autoSave: false);
}
await UpsertLanguageTextAsync(input.CultureName, input.HeroBackgroundImageKey, input.HeroBackgroundImageValue);
await UpsertLanguageTextAsync(input.CultureName, input.HeroPrimaryCtaKey, input.HeroPrimaryCtaValue);
await UpsertLanguageTextAsync(input.CultureName, input.HeroSecondaryCtaKey, input.HeroSecondaryCtaValue);
await UpsertLanguageTextAsync(input.CultureName, input.FeaturesTitleKey, input.FeaturesTitleValue);
await UpsertLanguageTextAsync(input.CultureName, input.FeaturesSubtitleKey, input.FeaturesSubtitleValue);
await UpsertLanguageTextAsync(input.CultureName, input.SolutionsTitleKey, input.SolutionsTitleValue);
await UpsertLanguageTextAsync(input.CultureName, input.SolutionsSubtitleKey, input.SolutionsSubtitleValue);
await UpsertLanguageTextAsync(input.CultureName, input.CtaTitleKey, input.CtaTitleValue);
await UpsertLanguageTextAsync(input.CultureName, input.CtaSubtitleKey, input.CtaSubtitleValue);
await UpsertLanguageTextAsync(input.CultureName, input.CtaButtonLabelKey, input.CtaButtonLabelValue);
foreach (var slide in input.Slides)
{
await UpsertLanguageTextAsync(input.CultureName, slide.TitleKey, slide.TitleValue);
await UpsertLanguageTextAsync(input.CultureName, slide.SubtitleKey, slide.SubtitleValue);
foreach (var service in slide.Services)
{
await UpsertLanguageTextAsync(input.CultureName, service.TitleKey, service.TitleValue);
await UpsertLanguageTextAsync(input.CultureName, service.DescriptionKey, service.DescriptionValue);
}
}
foreach (var feature in input.Features)
{
await UpsertLanguageTextAsync(input.CultureName, feature.TitleKey, feature.TitleValue);
await UpsertLanguageTextAsync(input.CultureName, feature.DescriptionKey, feature.DescriptionValue);
}
foreach (var solution in input.Solutions)
{
await UpsertLanguageTextAsync(input.CultureName, solution.TitleKey, solution.TitleValue);
await UpsertLanguageTextAsync(input.CultureName, solution.DescriptionKey, solution.DescriptionValue);
}
await CurrentUnitOfWork!.SaveChangesAsync();
await _languageTextAppService.ClearRedisCacheAsync();
}
public async Task CreateDemoAsync(DemoDto input)
{
var demo = ObjectMapper.Map<DemoDto, Demo>(input);
@ -406,6 +512,137 @@ public class PublicAppService : PlatformAppService
return ObjectMapper.Map<Contact, ContactDto>(entity);
}
public async Task SaveContactPageAsync(SaveContactPageInput input)
{
var entity = await _contactRepository.FirstOrDefaultAsync() ?? throw new EntityNotFoundException(typeof(Contact));
entity.Address = input.AddressKey;
entity.PhoneNumber = input.PhoneNumber;
entity.Email = input.Email;
entity.Location = input.Location;
entity.TaxNumber = long.TryParse(input.TaxNumber, out var taxNumber) ? taxNumber : null;
entity.BankJson = JsonSerializer.Serialize(new BankDto
{
AccountHolder = input.BankAccountHolder,
Branch = input.BankBranch,
AccountNumber = input.BankAccountNumber,
Iban = input.BankIban,
});
entity.WorkHoursJson = JsonSerializer.Serialize(new WorkHoursDto
{
Weekday = input.WorkWeekdayKey,
Weekend = input.WorkWeekendKey,
Whatsapp = input.WorkWhatsappKey,
});
entity.MapJson = JsonSerializer.Serialize(new MapDto
{
Title = input.MapTitleKey,
Src = input.MapSrc,
Width = input.MapWidth,
Height = input.MapHeight,
AllowFullScreen = input.MapAllowFullScreen,
Loading = input.MapLoading,
ReferrerPolicy = input.MapReferrerPolicy,
});
await _contactRepository.UpdateAsync(entity, autoSave: false);
await UpsertLanguageTextAsync(input.CultureName, input.HeroTitleKey, input.HeroTitleValue);
await UpsertLanguageTextAsync(input.CultureName, input.HeroSubtitleKey, input.HeroSubtitleValue);
await UpsertLanguageTextAsync(input.CultureName, input.HeroImageKey, input.HeroImageValue);
await UpsertLanguageTextAsync(input.CultureName, input.ContactInfoTitleKey, input.ContactInfoTitleValue);
await UpsertLanguageTextAsync(input.CultureName, input.AddressKey, input.AddressValue);
await UpsertLanguageTextAsync(input.CultureName, input.BankTitleKey, input.BankTitleValue);
await UpsertLanguageTextAsync(input.CultureName, input.WorkHoursTitleKey, input.WorkHoursTitleValue);
await UpsertLanguageTextAsync(input.CultureName, input.WorkWeekdayKey, input.WorkWeekdayValue);
await UpsertLanguageTextAsync(input.CultureName, input.WorkWeekendKey, input.WorkWeekendValue);
await UpsertLanguageTextAsync(input.CultureName, input.WorkWhatsappKey, input.WorkWhatsappValue);
await UpsertLanguageTextAsync(input.CultureName, input.MapTitleKey, input.MapTitleValue);
await CurrentUnitOfWork!.SaveChangesAsync();
await _languageTextAppService.ClearRedisCacheAsync();
}
private static Home CreateDefaultHomeEntity()
{
var slides = new List<HomeSlideDto>
{
new()
{
TitleKey = "Public.hero.slide1.title",
SubtitleKey = "Public.hero.slide1.subtitle",
Services = new List<HomeSlideServiceDto>
{
new() { Icon = "FaCalendarAlt", TitleKey = "Public.hero.slide1.service1.title", DescriptionKey = "Public.hero.slide1.service1.desc" },
new() { Icon = "FaUsers", TitleKey = "Public.hero.slide1.service2.title", DescriptionKey = "Public.hero.slide1.service2.desc" },
new() { Icon = "FaShieldAlt", TitleKey = "Public.hero.slide1.service3.title", DescriptionKey = "Public.hero.slide1.service3.desc" },
},
},
new()
{
TitleKey = "Public.hero.slide2.title",
SubtitleKey = "Public.hero.slide2.subtitle",
Services = new List<HomeSlideServiceDto>
{
new() { Icon = "FaChartBar", TitleKey = "Public.hero.slide2.service1.title", DescriptionKey = "Public.hero.slide2.service1.desc" },
new() { Icon = "FaCreditCard", TitleKey = "Public.hero.slide2.service2.title", DescriptionKey = "Public.hero.slide2.service2.desc" },
new() { Icon = "FaDatabase", TitleKey = "Public.hero.slide2.service3.title", DescriptionKey = "Public.hero.slide2.service3.desc" },
},
},
new()
{
TitleKey = "Public.hero.slide3.title",
SubtitleKey = "Public.hero.slide3.subtitle",
Services = new List<HomeSlideServiceDto>
{
new() { Icon = "FaDesktop", TitleKey = "Public.hero.slide3.service1.title", DescriptionKey = "Public.hero.slide3.service1.desc" },
new() { Icon = "FaServer", TitleKey = "Public.hero.slide3.service2.title", DescriptionKey = "Public.hero.slide3.service2.desc" },
new() { Icon = "FaMobileAlt", TitleKey = "Public.hero.slide3.service3.title", DescriptionKey = "Public.hero.slide3.service3.desc" },
},
},
};
var features = new List<HomeFeatureDto>
{
new() { Icon = "FaUsers", TitleKey = "Public.features.reliable", DescriptionKey = "Public.features.reliable.desc" },
new() { Icon = "FaCalendarAlt", TitleKey = "App.Coordinator.Classroom.Planning", DescriptionKey = "Public.features.rapid.desc" },
new() { Icon = "FaBookOpen", TitleKey = "Public.features.expert", DescriptionKey = "Public.features.expert.desc" },
new() { Icon = "FaCreditCard", TitleKey = "Public.features.muhasebe", DescriptionKey = "Public.features.muhasebe.desc" },
new() { Icon = "FaRegComment", TitleKey = "Public.features.iletisim", DescriptionKey = "Public.features.iletisim.desc" },
new() { Icon = "FaPhone", TitleKey = "Public.features.mobil", DescriptionKey = "Public.features.mobil.desc" },
new() { Icon = "FaChartBar", TitleKey = "Public.features.scalable", DescriptionKey = "Public.features.scalable.desc" },
new() { Icon = "FaShieldAlt", TitleKey = "Public.features.guvenlik", DescriptionKey = "Public.features.guvenlik.desc" },
};
var solutions = new List<HomeSolutionDto>
{
new() { Icon = "FaDesktop", ColorClass = "bg-blue-600", TitleKey = "Public.services.web.title", DescriptionKey = "Public.solutions.web.desc" },
new() { Icon = "FaMobileAlt", ColorClass = "bg-purple-600", TitleKey = "Public.services.mobile.title", DescriptionKey = "Public.solutions.mobile.desc" },
new() { Icon = "FaServer", ColorClass = "bg-green-600", TitleKey = "Public.solutions.custom.title", DescriptionKey = "Public.solutions.custom.desc" },
new() { Icon = "FaDatabase", ColorClass = "bg-red-600", TitleKey = "Public.solutions.database.title", DescriptionKey = "Public.solutions.database.desc" },
};
return new Home
{
HeroBackgroundImageKey = "Public.home.hero.backgroundImage",
HeroPrimaryCtaKey = "Public.hero.cta.consultation",
HeroSecondaryCtaKey = "Public.hero.cta.discover",
FeaturesTitleKey = "Public.features.title",
FeaturesSubtitleKey = "Public.features.subtitle",
SolutionsTitleKey = "Public.solutions.title",
SolutionsSubtitleKey = "Public.solutions.subtitle",
CtaTitleKey = "Public.common.getStarted",
CtaSubtitleKey = "Public.common.contact",
CtaButtonLabelKey = "Public.common.learnMore",
SlidesJson = JsonSerializer.Serialize(slides),
FeaturesJson = JsonSerializer.Serialize(features),
SolutionsJson = JsonSerializer.Serialize(solutions),
};
}
private async Task UpsertLanguageTextAsync(string cultureName, string key, string value)
{
if (key.IsNullOrWhiteSpace())

View file

@ -18,6 +18,7 @@ public class PublicAutoMapperProfile : Profile
CreateMap<InstallmentOption, InstallmentOptionDto>();
CreateMap<Order, OrderDto>();
CreateMap<About, AboutDto>();
CreateMap<Home, HomeDto>();
CreateMap<Contact, ContactDto>();
}
}

View file

@ -7385,237 +7385,5 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
}
#endregion
#region Contact
listFormName = AppCodes.Contact;
if (!await _listFormRepository.AnyAsync(a => a.ListFormCode == listFormName))
{
var listForm = await _listFormRepository.InsertAsync(
new ListForm
{
ListFormType = ListFormTypeEnum.List,
PageSize = 10,
ExportJson = DefaultExportJson,
IsSubForm = false,
ShowNote = true,
LayoutJson = DefaultLayoutJson(),
CultureName = LanguageCodes.En,
ListFormCode = listFormName,
Name = listFormName,
Title = listFormName,
DataSourceCode = SeedConsts.DataSources.DefaultCode,
IsTenant = false,
IsBranch = false,
IsOrganizationUnit = false,
Description = listFormName,
SelectCommandType = SelectCommandTypeEnum.Table,
SelectCommand = TableNameResolver.GetFullTableName(nameof(TableNameEnum.Contact)),
KeyFieldName = "Id",
DefaultFilter = DefaultFilterJson,
KeyFieldDbSourceType = DbType.Guid,
SortMode = GridOptions.SortModeSingle,
FilterRowJson = DefaultFilterRowJson,
HeaderFilterJson = DefaultHeaderFilterJson,
SearchPanelJson = DefaultSearchPanelJson,
GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }),
SelectionJson = DefaultSelectionSingleJson,
ColumnOptionJson = DefaultColumnOptionJson(),
PermissionJson = DefaultPermissionJson(listFormName),
PagerOptionJson = DefaultPagerOptionJson,
EditingOptionJson = DefaultEditingOptionJson(listFormName, 800, 700, true, true, true, true, false),
EditingFormJson = JsonSerializer.Serialize(new List<EditingFormDto>
{
new() {
Order = 1, ColCount = 1, ColSpan = 1, ItemType = "group", Items =
[
new EditingFormItemDto { Order = 1, DataField = "Address", ColSpan = 1, IsRequired = true, EditorType2=EditorTypes.dxAutocomplete, EditorOptions=EditorOptionValues.ShowClearButton },
new EditingFormItemDto { Order = 2, DataField = "PhoneNumber", ColSpan = 1, IsRequired = true, EditorType2=EditorTypes.dxTextBox, EditorOptions=EditorOptionValues.PhoneEditorOptions },
new EditingFormItemDto { Order = 3, DataField = "Email", ColSpan = 1, IsRequired = true, EditorType2=EditorTypes.dxTextBox },
new EditingFormItemDto { Order = 4, DataField = "Location", ColSpan = 1, IsRequired = true, EditorType2=EditorTypes.dxTextBox },
new EditingFormItemDto { Order = 5, DataField = "TaxNumber", ColSpan = 1, IsRequired = true, EditorType2=EditorTypes.dxNumberBox },
new EditingFormItemDto { Order = 6, DataField = "BankJson", ColSpan = 1, IsRequired = true, EditorType2=EditorTypes.dxTextArea, EditorOptions="{\"height\":100}" },
new EditingFormItemDto { Order = 7, DataField = "WorkHoursJson", ColSpan = 1, IsRequired = true, EditorType2=EditorTypes.dxTextArea, EditorOptions="{\"height\":100}" },
new EditingFormItemDto { Order = 8, DataField = "MapJson", ColSpan = 1, IsRequired = true, EditorType2=EditorTypes.dxTextArea, EditorOptions="{\"height\":100}" },
]
}
}),
DeleteCommand = DefaultDeleteCommand(nameof(TableNameEnum.Contact)),
DeleteFieldsDefaultValueJson = DefaultDeleteFieldsDefaultValueJson(),
InsertFieldsDefaultValueJson = DefaultInsertFieldsDefaultValueJson(),
});
#region Contact Fields
await _listFormFieldRepository.InsertManyAsync([
new()
{
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.Guid,
FieldName = "Id",
CaptionName = "App.Listform.ListformField.Id",
Width = 100,
ListOrderNo = 1,
Visible = false,
IsActive = true,
IsDeleted = false,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson,
},
new()
{
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.String,
FieldName = "Address",
CaptionName = "App.Listform.ListformField.Address",
Width = 400,
ListOrderNo = 2,
Visible = true,
IsActive = true,
IsDeleted = false,
AllowSearch = false,
LookupJson = JsonSerializer.Serialize(new LookupDto {
DataSourceType = UiLookupDataSourceTypeEnum.Query,
DisplayExpr = "Name",
ValueExpr = "Key",
LookupQuery = LookupQueryValues.LanguageKeyValues
}),
ValidationRuleJson = DefaultValidationRuleRequiredJson,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson,
},
new()
{
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.String,
FieldName = "PhoneNumber",
CaptionName = "App.Listform.ListformField.PhoneNumber",
Width = 100,
ListOrderNo = 3,
Visible = true,
IsActive = true,
IsDeleted = false,
AllowSearch = true,
ValidationRuleJson = DefaultValidationRuleRequiredJson,
EditorOptions = EditorOptionValues.PhoneEditorOptions,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson,
},
new()
{
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.String,
FieldName = "Email",
CaptionName = "App.Listform.ListformField.Email",
Width = 150,
ListOrderNo = 4,
Visible = true,
IsActive = true,
IsDeleted = false,
AllowSearch = true,
ValidationRuleJson = DefaultValidationRuleEmailRequiredJson,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson,
},
new()
{
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.String,
FieldName = "Location",
CaptionName = "App.Listform.ListformField.Location",
Width = 100,
ListOrderNo = 5,
Visible = true,
IsActive = true,
IsDeleted = false,
AllowSearch = true,
ValidationRuleJson = DefaultValidationRuleRequiredJson,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson,
},
new()
{
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.String,
FieldName = "TaxNumber",
CaptionName = "App.Listform.ListformField.TaxNumber",
Width = 100,
ListOrderNo = 6,
Visible = true,
IsActive = true,
IsDeleted = false,
AllowSearch = true,
ValidationRuleJson = DefaultValidationRuleRequiredJson,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson,
},
new()
{
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.String,
FieldName = "BankJson",
CaptionName = "App.Listform.ListformField.BankJson",
Width = 450,
ListOrderNo = 7,
Visible = true,
IsActive = true,
IsDeleted = false,
AllowSearch = true,
ValidationRuleJson = DefaultValidationRuleRequiredJson,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson,
},
new()
{
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.String,
FieldName = "WorkHoursJson",
CaptionName = "App.Listform.ListformField.WorkHoursJson",
Width = 350,
ListOrderNo = 8,
Visible = true,
IsActive = true,
IsDeleted = false,
AllowSearch = true,
ValidationRuleJson = DefaultValidationRuleRequiredJson,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson,
},
new()
{
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.String,
FieldName = "MapJson",
CaptionName = "App.Listform.ListformField.MapJson",
Width = 100,
ListOrderNo = 9,
Visible = false,
IsActive = true,
IsDeleted = false,
AllowSearch = true,
ValidationRuleJson = DefaultValidationRuleRequiredJson,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson,
},
]);
#endregion
}
#endregion
}
}

View file

@ -372,11 +372,11 @@
"authority": []
},
{
"key": "servicesDesigner",
"path": "/admin/public/services/designer",
"componentPath": "@/views/public/Services",
"key": "homeDesigner",
"path": "/admin/public/home/designer",
"componentPath": "@/views/public/Home",
"routeType": "protected",
"authority": ["App.Services"]
"authority": ["App.Home"]
},
{
"key": "aboutDesigner",
@ -384,6 +384,20 @@
"componentPath": "@/views/public/About",
"routeType": "protected",
"authority": ["App.About"]
},
{
"key": "servicesDesigner",
"path": "/admin/public/services/designer",
"componentPath": "@/views/public/Services",
"routeType": "protected",
"authority": ["App.Services"]
},
{
"key": "contactDesigner",
"path": "/admin/public/contact/designer",
"componentPath": "@/views/public/Contact",
"routeType": "protected",
"authority": ["App.Contact"]
}
],
"Menus": [
@ -639,6 +653,16 @@
"RequiredPermissionName": null,
"IsDisabled": false
},
{
"ParentCode": "App.Public",
"Code": "App.Home",
"DisplayName": "App.Home",
"Order": 0,
"Url": "/admin/public/home/designer",
"Icon": "FcHome",
"RequiredPermissionName": "App.Home",
"IsDisabled": false
},
{
"ParentCode": "App.Public",
"Code": "App.About",
@ -734,7 +758,7 @@
"Code": "App.Contact",
"DisplayName": "App.Contact",
"Order": 10,
"Url": "/admin/list/App.Contact",
"Url": "/admin/public/contact/designer",
"Icon": "FcContacts",
"RequiredPermissionName": "App.Contact",
"IsDisabled": false

View file

@ -1550,7 +1550,15 @@
"MenuGroup": "Erp|Kurs"
},
{
"GroupName": "App.Saas",
"Name": "App.Home",
"ParentName": null,
"DisplayName": "App.Home",
"IsEnabled": true,
"MultiTenancySide": 2,
"MenuGroup": "Erp|Kurs"
},
{
"GroupName": "App.Saas",
"Name": "App.About",
@ -2029,60 +2037,6 @@
"MultiTenancySide": 2,
"MenuGroup": "Erp|Kurs"
},
{
"GroupName": "App.Saas",
"Name": "App.Contact.Create",
"ParentName": "App.Contact",
"DisplayName": "Create",
"IsEnabled": true,
"MultiTenancySide": 2,
"MenuGroup": "Erp|Kurs"
},
{
"GroupName": "App.Saas",
"Name": "App.Contact.Update",
"ParentName": "App.Contact",
"DisplayName": "Update",
"IsEnabled": true,
"MultiTenancySide": 2,
"MenuGroup": "Erp|Kurs"
},
{
"GroupName": "App.Saas",
"Name": "App.Contact.Delete",
"ParentName": "App.Contact",
"DisplayName": "Delete",
"IsEnabled": true,
"MultiTenancySide": 2,
"MenuGroup": "Erp|Kurs"
},
{
"GroupName": "App.Saas",
"Name": "App.Contact.Export",
"ParentName": "App.Contact",
"DisplayName": "Export",
"IsEnabled": true,
"MultiTenancySide": 2,
"MenuGroup": "Erp|Kurs"
},
{
"GroupName": "App.Saas",
"Name": "App.Contact.Import",
"ParentName": "App.Contact",
"DisplayName": "Import",
"IsEnabled": true,
"MultiTenancySide": 2,
"MenuGroup": "Erp|Kurs"
},
{
"GroupName": "App.Saas",
"Name": "App.Contact.Note",
"ParentName": "App.Contact",
"DisplayName": "Note",
"IsEnabled": true,
"MultiTenancySide": 2,
"MenuGroup": "Erp|Kurs"
},
{
"GroupName": "App.Saas",
"Name": "App.Routes",

View file

@ -50,6 +50,7 @@ public enum TableNameEnum
Uom,
WorkHour,
About,
Home,
Service,
Product,
PaymentMethod,

View file

@ -47,6 +47,7 @@ public static class TableNameResolver
{ nameof(TableNameEnum.ForumCategory), (TablePrefix.TenantByName, MenuPrefix.Saas) },
{ nameof(TableNameEnum.ForumTopic), (TablePrefix.TenantByName, MenuPrefix.Saas) },
{ nameof(TableNameEnum.ForumPost), (TablePrefix.TenantByName, MenuPrefix.Saas) },
{ nameof(TableNameEnum.Home), (TablePrefix.PlatformByName, MenuPrefix.Saas) },
{ nameof(TableNameEnum.About), (TablePrefix.PlatformByName, MenuPrefix.Saas) },
{ nameof(TableNameEnum.Service), (TablePrefix.PlatformByName, MenuPrefix.Saas) },
{ nameof(TableNameEnum.Product), (TablePrefix.PlatformByName, MenuPrefix.Saas) },

View file

@ -0,0 +1,21 @@
using System;
using Volo.Abp.Domain.Entities.Auditing;
namespace Sozsoft.Platform.Entities;
public class Home : FullAuditedEntity<Guid>
{
public string HeroBackgroundImageKey { get; set; }
public string HeroPrimaryCtaKey { get; set; }
public string HeroSecondaryCtaKey { get; set; }
public string FeaturesTitleKey { get; set; }
public string FeaturesSubtitleKey { get; set; }
public string SolutionsTitleKey { get; set; }
public string SolutionsSubtitleKey { get; set; }
public string CtaTitleKey { get; set; }
public string CtaSubtitleKey { get; set; }
public string CtaButtonLabelKey { get; set; }
public string SlidesJson { get; set; }
public string FeaturesJson { get; set; }
public string SolutionsJson { get; set; }
}

View file

@ -84,6 +84,7 @@ public class PlatformDbContext :
public DbSet<IdentityUserDelegation> UserDelegations { get; set; }
public DbSet<IdentitySession> Sessions { get; set; }
public DbSet<About> Abouts { get; set; }
public DbSet<Home> Homes { get; set; }
public DbSet<Service> Services { get; set; }
public DbSet<Product> Products { get; set; }
public DbSet<PaymentMethod> PaymentMethods { get; set; }
@ -777,6 +778,26 @@ public class PlatformDbContext :
b.Property(x => x.SectionsJson).HasColumnType("text");
});
builder.Entity<Home>(b =>
{
b.ToTable(TableNameResolver.GetFullTableName(nameof(TableNameEnum.Home)), Prefix.DbSchema);
b.ConfigureByConvention();
b.Property(x => x.HeroBackgroundImageKey).HasMaxLength(256);
b.Property(x => x.HeroPrimaryCtaKey).HasMaxLength(256);
b.Property(x => x.HeroSecondaryCtaKey).HasMaxLength(256);
b.Property(x => x.FeaturesTitleKey).HasMaxLength(256);
b.Property(x => x.FeaturesSubtitleKey).HasMaxLength(256);
b.Property(x => x.SolutionsTitleKey).HasMaxLength(256);
b.Property(x => x.SolutionsSubtitleKey).HasMaxLength(256);
b.Property(x => x.CtaTitleKey).HasMaxLength(256);
b.Property(x => x.CtaSubtitleKey).HasMaxLength(256);
b.Property(x => x.CtaButtonLabelKey).HasMaxLength(256);
b.Property(x => x.SlidesJson).HasColumnType("text");
b.Property(x => x.FeaturesJson).HasColumnType("text");
b.Property(x => x.SolutionsJson).HasColumnType("text");
});
builder.Entity<Service>(b =>
{
b.ToTable(TableNameResolver.GetFullTableName(nameof(TableNameEnum.Service)), Prefix.DbSchema);

View file

@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore;
namespace Sozsoft.Platform.Migrations
{
[DbContext(typeof(PlatformDbContext))]
[Migration("20260315193224_Initial")]
[Migration("20260317104139_Initial")]
partial class Initial
{
/// <inheritdoc />
@ -1933,6 +1933,95 @@ namespace Sozsoft.Platform.Migrations
b.ToTable("Sas_T_GlobalSearch", (string)null);
});
modelBuilder.Entity("Sozsoft.Platform.Entities.Home", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uniqueidentifier")
.HasColumnName("CreatorId");
b.Property<string>("CtaButtonLabelKey")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<string>("CtaSubtitleKey")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<string>("CtaTitleKey")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<Guid?>("DeleterId")
.HasColumnType("uniqueidentifier")
.HasColumnName("DeleterId");
b.Property<DateTime?>("DeletionTime")
.HasColumnType("datetime2")
.HasColumnName("DeletionTime");
b.Property<string>("FeaturesJson")
.HasColumnType("text");
b.Property<string>("FeaturesSubtitleKey")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<string>("FeaturesTitleKey")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<string>("HeroBackgroundImageKey")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<string>("HeroPrimaryCtaKey")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<string>("HeroSecondaryCtaKey")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnType("bit")
.HasDefaultValue(false)
.HasColumnName("IsDeleted");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("datetime2")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uniqueidentifier")
.HasColumnName("LastModifierId");
b.Property<string>("SlidesJson")
.HasColumnType("text");
b.Property<string>("SolutionsJson")
.HasColumnType("text");
b.Property<string>("SolutionsSubtitleKey")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<string>("SolutionsTitleKey")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.HasKey("Id");
b.ToTable("Sas_H_Home", (string)null);
});
modelBuilder.Entity("Sozsoft.Platform.Entities.InstallmentOption", b =>
{
b.Property<Guid>("Id")

View file

@ -972,6 +972,37 @@ namespace Sozsoft.Platform.Migrations
table.PrimaryKey("PK_Sas_H_DynamicService", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Sas_H_Home",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
HeroBackgroundImageKey = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true),
HeroPrimaryCtaKey = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true),
HeroSecondaryCtaKey = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true),
FeaturesTitleKey = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true),
FeaturesSubtitleKey = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true),
SolutionsTitleKey = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true),
SolutionsSubtitleKey = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true),
CtaTitleKey = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true),
CtaSubtitleKey = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true),
CtaButtonLabelKey = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true),
SlidesJson = table.Column<string>(type: "text", nullable: true),
FeaturesJson = table.Column<string>(type: "text", nullable: true),
SolutionsJson = table.Column<string>(type: "text", nullable: true),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
IsDeleted = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
DeleterId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
DeletionTime = table.Column<DateTime>(type: "datetime2", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Sas_H_Home", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Sas_H_InstallmentOption",
columns: table => new
@ -3046,6 +3077,9 @@ namespace Sozsoft.Platform.Migrations
migrationBuilder.DropTable(
name: "Sas_H_DynamicService");
migrationBuilder.DropTable(
name: "Sas_H_Home");
migrationBuilder.DropTable(
name: "Sas_H_InstallmentOption");

View file

@ -1930,6 +1930,95 @@ namespace Sozsoft.Platform.Migrations
b.ToTable("Sas_T_GlobalSearch", (string)null);
});
modelBuilder.Entity("Sozsoft.Platform.Entities.Home", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uniqueidentifier")
.HasColumnName("CreatorId");
b.Property<string>("CtaButtonLabelKey")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<string>("CtaSubtitleKey")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<string>("CtaTitleKey")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<Guid?>("DeleterId")
.HasColumnType("uniqueidentifier")
.HasColumnName("DeleterId");
b.Property<DateTime?>("DeletionTime")
.HasColumnType("datetime2")
.HasColumnName("DeletionTime");
b.Property<string>("FeaturesJson")
.HasColumnType("text");
b.Property<string>("FeaturesSubtitleKey")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<string>("FeaturesTitleKey")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<string>("HeroBackgroundImageKey")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<string>("HeroPrimaryCtaKey")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<string>("HeroSecondaryCtaKey")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnType("bit")
.HasDefaultValue(false)
.HasColumnName("IsDeleted");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("datetime2")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uniqueidentifier")
.HasColumnName("LastModifierId");
b.Property<string>("SlidesJson")
.HasColumnType("text");
b.Property<string>("SolutionsJson")
.HasColumnType("text");
b.Property<string>("SolutionsSubtitleKey")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<string>("SolutionsTitleKey")
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.HasKey("Id");
b.ToTable("Sas_H_Home", (string)null);
});
modelBuilder.Entity("Sozsoft.Platform.Entities.InstallmentOption", b =>
{
b.Property<Guid>("Id")

View file

@ -10,3 +10,54 @@ export function getContact() {
{ apiName: 'Default' },
)
}
export interface SaveContactPageInput extends Record<string, unknown> {
cultureName: string
heroTitleKey: string
heroTitleValue: string
heroSubtitleKey: string
heroSubtitleValue: string
heroImageKey: string
heroImageValue: string
contactInfoTitleKey: string
contactInfoTitleValue: string
addressKey: string
addressValue: string
phoneNumber: string
email: string
location: string
taxNumber: string
bankTitleKey: string
bankTitleValue: string
bankAccountHolder: string
bankBranch: string
bankAccountNumber: string
bankIban: string
workHoursTitleKey: string
workHoursTitleValue: string
workWeekdayKey: string
workWeekdayValue: string
workWeekendKey: string
workWeekendValue: string
workWhatsappKey: string
workWhatsappValue: string
mapTitleKey: string
mapTitleValue: string
mapSrc: string
mapWidth: string
mapHeight: string
mapAllowFullScreen: boolean
mapLoading: string
mapReferrerPolicy: string
}
export function saveContactPage(input: SaveContactPageInput) {
return apiService.fetchData<void>(
{
method: 'POST',
url: '/api/app/public/save-contact-page',
data: input,
},
{ apiName: 'Default' },
)
}

View file

@ -0,0 +1,124 @@
import apiService from './api.service'
export interface HomeSlideServiceDto {
icon: string
titleKey: string
descriptionKey: string
}
export interface HomeSlideDto {
titleKey: string
subtitleKey: string
services: HomeSlideServiceDto[]
}
export interface HomeFeatureDto {
icon: string
titleKey: string
descriptionKey: string
}
export interface HomeSolutionDto {
icon: string
colorClass: string
titleKey: string
descriptionKey: string
}
export interface HomeDto {
id: string
heroBackgroundImageKey: string
heroPrimaryCtaKey: string
heroSecondaryCtaKey: string
featuresTitleKey: string
featuresSubtitleKey: string
solutionsTitleKey: string
solutionsSubtitleKey: string
ctaTitleKey: string
ctaSubtitleKey: string
ctaButtonLabelKey: string
slidesDto: HomeSlideDto[]
featuresDto: HomeFeatureDto[]
solutionsDto: HomeSolutionDto[]
}
export interface SaveHomeSlideServiceInput {
icon: string
titleKey: string
titleValue: string
descriptionKey: string
descriptionValue: string
}
export interface SaveHomeSlideInput {
titleKey: string
titleValue: string
subtitleKey: string
subtitleValue: string
services: SaveHomeSlideServiceInput[]
}
export interface SaveHomeFeatureInput {
icon: string
titleKey: string
titleValue: string
descriptionKey: string
descriptionValue: string
}
export interface SaveHomeSolutionInput {
icon: string
colorClass: string
titleKey: string
titleValue: string
descriptionKey: string
descriptionValue: string
}
export interface SaveHomePageInput {
cultureName: string
heroBackgroundImageKey: string
heroBackgroundImageValue: string
heroPrimaryCtaKey: string
heroPrimaryCtaValue: string
heroSecondaryCtaKey: string
heroSecondaryCtaValue: string
featuresTitleKey: string
featuresTitleValue: string
featuresSubtitleKey: string
featuresSubtitleValue: string
solutionsTitleKey: string
solutionsTitleValue: string
solutionsSubtitleKey: string
solutionsSubtitleValue: string
ctaTitleKey: string
ctaTitleValue: string
ctaSubtitleKey: string
ctaSubtitleValue: string
ctaButtonLabelKey: string
ctaButtonLabelValue: string
slides: SaveHomeSlideInput[]
features: SaveHomeFeatureInput[]
solutions: SaveHomeSolutionInput[]
}
export function getHome() {
return apiService.fetchData<HomeDto>(
{
method: 'GET',
url: '/api/app/public/home',
},
{ apiName: 'Default' },
)
}
export function saveHomePage(input: SaveHomePageInput) {
return apiService.fetchData<void, SaveHomePageInput>(
{
method: 'POST',
url: '/api/app/public/save-home-page',
data: input,
},
{ apiName: 'Default' },
)
}

View file

@ -1,9 +1,6 @@
import React, { useEffect, useState } from 'react'
import {
FaMailBulk,
FaPhone,
FaMapPin,
FaFileAlt,
FaBuilding,
FaCalendarAlt,
FaCalendarCheck,
@ -15,33 +12,491 @@ import {
import { useLocalization } from '@/utils/hooks/useLocalization'
import { Helmet } from 'react-helmet'
import { ContactDto } from '@/proxy/contact/models'
import { Loading } from '@/components/shared'
import { getContact } from '@/services/contact.service'
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'
interface ContactContent {
heroTitle: string
heroTitleKey: string
heroSubtitle: string
heroSubtitleKey: string
heroImage: string
heroImageKey: string
contactInfoTitle: string
contactInfoTitleKey: 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
workHoursTitle: string
workHoursTitleKey: string
workWeekday: string
workWeekdayKey: string
workWeekend: string
workWeekendKey: string
workWhatsapp: string
workWhatsappKey: string
mapTitle: string
mapTitleKey: string
mapSrc: string
mapWidth: string
mapHeight: string
mapAllowFullScreen: string
mapLoading: string
mapReferrerPolicy: 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_ADDRESS_KEY = 'Public.contact.address.full'
const CONTACT_BANK_TITLE_KEY = 'Public.contact.bank.title'
const CONTACT_WORK_HOURS_TITLE_KEY = 'App.Definitions.WorkHour'
const CONTACT_WORK_WEEKDAY_KEY = 'Public.contact.workHours.weekday'
const CONTACT_WORK_WEEKEND_KEY = 'Public.contact.workHours.weekend'
const CONTACT_WORK_WHATSAPP_KEY = 'Public.contact.workHours.whatsapp'
const CONTACT_MAP_TITLE_KEY = 'Public.contact.location'
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,
heroSubtitle: resolveLocalizedValue(translate, CONTACT_HERO_SUBTITLE_KEY),
heroSubtitleKey: CONTACT_HERO_SUBTITLE_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,
address: resolveLocalizedValue(translate, contact?.address || CONTACT_ADDRESS_KEY),
addressKey: contact?.address || CONTACT_ADDRESS_KEY,
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 || '',
workHoursTitle: resolveLocalizedValue(translate, CONTACT_WORK_HOURS_TITLE_KEY),
workHoursTitleKey: CONTACT_WORK_HOURS_TITLE_KEY,
workWeekday: resolveLocalizedValue(translate, contact?.workHoursDto?.weekday || CONTACT_WORK_WEEKDAY_KEY),
workWeekdayKey: contact?.workHoursDto?.weekday || CONTACT_WORK_WEEKDAY_KEY,
workWeekend: resolveLocalizedValue(translate, contact?.workHoursDto?.weekend || CONTACT_WORK_WEEKEND_KEY),
workWeekendKey: contact?.workHoursDto?.weekend || CONTACT_WORK_WEEKEND_KEY,
workWhatsapp: resolveLocalizedValue(
translate,
contact?.workHoursDto?.whatsapp || CONTACT_WORK_WHATSAPP_KEY,
),
workWhatsappKey: contact?.workHoursDto?.whatsapp || CONTACT_WORK_WHATSAPP_KEY,
mapTitle: resolveLocalizedValue(translate, contact?.mapDto?.title || CONTACT_MAP_TITLE_KEY),
mapTitleKey: contact?.mapDto?.title || CONTACT_MAP_TITLE_KEY,
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',
}
}
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 fetchServices = async () => {
const fetchContact = async () => {
try {
const result = await getContact()
setContact(result.data)
} catch (error) {
console.error('About alınırken hata oluştu:', error)
console.error('Contact alinirken hata olustu:', error)
} finally {
setLoading(false)
}
}
fetchServices()
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: 'Hero basligi, alt basligi ve arka plan gorselini duzenleyin.',
fields: [
{
key: 'heroTitle',
label: content.heroTitleKey,
type: 'text',
value: content.heroTitle,
},
{
key: 'heroSubtitle',
label: content.heroSubtitleKey,
type: 'textarea',
value: content.heroSubtitle,
},
{
key: 'heroImage',
label: content.heroImageKey,
type: 'image',
value: content.heroImage,
},
],
}
}
if (selectedBlockId === 'contact-info') {
return {
id: selectedBlockId,
title: content.contactInfoTitleKey,
description: 'Iletisim bilgilerini duzenleyin.',
fields: [
{
key: 'contactInfoTitle',
label: content.contactInfoTitleKey,
type: 'text',
value: content.contactInfoTitle,
},
{
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: 'Banka bilgilerini duzenleyin.',
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,
},
],
}
}
if (selectedBlockId === 'work-hours') {
return {
id: selectedBlockId,
title: content.workHoursTitleKey,
description: 'Calisma saatleri metinlerini duzenleyin.',
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,
},
],
}
}
if (selectedBlockId === 'map') {
return {
id: selectedBlockId,
title: content.mapTitleKey,
description: 'Harita basligi ve iframe ayarlarini duzenleyin.',
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,
},
],
}
}
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,
workHoursTitleKey: content.workHoursTitleKey,
workHoursTitleValue: content.workHoursTitle,
workWeekdayKey: content.workWeekdayKey,
workWeekdayValue: content.workWeekday,
workWeekendKey: content.workWeekendKey,
workWeekendValue: content.workWeekend,
workWhatsappKey: content.workWhatsappKey,
workWhatsappValue: content.workWhatsapp,
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,
})
await getConfig(false)
setSelectedBlockId(null)
} 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">
@ -53,153 +508,197 @@ const Contact: React.FC = () => {
}
return (
<div className="min-h-screen bg-gray-50">
<div className={`min-h-screen bg-gray-50 ${isDesignMode && isPanelVisible ? 'xl:pr-[420px]' : ''}`}>
<Helmet
titleTemplate={`%s | ${APP_NAME}`}
title={translate('::App.Contact')}
defaultTitle={APP_NAME}
></Helmet>
{/* Hero Section */}
<div className="relative bg-blue-900 text-white py-12">
{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="relative bg-blue-900 py-12 text-white">
<div
className="absolute inset-0 opacity-20"
style={{
backgroundImage:
'url("https://images.pexels.com/photos/3183171/pexels-photo-3183171.jpeg?auto=compress&cs=tinysrgb&w=1920")',
backgroundImage: `url("${content?.heroImage || CONTACT_HERO_IMAGE_DEFAULT}")`,
backgroundSize: 'cover',
backgroundPosition: 'center',
}}
></div>
<div className="container mx-auto pt-20 relative">
<h1 className="text-5xl font-bold ml-4 mt-3 mb-2 text-white">
{translate('::App.Contact')}
</h1>
<p className="text-xl max-w-3xl ml-4">{translate('::Public.contact.subtitle')}</p>
<div className="container relative mx-auto pt-20">
<h1 className="ml-4 mb-2 mt-3 text-5xl font-bold text-white">{content?.heroTitle}</h1>
<p className="ml-4 max-w-3xl text-xl">{content?.heroSubtitle}</p>
</div>
</div>
</SelectableBlock>
{/* Stats Section */}
<div className="py-16">
<div className="container mx-auto px-4">
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12">
<div className="grid grid-cols-1 gap-12 lg:grid-cols-2">
<div className="space-y-4">
<div className="bg-white rounded-xl shadow-lg p-8">
<h2 className="text-2xl font-bold text-gray-900 mb-6">
{translate('::Abp.Identity.User.UserInformation.ContactInformation')}
</h2>
<SelectableBlock
id="contact-info"
isActive={selectedBlockId === 'contact-info'}
isDesignMode={isDesignMode}
onSelect={handleSelectBlock}
>
<div className="rounded-xl bg-white p-8 shadow-lg">
<h2 className="mb-6 text-2xl font-bold text-gray-900">{content?.contactInfoTitle}</h2>
<div className="space-y-4">
<div className="flex items-start space-x-2">
<FaMapMarkerAlt className="w-5 h-5 text-blue-600 flex-shrink-0 mt-1" />
<FaMapMarkerAlt className="mt-1 h-5 w-5 flex-shrink-0 text-blue-600" />
<div>
<p className="text-gray-600">{translate('::' + contact?.address)}</p>
<p className="text-gray-600">{content?.address}</p>
</div>
</div>
<div className="flex items-start space-x-2">
<FaPhone className="w-5 h-5 text-blue-600 flex-shrink-0" />
<FaPhone className="h-5 w-5 flex-shrink-0 text-blue-600" />
<div>
<p className="text-gray-600">{contact?.phoneNumber}</p>
<p className="text-gray-600">{content?.phoneNumber}</p>
</div>
</div>
<div className="flex items-start space-x-2">
<FaEnvelope className="w-5 h-5 text-blue-600 flex-shrink-0" />
<FaEnvelope className="h-5 w-5 flex-shrink-0 text-blue-600" />
<div>
<p className="text-gray-600">
<a
href={`mailto:${contact?.email}`}
className="hover:underline text-blue-600"
>
{contact?.email}
<a href={`mailto:${content?.email}`} className="text-blue-600 hover:underline">
{content?.email}
</a>
</p>
</div>
</div>
<div className="flex items-start space-x-2">
<FaBuilding className="w-5 h-5 text-blue-600 flex-shrink-0" />
<FaBuilding className="h-5 w-5 flex-shrink-0 text-blue-600" />
<div>
<p className="text-gray-600">{contact?.location}</p>
<p className="text-gray-600">{content?.location}</p>
</div>
</div>
<div className="flex items-start space-x-2">
<FaIdCard className="w-5 h-5 text-blue-600 flex-shrink-0" />
<FaIdCard className="h-5 w-5 flex-shrink-0 text-blue-600" />
<div>
<p className="text-gray-600">{contact?.taxNumber}</p>
<p className="text-gray-600">{content?.taxNumber}</p>
</div>
</div>
</div>
</div>
</SelectableBlock>
<div className="bg-white rounded-xl shadow-lg p-8">
<h2 className="text-2xl font-bold text-gray-900 mb-6">
{translate('::Public.contact.bank.title')}
</h2>
<SelectableBlock
id="bank"
isActive={selectedBlockId === 'bank'}
isDesignMode={isDesignMode}
onSelect={handleSelectBlock}
>
<div className="rounded-xl bg-white p-8 shadow-lg">
<h2 className="mb-6 text-2xl font-bold text-gray-900">{content?.bankTitle}</h2>
<div className="mb-2">
<img
src="/img/enpara.svg"
alt="Enpara Logo"
className="w-24 object-contain mt-1 flex-shrink-0"
className="mt-1 w-24 flex-shrink-0 object-contain"
/>
<div>
<h3 className="font-semibold text-gray-900 mb-1">
{contact?.bankDto.accountHolder}
</h3>
<p className="text-gray-600 mb-1 ml-1">{contact?.bankDto.branch}</p>
<p className="text-gray-600 mb-1 ml-1">{contact?.bankDto.accountNumber}</p>
<p className="text-gray-600 mb-1 ml-1">{contact?.bankDto.iban}</p>
<h3 className="mb-1 font-semibold text-gray-900">{content?.bankAccountHolder}</h3>
<p className="mb-1 ml-1 text-gray-600">{content?.bankBranch}</p>
<p className="mb-1 ml-1 text-gray-600">{content?.bankAccountNumber}</p>
<p className="mb-1 ml-1 text-gray-600">{content?.bankIban}</p>
</div>
</div>
</div>
</SelectableBlock>
{/* Bank Information */}
<div className="bg-white rounded-xl shadow-lg p-8">
<h2 className="text-2xl font-bold text-gray-900 mb-6">
{translate('::App.Definitions.WorkHour')}
</h2>
<SelectableBlock
id="work-hours"
isActive={selectedBlockId === 'work-hours'}
isDesignMode={isDesignMode}
onSelect={handleSelectBlock}
>
<div className="rounded-xl bg-white p-8 shadow-lg">
<h2 className="mb-6 text-2xl font-bold text-gray-900">{content?.workHoursTitle}</h2>
<div className="space-y-2">
<div className="flex items-center space-x-2">
<FaCalendarAlt className="w-5 h-5 text-blue-500" />
<p className="text-gray-600">
{translate('::' + contact?.workHoursDto.weekday)}
</p>
<FaCalendarAlt className="h-5 w-5 text-blue-500" />
<p className="text-gray-600">{content?.workWeekday}</p>
</div>
<div className="flex items-center space-x-2">
<FaCalendarCheck className="w-5 h-5 text-blue-500" />
<p className="text-gray-600">
{translate('::' + contact?.workHoursDto.weekend)}
</p>
<FaCalendarCheck className="h-5 w-5 text-blue-500" />
<p className="text-gray-600">{content?.workWeekend}</p>
</div>
<div className="flex items-center space-x-2">
<FaRegComment className="w-5 h-5 text-green-500" />
<p className="text-gray-600">
{translate('::' + contact?.workHoursDto.whatsapp)}
</p>
<FaRegComment className="h-5 w-5 text-green-500" />
<p className="text-gray-600">{content?.workWhatsapp}</p>
</div>
</div>
</div>
</SelectableBlock>
</div>
{/* Map Section */}
<div className="bg-white rounded-xl shadow-lg p-8">
<h2 className="text-2xl font-bold text-gray-900 mb-2 text-center">
{translate('::' + contact?.mapDto.title)}
</h2>
<div className="aspect-w-16 aspect-h-9 bg-gray-200 rounded-xl overflow-hidden">
<SelectableBlock
id="map"
isActive={selectedBlockId === 'map'}
isDesignMode={isDesignMode}
onSelect={handleSelectBlock}
>
<div className="rounded-xl bg-white p-8 shadow-lg">
<h2 className="mb-2 text-center text-2xl font-bold text-gray-900">{content?.mapTitle}</h2>
<div className="aspect-w-16 aspect-h-9 overflow-hidden rounded-xl bg-gray-200">
<iframe
src={contact?.mapDto.src}
width={contact?.mapDto.width}
src={content?.mapSrc}
width={content?.mapWidth}
style={{ border: 0 }}
height={contact?.mapDto.height}
allowFullScreen={contact?.mapDto.allowFullScreen}
loading={contact?.mapDto.loading as 'lazy' | 'eager' | undefined}
referrerPolicy={
contact?.mapDto.referrerPolicy as React.HTMLAttributeReferrerPolicy | undefined
}
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>
)
}

File diff suppressed because it is too large Load diff

View file

@ -30,7 +30,10 @@ const SelectableBlock: React.FC<SelectableBlockProps> = ({
: 'ring-1 ring-sky-200/80 hover:ring-sky-400',
className,
)}
onClick={() => onSelect(id)}
onClick={(e) => {
e.stopPropagation()
onSelect(id)
}}
role="button"
tabIndex={0}
onKeyDown={(event) => {