Event Like özelliği eklendi
This commit is contained in:
parent
0554717bc6
commit
a70d8650f1
21 changed files with 595 additions and 47 deletions
|
|
@ -18,6 +18,7 @@ public class EventDto
|
|||
public UserInfoViewModel User { get; set; }
|
||||
public int ParticipantsCount { get; set; }
|
||||
public int Likes { get; set; }
|
||||
public bool IsLiked { get; set; }
|
||||
public bool IsPublished { get; set; }
|
||||
public string Photos { get; set; }
|
||||
public List<EventCommentDto> Comments { get; set; } = [];
|
||||
|
|
|
|||
|
|
@ -17,4 +17,5 @@ public interface IIntranetAppService : IApplicationService
|
|||
Task IncrementAnnouncementViewCountAsync(System.Guid id);
|
||||
Task<List<EventCommentDto>> GetEventCommentsAsync(Guid eventId);
|
||||
Task<EventCommentDto> CreateEventCommentAsync(Guid eventId, string content);
|
||||
Task<EventDto> LikeEventAsync(Guid id);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ public class IntranetAppService : PlatformAppService, IIntranetAppService
|
|||
private readonly IRepository<SocialMedia, Guid> _socialMediaRepository;
|
||||
private readonly IRepository<SocialPollOption, Guid> _socialPollOptionRepository;
|
||||
private readonly IRepository<EventComment, Guid> _eventCommentRepository;
|
||||
private readonly IRepository<EventLike, Guid> _eventLikeRepository;
|
||||
|
||||
public IntranetAppService(
|
||||
ICurrentTenant currentTenant,
|
||||
|
|
@ -63,7 +64,8 @@ public class IntranetAppService : PlatformAppService, IIntranetAppService
|
|||
IRepository<SocialLike, Guid> socialLikeRepository,
|
||||
IRepository<SocialMedia, Guid> socialMediaRepository,
|
||||
IRepository<SocialPollOption, Guid> socialPollOptionRepository,
|
||||
IRepository<EventComment, Guid> eventCommentRepository
|
||||
IRepository<EventComment, Guid> eventCommentRepository,
|
||||
IRepository<EventLike, Guid> eventLikeRepository
|
||||
)
|
||||
{
|
||||
_currentTenant = currentTenant;
|
||||
|
|
@ -84,6 +86,7 @@ public class IntranetAppService : PlatformAppService, IIntranetAppService
|
|||
_socialMediaRepository = socialMediaRepository;
|
||||
_socialPollOptionRepository = socialPollOptionRepository;
|
||||
_eventCommentRepository = eventCommentRepository;
|
||||
_eventLikeRepository = eventLikeRepository;
|
||||
}
|
||||
|
||||
[UnitOfWork]
|
||||
|
|
@ -141,6 +144,16 @@ public class IntranetAppService : PlatformAppService, IIntranetAppService
|
|||
commentsQueryable.Where(c => eventIds.Contains(c.EventId)).OrderBy(c => c.CreationTime)
|
||||
);
|
||||
|
||||
// Load all likes for these events
|
||||
var likesQueryable = await _eventLikeRepository.GetQueryableAsync();
|
||||
var allLikes = await AsyncExecuter.ToListAsync(
|
||||
likesQueryable.Where(l => eventIds.Contains(l.EventId))
|
||||
);
|
||||
var likedEventIds = allLikes
|
||||
.Where(l => l.UserId == CurrentUser.Id)
|
||||
.Select(l => l.EventId)
|
||||
.ToHashSet();
|
||||
|
||||
// Collect all unique user IDs
|
||||
var userIds = new HashSet<Guid>();
|
||||
foreach (var evt in events)
|
||||
|
|
@ -199,6 +212,7 @@ public class IntranetAppService : PlatformAppService, IIntranetAppService
|
|||
User = user,
|
||||
ParticipantsCount = evt.ParticipantsCount,
|
||||
Likes = evt.Likes,
|
||||
IsLiked = likedEventIds.Contains(evt.Id),
|
||||
IsPublished = evt.isPublished,
|
||||
Photos = evt.Photos,
|
||||
Comments = commentDtos
|
||||
|
|
@ -267,6 +281,43 @@ public class IntranetAppService : PlatformAppService, IIntranetAppService
|
|||
};
|
||||
}
|
||||
|
||||
[HttpPost("api/app/intranet/like-event")]
|
||||
public async Task<EventDto> LikeEventAsync(Guid id)
|
||||
{
|
||||
var evt = await _eventRepository.GetAsync(id);
|
||||
|
||||
var likeQueryable = await _eventLikeRepository.GetQueryableAsync();
|
||||
var existingLike = await AsyncExecuter.FirstOrDefaultAsync(
|
||||
likeQueryable.Where(l => l.EventId == id && l.UserId == CurrentUser.Id));
|
||||
|
||||
bool isNowLiked;
|
||||
if (existingLike != null)
|
||||
{
|
||||
await _eventLikeRepository.DeleteAsync(existingLike.Id);
|
||||
evt.Likes = Math.Max(0, evt.Likes - 1);
|
||||
isNowLiked = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
await _eventLikeRepository.InsertAsync(new EventLike(Guid.NewGuid())
|
||||
{
|
||||
EventId = id,
|
||||
UserId = CurrentUser.Id,
|
||||
});
|
||||
evt.Likes++;
|
||||
isNowLiked = true;
|
||||
}
|
||||
|
||||
await _eventRepository.UpdateAsync(evt, autoSave: true);
|
||||
|
||||
return new EventDto
|
||||
{
|
||||
Id = evt.Id,
|
||||
Likes = evt.Likes,
|
||||
IsLiked = isNowLiked,
|
||||
};
|
||||
}
|
||||
|
||||
private async Task<List<UserInfoViewModel>> GetBirthdaysAsync()
|
||||
{
|
||||
var today = DateTime.Now;
|
||||
|
|
|
|||
|
|
@ -6462,6 +6462,12 @@
|
|||
"tr": "Etkinlikler",
|
||||
"en": "Events"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.Intranet.Events.EventLike",
|
||||
"tr": "Etkinlik Beğenileri",
|
||||
"en": "Event Likes"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "App.Hr.Training",
|
||||
|
|
|
|||
|
|
@ -2759,21 +2759,6 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
|
|||
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
|
||||
PivotSettingsJson = DefaultPivotSettingsJson
|
||||
},
|
||||
new() {
|
||||
ListFormCode = listForm.ListFormCode,
|
||||
CultureName = LanguageCodes.En,
|
||||
SourceDbType = DbType.String,
|
||||
FieldName = "ImageUrl",
|
||||
CaptionName = "App.Listform.ListformField.ImageUrl",
|
||||
Width = 200,
|
||||
ListOrderNo = 5,
|
||||
Visible = true,
|
||||
IsActive = true,
|
||||
AllowSearch = true,
|
||||
ColumnCustomizationJson = DefaultColumnCustomizationJson,
|
||||
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
|
||||
PivotSettingsJson = DefaultPivotSettingsJson
|
||||
},
|
||||
new() {
|
||||
ListFormCode = listForm.ListFormCode,
|
||||
CultureName = LanguageCodes.En,
|
||||
|
|
@ -2781,7 +2766,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
|
|||
FieldName = "Category",
|
||||
CaptionName = "App.Listform.ListformField.Category",
|
||||
Width = 100,
|
||||
ListOrderNo = 6,
|
||||
ListOrderNo = 5,
|
||||
Visible = true,
|
||||
IsActive = true,
|
||||
AllowSearch = true,
|
||||
|
|
@ -2809,7 +2794,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
|
|||
FieldName = "UserId",
|
||||
CaptionName = "App.Listform.ListformField.UserId",
|
||||
Width = 100,
|
||||
ListOrderNo = 7,
|
||||
ListOrderNo = 6,
|
||||
Visible = true,
|
||||
IsActive = true,
|
||||
AllowSearch = true,
|
||||
|
|
@ -2831,7 +2816,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
|
|||
FieldName = "PublishDate",
|
||||
CaptionName = "App.Listform.ListformField.PublishDate",
|
||||
Width = 125,
|
||||
ListOrderNo = 8,
|
||||
ListOrderNo = 7,
|
||||
Visible = true,
|
||||
IsActive = true,
|
||||
AllowSearch = true,
|
||||
|
|
@ -2847,7 +2832,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
|
|||
FieldName = "ExpiryDate",
|
||||
CaptionName = "App.Listform.ListformField.ExpiryDate",
|
||||
Width = 125,
|
||||
ListOrderNo = 9,
|
||||
ListOrderNo = 8,
|
||||
Visible = true,
|
||||
IsActive = true,
|
||||
AllowSearch = true,
|
||||
|
|
@ -2862,6 +2847,21 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
|
|||
FieldName = "IsPinned",
|
||||
CaptionName = "App.Listform.ListformField.IsPinned",
|
||||
Width = 100,
|
||||
ListOrderNo = 9,
|
||||
Visible = true,
|
||||
IsActive = true,
|
||||
AllowSearch = true,
|
||||
ColumnCustomizationJson = DefaultColumnCustomizationJson,
|
||||
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
|
||||
PivotSettingsJson = DefaultPivotSettingsJson
|
||||
},
|
||||
new() {
|
||||
ListFormCode = listForm.ListFormCode,
|
||||
CultureName = LanguageCodes.En,
|
||||
SourceDbType = DbType.String,
|
||||
FieldName = "ImageUrl",
|
||||
CaptionName = "App.Listform.ListformField.ImageUrl",
|
||||
Width = 200,
|
||||
ListOrderNo = 10,
|
||||
Visible = true,
|
||||
IsActive = true,
|
||||
|
|
@ -4162,7 +4162,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
|
|||
DeleteCommand = DefaultDeleteCommand(nameof(TableNameEnum.Event)),
|
||||
DeleteFieldsDefaultValueJson = DefaultDeleteFieldsDefaultValueJson(),
|
||||
PagerOptionJson = DefaultPagerOptionJson,
|
||||
EditingOptionJson = DefaultEditingOptionJson(listFormName, 750, 500, true, true, true, true, false),
|
||||
EditingOptionJson = DefaultEditingOptionJson(listFormName, 750, 500, true, true, true, true, false, true),
|
||||
EditingFormJson = JsonSerializer.Serialize(new List<EditingFormDto>()
|
||||
{
|
||||
new() {
|
||||
|
|
@ -4176,13 +4176,28 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
|
|||
new EditingFormItemDto { Order = 6, DataField = "UserId", ColSpan = 1, IsRequired = true, EditorType2 = EditorTypes.dxSelectBox, EditorOptions=EditorOptionValues.ShowClearButton },
|
||||
new EditingFormItemDto { Order = 7, DataField = "Description", ColSpan = 2, EditorType2 = EditorTypes.dxTextArea },
|
||||
new EditingFormItemDto { Order = 8, DataField = "Status", ColSpan = 1, EditorType2 = EditorTypes.dxSelectBox, EditorOptions=EditorOptionValues.ShowClearButton },
|
||||
new EditingFormItemDto { Order = 9, DataField = "Photos", ColSpan = 1, EditorType2 = EditorTypes.dxImageUpload, EditorOptions = EditorOptionValues.ImageUploadOptions },
|
||||
new EditingFormItemDto { Order = 9, DataField = "ParticipantsCount", ColSpan = 1, EditorType2 = EditorTypes.dxNumberBox },
|
||||
new EditingFormItemDto { Order = 10, DataField = "Photos", ColSpan = 1, EditorType2 = EditorTypes.dxImageUpload, EditorOptions = EditorOptionValues.ImageUploadOptions },
|
||||
]}
|
||||
}),
|
||||
InsertFieldsDefaultValueJson = DefaultInsertFieldsDefaultValueJson(),
|
||||
FormFieldsDefaultValueJson = JsonSerializer.Serialize(new FieldsDefaultValue[] {
|
||||
new() { FieldName = "Status", FieldDbType = DbType.String, Value = "draft", CustomValueType = FieldCustomValueTypeEnum.Value },
|
||||
}),
|
||||
SubFormsJson = JsonSerializer.Serialize(new List<dynamic>() {
|
||||
new {
|
||||
TabType = ListFormTabTypeEnum.List,
|
||||
TabTitle = AppCodes.Intranet.EventLike,
|
||||
Code = AppCodes.Intranet.EventLike,
|
||||
Relation = new List<dynamic>() {
|
||||
new {
|
||||
ParentFieldName = "Id",
|
||||
DbType = DbType.Guid,
|
||||
ChildFieldName = "EventId"
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
|
|
@ -4415,5 +4430,112 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
|
|||
#endregion
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region EventLike
|
||||
listFormName = AppCodes.Intranet.EventLike;
|
||||
if (!await _listFormRepository.AnyAsync(a => a.ListFormCode == listFormName))
|
||||
{
|
||||
var listForm = await _listFormRepository.InsertAsync(
|
||||
new ListForm()
|
||||
{
|
||||
ListFormType = ListFormTypeEnum.List,
|
||||
PageSize = 10,
|
||||
ExportJson = DefaultExportJson,
|
||||
IsSubForm = false,
|
||||
ShowNote = true,
|
||||
LayoutJson = DefaultLayoutJson(),
|
||||
CultureName = LanguageCodes.En,
|
||||
ListFormCode = listFormName,
|
||||
Name = listFormName,
|
||||
Title = listFormName,
|
||||
DataSourceCode = SeedConsts.DataSources.DefaultCode,
|
||||
IsTenant = true,
|
||||
IsBranch = false,
|
||||
IsOrganizationUnit = false,
|
||||
Description = listFormName,
|
||||
SelectCommandType = SelectCommandTypeEnum.Table,
|
||||
SelectCommand = TableNameResolver.GetFullTableName(nameof(TableNameEnum.EventLike)),
|
||||
KeyFieldName = "Id",
|
||||
KeyFieldDbSourceType = DbType.Guid,
|
||||
DefaultFilter = DefaultFilterJson,
|
||||
SortMode = GridOptions.SortModeSingle,
|
||||
FilterRowJson = DefaultFilterRowJson,
|
||||
HeaderFilterJson = DefaultHeaderFilterJson,
|
||||
SearchPanelJson = DefaultSearchPanelJson,
|
||||
GroupPanelJson = DefaultGroupPanelJson,
|
||||
SelectionJson = DefaultSelectionSingleJson,
|
||||
ColumnOptionJson = DefaultColumnOptionJson(),
|
||||
PermissionJson = DefaultPermissionJson(listFormName),
|
||||
DeleteCommand = DefaultDeleteCommand(nameof(TableNameEnum.EventLike)),
|
||||
DeleteFieldsDefaultValueJson = DefaultDeleteFieldsDefaultValueJson(),
|
||||
PagerOptionJson = DefaultPagerOptionJson,
|
||||
EditingOptionJson = DefaultEditingOptionJson(listFormName, 500, 250, true, true, true, true, false),
|
||||
EditingFormJson = JsonSerializer.Serialize(new List<EditingFormDto>() {
|
||||
new() { Order=1, ColCount=1, ColSpan=1, ItemType="group", Items=[
|
||||
new EditingFormItemDto { Order = 1, DataField = "Name", ColSpan = 1, IsRequired = true, EditorType2=EditorTypes.dxTextBox },
|
||||
]}
|
||||
}),
|
||||
InsertFieldsDefaultValueJson = DefaultInsertFieldsDefaultValueJson(),
|
||||
}
|
||||
);
|
||||
|
||||
#region EventLike Fields
|
||||
await _listFormFieldRepository.InsertManyAsync(new ListFormField[] {
|
||||
new() {
|
||||
ListFormCode = listForm.ListFormCode,
|
||||
CultureName = LanguageCodes.En,
|
||||
SourceDbType = DbType.Guid,
|
||||
FieldName = "Id",
|
||||
CaptionName = "App.Listform.ListformField.Id",
|
||||
Width = 100,
|
||||
ListOrderNo = 1,
|
||||
Visible = false,
|
||||
IsActive = true,
|
||||
ValidationRuleJson = DefaultValidationRuleRequiredJson,
|
||||
ColumnCustomizationJson = DefaultColumnCustomizationJson,
|
||||
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
|
||||
PivotSettingsJson = DefaultPivotSettingsJson
|
||||
},
|
||||
new() {
|
||||
ListFormCode = listForm.ListFormCode,
|
||||
CultureName = LanguageCodes.En,
|
||||
SourceDbType = DbType.Guid,
|
||||
FieldName = "UserId",
|
||||
CaptionName = "App.Listform.ListformField.UserId",
|
||||
Width = 500,
|
||||
ListOrderNo = 2,
|
||||
Visible = true,
|
||||
IsActive = true,
|
||||
AllowSearch = true,
|
||||
LookupJson = JsonSerializer.Serialize(new LookupDto {
|
||||
DataSourceType = UiLookupDataSourceTypeEnum.Query,
|
||||
DisplayExpr = "Name",
|
||||
ValueExpr = "Key",
|
||||
LookupQuery = LookupQueryValues.UserValues
|
||||
}),
|
||||
ValidationRuleJson = DefaultValidationRuleRequiredJson,
|
||||
ColumnCustomizationJson = DefaultColumnCustomizationJson,
|
||||
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
|
||||
PivotSettingsJson = DefaultPivotSettingsJson
|
||||
},
|
||||
new() {
|
||||
ListFormCode = listForm.ListFormCode,
|
||||
CultureName = LanguageCodes.En,
|
||||
SourceDbType = DbType.Guid,
|
||||
FieldName = "EventId",
|
||||
CaptionName = "App.Listform.ListformField.EventId",
|
||||
Width = 100,
|
||||
ListOrderNo = 3,
|
||||
Visible = false,
|
||||
IsActive = true,
|
||||
ValidationRuleJson = DefaultValidationRuleRequiredJson,
|
||||
ColumnCustomizationJson = DefaultColumnCustomizationJson,
|
||||
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
|
||||
PivotSettingsJson = DefaultPivotSettingsJson
|
||||
},
|
||||
});
|
||||
#endregion
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3538,6 +3538,71 @@
|
|||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
"Name": "App.Intranet.Events.EventLike",
|
||||
"ParentName": "App.Intranet",
|
||||
"DisplayName": "App.Intranet.Events.EventLike",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
"Name": "App.Intranet.Events.EventLike.Create",
|
||||
"ParentName": "App.Intranet.Events.EventLike",
|
||||
"DisplayName": "Create",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
"Name": "App.Intranet.Events.EventLike.Update",
|
||||
"ParentName": "App.Intranet.Events.EventLike",
|
||||
"DisplayName": "Update",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
"Name": "App.Intranet.Events.EventLike.Delete",
|
||||
"ParentName": "App.Intranet.Events.EventLike",
|
||||
"DisplayName": "Delete",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
"Name": "App.Intranet.Events.EventLike.Export",
|
||||
"ParentName": "App.Intranet.Events.EventLike",
|
||||
"DisplayName": "Export",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
"Name": "App.Intranet.Events.EventLike.Import",
|
||||
"ParentName": "App.Intranet.Events.EventLike",
|
||||
"DisplayName": "Import",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
"Name": "App.Intranet.Events.EventLike.Note",
|
||||
"ParentName": "App.Intranet.Events.EventLike",
|
||||
"DisplayName": "Note",
|
||||
"IsEnabled": true,
|
||||
"MultiTenancySide": 3,
|
||||
"MenuGroup": "Erp|Kurs"
|
||||
},
|
||||
|
||||
{
|
||||
"GroupName": "App.Administration",
|
||||
"Name": "App.Intranet.Announcement",
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ public enum TableNameEnum
|
|||
SocialPollOption,
|
||||
SocialComment,
|
||||
SocialLike,
|
||||
EventLike,
|
||||
EventCategory,
|
||||
EventType,
|
||||
Event,
|
||||
|
|
|
|||
|
|
@ -362,6 +362,7 @@ public static class PlatformConsts
|
|||
public const string EventType = Events + ".EventType";
|
||||
public const string EventCategory = Events + ".EventCategory";
|
||||
public const string Event = Events + ".Event";
|
||||
public const string EventLike = Events + ".EventLike";
|
||||
}
|
||||
|
||||
public static class Definitions
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@ public static class TableNameResolver
|
|||
{ nameof(TableNameEnum.SocialPollOption), (TablePrefix.TenantByName, MenuPrefix.Administration) },
|
||||
{ nameof(TableNameEnum.SocialComment), (TablePrefix.TenantByName, MenuPrefix.Administration) },
|
||||
{ nameof(TableNameEnum.SocialLike), (TablePrefix.TenantByName, MenuPrefix.Administration) },
|
||||
{ nameof(TableNameEnum.EventLike), (TablePrefix.TenantByName, MenuPrefix.Administration) },
|
||||
{ nameof(TableNameEnum.EventCategory), (TablePrefix.TenantByName, MenuPrefix.Administration) },
|
||||
{ nameof(TableNameEnum.EventType), (TablePrefix.TenantByName, MenuPrefix.Administration) },
|
||||
{ nameof(TableNameEnum.Event), (TablePrefix.TenantByName, MenuPrefix.Administration) },
|
||||
|
|
|
|||
|
|
@ -341,6 +341,7 @@ public static class SeedConsts
|
|||
public const string EventType = Events + ".EventType";
|
||||
public const string EventCategory = Events + ".EventCategory";
|
||||
public const string Event = Events + ".Event";
|
||||
public const string EventLike = Events + ".EventLike";
|
||||
}
|
||||
|
||||
public static class Definitions
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ public class Event : FullAuditedEntity<Guid>, IMultiTenant
|
|||
public string Photos { get; set; }
|
||||
|
||||
public ICollection<EventComment> Comments { get; set; } = [];
|
||||
public ICollection<EventLike> EventLikes { get; set; } = [];
|
||||
|
||||
Guid? IMultiTenant.TenantId => TenantId;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
using System;
|
||||
using Volo.Abp.Domain.Entities.Auditing;
|
||||
using Volo.Abp.MultiTenancy;
|
||||
|
||||
namespace Sozsoft.Platform.Entities;
|
||||
|
||||
public class EventLike : FullAuditedEntity<Guid>, IMultiTenant
|
||||
{
|
||||
public Guid? TenantId { get; set; }
|
||||
|
||||
public Guid EventId { get; set; }
|
||||
public Event Event { get; set; }
|
||||
|
||||
public Guid? UserId { get; set; }
|
||||
|
||||
public EventLike(Guid id)
|
||||
{
|
||||
Id = id;
|
||||
}
|
||||
|
||||
protected EventLike() { }
|
||||
|
||||
Guid? IMultiTenant.TenantId => TenantId;
|
||||
}
|
||||
|
|
@ -114,6 +114,7 @@ public class PlatformDbContext :
|
|||
public DbSet<EventCategory> EventCategories { get; set; }
|
||||
public DbSet<EventType> EventTypes { get; set; }
|
||||
public DbSet<EventComment> EventComments { get; set; }
|
||||
public DbSet<EventLike> EventLikes { get; set; }
|
||||
|
||||
public DbSet<Announcement> Announcements { get; set; }
|
||||
|
||||
|
|
@ -1275,6 +1276,17 @@ public class PlatformDbContext :
|
|||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
builder.Entity<EventLike>(b =>
|
||||
{
|
||||
b.ToTable(TableNameResolver.GetFullTableName(nameof(TableNameEnum.EventLike)), Prefix.DbSchema);
|
||||
b.ConfigureByConvention();
|
||||
|
||||
b.HasOne(x => x.Event)
|
||||
.WithMany(x => x.EventLikes)
|
||||
.HasForeignKey(x => x.EventId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
//Videoroom
|
||||
builder.Entity<Videoroom>(b =>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore;
|
|||
namespace Sozsoft.Platform.Migrations
|
||||
{
|
||||
[DbContext(typeof(PlatformDbContext))]
|
||||
[Migration("20260507202053_Initial")]
|
||||
[Migration("20260508144450_Initial")]
|
||||
partial class Initial
|
||||
{
|
||||
/// <inheritdoc />
|
||||
|
|
@ -2146,6 +2146,58 @@ namespace Sozsoft.Platform.Migrations
|
|||
b.ToTable("Adm_T_EventComment", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Sozsoft.Platform.Entities.EventLike", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("datetime2")
|
||||
.HasColumnName("CreationTime");
|
||||
|
||||
b.Property<Guid?>("CreatorId")
|
||||
.HasColumnType("uniqueidentifier")
|
||||
.HasColumnName("CreatorId");
|
||||
|
||||
b.Property<Guid?>("DeleterId")
|
||||
.HasColumnType("uniqueidentifier")
|
||||
.HasColumnName("DeleterId");
|
||||
|
||||
b.Property<DateTime?>("DeletionTime")
|
||||
.HasColumnType("datetime2")
|
||||
.HasColumnName("DeletionTime");
|
||||
|
||||
b.Property<Guid>("EventId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bit")
|
||||
.HasDefaultValue(false)
|
||||
.HasColumnName("IsDeleted");
|
||||
|
||||
b.Property<DateTime?>("LastModificationTime")
|
||||
.HasColumnType("datetime2")
|
||||
.HasColumnName("LastModificationTime");
|
||||
|
||||
b.Property<Guid?>("LastModifierId")
|
||||
.HasColumnType("uniqueidentifier")
|
||||
.HasColumnName("LastModifierId");
|
||||
|
||||
b.Property<Guid?>("TenantId")
|
||||
.HasColumnType("uniqueidentifier")
|
||||
.HasColumnName("TenantId");
|
||||
|
||||
b.Property<Guid?>("UserId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("EventId");
|
||||
|
||||
b.ToTable("Adm_T_EventLike", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Sozsoft.Platform.Entities.EventType", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
|
|
@ -7737,6 +7789,17 @@ namespace Sozsoft.Platform.Migrations
|
|||
b.Navigation("Event");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Sozsoft.Platform.Entities.EventLike", b =>
|
||||
{
|
||||
b.HasOne("Sozsoft.Platform.Entities.Event", "Event")
|
||||
.WithMany("EventLikes")
|
||||
.HasForeignKey("EventId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Event");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Sozsoft.Platform.Entities.JobPosition", b =>
|
||||
{
|
||||
b.HasOne("Sozsoft.Platform.Entities.Department", "Department")
|
||||
|
|
@ -8201,6 +8264,8 @@ namespace Sozsoft.Platform.Migrations
|
|||
modelBuilder.Entity("Sozsoft.Platform.Entities.Event", b =>
|
||||
{
|
||||
b.Navigation("Comments");
|
||||
|
||||
b.Navigation("EventLikes");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Sozsoft.Platform.Entities.EventCategory", b =>
|
||||
|
|
@ -2869,6 +2869,33 @@ namespace Sozsoft.Platform.Migrations
|
|||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Adm_T_EventLike",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
EventId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
UserId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
LastModifierId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
IsDeleted = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
|
||||
DeleterId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
DeletionTime = table.Column<DateTime>(type: "datetime2", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Adm_T_EventLike", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_Adm_T_EventLike_Adm_T_Event_EventId",
|
||||
column: x => x.EventId,
|
||||
principalTable: "Adm_T_Event",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Adm_T_SocialPollOption",
|
||||
columns: table => new
|
||||
|
|
@ -3381,6 +3408,11 @@ namespace Sozsoft.Platform.Migrations
|
|||
table: "Adm_T_EventComment",
|
||||
column: "EventId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Adm_T_EventLike_EventId",
|
||||
table: "Adm_T_EventLike",
|
||||
column: "EventId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Adm_T_JobPosition_DepartmentId",
|
||||
table: "Adm_T_JobPosition",
|
||||
|
|
@ -3790,6 +3822,9 @@ namespace Sozsoft.Platform.Migrations
|
|||
migrationBuilder.DropTable(
|
||||
name: "Adm_T_EventComment");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "Adm_T_EventLike");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "Adm_T_IpRestriction");
|
||||
|
||||
|
|
@ -2143,6 +2143,58 @@ namespace Sozsoft.Platform.Migrations
|
|||
b.ToTable("Adm_T_EventComment", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Sozsoft.Platform.Entities.EventLike", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<DateTime>("CreationTime")
|
||||
.HasColumnType("datetime2")
|
||||
.HasColumnName("CreationTime");
|
||||
|
||||
b.Property<Guid?>("CreatorId")
|
||||
.HasColumnType("uniqueidentifier")
|
||||
.HasColumnName("CreatorId");
|
||||
|
||||
b.Property<Guid?>("DeleterId")
|
||||
.HasColumnType("uniqueidentifier")
|
||||
.HasColumnName("DeleterId");
|
||||
|
||||
b.Property<DateTime?>("DeletionTime")
|
||||
.HasColumnType("datetime2")
|
||||
.HasColumnName("DeletionTime");
|
||||
|
||||
b.Property<Guid>("EventId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bit")
|
||||
.HasDefaultValue(false)
|
||||
.HasColumnName("IsDeleted");
|
||||
|
||||
b.Property<DateTime?>("LastModificationTime")
|
||||
.HasColumnType("datetime2")
|
||||
.HasColumnName("LastModificationTime");
|
||||
|
||||
b.Property<Guid?>("LastModifierId")
|
||||
.HasColumnType("uniqueidentifier")
|
||||
.HasColumnName("LastModifierId");
|
||||
|
||||
b.Property<Guid?>("TenantId")
|
||||
.HasColumnType("uniqueidentifier")
|
||||
.HasColumnName("TenantId");
|
||||
|
||||
b.Property<Guid?>("UserId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("EventId");
|
||||
|
||||
b.ToTable("Adm_T_EventLike", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Sozsoft.Platform.Entities.EventType", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
|
|
@ -7734,6 +7786,17 @@ namespace Sozsoft.Platform.Migrations
|
|||
b.Navigation("Event");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Sozsoft.Platform.Entities.EventLike", b =>
|
||||
{
|
||||
b.HasOne("Sozsoft.Platform.Entities.Event", "Event")
|
||||
.WithMany("EventLikes")
|
||||
.HasForeignKey("EventId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Event");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Sozsoft.Platform.Entities.JobPosition", b =>
|
||||
{
|
||||
b.HasOne("Sozsoft.Platform.Entities.Department", "Department")
|
||||
|
|
@ -8198,6 +8261,8 @@ namespace Sozsoft.Platform.Migrations
|
|||
modelBuilder.Entity("Sozsoft.Platform.Entities.Event", b =>
|
||||
{
|
||||
b.Navigation("Comments");
|
||||
|
||||
b.Navigation("EventLikes");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Sozsoft.Platform.Entities.EventCategory", b =>
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ export interface EventDto {
|
|||
user: UserInfoViewModel
|
||||
participantsCount: number
|
||||
likes: number
|
||||
isLiked: boolean
|
||||
isPublished: boolean
|
||||
photos: string
|
||||
comments: EventCommentDto[]
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { EventCommentDto, IntranetDashboardDto, SocialCommentDto, SocialPostDto } from '@/proxy/intranet/models'
|
||||
import { EventCommentDto, EventDto, IntranetDashboardDto, SocialCommentDto, SocialPostDto } from '@/proxy/intranet/models'
|
||||
import apiService, { Config } from './api.service'
|
||||
|
||||
export interface CreateSocialPostInput {
|
||||
|
|
@ -114,6 +114,16 @@ export class IntranetService {
|
|||
},
|
||||
{ apiName: this.apiName, ...config },
|
||||
)
|
||||
|
||||
likeEvent = (id: string, config?: Partial<Config>) =>
|
||||
apiService.fetchData<EventDto>(
|
||||
{
|
||||
method: 'POST',
|
||||
url: `/api/app/intranet/like-event`,
|
||||
params: { id },
|
||||
},
|
||||
{ apiName: this.apiName, ...config },
|
||||
)
|
||||
}
|
||||
|
||||
export const intranetService = new IntranetService()
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import {
|
|||
FaExpand,
|
||||
FaCommentAlt,
|
||||
FaPaperPlane,
|
||||
FaHeart,
|
||||
} from 'react-icons/fa'
|
||||
import { EventCommentDto, EventDto } from '@/proxy/intranet/models'
|
||||
import useLocale from '@/utils/hooks/useLocale'
|
||||
|
|
@ -56,6 +57,11 @@ const EventModal: React.FC<EventModalProps> = ({ event, onClose }) => {
|
|||
const commentInputRef = useRef<HTMLTextAreaElement>(null)
|
||||
const commentsEndRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
// Likes state
|
||||
const [likes, setLikes] = useState(event.likes)
|
||||
const [isLiked, setIsLiked] = useState(event.isLiked)
|
||||
const [liking, setLiking] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
// Refresh comments from API on open
|
||||
intranetService.getEventComments(event.id).then((res) => {
|
||||
|
|
@ -89,6 +95,27 @@ const EventModal: React.FC<EventModalProps> = ({ event, onClose }) => {
|
|||
}
|
||||
}
|
||||
|
||||
const handleLike = async () => {
|
||||
if (liking) return
|
||||
setLiking(true)
|
||||
// Optimistic update
|
||||
setIsLiked((prev) => !prev)
|
||||
setLikes((prev) => (isLiked ? Math.max(0, prev - 1) : prev + 1))
|
||||
try {
|
||||
const res = await intranetService.likeEvent(event.id)
|
||||
if (res.data) {
|
||||
setLikes(res.data.likes)
|
||||
setIsLiked(res.data.isLiked)
|
||||
}
|
||||
} catch {
|
||||
// Revert on error
|
||||
setIsLiked((prev) => !prev)
|
||||
setLikes((prev) => (isLiked ? prev + 1 : Math.max(0, prev - 1)))
|
||||
} finally {
|
||||
setLiking(false)
|
||||
}
|
||||
}
|
||||
|
||||
const openLightbox = (idx: number) => {
|
||||
setLightboxIndex(idx)
|
||||
setLightboxOpen(true)
|
||||
|
|
@ -151,7 +178,22 @@ const EventModal: React.FC<EventModalProps> = ({ event, onClose }) => {
|
|||
{event.participantsCount}
|
||||
</span>
|
||||
)}
|
||||
<div>
|
||||
<button
|
||||
onClick={handleLike}
|
||||
disabled={liking}
|
||||
className={`flex items-center gap-2 border-0 transition-colors text-xs font-xs border ${
|
||||
isLiked
|
||||
? 'bg-red-50 dark:bg-red-900/20 border-red-200 dark:border-red-800 text-red-600 dark:text-red-400 hover:bg-red-100 dark:hover:bg-red-900/40'
|
||||
: 'bg-white dark:bg-gray-700 border-gray-200 dark:border-gray-600 text-gray-600 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-600'
|
||||
} disabled:opacity-50 disabled:cursor-not-allowed`}
|
||||
>
|
||||
<FaHeart className={`w-4 h-4 ${isLiked ? 'text-red-500' : ''}`} />
|
||||
{likes > 0 && likes}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{event.user && (
|
||||
<div className="flex items-center gap-2 mt-3">
|
||||
<Avatar
|
||||
|
|
@ -319,10 +361,10 @@ const EventModal: React.FC<EventModalProps> = ({ event, onClose }) => {
|
|||
</div>
|
||||
|
||||
{/* Footer */}
|
||||
<div className="p-4 border-t border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-700/50 flex-shrink-0">
|
||||
<div className="p-4 border-t border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-700/50 flex-shrink-0 flex items-center gap-3">
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="w-full px-4 py-2 bg-green-600 hover:bg-green-700 text-white rounded-lg transition-colors text-sm font-medium"
|
||||
className="flex-1 px-4 py-2 bg-green-600 hover:bg-green-700 text-white rounded-lg transition-colors text-sm font-medium"
|
||||
>
|
||||
{translate('::App.Platform.Close')}
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
import React from 'react'
|
||||
import { FaCalendarAlt } from 'react-icons/fa'
|
||||
import { FaCalendarAlt, FaHeart } from 'react-icons/fa'
|
||||
import dayjs from 'dayjs'
|
||||
import { EventDto } from '@/proxy/intranet/models'
|
||||
import useLocale from '@/utils/hooks/useLocale'
|
||||
import { currentLocalDate } from '@/utils/dateUtils'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
import { Avatar } from '@/components/ui'
|
||||
import { AVATAR_URL } from '@/constants/app.constant'
|
||||
|
||||
interface UpcomingEventsProps {
|
||||
events: EventDto[]
|
||||
|
|
@ -45,7 +47,7 @@ const UpcomingEvents: React.FC<UpcomingEventsProps> = ({ events, onEventClick })
|
|||
{translate('::App.Platform.Intranet.Widgets.UpcomingEvents.Title')}
|
||||
</h2>
|
||||
</div>
|
||||
<div className="p-4 space-y-3">
|
||||
<div className="divide-y divide-gray-200 dark:divide-gray-700">
|
||||
{upcomingEvents.length > 0 ? (
|
||||
upcomingEvents.slice(0, 3).map((event) => {
|
||||
const firstPhoto = getFirstPhoto(event.photos)
|
||||
|
|
@ -53,28 +55,59 @@ const UpcomingEvents: React.FC<UpcomingEventsProps> = ({ events, onEventClick })
|
|||
<div
|
||||
key={event.id}
|
||||
onClick={() => onEventClick?.(event)}
|
||||
className={`p-3 rounded-lg border-l-4 bg-gray-50 dark:bg-gray-700/50 border-l-green-500 flex items-center gap-3 ${onEventClick ? 'cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-600/50 transition-colors' : ''}`}
|
||||
className={`p-6 transition-colors ${onEventClick ? 'cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-700/50' : ''}`}
|
||||
>
|
||||
<div className="flex-1 min-w-0">
|
||||
<h4 className="text-sm font-medium text-gray-900 dark:text-white">{event.name}</h4>
|
||||
<p className="text-xs text-gray-600 dark:text-gray-400 mt-1">
|
||||
{currentLocalDate(event.date, currentLocale || 'tr')} - {event.place}
|
||||
</p>
|
||||
<div className="flex items-start gap-4">
|
||||
<div className="flex-1 min-w-0">
|
||||
<h4 className="text-base font-semibold text-gray-900 dark:text-white">{event.name}</h4>
|
||||
<p className="text-xs text-gray-500 dark:text-gray-400 mt-0.5">
|
||||
{currentLocalDate(event.date, currentLocale || 'tr')} - {event.place}
|
||||
</p>
|
||||
{event.description && (
|
||||
<p className="text-sm text-gray-600 dark:text-gray-400 line-clamp-2 mt-1">
|
||||
{event.description}
|
||||
</p>
|
||||
)}
|
||||
<div className="flex items-center gap-2 mt-3 text-xs text-gray-500 dark:text-gray-400">
|
||||
<Avatar
|
||||
size={24}
|
||||
shape="circle"
|
||||
src={AVATAR_URL(event.user.id, event.user.tenantId)}
|
||||
/>
|
||||
<span>{event.user.fullName}</span>
|
||||
<span>•</span>
|
||||
<span>{dayjs(event.date).fromNow()}</span>
|
||||
{event.likes > 0 && (
|
||||
<>
|
||||
<span>•</span>
|
||||
<span className={`flex items-center gap-1 ${event.isLiked ? 'text-red-500' : ''}`}>
|
||||
<FaHeart className="w-3 h-3" />
|
||||
{event.likes}
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{firstPhoto && (
|
||||
<img
|
||||
src={photoSrc(firstPhoto)}
|
||||
alt={event.name}
|
||||
className="w-14 h-14 rounded-lg object-cover flex-shrink-0"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
{firstPhoto && (
|
||||
<img
|
||||
src={photoSrc(firstPhoto)}
|
||||
alt={event.name}
|
||||
className="w-14 h-14 rounded-lg object-cover flex-shrink-0"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
})
|
||||
) : (
|
||||
<p className="text-sm text-gray-500 dark:text-gray-400 text-center py-4">
|
||||
{translate('::App.Platform.Intranet.Widgets.UpcomingEvents.NoEvent')}
|
||||
</p>
|
||||
<div className="text-center py-12">
|
||||
<div className="inline-flex items-center justify-center w-16 h-16 bg-gray-100 dark:bg-gray-700 rounded-full mb-4">
|
||||
<FaCalendarAlt className="w-8 h-8 text-gray-400" />
|
||||
</div>
|
||||
<p className="text-sm text-gray-500 dark:text-gray-400">
|
||||
{translate('::App.Platform.Intranet.Widgets.UpcomingEvents.NoEvent')}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { useEffect, useRef, useState } from 'react'
|
||||
import { APP_NAME } from '@/constants/app.constant'
|
||||
import { getMigrateUrl } from '@/services/setup.service'
|
||||
import { getMigrateUrl, getSetupStatus } from '@/services/setup.service'
|
||||
import { applicationConfigurationUrl } from '@/services/abpConfig.service'
|
||||
|
||||
interface LogLine {
|
||||
|
|
@ -77,6 +77,7 @@ const DatabaseSetup = () => {
|
|||
const [logs, setLogs] = useState<LogLine[]>([])
|
||||
const [status, setStatus] = useState<MigrationStatus>('idle')
|
||||
const [pollCountdown, setPollCountdown] = useState(0)
|
||||
const [dbExists, setDbExists] = useState<boolean | null>(null)
|
||||
const logEndRef = useRef<HTMLDivElement>(null)
|
||||
const pollTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
|
||||
|
||||
|
|
@ -85,6 +86,13 @@ const DatabaseSetup = () => {
|
|||
logEndRef.current?.scrollIntoView({ behavior: 'smooth' })
|
||||
}, [logs])
|
||||
|
||||
// Check DB existence on mount
|
||||
useEffect(() => {
|
||||
getSetupStatus()
|
||||
.then((res) => setDbExists(res.data.dbExists))
|
||||
.catch(() => setDbExists(false))
|
||||
}, [])
|
||||
|
||||
// Cleanup on component unmount
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
|
|
@ -227,7 +235,9 @@ const DatabaseSetup = () => {
|
|||
{/* Action Area */}
|
||||
<div className="flex items-center justify-between px-5 py-4 bg-gray-700 border-t border-gray-600">
|
||||
<div className="text-xs text-gray-400">
|
||||
{status === 'idle' && 'Database not found. Press the button to start migration.'}
|
||||
{status === 'idle' && dbExists === true && 'Database already exists. Migration is not required.'}
|
||||
{status === 'idle' && dbExists === false && 'Database not found. Press the button to start migration.'}
|
||||
{status === 'idle' && dbExists === null && 'Checking database status...'}
|
||||
{status === 'running' && 'Please wait, migration is in progress...'}
|
||||
{status === 'success' && 'Migration completed. Server is restarting...'}
|
||||
{status === 'restarting' &&
|
||||
|
|
@ -237,7 +247,7 @@ const DatabaseSetup = () => {
|
|||
</div>
|
||||
|
||||
<div className="flex gap-3">
|
||||
{(status === 'idle' || status === 'error') && (
|
||||
{(status === 'idle' || status === 'error') && !dbExists && (
|
||||
<button
|
||||
onClick={startMigration}
|
||||
className="px-4 py-2 bg-indigo-600 hover:bg-indigo-500 text-white text-sm font-medium rounded-lg transition-colors"
|
||||
|
|
|
|||
Loading…
Reference in a new issue