From 53ce6238c2b5e436bda664aef3649cf1a74adfa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sedat=20=C3=96ZT=C3=9CRK?= <76204082+iamsedatozturk@users.noreply.github.com> Date: Wed, 20 Aug 2025 13:06:40 +0300 Subject: [PATCH] =?UTF-8?q?Public=20Services=20ekran=C4=B1=20dinamik=20hal?= =?UTF-8?q?e=20getirildi.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Services/ServiceDto.cs | 8 +- .../Services/ServiceAutoMapperProfile.cs | 1 - .../Seeds/PlatformDataSeeder.cs | 32 +- .../Seeds/SeederData.json | 143 +++++-- .../Seeds/SeederDto.cs | 14 +- .../Kurs.Platform.Domain/Entities/Service.cs | 31 +- .../EntityFrameworkCore/PlatformDbContext.cs | 29 +- ....cs => 20250820091253_Service.Designer.cs} | 39 +- ...5_Service.cs => 20250820091253_Service.cs} | 28 +- .../PlatformDbContextModelSnapshot.cs | 37 +- ui/dev-dist/sw.js | 2 +- ui/src/proxy/services/models.ts | 9 +- ui/src/services/service.service.ts | 22 +- ui/src/views/public/Services.tsx | 374 ++++++++++-------- 14 files changed, 412 insertions(+), 357 deletions(-) rename api/src/Kurs.Platform.EntityFrameworkCore/Migrations/{20250820071335_Service.Designer.cs => 20250820091253_Service.Designer.cs} (99%) rename api/src/Kurs.Platform.EntityFrameworkCore/Migrations/{20250820071335_Service.cs => 20250820091253_Service.cs} (64%) diff --git a/api/src/Kurs.Platform.Application.Contracts/Services/ServiceDto.cs b/api/src/Kurs.Platform.Application.Contracts/Services/ServiceDto.cs index 8b261e35..dc8bdca1 100644 --- a/api/src/Kurs.Platform.Application.Contracts/Services/ServiceDto.cs +++ b/api/src/Kurs.Platform.Application.Contracts/Services/ServiceDto.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using Volo.Abp.Application.Dtos; namespace Kurs.Platform.Services; @@ -11,10 +10,5 @@ public class ServiceDto : FullAuditedEntityDto public string? Description { get; set; } public string Type { get; set; } - public List Features { get; set; } = new(); -} - -public class ServiceFeatureDto : EntityDto -{ - public string Name { get; set; } + public string[] Features { get; set; } = []; } diff --git a/api/src/Kurs.Platform.Application/Services/ServiceAutoMapperProfile.cs b/api/src/Kurs.Platform.Application/Services/ServiceAutoMapperProfile.cs index ebf61c0e..4e7302c8 100644 --- a/api/src/Kurs.Platform.Application/Services/ServiceAutoMapperProfile.cs +++ b/api/src/Kurs.Platform.Application/Services/ServiceAutoMapperProfile.cs @@ -9,6 +9,5 @@ public class ServiceAutoMapperProfile : Profile public ServiceAutoMapperProfile() { CreateMap(); - CreateMap(); } } diff --git a/api/src/Kurs.Platform.DbMigrator/Seeds/PlatformDataSeeder.cs b/api/src/Kurs.Platform.DbMigrator/Seeds/PlatformDataSeeder.cs index b69ecd0f..42aba2f7 100644 --- a/api/src/Kurs.Platform.DbMigrator/Seeds/PlatformDataSeeder.cs +++ b/api/src/Kurs.Platform.DbMigrator/Seeds/PlatformDataSeeder.cs @@ -65,6 +65,7 @@ public class PlatformDataSeeder : IDataSeedContributor, ITransientDependency private readonly IRepository _installmentOptionRepository; private readonly IRepository _customComponentRepository; private readonly IRepository _reportCategoriesRepository; + private readonly IRepository _servicesRepository; public PlatformDataSeeder( IRepository languages, @@ -102,7 +103,8 @@ public class PlatformDataSeeder : IDataSeedContributor, ITransientDependency IRepository PaymentMethodRepository, IRepository InstallmentOptionRepository, IRepository CustomComponentRepository, - IRepository ReportCategoriesRepository + IRepository ReportCategoriesRepository, + IRepository ServicesRepository ) { _languages = languages; @@ -141,6 +143,7 @@ public class PlatformDataSeeder : IDataSeedContributor, ITransientDependency _installmentOptionRepository = InstallmentOptionRepository; _customComponentRepository = CustomComponentRepository; _reportCategoriesRepository = ReportCategoriesRepository; + _servicesRepository = ServicesRepository; } private static IConfigurationRoot BuildConfiguration() @@ -578,7 +581,7 @@ public class PlatformDataSeeder : IDataSeedContributor, ITransientDependency if (!exists) { await _blogPostsRepository.InsertAsync(new BlogPost( - item.Id, + Guid.NewGuid(), item.Title, item.Slug, item.ContentTr, @@ -601,7 +604,7 @@ public class PlatformDataSeeder : IDataSeedContributor, ITransientDependency if (!exists) { var newCategory = new ForumCategory( - item.Id, + Guid.NewGuid(), item.Name, item.Slug, item.Description, @@ -620,7 +623,7 @@ public class PlatformDataSeeder : IDataSeedContributor, ITransientDependency if (!exists) { await _aiBotRepository.InsertAsync(new AiBot( - item.Id, + Guid.NewGuid(), item.BotName )); } @@ -668,7 +671,7 @@ public class PlatformDataSeeder : IDataSeedContributor, ITransientDependency if (!exists) { await _productRepository.InsertAsync(new Product( - item.Id, + Guid.NewGuid(), item.Name, item.Description, item.Category, @@ -732,12 +735,29 @@ public class PlatformDataSeeder : IDataSeedContributor, ITransientDependency if (!exists) { await _reportCategoriesRepository.InsertAsync(new ReportCategory( - item.Id, + Guid.NewGuid(), item.Name, item.Description, item.Icon)); } } + + foreach (var item in items.Services) + { + var exists = await _servicesRepository.AnyAsync(x => x.Title == item.Title); + + if (!exists) + { + await _servicesRepository.InsertAsync(new Service( + Guid.NewGuid(), + item.Icon, + item.Title, + item.Description, + item.Type, + item.Features + )); + } + } } public async Task SeedCountyGroupsAsync() diff --git a/api/src/Kurs.Platform.DbMigrator/Seeds/SeederData.json b/api/src/Kurs.Platform.DbMigrator/Seeds/SeederData.json index f41ec4fb..c44a0504 100644 --- a/api/src/Kurs.Platform.DbMigrator/Seeds/SeederData.json +++ b/api/src/Kurs.Platform.DbMigrator/Seeds/SeederData.json @@ -16808,7 +16808,6 @@ ], "BlogPosts": [ { - "Id": "1a79a36e-e062-4335-9ddf-0557c60f3ea9", "TenantId": null, "Title": "blog.posts.ai.title", "Slug": "ai-ve-gelecegi", @@ -16821,7 +16820,6 @@ "AuthorId": "1668adf0-fd2a-5216-9834-6b6874ec2a05" }, { - "Id": "e7d6f581-60ba-44d4-be37-c5d13e5c2fda", "TenantId": null, "Title": "blog.posts.web.title", "Slug": "web-gelistirmede-son-trendler", @@ -16834,7 +16832,6 @@ "AuthorId": "7df16a77-92ed-50e6-8749-ae34345c01b9" }, { - "Id": "54ac1095-0a95-467e-9f86-01efa8af136b", "TenantId": null, "Title": "blog.posts.security.title", "Slug": "siber-guvenlik-tehditleri-ve-korunma-yollari", @@ -16846,7 +16843,6 @@ "CategoryId": "e938e6e6-f355-5807-a7f7-f0d4fe368fc5" }, { - "Id": "bdd7e679-dd6e-4014-be13-b344fec2f283", "TenantId": null, "Title": "blog.posts.mobile.title", "Slug": "mobil-uygulama-gelistirmede-cross-platform-cozumler", @@ -16859,7 +16855,6 @@ "AuthorId": "c107a187-5e41-51e1-a5b3-5bf85c16b39e" }, { - "Id": "777a2bac-5651-43af-ae08-4753a2a1ea51", "TenantId": null, "Title": "blog.posts.database.title", "Slug": "veritabani-yonetim-sistemleri-karsilastirmasi", @@ -16872,7 +16867,6 @@ "AuthorId": "8f49d028-69d0-5d2b-abc3-559b7dee180f" }, { - "Id": "3dfbb220-9a2d-49e4-835a-213f47c60939", "TenantId": null, "Title": "blog.posts.digital.title", "Slug": "dijital-pazarlamada-veri-analizi", @@ -16925,7 +16919,6 @@ ], "AiBots": [ { - "Id": "1a79a36e-e062-4335-9ddf-0557c60f3ea9", "BotName": "Chat Bot" } ], @@ -16960,7 +16953,6 @@ ], "Products": [ { - "id": "5f4d6c1f-b1e0-4f91-854c-1d59c25e7193", "name": "Public.products.branchHosting", "description": "Public.products.branchHosting.desc", "category": "Public.products.categories.Üyelik", @@ -16971,7 +16963,6 @@ "imageUrl": "https://images.pexels.com/photos/1181673/pexels-photo-1181673.jpeg?auto=compress&cs=tinysrgb&w=300" }, { - "id": "a85d0f04-7d40-47cb-bcf6-d95fbe31ec93", "name": "Public.products.backupService", "description": "Public.products.backupService.desc", "category": "Public.products.categories.Üyelik", @@ -16982,7 +16973,6 @@ "imageUrl": "https://images.pexels.com/photos/442150/pexels-photo-442150.jpeg?auto=compress&cs=tinysrgb&w=300" }, { - "id": "03cfae0b-4e3a-4b4b-917f-f798f18e0f15", "name": "Public.products.remoteSupportContract", "description": "Public.products.remoteSupportContract.desc", "category": "Public.products.categories.Üyelik", @@ -16993,7 +16983,6 @@ "imageUrl": "https://images.pexels.com/photos/3184465/pexels-photo-3184465.jpeg?auto=compress&cs=tinysrgb&w=300" }, { - "id": "03cfae0b-4e3a-4b4b-917f-f798f18e0f11", "name": "Public.products.userLicense", "description": "Public.products.userLicense.desc", "category": "Public.products.categories.Lisans", @@ -17004,7 +16993,6 @@ "imageUrl": "https://images.pexels.com/photos/3184360/pexels-photo-3184360.jpeg?auto=compress&cs=tinysrgb&w=300" }, { - "id": "36d98c72-6a62-4fa1-b942-2689eb42e4d4", "name": "Public.products.teacherLicense", "description": "Public.products.teacherLicense.desc", "category": "Public.products.categories.Lisans", @@ -17015,7 +17003,6 @@ "imageUrl": "https://images.pexels.com/photos/5212345/pexels-photo-5212345.jpeg?auto=compress&cs=tinysrgb&w=300" }, { - "id": "9a80f69d-46e5-4b92-91dc-fbb4d2f90c1f", "name": "Public.products.mobileReporting", "description": "Public.products.mobileReporting.desc", "category": "Public.products.categories.Lisans", @@ -17026,7 +17013,6 @@ "imageUrl": "https://images.pexels.com/photos/1092644/pexels-photo-1092644.jpeg?auto=compress&cs=tinysrgb&w=300" }, { - "id": "66324548-8500-4f06-8b1c-1a31e8d25c39", "name": "Public.products.remoteBranchTraining", "description": "Public.products.remoteBranchTraining.desc", "category": "Public.products.categories.Ek Hizmetler", @@ -17037,7 +17023,6 @@ "imageUrl": "https://images.pexels.com/photos/3184339/pexels-photo-3184339.jpeg?auto=compress&cs=tinysrgb&w=300" }, { - "id": "b0b51a46-cf33-423f-b93f-2e2a3b8e27c0", "name": "Public.products.extraHourlyService", "description": "Public.products.extraHourlyService.desc", "order": 8, @@ -17048,7 +17033,6 @@ "imageUrl": "https://images.pexels.com/photos/3184291/pexels-photo-3184291.jpeg?auto=compress&cs=tinysrgb&w=300" }, { - "id": "15b813c6-4905-412b-999a-c303b91b3152", "name": "Public.products.sms5k", "description": "Public.products.sms5k.desc", "category": "Public.products.categories.Ek Hizmetler", @@ -17059,7 +17043,6 @@ "imageUrl": "https://images.pexels.com/photos/404280/pexels-photo-404280.jpeg?auto=compress&cs=tinysrgb&w=300" }, { - "id": "e2c940b4-4a35-4f3d-8600-b1c2b9ce5179", "name": "Public.products.sms10k", "description": "Public.products.sms10k.desc", "category": "Public.products.categories.Ek Hizmetler", @@ -17070,7 +17053,6 @@ "imageUrl": "https://images.pexels.com/photos/404280/pexels-photo-404280.jpeg?auto=compress&cs=tinysrgb&w=300" }, { - "id": "1985ba1b1-f4c6-40f2-a747-0cf45c96a5b7", "name": "Public.products.sms25k", "description": "Public.products.sms25k.desc", "category": "Public.products.categories.Ek Hizmetler", @@ -17081,7 +17063,6 @@ "imageUrl": "https://images.pexels.com/photos/404280/pexels-photo-404280.jpeg?auto=compress&cs=tinysrgb&w=300" }, { - "id": "7a7ae7c3-bef2-4978-90cf-96d1475e3492", "name": "Public.products.sms50k", "description": "Public.products.sms50k.desc", "category": "Public.products.categories.Ek Hizmetler", @@ -17092,7 +17073,6 @@ "imageUrl": "https://images.pexels.com/photos/404280/pexels-photo-404280.jpeg?auto=compress&cs=tinysrgb&w=300" }, { - "id": "3e6a8de1-6c48-4ff8-87f5-252735a7e89f", "name": "Public.products.sms100k", "description": "Public.products.sms100k.desc", "category": "Public.products.categories.Ek Hizmetler", @@ -17103,7 +17083,6 @@ "imageUrl": "https://images.pexels.com/photos/404280/pexels-photo-404280.jpeg?auto=compress&cs=tinysrgb&w=300" }, { - "id": "2e35b9b8-f404-4b83-9737-d059c05fd44b", "name": "Public.products.smsBlocking", "description": "Public.products.smsBlocking.desc", "category": "Public.products.categories.Ek Hizmetler", @@ -17180,22 +17159,138 @@ ], "ReportCategories": [ { - "id": "5f4d6c1f-b1e0-4f91-854c-1d59c25e7191", "name": "Genel Raporlar", "description": "Şirket içi genel tüm raporlar", "icon": "📊" }, { - "id": "5f4d6c1f-b1e0-4f91-854c-1d59c25e7192", "name": "Taahhütnameler", "description": "Kursiyeler ile ilgili taahhütname raporları", "icon": "✍️" }, { - "id": "5f4d6c1f-b1e0-4f91-854c-1d59c25e7193", "name": "Sözleşmeler", "description": "Tedarikçiler ile ilgili sözleşme raporları", "icon": "📜" } + ], + "Services": [ + { + "icon": "FaCode", + "title": "Public.services.software.title", + "description": "Public.services.software.desc", + "type": "service", + "features": [ + "Public.services.software.features.analysis", + "Public.services.software.features.design", + "Public.services.software.features.development", + "Public.services.software.features.testing", + "Public.services.software.features.maintenance" + ] + }, + { + "icon": "FaUsers", + "title": "Public.services.web.title", + "description": "Public.services.web.desc", + "type": "service", + "features": [ + "Public.services.web.features.frontend", + "Public.services.web.features.backend", + "Public.services.web.features.api", + "Public.services.web.features.seo", + "Public.services.web.features.performance" + ] + }, + { + "icon": "FaShieldAlt", + "title": "Public.services.mobile.title", + "description": "Public.services.mobile.desc", + "type": "service", + "features": [ + "Public.services.mobile.features.design", + "Public.services.mobile.features.native", + "Public.services.mobile.features.cross", + "Public.services.mobile.features.push", + "Public.services.mobile.features.store" + ] + }, + { + "icon": "FaServer", + "title": "Public.services.database.title", + "description": "Public.services.database.desc", + "type": "service", + "features": [ + "Public.services.database.features.design", + "Public.services.database.features.optimization", + "Public.services.database.features.migration", + "Public.services.database.features.backup", + "Public.services.database.features.recovery" + ] + }, + { + "icon": "FaGlobe", + "title": "Public.services.integration.title", + "description": "Public.services.integration.desc", + "type": "service", + "features": [ + "Public.services.integration.features.api", + "Public.services.integration.features.middleware", + "Public.services.integration.features.legacy", + "Public.services.integration.features.realtime", + "Public.services.integration.features.monitoring" + ] + }, + { + "icon": "FaCog", + "title": "Public.services.consulting.title", + "description": "Public.services.consulting.desc", + "type": "service", + "features": [ + "Public.services.consulting.features.tech", + "Public.services.consulting.features.project", + "Public.services.consulting.features.digital", + "Public.services.consulting.features.risk", + "Public.services.consulting.features.training" + ] + }, + { + "icon": "FaUsers", + "title": "Public.services.support.branchRemote.title", + "description": null, + "type": "support", + "features": [ + "Public.services.support.branchRemote.features.priority", + "Public.services.support.branchRemote.features.remote", + "Public.services.support.branchRemote.features.optimization", + "Public.services.support.branchRemote.features.maintenance", + "Public.services.support.branchRemote.features.consulting" + ] + }, + { + "icon": "FaServer", + "title": "Public.services.support.backup.title", + "description": null, + "type": "support", + "features": [ + "Public.services.support.backup.features.daily", + "Public.services.support.backup.features.encrypted", + "Public.services.support.backup.features.recovery", + "Public.services.support.backup.features.verification", + "Public.services.support.backup.features.access" + ] + }, + { + "icon": "FaGlobe", + "title": "Public.services.support.sms.title", + "description": null, + "type": "support", + "features": [ + "Public.services.support.sms.features.packages", + "Public.services.support.sms.features.bulk", + "Public.services.support.sms.features.template", + "Public.services.support.sms.features.reporting", + "Public.services.support.sms.features.api" + ] + } ] } diff --git a/api/src/Kurs.Platform.DbMigrator/Seeds/SeederDto.cs b/api/src/Kurs.Platform.DbMigrator/Seeds/SeederDto.cs index fa76fb12..7c1d6011 100644 --- a/api/src/Kurs.Platform.DbMigrator/Seeds/SeederDto.cs +++ b/api/src/Kurs.Platform.DbMigrator/Seeds/SeederDto.cs @@ -41,6 +41,7 @@ public class SeederDto public List InstallmentOptions { get; set; } public List CustomComponents { get; set; } public List ReportCategories { get; set; } + public List Services { get; set; } } public class ChartsSeedDto @@ -198,7 +199,6 @@ public class BlogCategorySeedDto public class BlogPostSeedDto { - public Guid Id { get; set; } public string Title { get; set; } public string Slug { get; set; } public string ContentTr { get; set; } @@ -214,7 +214,6 @@ public class BlogPostSeedDto public class ForumCategorySeedDto { - public Guid Id { get; set; } public string Name { get; set; } public string Slug { get; set; } public string Description { get; set; } @@ -225,7 +224,6 @@ public class ForumCategorySeedDto public class AiBotSeedDto { - public Guid Id { get; set; } public string BotName { get; set; } } @@ -290,8 +288,16 @@ public class CustomComponentSeedDto public class ReportCategorySeedDto { - public Guid Id { get; set; } public string Name { get; set; } public string Description { get; set; } public string Icon { get; set; } } + +public class ServiceSeedDto +{ + public string Icon { get; set; } + public string Title { get; set; } + public string Description { get; set; } + public string Type { get; set; } + public string[] Features { get; set; } +} diff --git a/api/src/Kurs.Platform.Domain/Entities/Service.cs b/api/src/Kurs.Platform.Domain/Entities/Service.cs index f81aea73..be6e3040 100644 --- a/api/src/Kurs.Platform.Domain/Entities/Service.cs +++ b/api/src/Kurs.Platform.Domain/Entities/Service.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Entities.Auditing; @@ -7,40 +6,24 @@ namespace Kurs.Platform.Entities; public class Service : FullAuditedAggregateRoot { - // Icon component adı (ör: "FaCode") public string? Icon { get; set; } - public string Title { get; set; } public string? Description { get; set; } public string Type { get; set; } - public ICollection Features { get; set; } + // JSON olarak saklanacak + public string[] Features { get; set; } = []; - protected Service() - { - Features = []; - } + protected Service() { } - public Service(Guid id, string title, string type) + public Service(Guid id, string icon, string title, string description, string type, string[] features) : base(id) { + Icon = icon; Title = title; + Description = description; Type = type; - Features = []; + Features = features; } } -public class ServiceFeature : Entity -{ - public Guid ServiceItemId { get; set; } - public string Name { get; set; } - - public ServiceFeature() { } - - public ServiceFeature(Guid id, Guid serviceItemId, string name) - : base(id) - { - ServiceItemId = serviceItemId; - Name = name; - } -} diff --git a/api/src/Kurs.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformDbContext.cs b/api/src/Kurs.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformDbContext.cs index 43a140c0..91308ece 100644 --- a/api/src/Kurs.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformDbContext.cs +++ b/api/src/Kurs.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformDbContext.cs @@ -23,6 +23,7 @@ using Microsoft.EntityFrameworkCore.ChangeTracking; using System; using System.Linq; using Kurs.Platform.Orders; +using System.Text.Json; namespace Kurs.Platform.EntityFrameworkCore; @@ -92,7 +93,6 @@ public class PlatformDbContext : public DbSet ReportCategories { get; set; } public DbSet Demos { get; set; } public DbSet Services { get; set; } - public DbSet ServiceFeatures { get; set; } #region Entities from the modules @@ -818,20 +818,19 @@ public class PlatformDbContext : b.Property(x => x.Description).HasMaxLength(512); b.Property(x => x.Icon).HasMaxLength(64); - // 1 - N ilişki - b.HasMany(x => x.Features) - .WithOne() - .HasForeignKey(f => f.ServiceItemId); - }); - - builder.Entity(b => - { - b.ToTable(PlatformConsts.DbTablePrefix + nameof(ServiceFeature), PlatformConsts.DbSchema); - b.ConfigureByConvention(); - - b.Property(x => x.Name) - .IsRequired() - .HasMaxLength(128); + b.Property(x => x.Features) + .HasConversion( + v => JsonSerializer.Serialize(v, (JsonSerializerOptions)null), + v => JsonSerializer.Deserialize(v, (JsonSerializerOptions)null) + ) + .Metadata + .SetValueComparer( + new ValueComparer( + (a, b) => a.SequenceEqual(b), + a => a.Aggregate(0, (c, v) => HashCode.Combine(c, v.GetHashCode())), + a => a.ToArray() // clone + ) + ); }); } } diff --git a/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250820071335_Service.Designer.cs b/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250820091253_Service.Designer.cs similarity index 99% rename from api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250820071335_Service.Designer.cs rename to api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250820091253_Service.Designer.cs index d2114e98..1f95636a 100644 --- a/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250820071335_Service.Designer.cs +++ b/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250820091253_Service.Designer.cs @@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore; namespace Kurs.Platform.Migrations { [DbContext(typeof(PlatformDbContext))] - [Migration("20250820071335_Service")] + [Migration("20250820091253_Service")] partial class Service { /// @@ -3486,6 +3486,9 @@ namespace Kurs.Platform.Migrations .HasColumnType("nvarchar(max)") .HasColumnName("ExtraProperties"); + b.Property("Features") + .HasColumnType("nvarchar(max)"); + b.Property("Icon") .HasMaxLength(64) .HasColumnType("nvarchar(64)"); @@ -3517,26 +3520,6 @@ namespace Kurs.Platform.Migrations b.ToTable("PService", (string)null); }); - modelBuilder.Entity("Kurs.Platform.Entities.ServiceFeature", b => - { - b.Property("Id") - .HasColumnType("uniqueidentifier"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("nvarchar(128)"); - - b.Property("ServiceItemId") - .HasColumnType("uniqueidentifier"); - - b.HasKey("Id"); - - b.HasIndex("ServiceItemId"); - - b.ToTable("PServiceFeature", (string)null); - }); - modelBuilder.Entity("Kurs.Platform.Entities.Uom", b => { b.Property("Id") @@ -6337,15 +6320,6 @@ namespace Kurs.Platform.Migrations b.Navigation("ReportCategory"); }); - modelBuilder.Entity("Kurs.Platform.Entities.ServiceFeature", b => - { - b.HasOne("Kurs.Platform.Entities.Service", null) - .WithMany("Features") - .HasForeignKey("ServiceItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - modelBuilder.Entity("Kurs.Platform.Entities.Uom", b => { b.HasOne("Kurs.Platform.Entities.UomCategory", "UomCategory") @@ -6587,11 +6561,6 @@ namespace Kurs.Platform.Migrations b.Navigation("Parameters"); }); - modelBuilder.Entity("Kurs.Platform.Entities.Service", b => - { - b.Navigation("Features"); - }); - modelBuilder.Entity("Kurs.Platform.Entities.UomCategory", b => { b.Navigation("Uoms"); diff --git a/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250820071335_Service.cs b/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250820091253_Service.cs similarity index 64% rename from api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250820071335_Service.cs rename to api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250820091253_Service.cs index 5342b323..01285bfc 100644 --- a/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250820071335_Service.cs +++ b/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/20250820091253_Service.cs @@ -20,6 +20,7 @@ namespace Kurs.Platform.Migrations Title = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), Description = table.Column(type: "nvarchar(512)", maxLength: 512, nullable: true), Type = table.Column(type: "nvarchar(max)", nullable: true), + Features = table.Column(type: "nvarchar(max)", nullable: true), ExtraProperties = table.Column(type: "nvarchar(max)", nullable: false), ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: false), CreationTime = table.Column(type: "datetime2", nullable: false), @@ -34,38 +35,11 @@ namespace Kurs.Platform.Migrations { table.PrimaryKey("PK_PService", x => x.Id); }); - - migrationBuilder.CreateTable( - name: "PServiceFeature", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - ServiceItemId = table.Column(type: "uniqueidentifier", nullable: false), - Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_PServiceFeature", x => x.Id); - table.ForeignKey( - name: "FK_PServiceFeature_PService_ServiceItemId", - column: x => x.ServiceItemId, - principalTable: "PService", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateIndex( - name: "IX_PServiceFeature_ServiceItemId", - table: "PServiceFeature", - column: "ServiceItemId"); } /// protected override void Down(MigrationBuilder migrationBuilder) { - migrationBuilder.DropTable( - name: "PServiceFeature"); - migrationBuilder.DropTable( name: "PService"); } diff --git a/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/PlatformDbContextModelSnapshot.cs b/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/PlatformDbContextModelSnapshot.cs index 8cffc4e3..c80aa349 100644 --- a/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/PlatformDbContextModelSnapshot.cs +++ b/api/src/Kurs.Platform.EntityFrameworkCore/Migrations/PlatformDbContextModelSnapshot.cs @@ -3483,6 +3483,9 @@ namespace Kurs.Platform.Migrations .HasColumnType("nvarchar(max)") .HasColumnName("ExtraProperties"); + b.Property("Features") + .HasColumnType("nvarchar(max)"); + b.Property("Icon") .HasMaxLength(64) .HasColumnType("nvarchar(64)"); @@ -3514,26 +3517,6 @@ namespace Kurs.Platform.Migrations b.ToTable("PService", (string)null); }); - modelBuilder.Entity("Kurs.Platform.Entities.ServiceFeature", b => - { - b.Property("Id") - .HasColumnType("uniqueidentifier"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("nvarchar(128)"); - - b.Property("ServiceItemId") - .HasColumnType("uniqueidentifier"); - - b.HasKey("Id"); - - b.HasIndex("ServiceItemId"); - - b.ToTable("PServiceFeature", (string)null); - }); - modelBuilder.Entity("Kurs.Platform.Entities.Uom", b => { b.Property("Id") @@ -6334,15 +6317,6 @@ namespace Kurs.Platform.Migrations b.Navigation("ReportCategory"); }); - modelBuilder.Entity("Kurs.Platform.Entities.ServiceFeature", b => - { - b.HasOne("Kurs.Platform.Entities.Service", null) - .WithMany("Features") - .HasForeignKey("ServiceItemId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - modelBuilder.Entity("Kurs.Platform.Entities.Uom", b => { b.HasOne("Kurs.Platform.Entities.UomCategory", "UomCategory") @@ -6584,11 +6558,6 @@ namespace Kurs.Platform.Migrations b.Navigation("Parameters"); }); - modelBuilder.Entity("Kurs.Platform.Entities.Service", b => - { - b.Navigation("Features"); - }); - modelBuilder.Entity("Kurs.Platform.Entities.UomCategory", b => { b.Navigation("Uoms"); diff --git a/ui/dev-dist/sw.js b/ui/dev-dist/sw.js index 945da89c..499b297c 100644 --- a/ui/dev-dist/sw.js +++ b/ui/dev-dist/sw.js @@ -82,7 +82,7 @@ define(['./workbox-54d0af47'], (function (workbox) { 'use strict'; "revision": "3ca0b8505b4bec776b69afdba2768812" }, { "url": "index.html", - "revision": "0.3u9qv452np" + "revision": "0.bmupql65hho" }], {}); workbox.cleanupOutdatedCaches(); workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), { diff --git a/ui/src/proxy/services/models.ts b/ui/src/proxy/services/models.ts index e96ca629..f4913db0 100644 --- a/ui/src/proxy/services/models.ts +++ b/ui/src/proxy/services/models.ts @@ -1,20 +1,15 @@ export type ItemType = 'service' | 'support' export interface Service { - icon?: React.ReactNode + icon?: string title: string description?: string type: ItemType features: string[] } -export interface ServiceFeature { - serviceItemId: string - name: string -} - export interface ServiceDto { - icon?: React.ReactNode + icon?: string title: string description?: string type: ItemType diff --git a/ui/src/services/service.service.ts b/ui/src/services/service.service.ts index 12d63487..07bb801c 100644 --- a/ui/src/services/service.service.ts +++ b/ui/src/services/service.service.ts @@ -1,16 +1,12 @@ -import { PagedAndSortedResultRequestDto, PagedResultDto } from '../proxy' -import apiService, { Config } from './api.service' +import apiService from './api.service' import { ServiceDto } from '@/proxy/services/models' -export class ServiceService { - apiName = 'Default' - - getList = () => - apiService.fetchData( - { - method: 'GET', - url: '/api/app/service', - }, - { apiName: this.apiName }, - ) +export function getServices() { + return apiService.fetchData( + { + method: 'GET', + url: '/api/app/service', + }, + { apiName: 'Default' }, + ) } diff --git a/ui/src/views/public/Services.tsx b/ui/src/views/public/Services.tsx index 2c10a4f6..5959171a 100644 --- a/ui/src/views/public/Services.tsx +++ b/ui/src/views/public/Services.tsx @@ -1,4 +1,4 @@ -import React from 'react' +import React, { useEffect, useState } from 'react' import { FaCode, FaGlobe, @@ -13,130 +13,169 @@ import { useLocalization } from '@/utils/hooks/useLocalization' import { ROUTES_ENUM } from '@/routes/route.constant' import { Helmet } from 'react-helmet' import { ServiceDto } from '@/proxy/services/models' +import { getServices } from '@/services/service.service' +import navigationIcon from '@/configs/navigation-icon.config' const Services: React.FC = () => { const { translate } = useLocalization() + const [services, setServices] = useState([]) - const services: ServiceDto[] = [ - { - icon: , - title: translate('::Public.services.software.title'), - description: translate('::Public.services.software.desc'), - type: 'service', - features: [ - translate('::Public.services.software.features.analysis'), - translate('::Public.services.software.features.design'), - translate('::Public.services.software.features.development'), - translate('::Public.services.software.features.testing'), - translate('::Public.services.software.features.maintenance'), - ], - }, - { - icon: , - title: translate('::Public.services.web.title'), - description: translate('::Public.services.web.desc'), - type: 'service', - features: [ - translate('::Public.services.web.features.frontend'), - translate('::Public.services.web.features.backend'), - translate('::Public.services.web.features.api'), - translate('::Public.services.web.features.seo'), - translate('::Public.services.web.features.performance'), - ], - }, - { - icon: , - title: translate('::Public.services.mobile.title'), - description: translate('::Public.services.mobile.desc'), - type: 'service', - features: [ - translate('::Public.services.mobile.features.design'), - translate('::Public.services.mobile.features.native'), - translate('::Public.services.mobile.features.cross'), - translate('::Public.services.mobile.features.push'), - translate('::Public.services.mobile.features.store'), - ], - }, - { - icon: , - title: translate('::Public.services.database.title'), - description: translate('::Public.services.database.desc'), - type: 'service', - features: [ - translate('::Public.services.database.features.design'), - translate('::Public.services.database.features.optimization'), - translate('::Public.services.database.features.migration'), - translate('::Public.services.database.features.backup'), - translate('::Public.services.database.features.recovery'), - ], - }, - { - icon: , - title: translate('::Public.services.integration.title'), - description: translate('::Public.services.integration.desc'), - type: 'service', - features: [ - translate('::Public.services.integration.features.api'), - translate('::Public.services.integration.features.middleware'), - translate('::Public.services.integration.features.legacy'), - translate('::Public.services.integration.features.realtime'), - translate('::Public.services.integration.features.monitoring'), - ], - }, - { - icon: , - title: translate('::Public.services.consulting.title'), - description: translate('::Public.services.consulting.desc'), - type: 'service', - features: [ - translate('::Public.services.consulting.features.tech'), - translate('::Public.services.consulting.features.project'), - translate('::Public.services.consulting.features.digital'), - translate('::Public.services.consulting.features.risk'), - translate('::Public.services.consulting.features.training'), - ], - }, - { - icon: , // Remote Branch Support - title: translate('::Public.services.support.branchRemote.title'), - description: '', - type: 'support', - features: [ - translate('::Public.services.support.branchRemote.features.priority'), - translate('::Public.services.support.branchRemote.features.remote'), - translate('::Public.services.support.branchRemote.features.optimization'), - translate('::Public.services.support.branchRemote.features.maintenance'), - translate('::Public.services.support.branchRemote.features.consulting'), - ], - }, - { - icon: , // Backup Support - title: translate('::Public.services.support.backup.title'), - description: '', - type: 'support', - features: [ - translate('::Public.services.support.backup.features.daily'), - translate('::Public.services.support.backup.features.encrypted'), - translate('::Public.services.support.backup.features.recovery'), - translate('::Public.services.support.backup.features.verification'), - translate('::Public.services.support.backup.features.access'), - ], - }, - { - icon: , // SMS Support - title: translate('::Public.services.support.sms.title'), - description: '', - type: 'support', - features: [ - translate('::Public.services.support.sms.features.packages'), - translate('::Public.services.support.sms.features.bulk'), - translate('::Public.services.support.sms.features.template'), - translate('::Public.services.support.sms.features.reporting'), - translate('::Public.services.support.sms.features.api'), - ], - }, + // const services: ServiceDto[] = [ + // { + // icon: , + // title: translate('::Public.services.software.title'), + // description: translate('::Public.services.software.desc'), + // type: 'service', + // features: [ + // translate('::Public.services.software.features.analysis'), + // translate('::Public.services.software.features.design'), + // translate('::Public.services.software.features.development'), + // translate('::Public.services.software.features.testing'), + // translate('::Public.services.software.features.maintenance'), + // ], + // }, + // { + // icon: , + // title: translate('::Public.services.web.title'), + // description: translate('::Public.services.web.desc'), + // type: 'service', + // features: [ + // translate('::Public.services.web.features.frontend'), + // translate('::Public.services.web.features.backend'), + // translate('::Public.services.web.features.api'), + // translate('::Public.services.web.features.seo'), + // translate('::Public.services.web.features.performance'), + // ], + // }, + // { + // icon: , + // title: translate('::Public.services.mobile.title'), + // description: translate('::Public.services.mobile.desc'), + // type: 'service', + // features: [ + // translate('::Public.services.mobile.features.design'), + // translate('::Public.services.mobile.features.native'), + // translate('::Public.services.mobile.features.cross'), + // translate('::Public.services.mobile.features.push'), + // translate('::Public.services.mobile.features.store'), + // ], + // }, + // { + // icon: , + // title: translate('::Public.services.database.title'), + // description: translate('::Public.services.database.desc'), + // type: 'service', + // features: [ + // translate('::Public.services.database.features.design'), + // translate('::Public.services.database.features.optimization'), + // translate('::Public.services.database.features.migration'), + // translate('::Public.services.database.features.backup'), + // translate('::Public.services.database.features.recovery'), + // ], + // }, + // { + // icon: , + // title: translate('::Public.services.integration.title'), + // description: translate('::Public.services.integration.desc'), + // type: 'service', + // features: [ + // translate('::Public.services.integration.features.api'), + // translate('::Public.services.integration.features.middleware'), + // translate('::Public.services.integration.features.legacy'), + // translate('::Public.services.integration.features.realtime'), + // translate('::Public.services.integration.features.monitoring'), + // ], + // }, + // { + // icon: , + // title: translate('::Public.services.consulting.title'), + // description: translate('::Public.services.consulting.desc'), + // type: 'service', + // features: [ + // translate('::Public.services.consulting.features.tech'), + // translate('::Public.services.consulting.features.project'), + // translate('::Public.services.consulting.features.digital'), + // translate('::Public.services.consulting.features.risk'), + // translate('::Public.services.consulting.features.training'), + // ], + // }, + // { + // icon: , // Remote Branch Support + // title: translate('::Public.services.support.branchRemote.title'), + // description: '', + // type: 'support', + // features: [ + // translate('::Public.services.support.branchRemote.features.priority'), + // translate('::Public.services.support.branchRemote.features.remote'), + // translate('::Public.services.support.branchRemote.features.optimization'), + // translate('::Public.services.support.branchRemote.features.maintenance'), + // translate('::Public.services.support.branchRemote.features.consulting'), + // ], + // }, + // { + // icon: , // Backup Support + // title: translate('::Public.services.support.backup.title'), + // description: '', + // type: 'support', + // features: [ + // translate('::Public.services.support.backup.features.daily'), + // translate('::Public.services.support.backup.features.encrypted'), + // translate('::Public.services.support.backup.features.recovery'), + // translate('::Public.services.support.backup.features.verification'), + // translate('::Public.services.support.backup.features.access'), + // ], + // }, + // { + // icon: , // SMS Support + // title: translate('::Public.services.support.sms.title'), + // description: '', + // type: 'support', + // features: [ + // translate('::Public.services.support.sms.features.packages'), + // translate('::Public.services.support.sms.features.bulk'), + // translate('::Public.services.support.sms.features.template'), + // translate('::Public.services.support.sms.features.reporting'), + // translate('::Public.services.support.sms.features.api'), + // ], + // }, + // ] + + // Botları çek + + const iconColors = [ + 'text-blue-600', + 'text-red-600', + 'text-green-600', + 'text-purple-600', + 'text-yellow-600', + 'text-indigo-600', ] + function getRandomColor() { + return iconColors[Math.floor(Math.random() * iconColors.length)] + } + + useEffect(() => { + const fetchServices = async () => { + try { + const result = await getServices() + const items = result?.data?.map((service: ServiceDto) => ({ + icon: service.icon, + title: service.title, + description: service.description, + type: service.type, + features: service.features, + })) + + setServices(items) + } catch (error) { + console.error('Service listesi alınırken hata oluştu:', error) + } + } + + fetchServices() + }, []) + return (
{
{services .filter((a) => a.type === 'service') - .map((service, index) => ( -
-
{service.icon}
-

{service.title}

-

{service.description}

-
    - {service.features.map((feature, fIndex) => ( -
  • - - {feature} -
  • - ))} -
-
- ))} + .map((service, index) => { + const IconComponent = navigationIcon[service.icon || ''] + return ( +
+
+ {IconComponent && ( + + )} +
+

+ {translate('::' + service.title)} +

+

{translate('::' + service.description)}

+
    + {service.features.map((feature, fIndex) => ( +
  • + + {translate('::' + feature)} +
  • + ))} +
+
+ ) + })}
@@ -201,29 +249,37 @@ const Services: React.FC = () => {
{services .filter((a) => a.type === 'support') - .map((plan, index) => ( -
-
{plan.icon}
-

{plan.title}

-
    - {plan.features.map((feature, fIndex) => ( -
  • - - {feature} -
  • - ))} -
- { + const IconComponent = navigationIcon[plan.icon || ''] + + return ( +
- {translate('::Public.services.support.contactButton')} - -
- ))} +
+ {IconComponent && ( + + )} +
+

{translate('::' + plan.title)}

+
    + {plan.features.map((feature, fIndex) => ( +
  • + + {translate('::' + feature)} +
  • + ))} +
+ + {translate('::Public.services.support.contactButton')} + +
+ ) + })}