Dil Desteği ve Seederlar
This commit is contained in:
parent
dd7458093c
commit
284d0d777c
16 changed files with 1252 additions and 334 deletions
|
|
@ -12186,8 +12186,8 @@ public class ListFormsSeeder : IDataSeedContributor, ITransientDependency
|
||||||
ItemType = "group",
|
ItemType = "group",
|
||||||
Items =
|
Items =
|
||||||
[
|
[
|
||||||
new EditingFormItemDto { Order = 1, DataField = "Name", ColSpan = 2, IsRequired = true, EditorType2 = EditorTypes.dxTextBox },
|
new EditingFormItemDto { Order = 1, DataField = "Name", ColSpan = 2, IsRequired = true, EditorType2 = EditorTypes.dxSelectBox },
|
||||||
new EditingFormItemDto { Order = 2, DataField = "Description", ColSpan = 2, EditorType2 = EditorTypes.dxTextBox },
|
new EditingFormItemDto { Order = 2, DataField = "Description", ColSpan = 2, EditorType2 = EditorTypes.dxSelectBox },
|
||||||
new EditingFormItemDto { Order = 3, DataField = "Category", ColSpan = 2, EditorType2 = EditorTypes.dxSelectBox },
|
new EditingFormItemDto { Order = 3, DataField = "Category", ColSpan = 2, EditorType2 = EditorTypes.dxSelectBox },
|
||||||
new EditingFormItemDto { Order = 4, DataField = "MonthlyPrice", ColSpan = 2, EditorType2 = EditorTypes.dxNumberBox },
|
new EditingFormItemDto { Order = 4, DataField = "MonthlyPrice", ColSpan = 2, EditorType2 = EditorTypes.dxNumberBox },
|
||||||
new EditingFormItemDto { Order = 5, DataField = "YearlyPrice", ColSpan = 2, EditorType2 = EditorTypes.dxNumberBox },
|
new EditingFormItemDto { Order = 5, DataField = "YearlyPrice", ColSpan = 2, EditorType2 = EditorTypes.dxNumberBox },
|
||||||
|
|
@ -12262,7 +12262,14 @@ public class ListFormsSeeder : IDataSeedContributor, ITransientDependency
|
||||||
E = true,
|
E = true,
|
||||||
I = true,
|
I = true,
|
||||||
Deny = false
|
Deny = false
|
||||||
})
|
}),
|
||||||
|
LookupJson = JsonSerializer.Serialize(new LookupDto
|
||||||
|
{
|
||||||
|
DataSourceType = UiLookupDataSourceTypeEnum.Query,
|
||||||
|
DisplayExpr = "Name",
|
||||||
|
ValueExpr = "Key",
|
||||||
|
LookupQuery = lookupQueryLanguageKeyValues
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
new()
|
new()
|
||||||
{
|
{
|
||||||
|
|
@ -12284,7 +12291,14 @@ public class ListFormsSeeder : IDataSeedContributor, ITransientDependency
|
||||||
E = true,
|
E = true,
|
||||||
I = true,
|
I = true,
|
||||||
Deny = false
|
Deny = false
|
||||||
})
|
}),
|
||||||
|
LookupJson = JsonSerializer.Serialize(new LookupDto
|
||||||
|
{
|
||||||
|
DataSourceType = UiLookupDataSourceTypeEnum.Query,
|
||||||
|
DisplayExpr = "Name",
|
||||||
|
ValueExpr = "Key",
|
||||||
|
LookupQuery = lookupQueryLanguageKeyValues
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
new()
|
new()
|
||||||
{
|
{
|
||||||
|
|
@ -12304,9 +12318,9 @@ public class ListFormsSeeder : IDataSeedContributor, ITransientDependency
|
||||||
DisplayExpr = "name",
|
DisplayExpr = "name",
|
||||||
ValueExpr = "key",
|
ValueExpr = "key",
|
||||||
LookupQuery = JsonSerializer.Serialize(new LookupDataDto[] {
|
LookupQuery = JsonSerializer.Serialize(new LookupDataDto[] {
|
||||||
new () { Key="Üyelik",Name="Üyelik" },
|
new () { Key="Public.products.categories.Üyelik",Name="Üyelik" },
|
||||||
new () { Key="Lisans",Name="Lisans" },
|
new () { Key="Public.products.categories.Lisans",Name="Lisans" },
|
||||||
new () { Key="Ek Hizmetler",Name="Ek Hizmetler" },
|
new () { Key="Public.products.categories.Ek Hizmetler",Name="Ek Hizmetler" },
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
ValidationRuleJson = JsonSerializer.Serialize(new[]
|
ValidationRuleJson = JsonSerializer.Serialize(new[]
|
||||||
|
|
|
||||||
|
|
@ -7189,6 +7189,600 @@
|
||||||
"tr": "Demo Talep Edin",
|
"tr": "Demo Talep Edin",
|
||||||
"en": "Request a Demo"
|
"en": "Request a Demo"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.billingcycle",
|
||||||
|
"tr": "Faturalama Döngüsü",
|
||||||
|
"en": "Billing Cycle"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.period",
|
||||||
|
"tr": "Periyot",
|
||||||
|
"en": "Period"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.billingcycle.yearly",
|
||||||
|
"tr": "Yıllık",
|
||||||
|
"en": "Yearly"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.billingcycle.monthly",
|
||||||
|
"tr": "Aylık",
|
||||||
|
"en": "Monthly"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.billingcycle.year",
|
||||||
|
"tr": "Yıl",
|
||||||
|
"en": "Year"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.billingcycle.month",
|
||||||
|
"tr": "Ay",
|
||||||
|
"en": "Month"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.categories",
|
||||||
|
"tr": "Kategoriler",
|
||||||
|
"en": "Categories"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.categories.all",
|
||||||
|
"tr": "Tüm Ürünler",
|
||||||
|
"en": "All Products"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.categories.Üyelik",
|
||||||
|
"tr": "Üyelik",
|
||||||
|
"en": "Membership"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.categories.Lisans",
|
||||||
|
"tr": "Lisans",
|
||||||
|
"en": "License"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.categories.Ek Hizmetler",
|
||||||
|
"tr": "Ek Hizmetler",
|
||||||
|
"en": "Additional Services"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.order.success.title",
|
||||||
|
"tr": "Siparişiniz Başarıyla Alındı!",
|
||||||
|
"en": "Your order has been received successfully!"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.order.success.number",
|
||||||
|
"tr": "Sipariş numaranız:",
|
||||||
|
"en": "Your order number:"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.order.success.nextSteps",
|
||||||
|
"tr": "Sonraki Adımlar",
|
||||||
|
"en": "Next Steps"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.order.success.step1",
|
||||||
|
"tr": "Siparişiniz 24 saat içinde işleme alınacaktır",
|
||||||
|
"en": "Your order will be processed within 24 hours"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.order.success.step2",
|
||||||
|
"tr": "Lisans bilgileri e-posta adresinize gönderilecektir",
|
||||||
|
"en": "License details will be sent to your email address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.order.success.step3",
|
||||||
|
"tr": "Kurulum desteği için ekibimizle iletişime geçebilirsiniz",
|
||||||
|
"en": "You can contact our team for installation support"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.order.success.backHome",
|
||||||
|
"tr": "Ana Sayfa'ya Dön",
|
||||||
|
"en": "Back to Home"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.payment.loading",
|
||||||
|
"tr": "Yükleniyor...",
|
||||||
|
"en": "Loading..."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.payment.customerInfo",
|
||||||
|
"tr": "Müşteri Bilgileri",
|
||||||
|
"en": "Customer Information"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.payment.customer.code",
|
||||||
|
"tr": "Kurum Kodu:",
|
||||||
|
"en": "Institution Code:"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.payment.customer.founder",
|
||||||
|
"tr": "Kurucu:",
|
||||||
|
"en": "Founder:"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.payment.customer.company",
|
||||||
|
"tr": "Şirket:",
|
||||||
|
"en": "Company:"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.payment.customer.email",
|
||||||
|
"tr": "E-posta:",
|
||||||
|
"en": "Email:"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.payment.customer.phone",
|
||||||
|
"tr": "Telefon:",
|
||||||
|
"en": "Phone:"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.payment.customer.address",
|
||||||
|
"tr": "Adres:",
|
||||||
|
"en": "Address:"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.payment.customer.country",
|
||||||
|
"tr": "Ülke:",
|
||||||
|
"en": "Country:"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.payment.customer.city",
|
||||||
|
"tr": "Şehir:",
|
||||||
|
"en": "City:"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.payment.customer.district",
|
||||||
|
"tr": "İlçe:",
|
||||||
|
"en": "District:"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.payment.customer.postalCode",
|
||||||
|
"tr": "Posta Kodu:",
|
||||||
|
"en": "Postal Code:"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.payment.customer.taxOffice",
|
||||||
|
"tr": "Vergi Dairesi:",
|
||||||
|
"en": "Tax Office:"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.payment.customer.taxNumber",
|
||||||
|
"tr": "Vergi No:",
|
||||||
|
"en": "Tax Number:"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.payment.customer.reference",
|
||||||
|
"tr": "Referans:",
|
||||||
|
"en": "Reference:"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.payment.method.title",
|
||||||
|
"tr": "Ödeme Yöntemi",
|
||||||
|
"en": "Payment Method"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.payment.method.installmentsAvailable",
|
||||||
|
"tr": "Taksit seçenekleri mevcut",
|
||||||
|
"en": "Installment options available"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.payment.method.noCommission",
|
||||||
|
"tr": "Komisyon yok",
|
||||||
|
"en": "No commission"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.payment.installments.title",
|
||||||
|
"tr": "Taksit Seçenekleri",
|
||||||
|
"en": "Installment Options"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.payment.installments.commission",
|
||||||
|
"tr": "Komisyon:",
|
||||||
|
"en": "Commission:"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.payment.installments.monthly",
|
||||||
|
"tr": "x aylık",
|
||||||
|
"en": "x monthly"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.payment.installments.single",
|
||||||
|
"tr": "Tek ödeme",
|
||||||
|
"en": "Single Payment"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.payment.card.title",
|
||||||
|
"tr": "Kart Bilgileri",
|
||||||
|
"en": "Card Information"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.payment.card.name",
|
||||||
|
"tr": "Kart Üzerindeki İsim",
|
||||||
|
"en": "Name on Card"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.payment.card.number",
|
||||||
|
"tr": "Kart Numarası",
|
||||||
|
"en": "Card Number"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.payment.summary.title",
|
||||||
|
"tr": "Sipariş Özeti",
|
||||||
|
"en": "Order Summary"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.payment.summary.subtotal",
|
||||||
|
"tr": "Ara Toplam:",
|
||||||
|
"en": "Subtotal:"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.payment.summary.commission",
|
||||||
|
"tr": "Komisyon:",
|
||||||
|
"en": "Commission:"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.payment.summary.monthlyInstallment",
|
||||||
|
"tr": "Aylık Taksit:",
|
||||||
|
"en": "Monthly Installment:"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.payment.summary.total",
|
||||||
|
"tr": "Toplam:",
|
||||||
|
"en": "Total:"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.payment.buttons.back",
|
||||||
|
"tr": "Geri",
|
||||||
|
"en": "Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.payment.buttons.completeOrder",
|
||||||
|
"tr": "Siparişi Tamamla",
|
||||||
|
"en": "Complete Order"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.payment.buttons.pay",
|
||||||
|
"tr": "Ödeme Yap",
|
||||||
|
"en": "Pay"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.tenantForm.customerInfo",
|
||||||
|
"tr": "Müşteri Bilgileri",
|
||||||
|
"en": "Customer Information"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.tenantForm.existing.title",
|
||||||
|
"tr": "Mevcut Müşteri",
|
||||||
|
"en": "Existing Customer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.tenantForm.existing.desc",
|
||||||
|
"tr": "Kurum kodunuz ile giriş yapın",
|
||||||
|
"en": "Log in with your organization code"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.tenantForm.new.title",
|
||||||
|
"tr": "Yeni Müşteri",
|
||||||
|
"en": "New Customer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.tenantForm.new.desc",
|
||||||
|
"tr": "Kayıt olun ve hemen başlayın",
|
||||||
|
"en": "Register and get started immediately"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.tenantForm.orgCode",
|
||||||
|
"tr": "Kurum Kodu *",
|
||||||
|
"en": "Organization Code *"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.tenantForm.orgName",
|
||||||
|
"tr": "Şirket Adı *",
|
||||||
|
"en": "Company Name *"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.tenantForm.searchOrg",
|
||||||
|
"tr": "Kurumu Bul",
|
||||||
|
"en": "Find Organization"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.tenantForm.founder",
|
||||||
|
"tr": "Kurucu:",
|
||||||
|
"en": "Founder:"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.tenantForm.company",
|
||||||
|
"tr": "Şirket:",
|
||||||
|
"en": "Company:"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.tenantForm.email",
|
||||||
|
"tr": "E-posta:",
|
||||||
|
"en": "Email:"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.tenantForm.phone",
|
||||||
|
"tr": "Telefon *",
|
||||||
|
"en": "Phone *"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.tenantForm.mobile",
|
||||||
|
"tr": "Mobile:",
|
||||||
|
"en": "Mobile:"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.tenantForm.address",
|
||||||
|
"tr": "Adres *",
|
||||||
|
"en": "Address *"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.tenantForm.country",
|
||||||
|
"tr": "Ülke",
|
||||||
|
"en": "Country"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.tenantForm.city",
|
||||||
|
"tr": "Şehir *",
|
||||||
|
"en": "City *"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.tenantForm.district",
|
||||||
|
"tr": "İlçe *",
|
||||||
|
"en": "District *"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.tenantForm.postalCode",
|
||||||
|
"tr": "Posta Kodu *",
|
||||||
|
"en": "Postal Code *"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.tenantForm.taxOffice",
|
||||||
|
"tr": "Vergi Dairesi *",
|
||||||
|
"en": "Tax Office *"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.tenantForm.taxNumber",
|
||||||
|
"tr": "Vergi No *",
|
||||||
|
"en": "Tax Number *"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.tenantForm.reference",
|
||||||
|
"tr": "Referans",
|
||||||
|
"en": "Reference"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.tenantForm.buttons.back",
|
||||||
|
"tr": "Geri",
|
||||||
|
"en": "Back"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.tenantForm.buttons.continue",
|
||||||
|
"tr": "Devam Et",
|
||||||
|
"en": "Continue"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.search.title",
|
||||||
|
"tr": "Arama",
|
||||||
|
"en": "Search"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.search.placeholder",
|
||||||
|
"tr": "Ürün ara...",
|
||||||
|
"en": "Search products..."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.empty.title",
|
||||||
|
"tr": "Ürün bulunamadı",
|
||||||
|
"en": "No products found"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.empty.description",
|
||||||
|
"tr": "Arama kriterlerinizi değiştirmeyi deneyin.",
|
||||||
|
"en": "Try changing your search criteria."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.loading",
|
||||||
|
"tr": "Yükleniyor...",
|
||||||
|
"en": "Loading..."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.cart.title",
|
||||||
|
"tr": "Sepetim",
|
||||||
|
"en": "My Cart"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.cart.clearConfirm",
|
||||||
|
"tr": "Sepetteki tüm ürünleri silmek istediğinizden emin misiniz?",
|
||||||
|
"en": "Are you sure you want to remove all items from the cart?"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.cart.clear",
|
||||||
|
"tr": "Sepeti Temizle",
|
||||||
|
"en": "Clear Cart"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.cart.empty.title",
|
||||||
|
"tr": "Sepetiniz boş",
|
||||||
|
"en": "Your cart is empty"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.cart.empty.subtitle",
|
||||||
|
"tr": "Ürün eklemek için katalogdan seçim yapın",
|
||||||
|
"en": "Add products from the catalog"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.cart.monthly",
|
||||||
|
"tr": "Aylık",
|
||||||
|
"en": "Monthly"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.cart.yearly",
|
||||||
|
"tr": "Yıllık",
|
||||||
|
"en": "Yearly"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.cart.month",
|
||||||
|
"tr": "Ay",
|
||||||
|
"en": "Month"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.cart.year",
|
||||||
|
"tr": "Yıl",
|
||||||
|
"en": "Year"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.cart.total",
|
||||||
|
"tr": "Toplam:",
|
||||||
|
"en": "Total:"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.cart.checkout",
|
||||||
|
"tr": "Ödemeye Geç",
|
||||||
|
"en": "Proceed to Checkout"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.quantity",
|
||||||
|
"tr": "Adet:",
|
||||||
|
"en": "Quantity:"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.savings.yearly",
|
||||||
|
"tr": "Yıllık ile %{{percent}} tasarruf",
|
||||||
|
"en": "Save {{percent}}% with yearly"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.price.perMonthSuffix",
|
||||||
|
"tr": "/ Ay",
|
||||||
|
"en": "/ Month"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.price.perYearSuffix",
|
||||||
|
"tr": "/ Yıl",
|
||||||
|
"en": "/ Year"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.period.month",
|
||||||
|
"tr": "Ay",
|
||||||
|
"en": "Month"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.period.year",
|
||||||
|
"tr": "Yıl",
|
||||||
|
"en": "Year"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.total",
|
||||||
|
"tr": "Toplam:",
|
||||||
|
"en": "Total:"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.addToCart",
|
||||||
|
"tr": "Sepete Ekle",
|
||||||
|
"en": "Add to Cart"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.inCart",
|
||||||
|
"tr": "Sepette Mevcut",
|
||||||
|
"en": "Already in Cart"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"resourceName": "Platform",
|
"resourceName": "Platform",
|
||||||
"key": "Public.products.cta.description",
|
"key": "Public.products.cta.description",
|
||||||
|
|
@ -9408,7 +10002,177 @@
|
||||||
"key": "App.DeveloperKit.ComponentEditor.Loading",
|
"key": "App.DeveloperKit.ComponentEditor.Loading",
|
||||||
"en": "Loading component...",
|
"en": "Loading component...",
|
||||||
"tr": "Bileşen yükleniyor..."
|
"tr": "Bileşen yükleniyor..."
|
||||||
}
|
},
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.remoteBranchTraining",
|
||||||
|
"tr": "Uzaktan Şube Eğitimi (5 Saat)",
|
||||||
|
"en": "Remote Branch Training (5 Hours)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.remoteBranchTraining.desc",
|
||||||
|
"tr": "Sistem kullanımı sırasında kullanıcı hataları ortaya çıkabilir, Sözsoft kullanıcı hatalarının giderilmesi yönünde destek hizmeti sunmaktadır.",
|
||||||
|
"en": "During system usage, user errors may occur. Sözsoft provides support services to resolve user errors."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.branchHosting",
|
||||||
|
"tr": "Şube Barındırma Hizmeti",
|
||||||
|
"en": "Branch Hosting Service"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.branchHosting.desc",
|
||||||
|
"tr": "Şube veya şubelerinize ait tüm bilgilerinizin veya resimlerinizin barındırıldığı alan kiralama hizmetidir.",
|
||||||
|
"en": "A hosting service where all your branch-related information or images are stored."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.sms100k",
|
||||||
|
"tr": "100,000 SMS SOFTWARE",
|
||||||
|
"en": "100,000 SMS SOFTWARE"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.sms100k.desc",
|
||||||
|
"tr": "http://www.smsyukle.com adresinden yüklenebilir. İhtiyacınız olan SMS adedini belirleyerek, SMS satın almak için lütfen SMS yükle linkine tıklayın veya bize ulaşın.",
|
||||||
|
"en": "Available at http://www.smsyukle.com. Select the number of SMS you need and click the SMS load link or contact us to purchase."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.teacherLicense",
|
||||||
|
"tr": "Öğretmen Lisansı",
|
||||||
|
"en": "Teacher License"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.teacherLicense.desc",
|
||||||
|
"tr": "Şube/şubelerinizde sistemin kaç öğretmen tarafından kullandırılacağı kararına bağlı olarak belirlenir. Öğretmen lisansları aylık/yıllık kullanım olarak sunulmaktadır.",
|
||||||
|
"en": "Determined by how many teachers in your branch/branches will use the system. Teacher licenses are offered monthly/annually."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.extraHourlyService",
|
||||||
|
"tr": "Saatlik Ek Hizmet",
|
||||||
|
"en": "Extra Hourly Service"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.extraHourlyService.desc",
|
||||||
|
"tr": "Şubelerin standart hizmetlerin dışında istedikleri özel çalışmaları için belirlenen saatlik hizmet bedelidir.",
|
||||||
|
"en": "Hourly service fee for special work requested outside the standard services of branches."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.sms50k",
|
||||||
|
"tr": "50,000 SMS SOFTWARE",
|
||||||
|
"en": "50,000 SMS SOFTWARE"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.sms50k.desc",
|
||||||
|
"tr": "http://www.smsyukle.com adresinden yüklenebilir. İhtiyacınız olan SMS adedini belirleyerek, SMS satın almak için lütfen SMS yükle linkine tıklayın veya bize ulaşın.",
|
||||||
|
"en": "Available at http://www.smsyukle.com. Select the number of SMS you need and click the SMS load link or contact us to purchase."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.sms25k",
|
||||||
|
"tr": "25,000 SMS SOFTWARE",
|
||||||
|
"en": "25,000 SMS SOFTWARE"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.sms25k.desc",
|
||||||
|
"tr": "http://www.smsyukle.com adresinden yüklenebilir. İhtiyacınız olan SMS adedini belirleyerek, SMS satın almak için lütfen SMS yükle linkine tıklayın veya bize ulaşın.",
|
||||||
|
"en": "Available at http://www.smsyukle.com. Select the number of SMS you need and click the SMS load link or contact us to purchase."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.sms10k",
|
||||||
|
"tr": "10,000 SMS SOFTWARE",
|
||||||
|
"en": "10,000 SMS SOFTWARE"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.sms10k.desc",
|
||||||
|
"tr": "http://www.smsyukle.com adresinden yüklenebilir. İhtiyacınız olan SMS adedini belirleyerek, SMS satın almak için lütfen SMS yükle linkine tıklayın veya bize ulaşın.",
|
||||||
|
"en": "Available at http://www.smsyukle.com. Select the number of SMS you need and click the SMS load link or contact us to purchase."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.sms5k",
|
||||||
|
"tr": "5,000 SMS SOFTWARE",
|
||||||
|
"en": "5,000 SMS SOFTWARE"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.sms5k.desc",
|
||||||
|
"tr": "http://www.smsyukle.com adresinden yüklenebilir. İhtiyacınız olan SMS adedini belirleyerek, SMS satın almak için lütfen SMS yükle linkine tıklayın veya bize ulaşın.",
|
||||||
|
"en": "Available at http://www.smsyukle.com. Select the number of SMS you need and click the SMS load link or contact us to purchase."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.smsBlocking",
|
||||||
|
"tr": "SMS Engelleme Hizmeti",
|
||||||
|
"en": "SMS Blocking Service"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.smsBlocking.desc",
|
||||||
|
"tr": "Şube/şubelerinizden gönderilen SMS'lerin kursiyerler tarafından engelleme hizmetidir.",
|
||||||
|
"en": "A service that allows recipients to block SMS messages sent from your branch/branches."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.backupService",
|
||||||
|
"tr": "Veri Yedekleme Hizmeti",
|
||||||
|
"en": "Data Backup Service"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.backupService.desc",
|
||||||
|
"tr": "Bilgileriniz bizler için de önemlidir. Bu doğrultuda aldığımız yüksek güvenlik önlemlerinin yanısıra BACK-UP/ yedekleme hizmeti sunmaktayız.",
|
||||||
|
"en": "Your data is also important to us. In addition to our high security measures, we provide a BACK-UP/backup service."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.userLicense",
|
||||||
|
"tr": "Kullanıcı Lisansı",
|
||||||
|
"en": "User License"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.userLicense.desc",
|
||||||
|
"tr": "Şube/şubelerinizde sistemin kaç personel tarafından kullandırılacağı kararına bağlı olarak belirlenir. Kullanıcı lisansları aylık/yıllık kullanım olarak sunulmaktadır.",
|
||||||
|
"en": "Determined by how many personnel in your branch/branches will use the system. User licenses are offered monthly/annually."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.remoteSupportContract",
|
||||||
|
"tr": "Şube Uzaktan Destek Sözleşmesi",
|
||||||
|
"en": "Branch Remote Support Contract"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.remoteSupportContract.desc",
|
||||||
|
"tr": "Kullanıcıların/Şubelerin talebi doğrultusunda imzalanan servis sözleşmesi ile Sözsoft kapsamı ve detayı sözleşmelerimizde yer alan iş birliği hizmeti sağlamaktadır.",
|
||||||
|
"en": "With a service contract signed upon user/branch request, Sözsoft provides cooperation services as detailed in our agreements."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.mobileReporting",
|
||||||
|
"tr": "Mobil Raporlama Arayüzü",
|
||||||
|
"en": "Mobile Reporting Interface"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Public.products.mobileReporting.desc",
|
||||||
|
"tr": "kursyazilimi.com mobil arayüzü ile şubeler bazında akıllı telefon teknolojisi ile yönetim imkanı sağlamaktadır.",
|
||||||
|
"en": "With kursyazilimi.com’s mobile interface, management is possible per branch using smartphone technology."
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"Settings": [
|
"Settings": [
|
||||||
{
|
{
|
||||||
|
|
@ -26730,9 +27494,9 @@
|
||||||
"Products": [
|
"Products": [
|
||||||
{
|
{
|
||||||
"id": "5f4d6c1f-b1e0-4f91-854c-1d59c25e7193",
|
"id": "5f4d6c1f-b1e0-4f91-854c-1d59c25e7193",
|
||||||
"name": "Şube Barındırma Hizmeti",
|
"name": "Public.products.branchHosting",
|
||||||
"description": "Şube veya şubelerinize ait tüm bilgilerinizin veya resimlerinizin barındırıldığı alan kiralama hizmetidir.",
|
"description": "Public.products.branchHosting.desc",
|
||||||
"category": "Üyelik",
|
"category": "Public.products.categories.Üyelik",
|
||||||
"order": 1,
|
"order": 1,
|
||||||
"monthlyPrice": 850,
|
"monthlyPrice": 850,
|
||||||
"yearlyPrice": 3400,
|
"yearlyPrice": 3400,
|
||||||
|
|
@ -26741,9 +27505,9 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "a85d0f04-7d40-47cb-bcf6-d95fbe31ec93",
|
"id": "a85d0f04-7d40-47cb-bcf6-d95fbe31ec93",
|
||||||
"name": "Veri Yedekleme Hizmeti",
|
"name": "Public.products.backupService",
|
||||||
"description": "Bilgileriniz bizler için de önemlidir. Bu doğrultuda aldığımız yüksek güvenlik önlemlerinin yanısıra BACK-UP/ yedekleme hizmeti sunmaktayız.",
|
"description": "Public.products.backupService.desc",
|
||||||
"category": "Üyelik",
|
"category": "Public.products.categories.Üyelik",
|
||||||
"order": 2,
|
"order": 2,
|
||||||
"monthlyPrice": 2100,
|
"monthlyPrice": 2100,
|
||||||
"yearlyPrice": 2100,
|
"yearlyPrice": 2100,
|
||||||
|
|
@ -26752,9 +27516,9 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "03cfae0b-4e3a-4b4b-917f-f798f18e0f15",
|
"id": "03cfae0b-4e3a-4b4b-917f-f798f18e0f15",
|
||||||
"name": "Şube Uzaktan Destek Sözleşmesi",
|
"name": "Public.products.remoteSupportContract",
|
||||||
"description": "Kullanıcıların/Şubelerin talebi doğrultusunda imzalanan servis sözleşmesi ile Sözsoft kapsamı ve detayı sözleşmelerimizde yer alan iş birliği hizmeti sağlamaktadır.",
|
"description": "Public.products.remoteSupportContract.desc",
|
||||||
"category": "Üyelik",
|
"category": "Public.products.categories.Üyelik",
|
||||||
"order": 3,
|
"order": 3,
|
||||||
"monthlyPrice": 5000,
|
"monthlyPrice": 5000,
|
||||||
"yearlyPrice": 5000,
|
"yearlyPrice": 5000,
|
||||||
|
|
@ -26763,9 +27527,9 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "03cfae0b-4e3a-4b4b-917f-f798f18e0f11",
|
"id": "03cfae0b-4e3a-4b4b-917f-f798f18e0f11",
|
||||||
"name": "Kullanıcı Lisansı",
|
"name": "Public.products.userLicense",
|
||||||
"description": "Şube/şubelerinizde sistemin kaç personel tarafından kullandırılacağı kararına bağlı olarak belirlenir. Kullanıcı lisansları aylık/yıllık kullanım olarak sunulmaktadır.",
|
"description": "Public.products.userLicense.desc",
|
||||||
"category": "Lisans",
|
"category": "Public.products.categories.Lisans",
|
||||||
"order": 4,
|
"order": 4,
|
||||||
"monthlyPrice": 900,
|
"monthlyPrice": 900,
|
||||||
"yearlyPrice": 3500,
|
"yearlyPrice": 3500,
|
||||||
|
|
@ -26774,9 +27538,9 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "36d98c72-6a62-4fa1-b942-2689eb42e4d4",
|
"id": "36d98c72-6a62-4fa1-b942-2689eb42e4d4",
|
||||||
"name": "Öğretmen Lisansı",
|
"name": "Public.products.teacherLicense",
|
||||||
"description": "Şube/şubelerinizde sistemin kaç öğretmen tarafından kullandırılacağı kararına bağlı olarak belirlenir. Öğretmen lisansları aylık/yıllık kullanım olarak sunulmaktadır.",
|
"description": "Public.products.teacherLicense.desc",
|
||||||
"category": "Lisans",
|
"category": "Public.products.categories.Lisans",
|
||||||
"order": 5,
|
"order": 5,
|
||||||
"monthlyPrice": 500,
|
"monthlyPrice": 500,
|
||||||
"yearlyPrice": 1700,
|
"yearlyPrice": 1700,
|
||||||
|
|
@ -26785,9 +27549,9 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "9a80f69d-46e5-4b92-91dc-fbb4d2f90c1f",
|
"id": "9a80f69d-46e5-4b92-91dc-fbb4d2f90c1f",
|
||||||
"name": "Mobil Raporlama Arayüzü",
|
"name": "Public.products.mobileReporting",
|
||||||
"description": "kursyazilimi.com mobil arayüzü ile şubeler bazında akıllı telefon teknolojisi ile yönetim imkanı sağlamaktadır.",
|
"description": "Public.products.mobileReporting.desc",
|
||||||
"category": "Lisans",
|
"category": "Public.products.categories.Lisans",
|
||||||
"order": 6,
|
"order": 6,
|
||||||
"monthlyPrice": 400,
|
"monthlyPrice": 400,
|
||||||
"yearlyPrice": 1400,
|
"yearlyPrice": 1400,
|
||||||
|
|
@ -26796,9 +27560,9 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "66324548-8500-4f06-8b1c-1a31e8d25c39",
|
"id": "66324548-8500-4f06-8b1c-1a31e8d25c39",
|
||||||
"name": "Uzaktan Şube Eğitimi (5 Saat)",
|
"name": "Public.products.remoteBranchTraining",
|
||||||
"description": "Sistem kullanımı sırasında kullanıcı hataları ortaya çıkabilir, sözsoft kullanıcı hatalarının giderilmesi yönünde destek hizmeti sunmaktadır.",
|
"description": "Public.products.remoteBranchTraining.desc",
|
||||||
"category": "Ek Hizmetler",
|
"category": "Public.products.categories.Ek Hizmetler",
|
||||||
"order": 7,
|
"order": 7,
|
||||||
"monthlyPrice": 3700,
|
"monthlyPrice": 3700,
|
||||||
"yearlyPrice": 3700,
|
"yearlyPrice": 3700,
|
||||||
|
|
@ -26807,10 +27571,10 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "b0b51a46-cf33-423f-b93f-2e2a3b8e27c0",
|
"id": "b0b51a46-cf33-423f-b93f-2e2a3b8e27c0",
|
||||||
"name": "Saatlik Ek Hizmet",
|
"name": "Public.products.extraHourlyService",
|
||||||
"description": "Şubelerin standart hizmetlerin dışında istedikleri özel çalışmaları için belirlenen saatlik hizmet bedelidir.",
|
"description": "Public.products.extraHourlyService.desc",
|
||||||
"order": 8,
|
"order": 8,
|
||||||
"category": "Ek Hizmetler",
|
"category": "Public.products.categories.Ek Hizmetler",
|
||||||
"monthlyPrice": 2000,
|
"monthlyPrice": 2000,
|
||||||
"yearlyPrice": 2000,
|
"yearlyPrice": 2000,
|
||||||
"isQuantityBased": true,
|
"isQuantityBased": true,
|
||||||
|
|
@ -26818,9 +27582,9 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "15b813c6-4905-412b-999a-c303b91b3152",
|
"id": "15b813c6-4905-412b-999a-c303b91b3152",
|
||||||
"name": "5,000 SMS SOFTWARE",
|
"name": "Public.products.sms5k",
|
||||||
"description": "http://www.smsyukle.com adresinden yüklenebilir. İhtiyacınız olan SMS adedini belirleyerek, SMS satın almak için lütfen SMS yükle linkine tıklayın veya bize ulaşın",
|
"description": "Public.products.sms5k.desc",
|
||||||
"category": "Ek Hizmetler",
|
"category": "Public.products.categories.Ek Hizmetler",
|
||||||
"order": 9,
|
"order": 9,
|
||||||
"monthlyPrice": 750,
|
"monthlyPrice": 750,
|
||||||
"yearlyPrice": 750,
|
"yearlyPrice": 750,
|
||||||
|
|
@ -26829,9 +27593,9 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "e2c940b4-4a35-4f3d-8600-b1c2b9ce5179",
|
"id": "e2c940b4-4a35-4f3d-8600-b1c2b9ce5179",
|
||||||
"name": "10,000 SMS SOFTWARE",
|
"name": "Public.products.sms10k",
|
||||||
"description": "http://www.smsyukle.com adresinden yüklenebilir. İhtiyacınız olan SMS adedini belirleyerek, SMS satın almak için lütfen SMS yükle linkine tıklayın veya bize ulaşın",
|
"description": "Public.products.sms10k.desc",
|
||||||
"category": "Ek Hizmetler",
|
"category": "Public.products.categories.Ek Hizmetler",
|
||||||
"order": 10,
|
"order": 10,
|
||||||
"monthlyPrice": 1350,
|
"monthlyPrice": 1350,
|
||||||
"yearlyPrice": 1350,
|
"yearlyPrice": 1350,
|
||||||
|
|
@ -26840,9 +27604,9 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "1985ba1b1-f4c6-40f2-a747-0cf45c96a5b7",
|
"id": "1985ba1b1-f4c6-40f2-a747-0cf45c96a5b7",
|
||||||
"name": "25,000 SMS SOFTWARE",
|
"name": "Public.products.sms25k",
|
||||||
"description": "http://www.smsyukle.com adresinden yüklenebilir. İhtiyacınız olan SMS adedini belirleyerek, SMS satın almak için lütfen SMS yükle linkine tıklayın veya bize ulaşın",
|
"description": "Public.products.sms25k.desc",
|
||||||
"category": "Ek Hizmetler",
|
"category": "Public.products.categories.Ek Hizmetler",
|
||||||
"order": 11,
|
"order": 11,
|
||||||
"monthlyPrice": 2900,
|
"monthlyPrice": 2900,
|
||||||
"yearlyPrice": 2900,
|
"yearlyPrice": 2900,
|
||||||
|
|
@ -26851,9 +27615,9 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "7a7ae7c3-bef2-4978-90cf-96d1475e3492",
|
"id": "7a7ae7c3-bef2-4978-90cf-96d1475e3492",
|
||||||
"name": "50,000 SMS SOFTWARE",
|
"name": "Public.products.sms50k",
|
||||||
"description": "http://www.smsyukle.com adresinden yüklenebilir. İhtiyacınız olan SMS adedini belirleyerek, SMS satın almak için lütfen SMS yükle linkine tıklayın veya bize ulaşın",
|
"description": "Public.products.sms50k.desc",
|
||||||
"category": "Ek Hizmetler",
|
"category": "Public.products.categories.Ek Hizmetler",
|
||||||
"order": 12,
|
"order": 12,
|
||||||
"monthlyPrice": 5100,
|
"monthlyPrice": 5100,
|
||||||
"yearlyPrice": 5100,
|
"yearlyPrice": 5100,
|
||||||
|
|
@ -26862,9 +27626,9 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "3e6a8de1-6c48-4ff8-87f5-252735a7e89f",
|
"id": "3e6a8de1-6c48-4ff8-87f5-252735a7e89f",
|
||||||
"name": "100,000 SMS SOFTWARE",
|
"name": "Public.products.sms100k",
|
||||||
"description": "http://www.smsyukle.com adresinden yüklenebilir. İhtiyacınız olan SMS adedini belirleyerek, SMS satın almak için lütfen SMS yükle linkine tıklayın veya bize ulaşın",
|
"description": "Public.products.sms100k.desc",
|
||||||
"category": "Ek Hizmetler",
|
"category": "Public.products.categories.Ek Hizmetler",
|
||||||
"order": 13,
|
"order": 13,
|
||||||
"monthlyPrice": 8800,
|
"monthlyPrice": 8800,
|
||||||
"yearlyPrice": 8800,
|
"yearlyPrice": 8800,
|
||||||
|
|
@ -26873,9 +27637,9 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "2e35b9b8-f404-4b83-9737-d059c05fd44b",
|
"id": "2e35b9b8-f404-4b83-9737-d059c05fd44b",
|
||||||
"name": "SMS Engelleme Hizmeti",
|
"name": "Public.products.smsBlocking",
|
||||||
"description": "Şube/şubelerinizden gönderilen SMS lerin kursiyerler tarafından engelleme hizmetidir.",
|
"description": "Public.products.smsBlocking.desc",
|
||||||
"category": "Ek Hizmetler",
|
"category": "Public.products.categories.Ek Hizmetler",
|
||||||
"order": 14,
|
"order": 14,
|
||||||
"monthlyPrice": 880,
|
"monthlyPrice": 880,
|
||||||
"yearlyPrice": 880,
|
"yearlyPrice": 880,
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,7 @@ define(['./workbox-54d0af47'], (function (workbox) { 'use strict';
|
||||||
"revision": "3ca0b8505b4bec776b69afdba2768812"
|
"revision": "3ca0b8505b4bec776b69afdba2768812"
|
||||||
}, {
|
}, {
|
||||||
"url": "index.html",
|
"url": "index.html",
|
||||||
"revision": "0.tihrrtufp5o"
|
"revision": "0.4fqifsv2jio"
|
||||||
}], {});
|
}], {});
|
||||||
workbox.cleanupOutdatedCaches();
|
workbox.cleanupOutdatedCaches();
|
||||||
workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), {
|
workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { FaCalendar, FaClock, FaMinus, FaPlus, FaShoppingCart } from 'react-icons/fa';
|
import { FaCalendar, FaClock, FaMinus, FaPlus, FaShoppingCart } from 'react-icons/fa'
|
||||||
import { BillingCycle } from '@/proxy/order/models'
|
import { BillingCycle } from '@/proxy/order/models'
|
||||||
import { CartState } from '@/utils/cartUtils'
|
import { CartState } from '@/utils/cartUtils'
|
||||||
import { useScroll } from '@/contexts/ScrollContext'
|
import { useScroll } from '@/contexts/ScrollContext'
|
||||||
|
|
@ -42,7 +42,9 @@ export const BillingControls: React.FC<BillingControlsProps> = ({
|
||||||
<div className="flex items-center space-x-6">
|
<div className="flex items-center space-x-6">
|
||||||
<div className="flex items-center space-x-2 rounded-lg">
|
<div className="flex items-center space-x-2 rounded-lg">
|
||||||
<FaCalendar className="w-5 h-5 text-gray-600" />
|
<FaCalendar className="w-5 h-5 text-gray-600" />
|
||||||
<span className="font-medium text-gray-900">Faturalama Döngüsü:</span>
|
<span className="font-medium text-gray-900">
|
||||||
|
{translate('::Public.products.billingcycle')}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex space-x-2">
|
<div className="flex space-x-2">
|
||||||
|
|
@ -60,7 +62,7 @@ export const BillingControls: React.FC<BillingControlsProps> = ({
|
||||||
hasCartItems ? 'Sepette ürün varken faturalama döngüsü değiştirilemez' : undefined
|
hasCartItems ? 'Sepette ürün varken faturalama döngüsü değiştirilemez' : undefined
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
Aylık
|
{translate('::Public.products.billingcycle.monthly')}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => !hasCartItems && setGlobalBillingCycle('yearly')}
|
onClick={() => !hasCartItems && setGlobalBillingCycle('yearly')}
|
||||||
|
|
@ -76,7 +78,7 @@ export const BillingControls: React.FC<BillingControlsProps> = ({
|
||||||
hasCartItems ? 'Sepette ürün varken faturalama döngüsü değiştirilemez' : undefined
|
hasCartItems ? 'Sepette ürün varken faturalama döngüsü değiştirilemez' : undefined
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
Yıllık
|
{translate('::Public.products.billingcycle.yearly')}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -85,7 +87,9 @@ export const BillingControls: React.FC<BillingControlsProps> = ({
|
||||||
<div className="flex items-center space-x-4">
|
<div className="flex items-center space-x-4">
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<FaClock className="w-5 h-5 text-gray-600" />
|
<FaClock className="w-5 h-5 text-gray-600" />
|
||||||
<span className="font-medium text-gray-900">Periyod:</span>
|
<span className="font-medium text-gray-900">
|
||||||
|
{translate('::Public.products.period')}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
|
|
@ -105,7 +109,9 @@ export const BillingControls: React.FC<BillingControlsProps> = ({
|
||||||
<div className="flex items-center space-x-2 bg-gray-50 px-4 py-2 rounded-lg">
|
<div className="flex items-center space-x-2 bg-gray-50 px-4 py-2 rounded-lg">
|
||||||
<span className="font-bold text-lg text-blue-600">{globalPeriod}</span>
|
<span className="font-bold text-lg text-blue-600">{globalPeriod}</span>
|
||||||
<span className="text-sm text-gray-600">
|
<span className="text-sm text-gray-600">
|
||||||
{globalBillingCycle === 'monthly' ? 'Ay' : 'Yıl'}
|
{globalBillingCycle === 'monthly'
|
||||||
|
? translate('::Public.products.billingcycle.month')
|
||||||
|
: translate('::Public.products.billingcycle.year')}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -139,16 +145,6 @@ export const BillingControls: React.FC<BillingControlsProps> = ({
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* {globalBillingCycle === 'yearly' && globalPeriod > 1 && (
|
|
||||||
<div className="mt-3 text-center">
|
|
||||||
<div className="inline-flex items-center px-3 py-1 bg-emerald-100 text-emerald-800 text-sm font-medium rounded-full">
|
|
||||||
<span>
|
|
||||||
{globalPeriod} yıllık abonelik ile %{Math.round((1 - (globalBillingCycle === 'yearly' ? 1 : 12)) * 100)} tasarruf
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)} */}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,23 @@
|
||||||
import React from 'react';
|
import React from 'react'
|
||||||
import {
|
import { FaTimes, FaMinus, FaPlus, FaShoppingBag, FaTrash } from 'react-icons/fa'
|
||||||
FaTimes,
|
import { BillingCycle, BasketItem } from '@/proxy/order/models'
|
||||||
FaMinus,
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
FaPlus,
|
|
||||||
FaShoppingBag,
|
|
||||||
FaTrash
|
|
||||||
} from 'react-icons/fa';
|
|
||||||
import { BillingCycle, BasketItem } from '@/proxy/order/models';
|
|
||||||
|
|
||||||
interface CartState {
|
interface CartState {
|
||||||
items: BasketItem[];
|
items: BasketItem[]
|
||||||
total: number;
|
total: number
|
||||||
globalBillingCycle: BillingCycle;
|
globalBillingCycle: BillingCycle
|
||||||
globalPeriod: number;
|
globalPeriod: number
|
||||||
}
|
}
|
||||||
|
|
||||||
interface CartProps {
|
interface CartProps {
|
||||||
isOpen: boolean;
|
isOpen: boolean
|
||||||
onClose: () => void;
|
onClose: () => void
|
||||||
onCheckout: () => void;
|
onCheckout: () => void
|
||||||
cartState: CartState;
|
cartState: CartState
|
||||||
updateQuantity: (id: string, quantity: number) => void;
|
updateQuantity: (id: string, quantity: number) => void
|
||||||
removeItem: (id: string) => void;
|
removeItem: (id: string) => void
|
||||||
clearCart: () => void;
|
clearCart: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Cart: React.FC<CartProps> = ({
|
export const Cart: React.FC<CartProps> = ({
|
||||||
|
|
@ -32,24 +27,25 @@ export const Cart: React.FC<CartProps> = ({
|
||||||
cartState,
|
cartState,
|
||||||
updateQuantity,
|
updateQuantity,
|
||||||
removeItem,
|
removeItem,
|
||||||
clearCart
|
clearCart,
|
||||||
}) => {
|
}) => {
|
||||||
|
const { translate } = useLocalization()
|
||||||
|
|
||||||
const handleClearCart = () => {
|
const handleClearCart = () => {
|
||||||
if (window.confirm('Sepetteki tüm ürünleri silmek istediğinizden emin misiniz?')) {
|
if (window.confirm('Sepetteki tüm ürünleri silmek istediğinizden emin misiniz?')) {
|
||||||
clearCart();
|
clearCart()
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
const formatPrice = (price: number) => {
|
const formatPrice = (price: number) => {
|
||||||
return new Intl.NumberFormat('tr-TR', {
|
return new Intl.NumberFormat('tr-TR', {
|
||||||
style: 'currency',
|
style: 'currency',
|
||||||
currency: 'TRY',
|
currency: 'TRY',
|
||||||
minimumFractionDigits: 0
|
minimumFractionDigits: 0,
|
||||||
}).format(price);
|
}).format(price)
|
||||||
};
|
}
|
||||||
|
|
||||||
if (!isOpen) return null;
|
if (!isOpen) return null
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed inset-0 z-50 overflow-hidden">
|
<div className="fixed inset-0 z-50 overflow-hidden">
|
||||||
|
|
@ -58,13 +54,15 @@ export const Cart: React.FC<CartProps> = ({
|
||||||
<div className="absolute right-0 top-0 h-full w-full max-w-md bg-white shadow-xl">
|
<div className="absolute right-0 top-0 h-full w-full max-w-md bg-white shadow-xl">
|
||||||
<div className="flex flex-col h-full">
|
<div className="flex flex-col h-full">
|
||||||
<div className="flex items-center justify-between p-6 border-b border-gray-200">
|
<div className="flex items-center justify-between p-6 border-b border-gray-200">
|
||||||
<h2 className="text-lg font-semibold text-gray-900">Sepetim</h2>
|
<h2 className="text-lg font-semibold text-gray-900">
|
||||||
|
{translate('::Public.cart.title')}
|
||||||
|
</h2>
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
{cartState.items.length > 0 && (
|
{cartState.items.length > 0 && (
|
||||||
<button
|
<button
|
||||||
onClick={handleClearCart}
|
onClick={handleClearCart}
|
||||||
className="p-2 text-red-500 hover:bg-red-50 rounded-lg transition-colors"
|
className="p-2 text-red-500 hover:bg-red-50 rounded-lg transition-colors"
|
||||||
title="Sepeti Temizle"
|
title={translate('::Public.cart.clear')}
|
||||||
>
|
>
|
||||||
<FaTrash className="w-5 h-5" />
|
<FaTrash className="w-5 h-5" />
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -82,16 +80,19 @@ export const Cart: React.FC<CartProps> = ({
|
||||||
{cartState.items.length === 0 ? (
|
{cartState.items.length === 0 ? (
|
||||||
<div className="flex flex-col items-center justify-center h-full text-gray-500">
|
<div className="flex flex-col items-center justify-center h-full text-gray-500">
|
||||||
<FaShoppingBag className="w-16 h-16 mb-4" />
|
<FaShoppingBag className="w-16 h-16 mb-4" />
|
||||||
<p className="text-lg font-medium">Sepetiniz boş</p>
|
<p className="text-lg font-medium">{translate('::Public.cart.empty.title')}</p>
|
||||||
<p className="text-sm">Ürün eklemek için katalogdan seçim yapın</p>
|
<p className="text-sm">{translate('::Public.cart.empty.subtitle')}</p>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{cartState.items.map((item: BasketItem, index: number) => (
|
{cartState.items.map((item: BasketItem, index: number) => (
|
||||||
<div key={`${item.product.id}-${item.billingCycle}-${index}`} className="border border-gray-200 rounded-lg p-4">
|
<div
|
||||||
|
key={`${item.product.id}-${item.billingCycle}-${index}`}
|
||||||
|
className="border border-gray-200 rounded-lg p-4"
|
||||||
|
>
|
||||||
<div className="flex justify-between items-start mb-2">
|
<div className="flex justify-between items-start mb-2">
|
||||||
<h4 className="font-medium text-gray-900 text-sm leading-tight">
|
<h4 className="font-medium text-gray-900 text-sm leading-tight">
|
||||||
{item.product.name}
|
{translate('::' + item.product.name)}
|
||||||
</h4>
|
</h4>
|
||||||
<button
|
<button
|
||||||
onClick={() => removeItem(item.product.id)}
|
onClick={() => removeItem(item.product.id)}
|
||||||
|
|
@ -106,11 +107,18 @@ export const Cart: React.FC<CartProps> = ({
|
||||||
{item.product.isQuantityBased && item.quantity > 1 && (
|
{item.product.isQuantityBased && item.quantity > 1 && (
|
||||||
<span className="font-medium text-gray-900">{item.quantity}x - </span>
|
<span className="font-medium text-gray-900">{item.quantity}x - </span>
|
||||||
)}
|
)}
|
||||||
{item.billingCycle === 'monthly' ? 'Aylık' :
|
{item.billingCycle === 'monthly'
|
||||||
item.billingCycle === 'yearly' ? 'Yıllık' : 'Aylık'}
|
? translate('::Public.cart.monthly')
|
||||||
|
: item.billingCycle === 'yearly'
|
||||||
|
? translate('::Public.cart.yearly')
|
||||||
|
: translate('::Public.cart.monthly')}
|
||||||
{cartState.globalPeriod > 1 && item.product.isQuantityBased && (
|
{cartState.globalPeriod > 1 && item.product.isQuantityBased && (
|
||||||
<span className="text-xs text-gray-500">
|
<span className="text-xs text-gray-500">
|
||||||
({cartState.globalPeriod} {item.billingCycle === 'monthly' ? 'Ay' : 'Yıl'})
|
({cartState.globalPeriod}{' '}
|
||||||
|
{item.billingCycle === 'monthly'
|
||||||
|
? translate('::Public.cart.month')
|
||||||
|
: translate('::Public.cart.year')}
|
||||||
|
)
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -146,7 +154,9 @@ export const Cart: React.FC<CartProps> = ({
|
||||||
{cartState.items.length > 0 && (
|
{cartState.items.length > 0 && (
|
||||||
<div className="border-t border-gray-200 p-6">
|
<div className="border-t border-gray-200 p-6">
|
||||||
<div className="flex justify-between items-center mb-4">
|
<div className="flex justify-between items-center mb-4">
|
||||||
<span className="text-lg font-semibold text-gray-900">Toplam:</span>
|
<span className="text-lg font-semibold text-gray-900">
|
||||||
|
{translate('::Public.cart.total')}
|
||||||
|
</span>
|
||||||
<span className="text-xl font-bold text-blue-600">
|
<span className="text-xl font-bold text-blue-600">
|
||||||
{formatPrice(cartState.total)}
|
{formatPrice(cartState.total)}
|
||||||
</span>
|
</span>
|
||||||
|
|
@ -156,12 +166,12 @@ export const Cart: React.FC<CartProps> = ({
|
||||||
onClick={onCheckout}
|
onClick={onCheckout}
|
||||||
className="w-full bg-blue-600 hover:bg-blue-700 text-white font-medium py-3 px-4 rounded-lg transition-colors duration-200"
|
className="w-full bg-blue-600 hover:bg-blue-700 text-white font-medium py-3 px-4 rounded-lg transition-colors duration-200"
|
||||||
>
|
>
|
||||||
Ödemeye Geç
|
{translate('::Public.cart.checkout')}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import {
|
||||||
} from 'react-icons/fa';
|
} from 'react-icons/fa';
|
||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate } from 'react-router-dom'
|
||||||
import { ROUTES_ENUM } from '@/routes/route.constant'
|
import { ROUTES_ENUM } from '@/routes/route.constant'
|
||||||
|
import { useLocalization } from '@/utils/hooks/useLocalization';
|
||||||
|
|
||||||
interface OrderSuccessProps {
|
interface OrderSuccessProps {
|
||||||
orderId: string
|
orderId: string
|
||||||
|
|
@ -13,24 +14,25 @@ interface OrderSuccessProps {
|
||||||
|
|
||||||
export const OrderSuccess: React.FC<OrderSuccessProps> = ({ orderId, onBackToShop }) => {
|
export const OrderSuccess: React.FC<OrderSuccessProps> = ({ orderId, onBackToShop }) => {
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
|
const { translate } = useLocalization()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="max-w-2xl mx-auto text-center">
|
<div className="max-w-2xl mx-auto text-center">
|
||||||
<div className="bg-white rounded-xl shadow-lg border border-gray-200 p-8">
|
<div className="bg-white rounded-xl shadow-lg border border-gray-200 p-8">
|
||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
<FaCheckCircle className="w-16 h-16 text-green-500 mx-auto mb-4" />
|
<FaCheckCircle className="w-16 h-16 text-green-500 mx-auto mb-4" />
|
||||||
<h2 className="text-2xl font-bold text-gray-900 mb-2">Siparişiniz Başarıyla Alındı!</h2>
|
<h2 className="text-2xl font-bold text-gray-900 mb-2">{translate('::Public.order.success.title')}</h2>
|
||||||
<p className="text-gray-600">
|
<p className="text-gray-600">
|
||||||
Sipariş numaranız: <span className="font-semibold text-blue-600">#{orderId}</span>
|
{translate('::Public.order.success.number')} <span className="font-semibold text-blue-600">#{orderId}</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="bg-green-50 border border-green-200 rounded-lg p-4 mb-6">
|
<div className="bg-green-50 border border-green-200 rounded-lg p-4 mb-6">
|
||||||
<h3 className="font-semibold text-green-800 mb-2">Sonraki Adımlar</h3>
|
<h3 className="font-semibold text-green-800 mb-2">{translate('::Public.order.success.nextSteps')}</h3>
|
||||||
<ul className="text-sm text-green-700 space-y-1 text-left">
|
<ul className="text-sm text-green-700 space-y-1 text-left">
|
||||||
<li>• Siparişiniz 24 saat içinde işleme alınacaktır</li>
|
<li>• {translate('::Public.order.success.step1')}</li>
|
||||||
<li>• Lisans bilgileri e-posta adresinize gönderilecektir</li>
|
<li>• {translate('::Public.order.success.step2')}</li>
|
||||||
<li>• Kurulum desteği için ekibimizle iletişime geçebilirsiniz</li>
|
<li>• {translate('::Public.order.success.step3')}</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -40,7 +42,7 @@ export const OrderSuccess: React.FC<OrderSuccessProps> = ({ orderId, onBackToSho
|
||||||
className="flex items-center justify-center px-6 py-3 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors"
|
className="flex items-center justify-center px-6 py-3 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors"
|
||||||
>
|
>
|
||||||
<FaArrowLeft className="w-4 h-4 mr-2" />
|
<FaArrowLeft className="w-4 h-4 mr-2" />
|
||||||
Ana Sayfa'ya Dön
|
{translate('::Public.order.success.backHome')}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,8 @@ import {
|
||||||
FaGlobe,
|
FaGlobe,
|
||||||
FaMoneyBillWave,
|
FaMoneyBillWave,
|
||||||
FaDollarSign,
|
FaDollarSign,
|
||||||
FaUserPlus
|
FaUserPlus,
|
||||||
} from 'react-icons/fa';
|
} from 'react-icons/fa'
|
||||||
import {
|
import {
|
||||||
BillingCycle,
|
BillingCycle,
|
||||||
BasketItem,
|
BasketItem,
|
||||||
|
|
@ -22,6 +22,7 @@ import {
|
||||||
} from '@/proxy/order/models'
|
} from '@/proxy/order/models'
|
||||||
import { OrderService } from '@/services/order.service'
|
import { OrderService } from '@/services/order.service'
|
||||||
import { CustomTenantDto } from '@/proxy/config/models'
|
import { CustomTenantDto } from '@/proxy/config/models'
|
||||||
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
|
|
||||||
interface CartState {
|
interface CartState {
|
||||||
items: BasketItem[]
|
items: BasketItem[]
|
||||||
|
|
@ -52,6 +53,7 @@ export const PaymentForm: React.FC<PaymentFormProps> = ({
|
||||||
cardName: '',
|
cardName: '',
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const { translate } = useLocalization()
|
||||||
const [paymentMethods, setPaymentMethods] = useState<PaymentMethodDto[]>([])
|
const [paymentMethods, setPaymentMethods] = useState<PaymentMethodDto[]>([])
|
||||||
const [installmentOptions, setInstallmentOptions] = useState<InstallmentOptionDto[]>([])
|
const [installmentOptions, setInstallmentOptions] = useState<InstallmentOptionDto[]>([])
|
||||||
const [loading, setLoading] = useState<boolean>(true)
|
const [loading, setLoading] = useState<boolean>(true)
|
||||||
|
|
@ -116,7 +118,9 @@ export const PaymentForm: React.FC<PaymentFormProps> = ({
|
||||||
return (
|
return (
|
||||||
<div className="mx-auto px-4 lg:px-8 mb-6">
|
<div className="mx-auto px-4 lg:px-8 mb-6">
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<div className="text-center py-12 text-gray-500">Yükleniyor...</div>
|
<div className="text-center py-12 text-gray-500">
|
||||||
|
{translate('::Public.payment.loading')}
|
||||||
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<form onSubmit={handleSubmit} className="flex flex-col lg:flex-row gap-6">
|
<form onSubmit={handleSubmit} className="flex flex-col lg:flex-row gap-6">
|
||||||
{/* 3 Sütun: Ödeme Yöntemi | Taksit Seçenekleri | Sipariş Özeti */}
|
{/* 3 Sütun: Ödeme Yöntemi | Taksit Seçenekleri | Sipariş Özeti */}
|
||||||
|
|
@ -125,88 +129,115 @@ export const PaymentForm: React.FC<PaymentFormProps> = ({
|
||||||
{tenant && (
|
{tenant && (
|
||||||
<>
|
<>
|
||||||
<h2 className="text-lg font-semibold mb-4 flex items-center">
|
<h2 className="text-lg font-semibold mb-4 flex items-center">
|
||||||
<FaUser className="w-5 h-5 text-green-600 mr-2" /> Müşteri Bilgileri
|
<FaUser className="w-5 h-5 text-green-600 mr-2" />{' '}
|
||||||
|
{translate('::Public.payment.customerInfo')}
|
||||||
</h2>
|
</h2>
|
||||||
<div className="pt-4 border-t border-gray-200">
|
<div className="pt-4 border-t border-gray-200">
|
||||||
<div className="grid grid-cols-1 gap-y-3 text-sm text-gray-700">
|
<div className="grid grid-cols-1 gap-y-3 text-sm text-gray-700">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<FaUser className="w-4 h-4 text-gray-500" />
|
<FaUser className="w-4 h-4 text-gray-500" />
|
||||||
<span className="font-medium">Kurum Kodu:</span>
|
<span className="font-medium">
|
||||||
|
{translate('::Public.payment.customer.code')}
|
||||||
|
</span>
|
||||||
<span>{tenant.name}</span>
|
<span>{tenant.name}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<FaUser className="w-4 h-4 text-gray-500" />
|
<FaUser className="w-4 h-4 text-gray-500" />
|
||||||
<span className="font-medium">Kurucu:</span>
|
<span className="font-medium">
|
||||||
|
{translate('::Public.payment.customer.founder')}
|
||||||
|
</span>
|
||||||
<span>{tenant.founder}</span>
|
<span>{tenant.founder}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<FaBuilding className="w-4 h-4 text-gray-500" />
|
<FaBuilding className="w-4 h-4 text-gray-500" />
|
||||||
<span className="font-medium">Şirket:</span>
|
<span className="font-medium">
|
||||||
|
{translate('::Public.payment.customer.company')}
|
||||||
|
</span>
|
||||||
<span>{tenant.institutionName}</span>
|
<span>{tenant.institutionName}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<FaMailBulk className="w-4 h-4 text-gray-500" />
|
<FaMailBulk className="w-4 h-4 text-gray-500" />
|
||||||
<span className="font-medium">E-posta:</span>
|
<span className="font-medium">
|
||||||
|
{translate('::Public.payment.customer.email')}
|
||||||
|
</span>
|
||||||
<span>{tenant.email}</span>
|
<span>{tenant.email}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<FaPhone className="w-4 h-4 text-gray-500" />
|
<FaPhone className="w-4 h-4 text-gray-500" />
|
||||||
<span className="font-medium">Telefon:</span>
|
<span className="font-medium">
|
||||||
|
{translate('::Public.payment.customer.phone')}
|
||||||
|
</span>
|
||||||
<span>{tenant.phone}</span>
|
<span>{tenant.phone}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-start gap-2">
|
<div className="flex items-start gap-2">
|
||||||
<FaMapMarkerAlt className="w-4 h-4 text-gray-500 mt-0.5" />
|
<FaMapMarkerAlt className="w-4 h-4 text-gray-500 mt-0.5" />
|
||||||
<div>
|
<div>
|
||||||
<span className="font-medium">Adres:</span>
|
<span className="font-medium">
|
||||||
|
{translate('::Public.payment.customer.address')}:
|
||||||
|
</span>
|
||||||
<div>{tenant.address}</div>
|
<div>{tenant.address}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<FaGlobe className="w-4 h-4 text-gray-500" />
|
<FaGlobe className="w-4 h-4 text-gray-500" />
|
||||||
<span className="font-medium">Ülke:</span>
|
<span className="font-medium">
|
||||||
|
{translate('::Public.payment.customer.country')}
|
||||||
|
</span>
|
||||||
<span>{tenant.country}</span>
|
<span>{tenant.country}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<FaGlobe className="w-4 h-4 text-gray-500" />
|
<FaGlobe className="w-4 h-4 text-gray-500" />
|
||||||
<span className="font-medium">Şehir:</span>
|
<span className="font-medium">
|
||||||
|
{translate('::Public.payment.customer.city')}
|
||||||
|
</span>
|
||||||
<span>{tenant.city}</span>
|
<span>{tenant.city}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<FaMap className="w-4 h-4 text-gray-500" />
|
<FaMap className="w-4 h-4 text-gray-500" />
|
||||||
<span className="font-medium">İlçe:</span>
|
<span className="font-medium">
|
||||||
|
{translate('::Public.payment.customer.district')}
|
||||||
|
</span>
|
||||||
<span>{tenant.district}</span>
|
<span>{tenant.district}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<FaMapMarkerAlt className="w-4 h-4 text-gray-500" />
|
<FaMapMarkerAlt className="w-4 h-4 text-gray-500" />
|
||||||
<span className="font-medium">Posta Kodu:</span>
|
<span className="font-medium">
|
||||||
|
{translate('::Public.payment.customer.postalCode')}:
|
||||||
|
</span>
|
||||||
<span>{tenant.postalCode}</span>
|
<span>{tenant.postalCode}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<FaMoneyBillWave className="w-4 h-4 text-gray-500" />
|
<FaMoneyBillWave className="w-4 h-4 text-gray-500" />
|
||||||
<span className="font-medium">Vergi Dairesi:</span>
|
<span className="font-medium">
|
||||||
|
{translate('::Public.payment.customer.taxOffice')}:
|
||||||
|
</span>
|
||||||
<span>{tenant.taxOffice}</span>
|
<span>{tenant.taxOffice}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<FaDollarSign className="w-4 h-4 text-gray-500" />
|
<FaDollarSign className="w-4 h-4 text-gray-500" />
|
||||||
<span className="font-medium">Vergi No:</span>
|
<span className="font-medium">
|
||||||
|
{translate('::Public.payment.customer.taxNumber')}:
|
||||||
|
</span>
|
||||||
<span>{tenant.vknTckn}</span>
|
<span>{tenant.vknTckn}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{tenant.reference && (
|
{tenant.reference && (
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<FaUserPlus className="w-4 h-4 text-gray-500" />
|
<FaUserPlus className="w-4 h-4 text-gray-500" />
|
||||||
<span className="font-medium">Referans:</span>
|
<span className="font-medium">
|
||||||
|
{translate('::Public.payment.customer.reference')}:
|
||||||
|
</span>
|
||||||
<span>{tenant.reference}</span>
|
<span>{tenant.reference}</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
@ -221,7 +252,8 @@ export const PaymentForm: React.FC<PaymentFormProps> = ({
|
||||||
{/* 1. Sütun: Ödeme Yöntemi */}
|
{/* 1. Sütun: Ödeme Yöntemi */}
|
||||||
<div className="bg-white rounded-xl shadow border p-6">
|
<div className="bg-white rounded-xl shadow border p-6">
|
||||||
<h2 className="text-lg font-semibold mb-4 flex items-center">
|
<h2 className="text-lg font-semibold mb-4 flex items-center">
|
||||||
<FaLock className="w-5 h-5 text-green-600 mr-2" /> Ödeme Yöntemi
|
<FaLock className="w-5 h-5 text-green-600 mr-2" />{' '}
|
||||||
|
{translate('::Public.payment.method.title')}
|
||||||
</h2>
|
</h2>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
{paymentMethods.map((method) => (
|
{paymentMethods.map((method) => (
|
||||||
|
|
@ -245,7 +277,9 @@ export const PaymentForm: React.FC<PaymentFormProps> = ({
|
||||||
<div>
|
<div>
|
||||||
<div className="font-medium text-gray-900">{method.name}</div>
|
<div className="font-medium text-gray-900">{method.name}</div>
|
||||||
<div className="text-sm text-gray-600">
|
<div className="text-sm text-gray-600">
|
||||||
{method.id === 'credit-card' ? 'Taksit seçenekleri mevcut' : 'Komisyon yok'}
|
{method.id === 'credit-card'
|
||||||
|
? translate('::Public.payment.method.installmentsAvailable')
|
||||||
|
: translate('::Public.payment.method.noCommission')}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
|
|
@ -256,7 +290,9 @@ export const PaymentForm: React.FC<PaymentFormProps> = ({
|
||||||
{/* Taksit Seçenekleri */}
|
{/* Taksit Seçenekleri */}
|
||||||
{selectedPaymentMethod === 'credit-card' && (
|
{selectedPaymentMethod === 'credit-card' && (
|
||||||
<div className="bg-white rounded-xl shadow border p-4">
|
<div className="bg-white rounded-xl shadow border p-4">
|
||||||
<h3 className="text-md font-medium text-gray-800 mb-2">Taksit Seçenekleri</h3>
|
<h3 className="text-md font-medium text-gray-800 mb-2">
|
||||||
|
{translate('::Public.payment.installments.title')}
|
||||||
|
</h3>
|
||||||
<div className="grid grid-cols-2 md:grid-cols-3 gap-3">
|
<div className="grid grid-cols-2 md:grid-cols-3 gap-3">
|
||||||
{installmentOptions.map((option) => (
|
{installmentOptions.map((option) => (
|
||||||
<label
|
<label
|
||||||
|
|
@ -277,13 +313,15 @@ export const PaymentForm: React.FC<PaymentFormProps> = ({
|
||||||
/>
|
/>
|
||||||
<div className="font-semibold text-base mb-1">{option.name}</div>
|
<div className="font-semibold text-base mb-1">{option.name}</div>
|
||||||
<div className="text-gray-500 mb-1">
|
<div className="text-gray-500 mb-1">
|
||||||
Komisyon:{' '}
|
{translate('::Public.payment.installments.commission')}{' '}
|
||||||
<span className="font-semibold">
|
<span className="font-semibold">
|
||||||
%{(option.commission * 100).toFixed(1)}
|
%{(option.commission * 100).toFixed(1)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-blue-700 font-bold mb-1">
|
<div className="text-blue-700 font-bold mb-1">
|
||||||
{option.id > 1 ? `${option.id} x aylık` : 'Tek ödeme'}
|
{option.id > 1
|
||||||
|
? `${option.id} ${translate('::Public.payment.installments.monthly')}`
|
||||||
|
: translate('::Public.payment.installments.single')}
|
||||||
</div>
|
</div>
|
||||||
<div className="font-extrabold text-lg text-gray-900 mt-1">
|
<div className="font-extrabold text-lg text-gray-900 mt-1">
|
||||||
{formatPrice(
|
{formatPrice(
|
||||||
|
|
@ -302,14 +340,16 @@ export const PaymentForm: React.FC<PaymentFormProps> = ({
|
||||||
{/* Kart Bilgileri */}
|
{/* Kart Bilgileri */}
|
||||||
{selectedPaymentMethod !== 'bank-transfer' && (
|
{selectedPaymentMethod !== 'bank-transfer' && (
|
||||||
<div className="bg-white rounded-xl shadow border p-6 space-y-3">
|
<div className="bg-white rounded-xl shadow border p-6 space-y-3">
|
||||||
<h3 className="text-md font-medium text-gray-800 mb-3">Kart Bilgileri</h3>
|
<h3 className="text-md font-medium text-gray-800 mb-3">
|
||||||
|
{translate('::Public.payment.card.title')}
|
||||||
|
</h3>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
required
|
required
|
||||||
value={paymentData.cardName}
|
value={paymentData.cardName}
|
||||||
onChange={(e) => handleInputChange('cardName', e.target.value)}
|
onChange={(e) => handleInputChange('cardName', e.target.value)}
|
||||||
className="w-full px-4 py-2 border border-gray-300 rounded-lg"
|
className="w-full px-4 py-2 border border-gray-300 rounded-lg"
|
||||||
placeholder="Kart Üzerindeki İsim"
|
placeholder={translate('::Public.payment.card.name')}
|
||||||
/>
|
/>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
|
|
@ -317,7 +357,7 @@ export const PaymentForm: React.FC<PaymentFormProps> = ({
|
||||||
value={paymentData.cardNumber}
|
value={paymentData.cardNumber}
|
||||||
onChange={(e) => handleInputChange('cardNumber', e.target.value)}
|
onChange={(e) => handleInputChange('cardNumber', e.target.value)}
|
||||||
className="w-full px-4 py-2 border border-gray-300 rounded-lg"
|
className="w-full px-4 py-2 border border-gray-300 rounded-lg"
|
||||||
placeholder="Kart Numarası"
|
placeholder={translate('::Public.payment.card.number')}
|
||||||
maxLength={19}
|
maxLength={19}
|
||||||
/>
|
/>
|
||||||
<div className="grid grid-cols-2 gap-3">
|
<div className="grid grid-cols-2 gap-3">
|
||||||
|
|
@ -345,7 +385,9 @@ export const PaymentForm: React.FC<PaymentFormProps> = ({
|
||||||
|
|
||||||
{/* Sipariş Özeti ve Butonlar */}
|
{/* Sipariş Özeti ve Butonlar */}
|
||||||
<div className="bg-white rounded-xl shadow border p-6">
|
<div className="bg-white rounded-xl shadow border p-6">
|
||||||
<h3 className="text-lg font-semibold text-gray-900 mb-4">Sipariş Özeti</h3>
|
<h3 className="text-lg font-semibold text-gray-900 mb-4">
|
||||||
|
{translate('::Public.payment.summary.title')}
|
||||||
|
</h3>
|
||||||
|
|
||||||
<div className="space-y-4 mb-4">
|
<div className="space-y-4 mb-4">
|
||||||
{cartState.items.map((item, index) => (
|
{cartState.items.map((item, index) => (
|
||||||
|
|
@ -370,18 +412,18 @@ export const PaymentForm: React.FC<PaymentFormProps> = ({
|
||||||
|
|
||||||
<div className="space-y-1 text-sm border-t border-gray-200 pt-4 text-gray-600">
|
<div className="space-y-1 text-sm border-t border-gray-200 pt-4 text-gray-600">
|
||||||
<div className="flex justify-between">
|
<div className="flex justify-between">
|
||||||
<span>Ara Toplam:</span>
|
<span>{translate('::Public.payment.summary.subtotal')}</span>
|
||||||
<span>{formatPrice(cartState.total)}</span>
|
<span>{formatPrice(cartState.total)}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-between">
|
<div className="flex justify-between">
|
||||||
<span>Komisyon:</span>
|
<span>{translate('::Public.payment.summary.commission')}</span>
|
||||||
<span>{formatPrice(commission)}</span>
|
<span>{formatPrice(commission)}</span>
|
||||||
</div>
|
</div>
|
||||||
{selectedPaymentMethod === 'credit-card' &&
|
{selectedPaymentMethod === 'credit-card' &&
|
||||||
selectedInstallment?.id &&
|
selectedInstallment?.id &&
|
||||||
selectedInstallment.id > 1 && (
|
selectedInstallment.id > 1 && (
|
||||||
<div className="flex justify-between text-blue-600">
|
<div className="flex justify-between text-blue-600">
|
||||||
<span>Aylık Taksit:</span>
|
<span>{translate('::Public.payment.summary.monthlyInstallment')}: </span>
|
||||||
<span>
|
<span>
|
||||||
{formatPrice(finalTotal / selectedInstallment.id)} x{' '}
|
{formatPrice(finalTotal / selectedInstallment.id)} x{' '}
|
||||||
{selectedInstallment.id}
|
{selectedInstallment.id}
|
||||||
|
|
@ -389,7 +431,7 @@ export const PaymentForm: React.FC<PaymentFormProps> = ({
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="flex justify-between text-base font-bold pt-2 text-gray-900">
|
<div className="flex justify-between text-base font-bold pt-2 text-gray-900">
|
||||||
<span>Toplam:</span>
|
<span>{translate('::Public.payment.summary.total')}</span>
|
||||||
<span className="text-blue-600">{formatPrice(finalTotal)}</span>
|
<span className="text-blue-600">{formatPrice(finalTotal)}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -402,14 +444,16 @@ export const PaymentForm: React.FC<PaymentFormProps> = ({
|
||||||
className="flex items-center px-6 py-3 border border-gray-300 text-gray-700 rounded-lg"
|
className="flex items-center px-6 py-3 border border-gray-300 text-gray-700 rounded-lg"
|
||||||
>
|
>
|
||||||
<FaArrowLeft className="w-4 h-4 mr-2" />
|
<FaArrowLeft className="w-4 h-4 mr-2" />
|
||||||
Geri
|
{translate('::Public.payment.buttons.back')}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
className="flex items-center justify-center px-6 py-3 bg-green-600 text-white rounded-lg"
|
className="flex items-center justify-center px-6 py-3 bg-green-600 text-white rounded-lg"
|
||||||
>
|
>
|
||||||
<FaCreditCard className="w-5 h-5 mr-2" />
|
<FaCreditCard className="w-5 h-5 mr-2" />
|
||||||
{selectedPaymentMethod === 'bank-transfer' ? 'Siparişi Tamamla' : 'Ödeme Yap'}
|
{selectedPaymentMethod === 'bank-transfer'
|
||||||
|
? translate('::Public.payment.buttons.completeOrder')
|
||||||
|
: translate('::Public.payment.buttons.pay')}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,15 @@
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react'
|
||||||
import { FaPlus, FaMinus } from 'react-icons/fa';
|
import { FaPlus, FaMinus } from 'react-icons/fa'
|
||||||
import { BillingCycle, Product, ProductDto } from '@/proxy/order/models';
|
import { BillingCycle, Product, ProductDto } from '@/proxy/order/models'
|
||||||
import { CartState } from '@/utils/cartUtils';
|
import { CartState } from '@/utils/cartUtils'
|
||||||
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
|
|
||||||
interface ProductCardProps {
|
interface ProductCardProps {
|
||||||
product: ProductDto;
|
product: ProductDto
|
||||||
globalBillingCycle: BillingCycle;
|
globalBillingCycle: BillingCycle
|
||||||
globalPeriod: number;
|
globalPeriod: number
|
||||||
addItem: (product: ProductDto, quantity: number, billingCycle: BillingCycle) => void;
|
addItem: (product: ProductDto, quantity: number, billingCycle: BillingCycle) => void
|
||||||
cartState: CartState;
|
cartState: CartState
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ProductCard: React.FC<ProductCardProps> = ({
|
export const ProductCard: React.FC<ProductCardProps> = ({
|
||||||
|
|
@ -16,66 +17,75 @@ export const ProductCard: React.FC<ProductCardProps> = ({
|
||||||
globalBillingCycle,
|
globalBillingCycle,
|
||||||
globalPeriod,
|
globalPeriod,
|
||||||
addItem,
|
addItem,
|
||||||
cartState
|
cartState,
|
||||||
}) => {
|
}) => {
|
||||||
const [quantity, setQuantity] = useState(1);
|
const [quantity, setQuantity] = useState(1)
|
||||||
|
const { translate } = useLocalization()
|
||||||
|
|
||||||
// Direct check with current cart state
|
// Direct check with current cart state
|
||||||
const isInCart = cartState.items.some(
|
const isInCart = cartState.items.some(
|
||||||
item => item.product.id === product.id && item.billingCycle === globalBillingCycle
|
(item) => item.product.id === product.id && item.billingCycle === globalBillingCycle,
|
||||||
);
|
)
|
||||||
|
|
||||||
const formatPrice = (price: number) => {
|
const formatPrice = (price: number) => {
|
||||||
return new Intl.NumberFormat('tr-TR', {
|
return new Intl.NumberFormat('tr-TR', {
|
||||||
style: 'currency',
|
style: 'currency',
|
||||||
currency: 'TRY',
|
currency: 'TRY',
|
||||||
minimumFractionDigits: 0
|
minimumFractionDigits: 0,
|
||||||
}).format(price);
|
}).format(price)
|
||||||
};
|
}
|
||||||
|
|
||||||
const getCurrentPrice = () => {
|
const getCurrentPrice = () => {
|
||||||
return globalBillingCycle === 'monthly' ? product.monthlyPrice! : product.yearlyPrice!;
|
return globalBillingCycle === 'monthly' ? product.monthlyPrice! : product.yearlyPrice!
|
||||||
};
|
}
|
||||||
|
|
||||||
const getTotalPrice = () => {
|
const getTotalPrice = () => {
|
||||||
return getCurrentPrice() * quantity * globalPeriod;
|
return getCurrentPrice() * quantity * globalPeriod
|
||||||
};
|
}
|
||||||
|
|
||||||
const handleAddToCart = () => {
|
const handleAddToCart = () => {
|
||||||
// Non-quantity products should not be added if already in cart
|
// Non-quantity products should not be added if already in cart
|
||||||
if (!product.isQuantityBased && isInCart) {
|
if (!product.isQuantityBased && isInCart) {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// For non-quantity products, always use quantity 1
|
// For non-quantity products, always use quantity 1
|
||||||
const quantityToAdd = !product.isQuantityBased ? 1 : quantity;
|
const quantityToAdd = !product.isQuantityBased ? 1 : quantity
|
||||||
addItem(product, quantityToAdd, globalBillingCycle);
|
addItem(product, quantityToAdd, globalBillingCycle)
|
||||||
setQuantity(1);
|
setQuantity(1)
|
||||||
};
|
}
|
||||||
|
|
||||||
const getUnitText = () => {
|
const getUnitText = () => {
|
||||||
switch (product.unit) {
|
switch (product.unit) {
|
||||||
case 'monthly': return globalBillingCycle === 'monthly' ? '/ Ay' : '/ Yıl';
|
case 'monthly':
|
||||||
case 'yearly': return '/ Yıl';
|
return globalBillingCycle === 'monthly'
|
||||||
default: return '';
|
? translate('::Public.products.price.perMonthSuffix')
|
||||||
|
: translate('::Public.products.price.perYearSuffix')
|
||||||
|
case 'yearly':
|
||||||
|
return translate('::Public.products.price.perYearSuffix')
|
||||||
|
default:
|
||||||
|
return ''
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
const getPeriodText = () => {
|
const getPeriodText = () => {
|
||||||
const periodText = globalBillingCycle === 'monthly' ? 'Ay' : 'Yıl';
|
const periodText =
|
||||||
return globalPeriod > 1 ? ` (${globalPeriod} ${periodText})` : '';
|
globalBillingCycle === 'monthly'
|
||||||
};
|
? translate('::Public.products.period.month')
|
||||||
|
: translate('::Public.products.period.year')
|
||||||
|
return globalPeriod > 1 ? ` (${globalPeriod} ${periodText})` : ''
|
||||||
|
}
|
||||||
|
|
||||||
// Check if product has valid price for current billing cycle
|
// Check if product has valid price for current billing cycle
|
||||||
const hasValidPrice = () => {
|
const hasValidPrice = () => {
|
||||||
if (globalBillingCycle === 'monthly' && !product.monthlyPrice) return false;
|
if (globalBillingCycle === 'monthly' && !product.monthlyPrice) return false
|
||||||
if (globalBillingCycle === 'yearly' && !product.yearlyPrice) return false;
|
if (globalBillingCycle === 'yearly' && !product.yearlyPrice) return false
|
||||||
return true;
|
return true
|
||||||
};
|
}
|
||||||
|
|
||||||
// If product doesn't have valid price, don't render it at all
|
// If product doesn't have valid price, don't render it at all
|
||||||
if (!hasValidPrice()) {
|
if (!hasValidPrice()) {
|
||||||
return null;
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -93,23 +103,21 @@ export const ProductCard: React.FC<ProductCardProps> = ({
|
||||||
<div className="p-6 flex flex-col flex-1">
|
<div className="p-6 flex flex-col flex-1">
|
||||||
<div className="mb-2">
|
<div className="mb-2">
|
||||||
<span className="inline-block px-3 py-1 bg-blue-100 text-blue-800 text-sm font-medium rounded-full">
|
<span className="inline-block px-3 py-1 bg-blue-100 text-blue-800 text-sm font-medium rounded-full">
|
||||||
{product.category}
|
{translate('::' + product.category)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h3 className="text-lg font-semibold text-gray-900 mb-2 line-clamp-2">
|
<h3 className="text-lg font-semibold text-gray-900 mb-2 line-clamp-2">{translate('::' + product.name)}</h3>
|
||||||
{product.name}
|
|
||||||
</h3>
|
|
||||||
|
|
||||||
<p className="text-gray-600 text-sm mb-4 line-clamp-3">
|
<p className="text-gray-600 text-sm mb-4 line-clamp-3">{translate('::' + product.description)}</p>
|
||||||
{product.description}
|
|
||||||
</p>
|
|
||||||
|
|
||||||
{/* Quantity and Yearly Savings above price */}
|
{/* Quantity and Yearly Savings above price */}
|
||||||
<div className="mb-4 space-y-3">
|
<div className="mb-4 space-y-3">
|
||||||
{product.isQuantityBased && (
|
{product.isQuantityBased && (
|
||||||
<div className="flex items-center space-x-3">
|
<div className="flex items-center space-x-3">
|
||||||
<span className="text-sm font-medium text-gray-700">Adet:</span>
|
<span className="text-sm font-medium text-gray-700">
|
||||||
|
{translate('::Public.products.quantity')}
|
||||||
|
</span>
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<button
|
<button
|
||||||
onClick={() => setQuantity(Math.max(1, quantity - 1))}
|
onClick={() => setQuantity(Math.max(1, quantity - 1))}
|
||||||
|
|
@ -130,7 +138,9 @@ export const ProductCard: React.FC<ProductCardProps> = ({
|
||||||
|
|
||||||
{globalBillingCycle === 'yearly' && product.monthlyPrice && product.yearlyPrice && (
|
{globalBillingCycle === 'yearly' && product.monthlyPrice && product.yearlyPrice && (
|
||||||
<div className="text-sm text-emerald-600 font-medium">
|
<div className="text-sm text-emerald-600 font-medium">
|
||||||
Yıllık ile %{Math.round((1 - (product.yearlyPrice / (product.monthlyPrice * 12))) * 100)} tasarruf
|
{translate('::Public.products.savings.yearly', {
|
||||||
|
percent: Math.round((1 - product.yearlyPrice / (product.monthlyPrice * 12)) * 100),
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -140,23 +150,19 @@ export const ProductCard: React.FC<ProductCardProps> = ({
|
||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
<div className="text-2xl font-bold text-gray-900">
|
<div className="text-2xl font-bold text-gray-900">
|
||||||
{formatPrice(getCurrentPrice())}
|
{formatPrice(getCurrentPrice())}
|
||||||
<span className="text-sm font-normal text-gray-500 ml-1">
|
<span className="text-sm font-normal text-gray-500 ml-1">{getUnitText()}</span>
|
||||||
{getUnitText()}
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
{globalPeriod > 1 && (
|
{globalPeriod > 1 && (
|
||||||
<div className="text-lg font-semibold text-blue-600 mt-1">
|
<div className="text-lg font-semibold text-blue-600 mt-1">
|
||||||
Toplam: {formatPrice(getTotalPrice())}
|
{translate('::Public.products.total')} {formatPrice(getTotalPrice())}
|
||||||
<span className="text-sm font-normal text-gray-500 ml-1">
|
<span className="text-sm font-normal text-gray-500 ml-1">{getPeriodText()}</span>
|
||||||
{getPeriodText()}
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{(() => {
|
{(() => {
|
||||||
const isNonQuantityProduct = !product.isQuantityBased;
|
const isNonQuantityProduct = !product.isQuantityBased
|
||||||
const isDisabled = isNonQuantityProduct && isInCart;
|
const isDisabled = isNonQuantityProduct && isInCart
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
|
|
@ -168,12 +174,12 @@ export const ProductCard: React.FC<ProductCardProps> = ({
|
||||||
: 'bg-blue-600 hover:bg-blue-700 text-white hover:scale-[1.02] active:scale-[0.98]'
|
: 'bg-blue-600 hover:bg-blue-700 text-white hover:scale-[1.02] active:scale-[0.98]'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{isDisabled ? 'Sepette Mevcut' : 'Sepete Ekle'}
|
{isDisabled ? translate('::Public.products.inCart') : translate('::Public.products.addToCart')}
|
||||||
</button>
|
</button>
|
||||||
);
|
)
|
||||||
})()}
|
})()}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import { ProductCard } from './ProductCard'
|
||||||
import { addItemToCart, CartState } from '@/utils/cartUtils'
|
import { addItemToCart, CartState } from '@/utils/cartUtils'
|
||||||
import { BillingCycle, ProductDto } from '@/proxy/order/models'
|
import { BillingCycle, ProductDto } from '@/proxy/order/models'
|
||||||
import { OrderService } from '@/services/order.service'
|
import { OrderService } from '@/services/order.service'
|
||||||
|
import { useLocalization } from '@/utils/hooks/useLocalization';
|
||||||
|
|
||||||
interface ProductCatalogProps {
|
interface ProductCatalogProps {
|
||||||
searchQuery: string
|
searchQuery: string
|
||||||
|
|
@ -18,6 +19,8 @@ export const ProductCatalog: React.FC<ProductCatalogProps> = ({
|
||||||
cartState,
|
cartState,
|
||||||
setCartState,
|
setCartState,
|
||||||
}) => {
|
}) => {
|
||||||
|
const { translate } = useLocalization()
|
||||||
|
|
||||||
const [selectedCategory, setSelectedCategory] = useState<string>('all')
|
const [selectedCategory, setSelectedCategory] = useState<string>('all')
|
||||||
const [products, setProducts] = useState<ProductDto[]>([])
|
const [products, setProducts] = useState<ProductDto[]>([])
|
||||||
const [loading, setLoading] = useState<boolean>(true)
|
const [loading, setLoading] = useState<boolean>(true)
|
||||||
|
|
@ -87,7 +90,7 @@ export const ProductCatalog: React.FC<ProductCatalogProps> = ({
|
||||||
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-6 sticky top-40">
|
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-6 sticky top-40">
|
||||||
<div className="flex items-center space-x-2 mb-4">
|
<div className="flex items-center space-x-2 mb-4">
|
||||||
<FaFilter className="w-5 h-5 text-gray-600" />
|
<FaFilter className="w-5 h-5 text-gray-600" />
|
||||||
<h3 className="font-semibold text-gray-900">Kategoriler</h3>
|
<h3 className="font-semibold text-gray-900">{translate('::Public.products.categories')}</h3>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
{categories.map((category) => (
|
{categories.map((category) => (
|
||||||
|
|
@ -100,7 +103,7 @@ export const ProductCatalog: React.FC<ProductCatalogProps> = ({
|
||||||
: 'text-gray-600 hover:bg-gray-50 hover:text-gray-900'
|
: 'text-gray-600 hover:bg-gray-50 hover:text-gray-900'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<span>{category === 'all' ? 'Tüm Ürünler' : category}</span>
|
<span>{category === 'all' ? translate('::Public.products.categories.all') : translate('::' + category)}</span>
|
||||||
<span
|
<span
|
||||||
className={`text-xs px-2 py-1 rounded-full ${
|
className={`text-xs px-2 py-1 rounded-full ${
|
||||||
selectedCategory === category
|
selectedCategory === category
|
||||||
|
|
@ -118,13 +121,13 @@ export const ProductCatalog: React.FC<ProductCatalogProps> = ({
|
||||||
<div className="mt-6">
|
<div className="mt-6">
|
||||||
<div className="flex items-center space-x-2 mb-3">
|
<div className="flex items-center space-x-2 mb-3">
|
||||||
<FaSearch className="w-5 h-5 text-gray-600" />
|
<FaSearch className="w-5 h-5 text-gray-600" />
|
||||||
<h3 className="font-semibold text-gray-900">Arama</h3>
|
<h3 className="font-semibold text-gray-900">{translate('::Public.products.search.title')}</h3>
|
||||||
</div>
|
</div>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<FaSearch className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 w-4 h-4" />
|
<FaSearch className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 w-4 h-4" />
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Ürün ara..."
|
placeholder={translate('::Public.products.search.placeholder')}
|
||||||
value={searchQuery}
|
value={searchQuery}
|
||||||
onChange={(e) => onSearchChange(e.target.value)}
|
onChange={(e) => onSearchChange(e.target.value)}
|
||||||
className="w-full pl-10 pr-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all"
|
className="w-full pl-10 pr-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all"
|
||||||
|
|
@ -136,7 +139,7 @@ export const ProductCatalog: React.FC<ProductCatalogProps> = ({
|
||||||
|
|
||||||
<main className="flex-1">
|
<main className="flex-1">
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<div className="text-center py-12 text-gray-500">Yükleniyor...</div>
|
<div className="text-center py-12 text-gray-500">{translate('::Public.products.loading')}</div>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-6">
|
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-6">
|
||||||
|
|
@ -156,8 +159,8 @@ export const ProductCatalog: React.FC<ProductCatalogProps> = ({
|
||||||
<div className="text-gray-400 mb-2">
|
<div className="text-gray-400 mb-2">
|
||||||
<FaFilter className="w-12 h-12 mx-auto" />
|
<FaFilter className="w-12 h-12 mx-auto" />
|
||||||
</div>
|
</div>
|
||||||
<h3 className="text-lg font-medium text-gray-900 mb-2">Ürün bulunamadı</h3>
|
<h3 className="text-lg font-medium text-gray-900 mb-2">{translate('::Public.products.empty.title')}</h3>
|
||||||
<p className="text-gray-600">Arama kriterlerinizi değiştirmeyi deneyin.</p>
|
<p className="text-gray-600">{translate('::Public.products.empty.description')}</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ import {
|
||||||
} from 'react-icons/fa'
|
} from 'react-icons/fa'
|
||||||
import React, { useState } from 'react'
|
import React, { useState } from 'react'
|
||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate } from 'react-router-dom'
|
||||||
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
|
|
||||||
interface TenantFormProps {
|
interface TenantFormProps {
|
||||||
onSubmit: (tenant: CustomTenantDto) => void
|
onSubmit: (tenant: CustomTenantDto) => void
|
||||||
|
|
@ -27,6 +28,7 @@ export const TenantForm: React.FC<TenantFormProps> = ({ onSubmit }) => {
|
||||||
const [isExisting, setIsExisting] = useState<boolean>(true)
|
const [isExisting, setIsExisting] = useState<boolean>(true)
|
||||||
const [formData, setFormData] = useState<Partial<CustomTenantDto>>({})
|
const [formData, setFormData] = useState<Partial<CustomTenantDto>>({})
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
|
const { translate } = useLocalization()
|
||||||
|
|
||||||
const handleSubmit = (e: React.FormEvent) => {
|
const handleSubmit = (e: React.FormEvent) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|
@ -73,7 +75,8 @@ export const TenantForm: React.FC<TenantFormProps> = ({ onSubmit }) => {
|
||||||
<div className="w-full lg:w-1/3 bg-white rounded-xl shadow-lg border border-gray-200 p-6">
|
<div className="w-full lg:w-1/3 bg-white rounded-xl shadow-lg border border-gray-200 p-6">
|
||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
<h2 className="text-lg font-semibold mb-4 flex items-center">
|
<h2 className="text-lg font-semibold mb-4 flex items-center">
|
||||||
<FaUser className="w-5 h-5 text-green-600 mr-2" /> Müşteri Bilgileri
|
<FaUser className="w-5 h-5 text-green-600 mr-2" />{' '}
|
||||||
|
{translate('::Public.products.tenantForm.customerInfo')}
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -87,8 +90,12 @@ export const TenantForm: React.FC<TenantFormProps> = ({ onSubmit }) => {
|
||||||
: 'border-gray-200 hover:border-blue-300'
|
: 'border-gray-200 hover:border-blue-300'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div className="font-semibold text-gray-900 mb-2">Mevcut Müşteri</div>
|
<div className="font-semibold text-gray-900 mb-2">
|
||||||
<div className="text-sm text-gray-600">Kurum kodunuz ile giriş yapın</div>
|
{translate('::Public.products.tenantForm.existing.title')}
|
||||||
|
</div>
|
||||||
|
<div className="text-sm text-gray-600">
|
||||||
|
{translate('::Public.products.tenantForm.existing.desc')}
|
||||||
|
</div>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
|
|
@ -99,8 +106,12 @@ export const TenantForm: React.FC<TenantFormProps> = ({ onSubmit }) => {
|
||||||
: 'border-gray-200 hover:border-blue-300'
|
: 'border-gray-200 hover:border-blue-300'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div className="font-semibold text-gray-900 mb-2">Yeni Müşteri</div>
|
<div className="font-semibold text-gray-900 mb-2">
|
||||||
<div className="text-sm text-gray-600">Kayıt olun ve hemen başlayın</div>
|
{translate('::Public.products.tenantForm.new.title')}
|
||||||
|
</div>
|
||||||
|
<div className="text-sm text-gray-600">
|
||||||
|
{translate('::Public.products.tenantForm.new.desc')}
|
||||||
|
</div>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -111,7 +122,9 @@ export const TenantForm: React.FC<TenantFormProps> = ({ onSubmit }) => {
|
||||||
<form onSubmit={handleSubmit} className="space-y-6">
|
<form onSubmit={handleSubmit} className="space-y-6">
|
||||||
{isExisting ? (
|
{isExisting ? (
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-2">Kurum Kodu *</label>
|
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||||
|
{translate('::Public.products.tenantForm.orgCode')}
|
||||||
|
</label>
|
||||||
<div className="relative flex flex-col sm:flex-row sm:items-stretch">
|
<div className="relative flex flex-col sm:flex-row sm:items-stretch">
|
||||||
<div className="relative w-full">
|
<div className="relative w-full">
|
||||||
<FaBuilding className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" />
|
<FaBuilding className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" />
|
||||||
|
|
@ -134,10 +147,10 @@ export const TenantForm: React.FC<TenantFormProps> = ({ onSubmit }) => {
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={getTenantInfo}
|
onClick={getTenantInfo}
|
||||||
className="flex items-center justify-center gap-2 px-4 py-3 bg-blue-600 text-white rounded-lg sm:rounded-r-lg sm:rounded-l-none hover:bg-blue-700 transition-colors min-w-[148px]"
|
className="flex items-center justify-center gap-2 px-4 py-3 bg-blue-600 text-white rounded-lg sm:rounded-r-lg sm:rounded-l-none hover:bg-blue-700 transition-colors min-w-[180px]"
|
||||||
>
|
>
|
||||||
<FaSearch className="w-4 h-4" />
|
<FaSearch className="w-4 h-4" />
|
||||||
Kurumu Bul
|
{translate('::Public.products.tenantForm.searchOrg')}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -145,76 +158,100 @@ export const TenantForm: React.FC<TenantFormProps> = ({ onSubmit }) => {
|
||||||
<div className="grid grid-cols-1 gap-y-3 text-sm text-gray-700 p-3">
|
<div className="grid grid-cols-1 gap-y-3 text-sm text-gray-700 p-3">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<FaUser className="w-4 h-4 text-gray-500" />
|
<FaUser className="w-4 h-4 text-gray-500" />
|
||||||
<span className="font-medium">Kurucu:</span>
|
<span className="font-medium">
|
||||||
|
{translate('::Public.products.tenantForm.founder')}
|
||||||
|
</span>
|
||||||
<span>{formData.founder}</span>
|
<span>{formData.founder}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<FaBuilding className="w-4 h-4 text-gray-500" />
|
<FaBuilding className="w-4 h-4 text-gray-500" />
|
||||||
<span className="font-medium">Şirket:</span>
|
<span className="font-medium">
|
||||||
|
{translate('::Public.products.tenantForm.company')}
|
||||||
|
</span>
|
||||||
<span>{formData.institutionName}</span>
|
<span>{formData.institutionName}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<FaEnvelope className="w-4 h-4 text-gray-500" />
|
<FaEnvelope className="w-4 h-4 text-gray-500" />
|
||||||
<span className="font-medium">E-posta:</span>
|
<span className="font-medium">
|
||||||
|
{translate('::Public.products.tenantForm.email')}:
|
||||||
|
</span>
|
||||||
<span>{formData.email}</span>
|
<span>{formData.email}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<FaPhone className="w-4 h-4 text-gray-500" />
|
<FaPhone className="w-4 h-4 text-gray-500" />
|
||||||
<span className="font-medium">Mobile:</span>
|
<span className="font-medium">
|
||||||
|
{translate('::Public.products.tenantForm.mobile')}:
|
||||||
|
</span>
|
||||||
<span>{formData.mobile}</span>
|
<span>{formData.mobile}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-start gap-2">
|
<div className="flex items-start gap-2">
|
||||||
<FaMapPin className="w-4 h-4 text-gray-500 mt-0.5" />
|
<FaMapPin className="w-4 h-4 text-gray-500 mt-0.5" />
|
||||||
<div>
|
<div>
|
||||||
<span className="font-medium">Adres:</span>
|
<span className="font-medium">
|
||||||
|
{translate('::Public.products.tenantForm.address')}:
|
||||||
|
</span>
|
||||||
<div>{formData.address}</div>
|
<div>{formData.address}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<FaGlobe className="w-4 h-4 text-gray-500" />
|
<FaGlobe className="w-4 h-4 text-gray-500" />
|
||||||
<span className="font-medium">Ülke:</span>
|
<span className="font-medium">
|
||||||
|
{translate('::Public.products.tenantForm.country')}:
|
||||||
|
</span>
|
||||||
<span>{formData.country}</span>
|
<span>{formData.country}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<FaGlobe className="w-4 h-4 text-gray-500" />
|
<FaGlobe className="w-4 h-4 text-gray-500" />
|
||||||
<span className="font-medium">Şehir:</span>
|
<span className="font-medium">
|
||||||
|
{translate('::Public.products.tenantForm.city')}:
|
||||||
|
</span>
|
||||||
<span>{formData.city}</span>
|
<span>{formData.city}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<FaMap className="w-4 h-4 text-gray-500" />
|
<FaMap className="w-4 h-4 text-gray-500" />
|
||||||
<span className="font-medium">İlçe:</span>
|
<span className="font-medium">
|
||||||
|
{translate('::Public.products.tenantForm.district')}:
|
||||||
|
</span>
|
||||||
<span>{formData.district}</span>
|
<span>{formData.district}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<FaMapPin className="w-4 h-4 text-gray-500" />
|
<FaMapPin className="w-4 h-4 text-gray-500" />
|
||||||
<span className="font-medium">Posta Kodu:</span>
|
<span className="font-medium">
|
||||||
|
{translate('::Public.products.tenantForm.postalCode')}:
|
||||||
|
</span>
|
||||||
<span>{formData.postalCode}</span>
|
<span>{formData.postalCode}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<FaMoneyBillWave className="w-4 h-4 text-gray-500" />
|
<FaMoneyBillWave className="w-4 h-4 text-gray-500" />
|
||||||
<span className="font-medium">Vergi Dairesi:</span>
|
<span className="font-medium">
|
||||||
|
{translate('::Public.products.tenantForm.taxOffice')}:
|
||||||
|
</span>
|
||||||
<span>{formData.taxOffice}</span>
|
<span>{formData.taxOffice}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<FaDollarSign className="w-4 h-4 text-gray-500" />
|
<FaDollarSign className="w-4 h-4 text-gray-500" />
|
||||||
<span className="font-medium">Vergi No:</span>
|
<span className="font-medium">
|
||||||
|
{translate('::Public.products.tenantForm.taxNumber')}:
|
||||||
|
</span>
|
||||||
<span>{formData.vknTckn}</span>
|
<span>{formData.vknTckn}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{formData.reference && (
|
{formData.reference && (
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<FaUserPlus className="w-4 h-4 text-gray-500" />
|
<FaUserPlus className="w-4 h-4 text-gray-500" />
|
||||||
<span className="font-medium">Referans:</span>
|
<span className="font-medium">
|
||||||
|
{translate('::Public.products.tenantForm.reference')}:
|
||||||
|
</span>
|
||||||
<span>{formData.reference}</span>
|
<span>{formData.reference}</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
@ -226,7 +263,7 @@ export const TenantForm: React.FC<TenantFormProps> = ({ onSubmit }) => {
|
||||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-2">
|
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||||
Şirket Adı *
|
{translate('::Public.products.tenantForm.orgName')}
|
||||||
</label>
|
</label>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<FaBuilding className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" />
|
<FaBuilding className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" />
|
||||||
|
|
@ -242,7 +279,7 @@ export const TenantForm: React.FC<TenantFormProps> = ({ onSubmit }) => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="text-sm font-medium text-gray-700">Kurucu *</label>
|
<label className="text-sm font-medium text-gray-700">{translate('::Public.products.tenantForm.founder')}</label>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<FaUser className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" />
|
<FaUser className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" />
|
||||||
<input
|
<input
|
||||||
|
|
@ -259,7 +296,7 @@ export const TenantForm: React.FC<TenantFormProps> = ({ onSubmit }) => {
|
||||||
|
|
||||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||||
<div>
|
<div>
|
||||||
<label className="text-sm font-medium text-gray-700">Telefon *</label>
|
<label className="text-sm font-medium text-gray-700">{translate('::Public.products.tenantForm.phone')}</label>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<FaPhone className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" />
|
<FaPhone className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" />
|
||||||
<input
|
<input
|
||||||
|
|
@ -273,7 +310,7 @@ export const TenantForm: React.FC<TenantFormProps> = ({ onSubmit }) => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="text-sm font-medium text-gray-700">E-posta *</label>
|
<label className="text-sm font-medium text-gray-700">{translate('::Public.products.tenantForm.email')}</label>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<FaEnvelope className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" />
|
<FaEnvelope className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" />
|
||||||
<input
|
<input
|
||||||
|
|
@ -289,7 +326,7 @@ export const TenantForm: React.FC<TenantFormProps> = ({ onSubmit }) => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label className="text-sm font-medium text-gray-700">Adres *</label>
|
<label className="text-sm font-medium text-gray-700">{translate('::Public.products.tenantForm.address')}</label>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<FaMapPin className="absolute left-3 top-3 text-gray-400 w-5 h-5" />
|
<FaMapPin className="absolute left-3 top-3 text-gray-400 w-5 h-5" />
|
||||||
<textarea
|
<textarea
|
||||||
|
|
@ -305,7 +342,7 @@ export const TenantForm: React.FC<TenantFormProps> = ({ onSubmit }) => {
|
||||||
|
|
||||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||||
<div>
|
<div>
|
||||||
<label className="text-sm font-medium text-gray-700">Ülke</label>
|
<label className="text-sm font-medium text-gray-700">{translate('::Public.products.tenantForm.country')}</label>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<FaGlobe className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" />
|
<FaGlobe className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" />
|
||||||
<input
|
<input
|
||||||
|
|
@ -318,7 +355,7 @@ export const TenantForm: React.FC<TenantFormProps> = ({ onSubmit }) => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="text-sm font-medium text-gray-700">Şehir *</label>
|
<label className="text-sm font-medium text-gray-700">{translate('::Public.products.tenantForm.city')}</label>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<FaGlobe className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" />
|
<FaGlobe className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" />
|
||||||
<input
|
<input
|
||||||
|
|
@ -335,7 +372,7 @@ export const TenantForm: React.FC<TenantFormProps> = ({ onSubmit }) => {
|
||||||
|
|
||||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||||
<div>
|
<div>
|
||||||
<label className="text-sm font-medium text-gray-700">İlçe *</label>
|
<label className="text-sm font-medium text-gray-700">{translate('::Public.products.tenantForm.district')}</label>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<FaMapPin className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" />
|
<FaMapPin className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" />
|
||||||
<input
|
<input
|
||||||
|
|
@ -349,7 +386,7 @@ export const TenantForm: React.FC<TenantFormProps> = ({ onSubmit }) => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="text-sm font-medium text-gray-700">Posta Kodu *</label>
|
<label className="text-sm font-medium text-gray-700">{translate('::Public.products.tenantForm.postalCode')}</label>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<FaMapPin className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" />
|
<FaMapPin className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" />
|
||||||
<input
|
<input
|
||||||
|
|
@ -366,7 +403,7 @@ export const TenantForm: React.FC<TenantFormProps> = ({ onSubmit }) => {
|
||||||
|
|
||||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||||
<div>
|
<div>
|
||||||
<label className="text-sm font-medium text-gray-700">Vergi Dairesi *</label>
|
<label className="text-sm font-medium text-gray-700">{translate('::Public.products.tenantForm.taxOffice')}</label>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<FaBuilding className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" />
|
<FaBuilding className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" />
|
||||||
<input
|
<input
|
||||||
|
|
@ -380,7 +417,7 @@ export const TenantForm: React.FC<TenantFormProps> = ({ onSubmit }) => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="text-sm font-medium text-gray-700">Vergi No *</label>
|
<label className="text-sm font-medium text-gray-700">{translate('::Public.products.tenantForm.taxNumber')}</label>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<FaDollarSign className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" />
|
<FaDollarSign className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" />
|
||||||
<input
|
<input
|
||||||
|
|
@ -396,12 +433,12 @@ export const TenantForm: React.FC<TenantFormProps> = ({ onSubmit }) => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label className="text-sm font-medium text-gray-700">Referans</label>
|
<label className="text-sm font-medium text-gray-700">{translate('::Public.products.tenantForm.reference')}</label>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<FaUserPlus className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" />
|
<FaUserPlus className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 w-5 h-5" />
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Referans kişi veya kodu"
|
placeholder={translate('::Public.products.tenantForm.reference')}
|
||||||
value={formData.reference || ''}
|
value={formData.reference || ''}
|
||||||
onChange={(e) => handleInputChange('reference', e.target.value)}
|
onChange={(e) => handleInputChange('reference', e.target.value)}
|
||||||
className="w-full pl-10 pr-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
className="w-full pl-10 pr-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
||||||
|
|
@ -418,14 +455,14 @@ export const TenantForm: React.FC<TenantFormProps> = ({ onSubmit }) => {
|
||||||
className="flex items-center px-6 py-3 border border-gray-300 text-gray-700 rounded-lg"
|
className="flex items-center px-6 py-3 border border-gray-300 text-gray-700 rounded-lg"
|
||||||
>
|
>
|
||||||
<FaArrowLeft className="w-4 h-4 mr-2" />
|
<FaArrowLeft className="w-4 h-4 mr-2" />
|
||||||
Geri
|
{translate('::Public.products.tenantForm.buttons.back')}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
className="flex items-center justify-center px-6 py-3 bg-green-600 text-white rounded-lg"
|
className="flex items-center justify-center px-6 py-3 bg-green-600 text-white rounded-lg"
|
||||||
>
|
>
|
||||||
<FaArrowRight className="w-5 h-5 mr-2" />
|
<FaArrowRight className="w-5 h-5 mr-2" />
|
||||||
Devam Et
|
{translate('::Public.products.tenantForm.buttons.continue')}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
||||||
|
|
@ -62,28 +62,26 @@ const _LanguageSelector = ({ className }: CommonProps) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tooltip title={translate('::App.Languages.Language')}>
|
<Dropdown renderTitle={selectedLanguage} placement="bottom-end">
|
||||||
<Dropdown renderTitle={selectedLanguage} placement="bottom-end">
|
{languageList?.map((lang) => (
|
||||||
{languageList?.map((lang) => (
|
<Dropdown.Item
|
||||||
<Dropdown.Item
|
key={lang.cultureName}
|
||||||
key={lang.cultureName}
|
className="justify-between"
|
||||||
className="justify-between"
|
eventKey={lang.cultureName}
|
||||||
eventKey={lang.cultureName}
|
onClick={() => onLanguageSelect(lang.cultureName)}
|
||||||
onClick={() => onLanguageSelect(lang.cultureName)}
|
>
|
||||||
>
|
<span className="flex items-center">
|
||||||
<span className="flex items-center">
|
<Avatar
|
||||||
<Avatar
|
size={18}
|
||||||
size={18}
|
shape="circle"
|
||||||
shape="circle"
|
src={`/img/countries/${lang.cultureName ?? 'default'}.png`}
|
||||||
src={`/img/countries/${lang.cultureName ?? 'default'}.png`}
|
/>
|
||||||
/>
|
<span className="ltr:ml-2 rtl:mr-2">{lang.displayName}</span>
|
||||||
<span className="ltr:ml-2 rtl:mr-2">{lang.displayName}</span>
|
</span>
|
||||||
</span>
|
{currentLang === lang.cultureName && <FaCheck className="text-emerald-500 text-lg" />}
|
||||||
{currentLang === lang.cultureName && <FaCheck className="text-emerald-500 text-lg" />}
|
</Dropdown.Item>
|
||||||
</Dropdown.Item>
|
))}
|
||||||
))}
|
</Dropdown>
|
||||||
</Dropdown>
|
|
||||||
</Tooltip>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,25 @@
|
||||||
const getBaseResources = (state, resourceNames) => {
|
// Type definitions
|
||||||
|
interface LocalizationResource {
|
||||||
|
texts: Record<string, string>
|
||||||
|
baseResources: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
interface LocalizationState {
|
||||||
|
resources: Record<string, LocalizationResource>
|
||||||
|
}
|
||||||
|
|
||||||
|
interface LocalizationKey {
|
||||||
|
key: string
|
||||||
|
defaultValue?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const getBaseResources = (state: LocalizationState, resourceNames: string[]): Record<string, string> => {
|
||||||
if (!resourceNames.length) {
|
if (!resourceNames.length) {
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// [{}, {}, {}]
|
// [{}, {}, {}]
|
||||||
const texts = resourceNames.map((resourceName) => {
|
const texts = resourceNames.map((resourceName: string) => {
|
||||||
const resource = state.resources[resourceName]
|
const resource = state.resources[resourceName]
|
||||||
return {
|
return {
|
||||||
...resource.texts,
|
...resource.texts,
|
||||||
|
|
@ -15,8 +30,8 @@ const getBaseResources = (state, resourceNames) => {
|
||||||
return Object.assign({}, ...texts)
|
return Object.assign({}, ...texts)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const setLocalization = (state) => {
|
export const setLocalization = (state: LocalizationState): Record<string, Record<string, string>> => {
|
||||||
const values = {}
|
const values: Record<string, Record<string, string>> = {}
|
||||||
Object.entries(state.resources).forEach(([key, value]) => {
|
Object.entries(state.resources).forEach(([key, value]) => {
|
||||||
values[key] = {
|
values[key] = {
|
||||||
...value.texts,
|
...value.texts,
|
||||||
|
|
@ -27,23 +42,40 @@ export const setLocalization = (state) => {
|
||||||
return values
|
return values
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getLocalization = (texts, defaultResourceName, key, ...interpolateParams) => {
|
// 🔑 Interpolation helper
|
||||||
if (!key) key = ''
|
const interpolate = (text: string, params: Record<string, string | number>) => {
|
||||||
|
if (!params || typeof params !== 'object') return text
|
||||||
|
|
||||||
|
return Object.entries(params).reduce((acc, [key, value]) => {
|
||||||
|
const pattern = new RegExp(`{{\\s*${key}\\s*}}`, 'g')
|
||||||
|
return acc.replace(pattern, String(value))
|
||||||
|
}, text)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getLocalization = (
|
||||||
|
texts: Record<string, Record<string, string>>,
|
||||||
|
defaultResourceName: string | undefined,
|
||||||
|
key: string | LocalizationKey,
|
||||||
|
params?: Record<string, string | number>
|
||||||
|
): string => {
|
||||||
|
let keyString = ''
|
||||||
let defaultValue = ''
|
let defaultValue = ''
|
||||||
|
|
||||||
if (typeof key !== 'string') {
|
if (typeof key === 'string') {
|
||||||
defaultValue = key.defaultValue
|
keyString = key || ''
|
||||||
key = key.key
|
} else {
|
||||||
|
defaultValue = key.defaultValue || ''
|
||||||
|
keyString = key.key
|
||||||
}
|
}
|
||||||
|
|
||||||
const keys = key.split('::')
|
const keys = keyString.split('::')
|
||||||
const warn = (message) => {
|
const warn = (message: string) => {
|
||||||
if (import.meta.env.DEV) console.warn(message)
|
if (import.meta.env.DEV) console.warn(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keys.length < 2) {
|
if (keys.length < 2) {
|
||||||
warn('The localization source separator (::) not found.')
|
warn('The localization source separator (::) not found.')
|
||||||
return defaultValue || key
|
return defaultValue || keyString
|
||||||
}
|
}
|
||||||
if (!texts) return defaultValue || keys[1]
|
if (!texts) return defaultValue || keys[1]
|
||||||
|
|
||||||
|
|
@ -56,7 +88,6 @@ export const getLocalization = (texts, defaultResourceName, key, ...interpolateP
|
||||||
|
|
||||||
if (!sourceName) {
|
if (!sourceName) {
|
||||||
warn('Localization source name is not specified and the defaultResourceName was not defined!')
|
warn('Localization source name is not specified and the defaultResourceName was not defined!')
|
||||||
|
|
||||||
return defaultValue || sourceKey
|
return defaultValue || sourceKey
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -71,11 +102,12 @@ export const getLocalization = (texts, defaultResourceName, key, ...interpolateP
|
||||||
return defaultValue || sourceKey
|
return defaultValue || sourceKey
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: Interpolate
|
|
||||||
// interpolateParams = interpolateParams.filter((params) => params != null)
|
|
||||||
// if (localization) localization = interpolate(localization, interpolateParams)
|
|
||||||
|
|
||||||
if (typeof localization !== 'string') localization = ''
|
if (typeof localization !== 'string') localization = ''
|
||||||
|
|
||||||
return localization || defaultValue || key
|
// ✅ Interpolation using the helper function
|
||||||
|
if (localization && params && typeof params === 'object') {
|
||||||
|
localization = interpolate(localization, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
return localization || defaultValue || keyString
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,26 @@
|
||||||
import { getLocalization } from '@/services/localization.service'
|
import { getLocalization } from '@/services/localization.service'
|
||||||
import { useStoreState } from '@/store'
|
import { useStoreState } from '@/store'
|
||||||
|
|
||||||
|
type TranslateParams = Record<string, string | number>
|
||||||
|
|
||||||
const useLocalization = () => {
|
const useLocalization = () => {
|
||||||
const { texts, config } = useStoreState((state) => state.abpConfig)
|
const { texts, config } = useStoreState((state) => state.abpConfig)
|
||||||
|
|
||||||
function translate(localizationKey: string, defaultResourceName?: string) {
|
function translate(
|
||||||
|
localizationKey: string,
|
||||||
|
params?: TranslateParams,
|
||||||
|
defaultResourceName?: string
|
||||||
|
): string {
|
||||||
|
// Guard against undefined texts
|
||||||
|
if (!texts) {
|
||||||
|
return localizationKey
|
||||||
|
}
|
||||||
|
|
||||||
return getLocalization(
|
return getLocalization(
|
||||||
texts,
|
texts,
|
||||||
defaultResourceName ?? config?.localization.defaultResourceName,
|
defaultResourceName ?? config?.localization?.defaultResourceName,
|
||||||
localizationKey,
|
localizationKey,
|
||||||
|
params
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -216,12 +216,12 @@ function RolesPermission({
|
||||||
<div className="flex flex-col md:flex-row gap-4 mb-2">
|
<div className="flex flex-col md:flex-row gap-4 mb-2">
|
||||||
<div style={{ width: '30%' }}>
|
<div style={{ width: '30%' }}>
|
||||||
<Checkbox name="all" checked={isAllSelected} onChange={onSelectAll}>
|
<Checkbox name="all" checked={isAllSelected} onChange={onSelectAll}>
|
||||||
{translate('::SelectAllInAllTabs', 'AbpPermissionManagement')}
|
{translate('AbpPermissionManagement::SelectAllInAllTabs')}
|
||||||
</Checkbox>
|
</Checkbox>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ width: '70%' }}>
|
<div style={{ width: '70%' }}>
|
||||||
<Checkbox name="group" checked={isAllSelectedForGroup} onChange={onSelectAll}>
|
<Checkbox name="group" checked={isAllSelectedForGroup} onChange={onSelectAll}>
|
||||||
{translate('::SelectAllInThisTab', 'AbpPermissionManagement')}
|
{translate('AbpPermissionManagement::SelectAllInThisTab')}
|
||||||
</Checkbox>
|
</Checkbox>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -226,12 +226,12 @@ function UsersPermission({
|
||||||
<div className="flex flex-col md:flex-row gap-4">
|
<div className="flex flex-col md:flex-row gap-4">
|
||||||
<div style={{ width: '30%' }}>
|
<div style={{ width: '30%' }}>
|
||||||
<Checkbox name="all" checked={isAllSelected} onChange={onSelectAll}>
|
<Checkbox name="all" checked={isAllSelected} onChange={onSelectAll}>
|
||||||
{translate('::SelectAllInAllTabs', 'AbpPermissionManagement')}
|
{translate('AbpPermissionManagement::SelectAllInAllTabs')}
|
||||||
</Checkbox>
|
</Checkbox>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ width: '70%' }}>
|
<div style={{ width: '70%' }}>
|
||||||
<Checkbox name="group" checked={isAllSelectedForGroup} onChange={onSelectAll}>
|
<Checkbox name="group" checked={isAllSelectedForGroup} onChange={onSelectAll}>
|
||||||
{translate('::SelectAllInThisTab', 'AbpPermissionManagement')}
|
{translate('AbpPermissionManagement::SelectAllInThisTab')}
|
||||||
</Checkbox>
|
</Checkbox>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -123,19 +123,19 @@ const Blog = () => {
|
||||||
<div className="flex gap-2 flex-wrap">
|
<div className="flex gap-2 flex-wrap">
|
||||||
<button
|
<button
|
||||||
onClick={() => handleCategoryChange('')}
|
onClick={() => handleCategoryChange('')}
|
||||||
className={`px-4 py-2 rounded-lg transition-colors ${
|
className={`px-4 py-2 bg-blue-100 text-blue-800 text-sm font-medium rounded-lg transition-colors ${
|
||||||
selectedCategory === ''
|
selectedCategory === ''
|
||||||
? 'bg-blue-600 text-white'
|
? 'bg-blue-600 text-white'
|
||||||
: 'bg-gray-200 text-gray-700 hover:bg-gray-300'
|
: 'bg-gray-200 text-gray-700 hover:bg-gray-300'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
Tümü
|
{translate('::App.Reports.Dashboard.All')}
|
||||||
</button>
|
</button>
|
||||||
{categories.map((category) => (
|
{categories.map((category) => (
|
||||||
<button
|
<button
|
||||||
key={category.id}
|
key={category.id}
|
||||||
onClick={() => handleCategoryChange(category.id)}
|
onClick={() => handleCategoryChange(category.id)}
|
||||||
className={`px-4 py-2 rounded-lg transition-colors ${
|
className={`px-4 py-2 bg-blue-100 text-blue-800 text-sm font-medium rounded-lg transition-colors ${
|
||||||
selectedCategory === category.id
|
selectedCategory === category.id
|
||||||
? 'bg-blue-600 text-white'
|
? 'bg-blue-600 text-white'
|
||||||
: 'bg-gray-200 text-gray-700 hover:bg-gray-300'
|
: 'bg-gray-200 text-gray-700 hover:bg-gray-300'
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue