Public Services ekranı dinamik hale getirildi.

This commit is contained in:
Sedat ÖZTÜRK 2025-08-20 13:06:40 +03:00
parent 7e3809f7bb
commit 53ce6238c2
14 changed files with 412 additions and 357 deletions

View file

@ -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<Guid>
public string? Description { get; set; }
public string Type { get; set; }
public List<ServiceFeatureDto> Features { get; set; } = new();
}
public class ServiceFeatureDto : EntityDto<Guid>
{
public string Name { get; set; }
public string[] Features { get; set; } = [];
}

View file

@ -9,6 +9,5 @@ public class ServiceAutoMapperProfile : Profile
public ServiceAutoMapperProfile()
{
CreateMap<Service, ServiceDto>();
CreateMap<ServiceFeature, ServiceFeatureDto>();
}
}

View file

@ -65,6 +65,7 @@ public class PlatformDataSeeder : IDataSeedContributor, ITransientDependency
private readonly IRepository<InstallmentOption, int> _installmentOptionRepository;
private readonly IRepository<CustomComponent, Guid> _customComponentRepository;
private readonly IRepository<ReportCategory, Guid> _reportCategoriesRepository;
private readonly IRepository<Service, Guid> _servicesRepository;
public PlatformDataSeeder(
IRepository<Language, Guid> languages,
@ -102,7 +103,8 @@ public class PlatformDataSeeder : IDataSeedContributor, ITransientDependency
IRepository<PaymentMethod, String> PaymentMethodRepository,
IRepository<InstallmentOption, int> InstallmentOptionRepository,
IRepository<CustomComponent, Guid> CustomComponentRepository,
IRepository<ReportCategory, Guid> ReportCategoriesRepository
IRepository<ReportCategory, Guid> ReportCategoriesRepository,
IRepository<Service, Guid> 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()

View file

@ -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"
]
}
]
}

View file

@ -41,6 +41,7 @@ public class SeederDto
public List<InstallmentOptionSeedDto> InstallmentOptions { get; set; }
public List<CustomComponentSeedDto> CustomComponents { get; set; }
public List<ReportCategorySeedDto> ReportCategories { get; set; }
public List<ServiceSeedDto> 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; }
}

View file

@ -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<Guid>
{
// 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<ServiceFeature> 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<Guid>
{
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;
}
}

View file

@ -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<ReportCategory> ReportCategories { get; set; }
public DbSet<Demo> Demos { get; set; }
public DbSet<Service> Services { get; set; }
public DbSet<ServiceFeature> 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<ServiceFeature>(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<string[]>(v, (JsonSerializerOptions)null)
)
.Metadata
.SetValueComparer(
new ValueComparer<string[]>(
(a, b) => a.SequenceEqual(b),
a => a.Aggregate(0, (c, v) => HashCode.Combine(c, v.GetHashCode())),
a => a.ToArray() // clone
)
);
});
}
}

View file

@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore;
namespace Kurs.Platform.Migrations
{
[DbContext(typeof(PlatformDbContext))]
[Migration("20250820071335_Service")]
[Migration("20250820091253_Service")]
partial class Service
{
/// <inheritdoc />
@ -3486,6 +3486,9 @@ namespace Kurs.Platform.Migrations
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
b.Property<string>("Features")
.HasColumnType("nvarchar(max)");
b.Property<string>("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<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.Property<Guid>("ServiceItemId")
.HasColumnType("uniqueidentifier");
b.HasKey("Id");
b.HasIndex("ServiceItemId");
b.ToTable("PServiceFeature", (string)null);
});
modelBuilder.Entity("Kurs.Platform.Entities.Uom", b =>
{
b.Property<Guid>("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");

View file

@ -20,6 +20,7 @@ namespace Kurs.Platform.Migrations
Title = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false),
Description = table.Column<string>(type: "nvarchar(512)", maxLength: 512, nullable: true),
Type = table.Column<string>(type: "nvarchar(max)", nullable: true),
Features = table.Column<string>(type: "nvarchar(max)", nullable: true),
ExtraProperties = table.Column<string>(type: "nvarchar(max)", nullable: false),
ConcurrencyStamp = table.Column<string>(type: "nvarchar(40)", maxLength: 40, nullable: false),
CreationTime = table.Column<DateTime>(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<Guid>(type: "uniqueidentifier", nullable: false),
ServiceItemId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
Name = table.Column<string>(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");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "PServiceFeature");
migrationBuilder.DropTable(
name: "PService");
}

View file

@ -3483,6 +3483,9 @@ namespace Kurs.Platform.Migrations
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
b.Property<string>("Features")
.HasColumnType("nvarchar(max)");
b.Property<string>("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<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.Property<Guid>("ServiceItemId")
.HasColumnType("uniqueidentifier");
b.HasKey("Id");
b.HasIndex("ServiceItemId");
b.ToTable("PServiceFeature", (string)null);
});
modelBuilder.Entity("Kurs.Platform.Entities.Uom", b =>
{
b.Property<Guid>("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");

View file

@ -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"), {

View file

@ -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

View file

@ -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<ServiceDto[]>(
{
method: 'GET',
url: '/api/app/service',
},
{ apiName: this.apiName },
)
export function getServices() {
return apiService.fetchData<ServiceDto[]>(
{
method: 'GET',
url: '/api/app/service',
},
{ apiName: 'Default' },
)
}

View file

@ -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<ServiceDto[]>([])
const services: ServiceDto[] = [
{
icon: <FaCode className="w-12 h-12 text-blue-600" />,
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: <FaUsers className="w-12 h-12 text-purple-600" />,
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: <FaShieldAlt className="w-12 h-12 text-green-600" />,
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: <FaServer className="w-12 h-12 text-red-600" />,
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: <FaGlobe className="w-12 h-12 text-yellow-600" />,
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: <FaCog className="w-12 h-12 text-indigo-600" />,
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: <FaUsers className="w-12 h-12 text-pink-600" />, // 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: <FaServer className="w-12 h-12 text-orange-600" />, // 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: <FaGlobe className="w-12 h-12 text-cyan-600" />, // 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: <FaCode className="w-12 h-12 text-blue-600" />,
// 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: <FaUsers className="w-12 h-12 text-purple-600" />,
// 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: <FaShieldAlt className="w-12 h-12 text-green-600" />,
// 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: <FaServer className="w-12 h-12 text-red-600" />,
// 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: <FaGlobe className="w-12 h-12 text-yellow-600" />,
// 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: <FaCog className="w-12 h-12 text-indigo-600" />,
// 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: <FaUsers className="w-12 h-12 text-pink-600" />, // 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: <FaServer className="w-12 h-12 text-orange-600" />, // 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: <FaGlobe className="w-12 h-12 text-cyan-600" />, // 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 (
<div className="min-h-screen bg-gray-50">
<Helmet
@ -170,24 +209,33 @@ const Services: React.FC = () => {
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
{services
.filter((a) => a.type === 'service')
.map((service, index) => (
<div
key={index}
className="bg-white rounded-xl shadow-lg p-8 hover:shadow-xl transition-shadow"
>
<div className="mb-6">{service.icon}</div>
<h3 className="text-2xl font-bold text-gray-900 mb-4">{service.title}</h3>
<p className="text-gray-600 mb-6">{service.description}</p>
<ul className="space-y-2">
{service.features.map((feature, fIndex) => (
<li key={fIndex} className="flex items-center text-gray-700">
<span className="w-2 h-2 bg-blue-600 rounded-full mr-2"></span>
{feature}
</li>
))}
</ul>
</div>
))}
.map((service, index) => {
const IconComponent = navigationIcon[service.icon || '']
return (
<div
key={index}
className="bg-white rounded-xl shadow-lg p-8 hover:shadow-xl transition-shadow"
>
<div className="mb-6">
{IconComponent && (
<IconComponent className={`w-12 h-12 ${getRandomColor()}`} />
)}
</div>
<h3 className="text-2xl font-bold text-gray-900 mb-4">
{translate('::' + service.title)}
</h3>
<p className="text-gray-600 mb-6">{translate('::' + service.description)}</p>
<ul className="space-y-2">
{service.features.map((feature, fIndex) => (
<li key={fIndex} className="flex items-center text-gray-700">
<span className="w-2 h-2 bg-blue-600 rounded-full mr-2"></span>
{translate('::' + feature)}
</li>
))}
</ul>
</div>
)
})}
</div>
</div>
</div>
@ -201,29 +249,37 @@ const Services: React.FC = () => {
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
{services
.filter((a) => a.type === 'support')
.map((plan, index) => (
<div
key={index}
className="bg-white rounded-xl shadow-lg p-8 border border-gray-200"
>
<div className="mb-6">{plan.icon}</div>
<h3 className="text-xl font-bold mb-4">{plan.title}</h3>
<ul className="space-y-3 mb-8">
{plan.features.map((feature, fIndex) => (
<li key={fIndex} className="flex items-center space-x-2 text-gray-700">
<FaCheckCircle className="w-5 h-5 text-green-500 flex-shrink-0" />
<span>{feature}</span>
</li>
))}
</ul>
<Link
to={ROUTES_ENUM.public.contact}
className="block text-center bg-blue-600 text-white px-6 py-3 rounded-lg hover:bg-blue-700 transition-colors"
.map((plan, index) => {
const IconComponent = navigationIcon[plan.icon || '']
return (
<div
key={index}
className="bg-white rounded-xl shadow-lg p-8 border border-gray-200"
>
{translate('::Public.services.support.contactButton')}
</Link>
</div>
))}
<div className="mb-6">
{IconComponent && (
<IconComponent className={`w-12 h-12 ${getRandomColor()}`} />
)}
</div>
<h3 className="text-xl font-bold mb-4">{translate('::' + plan.title)}</h3>
<ul className="space-y-3 mb-8">
{plan.features.map((feature, fIndex) => (
<li key={fIndex} className="flex items-center space-x-2 text-gray-700">
<FaCheckCircle className="w-5 h-5 text-green-500 flex-shrink-0" />
<span>{translate('::' + feature)}</span>
</li>
))}
</ul>
<Link
to={ROUTES_ENUM.public.contact}
className="block text-center bg-blue-600 text-white px-6 py-3 rounded-lg hover:bg-blue-700 transition-colors"
>
{translate('::Public.services.support.contactButton')}
</Link>
</div>
)
})}
</div>
</div>
</div>