Home sayfası için Seeder

This commit is contained in:
Sedat ÖZTÜRK 2026-06-01 13:26:04 +03:00
parent 5806ff5f9f
commit 57dbb0d308
5 changed files with 432 additions and 235 deletions

View file

@ -195,20 +195,13 @@ public class PublicAppService : PlatformAppService
public async Task<HomeDto> GetHomeAsync() public async Task<HomeDto> GetHomeAsync()
{ {
var entity = await _homeRepository.FirstOrDefaultAsync(); var entity = await _homeRepository.FirstOrDefaultAsync() ?? throw new EntityNotFoundException(typeof(Home));
if (entity == null)
{
entity = await _homeRepository.InsertAsync(CreateDefaultHomeEntity(), autoSave: true);
}
return ObjectMapper.Map<Home, HomeDto>(entity); return ObjectMapper.Map<Home, HomeDto>(entity);
} }
public async Task SaveHomePageAsync(SaveHomePageInput input) public async Task SaveHomePageAsync(SaveHomePageInput input)
{ {
var entity = await _homeRepository.FirstOrDefaultAsync(); var entity = await _homeRepository.FirstOrDefaultAsync() ?? throw new EntityNotFoundException(typeof(Home));
var isNewEntity = entity == null;
entity ??= CreateDefaultHomeEntity();
entity.HeroBackgroundImageKey = input.HeroBackgroundImageKey; entity.HeroBackgroundImageKey = input.HeroBackgroundImageKey;
entity.HeroPrimaryCtaKey = input.HeroPrimaryCtaKey; entity.HeroPrimaryCtaKey = input.HeroPrimaryCtaKey;
@ -252,14 +245,7 @@ public class PublicAppService : PlatformAppService
StyleClass = solution.StyleClass, StyleClass = solution.StyleClass,
}).ToList()); }).ToList());
if (isNewEntity) await _homeRepository.UpdateAsync(entity, autoSave: false);
{
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.HeroBackgroundImageKey, input.HeroBackgroundImageValue);
await UpsertLanguageTextAsync(input.CultureName, input.HeroPrimaryCtaKey, input.HeroPrimaryCtaValue); await UpsertLanguageTextAsync(input.CultureName, input.HeroPrimaryCtaKey, input.HeroPrimaryCtaValue);
@ -608,83 +594,6 @@ public class PublicAppService : PlatformAppService
await _languageTextAppService.ClearRedisCacheAsync(); 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.Videoroom.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) private async Task UpsertLanguageTextAsync(string cultureName, string key, string value)
{ {
if (key.IsNullOrWhiteSpace()) if (key.IsNullOrWhiteSpace())

View file

@ -429,6 +429,153 @@
] ]
} }
], ],
"Homes": [
{
"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",
"slides": [
{
"titleKey": "Public.hero.slide1.title",
"subtitleKey": "Public.hero.slide1.subtitle",
"services": [
{
"icon": "FaCalendarAlt",
"titleKey": "Public.hero.slide1.service1.title",
"descriptionKey": "Public.hero.slide1.service1.desc"
},
{
"icon": "FaUsers",
"titleKey": "Public.hero.slide1.service2.title",
"descriptionKey": "Public.hero.slide1.service2.desc"
},
{
"icon": "FaShieldAlt",
"titleKey": "Public.hero.slide1.service3.title",
"descriptionKey": "Public.hero.slide1.service3.desc"
}
]
},
{
"titleKey": "Public.hero.slide2.title",
"subtitleKey": "Public.hero.slide2.subtitle",
"services": [
{
"icon": "FaChartBar",
"titleKey": "Public.hero.slide2.service1.title",
"descriptionKey": "Public.hero.slide2.service1.desc"
},
{
"icon": "FaCreditCard",
"titleKey": "Public.hero.slide2.service2.title",
"descriptionKey": "Public.hero.slide2.service2.desc"
},
{
"icon": "FaDatabase",
"titleKey": "Public.hero.slide2.service3.title",
"descriptionKey": "Public.hero.slide2.service3.desc"
}
]
},
{
"titleKey": "Public.hero.slide3.title",
"subtitleKey": "Public.hero.slide3.subtitle",
"services": [
{
"icon": "FaDesktop",
"titleKey": "Public.hero.slide3.service1.title",
"descriptionKey": "Public.hero.slide3.service1.desc"
},
{
"icon": "FaServer",
"titleKey": "Public.hero.slide3.service2.title",
"descriptionKey": "Public.hero.slide3.service2.desc"
},
{
"icon": "FaMobileAlt",
"titleKey": "Public.hero.slide3.service3.title",
"descriptionKey": "Public.hero.slide3.service3.desc"
}
]
}
],
"features": [
{
"icon": "FaUsers",
"titleKey": "Public.features.reliable",
"descriptionKey": "Public.features.reliable.desc"
},
{
"icon": "FaCalendarAlt",
"titleKey": "App.Videoroom.Planning",
"descriptionKey": "Public.features.rapid.desc"
},
{
"icon": "FaBookOpen",
"titleKey": "Public.features.expert",
"descriptionKey": "Public.features.expert.desc"
},
{
"icon": "FaCreditCard",
"titleKey": "Public.features.muhasebe",
"descriptionKey": "Public.features.muhasebe.desc"
},
{
"icon": "FaRegComment",
"titleKey": "Public.features.iletisim",
"descriptionKey": "Public.features.iletisim.desc"
},
{
"icon": "FaPhone",
"titleKey": "Public.features.mobil",
"descriptionKey": "Public.features.mobil.desc"
},
{
"icon": "FaChartBar",
"titleKey": "Public.features.scalable",
"descriptionKey": "Public.features.scalable.desc"
},
{
"icon": "FaShieldAlt",
"titleKey": "Public.features.guvenlik",
"descriptionKey": "Public.features.guvenlik.desc"
}
],
"solutions": [
{
"icon": "FaDesktop",
"colorClass": "bg-blue-600",
"titleKey": "Public.services.web.title",
"descriptionKey": "Public.solutions.web.desc"
},
{
"icon": "FaMobileAlt",
"colorClass": "bg-purple-600",
"titleKey": "Public.services.mobile.title",
"descriptionKey": "Public.solutions.mobile.desc"
},
{
"icon": "FaServer",
"colorClass": "bg-green-600",
"titleKey": "Public.solutions.custom.title",
"descriptionKey": "Public.solutions.custom.desc"
},
{
"icon": "FaDatabase",
"colorClass": "bg-red-600",
"titleKey": "Public.solutions.database.title",
"descriptionKey": "Public.solutions.database.desc"
}
]
}
],
"Services": [ "Services": [
{ {
"icon": "FaCode", "icon": "FaCode",
@ -2077,4 +2224,4 @@
"ResetPeriod": "Daily" "ResetPeriod": "Daily"
} }
] ]
} }

View file

@ -40,6 +40,7 @@ public class TenantSeederDto
public List<JobPositionSeedDto> JobPositions { get; set; } public List<JobPositionSeedDto> JobPositions { get; set; }
//Public //Public
public List<HomeSeedDto> Homes { get; set; }
public List<AboutSeedDto> Abouts { get; set; } public List<AboutSeedDto> Abouts { get; set; }
public List<ServiceSeedDto> Services { get; set; } public List<ServiceSeedDto> Services { get; set; }
public List<PaymentMethodSeedDto> PaymentMethods { get; set; } public List<PaymentMethodSeedDto> PaymentMethods { get; set; }
@ -392,6 +393,56 @@ public class AboutSeedDto
public List<SectionDto> Sections { get; set; } public List<SectionDto> Sections { get; set; }
} }
public class HomeSeedDto
{
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 List<HomeSlideSeedDto> Slides { get; set; }
public List<HomeFeatureSeedDto> Features { get; set; }
public List<HomeSolutionSeedDto> Solutions { get; set; }
}
public class HomeSlideSeedDto
{
public string TitleKey { get; set; }
public string SubtitleKey { get; set; }
public string StyleClass { get; set; }
public List<HomeSlideServiceSeedDto> Services { get; set; }
}
public class HomeSlideServiceSeedDto
{
public string Icon { get; set; }
public string TitleKey { get; set; }
public string DescriptionKey { get; set; }
public string StyleClass { get; set; }
}
public class HomeFeatureSeedDto
{
public string Icon { get; set; }
public string TitleKey { get; set; }
public string DescriptionKey { get; set; }
public string StyleClass { get; set; }
}
public class HomeSolutionSeedDto
{
public string Icon { get; set; }
public string ColorClass { get; set; }
public string TitleKey { get; set; }
public string DescriptionKey { get; set; }
public string StyleClass { get; set; }
}
public class WorkHourSeedDto public class WorkHourSeedDto
{ {
public string Name { get; set; } public string Name { get; set; }
@ -440,6 +491,7 @@ public class TenantDataSeeder : IDataSeedContributor, ITransientDependency
private readonly IRepository<CustomComponent, Guid> _customComponentRepository; private readonly IRepository<CustomComponent, Guid> _customComponentRepository;
private readonly IRepository<ReportCategory, Guid> _reportCategoriesRepository; private readonly IRepository<ReportCategory, Guid> _reportCategoriesRepository;
private readonly IRepository<ReportTemplate, Guid> _reportTemplatesRepository; private readonly IRepository<ReportTemplate, Guid> _reportTemplatesRepository;
private readonly IRepository<Home, Guid> _homeRepository;
private readonly IRepository<About, Guid> _aboutRepository; private readonly IRepository<About, Guid> _aboutRepository;
private readonly IRepository<PaymentMethod, Guid> _paymentMethodRepository; private readonly IRepository<PaymentMethod, Guid> _paymentMethodRepository;
private readonly IRepository<InstallmentOption, Guid> _installmentOptionRepository; private readonly IRepository<InstallmentOption, Guid> _installmentOptionRepository;
@ -495,6 +547,7 @@ public class TenantDataSeeder : IDataSeedContributor, ITransientDependency
IRepository<CustomComponent, Guid> customComponentRepository, IRepository<CustomComponent, Guid> customComponentRepository,
IRepository<ReportCategory, Guid> reportCategoriesRepository, IRepository<ReportCategory, Guid> reportCategoriesRepository,
IRepository<ReportTemplate, Guid> reportTemplatesRepository, IRepository<ReportTemplate, Guid> reportTemplatesRepository,
IRepository<Home, Guid> homeRepository,
IRepository<About, Guid> aboutRepository, IRepository<About, Guid> aboutRepository,
IRepository<Service, Guid> servicesRepository, IRepository<Service, Guid> servicesRepository,
IRepository<Product, Guid> productRepository, IRepository<Product, Guid> productRepository,
@ -548,6 +601,7 @@ public class TenantDataSeeder : IDataSeedContributor, ITransientDependency
_customComponentRepository = customComponentRepository; _customComponentRepository = customComponentRepository;
_reportCategoriesRepository = reportCategoriesRepository; _reportCategoriesRepository = reportCategoriesRepository;
_reportTemplatesRepository = reportTemplatesRepository; _reportTemplatesRepository = reportTemplatesRepository;
_homeRepository = homeRepository;
_servicesRepository = servicesRepository; _servicesRepository = servicesRepository;
_aboutRepository = aboutRepository; _aboutRepository = aboutRepository;
_contactRepository = contactRepository; _contactRepository = contactRepository;
@ -848,6 +902,30 @@ public class TenantDataSeeder : IDataSeedContributor, ITransientDependency
} }
} }
foreach (var item in items.Homes)
{
var exists = await _homeRepository.FirstOrDefaultAsync();
if (exists == null)
{
await _homeRepository.InsertAsync(new Home
{
HeroBackgroundImageKey = item.HeroBackgroundImageKey,
HeroPrimaryCtaKey = item.HeroPrimaryCtaKey,
HeroSecondaryCtaKey = item.HeroSecondaryCtaKey,
FeaturesTitleKey = item.FeaturesTitleKey,
FeaturesSubtitleKey = item.FeaturesSubtitleKey,
SolutionsTitleKey = item.SolutionsTitleKey,
SolutionsSubtitleKey = item.SolutionsSubtitleKey,
CtaTitleKey = item.CtaTitleKey,
CtaSubtitleKey = item.CtaSubtitleKey,
CtaButtonLabelKey = item.CtaButtonLabelKey,
SlidesJson = JsonSerializer.Serialize(item.Slides),
FeaturesJson = JsonSerializer.Serialize(item.Features),
SolutionsJson = JsonSerializer.Serialize(item.Solutions)
});
}
}
foreach (var item in items.Contacts) foreach (var item in items.Contacts)
{ {
var exists = await _contactRepository.FirstOrDefaultAsync(); var exists = await _contactRepository.FirstOrDefaultAsync();

View file

@ -1,6 +1,28 @@
{ {
"commit": "0b5eb3d", "commit": "0d4703c",
"releases": [ "releases": [
{
"version": "1.1.03",
"buildDate": "2026-05-30",
"commit": "96f7091d46c248ba3c42849fe5d870db0ab96982",
"changeLog": [
"- User Detail komponentinin içerisinde Avatar ekleme",
"- EditForm un içerisinde EditorOptions dinamik oluşturulması",
"- Editform un içerisinde EditorScript dinamik oluşturulması"
]
},
{
"version": "1.1.02",
"buildDate": "2026-05-27",
"commit": "84b9f6510787bd82f3797728fd675f755b4caa2d",
"changeLog": [
"- .NET 10 yükseltildi.",
"- Abp Framework 10 yükseltildi.",
"- Sql Query Manager problemleri giderildi.",
"- AuditLog problemleri giderildi.",
"- Tenan yapısını uygunluğu için düzenlemeler yapıldı."
]
},
{ {
"version": "1.1.01", "version": "1.1.01",
"buildDate": "2026-05-24", "buildDate": "2026-05-24",
@ -115,4 +137,4 @@
] ]
} }
] ]
} }

View file

@ -52,6 +52,12 @@ type EditorScriptBuilderDialogProps = {
const baseInputClass = const baseInputClass =
'w-full h-9 px-2 rounded border border-gray-200 dark:border-gray-600 bg-white dark:bg-gray-800 text-sm text-gray-700 dark:text-gray-100 focus:outline-none focus:border-indigo-400' 'w-full h-9 px-2 rounded border border-gray-200 dark:border-gray-600 bg-white dark:bg-gray-800 text-sm text-gray-700 dark:text-gray-100 focus:outline-none focus:border-indigo-400'
const fieldLabelClass =
'flex flex-col gap-1 text-xs font-medium text-gray-500 dark:text-gray-400'
const actionIconCellClass =
'col-span-12 flex h-9 items-center justify-end md:col-span-1 md:justify-center'
const makeId = () => `${Date.now()}_${Math.random().toString(36).slice(2)}` const makeId = () => `${Date.now()}_${Math.random().toString(36).slice(2)}`
const createConditionalAction = (): ConditionalAction => ({ const createConditionalAction = (): ConditionalAction => ({
@ -612,7 +618,7 @@ function EditorScriptBuilderDialog({
value: string, value: string,
onChange: (value: string) => void, onChange: (value: string) => void,
) => ( ) => (
<label className="flex flex-col gap-1 text-xs font-medium text-gray-500 dark:text-gray-400"> <label className={fieldLabelClass}>
{label} {label}
{renderFieldSelect(value, onChange)} {renderFieldSelect(value, onChange)}
</label> </label>
@ -721,8 +727,8 @@ function EditorScriptBuilderDialog({
<div className="mb-3 rounded bg-gray-50 px-2 py-1.5 text-xs text-gray-600 dark:bg-gray-900 dark:text-gray-300"> <div className="mb-3 rounded bg-gray-50 px-2 py-1.5 text-xs text-gray-600 dark:bg-gray-900 dark:text-gray-300">
{describeCopyMapping(mapping)} {describeCopyMapping(mapping)}
</div> </div>
<div className="grid grid-cols-12 gap-2"> <div className="grid grid-cols-12 items-end gap-2">
<label className="col-span-12 flex flex-col gap-1 text-xs font-medium text-gray-500 dark:text-gray-400 md:col-span-5"> <label className={`${fieldLabelClass} col-span-12 md:col-span-5`}>
Seçili kayıttaki kolon/path Seçili kayıttaki kolon/path
<input <input
className={baseInputClass} className={baseInputClass}
@ -752,17 +758,20 @@ function EditorScriptBuilderDialog({
), ),
)} )}
</div> </div>
<Button <div className={`${actionIconCellClass} md:col-span-2`}>
type="button" <Button
shape="circle" type="button"
variant="plain" shape="circle"
icon={<FaTrash />} variant="plain"
onClick={() => icon={<FaTrash />}
setCopyMappings((current) => title="Bu kopyalama satırını sil"
current.filter((item) => item.id !== mapping.id), onClick={() =>
) setCopyMappings((current) =>
} current.filter((item) => item.id !== mapping.id),
/> )
}
/>
</div>
</div> </div>
</div> </div>
))} ))}
@ -774,7 +783,7 @@ function EditorScriptBuilderDialog({
<div> <div>
<div <div
className="text-sm font-semibold" className="text-sm font-semibold"
title="Önce koşulu kur: hangi field, hangi operatör, hangi değer. Sonra aksiyonu seç: field yaz, API çağırıp cevabı field'a yaz, URL aç, alert/confirm göster veya formül hesapla. Örnek: Değer IPTAL ise SatisOlmamaSebebiID visible true yap. Değer 1 ise /api/x/{value} çağır, gelen data.name bilgisini DisplayName alanına yaz." title="Önce koşulu kur: hangi field, hangi operatör, hangi değer. Sonra aksiyonu seç: field yaz, API çağırıp cevabı field'a yaz, URL aç, alert/confirm göster veya formül hesapla. Örnek: Değer Aktif ise SatisOlmamaSebebiID visible true yap. Değer 1 ise /api/x/{value} çağır, gelen data.name bilgisini DisplayName alanına yaz."
> >
2. Koşullu Aksiyon Builder 2. Koşullu Aksiyon Builder
</div> </div>
@ -783,7 +792,7 @@ function EditorScriptBuilderDialog({
type="button" type="button"
size="sm" size="sm"
icon={<FaPlus />} icon={<FaPlus />}
title="Koşul + aksiyon kuralı ekler. Örnek: değer IPTAL ise alanı pasif yap, API çağır, URL aç." title="Koşul + aksiyon kuralı ekler. Örnek: değer Aktif ise alanı pasif yap, API çağır, URL aç."
onClick={() => onClick={() =>
setConditionalActions((current) => [...current, createConditionalAction()]) setConditionalActions((current) => [...current, createConditionalAction()])
} }
@ -800,32 +809,35 @@ function EditorScriptBuilderDialog({
<div className="rounded bg-gray-50 px-2 py-1.5 text-xs text-gray-600 dark:bg-gray-900 dark:text-gray-300"> <div className="rounded bg-gray-50 px-2 py-1.5 text-xs text-gray-600 dark:bg-gray-900 dark:text-gray-300">
{describeConditionalAction(action)} {describeConditionalAction(action)}
</div> </div>
<div className="grid grid-cols-12 gap-2"> <div className="grid grid-cols-12 items-end gap-2">
<div className="col-span-12 md:col-span-3"> <div className="col-span-12 md:col-span-4">
{renderLabeledFieldSelect('Eğer: kaynak field', action.source, (value) => {renderLabeledFieldSelect('Eğer: kaynak field', action.source, (value) =>
updateConditionalAction(action.id, { source: value }), updateConditionalAction(action.id, { source: value }),
)} )}
</div> </div>
<select <label className={`${fieldLabelClass} col-span-12 md:col-span-3`}>
className={`${baseInputClass} col-span-12 self-end md:col-span-3`} Operatör
value={action.operator} <select
title="Koşul operatörü. Her zaman seçersen kaynak field ve karşılaştırma değeri gerekmez." className={baseInputClass}
onChange={(event) => value={action.operator}
updateConditionalAction(action.id, { title="Koşul operatörü. Her zaman seçersen kaynak field ve karşılaştırma değeri gerekmez."
operator: event.target.value as ConditionalAction['operator'], onChange={(event) =>
}) updateConditionalAction(action.id, {
} operator: event.target.value as ConditionalAction['operator'],
> })
<option value="always">always</option> }
<option value="empty">empty</option> >
<option value="notEmpty">notEmpty</option> <option value="always">always</option>
<option value="equals">equals</option> <option value="empty">empty</option>
<option value="notEquals">notEquals</option> <option value="notEmpty">notEmpty</option>
<option value="contains">contains</option> <option value="equals">equals</option>
<option value="greaterThan">greaterThan</option> <option value="notEquals">notEquals</option>
<option value="lessThan">lessThan</option> <option value="contains">contains</option>
</select> <option value="greaterThan">greaterThan</option>
<label className="col-span-12 flex flex-col gap-1 text-xs font-medium text-gray-500 dark:text-gray-400 md:col-span-3"> <option value="lessThan">lessThan</option>
</select>
</label>
<label className={`${fieldLabelClass} col-span-12 md:col-span-4`}>
Koşul değeri Koşul değeri
<input <input
className={baseInputClass} className={baseInputClass}
@ -838,25 +850,28 @@ function EditorScriptBuilderDialog({
onChange={(event) => onChange={(event) =>
updateConditionalAction(action.id, { value: event.target.value }) updateConditionalAction(action.id, { value: event.target.value })
} }
placeholder="Örn: IPTAL, 1000" placeholder="Örn: Aktif, 1000"
title="Koşulda kullanılacak sabit değer. Örnek: IPTAL, 0, True" title="Koşulda kullanılacak sabit değer. Örnek: Aktif, 0, True"
/> />
</label> </label>
<Button <div className={actionIconCellClass}>
type="button" <Button
shape="circle" type="button"
variant="plain" shape="circle"
icon={<FaTrash />} variant="plain"
onClick={() => icon={<FaTrash />}
setConditionalActions((current) => title="Bu koşullu aksiyonu sil"
current.filter((item) => item.id !== action.id), onClick={() =>
) setConditionalActions((current) =>
} current.filter((item) => item.id !== action.id),
/> )
}
/>
</div>
</div> </div>
<div className="grid grid-cols-12 gap-2"> <div className="grid grid-cols-12 items-end gap-2">
<label className="col-span-12 flex flex-col gap-1 text-xs font-medium text-gray-500 dark:text-gray-400 md:col-span-4"> <label className={`${fieldLabelClass} col-span-12 md:col-span-4`}>
O zaman: aksiyon O zaman: aksiyon
<select <select
className={baseInputClass} className={baseInputClass}
@ -890,104 +905,130 @@ function EditorScriptBuilderDialog({
)} )}
{action.actionType === 'setField' && ( {action.actionType === 'setField' && (
<input <label className={`${fieldLabelClass} col-span-12 md:col-span-4`}>
className={`${baseInputClass} col-span-4`} Değer
value={action.textValue} <input
onChange={(event) => className={baseInputClass}
updateConditionalAction(action.id, { textValue: event.target.value }) value={action.textValue}
} onChange={(event) =>
placeholder="text, {Field} or {selected.Name}" updateConditionalAction(action.id, { textValue: event.target.value })
title="Sabit metin veya token yaz. Örnek: {Name}, {value}, {selected.DisplayName}" }
/> placeholder="text, {Field} or {selected.Name}"
title="Sabit metin veya token yaz. Örnek: {Name}, {value}, {selected.DisplayName}"
/>
</label>
)} )}
{action.actionType === 'apiToField' && ( {action.actionType === 'apiToField' && (
<> <>
<select <label className={`${fieldLabelClass} col-span-12 md:col-span-2`}>
className={`${baseInputClass} col-span-2`} Method
value={action.apiMethod} <select
title="API çağrısı GET veya POST olabilir. POST formData'yı body olarak gönderir." className={baseInputClass}
onChange={(event) => value={action.apiMethod}
updateConditionalAction(action.id, { title="API çağrısı GET veya POST olabilir. POST formData'yı body olarak gönderir."
apiMethod: event.target.value as ConditionalAction['apiMethod'], onChange={(event) =>
}) updateConditionalAction(action.id, {
} apiMethod: event.target.value as ConditionalAction['apiMethod'],
> })
<option value="GET">GET</option> }
<option value="POST">POST</option> >
</select> <option value="GET">GET</option>
<input <option value="POST">POST</option>
className={`${baseInputClass} col-span-3`} </select>
value={action.apiUrl} </label>
onChange={(event) => <label className={`${fieldLabelClass} col-span-12 md:col-span-3`}>
updateConditionalAction(action.id, { apiUrl: event.target.value }) API URL
} <input
placeholder="/api/path/{Id}" className={baseInputClass}
title="Token kullanabilirsin: /api/orders/{OrderId}, /api/x/{selected.Id}, /api/y/{value}" value={action.apiUrl}
/> onChange={(event) =>
<input updateConditionalAction(action.id, { apiUrl: event.target.value })
className={`${baseInputClass} col-span-3`} }
value={action.responsePath} placeholder="/api/path/{Id}"
onChange={(event) => title="Token kullanabilirsin: /api/orders/{OrderId}, /api/x/{selected.Id}, /api/y/{value}"
updateConditionalAction(action.id, { />
responsePath: event.target.value, </label>
}) <label className={`${fieldLabelClass} col-span-12 md:col-span-3`}>
} Response path
placeholder="data.value" <input
title="API JSON cevabından okunacak path. Boş bırakırsan tüm JSON hedef field'a yazılır." className={baseInputClass}
/> value={action.responsePath}
onChange={(event) =>
updateConditionalAction(action.id, {
responsePath: event.target.value,
})
}
placeholder="data.value"
title="API JSON cevabından okunacak path. Boş bırakırsan tüm JSON hedef field'a yazılır."
/>
</label>
</> </>
)} )}
{action.actionType === 'openUrl' && ( {action.actionType === 'openUrl' && (
<> <>
<input <label className={`${fieldLabelClass} col-span-12 md:col-span-6`}>
className={`${baseInputClass} col-span-6`} URL
value={action.textValue} <input
onChange={(event) => className={baseInputClass}
updateConditionalAction(action.id, { textValue: event.target.value }) value={action.textValue}
} onChange={(event) =>
placeholder="/report?id={Id}&type={selected.Type}" updateConditionalAction(action.id, {
title="Açılacak URL. Token destekler: {Id}, {value}, {selected.Type}" textValue: event.target.value,
/> })
<select }
className={`${baseInputClass} col-span-2`} placeholder="/report?id={Id}&type={selected.Type}"
value={action.urlTarget} title="Açılacak URL. Token destekler: {Id}, {value}, {selected.Type}"
title="URL yeni sekmede mi mevcut sekmede mi açılsın?" />
onChange={(event) => </label>
updateConditionalAction(action.id, { <label className={`${fieldLabelClass} col-span-12 md:col-span-2`}>
urlTarget: event.target.value as ConditionalAction['urlTarget'], Hedef
}) <select
} className={baseInputClass}
> value={action.urlTarget}
<option value="_blank">_blank</option> title="URL yeni sekmede mi mevcut sekmede mi açılsın?"
<option value="_self">_self</option> onChange={(event) =>
</select> updateConditionalAction(action.id, {
urlTarget: event.target.value as ConditionalAction['urlTarget'],
})
}
>
<option value="_blank">_blank</option>
<option value="_self">_self</option>
</select>
</label>
</> </>
)} )}
{(action.actionType === 'alert' || action.actionType === 'confirm') && ( {(action.actionType === 'alert' || action.actionType === 'confirm') && (
<input <label className={`${fieldLabelClass} col-span-12 md:col-span-8`}>
className={`${baseInputClass} col-span-8`} Mesaj
value={action.message} <input
onChange={(event) => className={baseInputClass}
updateConditionalAction(action.id, { message: event.target.value }) value={action.message}
} onChange={(event) =>
placeholder="{Field} tokenları ile mesaj" updateConditionalAction(action.id, { message: event.target.value })
title="Alert/confirm mesajı. Token destekler: {Name}, {value}, {selected.Name}" }
/> placeholder="{Field} tokenları ile mesaj"
title="Alert/confirm mesajı. Token destekler: {Name}, {value}, {selected.Name}"
/>
</label>
)} )}
{action.actionType === 'calculate' && ( {action.actionType === 'calculate' && (
<input <label className={`${fieldLabelClass} col-span-12 md:col-span-4`}>
className={`${baseInputClass} col-span-4`} Formül
value={action.formula} <input
onChange={(event) => className={baseInputClass}
updateConditionalAction(action.id, { formula: event.target.value }) value={action.formula}
} onChange={(event) =>
placeholder="Number(data.Quantity || 0) * Number(data.UnitPrice || 0)" updateConditionalAction(action.id, { formula: event.target.value })
title="JavaScript expression yaz. data=formData, selected=selectedItem, value=e.value olarak kullanılır." }
/> placeholder="Number(data.Quantity || 0) * Number(data.UnitPrice || 0)"
title="JavaScript expression yaz. data=formData, selected=selectedItem, value=e.value olarak kullanılır."
/>
</label>
)} )}
</div> </div>
</div> </div>
@ -1020,7 +1061,7 @@ function EditorScriptBuilderDialog({
className="mb-3 text-sm font-semibold" className="mb-3 text-sm font-semibold"
title="Quantity ve UnitPrice ile TotalAmount hesaplar. Seçili kayıttan hesapla lookup kaydından değerleri alır; satır toplamını yenile mevcut form değerlerinden hesaplar." title="Quantity ve UnitPrice ile TotalAmount hesaplar. Seçili kayıttan hesapla lookup kaydından değerleri alır; satır toplamını yenile mevcut form değerlerinden hesaplar."
> >
5. Tutar Hesaplamaları 4. Tutar Hesaplamaları
</div> </div>
<div className="grid grid-cols-1 gap-2 mb-3 md:grid-cols-2"> <div className="grid grid-cols-1 gap-2 mb-3 md:grid-cols-2">
<label className="flex items-start gap-2 text-sm"> <label className="flex items-start gap-2 text-sm">
@ -1059,7 +1100,7 @@ function EditorScriptBuilderDialog({
className="mb-3 text-sm font-semibold" className="mb-3 text-sm font-semibold"
title="Tek satırlık global servis çağrıları için kullan. Daha detaylı kodu sağdaki TypeScript script editor alanında düzenleyebilirsin." title="Tek satırlık global servis çağrıları için kullan. Daha detaylı kodu sağdaki TypeScript script editor alanında düzenleyebilirsin."
> >
6. Servis Çağrısı 5. Servis Çağrısı
</div> </div>
<input <input
className={baseInputClass} className={baseInputClass}
@ -1084,7 +1125,7 @@ function EditorScriptBuilderDialog({
TypeScript TypeScript
</span> </span>
</div> </div>
<div className="flex-1 min-h-[430px] overflow-hidden rounded border border-gray-200 dark:border-gray-700"> <div className="flex-1 min-h-[350px] overflow-hidden rounded border border-gray-200 dark:border-gray-700">
<Editor <Editor
height="100%" height="100%"
language="typescript" language="typescript"