diff --git a/api/src/Sozsoft.Platform.Application/Intranet/IntranetAppService.cs b/api/src/Sozsoft.Platform.Application/Intranet/IntranetAppService.cs index 1e64778..d1814e0 100644 --- a/api/src/Sozsoft.Platform.Application/Intranet/IntranetAppService.cs +++ b/api/src/Sozsoft.Platform.Application/Intranet/IntranetAppService.cs @@ -693,8 +693,8 @@ public class IntranetAppService : PlatformAppService, IIntranetAppService if (!Directory.Exists(fullPath)) { - Logger.LogWarning($"Directory not found: {fullPath}"); - return items; + Logger.LogInformation($"Directory not found. Creating: {fullPath}"); + Directory.CreateDirectory(fullPath); } var files = Directory.GetFiles(fullPath); diff --git a/api/src/Sozsoft.Platform.DbMigrator/Seeds/LanguagesData.json b/api/src/Sozsoft.Platform.DbMigrator/Seeds/LanguagesData.json index 4df81ab..4d77bfc 100644 --- a/api/src/Sozsoft.Platform.DbMigrator/Seeds/LanguagesData.json +++ b/api/src/Sozsoft.Platform.DbMigrator/Seeds/LanguagesData.json @@ -6648,6 +6648,12 @@ "tr": "Intranet", "en": "Intranet" }, + { + "resourceName": "Platform", + "key": "App.Intranet.SocialLike", + "tr": "Sosyal Beğeniler", + "en": "Social Likes" + }, { "resourceName": "Platform", "key": "App.Intranet.SocialComment", diff --git a/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Administration.cs b/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Administration.cs index c4a3c57..2479a3d 100644 --- a/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Administration.cs +++ b/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Administration.cs @@ -3423,7 +3423,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep DeleteCommand = DefaultDeleteCommand(nameof(TableNameEnum.SurveyQuestion)), DeleteFieldsDefaultValueJson = DefaultDeleteFieldsDefaultValueJson(), PagerOptionJson = DefaultPagerOptionJson, - EditingOptionJson = DefaultEditingOptionJson(listFormName, 500, 400, true, true, true, true, false, true), + EditingOptionJson = DefaultEditingOptionJson(listFormName, 700, 400, true, true, true, true, false, true), InsertFieldsDefaultValueJson = DefaultInsertFieldsDefaultValueJson(), EditingFormJson = JsonSerializer.Serialize(new List() { @@ -3738,8 +3738,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep new() { Order=1, ColCount=1, ColSpan=1, ItemType="group", Items =[ new EditingFormItemDto { Order = 1, DataField = "UserId", ColSpan=1, EditorType2 = EditorTypes.dxSelectBox, EditorOptions=EditorOptionValues.ShowClearButton }, - new EditingFormItemDto { Order = 2, DataField = "SubmissionTime", ColSpan=1, EditorType2 = EditorTypes.dxTextBox }, - new EditingFormItemDto { Order = 3, DataField = "CreationTime", ColSpan=1, EditorType2 = EditorTypes.dxDateBox } + new EditingFormItemDto { Order = 2, DataField = "SubmissionTime", ColSpan=1, EditorType2 = EditorTypes.dxDateBox }, ]} }), SubFormsJson = JsonSerializer.Serialize(new List() { @@ -3756,10 +3755,6 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep } } }), - FormFieldsDefaultValueJson = JsonSerializer.Serialize(new FieldsDefaultValue[] - { - new() { FieldName = "CreationTime", FieldDbType = DbType.DateTime, Value = "@NOW", CustomValueType = FieldCustomValueTypeEnum.CustomKey } - }) }, autoSave: true ); @@ -3819,22 +3814,6 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep PermissionJson = DefaultFieldPermissionJson(listForm.Name), PivotSettingsJson = DefaultPivotSettingsJson }, - new() { - ListFormCode = listForm.ListFormCode, - CultureName = LanguageCodes.En, - SourceDbType = DbType.DateTime, - FieldName = "CreationTime", - CaptionName = "App.Listform.ListformField.CreationTime", - Width = 0, - ListOrderNo = 4, - Visible = true, - IsActive = true, - AllowSearch = true, - ValidationRuleJson = DefaultValidationRuleRequiredJson, - ColumnCustomizationJson = DefaultColumnCustomizationJson, - PermissionJson = DefaultFieldPermissionJson(listForm.Name), - PivotSettingsJson = DefaultPivotSettingsJson - }, new() { ListFormCode = listForm.ListFormCode, CultureName = LanguageCodes.En, @@ -3842,7 +3821,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep FieldName = "SurveyId", CaptionName = "App.Listform.ListformField.SurveyId", Width = 0, - ListOrderNo = 5, + ListOrderNo = 4, Visible = false, IsActive = true, AllowSearch = true, @@ -4053,6 +4032,18 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep ChildFieldName = "SocialPostId" } } + }, + new { + TabType = ListFormTabTypeEnum.List, + TabTitle = AppCodes.Intranet.SocialLike, + Code = AppCodes.Intranet.SocialLike, + Relation = new List() { + new { + ParentFieldName = "Id", + DbType = DbType.Guid, + ChildFieldName = "SocialPostId" + } + } } }) } @@ -4269,6 +4260,114 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep } #endregion + #region Social Like + listFormName = AppCodes.Intranet.SocialLike; + 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 = false, + 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.SocialLike)), + 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.SocialLike)), + DeleteFieldsDefaultValueJson = DefaultDeleteFieldsDefaultValueJson(), + PagerOptionJson = DefaultPagerOptionJson, + EditingOptionJson = DefaultEditingOptionJson(listFormName, 500, 250, true, true, true, true, false), + EditingFormJson = JsonSerializer.Serialize(new List() { + new() { Order=1, ColCount=1, ColSpan=1, ItemType="group", Items=[ + new EditingFormItemDto { Order = 1, DataField = "UserId", ColSpan = 1, EditorType2=EditorTypes.dxSelectBox }, + ]} + }), + InsertFieldsDefaultValueJson = DefaultInsertFieldsDefaultValueJson(), + } + ); + + #region Social Like Fields + await _listFormFieldRepository.InsertManyAsync([ + new() { + ListFormCode = listForm.ListFormCode, + CultureName = LanguageCodes.En, + SourceDbType = DbType.Guid, + FieldName = "Id", + CaptionName = "App.Listform.ListformField.Id", + Width = 0, + 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 = 0, + 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 = "SocialPostId", + CaptionName = "App.Listform.ListformField.SocialPostId", + Width = 0, + ListOrderNo = 3, + Visible = false, + IsActive = true, + AllowSearch = true, + ValidationRuleJson = DefaultValidationRuleRequiredJson, + ColumnCustomizationJson = DefaultColumnCustomizationJson, + PermissionJson = DefaultFieldPermissionJson(listForm.Name), + PivotSettingsJson = DefaultPivotSettingsJson + } + ]); + #endregion + } + #endregion + #region EventType listFormName = AppCodes.Intranet.EventType; if (!await _listFormRepository.AnyAsync(a => a.ListFormCode == listFormName)) diff --git a/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_DefaultJsons.cs b/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_DefaultJsons.cs index c147922..54a5662 100644 --- a/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_DefaultJsons.cs +++ b/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_DefaultJsons.cs @@ -121,6 +121,12 @@ public static class ListFormSeeder_DefaultJsons { IsPivot = true }); + public static string DefaultGroupingJson(int groupIndex) => JsonSerializer.Serialize(new ColumnGroupingDto + { + AllowGrouping = true, + GroupIndex = groupIndex, + AutoExpandGroup = false + }); public static readonly string DefaultValidationRuleRequiredJson = JsonSerializer.Serialize(new ValidationRuleDto[] { new() { Type = Enum.GetName(UiColumnValidationRuleTypeEnum.required) } diff --git a/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Saas.cs b/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Saas.cs index 3f7a6f3..119df24 100644 --- a/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Saas.cs +++ b/api/src/Sozsoft.Platform.DbMigrator/Seeds/ListFormSeeder_Saas.cs @@ -3297,7 +3297,8 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency ValidationRuleJson = DefaultValidationRuleRequiredJson, ColumnCustomizationJson = DefaultColumnCustomizationJson, PermissionJson = DefaultFieldPermissionJson(listForm.Name), - PivotSettingsJson = DefaultPivotSettingsJson + PivotSettingsJson = DefaultPivotSettingsJson, + GroupingJson = DefaultGroupingJson(1) }, new ListFormField { @@ -3321,7 +3322,8 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency ValidationRuleJson = DefaultValidationRuleRequiredJson, ColumnCustomizationJson = DefaultColumnCustomizationJson, PermissionJson = DefaultFieldPermissionJson(listForm.Name), - PivotSettingsJson = DefaultPivotSettingsJson + PivotSettingsJson = DefaultPivotSettingsJson, + GroupingJson = DefaultGroupingJson(2) }, new ListFormField { diff --git a/api/src/Sozsoft.Platform.DbMigrator/Seeds/PermissionsData.json b/api/src/Sozsoft.Platform.DbMigrator/Seeds/PermissionsData.json index a60008e..8a56479 100644 --- a/api/src/Sozsoft.Platform.DbMigrator/Seeds/PermissionsData.json +++ b/api/src/Sozsoft.Platform.DbMigrator/Seeds/PermissionsData.json @@ -3934,7 +3934,6 @@ "MultiTenancySide": 3, "MenuGroup": "Erp|Kurs" }, - { "GroupName": "App.Administration", "Name": "App.Intranet.Announcement.AnnouncementComment", @@ -3989,7 +3988,6 @@ "MultiTenancySide": 3, "MenuGroup": "Erp|Kurs" }, - { "GroupName": "App.Administration", "Name": "App.Intranet.SocialPost", @@ -4116,6 +4114,60 @@ "MultiTenancySide": 3, "MenuGroup": "Erp|Kurs" }, + { + "GroupName": "App.Administration", + "Name": "App.Intranet.SocialLike", + "ParentName": "App.Intranet", + "DisplayName": "App.Intranet.SocialLike", + "IsEnabled": true, + "MultiTenancySide": 3, + "MenuGroup": "Erp|Kurs" + }, + { + "GroupName": "App.Administration", + "Name": "App.Intranet.SocialLike.Create", + "ParentName": "App.Intranet.SocialLike", + "DisplayName": "Create", + "IsEnabled": true, + "MultiTenancySide": 3, + "MenuGroup": "Erp|Kurs" + }, + { + "GroupName": "App.Administration", + "Name": "App.Intranet.SocialLike.Update", + "ParentName": "App.Intranet.SocialLike", + "DisplayName": "Update", + "IsEnabled": true, + "MultiTenancySide": 3, + "MenuGroup": "Erp|Kurs" + }, + { + "GroupName": "App.Administration", + "Name": "App.Intranet.SocialLike.Delete", + "ParentName": "App.Intranet.SocialLike", + "DisplayName": "Delete", + "IsEnabled": true, + "MultiTenancySide": 3, + "MenuGroup": "Erp|Kurs" + }, + { + "GroupName": "App.Administration", + "Name": "App.Intranet.SocialLike.Export", + "ParentName": "App.Intranet.SocialLike", + "DisplayName": "Export", + "IsEnabled": true, + "MultiTenancySide": 3, + "MenuGroup": "Erp|Kurs" + }, + { + "GroupName": "App.Administration", + "Name": "App.Intranet.SocialLike.Import", + "ParentName": "App.Intranet.SocialLike", + "DisplayName": "Import", + "IsEnabled": true, + "MultiTenancySide": 3, + "MenuGroup": "Erp|Kurs" + }, { "GroupName": "App.Administration", "Name": "App.Intranet.Survey", @@ -4459,4 +4511,4 @@ "MenuGroup": "Kurs" } ] -} +} \ No newline at end of file diff --git a/api/src/Sozsoft.Platform.Domain/Data/SeedConsts.cs b/api/src/Sozsoft.Platform.Domain/Data/SeedConsts.cs index 029404e..2859344 100644 --- a/api/src/Sozsoft.Platform.Domain/Data/SeedConsts.cs +++ b/api/src/Sozsoft.Platform.Domain/Data/SeedConsts.cs @@ -338,6 +338,7 @@ public static class SeedConsts public const string SocialPost = Default + ".SocialPost"; public const string SocialComment = Default + ".SocialComment"; + public const string SocialLike = Default + ".SocialLike"; public const string Events = Default + ".Events"; public const string EventType = Events + ".EventType"; diff --git a/api/src/Sozsoft.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformDbContext.cs b/api/src/Sozsoft.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformDbContext.cs index 755706a..2af5040 100644 --- a/api/src/Sozsoft.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformDbContext.cs +++ b/api/src/Sozsoft.Platform.EntityFrameworkCore/EntityFrameworkCore/PlatformDbContext.cs @@ -1174,6 +1174,8 @@ public class PlatformDbContext : b.ToTable(TableNameResolver.GetFullTableName(nameof(TableNameEnum.AnnouncementLike)), Prefix.DbSchema); b.ConfigureByConvention(); + b.HasIndex(x => new { x.AnnouncementId, x.UserId }).IsUnique().HasFilter("[IsDeleted] = 0"); + b.HasOne(x => x.Announcement) .WithMany(x => x.AnnouncementLikes) .HasForeignKey(x => x.AnnouncementId) @@ -1229,6 +1231,8 @@ public class PlatformDbContext : b.Property(x => x.SubmissionTime).IsRequired(); + b.HasIndex(x => new { x.SurveyId, x.UserId }).IsUnique().HasFilter("[IsDeleted] = 0"); + b.HasOne(x => x.Survey) .WithMany(x => x.SurveyResponses) .HasForeignKey(x => x.SurveyId) @@ -1326,6 +1330,8 @@ public class PlatformDbContext : b.ToTable(TableNameResolver.GetFullTableName(nameof(TableNameEnum.SocialLike)), Prefix.DbSchema); b.ConfigureByConvention(); + b.HasIndex(x => new { x.SocialPostId, x.UserId }).IsUnique().HasFilter("[IsDeleted] = 0"); + b.HasOne(x => x.SocialPost) .WithMany(x => x.Likes) .HasForeignKey(x => x.SocialPostId) @@ -1396,6 +1402,8 @@ public class PlatformDbContext : b.ToTable(TableNameResolver.GetFullTableName(nameof(TableNameEnum.EventLike)), Prefix.DbSchema); b.ConfigureByConvention(); + b.HasIndex(x => new { x.EventId, x.UserId }).IsUnique().HasFilter("[IsDeleted] = 0"); + b.HasOne(x => x.Event) .WithMany(x => x.EventLikes) .HasForeignKey(x => x.EventId) diff --git a/api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/20260616123136_Initial.Designer.cs b/api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/20260619185755_Initial.Designer.cs similarity index 99% rename from api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/20260616123136_Initial.Designer.cs rename to api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/20260619185755_Initial.Designer.cs index 6ef80b1..938a71d 100644 --- a/api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/20260616123136_Initial.Designer.cs +++ b/api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/20260619185755_Initial.Designer.cs @@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore; namespace Sozsoft.Platform.Migrations { [DbContext(typeof(PlatformDbContext))] - [Migration("20260616123136_Initial")] + [Migration("20260619185755_Initial")] partial class Initial { /// @@ -912,7 +912,9 @@ namespace Sozsoft.Platform.Migrations b.HasKey("Id"); - b.HasIndex("AnnouncementId"); + b.HasIndex("AnnouncementId", "UserId") + .IsUnique() + .HasFilter("[IsDeleted] = 0"); b.ToTable("Adm_T_AnnouncementLike", (string)null); }); @@ -2512,7 +2514,9 @@ namespace Sozsoft.Platform.Migrations b.HasKey("Id"); - b.HasIndex("EventId"); + b.HasIndex("EventId", "UserId") + .IsUnique() + .HasFilter("[IsDeleted] = 0"); b.ToTable("Adm_T_EventLike", (string)null); }); @@ -4885,7 +4889,9 @@ namespace Sozsoft.Platform.Migrations b.HasKey("Id"); - b.HasIndex("SocialPostId"); + b.HasIndex("SocialPostId", "UserId") + .IsUnique() + .HasFilter("[IsDeleted] = 0"); b.ToTable("Adm_T_SocialLike", (string)null); }); @@ -5464,7 +5470,9 @@ namespace Sozsoft.Platform.Migrations b.HasKey("Id"); - b.HasIndex("SurveyId"); + b.HasIndex("SurveyId", "UserId") + .IsUnique() + .HasFilter("[IsDeleted] = 0"); b.ToTable("Adm_T_SurveyResponse", (string)null); }); diff --git a/api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/20260616123136_Initial.cs b/api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/20260619185755_Initial.cs similarity index 99% rename from api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/20260616123136_Initial.cs rename to api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/20260619185755_Initial.cs index 8d249e1..003a7a4 100644 --- a/api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/20260616123136_Initial.cs +++ b/api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/20260619185755_Initial.cs @@ -3626,9 +3626,11 @@ namespace Sozsoft.Platform.Migrations column: "AnnouncementId"); migrationBuilder.CreateIndex( - name: "IX_Adm_T_AnnouncementLike_AnnouncementId", + name: "IX_Adm_T_AnnouncementLike_AnnouncementId_UserId", table: "Adm_T_AnnouncementLike", - column: "AnnouncementId"); + columns: new[] { "AnnouncementId", "UserId" }, + unique: true, + filter: "[IsDeleted] = 0"); migrationBuilder.CreateIndex( name: "IX_Adm_T_Department_TenantId_Name", @@ -3667,9 +3669,11 @@ namespace Sozsoft.Platform.Migrations column: "EventId"); migrationBuilder.CreateIndex( - name: "IX_Adm_T_EventLike_EventId", + name: "IX_Adm_T_EventLike_EventId_UserId", table: "Adm_T_EventLike", - column: "EventId"); + columns: new[] { "EventId", "UserId" }, + unique: true, + filter: "[IsDeleted] = 0"); migrationBuilder.CreateIndex( name: "IX_Adm_T_EventType_TenantId_Name", @@ -3753,9 +3757,11 @@ namespace Sozsoft.Platform.Migrations column: "SocialPostId"); migrationBuilder.CreateIndex( - name: "IX_Adm_T_SocialLike_SocialPostId", + name: "IX_Adm_T_SocialLike_SocialPostId_UserId", table: "Adm_T_SocialLike", - column: "SocialPostId"); + columns: new[] { "SocialPostId", "UserId" }, + unique: true, + filter: "[IsDeleted] = 0"); migrationBuilder.CreateIndex( name: "IX_Adm_T_SocialLocation_SocialPostId", @@ -3802,9 +3808,11 @@ namespace Sozsoft.Platform.Migrations column: "QuestionId"); migrationBuilder.CreateIndex( - name: "IX_Adm_T_SurveyResponse_SurveyId", + name: "IX_Adm_T_SurveyResponse_SurveyId_UserId", table: "Adm_T_SurveyResponse", - column: "SurveyId"); + columns: new[] { "SurveyId", "UserId" }, + unique: true, + filter: "[IsDeleted] = 0"); migrationBuilder.CreateIndex( name: "IX_Adm_T_Videoroom_TenantId_BranchId_Name", diff --git a/api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/PlatformDbContextModelSnapshot.cs b/api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/PlatformDbContextModelSnapshot.cs index 5c326e1..eba8393 100644 --- a/api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/PlatformDbContextModelSnapshot.cs +++ b/api/src/Sozsoft.Platform.EntityFrameworkCore/Migrations/PlatformDbContextModelSnapshot.cs @@ -909,7 +909,9 @@ namespace Sozsoft.Platform.Migrations b.HasKey("Id"); - b.HasIndex("AnnouncementId"); + b.HasIndex("AnnouncementId", "UserId") + .IsUnique() + .HasFilter("[IsDeleted] = 0"); b.ToTable("Adm_T_AnnouncementLike", (string)null); }); @@ -2509,7 +2511,9 @@ namespace Sozsoft.Platform.Migrations b.HasKey("Id"); - b.HasIndex("EventId"); + b.HasIndex("EventId", "UserId") + .IsUnique() + .HasFilter("[IsDeleted] = 0"); b.ToTable("Adm_T_EventLike", (string)null); }); @@ -4882,7 +4886,9 @@ namespace Sozsoft.Platform.Migrations b.HasKey("Id"); - b.HasIndex("SocialPostId"); + b.HasIndex("SocialPostId", "UserId") + .IsUnique() + .HasFilter("[IsDeleted] = 0"); b.ToTable("Adm_T_SocialLike", (string)null); }); @@ -5461,7 +5467,9 @@ namespace Sozsoft.Platform.Migrations b.HasKey("Id"); - b.HasIndex("SurveyId"); + b.HasIndex("SurveyId", "UserId") + .IsUnique() + .HasFilter("[IsDeleted] = 0"); b.ToTable("Adm_T_SurveyResponse", (string)null); }); diff --git a/ui/src/components/template/MessengerWidget.tsx b/ui/src/components/template/MessengerWidget.tsx index e07a331..ff2a632 100644 --- a/ui/src/components/template/MessengerWidget.tsx +++ b/ui/src/components/template/MessengerWidget.tsx @@ -27,6 +27,7 @@ import { FaSearch, FaTimes, FaTrash, + FaUsers, } from 'react-icons/fa' import { IoCheckmarkDone, IoChatbubbleEllipsesOutline, IoSend } from 'react-icons/io5' import { useLocalization } from '@/utils/hooks/useLocalization' @@ -315,413 +316,451 @@ const MessengerWidget = () => { if (!auth.session.signedIn) return null const panelClassName = maximized - ? 'pointer-events-auto fixed inset-2 overflow-hidden rounded-lg border border-gray-200 bg-white shadow-2xl dark:border-gray-700 dark:bg-gray-800 sm:inset-4' - : 'pointer-events-auto fixed inset-x-2 bottom-20 top-3 overflow-hidden rounded-lg border border-gray-200 bg-white shadow-2xl dark:border-gray-700 dark:bg-gray-800 sm:absolute sm:inset-auto sm:bottom-16 sm:right-0 sm:h-[min(70vh,640px)] sm:w-[min(78vw,800px)]' + ? 'pointer-events-auto fixed inset-2 z-[51] overflow-hidden rounded-xl border border-blue-300 bg-slate-50 shadow-[0_24px_80px_rgba(15,23,42,0.45)] dark:border-blue-800 dark:bg-slate-900 sm:inset-4' + : 'pointer-events-auto fixed inset-x-2 bottom-20 top-3 z-[51] overflow-hidden rounded-xl border border-blue-300 bg-slate-50 shadow-[0_24px_80px_rgba(15,23,42,0.45)] dark:border-blue-800 dark:bg-slate-900 sm:inset-auto sm:bottom-20 sm:right-5 sm:h-[min(75vh,680px)] sm:w-[min(78vw,800px)]' + + const headerActionClassName = 'text-white hover:bg-white/15 hover:text-white active:bg-white/25' return ( -
+ <> {open && ( -
-
- - -
-
-
-
-
- +
+ } + placeholder={translate('::MessengerWidget.SearchPerson')} + onChange={(event) => setFilter(event.target.value)} + /> +
+
+ +
+ {contacts.map((contact) => { + const active = selectedIds.includes(contact.id) + const contactUnread = unreadByContact[contact.id] || 0 + return ( + + ) + })} +
+ + +
+
+
+
+
-
-
- {visibleMessages.length === 0 && ( -
- {translate('::MessengerWidget.NoMessagesYet')} +
+ {visibleMessages.length === 0 && ( +
+ {translate('::MessengerWidget.NoMessagesYet')} +
+ )} + + {visibleMessages.map((message) => { + const own = message.senderId === auth.user.id + const deletable = canDeleteMessage(message, auth.user.id) + return ( +
+
+
+
+ + + {own + ? auth.user.name || + auth.user.userName || + translate('::MessengerWidget.Me') + : message.senderName} + +
+ {message.text && ( +
+ {message.text} +
+ )} + {message.attachments.length > 0 && ( +
+ {message.attachments.map((file) => ( + + {file.fileName} + + {formatFileSize(file.fileSize)} + + + ))} +
+ )} +
+ {dayjs(message.sentAt).format('HH:mm')} +
+
+ {own && deletable && ( + + )} +
+
+ ) + })} +
+
+ + {selectedIds.length > 0 && attachments.length > 0 && ( +
+ {attachments.map((file) => ( + + {file.fileName} + + + ))}
)} - {visibleMessages.map((message) => { - const own = message.senderId === auth.user.id - const deletable = canDeleteMessage(message, auth.user.id) - return ( -
-
-
-
- - - {own - ? auth.user.name || - auth.user.userName || - translate('::MessengerWidget.Me') - : message.senderName} - -
- {message.text && ( -
- {message.text} -
- )} - {message.attachments.length > 0 && ( -
- {message.attachments.map((file) => ( - - {file.fileName} - - {formatFileSize(file.fileSize)} - - - ))} -
- )} -
- {dayjs(message.sentAt).format('HH:mm')} -
-
- {own && deletable && ( - - )} + {selectedIds.length > 0 && ( +
+ {showEmoji && ( +
+
-
- ) - })} -
-
- - {selectedIds.length > 0 && attachments.length > 0 && ( -
- {attachments.map((file) => ( - - {file.fileName} - - - ))} -
- )} - - {selectedIds.length > 0 && ( -
- {showEmoji && ( -
- + handleFiles(event.target.files)} /> -
- )} -
- handleFiles(event.target.files)} - /> - -