Intranet App Service ve Intranet Dashboard
This commit is contained in:
parent
0e102b3dfc
commit
c350acbf2a
101 changed files with 8321 additions and 1362 deletions
|
|
@ -0,0 +1,13 @@
|
||||||
|
using System;
|
||||||
|
using Volo.Abp.Application.Dtos;
|
||||||
|
|
||||||
|
namespace Sozsoft.Platform.Hr;
|
||||||
|
|
||||||
|
public class DepartmentDto : FullAuditedEntityDto<Guid>
|
||||||
|
{
|
||||||
|
public Guid? TenantId { get; set; }
|
||||||
|
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
public Guid? ParentId { get; set; }
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
using System;
|
||||||
|
using Volo.Abp.Application.Dtos;
|
||||||
|
|
||||||
|
namespace Sozsoft.Platform.Hr;
|
||||||
|
|
||||||
|
public class JobPositionDto : FullAuditedEntityDto<Guid>
|
||||||
|
{
|
||||||
|
public Guid? TenantId { get; set; }
|
||||||
|
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
public Guid DepartmentId { get; set; }
|
||||||
|
|
||||||
|
public Guid? ParentId { get; set; }
|
||||||
|
}
|
||||||
|
|
@ -4,13 +4,15 @@ using Volo.Abp.ObjectExtending;
|
||||||
|
|
||||||
namespace Sozsoft.Platform.Identity.Dto;
|
namespace Sozsoft.Platform.Identity.Dto;
|
||||||
|
|
||||||
public class UserInfoViewModel: ExtensibleObject
|
public class UserInfoViewModel : ExtensibleObject
|
||||||
{
|
{
|
||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
|
public Guid? TenantId { get; set; }
|
||||||
public string ConcurrencyStamp { get; set; }
|
public string ConcurrencyStamp { get; set; }
|
||||||
public string UserName { get; set; }
|
public string UserName { get; set; }
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public string Surname { get; set; }
|
public string Surname { get; set; }
|
||||||
|
public string FullName => $"{Name} {Surname}".TrimEnd();
|
||||||
public string Email { get; set; }
|
public string Email { get; set; }
|
||||||
public string PhoneNumber { get; set; }
|
public string PhoneNumber { get; set; }
|
||||||
public bool IsActive { get; set; }
|
public bool IsActive { get; set; }
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
using System;
|
||||||
|
using Sozsoft.Platform.Identity.Dto;
|
||||||
|
using Volo.Abp.Application.Dtos;
|
||||||
|
|
||||||
|
namespace Sozsoft.Platform.Intranet;
|
||||||
|
|
||||||
|
public class AnnouncementDto : FullAuditedEntityDto<Guid>
|
||||||
|
{
|
||||||
|
public Guid? TenantId { get; set; }
|
||||||
|
|
||||||
|
public string Title { get; set; }
|
||||||
|
public string Excerpt { get; set; }
|
||||||
|
public string Content { get; set; }
|
||||||
|
public string ImageUrl { get; set; }
|
||||||
|
public string Category { get; set; }
|
||||||
|
public Guid? UserId { get; set; }
|
||||||
|
public UserInfoViewModel User { get; set; }
|
||||||
|
public DateTime PublishDate { get; set; }
|
||||||
|
public DateTime? ExpiryDate { get; set; }
|
||||||
|
public bool IsPinned { get; set; }
|
||||||
|
public int ViewCount { get; set; }
|
||||||
|
public string Attachments { get; set; }
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Volo.Abp.Application.Services;
|
||||||
|
|
||||||
|
namespace Sozsoft.Platform.Intranet;
|
||||||
|
|
||||||
|
public interface IIntranetAppService : IApplicationService
|
||||||
|
{
|
||||||
|
Task<IntranetDashboardDto> GetIntranetDashboardAsync();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Sozsoft.Platform.FileManagement;
|
||||||
|
using Sozsoft.Platform.Identity.Dto;
|
||||||
|
|
||||||
|
namespace Sozsoft.Platform.Intranet;
|
||||||
|
|
||||||
|
public class IntranetDashboardDto
|
||||||
|
{
|
||||||
|
public List<UserInfoViewModel> Birthdays { get; set; } = [];
|
||||||
|
public List<FileItemDto> Documents { get; set; } = [];
|
||||||
|
public List<AnnouncementDto> Announcements { get; set; } = [];
|
||||||
|
public List<SurveyDto> Surveys { get; set; } = [];
|
||||||
|
public List<SocialPostDto> SocialPosts { get; set; } = [];
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,69 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Sozsoft.Platform.Identity.Dto;
|
||||||
|
using Volo.Abp.Application.Dtos;
|
||||||
|
|
||||||
|
namespace Sozsoft.Platform.Intranet;
|
||||||
|
|
||||||
|
public class SocialPostDto : FullAuditedEntityDto<Guid>
|
||||||
|
{
|
||||||
|
public Guid? UserId { get; set; }
|
||||||
|
public UserInfoViewModel? User { get; set; }
|
||||||
|
public string Content { get; set; }
|
||||||
|
|
||||||
|
public int LikeCount { get; set; }
|
||||||
|
public bool IsLiked { get; set; }
|
||||||
|
public bool IsOwnPost { get; set; }
|
||||||
|
|
||||||
|
public SocialLocationDto? Location { get; set; }
|
||||||
|
public SocialMediaDto? Media { get; set; }
|
||||||
|
public List<SocialCommentDto> Comments { get; set; }
|
||||||
|
public List<SocialLikeDto> Likes { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SocialLocationDto : FullAuditedEntityDto<Guid>
|
||||||
|
{
|
||||||
|
public Guid SocialPostId { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string? Address { get; set; }
|
||||||
|
public double? Lat { get; set; }
|
||||||
|
public double? Lng { get; set; }
|
||||||
|
public string? PlaceId { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SocialMediaDto : FullAuditedEntityDto<Guid>
|
||||||
|
{
|
||||||
|
public Guid SocialPostId { get; set; }
|
||||||
|
public string Type { get; set; } // image | video | poll
|
||||||
|
public string[] Urls { get; set; }
|
||||||
|
|
||||||
|
// Poll Fields
|
||||||
|
public string? PollQuestion { get; set; }
|
||||||
|
public int? PollTotalVotes { get; set; }
|
||||||
|
public DateTime? PollEndsAt { get; set; }
|
||||||
|
public string? PollUserVoteId { get; set; }
|
||||||
|
|
||||||
|
public List<SocialPollOptionDto> PollOptions { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SocialPollOptionDto : FullAuditedEntityDto<Guid>
|
||||||
|
{
|
||||||
|
public Guid SocialMediaId { get; set; }
|
||||||
|
public string Text { get; set; }
|
||||||
|
public int Votes { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SocialCommentDto : FullAuditedEntityDto<Guid>
|
||||||
|
{
|
||||||
|
public Guid SocialPostId { get; set; }
|
||||||
|
public Guid? UserId { get; set; }
|
||||||
|
public UserInfoViewModel? User { get; set; }
|
||||||
|
public string Content { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SocialLikeDto : FullAuditedEntityDto<Guid>
|
||||||
|
{
|
||||||
|
public Guid SocialPostId { get; set; }
|
||||||
|
public Guid? UserId { get; set; }
|
||||||
|
public UserInfoViewModel? User { get; set; }
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Volo.Abp.Application.Dtos;
|
||||||
|
|
||||||
|
namespace Sozsoft.Platform.Intranet;
|
||||||
|
|
||||||
|
public class SurveyDto : FullAuditedEntityDto<Guid>
|
||||||
|
{
|
||||||
|
public string Title { get; set; }
|
||||||
|
public string Description { get; set; }
|
||||||
|
public DateTime Deadline { get; set; }
|
||||||
|
public int Responses { get; set; }
|
||||||
|
public string Status { get; set; } // draft | active | closed
|
||||||
|
public bool IsAnonymous { get; set; }
|
||||||
|
|
||||||
|
public List<SurveyQuestionDto> Questions { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SurveyQuestionDto : FullAuditedEntityDto<Guid>
|
||||||
|
{
|
||||||
|
public Guid SurveyId { get; set; }
|
||||||
|
public string QuestionText { get; set; }
|
||||||
|
public string Type { get; set; } // rating | multiple-choice | text | textarea | yes-no
|
||||||
|
public int Order { get; set; }
|
||||||
|
public bool IsRequired { get; set; }
|
||||||
|
|
||||||
|
public List<SurveyQuestionOptionDto> Options { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SurveyQuestionOptionDto : FullAuditedEntityDto<Guid>
|
||||||
|
{
|
||||||
|
public Guid QuestionId { get; set; }
|
||||||
|
public string Text { get; set; }
|
||||||
|
public int Order { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SurveyResponseDto : FullAuditedEntityDto<Guid>
|
||||||
|
{
|
||||||
|
public Guid SurveyId { get; set; }
|
||||||
|
public Guid? UserId { get; set; }
|
||||||
|
public DateTime SubmissionTime { get; set; }
|
||||||
|
|
||||||
|
public List<SurveyAnswerDto> Answers { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SurveyAnswerDto : FullAuditedEntityDto<Guid>
|
||||||
|
{
|
||||||
|
public Guid ResponseId { get; set; }
|
||||||
|
public Guid QuestionId { get; set; }
|
||||||
|
public string QuestionType { get; set; }
|
||||||
|
public string Value { get; set; }
|
||||||
|
}
|
||||||
|
|
@ -33,7 +33,7 @@ public class SearchBlogPostsInput : PagedAndSortedResultRequestDto
|
||||||
public string Query { get; set; }
|
public string Query { get; set; }
|
||||||
public Guid? CategoryId { get; set; }
|
public Guid? CategoryId { get; set; }
|
||||||
public string Tag { get; set; }
|
public string Tag { get; set; }
|
||||||
public Guid? EmployeeId { get; set; }
|
public Guid? UserId { get; set; }
|
||||||
public bool? IsPublished { get; set; }
|
public bool? IsPublished { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
using AutoMapper;
|
||||||
|
using Sozsoft.Platform.Entities;
|
||||||
|
using Sozsoft.Platform.Hr;
|
||||||
|
|
||||||
|
namespace Sozsoft.Platform.Intranet;
|
||||||
|
|
||||||
|
public class HrAutoMapperProfile : Profile
|
||||||
|
{
|
||||||
|
public HrAutoMapperProfile()
|
||||||
|
{
|
||||||
|
CreateMap<Department, DepartmentDto>();
|
||||||
|
CreateMap<JobPosition, JobPositionDto>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -11,7 +11,14 @@ public class IdentityAutoMapperProfile : Profile
|
||||||
{
|
{
|
||||||
public IdentityAutoMapperProfile()
|
public IdentityAutoMapperProfile()
|
||||||
{
|
{
|
||||||
CreateMap<IdentityUser, UserInfoViewModel>();
|
CreateMap<IdentityUser, UserInfoViewModel>()
|
||||||
|
.ForMember(dest => dest.Roles, opt => opt.Ignore())
|
||||||
|
.ForMember(dest => dest.Branches, opt => opt.Ignore())
|
||||||
|
.ForMember(dest => dest.Claims, opt => opt.Ignore())
|
||||||
|
.ForMember(dest => dest.WorkHours, opt => opt.Ignore())
|
||||||
|
.ForMember(dest => dest.Departments, opt => opt.Ignore())
|
||||||
|
.ForMember(dest => dest.JobPositions, opt => opt.Ignore())
|
||||||
|
.ForMember(dest => dest.userRoleNames, opt => opt.Ignore());
|
||||||
CreateMap<OrganizationUnit, OrganizationUnitDto>();
|
CreateMap<OrganizationUnit, OrganizationUnitDto>();
|
||||||
CreateMap<CreateUpdateOrganizationUnitDto, OrganizationUnit>();
|
CreateMap<CreateUpdateOrganizationUnitDto, OrganizationUnit>();
|
||||||
CreateMap<Tenant, CustomTenantDto>();
|
CreateMap<Tenant, CustomTenantDto>();
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,350 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Sozsoft.Platform.BlobStoring;
|
||||||
|
using Sozsoft.Platform.Entities;
|
||||||
|
using Sozsoft.Platform.FileManagement;
|
||||||
|
using Sozsoft.Platform.Identity.Dto;
|
||||||
|
using Sozsoft.Platform.Extensions;
|
||||||
|
using Volo.Abp.Domain.Repositories;
|
||||||
|
using Volo.Abp.Identity;
|
||||||
|
using Volo.Abp.MultiTenancy;
|
||||||
|
using Volo.Abp.Uow;
|
||||||
|
|
||||||
|
namespace Sozsoft.Platform.Intranet;
|
||||||
|
|
||||||
|
[Authorize]
|
||||||
|
public class IntranetAppService : PlatformAppService, IIntranetAppService
|
||||||
|
{
|
||||||
|
private readonly ICurrentTenant _currentTenant;
|
||||||
|
private readonly BlobManager _blobContainer;
|
||||||
|
private readonly IConfiguration _configuration;
|
||||||
|
|
||||||
|
private readonly IIdentityUserAppService _identityUserAppService;
|
||||||
|
private readonly IIdentityUserRepository _identityUserRepository;
|
||||||
|
private readonly IRepository<Department, Guid> _departmentRepository;
|
||||||
|
private readonly IRepository<JobPosition, Guid> _jobPositionRepository;
|
||||||
|
private readonly IRepository<Announcement, Guid> _announcementRepository;
|
||||||
|
private readonly IRepository<Survey, Guid> _surveyRepository;
|
||||||
|
private readonly IRepository<SocialPost, Guid> _socialPostRepository;
|
||||||
|
|
||||||
|
public IntranetAppService(
|
||||||
|
ICurrentTenant currentTenant,
|
||||||
|
BlobManager blobContainer,
|
||||||
|
IConfiguration configuration,
|
||||||
|
|
||||||
|
IIdentityUserAppService identityUserAppService,
|
||||||
|
IIdentityUserRepository identityUserRepository,
|
||||||
|
IRepository<Department, Guid> departmentRepository,
|
||||||
|
IRepository<JobPosition, Guid> jobPositionRepository,
|
||||||
|
IRepository<Announcement, Guid> announcementRepository,
|
||||||
|
IRepository<Survey, Guid> surveyRepository,
|
||||||
|
IRepository<SocialPost, Guid> socialPostRepository
|
||||||
|
)
|
||||||
|
{
|
||||||
|
_currentTenant = currentTenant;
|
||||||
|
_blobContainer = blobContainer;
|
||||||
|
_configuration = configuration;
|
||||||
|
_identityUserAppService = identityUserAppService;
|
||||||
|
_identityUserRepository = identityUserRepository;
|
||||||
|
_departmentRepository = departmentRepository;
|
||||||
|
_jobPositionRepository = jobPositionRepository;
|
||||||
|
_announcementRepository = announcementRepository;
|
||||||
|
_surveyRepository = surveyRepository;
|
||||||
|
_socialPostRepository = socialPostRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
[UnitOfWork]
|
||||||
|
public async Task<IntranetDashboardDto> GetIntranetDashboardAsync()
|
||||||
|
{
|
||||||
|
return new IntranetDashboardDto
|
||||||
|
{
|
||||||
|
Birthdays = await GetBirthdaysAsync(), //1
|
||||||
|
Documents = await GetIntranetDocumentsAsync(BlobContainerNames.Intranet), //2
|
||||||
|
Announcements = await GetAnnouncementsAsync(), //3
|
||||||
|
Surveys = await GetSurveysAsync(), //4
|
||||||
|
SocialPosts = await GetSocialPostsAsync(), //5
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<List<UserInfoViewModel>> GetBirthdaysAsync()
|
||||||
|
{
|
||||||
|
var today = DateTime.Now;
|
||||||
|
|
||||||
|
var users = await _identityUserRepository.GetListAsync();
|
||||||
|
|
||||||
|
var userList = users
|
||||||
|
.Where(u =>
|
||||||
|
{
|
||||||
|
var birthDate = u.GetBirthDate();
|
||||||
|
return birthDate.HasValue
|
||||||
|
&& birthDate.Value.Day == today.Day
|
||||||
|
&& birthDate.Value.Month == today.Month;
|
||||||
|
})
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var allDepartments = await _departmentRepository.GetListAsync();
|
||||||
|
var departmentDict = allDepartments.ToDictionary(d => d.Id, d => d.Name);
|
||||||
|
|
||||||
|
var allJobPositions = await _jobPositionRepository.GetListAsync();
|
||||||
|
var jobPositionDict = allJobPositions.ToDictionary(j => j.Id, j => j);
|
||||||
|
|
||||||
|
var result = ObjectMapper.Map<List<IdentityUser>, List<UserInfoViewModel>>(userList);
|
||||||
|
|
||||||
|
for (var i = 0; i < userList.Count; i++)
|
||||||
|
{
|
||||||
|
var user = userList[i];
|
||||||
|
|
||||||
|
result[i].BirthDate = user.GetBirthDate();
|
||||||
|
result[i].WorkHour = user.GetWorkHour();
|
||||||
|
result[i].Nationality = user.GetNationality();
|
||||||
|
|
||||||
|
var deptId = user.GetDepartmentId();
|
||||||
|
if (deptId != Guid.Empty && departmentDict.TryGetValue(deptId, out var deptName))
|
||||||
|
{
|
||||||
|
result[i].DepartmentId = deptId;
|
||||||
|
result[i].Departments =
|
||||||
|
[
|
||||||
|
new AssignedDepartmentViewModel { Id = deptId, Name = deptName, IsAssigned = true }
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
var jobPosId = user.GetJobPositionId();
|
||||||
|
if (jobPosId != Guid.Empty && jobPositionDict.TryGetValue(jobPosId, out var jobPosition))
|
||||||
|
{
|
||||||
|
result[i].JobPositionId = jobPosId;
|
||||||
|
result[i].JobPositions =
|
||||||
|
[
|
||||||
|
new AssignedJobPoisitionViewModel { Id = jobPosId, Name = jobPosition.Name, DepartmentId = jobPosition.DepartmentId, IsAssigned = true }
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<List<AnnouncementDto>> GetAnnouncementsAsync()
|
||||||
|
{
|
||||||
|
var announcements = await _announcementRepository.GetListAsync();
|
||||||
|
var announcementDtos = new List<AnnouncementDto>();
|
||||||
|
|
||||||
|
var allDepartments = await _departmentRepository.GetListAsync();
|
||||||
|
var departmentDict = allDepartments.ToDictionary(d => d.Id, d => d.Name);
|
||||||
|
|
||||||
|
var allJobPositions = await _jobPositionRepository.GetListAsync();
|
||||||
|
var jobPositionDict = allJobPositions.ToDictionary(j => j.Id, j => j);
|
||||||
|
|
||||||
|
foreach (var announcement in announcements)
|
||||||
|
{
|
||||||
|
var dto = ObjectMapper.Map<Announcement, AnnouncementDto>(announcement);
|
||||||
|
|
||||||
|
var user = await _identityUserRepository.FindAsync(announcement.UserId ?? Guid.Empty);
|
||||||
|
if (user != null)
|
||||||
|
{
|
||||||
|
var userVm = ObjectMapper.Map<IdentityUser, UserInfoViewModel>(user);
|
||||||
|
|
||||||
|
userVm.BirthDate = user.GetBirthDate();
|
||||||
|
userVm.WorkHour = user.GetWorkHour();
|
||||||
|
userVm.Nationality = user.GetNationality();
|
||||||
|
|
||||||
|
var deptId = user.GetDepartmentId();
|
||||||
|
if (deptId != Guid.Empty && departmentDict.TryGetValue(deptId, out var deptName))
|
||||||
|
{
|
||||||
|
userVm.DepartmentId = deptId;
|
||||||
|
userVm.Departments =
|
||||||
|
[
|
||||||
|
new AssignedDepartmentViewModel { Id = deptId, Name = deptName, IsAssigned = true }
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
var jobPosId = user.GetJobPositionId();
|
||||||
|
if (jobPosId != Guid.Empty && jobPositionDict.TryGetValue(jobPosId, out var jobPosition))
|
||||||
|
{
|
||||||
|
userVm.JobPositionId = jobPosId;
|
||||||
|
userVm.JobPositions =
|
||||||
|
[
|
||||||
|
new AssignedJobPoisitionViewModel { Id = jobPosId, Name = jobPosition.Name, DepartmentId = jobPosition.DepartmentId, IsAssigned = true }
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
dto.User = userVm;
|
||||||
|
}
|
||||||
|
|
||||||
|
announcementDtos.Add(dto);
|
||||||
|
}
|
||||||
|
|
||||||
|
return announcementDtos;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<List<SurveyDto>> GetSurveysAsync()
|
||||||
|
{
|
||||||
|
var queryable = await _surveyRepository.GetQueryableAsync();
|
||||||
|
|
||||||
|
var surveys = await AsyncExecuter.ToListAsync(
|
||||||
|
queryable
|
||||||
|
.Where(s => s.Status == "active")
|
||||||
|
.Include(s => s.Questions)
|
||||||
|
.ThenInclude(q => q.Options)
|
||||||
|
);
|
||||||
|
|
||||||
|
return ObjectMapper.Map<List<Survey>, List<SurveyDto>>(surveys);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<List<SocialPostDto>> GetSocialPostsAsync()
|
||||||
|
{
|
||||||
|
var queryable = await _socialPostRepository
|
||||||
|
.WithDetailsAsync(e => e.Location, e => e.Media, e => e.Comments, e => e.Likes);
|
||||||
|
|
||||||
|
var socialPosts = await AsyncExecuter.ToListAsync(queryable);
|
||||||
|
|
||||||
|
var dtos = ObjectMapper.Map<List<SocialPost>, List<SocialPostDto>>(socialPosts);
|
||||||
|
|
||||||
|
// Collect all unique user IDs to resolve in a single query
|
||||||
|
var userIds = dtos
|
||||||
|
.Select(p => p.UserId)
|
||||||
|
.Union(dtos.SelectMany(p => p.Comments.Select(c => c.UserId)))
|
||||||
|
.Union(dtos.SelectMany(p => p.Likes.Select(l => l.UserId)))
|
||||||
|
.Where(id => id.HasValue)
|
||||||
|
.Select(id => id!.Value)
|
||||||
|
.Distinct()
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
if (userIds.Count > 0)
|
||||||
|
{
|
||||||
|
var allDepartments = await _departmentRepository.GetListAsync();
|
||||||
|
var departmentDict = allDepartments.ToDictionary(d => d.Id, d => d.Name);
|
||||||
|
|
||||||
|
var allJobPositions = await _jobPositionRepository.GetListAsync();
|
||||||
|
var jobPositionDict = allJobPositions.ToDictionary(j => j.Id, j => j);
|
||||||
|
|
||||||
|
var users = await _identityUserRepository.GetListAsync();
|
||||||
|
var userMap = users
|
||||||
|
.Where(u => userIds.Contains(u.Id))
|
||||||
|
.ToDictionary(u => u.Id, u =>
|
||||||
|
{
|
||||||
|
var vm = ObjectMapper.Map<IdentityUser, UserInfoViewModel>(u);
|
||||||
|
vm.BirthDate = u.GetBirthDate();
|
||||||
|
vm.WorkHour = u.GetWorkHour();
|
||||||
|
vm.Nationality = u.GetNationality();
|
||||||
|
|
||||||
|
var deptId = u.GetDepartmentId();
|
||||||
|
if (deptId != Guid.Empty && departmentDict.TryGetValue(deptId, out var deptName))
|
||||||
|
{
|
||||||
|
vm.DepartmentId = deptId;
|
||||||
|
vm.Departments =
|
||||||
|
[
|
||||||
|
new AssignedDepartmentViewModel { Id = deptId, Name = deptName, IsAssigned = true }
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
var jobPosId = u.GetJobPositionId();
|
||||||
|
if (jobPosId != Guid.Empty && jobPositionDict.TryGetValue(jobPosId, out var jobPosition))
|
||||||
|
{
|
||||||
|
vm.JobPositionId = jobPosId;
|
||||||
|
vm.JobPositions =
|
||||||
|
[
|
||||||
|
new AssignedJobPoisitionViewModel { Id = jobPosId, Name = jobPosition.Name, DepartmentId = jobPosition.DepartmentId, IsAssigned = true }
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return vm;
|
||||||
|
});
|
||||||
|
|
||||||
|
foreach (var dto in dtos)
|
||||||
|
{
|
||||||
|
if (dto.UserId.HasValue && userMap.TryGetValue(dto.UserId.Value, out var postUser))
|
||||||
|
dto.User = postUser;
|
||||||
|
|
||||||
|
foreach (var comment in dto.Comments)
|
||||||
|
if (comment.UserId.HasValue && userMap.TryGetValue(comment.UserId.Value, out var commentUser))
|
||||||
|
comment.User = commentUser;
|
||||||
|
|
||||||
|
foreach (var like in dto.Likes)
|
||||||
|
if (like.UserId.HasValue && userMap.TryGetValue(like.UserId.Value, out var likeUser))
|
||||||
|
like.User = likeUser;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dtos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<FileItemDto>> GetIntranetDocumentsAsync(string folderPath)
|
||||||
|
{
|
||||||
|
var items = new List<FileItemDto>();
|
||||||
|
var cdnBasePath = _configuration["App:CdnPath"];
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(cdnBasePath))
|
||||||
|
{
|
||||||
|
Logger.LogWarning("CDN path is not configured");
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
var tenantId = _currentTenant.Id?.ToString() ?? "host";
|
||||||
|
var fullPath = Path.Combine(cdnBasePath, tenantId);
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(folderPath))
|
||||||
|
{
|
||||||
|
fullPath = Path.Combine(fullPath, folderPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Directory.Exists(fullPath))
|
||||||
|
{
|
||||||
|
Logger.LogWarning($"Directory not found: {fullPath}");
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
var files = Directory.GetFiles(fullPath);
|
||||||
|
foreach (var file in files)
|
||||||
|
{
|
||||||
|
var fileInfo = new FileInfo(file);
|
||||||
|
var relativePath = string.IsNullOrEmpty(folderPath) ? fileInfo.Name : $"{folderPath}/{fileInfo.Name}";
|
||||||
|
|
||||||
|
items.Add(new FileItemDto
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid().ToString(),
|
||||||
|
Name = fileInfo.Name,
|
||||||
|
Type = "file",
|
||||||
|
Size = fileInfo.Length,
|
||||||
|
Extension = fileInfo.Extension,
|
||||||
|
MimeType = GetMimeType(fileInfo.Extension),
|
||||||
|
CreatedAt = fileInfo.CreationTime,
|
||||||
|
ModifiedAt = fileInfo.LastWriteTime,
|
||||||
|
Path = relativePath,
|
||||||
|
ParentId = string.Empty,
|
||||||
|
IsReadOnly = false,
|
||||||
|
ChildCount = 0,
|
||||||
|
TenantId = _currentTenant.Id?.ToString()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return items.OrderBy(x => x.Name).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetMimeType(string extension)
|
||||||
|
{
|
||||||
|
return extension.ToLowerInvariant() switch
|
||||||
|
{
|
||||||
|
".pdf" => "application/pdf",
|
||||||
|
".doc" => "application/msword",
|
||||||
|
".docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||||
|
".xls" => "application/vnd.ms-excel",
|
||||||
|
".xlsx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||||
|
".ppt" => "application/vnd.ms-powerpoint",
|
||||||
|
".pptx" => "application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
||||||
|
".jpg" or ".jpeg" => "image/jpeg",
|
||||||
|
".png" => "image/png",
|
||||||
|
".gif" => "image/gif",
|
||||||
|
".txt" => "text/plain",
|
||||||
|
".zip" => "application/zip",
|
||||||
|
".rar" => "application/x-rar-compressed",
|
||||||
|
_ => "application/octet-stream"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
using AutoMapper;
|
||||||
|
using Sozsoft.Platform.Entities;
|
||||||
|
|
||||||
|
namespace Sozsoft.Platform.Intranet;
|
||||||
|
|
||||||
|
public class IntranetAutoMapperProfile : Profile
|
||||||
|
{
|
||||||
|
public IntranetAutoMapperProfile()
|
||||||
|
{
|
||||||
|
CreateMap<Announcement, AnnouncementDto>();
|
||||||
|
CreateMap<Survey, SurveyDto>();
|
||||||
|
CreateMap<SurveyQuestion, SurveyQuestionDto>();
|
||||||
|
CreateMap<SurveyQuestionOption, SurveyQuestionOptionDto>();
|
||||||
|
CreateMap<SurveyResponse, SurveyResponseDto>();
|
||||||
|
CreateMap<SurveyAnswer, SurveyAnswerDto>();
|
||||||
|
|
||||||
|
CreateMap<SocialPost, SocialPostDto>();
|
||||||
|
CreateMap<SocialLocation, SocialLocationDto>();
|
||||||
|
CreateMap<SocialMedia, SocialMediaDto>();
|
||||||
|
CreateMap<SocialPollOption, SocialPollOptionDto>();
|
||||||
|
CreateMap<SocialComment, SocialCommentDto>();
|
||||||
|
CreateMap<SocialLike, SocialLikeDto>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -138,12 +138,6 @@
|
||||||
"en": "Administration",
|
"en": "Administration",
|
||||||
"tr": "Yönetim"
|
"tr": "Yönetim"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"resourceName": "Platform",
|
|
||||||
"key": "App.Intranet",
|
|
||||||
"en": "Intranet",
|
|
||||||
"tr": "Intranet"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"resourceName": "Platform",
|
"resourceName": "Platform",
|
||||||
"key": "App.SupplyChain",
|
"key": "App.SupplyChain",
|
||||||
|
|
@ -3644,6 +3638,12 @@
|
||||||
"en": "Audit Logs",
|
"en": "Audit Logs",
|
||||||
"tr": "Audit Günlükleri"
|
"tr": "Audit Günlükleri"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Intranet",
|
||||||
|
"en": "Intranet",
|
||||||
|
"tr": "Intranet"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"resourceName": "Platform",
|
"resourceName": "Platform",
|
||||||
"key": "App.AuditLogs.FetchFailed",
|
"key": "App.AuditLogs.FetchFailed",
|
||||||
|
|
@ -6092,6 +6092,12 @@
|
||||||
"tr": "Eğitim Durumu",
|
"tr": "Eğitim Durumu",
|
||||||
"en": "Education Status"
|
"en": "Education Status"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Intranet.SocialComment",
|
||||||
|
"tr": "Sosyal Yorumlar",
|
||||||
|
"en": "Social Comments"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"resourceName": "Platform",
|
"resourceName": "Platform",
|
||||||
"key": "App.Intranet.Events",
|
"key": "App.Intranet.Events",
|
||||||
|
|
@ -12284,6 +12290,12 @@
|
||||||
"tr": "Acil",
|
"tr": "Acil",
|
||||||
"en": "Urgent"
|
"en": "Urgent"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Platform.Intranet.Widgets.ActiveSurveys.Questions",
|
||||||
|
"tr": "Sorular",
|
||||||
|
"en": "Questions"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"resourceName": "Platform",
|
"resourceName": "Platform",
|
||||||
"key": "App.Platform.Intranet.Widgets.ActiveSurveys.Title",
|
"key": "App.Platform.Intranet.Widgets.ActiveSurveys.Title",
|
||||||
|
|
|
||||||
|
|
@ -2989,6 +2989,15 @@
|
||||||
"MultiTenancySide": 3,
|
"MultiTenancySide": 3,
|
||||||
"MenuGroup": "Erp|Kurs"
|
"MenuGroup": "Erp|Kurs"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "AbpIdentity.Users.Widget",
|
||||||
|
"ParentName": "AbpIdentity.Users",
|
||||||
|
"DisplayName": "Widget",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Erp|Kurs"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"GroupName": "App.Administration",
|
"GroupName": "App.Administration",
|
||||||
"Name": "AbpIdentity.Users.Update.ManageRoles",
|
"Name": "AbpIdentity.Users.Update.ManageRoles",
|
||||||
|
|
@ -3304,6 +3313,15 @@
|
||||||
"MultiTenancySide": 3,
|
"MultiTenancySide": 3,
|
||||||
"MenuGroup": "Erp|Kurs"
|
"MenuGroup": "Erp|Kurs"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Files.Widget",
|
||||||
|
"ParentName": "App.Files",
|
||||||
|
"DisplayName": "Widget",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Erp|Kurs"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"GroupName": "App.Administration",
|
"GroupName": "App.Administration",
|
||||||
"Name": "App.ForumManagement.Publish",
|
"Name": "App.ForumManagement.Publish",
|
||||||
|
|
@ -3312,6 +3330,429 @@
|
||||||
"IsEnabled": true,
|
"IsEnabled": true,
|
||||||
"MultiTenancySide": 3,
|
"MultiTenancySide": 3,
|
||||||
"MenuGroup": "Erp|Kurs"
|
"MenuGroup": "Erp|Kurs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Intranet",
|
||||||
|
"ParentName": null,
|
||||||
|
"DisplayName": "App.Intranet",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Erp|Kurs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Intranet.Events.EventType",
|
||||||
|
"ParentName": "App.Intranet",
|
||||||
|
"DisplayName": "App.Intranet.Events.EventType",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Kurs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Intranet.Events.EventType.Create",
|
||||||
|
"ParentName": "App.Intranet.Events.EventType",
|
||||||
|
"DisplayName": "Create",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Kurs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Intranet.Events.EventType.Update",
|
||||||
|
"ParentName": "App.Intranet.Events.EventType",
|
||||||
|
"DisplayName": "Update",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Kurs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Intranet.Events.EventType.Delete",
|
||||||
|
"ParentName": "App.Intranet.Events.EventType",
|
||||||
|
"DisplayName": "Delete",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Kurs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Intranet.Events.EventType.Export",
|
||||||
|
"ParentName": "App.Intranet.Events.EventType",
|
||||||
|
"DisplayName": "Export",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Kurs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Intranet.Events.EventType.Import",
|
||||||
|
"ParentName": "App.Intranet.Events.EventType",
|
||||||
|
"DisplayName": "Import",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Kurs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Intranet.Events.EventType.Note",
|
||||||
|
"ParentName": "App.Intranet.Events.EventType",
|
||||||
|
"DisplayName": "Note",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Kurs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Intranet.Events.EventCategory",
|
||||||
|
"ParentName": "App.Intranet",
|
||||||
|
"DisplayName": "App.Intranet.Events.EventCategory",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Kurs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Intranet.Events.EventCategory.Create",
|
||||||
|
"ParentName": "App.Intranet.Events.EventCategory",
|
||||||
|
"DisplayName": "Create",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Kurs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Intranet.Events.EventCategory.Update",
|
||||||
|
"ParentName": "App.Intranet.Events.EventCategory",
|
||||||
|
"DisplayName": "Update",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Kurs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Intranet.Events.EventCategory.Delete",
|
||||||
|
"ParentName": "App.Intranet.Events.EventCategory",
|
||||||
|
"DisplayName": "Delete",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Kurs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Intranet.Events.EventCategory.Export",
|
||||||
|
"ParentName": "App.Intranet.Events.EventCategory",
|
||||||
|
"DisplayName": "Export",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Kurs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Intranet.Events.EventCategory.Import",
|
||||||
|
"ParentName": "App.Intranet.Events.EventCategory",
|
||||||
|
"DisplayName": "Import",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Kurs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Intranet.Events.EventCategory.Note",
|
||||||
|
"ParentName": "App.Intranet.Events.EventCategory",
|
||||||
|
"DisplayName": "Note",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Kurs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Intranet.Events.Event",
|
||||||
|
"ParentName": "App.Intranet",
|
||||||
|
"DisplayName": "App.Intranet.Events.Event",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Kurs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Intranet.Events.Event.Create",
|
||||||
|
"ParentName": "App.Intranet.Events.Event",
|
||||||
|
"DisplayName": "Create",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Kurs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Intranet.Events.Event.Update",
|
||||||
|
"ParentName": "App.Intranet.Events.Event",
|
||||||
|
"DisplayName": "Update",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Kurs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Intranet.Events.Event.Delete",
|
||||||
|
"ParentName": "App.Intranet.Events.Event",
|
||||||
|
"DisplayName": "Delete",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Kurs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Intranet.Events.Event.Export",
|
||||||
|
"ParentName": "App.Intranet.Events.Event",
|
||||||
|
"DisplayName": "Export",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Kurs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Intranet.Events.Event.Import",
|
||||||
|
"ParentName": "App.Intranet.Events.Event",
|
||||||
|
"DisplayName": "Import",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Kurs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Intranet.Events.Event.Note",
|
||||||
|
"ParentName": "App.Intranet.Events.Event",
|
||||||
|
"DisplayName": "Note",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Kurs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Intranet.Events.Event.Widget",
|
||||||
|
"ParentName": "App.Intranet.Events.Event",
|
||||||
|
"DisplayName": "Widget",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Kurs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Intranet.Announcement",
|
||||||
|
"ParentName": "App.Intranet",
|
||||||
|
"DisplayName": "App.Intranet.Announcement",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Kurs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Intranet.Announcement.Create",
|
||||||
|
"ParentName": "App.Intranet.Announcement",
|
||||||
|
"DisplayName": "Create",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Kurs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Intranet.Announcement.Update",
|
||||||
|
"ParentName": "App.Intranet.Announcement",
|
||||||
|
"DisplayName": "Update",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Kurs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Intranet.Announcement.Delete",
|
||||||
|
"ParentName": "App.Intranet.Announcement",
|
||||||
|
"DisplayName": "Delete",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Kurs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Intranet.Announcement.Export",
|
||||||
|
"ParentName": "App.Intranet.Announcement",
|
||||||
|
"DisplayName": "Export",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Kurs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Intranet.Announcement.Import",
|
||||||
|
"ParentName": "App.Intranet.Announcement",
|
||||||
|
"DisplayName": "Import",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Kurs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Intranet.Announcement.Note",
|
||||||
|
"ParentName": "App.Intranet.Announcement",
|
||||||
|
"DisplayName": "Note",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Kurs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Intranet.Announcement.Widget",
|
||||||
|
"ParentName": "App.Intranet.Announcement",
|
||||||
|
"DisplayName": "Widget",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Kurs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Intranet.SocialPost",
|
||||||
|
"ParentName": "App.Intranet",
|
||||||
|
"DisplayName": "App.Intranet.SocialPost",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Kurs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Intranet.SocialPost.Create",
|
||||||
|
"ParentName": "App.Intranet.SocialPost",
|
||||||
|
"DisplayName": "Create",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Kurs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Intranet.SocialPost.Update",
|
||||||
|
"ParentName": "App.Intranet.SocialPost",
|
||||||
|
"DisplayName": "Update",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Kurs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Intranet.SocialPost.Delete",
|
||||||
|
"ParentName": "App.Intranet.SocialPost",
|
||||||
|
"DisplayName": "Delete",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Kurs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Intranet.SocialPost.Export",
|
||||||
|
"ParentName": "App.Intranet.SocialPost",
|
||||||
|
"DisplayName": "Export",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Kurs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Intranet.SocialPost.Import",
|
||||||
|
"ParentName": "App.Intranet.SocialPost",
|
||||||
|
"DisplayName": "Import",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Kurs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Intranet.SocialPost.Note",
|
||||||
|
"ParentName": "App.Intranet.SocialPost",
|
||||||
|
"DisplayName": "Note",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Kurs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Intranet.SocialPost.Widget",
|
||||||
|
"ParentName": "App.Intranet.SocialPost",
|
||||||
|
"DisplayName": "Widget",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Kurs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Intranet.SocialComment",
|
||||||
|
"ParentName": "App.Intranet",
|
||||||
|
"DisplayName": "App.Intranet.SocialComment",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Kurs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Intranet.SocialComment.Create",
|
||||||
|
"ParentName": "App.Intranet.SocialComment",
|
||||||
|
"DisplayName": "Create",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Kurs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Intranet.SocialComment.Update",
|
||||||
|
"ParentName": "App.Intranet.SocialComment",
|
||||||
|
"DisplayName": "Update",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Kurs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Intranet.SocialComment.Delete",
|
||||||
|
"ParentName": "App.Intranet.SocialComment",
|
||||||
|
"DisplayName": "Delete",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Kurs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Intranet.SocialComment.Export",
|
||||||
|
"ParentName": "App.Intranet.SocialComment",
|
||||||
|
"DisplayName": "Export",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Kurs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Intranet.SocialComment.Import",
|
||||||
|
"ParentName": "App.Intranet.SocialComment",
|
||||||
|
"DisplayName": "Import",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Kurs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Intranet.SocialComment.Note",
|
||||||
|
"ParentName": "App.Intranet.SocialComment",
|
||||||
|
"DisplayName": "Note",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Kurs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"GroupName": "App.Administration",
|
||||||
|
"Name": "App.Intranet.Survey.Widget",
|
||||||
|
"ParentName": "App.Intranet",
|
||||||
|
"DisplayName": "App.Intranet.Survey.Widget",
|
||||||
|
"IsEnabled": true,
|
||||||
|
"MultiTenancySide": 3,
|
||||||
|
"MenuGroup": "Erp|Kurs"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
@ -70,14 +70,14 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency
|
||||||
var wizardDataPath = Path.Combine(Directory.GetCurrentDirectory(), "Seeds", "WizardData");
|
var wizardDataPath = Path.Combine(Directory.GetCurrentDirectory(), "Seeds", "WizardData");
|
||||||
if (!Directory.Exists(wizardDataPath))
|
if (!Directory.Exists(wizardDataPath))
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Seeds/WizardData directory not found, skipping.");
|
_logger.LogInformation("WizardData directory not found, skipping.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var jsonFiles = Directory.GetFiles(wizardDataPath, "*.json").OrderBy(f => Path.GetFileName(f)).ToArray();
|
var jsonFiles = Directory.GetFiles(wizardDataPath, "*.json").OrderBy(f => Path.GetFileName(f)).ToArray();
|
||||||
if (jsonFiles.Length == 0)
|
if (jsonFiles.Length == 0)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("No JSON files found in Seeds/WizardData directory, skipping.");
|
_logger.LogInformation("No JSON files found in WizardData directory, skipping.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -64,4 +64,16 @@ public enum TableNameEnum
|
||||||
BlogPost,
|
BlogPost,
|
||||||
Demo,
|
Demo,
|
||||||
Contact,
|
Contact,
|
||||||
|
Announcement,
|
||||||
|
Survey,
|
||||||
|
SurveyQuestion,
|
||||||
|
SurveyQuestionOption,
|
||||||
|
SurveyResponse,
|
||||||
|
SurveyAnswer,
|
||||||
|
SocialPost,
|
||||||
|
SocialLocation,
|
||||||
|
SocialMedia,
|
||||||
|
SocialPollOption,
|
||||||
|
SocialComment,
|
||||||
|
SocialLike
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,21 @@ public static class TableNameResolver
|
||||||
{ nameof(TableNameEnum.Note), (TablePrefix.TenantByName, MenuPrefix.Administration) },
|
{ nameof(TableNameEnum.Note), (TablePrefix.TenantByName, MenuPrefix.Administration) },
|
||||||
{ nameof(TableNameEnum.ReportCategory), (TablePrefix.TenantByName, MenuPrefix.Administration) },
|
{ nameof(TableNameEnum.ReportCategory), (TablePrefix.TenantByName, MenuPrefix.Administration) },
|
||||||
{ nameof(TableNameEnum.ReportTemplate), (TablePrefix.TenantByName, MenuPrefix.Administration) },
|
{ nameof(TableNameEnum.ReportTemplate), (TablePrefix.TenantByName, MenuPrefix.Administration) },
|
||||||
|
|
||||||
|
// 🔹 INTRANET TABLOLARI
|
||||||
|
{ nameof(TableNameEnum.Announcement), (TablePrefix.TenantByName, MenuPrefix.Administration) },
|
||||||
|
{ nameof(TableNameEnum.Survey), (TablePrefix.TenantByName, MenuPrefix.Administration) },
|
||||||
|
{ nameof(TableNameEnum.SurveyQuestion), (TablePrefix.TenantByName, MenuPrefix.Administration) },
|
||||||
|
{ nameof(TableNameEnum.SurveyQuestionOption), (TablePrefix.TenantByName, MenuPrefix.Administration) },
|
||||||
|
{ nameof(TableNameEnum.SurveyResponse), (TablePrefix.TenantByName, MenuPrefix.Administration) },
|
||||||
|
{ nameof(TableNameEnum.SurveyAnswer), (TablePrefix.TenantByName, MenuPrefix.Administration) },
|
||||||
|
{ nameof(TableNameEnum.SocialPost), (TablePrefix.TenantByName, MenuPrefix.Administration) },
|
||||||
|
{ nameof(TableNameEnum.SocialLocation), (TablePrefix.TenantByName, MenuPrefix.Administration) },
|
||||||
|
{ nameof(TableNameEnum.SocialMedia), (TablePrefix.TenantByName, MenuPrefix.Administration) },
|
||||||
|
{ nameof(TableNameEnum.SocialPollOption), (TablePrefix.TenantByName, MenuPrefix.Administration) },
|
||||||
|
{ nameof(TableNameEnum.SocialComment), (TablePrefix.TenantByName, MenuPrefix.Administration) },
|
||||||
|
{ nameof(TableNameEnum.SocialLike), (TablePrefix.TenantByName, MenuPrefix.Administration) },
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
public static string GetFullTableName(string tableName)
|
public static string GetFullTableName(string tableName)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
using System;
|
||||||
|
using Volo.Abp.Domain.Entities.Auditing;
|
||||||
|
using Volo.Abp.MultiTenancy;
|
||||||
|
|
||||||
|
namespace Sozsoft.Platform.Entities;
|
||||||
|
|
||||||
|
public class Announcement : FullAuditedEntity<Guid>, IMultiTenant
|
||||||
|
{
|
||||||
|
public Guid? TenantId { get; set; }
|
||||||
|
|
||||||
|
public string Title { get; set; }
|
||||||
|
public string Excerpt { get; set; }
|
||||||
|
public string Content { get; set; }
|
||||||
|
public string ImageUrl { get; set; }
|
||||||
|
public string Category { get; set; }
|
||||||
|
public Guid? UserId { get; set; }
|
||||||
|
public DateTime PublishDate { get; set; }
|
||||||
|
public DateTime? ExpiryDate { get; set; }
|
||||||
|
public bool IsPinned { get; set; }
|
||||||
|
public int ViewCount { get; set; }
|
||||||
|
public string Attachments { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,91 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Volo.Abp.Domain.Entities.Auditing;
|
||||||
|
using Volo.Abp.MultiTenancy;
|
||||||
|
|
||||||
|
namespace Sozsoft.Platform.Entities;
|
||||||
|
|
||||||
|
public class SocialPost : FullAuditedEntity<Guid>, IMultiTenant
|
||||||
|
{
|
||||||
|
public Guid? TenantId { get; set; }
|
||||||
|
|
||||||
|
public Guid? UserId { get; set; }
|
||||||
|
|
||||||
|
public string Content { get; set; }
|
||||||
|
|
||||||
|
public int LikeCount { get; set; }
|
||||||
|
public bool IsLiked { get; set; }
|
||||||
|
public bool IsOwnPost { get; set; }
|
||||||
|
|
||||||
|
// Relations
|
||||||
|
public SocialLocation Location { get; set; }
|
||||||
|
public SocialMedia Media { get; set; }
|
||||||
|
public ICollection<SocialComment> Comments { get; set; }
|
||||||
|
public ICollection<SocialLike> Likes { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SocialLocation : FullAuditedEntity<Guid>, IMultiTenant
|
||||||
|
{
|
||||||
|
public Guid? TenantId { get; set; }
|
||||||
|
|
||||||
|
public Guid SocialPostId { get; set; }
|
||||||
|
public SocialPost SocialPost { get; set; }
|
||||||
|
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string? Address { get; set; }
|
||||||
|
public double? Lat { get; set; }
|
||||||
|
public double? Lng { get; set; }
|
||||||
|
public string? PlaceId { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SocialMedia : FullAuditedEntity<Guid>, IMultiTenant
|
||||||
|
{
|
||||||
|
public Guid? TenantId { get; set; }
|
||||||
|
|
||||||
|
public Guid SocialPostId { get; set; }
|
||||||
|
public SocialPost SocialPost { get; set; }
|
||||||
|
|
||||||
|
public string Type { get; set; } // image | video | poll
|
||||||
|
public string[] Urls { get; set; }
|
||||||
|
|
||||||
|
// Poll fields
|
||||||
|
public string? PollQuestion { get; set; }
|
||||||
|
public int? PollTotalVotes { get; set; }
|
||||||
|
public DateTime? PollEndsAt { get; set; }
|
||||||
|
public string? PollUserVoteId { get; set; }
|
||||||
|
|
||||||
|
public ICollection<SocialPollOption> PollOptions { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SocialPollOption : FullAuditedEntity<Guid>, IMultiTenant
|
||||||
|
{
|
||||||
|
public Guid? TenantId { get; set; }
|
||||||
|
|
||||||
|
public Guid SocialMediaId { get; set; }
|
||||||
|
public SocialMedia SocialMedia { get; set; }
|
||||||
|
|
||||||
|
public string Text { get; set; }
|
||||||
|
public int Votes { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SocialComment : FullAuditedEntity<Guid>, IMultiTenant
|
||||||
|
{
|
||||||
|
public Guid? TenantId { get; set; }
|
||||||
|
|
||||||
|
public Guid SocialPostId { get; set; }
|
||||||
|
public SocialPost SocialPost { get; set; }
|
||||||
|
|
||||||
|
public Guid? UserId { get; set; }
|
||||||
|
|
||||||
|
public string Content { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SocialLike : FullAuditedEntity<Guid>, IMultiTenant
|
||||||
|
{
|
||||||
|
public Guid? TenantId { get; set; }
|
||||||
|
|
||||||
|
public Guid SocialPostId { get; set; }
|
||||||
|
public SocialPost SocialPost { get; set; }
|
||||||
|
|
||||||
|
public Guid? UserId { get; set; }
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,76 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using Volo.Abp.Domain.Entities.Auditing;
|
||||||
|
using Volo.Abp.MultiTenancy;
|
||||||
|
|
||||||
|
namespace Sozsoft.Platform.Entities;
|
||||||
|
|
||||||
|
public class Survey : FullAuditedEntity<Guid>, IMultiTenant
|
||||||
|
{
|
||||||
|
public Guid? TenantId { get; set; }
|
||||||
|
|
||||||
|
public string Title { get; set; }
|
||||||
|
public string Description { get; set; }
|
||||||
|
public DateTime Deadline { get; set; }
|
||||||
|
public int Responses { get; set; }
|
||||||
|
public string Status { get; set; } // draft | active | closed
|
||||||
|
public bool IsAnonymous { get; set; }
|
||||||
|
|
||||||
|
public ICollection<SurveyQuestion> Questions { get; set; }
|
||||||
|
public ICollection<SurveyResponse> SurveyResponses { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SurveyQuestion : FullAuditedEntity<Guid>, IMultiTenant
|
||||||
|
{
|
||||||
|
public Guid? TenantId { get; set; }
|
||||||
|
|
||||||
|
public Guid SurveyId { get; set; }
|
||||||
|
public Survey Survey { get; set; }
|
||||||
|
|
||||||
|
public string QuestionText { get; set; }
|
||||||
|
public string Type { get; set; } // rating | multiple-choice | text | textarea | yes-no
|
||||||
|
public int Order { get; set; }
|
||||||
|
public bool IsRequired { get; set; }
|
||||||
|
|
||||||
|
public ICollection<SurveyQuestionOption> Options { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SurveyQuestionOption : FullAuditedEntity<Guid>, IMultiTenant
|
||||||
|
{
|
||||||
|
public Guid? TenantId { get; set; }
|
||||||
|
|
||||||
|
public Guid QuestionId { get; set; }
|
||||||
|
public SurveyQuestion Question { get; set; }
|
||||||
|
|
||||||
|
public string Text { get; set; }
|
||||||
|
public int Order { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SurveyResponse : FullAuditedEntity<Guid>, IMultiTenant
|
||||||
|
{
|
||||||
|
public Guid? TenantId { get; set; }
|
||||||
|
|
||||||
|
public Guid SurveyId { get; set; }
|
||||||
|
public Survey Survey { get; set; }
|
||||||
|
|
||||||
|
public Guid? UserId { get; set; }
|
||||||
|
|
||||||
|
public DateTime SubmissionTime { get; set; }
|
||||||
|
|
||||||
|
public ICollection<SurveyAnswer> Answers { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SurveyAnswer : FullAuditedEntity<Guid>, IMultiTenant
|
||||||
|
{
|
||||||
|
public Guid? TenantId { get; set; }
|
||||||
|
|
||||||
|
public Guid ResponseId { get; set; }
|
||||||
|
public SurveyResponse Response { get; set; }
|
||||||
|
|
||||||
|
public Guid QuestionId { get; set; }
|
||||||
|
public SurveyQuestion Question { get; set; }
|
||||||
|
|
||||||
|
public string QuestionType { get; set; } // rating | multiple-choice | text | textarea | yes-no
|
||||||
|
public string Value { get; set; }
|
||||||
|
}
|
||||||
|
|
@ -109,6 +109,23 @@ public class PlatformDbContext :
|
||||||
public DbSet<JobPosition> JobPositions { get; set; }
|
public DbSet<JobPosition> JobPositions { get; set; }
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Intranet
|
||||||
|
public DbSet<Announcement> Announcements { get; set; }
|
||||||
|
|
||||||
|
public DbSet<Survey> Surveys { get; set; }
|
||||||
|
public DbSet<SurveyQuestion> SurveyQuestions { get; set; }
|
||||||
|
public DbSet<SurveyQuestionOption> SurveyQuestionOptions { get; set; }
|
||||||
|
public DbSet<SurveyResponse> SurveyResponses { get; set; }
|
||||||
|
public DbSet<SurveyAnswer> SurveyAnswers { get; set; }
|
||||||
|
|
||||||
|
public DbSet<SocialPost> SocialPosts { get; set; }
|
||||||
|
public DbSet<SocialLocation> SocialLocations { get; set; }
|
||||||
|
public DbSet<SocialMedia> SocialMedias { get; set; }
|
||||||
|
public DbSet<SocialPollOption> SocialPollOptions { get; set; }
|
||||||
|
public DbSet<SocialComment> SocialComments { get; set; }
|
||||||
|
public DbSet<SocialLike> SocialLikes { get; set; }
|
||||||
|
#endregion
|
||||||
|
|
||||||
public PlatformDbContext(DbContextOptions<PlatformDbContext> options)
|
public PlatformDbContext(DbContextOptions<PlatformDbContext> options)
|
||||||
: base(options)
|
: base(options)
|
||||||
{
|
{
|
||||||
|
|
@ -1026,5 +1043,171 @@ public class PlatformDbContext :
|
||||||
b.Property(x => x.PrimaryEntityType).HasMaxLength(256);
|
b.Property(x => x.PrimaryEntityType).HasMaxLength(256);
|
||||||
b.Property(x => x.ControllerName).HasMaxLength(256);
|
b.Property(x => x.ControllerName).HasMaxLength(256);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
builder.Entity<Announcement>(b =>
|
||||||
|
{
|
||||||
|
b.ToTable(TableNameResolver.GetFullTableName(nameof(TableNameEnum.Announcement)), Prefix.DbSchema);
|
||||||
|
b.ConfigureByConvention();
|
||||||
|
|
||||||
|
b.Property(x => x.Title).IsRequired().HasMaxLength(256);
|
||||||
|
b.Property(x => x.Excerpt).IsRequired().HasMaxLength(512);
|
||||||
|
b.Property(x => x.Content).IsRequired().HasMaxLength(4096);
|
||||||
|
b.Property(x => x.ImageUrl).HasMaxLength(512);
|
||||||
|
b.Property(x => x.Category).IsRequired().HasMaxLength(64);
|
||||||
|
b.Property(x => x.PublishDate).IsRequired();
|
||||||
|
b.Property(x => x.Attachments).HasMaxLength(2048);
|
||||||
|
b.Property(x => x.ViewCount).HasDefaultValue(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.Entity<Survey>(b =>
|
||||||
|
{
|
||||||
|
b.ToTable(TableNameResolver.GetFullTableName(nameof(TableNameEnum.Survey)), Prefix.DbSchema);
|
||||||
|
b.ConfigureByConvention();
|
||||||
|
|
||||||
|
b.Property(x => x.Title).IsRequired().HasMaxLength(256);
|
||||||
|
b.Property(x => x.Description).HasMaxLength(2048);
|
||||||
|
b.Property(x => x.Deadline).IsRequired();
|
||||||
|
b.Property(x => x.Responses).HasDefaultValue(0);
|
||||||
|
b.Property(x => x.Status).IsRequired().HasMaxLength(10);
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.Entity<SurveyQuestion>(b =>
|
||||||
|
{
|
||||||
|
b.ToTable(TableNameResolver.GetFullTableName(nameof(TableNameEnum.SurveyQuestion)), Prefix.DbSchema);
|
||||||
|
b.ConfigureByConvention();
|
||||||
|
|
||||||
|
b.Property(x => x.QuestionText).IsRequired().HasMaxLength(1024);
|
||||||
|
b.Property(x => x.Type).IsRequired().HasMaxLength(64);
|
||||||
|
|
||||||
|
b.HasOne(x => x.Survey)
|
||||||
|
.WithMany(x => x.Questions)
|
||||||
|
.HasForeignKey(x => x.SurveyId)
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.Entity<SurveyQuestionOption>(b =>
|
||||||
|
{
|
||||||
|
b.ToTable(TableNameResolver.GetFullTableName(nameof(TableNameEnum.SurveyQuestionOption)), Prefix.DbSchema);
|
||||||
|
b.ConfigureByConvention();
|
||||||
|
|
||||||
|
b.Property(x => x.Text).IsRequired().HasMaxLength(512);
|
||||||
|
b.Property(x => x.Order).IsRequired();
|
||||||
|
|
||||||
|
b.HasOne(x => x.Question)
|
||||||
|
.WithMany(x => x.Options)
|
||||||
|
.HasForeignKey(x => x.QuestionId)
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.Entity<SurveyResponse>(b =>
|
||||||
|
{
|
||||||
|
b.ToTable(TableNameResolver.GetFullTableName(nameof(TableNameEnum.SurveyResponse)), Prefix.DbSchema);
|
||||||
|
b.ConfigureByConvention();
|
||||||
|
|
||||||
|
b.Property(x => x.SubmissionTime).IsRequired();
|
||||||
|
|
||||||
|
b.HasOne(x => x.Survey)
|
||||||
|
.WithMany(x => x.SurveyResponses)
|
||||||
|
.HasForeignKey(x => x.SurveyId)
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.Entity<SurveyAnswer>(b =>
|
||||||
|
{
|
||||||
|
b.ToTable(TableNameResolver.GetFullTableName(nameof(TableNameEnum.SurveyAnswer)), Prefix.DbSchema);
|
||||||
|
b.ConfigureByConvention();
|
||||||
|
|
||||||
|
b.Property(x => x.QuestionType).IsRequired().HasMaxLength(64);
|
||||||
|
b.Property(x => x.Value).IsRequired().HasMaxLength(1024);
|
||||||
|
|
||||||
|
b.HasOne(x => x.Response)
|
||||||
|
.WithMany(x => x.Answers)
|
||||||
|
.HasForeignKey(x => x.ResponseId)
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne(x => x.Question)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey(x => x.QuestionId)
|
||||||
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.Entity<SocialPost>(b =>
|
||||||
|
{
|
||||||
|
b.ToTable(TableNameResolver.GetFullTableName(nameof(TableNameEnum.SocialPost)), Prefix.DbSchema);
|
||||||
|
b.ConfigureByConvention();
|
||||||
|
|
||||||
|
b.Property(x => x.Content).IsRequired().HasMaxLength(4096);
|
||||||
|
b.Property(x => x.LikeCount).HasDefaultValue(0);
|
||||||
|
b.Property(x => x.IsOwnPost).HasDefaultValue(false);
|
||||||
|
b.Property(x => x.IsLiked).HasDefaultValue(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.Entity<SocialLocation>(b =>
|
||||||
|
{
|
||||||
|
b.ToTable(TableNameResolver.GetFullTableName(nameof(TableNameEnum.SocialLocation)), Prefix.DbSchema);
|
||||||
|
b.ConfigureByConvention();
|
||||||
|
|
||||||
|
b.Property(x => x.Name).IsRequired().HasMaxLength(256);
|
||||||
|
b.Property(x => x.Address).HasMaxLength(512);
|
||||||
|
b.Property(x => x.PlaceId).HasMaxLength(128);
|
||||||
|
|
||||||
|
b.HasOne(x => x.SocialPost)
|
||||||
|
.WithOne(p => p.Location)
|
||||||
|
.HasForeignKey<SocialLocation>(x => x.SocialPostId)
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.Entity<SocialMedia>(b =>
|
||||||
|
{
|
||||||
|
b.ToTable(TableNameResolver.GetFullTableName(nameof(TableNameEnum.SocialMedia)), Prefix.DbSchema);
|
||||||
|
b.ConfigureByConvention();
|
||||||
|
|
||||||
|
b.Property(x => x.Type).IsRequired().HasMaxLength(64);
|
||||||
|
b.Property(x => x.Urls).HasMaxLength(2048);
|
||||||
|
b.Property(x => x.PollQuestion).HasMaxLength(512);
|
||||||
|
b.Property(x => x.PollUserVoteId).HasMaxLength(128);
|
||||||
|
|
||||||
|
b.HasOne(x => x.SocialPost)
|
||||||
|
.WithOne(p => p.Media)
|
||||||
|
.HasForeignKey<SocialMedia>(x => x.SocialPostId)
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.Entity<SocialPollOption>(b =>
|
||||||
|
{
|
||||||
|
b.ToTable(TableNameResolver.GetFullTableName(nameof(TableNameEnum.SocialPollOption)), Prefix.DbSchema);
|
||||||
|
b.ConfigureByConvention();
|
||||||
|
|
||||||
|
b.Property(x => x.Text).IsRequired().HasMaxLength(512);
|
||||||
|
|
||||||
|
b.HasOne(x => x.SocialMedia)
|
||||||
|
.WithMany(x => x.PollOptions)
|
||||||
|
.HasForeignKey(x => x.SocialMediaId)
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.Entity<SocialComment>(b =>
|
||||||
|
{
|
||||||
|
b.ToTable(TableNameResolver.GetFullTableName(nameof(TableNameEnum.SocialComment)), Prefix.DbSchema);
|
||||||
|
b.ConfigureByConvention();
|
||||||
|
|
||||||
|
b.Property(x => x.Content).IsRequired().HasMaxLength(8192);
|
||||||
|
|
||||||
|
b.HasOne(x => x.SocialPost)
|
||||||
|
.WithMany(x => x.Comments)
|
||||||
|
.HasForeignKey(x => x.SocialPostId)
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.Entity<SocialLike>(b =>
|
||||||
|
{
|
||||||
|
b.ToTable(TableNameResolver.GetFullTableName(nameof(TableNameEnum.SocialLike)), Prefix.DbSchema);
|
||||||
|
b.ConfigureByConvention();
|
||||||
|
|
||||||
|
b.HasOne(x => x.SocialPost)
|
||||||
|
.WithMany(x => x.Likes)
|
||||||
|
.HasForeignKey(x => x.SocialPostId)
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore;
|
||||||
namespace Sozsoft.Platform.Migrations
|
namespace Sozsoft.Platform.Migrations
|
||||||
{
|
{
|
||||||
[DbContext(typeof(PlatformDbContext))]
|
[DbContext(typeof(PlatformDbContext))]
|
||||||
[Migration("20260505071050_Initial")]
|
[Migration("20260505120031_Initial")]
|
||||||
partial class Initial
|
partial class Initial
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|
@ -559,6 +559,95 @@ namespace Sozsoft.Platform.Migrations
|
||||||
b.ToTable("Sas_H_AiBot", (string)null);
|
b.ToTable("Sas_H_AiBot", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.Announcement", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<string>("Attachments")
|
||||||
|
.HasMaxLength(2048)
|
||||||
|
.HasColumnType("nvarchar(2048)");
|
||||||
|
|
||||||
|
b.Property<string>("Category")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(64)
|
||||||
|
.HasColumnType("nvarchar(64)");
|
||||||
|
|
||||||
|
b.Property<string>("Content")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(4096)
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
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<string>("Excerpt")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(512)
|
||||||
|
.HasColumnType("nvarchar(512)");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("ExpiryDate")
|
||||||
|
.HasColumnType("datetime2");
|
||||||
|
|
||||||
|
b.Property<string>("ImageUrl")
|
||||||
|
.HasMaxLength(512)
|
||||||
|
.HasColumnType("nvarchar(512)");
|
||||||
|
|
||||||
|
b.Property<bool>("IsDeleted")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bit")
|
||||||
|
.HasDefaultValue(false)
|
||||||
|
.HasColumnName("IsDeleted");
|
||||||
|
|
||||||
|
b.Property<bool>("IsPinned")
|
||||||
|
.HasColumnType("bit");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("LastModificationTime")
|
||||||
|
.HasColumnType("datetime2")
|
||||||
|
.HasColumnName("LastModificationTime");
|
||||||
|
|
||||||
|
b.Property<Guid?>("LastModifierId")
|
||||||
|
.HasColumnType("uniqueidentifier")
|
||||||
|
.HasColumnName("LastModifierId");
|
||||||
|
|
||||||
|
b.Property<DateTime>("PublishDate")
|
||||||
|
.HasColumnType("datetime2");
|
||||||
|
|
||||||
|
b.Property<Guid?>("TenantId")
|
||||||
|
.HasColumnType("uniqueidentifier")
|
||||||
|
.HasColumnName("TenantId");
|
||||||
|
|
||||||
|
b.Property<string>("Title")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("nvarchar(256)");
|
||||||
|
|
||||||
|
b.Property<Guid?>("UserId")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<int>("ViewCount")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int")
|
||||||
|
.HasDefaultValue(0);
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Adm_T_Announcement", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Sozsoft.Platform.Entities.BackgroundWorker", b =>
|
modelBuilder.Entity("Sozsoft.Platform.Entities.BackgroundWorker", b =>
|
||||||
{
|
{
|
||||||
b.Property<Guid>("Id")
|
b.Property<Guid>("Id")
|
||||||
|
|
@ -3757,6 +3846,691 @@ namespace Sozsoft.Platform.Migrations
|
||||||
b.ToTable("Sas_H_SkillType", (string)null);
|
b.ToTable("Sas_H_SkillType", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.SocialComment", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<string>("Content")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(8192)
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
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<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>("SocialPostId")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<Guid?>("TenantId")
|
||||||
|
.HasColumnType("uniqueidentifier")
|
||||||
|
.HasColumnName("TenantId");
|
||||||
|
|
||||||
|
b.Property<Guid?>("UserId")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("SocialPostId");
|
||||||
|
|
||||||
|
b.ToTable("Adm_T_SocialComment", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.SocialLike", 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<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>("SocialPostId")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<Guid?>("TenantId")
|
||||||
|
.HasColumnType("uniqueidentifier")
|
||||||
|
.HasColumnName("TenantId");
|
||||||
|
|
||||||
|
b.Property<Guid?>("UserId")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("SocialPostId");
|
||||||
|
|
||||||
|
b.ToTable("Adm_T_SocialLike", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.SocialLocation", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<string>("Address")
|
||||||
|
.HasMaxLength(512)
|
||||||
|
.HasColumnType("nvarchar(512)");
|
||||||
|
|
||||||
|
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<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<double?>("Lat")
|
||||||
|
.HasColumnType("float");
|
||||||
|
|
||||||
|
b.Property<double?>("Lng")
|
||||||
|
.HasColumnType("float");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("nvarchar(256)");
|
||||||
|
|
||||||
|
b.Property<string>("PlaceId")
|
||||||
|
.HasMaxLength(128)
|
||||||
|
.HasColumnType("nvarchar(128)");
|
||||||
|
|
||||||
|
b.Property<Guid>("SocialPostId")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<Guid?>("TenantId")
|
||||||
|
.HasColumnType("uniqueidentifier")
|
||||||
|
.HasColumnName("TenantId");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("SocialPostId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("Adm_T_SocialLocation", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.SocialMedia", 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<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<DateTime?>("PollEndsAt")
|
||||||
|
.HasColumnType("datetime2");
|
||||||
|
|
||||||
|
b.Property<string>("PollQuestion")
|
||||||
|
.HasMaxLength(512)
|
||||||
|
.HasColumnType("nvarchar(512)");
|
||||||
|
|
||||||
|
b.Property<int?>("PollTotalVotes")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("PollUserVoteId")
|
||||||
|
.HasMaxLength(128)
|
||||||
|
.HasColumnType("nvarchar(128)");
|
||||||
|
|
||||||
|
b.Property<Guid>("SocialPostId")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<Guid?>("TenantId")
|
||||||
|
.HasColumnType("uniqueidentifier")
|
||||||
|
.HasColumnName("TenantId");
|
||||||
|
|
||||||
|
b.Property<string>("Type")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(64)
|
||||||
|
.HasColumnType("nvarchar(64)");
|
||||||
|
|
||||||
|
b.PrimitiveCollection<string>("Urls")
|
||||||
|
.HasMaxLength(2048)
|
||||||
|
.HasColumnType("nvarchar(2048)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("SocialPostId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("Adm_T_SocialMedia", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.SocialPollOption", 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<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>("SocialMediaId")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<Guid?>("TenantId")
|
||||||
|
.HasColumnType("uniqueidentifier")
|
||||||
|
.HasColumnName("TenantId");
|
||||||
|
|
||||||
|
b.Property<string>("Text")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(512)
|
||||||
|
.HasColumnType("nvarchar(512)");
|
||||||
|
|
||||||
|
b.Property<int>("Votes")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("SocialMediaId");
|
||||||
|
|
||||||
|
b.ToTable("Adm_T_SocialPollOption", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.SocialPost", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<string>("Content")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(4096)
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
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<bool>("IsDeleted")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bit")
|
||||||
|
.HasDefaultValue(false)
|
||||||
|
.HasColumnName("IsDeleted");
|
||||||
|
|
||||||
|
b.Property<bool>("IsLiked")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bit")
|
||||||
|
.HasDefaultValue(false);
|
||||||
|
|
||||||
|
b.Property<bool>("IsOwnPost")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bit")
|
||||||
|
.HasDefaultValue(false);
|
||||||
|
|
||||||
|
b.Property<DateTime?>("LastModificationTime")
|
||||||
|
.HasColumnType("datetime2")
|
||||||
|
.HasColumnName("LastModificationTime");
|
||||||
|
|
||||||
|
b.Property<Guid?>("LastModifierId")
|
||||||
|
.HasColumnType("uniqueidentifier")
|
||||||
|
.HasColumnName("LastModifierId");
|
||||||
|
|
||||||
|
b.Property<int>("LikeCount")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int")
|
||||||
|
.HasDefaultValue(0);
|
||||||
|
|
||||||
|
b.Property<Guid?>("TenantId")
|
||||||
|
.HasColumnType("uniqueidentifier")
|
||||||
|
.HasColumnName("TenantId");
|
||||||
|
|
||||||
|
b.Property<Guid?>("UserId")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Adm_T_SocialPost", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.Survey", 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<DateTime>("Deadline")
|
||||||
|
.HasColumnType("datetime2");
|
||||||
|
|
||||||
|
b.Property<Guid?>("DeleterId")
|
||||||
|
.HasColumnType("uniqueidentifier")
|
||||||
|
.HasColumnName("DeleterId");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DeletionTime")
|
||||||
|
.HasColumnType("datetime2")
|
||||||
|
.HasColumnName("DeletionTime");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.HasMaxLength(2048)
|
||||||
|
.HasColumnType("nvarchar(2048)");
|
||||||
|
|
||||||
|
b.Property<bool>("IsAnonymous")
|
||||||
|
.HasColumnType("bit");
|
||||||
|
|
||||||
|
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<int>("Responses")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int")
|
||||||
|
.HasDefaultValue(0);
|
||||||
|
|
||||||
|
b.Property<string>("Status")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(10)
|
||||||
|
.HasColumnType("nvarchar(10)");
|
||||||
|
|
||||||
|
b.Property<Guid?>("TenantId")
|
||||||
|
.HasColumnType("uniqueidentifier")
|
||||||
|
.HasColumnName("TenantId");
|
||||||
|
|
||||||
|
b.Property<string>("Title")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("nvarchar(256)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Adm_T_Survey", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.SurveyAnswer", 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<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>("QuestionId")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<string>("QuestionType")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(64)
|
||||||
|
.HasColumnType("nvarchar(64)");
|
||||||
|
|
||||||
|
b.Property<Guid>("ResponseId")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<Guid?>("TenantId")
|
||||||
|
.HasColumnType("uniqueidentifier")
|
||||||
|
.HasColumnName("TenantId");
|
||||||
|
|
||||||
|
b.Property<string>("Value")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(1024)
|
||||||
|
.HasColumnType("nvarchar(1024)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("QuestionId");
|
||||||
|
|
||||||
|
b.HasIndex("ResponseId");
|
||||||
|
|
||||||
|
b.ToTable("Adm_T_SurveyAnswer", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.SurveyQuestion", 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<bool>("IsDeleted")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bit")
|
||||||
|
.HasDefaultValue(false)
|
||||||
|
.HasColumnName("IsDeleted");
|
||||||
|
|
||||||
|
b.Property<bool>("IsRequired")
|
||||||
|
.HasColumnType("bit");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("LastModificationTime")
|
||||||
|
.HasColumnType("datetime2")
|
||||||
|
.HasColumnName("LastModificationTime");
|
||||||
|
|
||||||
|
b.Property<Guid?>("LastModifierId")
|
||||||
|
.HasColumnType("uniqueidentifier")
|
||||||
|
.HasColumnName("LastModifierId");
|
||||||
|
|
||||||
|
b.Property<int>("Order")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("QuestionText")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(1024)
|
||||||
|
.HasColumnType("nvarchar(1024)");
|
||||||
|
|
||||||
|
b.Property<Guid>("SurveyId")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<Guid?>("TenantId")
|
||||||
|
.HasColumnType("uniqueidentifier")
|
||||||
|
.HasColumnName("TenantId");
|
||||||
|
|
||||||
|
b.Property<string>("Type")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(64)
|
||||||
|
.HasColumnType("nvarchar(64)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("SurveyId");
|
||||||
|
|
||||||
|
b.ToTable("Adm_T_SurveyQuestion", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.SurveyQuestionOption", 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<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<int>("Order")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<Guid>("QuestionId")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<Guid?>("TenantId")
|
||||||
|
.HasColumnType("uniqueidentifier")
|
||||||
|
.HasColumnName("TenantId");
|
||||||
|
|
||||||
|
b.Property<string>("Text")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(512)
|
||||||
|
.HasColumnType("nvarchar(512)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("QuestionId");
|
||||||
|
|
||||||
|
b.ToTable("Adm_T_SurveyQuestionOption", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.SurveyResponse", 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<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<DateTime>("SubmissionTime")
|
||||||
|
.HasColumnType("datetime2");
|
||||||
|
|
||||||
|
b.Property<Guid>("SurveyId")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<Guid?>("TenantId")
|
||||||
|
.HasColumnType("uniqueidentifier")
|
||||||
|
.HasColumnName("TenantId");
|
||||||
|
|
||||||
|
b.Property<Guid?>("UserId")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("SurveyId");
|
||||||
|
|
||||||
|
b.ToTable("Adm_T_SurveyResponse", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Sozsoft.Platform.Entities.Uom", b =>
|
modelBuilder.Entity("Sozsoft.Platform.Entities.Uom", b =>
|
||||||
{
|
{
|
||||||
b.Property<string>("Id")
|
b.Property<string>("Id")
|
||||||
|
|
@ -6429,6 +7203,113 @@ namespace Sozsoft.Platform.Migrations
|
||||||
b.Navigation("SkillType");
|
b.Navigation("SkillType");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.SocialComment", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Sozsoft.Platform.Entities.SocialPost", "SocialPost")
|
||||||
|
.WithMany("Comments")
|
||||||
|
.HasForeignKey("SocialPostId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("SocialPost");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.SocialLike", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Sozsoft.Platform.Entities.SocialPost", "SocialPost")
|
||||||
|
.WithMany("Likes")
|
||||||
|
.HasForeignKey("SocialPostId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("SocialPost");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.SocialLocation", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Sozsoft.Platform.Entities.SocialPost", "SocialPost")
|
||||||
|
.WithOne("Location")
|
||||||
|
.HasForeignKey("Sozsoft.Platform.Entities.SocialLocation", "SocialPostId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("SocialPost");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.SocialMedia", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Sozsoft.Platform.Entities.SocialPost", "SocialPost")
|
||||||
|
.WithOne("Media")
|
||||||
|
.HasForeignKey("Sozsoft.Platform.Entities.SocialMedia", "SocialPostId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("SocialPost");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.SocialPollOption", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Sozsoft.Platform.Entities.SocialMedia", "SocialMedia")
|
||||||
|
.WithMany("PollOptions")
|
||||||
|
.HasForeignKey("SocialMediaId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("SocialMedia");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.SurveyAnswer", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Sozsoft.Platform.Entities.SurveyQuestion", "Question")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("QuestionId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Sozsoft.Platform.Entities.SurveyResponse", "Response")
|
||||||
|
.WithMany("Answers")
|
||||||
|
.HasForeignKey("ResponseId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Question");
|
||||||
|
|
||||||
|
b.Navigation("Response");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.SurveyQuestion", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Sozsoft.Platform.Entities.Survey", "Survey")
|
||||||
|
.WithMany("Questions")
|
||||||
|
.HasForeignKey("SurveyId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Survey");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.SurveyQuestionOption", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Sozsoft.Platform.Entities.SurveyQuestion", "Question")
|
||||||
|
.WithMany("Options")
|
||||||
|
.HasForeignKey("QuestionId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Question");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.SurveyResponse", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Sozsoft.Platform.Entities.Survey", "Survey")
|
||||||
|
.WithMany("SurveyResponses")
|
||||||
|
.HasForeignKey("SurveyId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Survey");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Sozsoft.Platform.Entities.Uom", b =>
|
modelBuilder.Entity("Sozsoft.Platform.Entities.Uom", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("Sozsoft.Platform.Entities.UomCategory", "UomCategory")
|
b.HasOne("Sozsoft.Platform.Entities.UomCategory", "UomCategory")
|
||||||
|
|
@ -6673,6 +7554,39 @@ namespace Sozsoft.Platform.Migrations
|
||||||
b.Navigation("Skills");
|
b.Navigation("Skills");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.SocialMedia", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("PollOptions");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.SocialPost", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Comments");
|
||||||
|
|
||||||
|
b.Navigation("Likes");
|
||||||
|
|
||||||
|
b.Navigation("Location");
|
||||||
|
|
||||||
|
b.Navigation("Media");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.Survey", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Questions");
|
||||||
|
|
||||||
|
b.Navigation("SurveyResponses");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.SurveyQuestion", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Options");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.SurveyResponse", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Answers");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Sozsoft.Platform.Entities.UomCategory", b =>
|
modelBuilder.Entity("Sozsoft.Platform.Entities.UomCategory", b =>
|
||||||
{
|
{
|
||||||
b.Navigation("Uoms");
|
b.Navigation("Uoms");
|
||||||
|
|
@ -462,6 +462,36 @@ namespace Sozsoft.Platform.Migrations
|
||||||
table.PrimaryKey("PK_AbpUsers", x => x.Id);
|
table.PrimaryKey("PK_AbpUsers", x => x.Id);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Adm_T_Announcement",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||||
|
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||||
|
Title = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: false),
|
||||||
|
Excerpt = table.Column<string>(type: "nvarchar(512)", maxLength: 512, nullable: false),
|
||||||
|
Content = table.Column<string>(type: "nvarchar(max)", maxLength: 4096, nullable: false),
|
||||||
|
ImageUrl = table.Column<string>(type: "nvarchar(512)", maxLength: 512, nullable: true),
|
||||||
|
Category = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: false),
|
||||||
|
UserId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||||
|
PublishDate = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||||
|
ExpiryDate = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||||
|
IsPinned = table.Column<bool>(type: "bit", nullable: false),
|
||||||
|
ViewCount = table.Column<int>(type: "int", nullable: false, defaultValue: 0),
|
||||||
|
Attachments = table.Column<string>(type: "nvarchar(2048)", maxLength: 2048, 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_Announcement", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
migrationBuilder.CreateTable(
|
||||||
name: "Adm_T_Department",
|
name: "Adm_T_Department",
|
||||||
columns: table => new
|
columns: table => new
|
||||||
|
|
@ -572,6 +602,55 @@ namespace Sozsoft.Platform.Migrations
|
||||||
table.PrimaryKey("PK_Adm_T_Sector", x => x.Id);
|
table.PrimaryKey("PK_Adm_T_Sector", x => x.Id);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Adm_T_SocialPost",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||||
|
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||||
|
UserId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||||
|
Content = table.Column<string>(type: "nvarchar(max)", maxLength: 4096, nullable: false),
|
||||||
|
LikeCount = table.Column<int>(type: "int", nullable: false, defaultValue: 0),
|
||||||
|
IsLiked = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
|
||||||
|
IsOwnPost = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
|
||||||
|
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_SocialPost", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Adm_T_Survey",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||||
|
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||||
|
Title = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: false),
|
||||||
|
Description = table.Column<string>(type: "nvarchar(2048)", maxLength: 2048, nullable: true),
|
||||||
|
Deadline = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||||
|
Responses = table.Column<int>(type: "int", nullable: false, defaultValue: 0),
|
||||||
|
Status = table.Column<string>(type: "nvarchar(10)", maxLength: 10, nullable: false),
|
||||||
|
IsAnonymous = table.Column<bool>(type: "bit", nullable: false),
|
||||||
|
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_Survey", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
migrationBuilder.CreateTable(
|
||||||
name: "Adm_T_WorkHour",
|
name: "Adm_T_WorkHour",
|
||||||
columns: table => new
|
columns: table => new
|
||||||
|
|
@ -1867,6 +1946,182 @@ namespace Sozsoft.Platform.Migrations
|
||||||
onDelete: ReferentialAction.Cascade);
|
onDelete: ReferentialAction.Cascade);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Adm_T_SocialComment",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||||
|
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||||
|
SocialPostId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||||
|
UserId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||||
|
Content = table.Column<string>(type: "nvarchar(max)", maxLength: 8192, nullable: false),
|
||||||
|
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_SocialComment", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Adm_T_SocialComment_Adm_T_SocialPost_SocialPostId",
|
||||||
|
column: x => x.SocialPostId,
|
||||||
|
principalTable: "Adm_T_SocialPost",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Adm_T_SocialLike",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||||
|
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||||
|
SocialPostId = 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_SocialLike", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Adm_T_SocialLike_Adm_T_SocialPost_SocialPostId",
|
||||||
|
column: x => x.SocialPostId,
|
||||||
|
principalTable: "Adm_T_SocialPost",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Adm_T_SocialLocation",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||||
|
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||||
|
SocialPostId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||||
|
Name = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: false),
|
||||||
|
Address = table.Column<string>(type: "nvarchar(512)", maxLength: 512, nullable: true),
|
||||||
|
Lat = table.Column<double>(type: "float", nullable: true),
|
||||||
|
Lng = table.Column<double>(type: "float", nullable: true),
|
||||||
|
PlaceId = table.Column<string>(type: "nvarchar(128)", maxLength: 128, 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_SocialLocation", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Adm_T_SocialLocation_Adm_T_SocialPost_SocialPostId",
|
||||||
|
column: x => x.SocialPostId,
|
||||||
|
principalTable: "Adm_T_SocialPost",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Adm_T_SocialMedia",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||||
|
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||||
|
SocialPostId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||||
|
Type = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: false),
|
||||||
|
Urls = table.Column<string>(type: "nvarchar(2048)", maxLength: 2048, nullable: true),
|
||||||
|
PollQuestion = table.Column<string>(type: "nvarchar(512)", maxLength: 512, nullable: true),
|
||||||
|
PollTotalVotes = table.Column<int>(type: "int", nullable: true),
|
||||||
|
PollEndsAt = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||||
|
PollUserVoteId = table.Column<string>(type: "nvarchar(128)", maxLength: 128, 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_SocialMedia", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Adm_T_SocialMedia_Adm_T_SocialPost_SocialPostId",
|
||||||
|
column: x => x.SocialPostId,
|
||||||
|
principalTable: "Adm_T_SocialPost",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Adm_T_SurveyQuestion",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||||
|
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||||
|
SurveyId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||||
|
QuestionText = table.Column<string>(type: "nvarchar(1024)", maxLength: 1024, nullable: false),
|
||||||
|
Type = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: false),
|
||||||
|
Order = table.Column<int>(type: "int", nullable: false),
|
||||||
|
IsRequired = table.Column<bool>(type: "bit", nullable: false),
|
||||||
|
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_SurveyQuestion", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Adm_T_SurveyQuestion_Adm_T_Survey_SurveyId",
|
||||||
|
column: x => x.SurveyId,
|
||||||
|
principalTable: "Adm_T_Survey",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Adm_T_SurveyResponse",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||||
|
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||||
|
SurveyId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||||
|
UserId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||||
|
SubmissionTime = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||||
|
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_SurveyResponse", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Adm_T_SurveyResponse_Adm_T_Survey_SurveyId",
|
||||||
|
column: x => x.SurveyId,
|
||||||
|
principalTable: "Adm_T_Survey",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
migrationBuilder.CreateTable(
|
||||||
name: "OpenIddictAuthorizations",
|
name: "OpenIddictAuthorizations",
|
||||||
columns: table => new
|
columns: table => new
|
||||||
|
|
@ -2365,6 +2620,97 @@ namespace Sozsoft.Platform.Migrations
|
||||||
onDelete: ReferentialAction.Cascade);
|
onDelete: ReferentialAction.Cascade);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Adm_T_SocialPollOption",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||||
|
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||||
|
SocialMediaId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||||
|
Text = table.Column<string>(type: "nvarchar(512)", maxLength: 512, nullable: false),
|
||||||
|
Votes = table.Column<int>(type: "int", nullable: false),
|
||||||
|
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_SocialPollOption", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Adm_T_SocialPollOption_Adm_T_SocialMedia_SocialMediaId",
|
||||||
|
column: x => x.SocialMediaId,
|
||||||
|
principalTable: "Adm_T_SocialMedia",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Adm_T_SurveyQuestionOption",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||||
|
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||||
|
QuestionId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||||
|
Text = table.Column<string>(type: "nvarchar(512)", maxLength: 512, nullable: false),
|
||||||
|
Order = table.Column<int>(type: "int", nullable: false),
|
||||||
|
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_SurveyQuestionOption", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Adm_T_SurveyQuestionOption_Adm_T_SurveyQuestion_QuestionId",
|
||||||
|
column: x => x.QuestionId,
|
||||||
|
principalTable: "Adm_T_SurveyQuestion",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Adm_T_SurveyAnswer",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||||
|
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||||
|
ResponseId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||||
|
QuestionId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||||
|
QuestionType = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: false),
|
||||||
|
Value = table.Column<string>(type: "nvarchar(1024)", maxLength: 1024, nullable: false),
|
||||||
|
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_SurveyAnswer", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Adm_T_SurveyAnswer_Adm_T_SurveyQuestion_QuestionId",
|
||||||
|
column: x => x.QuestionId,
|
||||||
|
principalTable: "Adm_T_SurveyQuestion",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Restrict);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Adm_T_SurveyAnswer_Adm_T_SurveyResponse_ResponseId",
|
||||||
|
column: x => x.ResponseId,
|
||||||
|
principalTable: "Adm_T_SurveyResponse",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
migrationBuilder.CreateTable(
|
||||||
name: "OpenIddictTokens",
|
name: "OpenIddictTokens",
|
||||||
columns: table => new
|
columns: table => new
|
||||||
|
|
@ -2781,6 +3127,58 @@ namespace Sozsoft.Platform.Migrations
|
||||||
table: "Adm_T_ReportTemplate",
|
table: "Adm_T_ReportTemplate",
|
||||||
column: "CategoryId");
|
column: "CategoryId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Adm_T_SocialComment_SocialPostId",
|
||||||
|
table: "Adm_T_SocialComment",
|
||||||
|
column: "SocialPostId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Adm_T_SocialLike_SocialPostId",
|
||||||
|
table: "Adm_T_SocialLike",
|
||||||
|
column: "SocialPostId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Adm_T_SocialLocation_SocialPostId",
|
||||||
|
table: "Adm_T_SocialLocation",
|
||||||
|
column: "SocialPostId",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Adm_T_SocialMedia_SocialPostId",
|
||||||
|
table: "Adm_T_SocialMedia",
|
||||||
|
column: "SocialPostId",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Adm_T_SocialPollOption_SocialMediaId",
|
||||||
|
table: "Adm_T_SocialPollOption",
|
||||||
|
column: "SocialMediaId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Adm_T_SurveyAnswer_QuestionId",
|
||||||
|
table: "Adm_T_SurveyAnswer",
|
||||||
|
column: "QuestionId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Adm_T_SurveyAnswer_ResponseId",
|
||||||
|
table: "Adm_T_SurveyAnswer",
|
||||||
|
column: "ResponseId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Adm_T_SurveyQuestion_SurveyId",
|
||||||
|
table: "Adm_T_SurveyQuestion",
|
||||||
|
column: "SurveyId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Adm_T_SurveyQuestionOption_QuestionId",
|
||||||
|
table: "Adm_T_SurveyQuestionOption",
|
||||||
|
column: "QuestionId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Adm_T_SurveyResponse_SurveyId",
|
||||||
|
table: "Adm_T_SurveyResponse",
|
||||||
|
column: "SurveyId");
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
migrationBuilder.CreateIndex(
|
||||||
name: "IX_OpenIddictApplications_ClientId",
|
name: "IX_OpenIddictApplications_ClientId",
|
||||||
table: "OpenIddictApplications",
|
table: "OpenIddictApplications",
|
||||||
|
|
@ -3065,6 +3463,9 @@ namespace Sozsoft.Platform.Migrations
|
||||||
migrationBuilder.DropTable(
|
migrationBuilder.DropTable(
|
||||||
name: "AbpUserTokens");
|
name: "AbpUserTokens");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Adm_T_Announcement");
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
migrationBuilder.DropTable(
|
||||||
name: "Adm_T_IpRestriction");
|
name: "Adm_T_IpRestriction");
|
||||||
|
|
||||||
|
|
@ -3080,6 +3481,24 @@ namespace Sozsoft.Platform.Migrations
|
||||||
migrationBuilder.DropTable(
|
migrationBuilder.DropTable(
|
||||||
name: "Adm_T_Sector");
|
name: "Adm_T_Sector");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Adm_T_SocialComment");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Adm_T_SocialLike");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Adm_T_SocialLocation");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Adm_T_SocialPollOption");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Adm_T_SurveyAnswer");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Adm_T_SurveyQuestionOption");
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
migrationBuilder.DropTable(
|
||||||
name: "Adm_T_WorkHour");
|
name: "Adm_T_WorkHour");
|
||||||
|
|
||||||
|
|
@ -3221,6 +3640,15 @@ namespace Sozsoft.Platform.Migrations
|
||||||
migrationBuilder.DropTable(
|
migrationBuilder.DropTable(
|
||||||
name: "Adm_T_ReportCategory");
|
name: "Adm_T_ReportCategory");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Adm_T_SocialMedia");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Adm_T_SurveyResponse");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Adm_T_SurveyQuestion");
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
migrationBuilder.DropTable(
|
||||||
name: "OpenIddictAuthorizations");
|
name: "OpenIddictAuthorizations");
|
||||||
|
|
||||||
|
|
@ -3263,6 +3691,12 @@ namespace Sozsoft.Platform.Migrations
|
||||||
migrationBuilder.DropTable(
|
migrationBuilder.DropTable(
|
||||||
name: "AbpAuditLogs");
|
name: "AbpAuditLogs");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Adm_T_SocialPost");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Adm_T_Survey");
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
migrationBuilder.DropTable(
|
||||||
name: "OpenIddictApplications");
|
name: "OpenIddictApplications");
|
||||||
|
|
||||||
|
|
@ -556,6 +556,95 @@ namespace Sozsoft.Platform.Migrations
|
||||||
b.ToTable("Sas_H_AiBot", (string)null);
|
b.ToTable("Sas_H_AiBot", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.Announcement", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<string>("Attachments")
|
||||||
|
.HasMaxLength(2048)
|
||||||
|
.HasColumnType("nvarchar(2048)");
|
||||||
|
|
||||||
|
b.Property<string>("Category")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(64)
|
||||||
|
.HasColumnType("nvarchar(64)");
|
||||||
|
|
||||||
|
b.Property<string>("Content")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(4096)
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
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<string>("Excerpt")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(512)
|
||||||
|
.HasColumnType("nvarchar(512)");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("ExpiryDate")
|
||||||
|
.HasColumnType("datetime2");
|
||||||
|
|
||||||
|
b.Property<string>("ImageUrl")
|
||||||
|
.HasMaxLength(512)
|
||||||
|
.HasColumnType("nvarchar(512)");
|
||||||
|
|
||||||
|
b.Property<bool>("IsDeleted")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bit")
|
||||||
|
.HasDefaultValue(false)
|
||||||
|
.HasColumnName("IsDeleted");
|
||||||
|
|
||||||
|
b.Property<bool>("IsPinned")
|
||||||
|
.HasColumnType("bit");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("LastModificationTime")
|
||||||
|
.HasColumnType("datetime2")
|
||||||
|
.HasColumnName("LastModificationTime");
|
||||||
|
|
||||||
|
b.Property<Guid?>("LastModifierId")
|
||||||
|
.HasColumnType("uniqueidentifier")
|
||||||
|
.HasColumnName("LastModifierId");
|
||||||
|
|
||||||
|
b.Property<DateTime>("PublishDate")
|
||||||
|
.HasColumnType("datetime2");
|
||||||
|
|
||||||
|
b.Property<Guid?>("TenantId")
|
||||||
|
.HasColumnType("uniqueidentifier")
|
||||||
|
.HasColumnName("TenantId");
|
||||||
|
|
||||||
|
b.Property<string>("Title")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("nvarchar(256)");
|
||||||
|
|
||||||
|
b.Property<Guid?>("UserId")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<int>("ViewCount")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int")
|
||||||
|
.HasDefaultValue(0);
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Adm_T_Announcement", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Sozsoft.Platform.Entities.BackgroundWorker", b =>
|
modelBuilder.Entity("Sozsoft.Platform.Entities.BackgroundWorker", b =>
|
||||||
{
|
{
|
||||||
b.Property<Guid>("Id")
|
b.Property<Guid>("Id")
|
||||||
|
|
@ -3754,6 +3843,691 @@ namespace Sozsoft.Platform.Migrations
|
||||||
b.ToTable("Sas_H_SkillType", (string)null);
|
b.ToTable("Sas_H_SkillType", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.SocialComment", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<string>("Content")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(8192)
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
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<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>("SocialPostId")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<Guid?>("TenantId")
|
||||||
|
.HasColumnType("uniqueidentifier")
|
||||||
|
.HasColumnName("TenantId");
|
||||||
|
|
||||||
|
b.Property<Guid?>("UserId")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("SocialPostId");
|
||||||
|
|
||||||
|
b.ToTable("Adm_T_SocialComment", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.SocialLike", 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<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>("SocialPostId")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<Guid?>("TenantId")
|
||||||
|
.HasColumnType("uniqueidentifier")
|
||||||
|
.HasColumnName("TenantId");
|
||||||
|
|
||||||
|
b.Property<Guid?>("UserId")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("SocialPostId");
|
||||||
|
|
||||||
|
b.ToTable("Adm_T_SocialLike", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.SocialLocation", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<string>("Address")
|
||||||
|
.HasMaxLength(512)
|
||||||
|
.HasColumnType("nvarchar(512)");
|
||||||
|
|
||||||
|
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<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<double?>("Lat")
|
||||||
|
.HasColumnType("float");
|
||||||
|
|
||||||
|
b.Property<double?>("Lng")
|
||||||
|
.HasColumnType("float");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("nvarchar(256)");
|
||||||
|
|
||||||
|
b.Property<string>("PlaceId")
|
||||||
|
.HasMaxLength(128)
|
||||||
|
.HasColumnType("nvarchar(128)");
|
||||||
|
|
||||||
|
b.Property<Guid>("SocialPostId")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<Guid?>("TenantId")
|
||||||
|
.HasColumnType("uniqueidentifier")
|
||||||
|
.HasColumnName("TenantId");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("SocialPostId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("Adm_T_SocialLocation", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.SocialMedia", 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<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<DateTime?>("PollEndsAt")
|
||||||
|
.HasColumnType("datetime2");
|
||||||
|
|
||||||
|
b.Property<string>("PollQuestion")
|
||||||
|
.HasMaxLength(512)
|
||||||
|
.HasColumnType("nvarchar(512)");
|
||||||
|
|
||||||
|
b.Property<int?>("PollTotalVotes")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("PollUserVoteId")
|
||||||
|
.HasMaxLength(128)
|
||||||
|
.HasColumnType("nvarchar(128)");
|
||||||
|
|
||||||
|
b.Property<Guid>("SocialPostId")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<Guid?>("TenantId")
|
||||||
|
.HasColumnType("uniqueidentifier")
|
||||||
|
.HasColumnName("TenantId");
|
||||||
|
|
||||||
|
b.Property<string>("Type")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(64)
|
||||||
|
.HasColumnType("nvarchar(64)");
|
||||||
|
|
||||||
|
b.PrimitiveCollection<string>("Urls")
|
||||||
|
.HasMaxLength(2048)
|
||||||
|
.HasColumnType("nvarchar(2048)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("SocialPostId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("Adm_T_SocialMedia", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.SocialPollOption", 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<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>("SocialMediaId")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<Guid?>("TenantId")
|
||||||
|
.HasColumnType("uniqueidentifier")
|
||||||
|
.HasColumnName("TenantId");
|
||||||
|
|
||||||
|
b.Property<string>("Text")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(512)
|
||||||
|
.HasColumnType("nvarchar(512)");
|
||||||
|
|
||||||
|
b.Property<int>("Votes")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("SocialMediaId");
|
||||||
|
|
||||||
|
b.ToTable("Adm_T_SocialPollOption", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.SocialPost", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<string>("Content")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(4096)
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
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<bool>("IsDeleted")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bit")
|
||||||
|
.HasDefaultValue(false)
|
||||||
|
.HasColumnName("IsDeleted");
|
||||||
|
|
||||||
|
b.Property<bool>("IsLiked")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bit")
|
||||||
|
.HasDefaultValue(false);
|
||||||
|
|
||||||
|
b.Property<bool>("IsOwnPost")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bit")
|
||||||
|
.HasDefaultValue(false);
|
||||||
|
|
||||||
|
b.Property<DateTime?>("LastModificationTime")
|
||||||
|
.HasColumnType("datetime2")
|
||||||
|
.HasColumnName("LastModificationTime");
|
||||||
|
|
||||||
|
b.Property<Guid?>("LastModifierId")
|
||||||
|
.HasColumnType("uniqueidentifier")
|
||||||
|
.HasColumnName("LastModifierId");
|
||||||
|
|
||||||
|
b.Property<int>("LikeCount")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int")
|
||||||
|
.HasDefaultValue(0);
|
||||||
|
|
||||||
|
b.Property<Guid?>("TenantId")
|
||||||
|
.HasColumnType("uniqueidentifier")
|
||||||
|
.HasColumnName("TenantId");
|
||||||
|
|
||||||
|
b.Property<Guid?>("UserId")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Adm_T_SocialPost", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.Survey", 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<DateTime>("Deadline")
|
||||||
|
.HasColumnType("datetime2");
|
||||||
|
|
||||||
|
b.Property<Guid?>("DeleterId")
|
||||||
|
.HasColumnType("uniqueidentifier")
|
||||||
|
.HasColumnName("DeleterId");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DeletionTime")
|
||||||
|
.HasColumnType("datetime2")
|
||||||
|
.HasColumnName("DeletionTime");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.HasMaxLength(2048)
|
||||||
|
.HasColumnType("nvarchar(2048)");
|
||||||
|
|
||||||
|
b.Property<bool>("IsAnonymous")
|
||||||
|
.HasColumnType("bit");
|
||||||
|
|
||||||
|
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<int>("Responses")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int")
|
||||||
|
.HasDefaultValue(0);
|
||||||
|
|
||||||
|
b.Property<string>("Status")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(10)
|
||||||
|
.HasColumnType("nvarchar(10)");
|
||||||
|
|
||||||
|
b.Property<Guid?>("TenantId")
|
||||||
|
.HasColumnType("uniqueidentifier")
|
||||||
|
.HasColumnName("TenantId");
|
||||||
|
|
||||||
|
b.Property<string>("Title")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("nvarchar(256)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Adm_T_Survey", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.SurveyAnswer", 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<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>("QuestionId")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<string>("QuestionType")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(64)
|
||||||
|
.HasColumnType("nvarchar(64)");
|
||||||
|
|
||||||
|
b.Property<Guid>("ResponseId")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<Guid?>("TenantId")
|
||||||
|
.HasColumnType("uniqueidentifier")
|
||||||
|
.HasColumnName("TenantId");
|
||||||
|
|
||||||
|
b.Property<string>("Value")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(1024)
|
||||||
|
.HasColumnType("nvarchar(1024)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("QuestionId");
|
||||||
|
|
||||||
|
b.HasIndex("ResponseId");
|
||||||
|
|
||||||
|
b.ToTable("Adm_T_SurveyAnswer", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.SurveyQuestion", 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<bool>("IsDeleted")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bit")
|
||||||
|
.HasDefaultValue(false)
|
||||||
|
.HasColumnName("IsDeleted");
|
||||||
|
|
||||||
|
b.Property<bool>("IsRequired")
|
||||||
|
.HasColumnType("bit");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("LastModificationTime")
|
||||||
|
.HasColumnType("datetime2")
|
||||||
|
.HasColumnName("LastModificationTime");
|
||||||
|
|
||||||
|
b.Property<Guid?>("LastModifierId")
|
||||||
|
.HasColumnType("uniqueidentifier")
|
||||||
|
.HasColumnName("LastModifierId");
|
||||||
|
|
||||||
|
b.Property<int>("Order")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("QuestionText")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(1024)
|
||||||
|
.HasColumnType("nvarchar(1024)");
|
||||||
|
|
||||||
|
b.Property<Guid>("SurveyId")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<Guid?>("TenantId")
|
||||||
|
.HasColumnType("uniqueidentifier")
|
||||||
|
.HasColumnName("TenantId");
|
||||||
|
|
||||||
|
b.Property<string>("Type")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(64)
|
||||||
|
.HasColumnType("nvarchar(64)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("SurveyId");
|
||||||
|
|
||||||
|
b.ToTable("Adm_T_SurveyQuestion", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.SurveyQuestionOption", 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<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<int>("Order")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<Guid>("QuestionId")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<Guid?>("TenantId")
|
||||||
|
.HasColumnType("uniqueidentifier")
|
||||||
|
.HasColumnName("TenantId");
|
||||||
|
|
||||||
|
b.Property<string>("Text")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(512)
|
||||||
|
.HasColumnType("nvarchar(512)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("QuestionId");
|
||||||
|
|
||||||
|
b.ToTable("Adm_T_SurveyQuestionOption", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.SurveyResponse", 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<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<DateTime>("SubmissionTime")
|
||||||
|
.HasColumnType("datetime2");
|
||||||
|
|
||||||
|
b.Property<Guid>("SurveyId")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<Guid?>("TenantId")
|
||||||
|
.HasColumnType("uniqueidentifier")
|
||||||
|
.HasColumnName("TenantId");
|
||||||
|
|
||||||
|
b.Property<Guid?>("UserId")
|
||||||
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("SurveyId");
|
||||||
|
|
||||||
|
b.ToTable("Adm_T_SurveyResponse", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Sozsoft.Platform.Entities.Uom", b =>
|
modelBuilder.Entity("Sozsoft.Platform.Entities.Uom", b =>
|
||||||
{
|
{
|
||||||
b.Property<string>("Id")
|
b.Property<string>("Id")
|
||||||
|
|
@ -6426,6 +7200,113 @@ namespace Sozsoft.Platform.Migrations
|
||||||
b.Navigation("SkillType");
|
b.Navigation("SkillType");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.SocialComment", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Sozsoft.Platform.Entities.SocialPost", "SocialPost")
|
||||||
|
.WithMany("Comments")
|
||||||
|
.HasForeignKey("SocialPostId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("SocialPost");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.SocialLike", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Sozsoft.Platform.Entities.SocialPost", "SocialPost")
|
||||||
|
.WithMany("Likes")
|
||||||
|
.HasForeignKey("SocialPostId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("SocialPost");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.SocialLocation", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Sozsoft.Platform.Entities.SocialPost", "SocialPost")
|
||||||
|
.WithOne("Location")
|
||||||
|
.HasForeignKey("Sozsoft.Platform.Entities.SocialLocation", "SocialPostId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("SocialPost");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.SocialMedia", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Sozsoft.Platform.Entities.SocialPost", "SocialPost")
|
||||||
|
.WithOne("Media")
|
||||||
|
.HasForeignKey("Sozsoft.Platform.Entities.SocialMedia", "SocialPostId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("SocialPost");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.SocialPollOption", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Sozsoft.Platform.Entities.SocialMedia", "SocialMedia")
|
||||||
|
.WithMany("PollOptions")
|
||||||
|
.HasForeignKey("SocialMediaId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("SocialMedia");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.SurveyAnswer", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Sozsoft.Platform.Entities.SurveyQuestion", "Question")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("QuestionId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Sozsoft.Platform.Entities.SurveyResponse", "Response")
|
||||||
|
.WithMany("Answers")
|
||||||
|
.HasForeignKey("ResponseId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Question");
|
||||||
|
|
||||||
|
b.Navigation("Response");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.SurveyQuestion", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Sozsoft.Platform.Entities.Survey", "Survey")
|
||||||
|
.WithMany("Questions")
|
||||||
|
.HasForeignKey("SurveyId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Survey");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.SurveyQuestionOption", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Sozsoft.Platform.Entities.SurveyQuestion", "Question")
|
||||||
|
.WithMany("Options")
|
||||||
|
.HasForeignKey("QuestionId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Question");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.SurveyResponse", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Sozsoft.Platform.Entities.Survey", "Survey")
|
||||||
|
.WithMany("SurveyResponses")
|
||||||
|
.HasForeignKey("SurveyId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Survey");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Sozsoft.Platform.Entities.Uom", b =>
|
modelBuilder.Entity("Sozsoft.Platform.Entities.Uom", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("Sozsoft.Platform.Entities.UomCategory", "UomCategory")
|
b.HasOne("Sozsoft.Platform.Entities.UomCategory", "UomCategory")
|
||||||
|
|
@ -6670,6 +7551,39 @@ namespace Sozsoft.Platform.Migrations
|
||||||
b.Navigation("Skills");
|
b.Navigation("Skills");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.SocialMedia", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("PollOptions");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.SocialPost", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Comments");
|
||||||
|
|
||||||
|
b.Navigation("Likes");
|
||||||
|
|
||||||
|
b.Navigation("Location");
|
||||||
|
|
||||||
|
b.Navigation("Media");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.Survey", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Questions");
|
||||||
|
|
||||||
|
b.Navigation("SurveyResponses");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.SurveyQuestion", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Options");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Sozsoft.Platform.Entities.SurveyResponse", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Answers");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Sozsoft.Platform.Entities.UomCategory", b =>
|
modelBuilder.Entity("Sozsoft.Platform.Entities.UomCategory", b =>
|
||||||
{
|
{
|
||||||
b.Navigation("Uoms");
|
b.Navigation("Uoms");
|
||||||
|
|
|
||||||
|
|
@ -1289,5 +1289,395 @@
|
||||||
"Name": "Muhasebe Şefi",
|
"Name": "Muhasebe Şefi",
|
||||||
"ParentName": "Muhasebe Müdürü"
|
"ParentName": "Muhasebe Müdürü"
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"Announcements": [
|
||||||
|
{
|
||||||
|
"title": "🎉 Yeni Ofis Açılışı",
|
||||||
|
"content": "Ankara ofisimiz 1 Kasım tarihinde hizmete başlıyor! Tüm çalışanlarımızı açılış törenimize davet ediyoruz.",
|
||||||
|
"excerpt": "Ankara ofisimiz 1 Kasım tarihinde hizmete başlıyor!",
|
||||||
|
"category": "general",
|
||||||
|
"userName": "system@sozsoft.com",
|
||||||
|
"publishDate": "12-10-2024",
|
||||||
|
"isPinned": true,
|
||||||
|
"viewCount": 156,
|
||||||
|
"imageUrl": "https://images.unsplash.com/photo-1497366216548-37526070297c?w=800&q=80"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "📅 Performans Değerlendirme Dönemi",
|
||||||
|
"content": "Yıl sonu performans değerlendirmelerimiz 20 Ekim - 5 Kasım tarihleri arasında gerçekleştirilecektir. Lütfen formları zamanında doldurunuz.",
|
||||||
|
"excerpt": "Yıl sonu performans değerlendirmeleri başlıyor.",
|
||||||
|
"category": "hr",
|
||||||
|
"userName": "system@sozsoft.com",
|
||||||
|
"publishDate": "08-10-2024",
|
||||||
|
"expiryDate": "05-11-2024",
|
||||||
|
"isPinned": true,
|
||||||
|
"viewCount": 89
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "💻 Sistem Bakımı Duyurusu",
|
||||||
|
"content": "Bu Cumartesi saat 02: 00 - 06: 00 arası sistemlerimizde bakım çalışması yapılacaktır. Bu süre içinde sistemlere erişim sağlanamayacaktır.",
|
||||||
|
"excerpt": "Cumartesi gecesi planlı bakım çalışması",
|
||||||
|
"category": "it",
|
||||||
|
"userName": "system@sozsoft.com",
|
||||||
|
"publishDate": "08-10-2024",
|
||||||
|
"isPinned": false,
|
||||||
|
"viewCount": 234
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "🎓 React İleri Seviye Eğitimi",
|
||||||
|
"content": "Yazılım Geliştirme ekibimiz için React İleri Seviye eğitimi 25-26 Ekim tarihlerinde düzenlenecektir. Katılım için IK birimine başvurunuz.",
|
||||||
|
"excerpt": "React İleri Seviye eğitimi kayıtları başladı",
|
||||||
|
"category": "event",
|
||||||
|
"userName": "system@sozsoft.com",
|
||||||
|
"publishDate": "09-10-2024",
|
||||||
|
"isPinned": false,
|
||||||
|
"viewCount": 67
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "⚠️ Güvenlik Politikası Güncellemesi",
|
||||||
|
"content": "Bilgi güvenliği politikamız güncellenmiştir. Tüm çalışanlarımızın yeni politikayı okuması ve onaylaması gerekmektedir.",
|
||||||
|
"excerpt": "Güvenlik politikası güncellendi - Onay gerekli",
|
||||||
|
"category": "urgent",
|
||||||
|
"userName": "system@sozsoft.com",
|
||||||
|
"publishDate": "04-10-2024",
|
||||||
|
"isPinned": true,
|
||||||
|
"viewCount": 312
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Surveys": [
|
||||||
|
{
|
||||||
|
"Title": "Çalışan Memnuniyet Anketi 2024",
|
||||||
|
"Description": "Yıllık çalışan memnuniyeti ve bağlılık araştırması",
|
||||||
|
"Deadline": "2024-10-31T00:00:00",
|
||||||
|
"Responses": 45,
|
||||||
|
"Status": "active",
|
||||||
|
"IsAnonymous": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Title": "Eğitim İhtiyaç Analizi",
|
||||||
|
"Description": "2025 yılı eğitim planlaması için ihtiyaç tespiti",
|
||||||
|
"Deadline": "2024-11-15T00:00:00",
|
||||||
|
"Responses": 28,
|
||||||
|
"Status": "active",
|
||||||
|
"IsAnonymous": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Title": "Kafeterya Memnuniyet Anketi",
|
||||||
|
"Description": "Yemek kalitesi ve servis değerlendirmesi",
|
||||||
|
"Deadline": "2024-09-30T00:00:00",
|
||||||
|
"Responses": 62,
|
||||||
|
"Status": "passive",
|
||||||
|
"IsAnonymous": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"SurveyQuestions": [
|
||||||
|
{
|
||||||
|
"SurveyTitle": "Çalışan Memnuniyet Anketi 2024",
|
||||||
|
"QuestionText": "Genel memnuniyet düzeyiniz nedir?",
|
||||||
|
"Type": "rating",
|
||||||
|
"Order": 1,
|
||||||
|
"IsRequired": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"SurveyTitle": "Çalışan Memnuniyet Anketi 2024",
|
||||||
|
"QuestionText": "Hangi departmanda çalışıyorsunuz?",
|
||||||
|
"Type": "multiple-choice",
|
||||||
|
"Order": 2,
|
||||||
|
"IsRequired": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"SurveyTitle": "Çalışan Memnuniyet Anketi 2024",
|
||||||
|
"QuestionText": "Görüş ve önerileriniz",
|
||||||
|
"Type": "textarea",
|
||||||
|
"Order": 3,
|
||||||
|
"IsRequired": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"SurveyTitle": "Çalışan Memnuniyet Anketi 2024",
|
||||||
|
"QuestionText": "Çalışma ortamından memnun musunuz?",
|
||||||
|
"Type": "yes-no",
|
||||||
|
"Order": 4,
|
||||||
|
"IsRequired": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"SurveyTitle": "Eğitim İhtiyaç Analizi",
|
||||||
|
"QuestionText": "Hangi teknoloji konularında eğitim almak istiyorsunuz?",
|
||||||
|
"Type": "multiple-choice",
|
||||||
|
"Order": 1,
|
||||||
|
"IsRequired": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"SurveyTitle": "Eğitim İhtiyaç Analizi",
|
||||||
|
"QuestionText": "Eğitim formatı tercihiniz nedir?",
|
||||||
|
"Type": "multiple-choice",
|
||||||
|
"Order": 2,
|
||||||
|
"IsRequired": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"SurveyTitle": "Eğitim İhtiyaç Analizi",
|
||||||
|
"QuestionText": "Eğitim için haftalık ne kadar zaman ayırabilirsiniz?",
|
||||||
|
"Type": "rating",
|
||||||
|
"Order": 3,
|
||||||
|
"IsRequired": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"SurveyTitle": "Kafeterya Memnuniyet Anketi",
|
||||||
|
"QuestionText": "Yemek kalitesini nasıl değerlendiriyorsunuz?",
|
||||||
|
"Type": "rating",
|
||||||
|
"Order": 1,
|
||||||
|
"IsRequired": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"SurveyTitle": "Kafeterya Memnuniyet Anketi",
|
||||||
|
"QuestionText": "Hangi yemekleri daha sık görmek istiyorsunuz?",
|
||||||
|
"Type": "textarea",
|
||||||
|
"Order": 2,
|
||||||
|
"IsRequired": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"SurveyTitle": "Kafeterya Memnuniyet Anketi",
|
||||||
|
"QuestionText": "Servis hızından memnun musunuz?",
|
||||||
|
"Type": "yes-no",
|
||||||
|
"Order": 3,
|
||||||
|
"IsRequired": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"SurveyQuestionOptions": [
|
||||||
|
{
|
||||||
|
"QuestionText": "Hangi departmanda çalışıyorsunuz?",
|
||||||
|
"Text": "Bilgi Teknolojileri",
|
||||||
|
"Order": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"QuestionText": "Hangi departmanda çalışıyorsunuz?",
|
||||||
|
"Text": "İnsan Kaynakları",
|
||||||
|
"Order": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"QuestionText": "Hangi departmanda çalışıyorsunuz?",
|
||||||
|
"Text": "Finans",
|
||||||
|
"Order": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"QuestionText": "Hangi departmanda çalışıyorsunuz?",
|
||||||
|
"Text": "Satış",
|
||||||
|
"Order": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"QuestionText": "Hangi departmanda çalışıyorsunuz?",
|
||||||
|
"Text": "Pazarlama",
|
||||||
|
"Order": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"QuestionText": "Hangi teknoloji konularında eğitim almak istiyorsunuz?",
|
||||||
|
"Text": "React / Frontend",
|
||||||
|
"Order": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"QuestionText": "Hangi teknoloji konularında eğitim almak istiyorsunuz?",
|
||||||
|
"Text": "Node.js / Backend",
|
||||||
|
"Order": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"QuestionText": "Hangi teknoloji konularında eğitim almak istiyorsunuz?",
|
||||||
|
"Text": "Database / SQL",
|
||||||
|
"Order": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"QuestionText": "Hangi teknoloji konularında eğitim almak istiyorsunuz?",
|
||||||
|
"Text": "DevOps / Cloud",
|
||||||
|
"Order": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"QuestionText": "Hangi teknoloji konularında eğitim almak istiyorsunuz?",
|
||||||
|
"Text": "Mobile Development",
|
||||||
|
"Order": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"QuestionText": "Eğitim formatı tercihiniz nedir?",
|
||||||
|
"Text": "Online Eğitim",
|
||||||
|
"Order": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"QuestionText": "Eğitim formatı tercihiniz nedir?",
|
||||||
|
"Text": "Yüz Yüze Eğitim",
|
||||||
|
"Order": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"QuestionText": "Eğitim formatı tercihiniz nedir?",
|
||||||
|
"Text": "Hibrit (Karma)",
|
||||||
|
"Order": 3
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"SocialPosts": [
|
||||||
|
{
|
||||||
|
"content": "Yeni proje üzerinde çalışıyoruz! React ve TypeScript ile harika bir deneyim oluşturuyoruz. Ekip çalışması harika gidiyor! 🚀",
|
||||||
|
"userName": "system@sozsoft.com",
|
||||||
|
"likeCount": 24,
|
||||||
|
"isLiked": true,
|
||||||
|
"isOwnPost": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": "Bu hafta sprint planlamasını yaptık. Ekibimizle birlikte yeni özellikleri değerlendirdik. Heyecan verici bir hafta olacak!",
|
||||||
|
"userName": "system@sozsoft.com",
|
||||||
|
"likeCount": 18,
|
||||||
|
"isLiked": false,
|
||||||
|
"isOwnPost": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": "Yeni tasarım sistemimizin ilk prototipini hazırladık! Kullanıcı deneyimini iyileştirmek için çok çalıştık. Geri bildirimlerinizi bekliyorum! 🎨",
|
||||||
|
"userName": "system@sozsoft.com",
|
||||||
|
"likeCount": 42,
|
||||||
|
"isLiked": true,
|
||||||
|
"isOwnPost": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": "CI/CD pipeline güncellememiz tamamlandı! Deployment süremiz %40 azaldı. Otomasyonun gücü 💪",
|
||||||
|
"userName": "system@sozsoft.com",
|
||||||
|
"likeCount": 31,
|
||||||
|
"isLiked": false,
|
||||||
|
"isOwnPost": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": "Ekip üyelerimize yeni eğitim programımızı duyurmak istiyorum! 🎓 React, TypeScript ve Modern Web Geliştirme konularında kapsamlı bir program hazırladık.",
|
||||||
|
"userName": "system@sozsoft.com",
|
||||||
|
"likeCount": 56,
|
||||||
|
"isLiked": true,
|
||||||
|
"isOwnPost": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": "Bugün müşteri ile harika bir toplantı yaptık! Yeni projenin detaylarını konuştuk. 🎯",
|
||||||
|
"userName": "system@sozsoft.com",
|
||||||
|
"likeCount": 18,
|
||||||
|
"isLiked": false,
|
||||||
|
"isOwnPost": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"SocialLocations": [
|
||||||
|
{
|
||||||
|
"postContent": "Yeni proje üzerinde çalışıyoruz! React ve TypeScript ile harika bir deneyim oluşturuyoruz. Ekip çalışması harika gidiyor! 🚀",
|
||||||
|
"name": "Taksim Meydanı",
|
||||||
|
"address": "Taksim, Gümüşsuyu Mahallesi, 34437 Beyoğlu/İstanbul",
|
||||||
|
"lat": 41.0369,
|
||||||
|
"lng": 28.985,
|
||||||
|
"placeId": "ChIJBQRGmL25yhQRXwqRTHAwAAQ"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"postContent": "Bugün müşteri ile harika bir toplantı yaptık! Yeni projenin detaylarını konuştuk. 🎯",
|
||||||
|
"name": "Sultanahmet Meydanı",
|
||||||
|
"address": "Sultanahmet Mahallesi, 34122 Fatih/İstanbul",
|
||||||
|
"lat": 41.0058,
|
||||||
|
"lng": 28.9768,
|
||||||
|
"placeId": "ChIJ7fVVZiy5yhQRzsXXXXXXXXk"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"SocialMedias": [
|
||||||
|
{
|
||||||
|
"postContent": "Yeni proje üzerinde çalışıyoruz! React ve TypeScript ile harika bir deneyim oluşturuyoruz. Ekip çalışması harika gidiyor! 🚀",
|
||||||
|
"type": "image",
|
||||||
|
"urls": [
|
||||||
|
"https://images.unsplash.com/photo-1633356122544-f134324a6cee?w=800&q=80"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"postContent": "Bu hafta sprint planlamasını yaptık. Ekibimizle birlikte yeni özellikleri değerlendirdik. Heyecan verici bir hafta olacak!",
|
||||||
|
"type": "poll",
|
||||||
|
"pollQuestion": "Hangi özelliği öncelikli olarak geliştirmeliyiz?",
|
||||||
|
"pollTotalVotes": 40,
|
||||||
|
"pollEndsAt": "2024-10-20T23:59:59",
|
||||||
|
"pollUserVoteId": "p3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"postContent": "Yeni tasarım sistemimizin ilk prototipini hazırladık! Kullanıcı deneyimini iyileştirmek için çok çalıştık. Geri bildirimlerinizi bekliyorum! 🎨",
|
||||||
|
"type": "image",
|
||||||
|
"urls": [
|
||||||
|
"https://images.unsplash.com/photo-1561070791-2526d30994b5?w=800&q=80",
|
||||||
|
"https://images.unsplash.com/photo-1586717799252-bd134ad00e26?w=800&q=80",
|
||||||
|
"https://images.unsplash.com/photo-1609921212029-bb5a28e60960?w=800&q=80"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"postContent": "CI/CD pipeline güncellememiz tamamlandı! Deployment süremiz %40 azaldı. Otomasyonun gücü 💪",
|
||||||
|
"type": "video",
|
||||||
|
"urls": ["https://www.w3schools.com/html/mov_bbb.mp4"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"SocialPollOptions": [
|
||||||
|
{
|
||||||
|
"postContent": "Bu hafta sprint planlamasını yaptık. Ekibimizle birlikte yeni özellikleri değerlendirdik. Heyecan verici bir hafta olacak!",
|
||||||
|
"pollQuestion": "Hangi özelliği öncelikli olarak geliştirmeliyiz?",
|
||||||
|
"Text": "Kullanıcı profilleri",
|
||||||
|
"Votes": 12
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"postContent": "Bu hafta sprint planlamasını yaptık. Ekibimizle birlikte yeni özellikleri değerlendirdik. Heyecan verici bir hafta olacak!",
|
||||||
|
"pollQuestion": "Hangi özelliği öncelikli olarak geliştirmeliyiz?",
|
||||||
|
"Text": "Bildirim sistemi",
|
||||||
|
"Votes": 8
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"postContent": "Bu hafta sprint planlamasını yaptık. Ekibimizle birlikte yeni özellikleri değerlendirdik. Heyecan verici bir hafta olacak!",
|
||||||
|
"pollQuestion": "Hangi özelliği öncelikli olarak geliştirmeliyiz?",
|
||||||
|
"Text": "Mesajlaşma",
|
||||||
|
"Votes": 15
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"postContent": "Bu hafta sprint planlamasını yaptık. Ekibimizle birlikte yeni özellikleri değerlendirdik. Heyecan verici bir hafta olacak!",
|
||||||
|
"pollQuestion": "Hangi özelliği öncelikli olarak geliştirmeliyiz?",
|
||||||
|
"Text": "Raporlama",
|
||||||
|
"Votes": 5
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"SocialComments": [
|
||||||
|
{
|
||||||
|
"postContent": "Yeni proje üzerinde çalışıyoruz! React ve TypeScript ile harika bir deneyim oluşturuyoruz. Ekip çalışması harika gidiyor! 🚀",
|
||||||
|
"userName": "system@sozsoft.com",
|
||||||
|
"content": "Harika görünüyor! Başarılar 👏"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"postContent": "Yeni proje üzerinde çalışıyoruz! React ve TypeScript ile harika bir deneyim oluşturuyoruz. Ekip çalışması harika gidiyor! 🚀",
|
||||||
|
"userName": "system@sozsoft.com",
|
||||||
|
"content": "TypeScript gerçekten fark yaratıyor!"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"postContent": "Bu hafta sprint planlamasını yaptık. Ekibimizle birlikte yeni özellikleri değerlendirdik. Heyecan verici bir hafta olacak!",
|
||||||
|
"userName": "system@sozsoft.com",
|
||||||
|
"content": "Mesajlaşma özelliğine kesinlikle ihtiyacımız var!"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"postContent": "Yeni tasarım sistemimizin ilk prototipini hazırladık! Kullanıcı deneyimini iyileştirmek için çok çalıştık. Geri bildirimlerinizi bekliyorum! 🎨",
|
||||||
|
"userName": "system@sozsoft.com",
|
||||||
|
"content": "Tasarımlar çok şık! Renk paleti özellikle güzel 😍"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"postContent": "Yeni tasarım sistemimizin ilk prototipini hazırladık! Kullanıcı deneyimini iyileştirmek için çok çalıştık. Geri bildirimlerinizi bekliyorum! 🎨",
|
||||||
|
"userName": "system@sozsoft.com",
|
||||||
|
"content": "Dark mode opsiyonu da olacak mı?"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"postContent": "CI/CD pipeline güncellememiz tamamlandı! Deployment süremiz %40 azaldı. Otomasyonun gücü 💪",
|
||||||
|
"userName": "system@sozsoft.com",
|
||||||
|
"content": "Harika iş! Detayları paylaşabilir misin?"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"postContent": "Ekip üyelerimize yeni eğitim programımızı duyurmak istiyorum! 🎓 React, TypeScript ve Modern Web Geliştirme konularında kapsamlı bir program hazırladık.",
|
||||||
|
"userName": "system@sozsoft.com",
|
||||||
|
"content": "Ne zaman başlıyor?"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"postContent": "Ekip üyelerimize yeni eğitim programımızı duyurmak istiyorum! 🎓 React, TypeScript ve Modern Web Geliştirme konularında kapsamlı bir program hazırladık.",
|
||||||
|
"userName": "system@sozsoft.com",
|
||||||
|
"content": "Gelecek hafta başlıyoruz! Kayıt linki mail ile paylaşılacak."
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"SocialLikes": [
|
||||||
|
{
|
||||||
|
"postContent": "Yeni proje üzerinde çalışıyoruz! React ve TypeScript ile harika bir deneyim oluşturuyoruz. Ekip çalışması harika gidiyor! 🚀",
|
||||||
|
"userName": "system@sozsoft.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"postContent": "Yeni tasarım sistemimizin ilk prototipini hazırladık! Kullanıcı deneyimini iyileştirmek için çok çalıştık. Geri bildirimlerinizi bekliyorum! 🎨",
|
||||||
|
"userName": "system@sozsoft.com"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ using Volo.Abp.Timing;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Volo.Abp.MultiTenancy;
|
using Volo.Abp.MultiTenancy;
|
||||||
using Sozsoft.Platform.Extensions;
|
using Sozsoft.Platform.Extensions;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Sozsoft.Platform.Data.Seeds;
|
namespace Sozsoft.Platform.Data.Seeds;
|
||||||
|
|
||||||
|
|
@ -52,6 +53,113 @@ public class TenantSeederDto
|
||||||
|
|
||||||
//Forum
|
//Forum
|
||||||
public List<ForumCategorySeedDto> ForumCategories { get; set; }
|
public List<ForumCategorySeedDto> ForumCategories { get; set; }
|
||||||
|
|
||||||
|
//Intranet
|
||||||
|
public List<AnnouncementSeedDto> Announcements { get; set; }
|
||||||
|
public List<SurveySeedDto> Surveys { get; set; }
|
||||||
|
public List<SurveyQuestionSeedDto> SurveyQuestions { get; set; }
|
||||||
|
public List<SurveyQuestionOptionSeedDto> SurveyQuestionOptions { get; set; }
|
||||||
|
public List<SocialPostSeedDto> SocialPosts { get; set; }
|
||||||
|
public List<SocialLocationSeedDto> SocialLocations { get; set; }
|
||||||
|
public List<SocialMediaSeedDto> SocialMedias { get; set; }
|
||||||
|
public List<SocialPollOptionSeedDto> SocialPollOptions { get; set; }
|
||||||
|
public List<SocialCommentSeedDto> SocialComments { get; set; }
|
||||||
|
public List<SocialLikeSeedDto> SocialLikes { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SocialPostSeedDto
|
||||||
|
{
|
||||||
|
public string Content { get; set; }
|
||||||
|
public string UserName { get; set; }
|
||||||
|
public int LikeCount { get; set; }
|
||||||
|
public bool IsLiked { get; set; }
|
||||||
|
public bool IsOwnPost { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SocialLocationSeedDto
|
||||||
|
{
|
||||||
|
public string PostContent { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string Address { get; set; }
|
||||||
|
public double? Lat { get; set; }
|
||||||
|
public double? Lng { get; set; }
|
||||||
|
public string PlaceId { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SocialMediaSeedDto
|
||||||
|
{
|
||||||
|
public string PostContent { get; set; }
|
||||||
|
public string Type { get; set; }
|
||||||
|
public string[] Urls { get; set; }
|
||||||
|
|
||||||
|
public string PollQuestion { get; set; }
|
||||||
|
public int? PollTotalVotes { get; set; }
|
||||||
|
public DateTime? PollEndsAt { get; set; }
|
||||||
|
public string PollUserVoteId { get; set; }
|
||||||
|
|
||||||
|
public List<SocialPollOptionSeedDto> PollOptions { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SocialPollOptionSeedDto
|
||||||
|
{
|
||||||
|
public string PostContent { get; set; }
|
||||||
|
public string PollQuestion { get; set; }
|
||||||
|
public string Text { get; set; }
|
||||||
|
public int Votes { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SocialCommentSeedDto
|
||||||
|
{
|
||||||
|
public string PostContent { get; set; }
|
||||||
|
public string UserName { get; set; }
|
||||||
|
public string Content { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SocialLikeSeedDto
|
||||||
|
{
|
||||||
|
public string PostContent { get; set; }
|
||||||
|
public string UserName { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SurveySeedDto
|
||||||
|
{
|
||||||
|
public string Title { get; set; }
|
||||||
|
public string Description { get; set; }
|
||||||
|
public DateTime Deadline { get; set; }
|
||||||
|
public int Responses { get; set; }
|
||||||
|
public string Status { get; set; }
|
||||||
|
public bool IsAnonymous { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SurveyQuestionSeedDto
|
||||||
|
{
|
||||||
|
public string QuestionText { get; set; }
|
||||||
|
public string SurveyTitle { get; set; }
|
||||||
|
public string Type { get; set; }
|
||||||
|
public int Order { get; set; }
|
||||||
|
public bool IsRequired { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SurveyQuestionOptionSeedDto
|
||||||
|
{
|
||||||
|
public string QuestionText { get; set; }
|
||||||
|
public string Text { get; set; }
|
||||||
|
public int Order { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AnnouncementSeedDto
|
||||||
|
{
|
||||||
|
public string Title { get; set; }
|
||||||
|
public string Excerpt { get; set; }
|
||||||
|
public string Content { get; set; }
|
||||||
|
public string ImageUrl { get; set; }
|
||||||
|
public string Category { get; set; }
|
||||||
|
public string UserName { get; set; }
|
||||||
|
public DateTime PublishDate { get; set; }
|
||||||
|
public DateTime? ExpiryDate { get; set; }
|
||||||
|
public bool IsPinned { get; set; }
|
||||||
|
public int ViewCount { get; set; }
|
||||||
|
public string DepartmentNames { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class JobPositionSeedDto
|
public class JobPositionSeedDto
|
||||||
|
|
@ -291,6 +399,16 @@ public class TenantDataSeeder : IDataSeedContributor, ITransientDependency
|
||||||
private readonly IRepository<Product, Guid> _productRepository;
|
private readonly IRepository<Product, Guid> _productRepository;
|
||||||
private readonly IRepository<Department, Guid> _departmentRepository;
|
private readonly IRepository<Department, Guid> _departmentRepository;
|
||||||
private readonly IRepository<JobPosition, Guid> _jobPositionRepository;
|
private readonly IRepository<JobPosition, Guid> _jobPositionRepository;
|
||||||
|
private readonly IRepository<Announcement, Guid> _announcementRepository;
|
||||||
|
private readonly IRepository<Survey, Guid> _surveyRepository;
|
||||||
|
private readonly IRepository<SurveyQuestion, Guid> _surveyQuestionRepository;
|
||||||
|
private readonly IRepository<SurveyQuestionOption, Guid> _surveyQuestionOptionRepository;
|
||||||
|
private readonly IRepository<SocialPost, Guid> _socialPostRepository;
|
||||||
|
private readonly IRepository<SocialLocation, Guid> _socialLocationRepository;
|
||||||
|
private readonly IRepository<SocialMedia, Guid> _socialMediaRepository;
|
||||||
|
private readonly IRepository<SocialPollOption, Guid> _socialPollOptionRepository;
|
||||||
|
private readonly IRepository<SocialComment, Guid> _socialCommentRepository;
|
||||||
|
private readonly IRepository<SocialLike, Guid> _socialLikeRepository;
|
||||||
private readonly ICurrentTenant _currentTenant;
|
private readonly ICurrentTenant _currentTenant;
|
||||||
|
|
||||||
public TenantDataSeeder(
|
public TenantDataSeeder(
|
||||||
|
|
@ -322,6 +440,18 @@ public class TenantDataSeeder : IDataSeedContributor, ITransientDependency
|
||||||
IRepository<OrganizationUnit, Guid> organizationUnitRepository,
|
IRepository<OrganizationUnit, Guid> organizationUnitRepository,
|
||||||
IRepository<Department, Guid> departmentRepository,
|
IRepository<Department, Guid> departmentRepository,
|
||||||
IRepository<JobPosition, Guid> jobPositionRepository,
|
IRepository<JobPosition, Guid> jobPositionRepository,
|
||||||
|
|
||||||
|
IRepository<Announcement, Guid> announcementRepository,
|
||||||
|
IRepository<Survey, Guid> surveyRepository,
|
||||||
|
IRepository<SurveyQuestion, Guid> surveyQuestionRepository,
|
||||||
|
IRepository<SurveyQuestionOption, Guid> surveyQuestionOptionRepository,
|
||||||
|
IRepository<SocialPost, Guid> socialPostRepository,
|
||||||
|
IRepository<SocialLocation, Guid> socialLocationRepository,
|
||||||
|
IRepository<SocialMedia, Guid> socialMediaRepository,
|
||||||
|
IRepository<SocialPollOption, Guid> socialPollOptionRepository,
|
||||||
|
IRepository<SocialComment, Guid> socialCommentRepository,
|
||||||
|
IRepository<SocialLike, Guid> socialLikeRepository,
|
||||||
|
|
||||||
OrganizationUnitManager organizationUnitManager,
|
OrganizationUnitManager organizationUnitManager,
|
||||||
ICurrentTenant currentTenant
|
ICurrentTenant currentTenant
|
||||||
)
|
)
|
||||||
|
|
@ -354,6 +484,16 @@ public class TenantDataSeeder : IDataSeedContributor, ITransientDependency
|
||||||
_organizationUnitRepository = organizationUnitRepository;
|
_organizationUnitRepository = organizationUnitRepository;
|
||||||
_departmentRepository = departmentRepository;
|
_departmentRepository = departmentRepository;
|
||||||
_jobPositionRepository = jobPositionRepository;
|
_jobPositionRepository = jobPositionRepository;
|
||||||
|
_announcementRepository = announcementRepository;
|
||||||
|
_surveyRepository = surveyRepository;
|
||||||
|
_surveyQuestionRepository = surveyQuestionRepository;
|
||||||
|
_surveyQuestionOptionRepository = surveyQuestionOptionRepository;
|
||||||
|
_socialPostRepository = socialPostRepository;
|
||||||
|
_socialLocationRepository = socialLocationRepository;
|
||||||
|
_socialMediaRepository = socialMediaRepository;
|
||||||
|
_socialPollOptionRepository = socialPollOptionRepository;
|
||||||
|
_socialCommentRepository = socialCommentRepository;
|
||||||
|
_socialLikeRepository = socialLikeRepository;
|
||||||
_organizationUnitManager = organizationUnitManager;
|
_organizationUnitManager = organizationUnitManager;
|
||||||
_currentTenant = currentTenant;
|
_currentTenant = currentTenant;
|
||||||
}
|
}
|
||||||
|
|
@ -770,6 +910,204 @@ public class TenantDataSeeder : IDataSeedContributor, ITransientDependency
|
||||||
}, autoSave: true);
|
}, autoSave: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (var item in items.Announcements)
|
||||||
|
{
|
||||||
|
var exists = await _announcementRepository.AnyAsync(x => x.Title == item.Title);
|
||||||
|
if (exists)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var user = await _repositoryUser.FindByNormalizedUserNameAsync(item.UserName);
|
||||||
|
await _announcementRepository.InsertAsync(new Announcement
|
||||||
|
{
|
||||||
|
Title = item.Title,
|
||||||
|
Excerpt = item.Excerpt,
|
||||||
|
Content = item.Content,
|
||||||
|
ImageUrl = item.ImageUrl,
|
||||||
|
Category = item.Category,
|
||||||
|
UserId = user != null ? user.Id : null,
|
||||||
|
PublishDate = item.PublishDate,
|
||||||
|
ExpiryDate = item.ExpiryDate,
|
||||||
|
IsPinned = item.IsPinned,
|
||||||
|
ViewCount = item.ViewCount
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var item in items.Surveys)
|
||||||
|
{
|
||||||
|
var exists = await _surveyRepository.AnyAsync(x => x.Title == item.Title);
|
||||||
|
if (exists)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
await _surveyRepository.InsertAsync(new Survey
|
||||||
|
{
|
||||||
|
Title = item.Title,
|
||||||
|
Description = item.Description,
|
||||||
|
Deadline = item.Deadline,
|
||||||
|
Responses = item.Responses,
|
||||||
|
Status = item.Status,
|
||||||
|
IsAnonymous = item.IsAnonymous
|
||||||
|
}, autoSave: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var item in items.SurveyQuestions)
|
||||||
|
{
|
||||||
|
var exists = await _surveyQuestionRepository.AnyAsync(x => x.QuestionText == item.QuestionText);
|
||||||
|
if (exists)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var survey = await _surveyRepository.FirstOrDefaultAsync(x => x.Title == item.SurveyTitle);
|
||||||
|
await _surveyQuestionRepository.InsertAsync(new SurveyQuestion
|
||||||
|
{
|
||||||
|
SurveyId = survey != null ? survey.Id : Guid.Empty,
|
||||||
|
QuestionText = item.QuestionText,
|
||||||
|
Type = item.Type,
|
||||||
|
Order = item.Order,
|
||||||
|
IsRequired = item.IsRequired
|
||||||
|
}, autoSave: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var item in items.SurveyQuestionOptions)
|
||||||
|
{
|
||||||
|
var surveyQuestion = await _surveyQuestionRepository.FirstOrDefaultAsync(x => x.QuestionText == item.QuestionText);
|
||||||
|
if (surveyQuestion == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var exists = await _surveyQuestionOptionRepository.AnyAsync(x => x.QuestionId == surveyQuestion.Id && x.Text == item.Text);
|
||||||
|
if (exists)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
await _surveyQuestionOptionRepository.InsertAsync(new SurveyQuestionOption
|
||||||
|
{
|
||||||
|
QuestionId = surveyQuestion.Id,
|
||||||
|
Text = item.Text,
|
||||||
|
Order = item.Order
|
||||||
|
}, autoSave: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var item in items.SocialPosts)
|
||||||
|
{
|
||||||
|
var exists = await _socialPostRepository.AnyAsync(x => x.Content == item.Content);
|
||||||
|
if (exists)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var user = await _repositoryUser.FindByNormalizedUserNameAsync(item.UserName);
|
||||||
|
|
||||||
|
await _socialPostRepository.InsertAsync(new SocialPost
|
||||||
|
{
|
||||||
|
UserId = user != null ? user.Id : null,
|
||||||
|
Content = item.Content,
|
||||||
|
LikeCount = item.LikeCount,
|
||||||
|
IsLiked = item.IsLiked,
|
||||||
|
IsOwnPost = item.IsOwnPost
|
||||||
|
}, autoSave: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var item in items.SocialLocations)
|
||||||
|
{
|
||||||
|
var post = await _socialPostRepository.FirstOrDefaultAsync(x => x.Content == item.PostContent);
|
||||||
|
|
||||||
|
if (post == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var exists = await _socialLocationRepository.AnyAsync(x => x.SocialPostId == post.Id && x.Name == item.Name);
|
||||||
|
if (exists)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
await _socialLocationRepository.InsertAsync(new SocialLocation
|
||||||
|
{
|
||||||
|
SocialPostId = post != null ? post.Id : Guid.Empty,
|
||||||
|
Name = item.Name,
|
||||||
|
Address = item.Address,
|
||||||
|
Lat = item.Lat,
|
||||||
|
Lng = item.Lng,
|
||||||
|
PlaceId = item.PlaceId
|
||||||
|
}, autoSave: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var item in items.SocialMedias)
|
||||||
|
{
|
||||||
|
var post = await _socialPostRepository.FirstOrDefaultAsync(x => x.Content == item.PostContent);
|
||||||
|
|
||||||
|
if (post == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var exists = await _socialMediaRepository.AnyAsync(x => x.SocialPostId == post.Id);
|
||||||
|
if (exists)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
await _socialMediaRepository.InsertAsync(new SocialMedia
|
||||||
|
{
|
||||||
|
SocialPostId = post != null ? post.Id : Guid.Empty,
|
||||||
|
Type = item.Type,
|
||||||
|
Urls = item.Urls,
|
||||||
|
PollQuestion = item.PollQuestion,
|
||||||
|
PollTotalVotes = item.PollTotalVotes,
|
||||||
|
PollEndsAt = item.PollEndsAt,
|
||||||
|
PollUserVoteId = item.PollUserVoteId
|
||||||
|
}, autoSave: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var item in items.SocialPollOptions)
|
||||||
|
{
|
||||||
|
var post = await _socialPostRepository.FirstOrDefaultAsync(x => x.Content == item.PostContent);
|
||||||
|
if (post == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var media = await _socialMediaRepository.FirstOrDefaultAsync(x => x.SocialPostId == post.Id && x.PollQuestion == item.PollQuestion);
|
||||||
|
if (media == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var exists = await _socialPollOptionRepository.AnyAsync(x => x.SocialMediaId == media.Id && x.Text == item.Text);
|
||||||
|
if (exists)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
await _socialPollOptionRepository.InsertAsync(new SocialPollOption
|
||||||
|
{
|
||||||
|
SocialMediaId = media != null ? media.Id : Guid.Empty,
|
||||||
|
Text = item.Text,
|
||||||
|
Votes = item.Votes
|
||||||
|
}, autoSave: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var item in items.SocialComments)
|
||||||
|
{
|
||||||
|
var post = await _socialPostRepository.FirstOrDefaultAsync(x => x.Content == item.PostContent);
|
||||||
|
|
||||||
|
if (post == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var exists = await _socialCommentRepository.AnyAsync(x => x.SocialPostId == post.Id && x.Content == item.Content);
|
||||||
|
if (exists)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var user = await _repositoryUser.FindByNormalizedUserNameAsync(item.UserName);
|
||||||
|
await _socialCommentRepository.InsertAsync(new SocialComment
|
||||||
|
{
|
||||||
|
UserId = user != null ? user.Id : null,
|
||||||
|
SocialPostId = post != null ? post.Id : Guid.Empty,
|
||||||
|
Content = item.Content
|
||||||
|
}, autoSave: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var item in items.SocialLikes)
|
||||||
|
{
|
||||||
|
var post = await _socialPostRepository.FirstOrDefaultAsync(x => x.Content == item.PostContent);
|
||||||
|
|
||||||
|
if (post == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var exists = await _socialLikeRepository.AnyAsync(x => x.SocialPostId == post.Id);
|
||||||
|
if (exists)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var user = await _repositoryUser.FindByNormalizedUserNameAsync(item.UserName);
|
||||||
|
await _socialLikeRepository.InsertAsync(new SocialLike
|
||||||
|
{
|
||||||
|
SocialPostId = post != null ? post.Id : Guid.Empty,
|
||||||
|
UserId = user != null ? user.Id : null
|
||||||
|
}, autoSave: true);
|
||||||
|
}
|
||||||
|
|
||||||
//admin kullanının departmen ve pozisyonunu default olarak belirliyoruz
|
//admin kullanının departmen ve pozisyonunu default olarak belirliyoruz
|
||||||
var adminUser = await _repositoryUser.FindByNormalizedEmailAsync(PlatformConsts.AbpIdentity.User.AdminEmailDefaultValue);
|
var adminUser = await _repositoryUser.FindByNormalizedEmailAsync(PlatformConsts.AbpIdentity.User.AdminEmailDefaultValue);
|
||||||
if (adminUser != null)
|
if (adminUser != null)
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ const ComponentSelector: React.FC<ComponentSelectorProps> = ({
|
||||||
</label>
|
</label>
|
||||||
<Button
|
<Button
|
||||||
variant='solid'
|
variant='solid'
|
||||||
size="xs"
|
size="sm"
|
||||||
onClick={onRefresh}
|
onClick={onRefresh}
|
||||||
className="px-3 py-1 bg-blue-500 text-white text-xs rounded hover:bg-blue-600 transition-colors"
|
className="px-3 py-1 bg-blue-500 text-white text-xs rounded hover:bg-blue-600 transition-colors"
|
||||||
title="Refresh component list"
|
title="Refresh component list"
|
||||||
|
|
|
||||||
|
|
@ -528,7 +528,7 @@ const PropertyPanel: React.FC<PropertyPanelProps> = ({
|
||||||
{/* Sil Butonu */}
|
{/* Sil Butonu */}
|
||||||
<Button
|
<Button
|
||||||
variant="solid"
|
variant="solid"
|
||||||
size="xs"
|
size="sm"
|
||||||
className="mr-2 px-3 py-1 rounded bg-red-500 text-white hover:bg-red-600 transition-colors text-sm"
|
className="mr-2 px-3 py-1 rounded bg-red-500 text-white hover:bg-red-600 transition-colors text-sm"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (selectedComponent) {
|
if (selectedComponent) {
|
||||||
|
|
@ -551,7 +551,7 @@ const PropertyPanel: React.FC<PropertyPanelProps> = ({
|
||||||
<div className="p-4 border-t">
|
<div className="p-4 border-t">
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<Button
|
<Button
|
||||||
size="xs"
|
size="sm"
|
||||||
variant="solid"
|
variant="solid"
|
||||||
onClick={
|
onClick={
|
||||||
activeTab === "props"
|
activeTab === "props"
|
||||||
|
|
@ -568,7 +568,7 @@ const PropertyPanel: React.FC<PropertyPanelProps> = ({
|
||||||
Uygula
|
Uygula
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
size="xs"
|
size="sm"
|
||||||
variant="default"
|
variant="default"
|
||||||
onClick={
|
onClick={
|
||||||
activeTab === "props"
|
activeTab === "props"
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ const CopyButton = () => {
|
||||||
<Button
|
<Button
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
size="xs"
|
size="sm"
|
||||||
onClick={handleCopy}
|
onClick={handleCopy}
|
||||||
title={translate('::SidePanel.SaveConfig')}
|
title={translate('::SidePanel.SaveConfig')}
|
||||||
icon={<FaSave />}
|
icon={<FaSave />}
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ const Button = forwardRef<HTMLButtonElement, ButtonProps>((props, ref) => {
|
||||||
`h-${CONTROL_SIZES.lg}`,
|
`h-${CONTROL_SIZES.lg}`,
|
||||||
icon && !children
|
icon && !children
|
||||||
? `w-${CONTROL_SIZES.lg} ${sizeIconClass} text-2xl`
|
? `w-${CONTROL_SIZES.lg} ${sizeIconClass} text-2xl`
|
||||||
: 'px-8 py-2 text-base'
|
: 'px-8 text-base'
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
case SIZES.SM:
|
case SIZES.SM:
|
||||||
|
|
@ -78,7 +78,7 @@ const Button = forwardRef<HTMLButtonElement, ButtonProps>((props, ref) => {
|
||||||
`h-${CONTROL_SIZES.sm}`,
|
`h-${CONTROL_SIZES.sm}`,
|
||||||
icon && !children
|
icon && !children
|
||||||
? `w-${CONTROL_SIZES.sm} ${sizeIconClass} text-lg`
|
? `w-${CONTROL_SIZES.sm} ${sizeIconClass} text-lg`
|
||||||
: 'px-3 py-2 text-sm'
|
: 'px-3 text-sm'
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
case SIZES.XS:
|
case SIZES.XS:
|
||||||
|
|
@ -86,7 +86,7 @@ const Button = forwardRef<HTMLButtonElement, ButtonProps>((props, ref) => {
|
||||||
`h-${CONTROL_SIZES.xs}`,
|
`h-${CONTROL_SIZES.xs}`,
|
||||||
icon && !children
|
icon && !children
|
||||||
? `w-${CONTROL_SIZES.xs} ${sizeIconClass} text-base`
|
? `w-${CONTROL_SIZES.xs} ${sizeIconClass} text-base`
|
||||||
: 'px-2 py-1 text-xs'
|
: 'px-2 text-xs'
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
|
|
@ -94,7 +94,7 @@ const Button = forwardRef<HTMLButtonElement, ButtonProps>((props, ref) => {
|
||||||
`h-${CONTROL_SIZES.md}`,
|
`h-${CONTROL_SIZES.md}`,
|
||||||
icon && !children
|
icon && !children
|
||||||
? `w-${CONTROL_SIZES.md} ${sizeIconClass} text-xl`
|
? `w-${CONTROL_SIZES.md} ${sizeIconClass} text-xl`
|
||||||
: 'px-8 py-2'
|
: 'px-8'
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
import { BankAccount, BankAccountTypeEnum } from "@/proxy/intranet/models";
|
|
||||||
|
|
||||||
export const mockBanks: BankAccount[] = [
|
|
||||||
{
|
|
||||||
id: "1",
|
|
||||||
accountCode: "BANKA001",
|
|
||||||
bankName: "İş Bankası",
|
|
||||||
branchName: "Levent Şubesi",
|
|
||||||
accountNumber: "1234567890",
|
|
||||||
iban: "TR120006400000112345678901",
|
|
||||||
accountType: BankAccountTypeEnum.Current,
|
|
||||||
currency: "TRY",
|
|
||||||
balance: 125000,
|
|
||||||
overdraftLimit: 50000,
|
|
||||||
dailyTransferLimit: 100000,
|
|
||||||
isActive: true,
|
|
||||||
contactPerson: "Mehmet Ak",
|
|
||||||
phoneNumber: "+90 212 555 1111",
|
|
||||||
creationTime: new Date("2024-01-01"),
|
|
||||||
lastModificationTime: new Date("2024-01-20"),
|
|
||||||
swiftCode: "ISBKTRIS",
|
|
||||||
isDefault: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "2",
|
|
||||||
accountCode: "BANKA002",
|
|
||||||
bankName: "Garanti BBVA",
|
|
||||||
branchName: "Şişli Şubesi",
|
|
||||||
accountNumber: "9876543210",
|
|
||||||
iban: "TR980006200012600006298453",
|
|
||||||
accountType: BankAccountTypeEnum.Deposit,
|
|
||||||
currency: "USD",
|
|
||||||
balance: 15000,
|
|
||||||
overdraftLimit: 0,
|
|
||||||
dailyTransferLimit: 50000,
|
|
||||||
isActive: true,
|
|
||||||
contactPerson: "Ayşe Yıldız",
|
|
||||||
phoneNumber: "+90 212 555 2222",
|
|
||||||
creationTime: new Date("2024-01-01"),
|
|
||||||
lastModificationTime: new Date("2024-01-18"),
|
|
||||||
swiftCode: "TGBATRIS",
|
|
||||||
isDefault: false,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
@ -1,100 +0,0 @@
|
||||||
import { DepartmentDto } from "@/proxy/intranet/models"
|
|
||||||
|
|
||||||
export const mockDepartments: DepartmentDto[] = [
|
|
||||||
{
|
|
||||||
id: '1',
|
|
||||||
name: 'Üretim',
|
|
||||||
description: 'Üretim departmanı',
|
|
||||||
parentDepartmentId: undefined,
|
|
||||||
parentDepartment: undefined,
|
|
||||||
subDepartments: [],
|
|
||||||
managerId: '1',
|
|
||||||
manager: undefined,
|
|
||||||
costCenterId: 'cc-005',
|
|
||||||
costCenter: undefined,
|
|
||||||
budget: 8500000,
|
|
||||||
isActive: true,
|
|
||||||
creationTime: new Date('2022-03-15'),
|
|
||||||
lastModificationTime: new Date('2024-01-15'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '2',
|
|
||||||
name: 'Bakım',
|
|
||||||
description: 'Bakım departmanı',
|
|
||||||
parentDepartmentId: undefined,
|
|
||||||
parentDepartment: undefined,
|
|
||||||
subDepartments: [],
|
|
||||||
managerId: '7',
|
|
||||||
manager: undefined,
|
|
||||||
costCenterId: 'cc-011',
|
|
||||||
costCenter: undefined,
|
|
||||||
budget: 2200000,
|
|
||||||
isActive: true,
|
|
||||||
creationTime: new Date('2022-03-15'),
|
|
||||||
lastModificationTime: new Date('2024-01-15'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '3',
|
|
||||||
name: 'Kalite Kontrol',
|
|
||||||
description: 'Kalite kontrol departmanı',
|
|
||||||
parentDepartmentId: '1',
|
|
||||||
parentDepartment: undefined,
|
|
||||||
subDepartments: [],
|
|
||||||
managerId: '5',
|
|
||||||
manager: undefined,
|
|
||||||
costCenterId: 'cc-007',
|
|
||||||
costCenter: undefined,
|
|
||||||
budget: 1200000,
|
|
||||||
isActive: true,
|
|
||||||
creationTime: new Date('2022-03-15'),
|
|
||||||
lastModificationTime: new Date('2024-01-15'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '4',
|
|
||||||
name: 'Depo',
|
|
||||||
description: 'Depo departmanı',
|
|
||||||
parentDepartmentId: '1',
|
|
||||||
parentDepartment: undefined,
|
|
||||||
subDepartments: [],
|
|
||||||
managerId: '3',
|
|
||||||
manager: undefined,
|
|
||||||
costCenterId: 'cc-008',
|
|
||||||
costCenter: undefined,
|
|
||||||
budget: 2800000,
|
|
||||||
isActive: true,
|
|
||||||
creationTime: new Date('2022-03-15'),
|
|
||||||
lastModificationTime: new Date('2024-01-15'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '5',
|
|
||||||
name: 'İdari İşler',
|
|
||||||
description: 'İdari işler departmanı',
|
|
||||||
parentDepartmentId: undefined,
|
|
||||||
parentDepartment: undefined,
|
|
||||||
subDepartments: [],
|
|
||||||
managerId: '2',
|
|
||||||
manager: undefined,
|
|
||||||
costCenterId: 'cc-001',
|
|
||||||
costCenter: undefined,
|
|
||||||
budget: 2500000,
|
|
||||||
isActive: true,
|
|
||||||
creationTime: new Date('2022-03-15'),
|
|
||||||
lastModificationTime: new Date('2024-01-15'),
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
mockDepartments.forEach((dept) => {
|
|
||||||
if (dept.parentDepartmentId) {
|
|
||||||
dept.parentDepartment = mockDepartments.find((d) => d.id === dept.parentDepartmentId)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
mockDepartments.forEach((dept) => {
|
|
||||||
if (dept.parentDepartmentId) {
|
|
||||||
const parent = mockDepartments.find((d) => d.id === dept.parentDepartmentId)
|
|
||||||
if (parent) {
|
|
||||||
dept.parentDepartment = parent
|
|
||||||
parent.subDepartments.push(dept) // subDepartments bağlantısı
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
@ -1,602 +0,0 @@
|
||||||
import { EmployeeDto } from "@/proxy/intranet/models";
|
|
||||||
import {
|
|
||||||
EmployeeStatusEnum,
|
|
||||||
EmploymentTypeEnum,
|
|
||||||
GenderEnum,
|
|
||||||
MaritalStatusEnum,
|
|
||||||
} from "../types/hr";
|
|
||||||
import { mockBanks } from "./mockBanks";
|
|
||||||
import { mockDepartments } from "./mockDepartments";
|
|
||||||
import { mockJobPositions } from "./mockJobPositions";
|
|
||||||
|
|
||||||
export const mockEmployees: EmployeeDto[] = [
|
|
||||||
{
|
|
||||||
id: "1",
|
|
||||||
code: "EMP-001",
|
|
||||||
firstName: "Ali",
|
|
||||||
lastName: "Öztürk",
|
|
||||||
name: "Ali Öztürk",
|
|
||||||
email: "ali.ozturk@company.com",
|
|
||||||
phoneNumber: "2125550100",
|
|
||||||
mobileNumber: "5325550101",
|
|
||||||
avatar: "https://i.pravatar.cc/150?img=12",
|
|
||||||
nationalId: "12345678901",
|
|
||||||
birthDate: new Date("1988-10-20"),
|
|
||||||
gender: GenderEnum.Male,
|
|
||||||
maritalStatus: MaritalStatusEnum.Married,
|
|
||||||
address: {
|
|
||||||
street: "Kızılay Cd. No:12",
|
|
||||||
city: "Ankara",
|
|
||||||
state: "Ankara",
|
|
||||||
postalCode: "06050",
|
|
||||||
country: "Türkiye",
|
|
||||||
},
|
|
||||||
emergencyContact: {
|
|
||||||
name: "Ayşe Öztürk",
|
|
||||||
relationship: "Eşi",
|
|
||||||
phoneNumber: "+90 532 555 0100",
|
|
||||||
},
|
|
||||||
hireDate: new Date("2020-01-15"),
|
|
||||||
employmentType: EmploymentTypeEnum.FullTime,
|
|
||||||
jobPositionId: "1",
|
|
||||||
jobPosition: mockJobPositions.find((jp) => jp.id === "1")!,
|
|
||||||
departmentId: "1",
|
|
||||||
department: mockDepartments.find((d) => d.id === "1")!,
|
|
||||||
baseSalary: 65000,
|
|
||||||
currency: "TRY",
|
|
||||||
payrollGroup: "MONTHLY",
|
|
||||||
bankAccountId: "1",
|
|
||||||
bankAccount: mockBanks.find((b) => b.id === "1")!,
|
|
||||||
workLocation: "Ankara Merkez",
|
|
||||||
workSchedule: {
|
|
||||||
id: "1",
|
|
||||||
scheduleCode: "STD",
|
|
||||||
name: "Standart Mesai",
|
|
||||||
description: "08:30-17:30 Pazartesi-Cuma",
|
|
||||||
workingDays: [],
|
|
||||||
totalHoursPerWeek: 40,
|
|
||||||
isFlexible: false,
|
|
||||||
isActive: true,
|
|
||||||
},
|
|
||||||
badgeNumber: "B001",
|
|
||||||
employeeStatus: EmployeeStatusEnum.Active,
|
|
||||||
isActive: true,
|
|
||||||
leaves: [],
|
|
||||||
evaluations: [],
|
|
||||||
trainings: [],
|
|
||||||
disciplinaryActions: [],
|
|
||||||
creationTime: new Date("2020-01-15"),
|
|
||||||
lastModificationTime: new Date("2024-01-18"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "2",
|
|
||||||
code: "EMP-002",
|
|
||||||
firstName: "Ayşe",
|
|
||||||
lastName: "Kaya",
|
|
||||||
name: "Ayşe Kaya",
|
|
||||||
email: "ayse.kaya@company.com",
|
|
||||||
phoneNumber: "2125550102",
|
|
||||||
mobileNumber: "5325550103",
|
|
||||||
avatar: "https://i.pravatar.cc/150?img=5",
|
|
||||||
nationalId: "12345678902",
|
|
||||||
birthDate: new Date("1990-08-22"),
|
|
||||||
gender: GenderEnum.Female,
|
|
||||||
maritalStatus: MaritalStatusEnum.Single,
|
|
||||||
address: {
|
|
||||||
street: "İnönü Bulvarı No:456",
|
|
||||||
city: "Ankara",
|
|
||||||
state: "Ankara",
|
|
||||||
postalCode: "06000",
|
|
||||||
country: "Türkiye",
|
|
||||||
},
|
|
||||||
emergencyContact: {
|
|
||||||
name: "Fatma Kaya",
|
|
||||||
relationship: "Anne",
|
|
||||||
phoneNumber: "+90 532 555 0104",
|
|
||||||
},
|
|
||||||
hireDate: new Date("2021-06-01"),
|
|
||||||
employmentType: EmploymentTypeEnum.FullTime,
|
|
||||||
jobPositionId: "2",
|
|
||||||
jobPosition: mockJobPositions.find((jp) => jp.id === "2")!,
|
|
||||||
|
|
||||||
departmentId: "1",
|
|
||||||
department: mockDepartments.find((d) => d.id === "1")!,
|
|
||||||
baseSalary: 72000,
|
|
||||||
currency: "TRY",
|
|
||||||
payrollGroup: "MONTHLY",
|
|
||||||
bankAccountId: "2",
|
|
||||||
bankAccount: mockBanks.find((b) => b.id === "2")!,
|
|
||||||
workLocation: "Ankara Şube",
|
|
||||||
workSchedule: {
|
|
||||||
id: "2",
|
|
||||||
scheduleCode: "STD",
|
|
||||||
name: "Standart Mesai",
|
|
||||||
description: "08:30-17:30 Pazartesi-Cuma",
|
|
||||||
workingDays: [],
|
|
||||||
totalHoursPerWeek: 40,
|
|
||||||
isFlexible: false,
|
|
||||||
isActive: true,
|
|
||||||
},
|
|
||||||
badgeNumber: "B002",
|
|
||||||
employeeStatus: EmployeeStatusEnum.Active,
|
|
||||||
isActive: true,
|
|
||||||
leaves: [],
|
|
||||||
evaluations: [],
|
|
||||||
trainings: [],
|
|
||||||
disciplinaryActions: [],
|
|
||||||
creationTime: new Date("2021-06-01"),
|
|
||||||
lastModificationTime: new Date("2024-01-18"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "3",
|
|
||||||
code: "EMP-003",
|
|
||||||
firstName: "Mehmet",
|
|
||||||
lastName: "Yılmaz",
|
|
||||||
name: "Mehmet Yılmaz",
|
|
||||||
email: "mehmet.yilmaz@company.com",
|
|
||||||
phoneNumber: "2125550105",
|
|
||||||
mobileNumber: "5325550106",
|
|
||||||
avatar: "https://i.pravatar.cc/150?img=8",
|
|
||||||
nationalId: "12345678903",
|
|
||||||
birthDate: new Date("1987-03-12"),
|
|
||||||
gender: GenderEnum.Male,
|
|
||||||
maritalStatus: MaritalStatusEnum.Married,
|
|
||||||
address: {
|
|
||||||
street: "Cumhuriyet Cad. No:123",
|
|
||||||
city: "İstanbul",
|
|
||||||
state: "İstanbul",
|
|
||||||
postalCode: "34000",
|
|
||||||
country: "Türkiye",
|
|
||||||
},
|
|
||||||
emergencyContact: {
|
|
||||||
name: "Zeynep Yılmaz",
|
|
||||||
relationship: "Eşi",
|
|
||||||
phoneNumber: "+90 532 555 0107",
|
|
||||||
},
|
|
||||||
hireDate: new Date("2020-02-15"),
|
|
||||||
employmentType: EmploymentTypeEnum.FullTime,
|
|
||||||
jobPositionId: "3",
|
|
||||||
jobPosition: mockJobPositions.find((jp) => jp.id === "3")!,
|
|
||||||
|
|
||||||
departmentId: "1",
|
|
||||||
department: mockDepartments.find((d) => d.id === "1")!,
|
|
||||||
baseSalary: 85000,
|
|
||||||
currency: "TRY",
|
|
||||||
payrollGroup: "MONTHLY",
|
|
||||||
bankAccountId: "2",
|
|
||||||
bankAccount: mockBanks.find((b) => b.id === "2")!,
|
|
||||||
workLocation: "İstanbul HQ",
|
|
||||||
workSchedule: {
|
|
||||||
id: "2",
|
|
||||||
scheduleCode: "FLEX",
|
|
||||||
name: "Esnek Çalışma",
|
|
||||||
description: "09:00-18:00 Pazartesi-Cuma",
|
|
||||||
workingDays: [],
|
|
||||||
totalHoursPerWeek: 40,
|
|
||||||
isFlexible: true,
|
|
||||||
isActive: true,
|
|
||||||
},
|
|
||||||
badgeNumber: "B003",
|
|
||||||
employeeStatus: EmployeeStatusEnum.Active,
|
|
||||||
isActive: true,
|
|
||||||
leaves: [],
|
|
||||||
evaluations: [],
|
|
||||||
trainings: [],
|
|
||||||
disciplinaryActions: [],
|
|
||||||
creationTime: new Date("2020-02-15"),
|
|
||||||
lastModificationTime: new Date("2024-02-01"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "4",
|
|
||||||
code: "EMP-004",
|
|
||||||
firstName: "Selin",
|
|
||||||
lastName: "Demir",
|
|
||||||
name: "Selin Demir",
|
|
||||||
email: "selin.demir@company.com",
|
|
||||||
phoneNumber: "3125550108",
|
|
||||||
mobileNumber: "5425550109",
|
|
||||||
avatar: "https://i.pravatar.cc/150?img=9",
|
|
||||||
nationalId: "12345678904",
|
|
||||||
birthDate: new Date("1993-05-25"),
|
|
||||||
gender: GenderEnum.Female,
|
|
||||||
maritalStatus: MaritalStatusEnum.Single,
|
|
||||||
address: {
|
|
||||||
street: "Atatürk Bulvarı No:78",
|
|
||||||
city: "Ankara",
|
|
||||||
state: "Ankara",
|
|
||||||
postalCode: "06100",
|
|
||||||
country: "Türkiye",
|
|
||||||
},
|
|
||||||
emergencyContact: {
|
|
||||||
name: "Ali Demir",
|
|
||||||
relationship: "Baba",
|
|
||||||
phoneNumber: "532 555 0110",
|
|
||||||
},
|
|
||||||
hireDate: new Date("2022-01-10"),
|
|
||||||
employmentType: EmploymentTypeEnum.PartTime,
|
|
||||||
jobPositionId: "4",
|
|
||||||
jobPosition: mockJobPositions.find((jp) => jp.id === "4")!,
|
|
||||||
|
|
||||||
departmentId: "1",
|
|
||||||
department: mockDepartments.find((d) => d.id === "1")!,
|
|
||||||
baseSalary: 60000,
|
|
||||||
currency: "TRY",
|
|
||||||
payrollGroup: "MONTHLY",
|
|
||||||
bankAccountId: "3",
|
|
||||||
bankAccount: mockBanks.find((b) => b.id === "3")!,
|
|
||||||
workLocation: "Ankara Şube",
|
|
||||||
workSchedule: {
|
|
||||||
id: "3",
|
|
||||||
scheduleCode: "PT",
|
|
||||||
name: "Yarı Zamanlı",
|
|
||||||
description: "09:00-13:00 Pazartesi-Cuma",
|
|
||||||
workingDays: [],
|
|
||||||
totalHoursPerWeek: 20,
|
|
||||||
isFlexible: false,
|
|
||||||
isActive: true,
|
|
||||||
},
|
|
||||||
badgeNumber: "B004",
|
|
||||||
employeeStatus: EmployeeStatusEnum.Active,
|
|
||||||
isActive: true,
|
|
||||||
leaves: [],
|
|
||||||
evaluations: [],
|
|
||||||
trainings: [],
|
|
||||||
disciplinaryActions: [],
|
|
||||||
creationTime: new Date("2022-01-10"),
|
|
||||||
lastModificationTime: new Date("2024-01-20"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "5",
|
|
||||||
code: "EMP-005",
|
|
||||||
firstName: "Ahmet",
|
|
||||||
lastName: "Çelik",
|
|
||||||
name: "Ahmet Çelik",
|
|
||||||
email: "ahmet.celik@company.com",
|
|
||||||
phoneNumber: "2125550111",
|
|
||||||
mobileNumber: "5325550112",
|
|
||||||
avatar: "https://i.pravatar.cc/150?img=33",
|
|
||||||
nationalId: "12345678905",
|
|
||||||
birthDate: new Date("1985-09-10"),
|
|
||||||
gender: GenderEnum.Male,
|
|
||||||
maritalStatus: MaritalStatusEnum.Married,
|
|
||||||
address: {
|
|
||||||
street: "Bağdat Cad. No:25",
|
|
||||||
city: "İstanbul",
|
|
||||||
state: "İstanbul",
|
|
||||||
postalCode: "34728",
|
|
||||||
country: "Türkiye",
|
|
||||||
},
|
|
||||||
emergencyContact: {
|
|
||||||
name: "Emine Çelik",
|
|
||||||
relationship: "Eşi",
|
|
||||||
phoneNumber: "532 555 0113",
|
|
||||||
},
|
|
||||||
hireDate: new Date("2019-04-01"),
|
|
||||||
employmentType: EmploymentTypeEnum.FullTime,
|
|
||||||
jobPositionId: "5",
|
|
||||||
jobPosition: mockJobPositions.find((jp) => jp.id === "5")!,
|
|
||||||
|
|
||||||
departmentId: "1",
|
|
||||||
department: mockDepartments.find((d) => d.id === "1")!,
|
|
||||||
baseSalary: 95000,
|
|
||||||
currency: "TRY",
|
|
||||||
payrollGroup: "MONTHLY",
|
|
||||||
bankAccountId: "4",
|
|
||||||
bankAccount: mockBanks.find((b) => b.id === "4")!,
|
|
||||||
workLocation: "İstanbul HQ",
|
|
||||||
workSchedule: {
|
|
||||||
id: "4",
|
|
||||||
scheduleCode: "STD",
|
|
||||||
name: "Standart Mesai",
|
|
||||||
description: "08:30-17:30 Pazartesi-Cuma",
|
|
||||||
workingDays: [],
|
|
||||||
totalHoursPerWeek: 40,
|
|
||||||
isFlexible: false,
|
|
||||||
isActive: true,
|
|
||||||
},
|
|
||||||
badgeNumber: "B005",
|
|
||||||
employeeStatus: EmployeeStatusEnum.Active,
|
|
||||||
isActive: true,
|
|
||||||
leaves: [],
|
|
||||||
evaluations: [],
|
|
||||||
trainings: [],
|
|
||||||
disciplinaryActions: [],
|
|
||||||
creationTime: new Date("2019-04-01"),
|
|
||||||
lastModificationTime: new Date("2024-01-10"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "6",
|
|
||||||
code: "EMP-006",
|
|
||||||
firstName: "Zeynep",
|
|
||||||
lastName: "Arslan",
|
|
||||||
name: "Zeynep Arslan",
|
|
||||||
email: "zeynep.arslan@company.com",
|
|
||||||
phoneNumber: "2165550114",
|
|
||||||
mobileNumber: "5325550115",
|
|
||||||
avatar: "https://i.pravatar.cc/150?img=10",
|
|
||||||
nationalId: "12345678906",
|
|
||||||
birthDate: new Date("1995-01-30"),
|
|
||||||
gender: GenderEnum.Female,
|
|
||||||
maritalStatus: MaritalStatusEnum.Single,
|
|
||||||
address: {
|
|
||||||
street: "Yıldız Mah. No:19",
|
|
||||||
city: "İzmir",
|
|
||||||
state: "İzmir",
|
|
||||||
postalCode: "35000",
|
|
||||||
country: "Türkiye",
|
|
||||||
},
|
|
||||||
emergencyContact: {
|
|
||||||
name: "Hasan Arslan",
|
|
||||||
relationship: "Baba",
|
|
||||||
phoneNumber: "532 555 0116",
|
|
||||||
},
|
|
||||||
hireDate: new Date("2023-03-20"),
|
|
||||||
employmentType: EmploymentTypeEnum.Intern,
|
|
||||||
jobPositionId: "6",
|
|
||||||
jobPosition: mockJobPositions.find((jp) => jp.id === "6")!,
|
|
||||||
|
|
||||||
departmentId: "1",
|
|
||||||
department: mockDepartments.find((d) => d.id === "1")!,
|
|
||||||
baseSalary: 15000,
|
|
||||||
currency: "TRY",
|
|
||||||
payrollGroup: "MONTHLY",
|
|
||||||
bankAccountId: "1",
|
|
||||||
bankAccount: mockBanks.find((b) => b.id === "1")!,
|
|
||||||
workLocation: "İzmir Ofis",
|
|
||||||
workSchedule: {
|
|
||||||
id: "5",
|
|
||||||
scheduleCode: "INT",
|
|
||||||
name: "Staj Programı",
|
|
||||||
description: "09:00-16:00 Pazartesi-Perşembe",
|
|
||||||
workingDays: [],
|
|
||||||
totalHoursPerWeek: 30,
|
|
||||||
isFlexible: true,
|
|
||||||
isActive: true,
|
|
||||||
},
|
|
||||||
badgeNumber: "B006",
|
|
||||||
employeeStatus: EmployeeStatusEnum.Active,
|
|
||||||
isActive: true,
|
|
||||||
leaves: [],
|
|
||||||
evaluations: [],
|
|
||||||
trainings: [],
|
|
||||||
disciplinaryActions: [],
|
|
||||||
creationTime: new Date("2023-03-20"),
|
|
||||||
lastModificationTime: new Date("2024-02-15"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "7",
|
|
||||||
code: "EMP-007",
|
|
||||||
firstName: "Burak",
|
|
||||||
lastName: "Koç",
|
|
||||||
name: "Burak Koç",
|
|
||||||
email: "burak.koc@company.com",
|
|
||||||
phoneNumber: "2245550117",
|
|
||||||
mobileNumber: "5325550118",
|
|
||||||
avatar: "https://i.pravatar.cc/150?img=14",
|
|
||||||
nationalId: "12345678907",
|
|
||||||
birthDate: new Date("1991-06-18"),
|
|
||||||
gender: GenderEnum.Male,
|
|
||||||
maritalStatus: MaritalStatusEnum.Married,
|
|
||||||
address: {
|
|
||||||
street: "Osmangazi Mah. No:45",
|
|
||||||
city: "Bursa",
|
|
||||||
state: "Bursa",
|
|
||||||
postalCode: "16000",
|
|
||||||
country: "Türkiye",
|
|
||||||
},
|
|
||||||
emergencyContact: {
|
|
||||||
name: "Elif Koç",
|
|
||||||
relationship: "Eşi",
|
|
||||||
phoneNumber: "+90 532 555 0119",
|
|
||||||
},
|
|
||||||
hireDate: new Date("2021-07-12"),
|
|
||||||
employmentType: EmploymentTypeEnum.FullTime,
|
|
||||||
jobPositionId: "7",
|
|
||||||
jobPosition: mockJobPositions.find((jp) => jp.id === "7")!,
|
|
||||||
|
|
||||||
departmentId: "2",
|
|
||||||
department: mockDepartments.find((d) => d.id === "2")!,
|
|
||||||
baseSalary: 75000,
|
|
||||||
currency: "TRY",
|
|
||||||
payrollGroup: "MONTHLY",
|
|
||||||
bankAccountId: "3",
|
|
||||||
bankAccount: mockBanks.find((b) => b.id === "3")!,
|
|
||||||
workLocation: "Bursa Depo",
|
|
||||||
workSchedule: {
|
|
||||||
id: "6",
|
|
||||||
scheduleCode: "STD",
|
|
||||||
name: "Standart Mesai",
|
|
||||||
description: "08:00-17:00 Pazartesi-Cumartesi",
|
|
||||||
workingDays: [],
|
|
||||||
totalHoursPerWeek: 45,
|
|
||||||
isFlexible: false,
|
|
||||||
isActive: true,
|
|
||||||
},
|
|
||||||
badgeNumber: "B007",
|
|
||||||
employeeStatus: EmployeeStatusEnum.Active,
|
|
||||||
isActive: true,
|
|
||||||
leaves: [],
|
|
||||||
evaluations: [],
|
|
||||||
trainings: [],
|
|
||||||
disciplinaryActions: [],
|
|
||||||
creationTime: new Date("2021-07-12"),
|
|
||||||
lastModificationTime: new Date("2024-01-05"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "8",
|
|
||||||
code: "EMP-008",
|
|
||||||
firstName: "Elif",
|
|
||||||
lastName: "Şahin",
|
|
||||||
name: "Elif Şahin",
|
|
||||||
email: "elif.sahin@company.com",
|
|
||||||
phoneNumber: "2325550120",
|
|
||||||
mobileNumber: "5325550121",
|
|
||||||
avatar: "https://i.pravatar.cc/150?img=20",
|
|
||||||
nationalId: "12345678908",
|
|
||||||
birthDate: new Date("1989-11-05"),
|
|
||||||
gender: GenderEnum.Female,
|
|
||||||
maritalStatus: MaritalStatusEnum.Married,
|
|
||||||
address: {
|
|
||||||
street: "Alsancak Mah. No:88",
|
|
||||||
city: "İzmir",
|
|
||||||
state: "İzmir",
|
|
||||||
postalCode: "35220",
|
|
||||||
country: "Türkiye",
|
|
||||||
},
|
|
||||||
emergencyContact: {
|
|
||||||
name: "Murat Şahin",
|
|
||||||
relationship: "Eşi",
|
|
||||||
phoneNumber: "+90 532 555 0122",
|
|
||||||
},
|
|
||||||
hireDate: new Date("2018-09-01"),
|
|
||||||
employmentType: EmploymentTypeEnum.FullTime,
|
|
||||||
jobPositionId: "8",
|
|
||||||
jobPosition: mockJobPositions.find((jp) => jp.id === "8")!,
|
|
||||||
|
|
||||||
departmentId: "2",
|
|
||||||
department: mockDepartments.find((d) => d.id === "2")!,
|
|
||||||
baseSalary: 130000,
|
|
||||||
currency: "TRY",
|
|
||||||
payrollGroup: "MONTHLY",
|
|
||||||
bankAccountId: "2",
|
|
||||||
bankAccount: mockBanks.find((b) => b.id === "2")!,
|
|
||||||
workLocation: "İzmir Bölge Ofisi",
|
|
||||||
workSchedule: {
|
|
||||||
id: "7",
|
|
||||||
scheduleCode: "STD",
|
|
||||||
name: "Standart Mesai",
|
|
||||||
description: "08:30-17:30 Pazartesi-Cuma",
|
|
||||||
workingDays: [],
|
|
||||||
totalHoursPerWeek: 40,
|
|
||||||
isFlexible: false,
|
|
||||||
isActive: true,
|
|
||||||
},
|
|
||||||
badgeNumber: "B008",
|
|
||||||
employeeStatus: EmployeeStatusEnum.Active,
|
|
||||||
isActive: true,
|
|
||||||
leaves: [],
|
|
||||||
evaluations: [],
|
|
||||||
trainings: [],
|
|
||||||
disciplinaryActions: [],
|
|
||||||
creationTime: new Date("2018-09-01"),
|
|
||||||
lastModificationTime: new Date("2024-01-12"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "9",
|
|
||||||
code: "EMP-009",
|
|
||||||
firstName: "Canan",
|
|
||||||
lastName: "Öztürk",
|
|
||||||
name: "Canan Öztürk",
|
|
||||||
email: "canan.ozturk@company.com",
|
|
||||||
phoneNumber: "3125550123",
|
|
||||||
mobileNumber: "5325550124",
|
|
||||||
avatar: "https://i.pravatar.cc/150?img=25",
|
|
||||||
nationalId: "12345678909",
|
|
||||||
birthDate: new Date("1992-04-14"),
|
|
||||||
gender: GenderEnum.Female,
|
|
||||||
maritalStatus: MaritalStatusEnum.Single,
|
|
||||||
address: {
|
|
||||||
street: "Bahçelievler Mah. No:55",
|
|
||||||
city: "Ankara",
|
|
||||||
state: "Ankara",
|
|
||||||
postalCode: "06490",
|
|
||||||
country: "Türkiye",
|
|
||||||
},
|
|
||||||
emergencyContact: {
|
|
||||||
name: "Hüseyin Öztürk",
|
|
||||||
relationship: "Baba",
|
|
||||||
phoneNumber: "+90 532 555 0125",
|
|
||||||
},
|
|
||||||
hireDate: new Date("2020-11-02"),
|
|
||||||
employmentType: EmploymentTypeEnum.FullTime,
|
|
||||||
jobPositionId: "9",
|
|
||||||
jobPosition: mockJobPositions.find((jp) => jp.id === "9")!,
|
|
||||||
|
|
||||||
departmentId: "1",
|
|
||||||
department: mockDepartments.find((d) => d.id === "1")!,
|
|
||||||
baseSalary: 50000,
|
|
||||||
currency: "TRY",
|
|
||||||
payrollGroup: "MONTHLY",
|
|
||||||
bankAccountId: "1",
|
|
||||||
bankAccount: mockBanks.find((b) => b.id === "1")!,
|
|
||||||
workLocation: "Ankara Çağrı Merkezi",
|
|
||||||
workSchedule: {
|
|
||||||
id: "8",
|
|
||||||
scheduleCode: "SHIFT",
|
|
||||||
name: "Vardiya",
|
|
||||||
description: "3 vardiya sistemi",
|
|
||||||
workingDays: [],
|
|
||||||
totalHoursPerWeek: 40,
|
|
||||||
isFlexible: true,
|
|
||||||
isActive: true,
|
|
||||||
},
|
|
||||||
badgeNumber: "B009",
|
|
||||||
employeeStatus: EmployeeStatusEnum.Active,
|
|
||||||
isActive: true,
|
|
||||||
leaves: [],
|
|
||||||
evaluations: [],
|
|
||||||
trainings: [],
|
|
||||||
disciplinaryActions: [],
|
|
||||||
creationTime: new Date("2020-11-02"),
|
|
||||||
lastModificationTime: new Date("2024-01-18"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "10",
|
|
||||||
code: "EMP-010",
|
|
||||||
firstName: "Murat",
|
|
||||||
lastName: "Aydın",
|
|
||||||
name: "Murat Aydın",
|
|
||||||
email: "murat.aydin@company.com",
|
|
||||||
phoneNumber: "2125550126",
|
|
||||||
mobileNumber: "5325550127",
|
|
||||||
avatar: "https://i.pravatar.cc/150?img=30",
|
|
||||||
nationalId: "12345678910",
|
|
||||||
birthDate: new Date("1984-12-22"),
|
|
||||||
gender: GenderEnum.Male,
|
|
||||||
maritalStatus: MaritalStatusEnum.Married,
|
|
||||||
address: {
|
|
||||||
street: "Şişli Mah. No:101",
|
|
||||||
city: "İstanbul",
|
|
||||||
state: "İstanbul",
|
|
||||||
postalCode: "34360",
|
|
||||||
country: "Türkiye",
|
|
||||||
},
|
|
||||||
emergencyContact: {
|
|
||||||
name: "Ayten Aydın",
|
|
||||||
relationship: "Eşi",
|
|
||||||
phoneNumber: "+90 532 555 0128",
|
|
||||||
},
|
|
||||||
hireDate: new Date("2017-05-15"),
|
|
||||||
employmentType: EmploymentTypeEnum.FullTime,
|
|
||||||
jobPositionId: "10",
|
|
||||||
jobPosition: mockJobPositions.find((jp) => jp.id === "10")!,
|
|
||||||
|
|
||||||
departmentId: "1",
|
|
||||||
department: mockDepartments.find((d) => d.id === "1")!,
|
|
||||||
baseSalary: 250000,
|
|
||||||
currency: "TRY",
|
|
||||||
payrollGroup: "MONTHLY",
|
|
||||||
bankAccountId: "4",
|
|
||||||
bankAccount: mockBanks.find((b) => b.id === "4")!,
|
|
||||||
workLocation: "İstanbul Genel Merkez",
|
|
||||||
workSchedule: {
|
|
||||||
id: "9",
|
|
||||||
scheduleCode: "EXEC",
|
|
||||||
name: "Yönetici Çalışma Programı",
|
|
||||||
description: "Esnek yönetici programı",
|
|
||||||
workingDays: [],
|
|
||||||
totalHoursPerWeek: 50,
|
|
||||||
isFlexible: true,
|
|
||||||
isActive: true,
|
|
||||||
},
|
|
||||||
badgeNumber: "B010",
|
|
||||||
employeeStatus: EmployeeStatusEnum.Active,
|
|
||||||
isActive: true,
|
|
||||||
leaves: [],
|
|
||||||
evaluations: [],
|
|
||||||
trainings: [],
|
|
||||||
disciplinaryActions: [],
|
|
||||||
creationTime: new Date("2017-05-15"),
|
|
||||||
lastModificationTime: new Date("2024-01-22"),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
||||||
import { Exam } from "@/types/coordinator";
|
|
||||||
import { generateMockPools } from "./mockPools";
|
|
||||||
|
|
||||||
export const generateMockExam = (): Exam[] => [
|
|
||||||
{
|
|
||||||
id: "exam-1",
|
|
||||||
title: "Grammar Assessment",
|
|
||||||
description: "Comprehensive grammar evaluation",
|
|
||||||
type: "exam",
|
|
||||||
questions: generateMockPools()[0].questions,
|
|
||||||
timeLimit: 30,
|
|
||||||
totalPoints: 25,
|
|
||||||
passingScore: 60,
|
|
||||||
allowReview: true,
|
|
||||||
randomizeQuestions: false,
|
|
||||||
showResults: true,
|
|
||||||
maxAttempts: 1,
|
|
||||||
isActive: true,
|
|
||||||
creationTime: new Date(),
|
|
||||||
lastModificationTime: new Date(),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "assignment-1",
|
|
||||||
title: "Assignment 1",
|
|
||||||
description: "First assignment on grammar topics",
|
|
||||||
type: "assignment",
|
|
||||||
questions: generateMockPools()[0].questions,
|
|
||||||
timeLimit: 30,
|
|
||||||
totalPoints: 25,
|
|
||||||
passingScore: 60,
|
|
||||||
allowReview: true,
|
|
||||||
randomizeQuestions: false,
|
|
||||||
showResults: true,
|
|
||||||
maxAttempts: 1,
|
|
||||||
isActive: true,
|
|
||||||
creationTime: new Date(),
|
|
||||||
lastModificationTime: new Date(),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
@ -1,301 +0,0 @@
|
||||||
import { JobPositionDto } from "@/proxy/intranet/models";
|
|
||||||
import { mockDepartments } from "./mockDepartments";
|
|
||||||
import { JobLevelEnum } from "@/types/hr";
|
|
||||||
|
|
||||||
export const mockJobPositions: JobPositionDto[] = [
|
|
||||||
{
|
|
||||||
id: "1",
|
|
||||||
name: "Software Developer",
|
|
||||||
description: "Responsible for developing and maintaining web applications",
|
|
||||||
departmentId: "1",
|
|
||||||
department: mockDepartments.find((dept) => dept.id === "1"),
|
|
||||||
level: JobLevelEnum.Mid,
|
|
||||||
minSalary: 80000,
|
|
||||||
maxSalary: 120000,
|
|
||||||
currency: "USD",
|
|
||||||
requiredSkills: ["JavaScript", "TypeScript", "React", "Node.js"],
|
|
||||||
responsibilities: [
|
|
||||||
"Develop frontend and backend applications",
|
|
||||||
"Write clean and maintainable code",
|
|
||||||
"Participate in code reviews",
|
|
||||||
"Collaborate with team members",
|
|
||||||
],
|
|
||||||
qualifications: [
|
|
||||||
"Bachelor's degree in Computer Science or related field",
|
|
||||||
"3+ years of experience in web development",
|
|
||||||
"Strong knowledge of JavaScript and TypeScript",
|
|
||||||
],
|
|
||||||
isActive: true,
|
|
||||||
employees: [],
|
|
||||||
creationTime: new Date("2024-01-15T08:00:00Z"),
|
|
||||||
lastModificationTime: new Date("2024-01-15T08:00:00Z"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "2",
|
|
||||||
name: "Project Manager",
|
|
||||||
description: "Lead and manage software development projects",
|
|
||||||
departmentId: "1",
|
|
||||||
department: mockDepartments.find((dept) => dept.id === "1"),
|
|
||||||
level: JobLevelEnum.Manager,
|
|
||||||
minSalary: 100000,
|
|
||||||
maxSalary: 150000,
|
|
||||||
currency: "USD",
|
|
||||||
requiredSkills: ["Project Management", "Agile", "Scrum", "Leadership"],
|
|
||||||
responsibilities: [
|
|
||||||
"Plan and execute project timelines",
|
|
||||||
"Coordinate with cross-functional teams",
|
|
||||||
"Manage project budgets and resources",
|
|
||||||
"Ensure project delivery within scope and timeline",
|
|
||||||
],
|
|
||||||
qualifications: [
|
|
||||||
"Bachelor's degree in Business or related field",
|
|
||||||
"5+ years of project management experience",
|
|
||||||
"PMP certification preferred",
|
|
||||||
],
|
|
||||||
isActive: true,
|
|
||||||
employees: [],
|
|
||||||
creationTime: new Date("2024-01-16T08:00:00Z"),
|
|
||||||
lastModificationTime: new Date("2024-01-16T08:00:00Z"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "3",
|
|
||||||
name: "Quality Assurance Engineer",
|
|
||||||
description: "Ensure software quality through testing and automation",
|
|
||||||
departmentId: "1",
|
|
||||||
department: mockDepartments.find((dept) => dept.id === "1"),
|
|
||||||
level: JobLevelEnum.Mid,
|
|
||||||
minSalary: 70000,
|
|
||||||
maxSalary: 100000,
|
|
||||||
currency: "USD",
|
|
||||||
requiredSkills: ["Testing", "Automation", "Selenium", "API Testing"],
|
|
||||||
responsibilities: [
|
|
||||||
"Design and execute test cases",
|
|
||||||
"Automate testing processes",
|
|
||||||
"Report and track bugs",
|
|
||||||
"Collaborate with development team",
|
|
||||||
],
|
|
||||||
qualifications: [
|
|
||||||
"Bachelor's degree in Computer Science or related field",
|
|
||||||
"3+ years of QA experience",
|
|
||||||
"Experience with automation tools",
|
|
||||||
],
|
|
||||||
isActive: true,
|
|
||||||
employees: [],
|
|
||||||
creationTime: new Date("2024-01-17T08:00:00Z"),
|
|
||||||
lastModificationTime: new Date("2024-01-17T08:00:00Z"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "4",
|
|
||||||
name: "UX/UI Designer",
|
|
||||||
description: "Design user interfaces and improve user experience",
|
|
||||||
departmentId: "2",
|
|
||||||
department: mockDepartments.find((dept) => dept.id === "2"),
|
|
||||||
level: JobLevelEnum.Mid,
|
|
||||||
minSalary: 75000,
|
|
||||||
maxSalary: 110000,
|
|
||||||
currency: "USD",
|
|
||||||
requiredSkills: [
|
|
||||||
"Figma",
|
|
||||||
"Adobe Creative Suite",
|
|
||||||
"User Research",
|
|
||||||
"Prototyping",
|
|
||||||
],
|
|
||||||
responsibilities: [
|
|
||||||
"Create wireframes and prototypes",
|
|
||||||
"Conduct user research",
|
|
||||||
"Design intuitive user interfaces",
|
|
||||||
"Collaborate with development team",
|
|
||||||
],
|
|
||||||
qualifications: [
|
|
||||||
"Bachelor's degree in Design or related field",
|
|
||||||
"3+ years of UX/UI design experience",
|
|
||||||
"Strong portfolio demonstrating design skills",
|
|
||||||
],
|
|
||||||
isActive: true,
|
|
||||||
employees: [],
|
|
||||||
creationTime: new Date("2024-01-18T08:00:00Z"),
|
|
||||||
lastModificationTime: new Date("2024-01-18T08:00:00Z"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "5",
|
|
||||||
name: "Data Analyst",
|
|
||||||
description: "Analyze business data and provide insights",
|
|
||||||
departmentId: "1",
|
|
||||||
department: mockDepartments.find((dept) => dept.id === "1"),
|
|
||||||
level: JobLevelEnum.Mid,
|
|
||||||
minSalary: 85000,
|
|
||||||
maxSalary: 125000,
|
|
||||||
currency: "USD",
|
|
||||||
requiredSkills: ["SQL", "Python", "Excel", "Tableau", "Statistics"],
|
|
||||||
responsibilities: [
|
|
||||||
"Analyze large datasets",
|
|
||||||
"Create reports and dashboards",
|
|
||||||
"Identify trends and patterns",
|
|
||||||
"Present findings to stakeholders",
|
|
||||||
],
|
|
||||||
qualifications: [
|
|
||||||
"Bachelor's degree in Statistics, Mathematics, or related field",
|
|
||||||
"3+ years of data analysis experience",
|
|
||||||
"Strong analytical and problem-solving skills",
|
|
||||||
],
|
|
||||||
isActive: true,
|
|
||||||
employees: [],
|
|
||||||
creationTime: new Date("2024-01-19T08:00:00Z"),
|
|
||||||
lastModificationTime: new Date("2024-01-19T08:00:00Z"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "6",
|
|
||||||
name: "HR Specialist",
|
|
||||||
description: "Support human resources operations and employee relations",
|
|
||||||
departmentId: "4",
|
|
||||||
department: mockDepartments.find((dept) => dept.id === "4"),
|
|
||||||
level: JobLevelEnum.Mid,
|
|
||||||
minSalary: 60000,
|
|
||||||
maxSalary: 85000,
|
|
||||||
currency: "USD",
|
|
||||||
requiredSkills: [
|
|
||||||
"HR Management",
|
|
||||||
"Recruitment",
|
|
||||||
"Employee Relations",
|
|
||||||
"HRIS",
|
|
||||||
],
|
|
||||||
responsibilities: [
|
|
||||||
"Manage recruitment processes",
|
|
||||||
"Handle employee relations issues",
|
|
||||||
"Maintain HR records and policies",
|
|
||||||
"Support employee onboarding",
|
|
||||||
],
|
|
||||||
qualifications: [
|
|
||||||
"Bachelor's degree in Human Resources or related field",
|
|
||||||
"2+ years of HR experience",
|
|
||||||
"Knowledge of employment laws and regulations",
|
|
||||||
],
|
|
||||||
isActive: true,
|
|
||||||
employees: [],
|
|
||||||
creationTime: new Date("2024-01-20T08:00:00Z"),
|
|
||||||
lastModificationTime: new Date("2024-01-20T08:00:00Z"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "7",
|
|
||||||
name: "Sales Associate",
|
|
||||||
description: "Generate sales leads and maintain customer relationships",
|
|
||||||
departmentId: "2",
|
|
||||||
department: mockDepartments.find((dept) => dept.id === "2"),
|
|
||||||
level: JobLevelEnum.Junior,
|
|
||||||
minSalary: 45000,
|
|
||||||
maxSalary: 70000,
|
|
||||||
currency: "USD",
|
|
||||||
requiredSkills: ["Sales", "CRM", "Communication", "Customer Service"],
|
|
||||||
responsibilities: [
|
|
||||||
"Identify and pursue sales opportunities",
|
|
||||||
"Maintain customer relationships",
|
|
||||||
"Prepare sales proposals",
|
|
||||||
"Meet monthly sales targets",
|
|
||||||
],
|
|
||||||
qualifications: [
|
|
||||||
"Bachelor's degree in Business or related field",
|
|
||||||
"1+ years of sales experience",
|
|
||||||
"Excellent communication skills",
|
|
||||||
],
|
|
||||||
isActive: true,
|
|
||||||
employees: [],
|
|
||||||
creationTime: new Date("2024-01-21T08:00:00Z"),
|
|
||||||
lastModificationTime: new Date("2024-01-21T08:00:00Z"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "8",
|
|
||||||
name: "Accountant",
|
|
||||||
description: "Manage financial records and ensure compliance",
|
|
||||||
departmentId: "3",
|
|
||||||
department: mockDepartments.find((dept) => dept.id === "3"),
|
|
||||||
level: JobLevelEnum.Mid,
|
|
||||||
minSalary: 55000,
|
|
||||||
maxSalary: 80000,
|
|
||||||
currency: "USD",
|
|
||||||
requiredSkills: [
|
|
||||||
"Accounting",
|
|
||||||
"Excel",
|
|
||||||
"Financial Analysis",
|
|
||||||
"Tax Preparation",
|
|
||||||
],
|
|
||||||
responsibilities: [
|
|
||||||
"Maintain financial records",
|
|
||||||
"Prepare financial statements",
|
|
||||||
"Ensure regulatory compliance",
|
|
||||||
"Assist with budget planning",
|
|
||||||
],
|
|
||||||
qualifications: [
|
|
||||||
"Bachelor's degree in Accounting or Finance",
|
|
||||||
"CPA certification preferred",
|
|
||||||
"3+ years of accounting experience",
|
|
||||||
],
|
|
||||||
isActive: true,
|
|
||||||
employees: [],
|
|
||||||
creationTime: new Date("2024-01-22T08:00:00Z"),
|
|
||||||
lastModificationTime: new Date("2024-01-22T08:00:00Z"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "9",
|
|
||||||
name: "Customer Support Representative",
|
|
||||||
description: "Provide excellent customer service and technical support",
|
|
||||||
departmentId: "2",
|
|
||||||
department: mockDepartments.find((dept) => dept.id === "2"),
|
|
||||||
level: JobLevelEnum.Entry,
|
|
||||||
minSalary: 35000,
|
|
||||||
maxSalary: 50000,
|
|
||||||
currency: "USD",
|
|
||||||
requiredSkills: [
|
|
||||||
"Customer Service",
|
|
||||||
"Communication",
|
|
||||||
"Problem Solving",
|
|
||||||
"CRM",
|
|
||||||
],
|
|
||||||
responsibilities: [
|
|
||||||
"Respond to customer inquiries",
|
|
||||||
"Resolve technical issues",
|
|
||||||
"Document customer interactions",
|
|
||||||
"Escalate complex issues when needed",
|
|
||||||
],
|
|
||||||
qualifications: [
|
|
||||||
"High school diploma or equivalent",
|
|
||||||
"1+ years of customer service experience",
|
|
||||||
"Strong communication skills",
|
|
||||||
],
|
|
||||||
isActive: true,
|
|
||||||
employees: [],
|
|
||||||
creationTime: new Date("2024-01-23T08:00:00Z"),
|
|
||||||
lastModificationTime: new Date("2024-01-23T08:00:00Z"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "10",
|
|
||||||
name: "IT Support Specialist",
|
|
||||||
description: "Provide technical support and maintain IT infrastructure",
|
|
||||||
departmentId: "1",
|
|
||||||
department: mockDepartments.find((dept) => dept.id === "1"),
|
|
||||||
level: JobLevelEnum.Junior,
|
|
||||||
minSalary: 50000,
|
|
||||||
maxSalary: 75000,
|
|
||||||
currency: "USD",
|
|
||||||
requiredSkills: [
|
|
||||||
"Windows",
|
|
||||||
"Network Administration",
|
|
||||||
"Hardware",
|
|
||||||
"Troubleshooting",
|
|
||||||
],
|
|
||||||
responsibilities: [
|
|
||||||
"Provide technical support to employees",
|
|
||||||
"Maintain computer systems and networks",
|
|
||||||
"Install and configure software",
|
|
||||||
"Document IT procedures",
|
|
||||||
],
|
|
||||||
qualifications: [
|
|
||||||
"Associate degree in Information Technology or related field",
|
|
||||||
"2+ years of IT support experience",
|
|
||||||
"CompTIA A+ certification preferred",
|
|
||||||
],
|
|
||||||
isActive: true,
|
|
||||||
employees: [],
|
|
||||||
creationTime: new Date("2024-01-24T08:00:00Z"),
|
|
||||||
lastModificationTime: new Date("2024-01-24T08:00:00Z"),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
import { QuestionPoolDto } from "@/types/coordinator";
|
|
||||||
|
|
||||||
// Dynamic data - no hardcoded content
|
|
||||||
export const generateMockPools = (): QuestionPoolDto[] => [
|
|
||||||
{
|
|
||||||
id: "pool-1",
|
|
||||||
name: "Grammar Fundamentals",
|
|
||||||
description: "Essential grammar concepts and structures",
|
|
||||||
questions: [
|
|
||||||
{
|
|
||||||
id: "q1",
|
|
||||||
questionType: "multiple-choice",
|
|
||||||
title: "Verb Tenses",
|
|
||||||
content: "Select the appropriate tense form for the given context.",
|
|
||||||
options: [
|
|
||||||
{ id: "opt1", text: "Option A", isCorrect: false },
|
|
||||||
{ id: "opt2", text: "Option B", isCorrect: true },
|
|
||||||
{ id: "opt3", text: "Option C", isCorrect: false },
|
|
||||||
{ id: "opt4", text: "Option D", isCorrect: false },
|
|
||||||
],
|
|
||||||
correctAnswer: "opt2",
|
|
||||||
points: 10,
|
|
||||||
difficulty: "easy",
|
|
||||||
creationTime: new Date(),
|
|
||||||
lastModificationTime: new Date(),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "q2",
|
|
||||||
questionType: "fill-blank",
|
|
||||||
title: "Articles",
|
|
||||||
content:
|
|
||||||
'Fill in the blank: "I saw _____ elephant at the zoo yesterday."',
|
|
||||||
correctAnswer: "an",
|
|
||||||
points: 15,
|
|
||||||
difficulty: "medium",
|
|
||||||
creationTime: new Date(),
|
|
||||||
lastModificationTime: new Date(),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
tags: ["grammar", "fundamentals"],
|
|
||||||
creationTime: new Date(),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
import { TagItem } from "@/types/coordinator";
|
|
||||||
|
|
||||||
export const generateMockTags = (): TagItem[] => [
|
|
||||||
{
|
|
||||||
id: "tag-1",
|
|
||||||
name: "Grammar",
|
|
||||||
description: "Grammar related questions",
|
|
||||||
color: "#3B82F6",
|
|
||||||
usageCount: 25,
|
|
||||||
creationTime: new Date(),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "tag-2",
|
|
||||||
name: "Vocabulary",
|
|
||||||
description: "Vocabulary building exercises",
|
|
||||||
color: "#10B981",
|
|
||||||
usageCount: 18,
|
|
||||||
creationTime: new Date(),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "tag-3",
|
|
||||||
name: "Reading",
|
|
||||||
description: "Reading comprehension tasks",
|
|
||||||
color: "#F59E0B",
|
|
||||||
usageCount: 12,
|
|
||||||
creationTime: new Date(),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "tag-4",
|
|
||||||
name: "Writing",
|
|
||||||
description: "Writing skill assessments",
|
|
||||||
color: "#EF4444",
|
|
||||||
usageCount: 8,
|
|
||||||
creationTime: new Date(),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
@ -1,48 +0,0 @@
|
||||||
import { Exam } from "@/types/coordinator";
|
|
||||||
|
|
||||||
export const generateMockPDFTest = (): Exam => ({
|
|
||||||
id: "test-1",
|
|
||||||
title: "Reading Assessment",
|
|
||||||
description: "Document-based reading evaluation",
|
|
||||||
type: "test",
|
|
||||||
testDocument: {
|
|
||||||
url: "/sample-documents/reading-test.pdf",
|
|
||||||
type: "pdf",
|
|
||||||
name: "reading-assessment.pdf",
|
|
||||||
},
|
|
||||||
answerKeyTemplate: [
|
|
||||||
{
|
|
||||||
id: "ak1",
|
|
||||||
questionNumber: 1,
|
|
||||||
type: "multiple-choice",
|
|
||||||
options: ["A", "B", "C", "D"],
|
|
||||||
points: 10,
|
|
||||||
correctAnswer: "A",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "ak2",
|
|
||||||
questionNumber: 2,
|
|
||||||
type: "true-false",
|
|
||||||
points: 5,
|
|
||||||
correctAnswer: "true",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "ak3",
|
|
||||||
questionNumber: 3,
|
|
||||||
type: "fill-blank",
|
|
||||||
points: 15,
|
|
||||||
correctAnswer: "answer",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
questions: [],
|
|
||||||
timeLimit: 45,
|
|
||||||
totalPoints: 30,
|
|
||||||
passingScore: 70,
|
|
||||||
allowReview: true,
|
|
||||||
randomizeQuestions: false,
|
|
||||||
showResults: true,
|
|
||||||
maxAttempts: 1,
|
|
||||||
isActive: true,
|
|
||||||
creationTime: new Date(),
|
|
||||||
lastModificationTime: new Date(),
|
|
||||||
});
|
|
||||||
|
|
@ -63,6 +63,7 @@ export interface IdentityUserDto extends ExtensibleFullAuditedEntityDto<string>
|
||||||
userName?: string
|
userName?: string
|
||||||
name?: string
|
name?: string
|
||||||
surname?: string
|
surname?: string
|
||||||
|
fullName?: string
|
||||||
email?: string
|
email?: string
|
||||||
emailConfirmed: boolean
|
emailConfirmed: boolean
|
||||||
phoneNumber?: string
|
phoneNumber?: string
|
||||||
|
|
@ -109,10 +110,12 @@ export class ExtensibleFullAuditedEntityDto<
|
||||||
|
|
||||||
export interface UserInfoViewModel extends ExtensibleObject {
|
export interface UserInfoViewModel extends ExtensibleObject {
|
||||||
id?: string
|
id?: string
|
||||||
|
tenantId?: string
|
||||||
concurrencyStamp?: string
|
concurrencyStamp?: string
|
||||||
userName?: string
|
userName?: string
|
||||||
name?: string
|
name?: string
|
||||||
surname?: string
|
surname?: string
|
||||||
|
fullName?: string
|
||||||
email?: string
|
email?: string
|
||||||
phoneNumber?: string
|
phoneNumber?: string
|
||||||
isActive: boolean
|
isActive: boolean
|
||||||
|
|
@ -139,6 +142,7 @@ export interface UserInfoViewModel extends ExtensibleObject {
|
||||||
lastModificationTime: Date | string
|
lastModificationTime: Date | string
|
||||||
workHour?: string
|
workHour?: string
|
||||||
departmentId?: string
|
departmentId?: string
|
||||||
|
department?: AssignedDepartmentViewModel
|
||||||
jobPositionId?: string
|
jobPositionId?: string
|
||||||
nationality?: string
|
nationality?: string
|
||||||
sskNo?: string
|
sskNo?: string
|
||||||
|
|
|
||||||
137
ui/src/proxy/intranet/models.ts
Normal file
137
ui/src/proxy/intranet/models.ts
Normal file
|
|
@ -0,0 +1,137 @@
|
||||||
|
import { UserInfoViewModel } from "../admin/models"
|
||||||
|
|
||||||
|
export interface IntranetDashboardDto {
|
||||||
|
birthdays: UserInfoViewModel[]
|
||||||
|
documents: DocumentDto[]
|
||||||
|
announcements: AnnouncementDto[]
|
||||||
|
surveys: SurveyDto[]
|
||||||
|
socialPosts: SocialPostDto[]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Doküman (FileItemDto ile uyumlu)
|
||||||
|
export interface DocumentDto {
|
||||||
|
id: string
|
||||||
|
name: string
|
||||||
|
type: string // "file" or "folder"
|
||||||
|
size: number
|
||||||
|
extension: string
|
||||||
|
mimeType: string
|
||||||
|
createdAt: Date
|
||||||
|
modifiedAt: Date
|
||||||
|
path: string
|
||||||
|
parentId: string
|
||||||
|
isReadOnly: boolean
|
||||||
|
childCount: number
|
||||||
|
}
|
||||||
|
|
||||||
|
// Duyuru
|
||||||
|
export interface AnnouncementDto {
|
||||||
|
id: string
|
||||||
|
title: string
|
||||||
|
excerpt: string
|
||||||
|
content: string
|
||||||
|
imageUrl?: string
|
||||||
|
category: string
|
||||||
|
userId: string
|
||||||
|
user: UserInfoViewModel
|
||||||
|
publishDate: Date
|
||||||
|
expiryDate?: Date
|
||||||
|
isPinned: boolean
|
||||||
|
viewCount: number
|
||||||
|
departments?: string[]
|
||||||
|
attachments?: { name: string; url: string; size: string }[]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Anket Cevap
|
||||||
|
export interface SurveyAnswerDto {
|
||||||
|
questionId: string
|
||||||
|
questionType: 'rating' | 'multiple-choice' | 'text' | 'textarea' | 'yes-no'
|
||||||
|
value: string | number | string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Anket Cevabı
|
||||||
|
export interface SurveyResponseDto {
|
||||||
|
id: string
|
||||||
|
surveyId: string
|
||||||
|
respondentId?: string // Anonymous ise null
|
||||||
|
submissionTime: Date
|
||||||
|
answers: SurveyAnswerDto[]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Anket Sorusu Seçeneği
|
||||||
|
export interface SurveyQuestionOptionDto {
|
||||||
|
id: string
|
||||||
|
text: string
|
||||||
|
order: number
|
||||||
|
}
|
||||||
|
|
||||||
|
// Anket Sorusu
|
||||||
|
export interface SurveyQuestionDto {
|
||||||
|
id: string
|
||||||
|
surveyId: string
|
||||||
|
questionText: string
|
||||||
|
type: 'rating' | 'multiple-choice' | 'text' | 'textarea' | 'yes-no'
|
||||||
|
order: number
|
||||||
|
isRequired: boolean
|
||||||
|
options?: SurveyQuestionOptionDto[]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Anket
|
||||||
|
export interface SurveyDto {
|
||||||
|
id: string
|
||||||
|
title: string
|
||||||
|
description: string
|
||||||
|
creatorId: UserInfoViewModel
|
||||||
|
creationTime: Date
|
||||||
|
deadline: Date
|
||||||
|
questions: SurveyQuestionDto[]
|
||||||
|
responses: number
|
||||||
|
targetAudience: string[]
|
||||||
|
status: 'draft' | 'active' | 'closed'
|
||||||
|
isAnonymous: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sosyal Duvar - Comment Interface
|
||||||
|
export interface SocialCommentDto {
|
||||||
|
id: string
|
||||||
|
creator: UserInfoViewModel
|
||||||
|
content: string
|
||||||
|
creationTime: Date
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SocialPollOptionDto {
|
||||||
|
id: string
|
||||||
|
text: string
|
||||||
|
votes: number
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sosyal Duvar - Social Media Interface
|
||||||
|
export interface SocialMediaDto {
|
||||||
|
id?: string
|
||||||
|
type: 'image' | 'video' | 'poll'
|
||||||
|
|
||||||
|
// Ortak alanlar
|
||||||
|
urls?: string[]
|
||||||
|
|
||||||
|
// Anket (poll) ile ilgili alanlar doğrudan burada
|
||||||
|
pollQuestion?: string
|
||||||
|
pollOptions?: SocialPollOptionDto[]
|
||||||
|
pollTotalVotes?: number
|
||||||
|
pollEndsAt?: Date
|
||||||
|
pollUserVoteId?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sosyal Duvar - Ana Interface
|
||||||
|
export interface SocialPostDto {
|
||||||
|
id: string
|
||||||
|
user: UserInfoViewModel
|
||||||
|
content: string
|
||||||
|
locationJson?: string
|
||||||
|
media?: SocialMediaDto
|
||||||
|
likeCount: number
|
||||||
|
isLiked: boolean
|
||||||
|
likeUsers: UserInfoViewModel[]
|
||||||
|
comments: SocialCommentDto[]
|
||||||
|
isOwnPost: boolean
|
||||||
|
creationTime: Date
|
||||||
|
}
|
||||||
69
ui/src/proxy/intranet/utils.tsx
Normal file
69
ui/src/proxy/intranet/utils.tsx
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
import {
|
||||||
|
FaFileAlt,
|
||||||
|
FaFilePdf,
|
||||||
|
FaFileWord,
|
||||||
|
FaFileExcel,
|
||||||
|
FaFilePowerpoint,
|
||||||
|
FaFileImage,
|
||||||
|
FaFileArchive,
|
||||||
|
FaFileCode,
|
||||||
|
} from 'react-icons/fa'
|
||||||
|
|
||||||
|
export const getFileIcon = (extension: string) => {
|
||||||
|
switch (extension.toLowerCase()) {
|
||||||
|
case '.pdf':
|
||||||
|
return <FaFilePdf className="w-4 h-4 text-red-600 dark:text-red-400" />
|
||||||
|
case '.doc':
|
||||||
|
case '.docx':
|
||||||
|
return <FaFileWord className="w-4 h-4 text-blue-600 dark:text-blue-400" />
|
||||||
|
case '.xls':
|
||||||
|
case '.xlsx':
|
||||||
|
return <FaFileExcel className="w-4 h-4 text-green-600 dark:text-green-400" />
|
||||||
|
case '.ppt':
|
||||||
|
case '.pptx':
|
||||||
|
return <FaFilePowerpoint className="w-4 h-4 text-orange-600 dark:text-orange-400" />
|
||||||
|
case '.jpg':
|
||||||
|
case '.jpeg':
|
||||||
|
case '.png':
|
||||||
|
case '.gif':
|
||||||
|
return <FaFileImage className="w-4 h-4 text-purple-600 dark:text-purple-400" />
|
||||||
|
case '.zip':
|
||||||
|
case '.rar':
|
||||||
|
return <FaFileArchive className="w-4 h-4 text-yellow-600 dark:text-yellow-400" />
|
||||||
|
case '.txt':
|
||||||
|
return <FaFileCode className="w-4 h-4 text-gray-600 dark:text-gray-400" />
|
||||||
|
default:
|
||||||
|
return <FaFileAlt className="w-4 h-4 text-gray-600 dark:text-gray-400" />
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getFileType = (extension: string) => {
|
||||||
|
switch (extension.toLowerCase()) {
|
||||||
|
case '.pdf':
|
||||||
|
return '📄 PDF'
|
||||||
|
case '.doc':
|
||||||
|
case '.docx':
|
||||||
|
return '📝 Word'
|
||||||
|
case '.xls':
|
||||||
|
case '.xlsx':
|
||||||
|
return '📊 Excel'
|
||||||
|
case '.ppt':
|
||||||
|
case '.pptx':
|
||||||
|
return '📽️ PowerPoint'
|
||||||
|
case '.jpg':
|
||||||
|
case '.jpeg':
|
||||||
|
return '🖼️ JPEG'
|
||||||
|
case '.png':
|
||||||
|
return '🖼️ PNG'
|
||||||
|
case '.gif':
|
||||||
|
return '🖼️ GIF'
|
||||||
|
case '.zip':
|
||||||
|
return '🗜️ ZIP'
|
||||||
|
case '.rar':
|
||||||
|
return '🗜️ RAR'
|
||||||
|
case '.txt':
|
||||||
|
return '📝 Text'
|
||||||
|
default:
|
||||||
|
return '📄 Dosya'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -81,7 +81,9 @@ export const ROUTES_ENUM = {
|
||||||
pivot: '/admin/pivot/:listFormCode',
|
pivot: '/admin/pivot/:listFormCode',
|
||||||
},
|
},
|
||||||
|
|
||||||
participant: {},
|
sqlManager: '/admin/sql-manager',
|
||||||
|
|
||||||
|
accessDenied: '/admin/access-denied',
|
||||||
|
|
||||||
coordinator: {
|
coordinator: {
|
||||||
classroom: {
|
classroom: {
|
||||||
|
|
@ -237,9 +239,5 @@ export const ROUTES_ENUM = {
|
||||||
bank: '/admin/accounting/bank',
|
bank: '/admin/accounting/bank',
|
||||||
checkNote: '/admin/accounting/check-note',
|
checkNote: '/admin/accounting/check-note',
|
||||||
},
|
},
|
||||||
|
|
||||||
sqlManager: '/admin/sql-manager',
|
|
||||||
|
|
||||||
accessDenied: '/admin/access-denied',
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
17
ui/src/services/intranet.service.ts
Normal file
17
ui/src/services/intranet.service.ts
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
import { IntranetDashboardDto } from '@/proxy/intranet/models'
|
||||||
|
import apiService, { Config } from './api.service'
|
||||||
|
|
||||||
|
export class IntranetService {
|
||||||
|
apiName = 'Default'
|
||||||
|
|
||||||
|
getDashboard = (config?: Partial<Config>) =>
|
||||||
|
apiService.fetchData<IntranetDashboardDto>(
|
||||||
|
{
|
||||||
|
method: 'GET',
|
||||||
|
url: '/api/app/intranet/intranet-dashboard',
|
||||||
|
},
|
||||||
|
{ apiName: this.apiName, ...config },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const intranetService = new IntranetService()
|
||||||
|
|
@ -52,9 +52,10 @@ const interpolate = (text: string, params: Record<string, string | number>) => {
|
||||||
const pattern = new RegExp(`\\{${key}\\}`, 'g')
|
const pattern = new RegExp(`\\{${key}\\}`, 'g')
|
||||||
return acc.replace(pattern, String(value))
|
return acc.replace(pattern, String(value))
|
||||||
} else {
|
} else {
|
||||||
// Named: {{ key }}
|
// Named: {{ key }} or {key}
|
||||||
const pattern = new RegExp(`{{\\s*${key}\\s*}}`, 'g')
|
let result = acc.replace(new RegExp(`{{\\s*${key}\\s*}}`, 'g'), String(value))
|
||||||
return acc.replace(pattern, String(value))
|
result = result.replace(new RegExp(`(?<!{){${key}}(?!})`, 'g'), String(value))
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
}, text)
|
}, text)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ const AccessDenied = () => {
|
||||||
<p className="text-base">{translate('::AccessDeniedMessage')}</p>
|
<p className="text-base">{translate('::AccessDeniedMessage')}</p>
|
||||||
</div>
|
</div>
|
||||||
<Button
|
<Button
|
||||||
size="xs"
|
size="sm"
|
||||||
className="mt-2"
|
className="mt-2"
|
||||||
variant="default"
|
variant="default"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
import { Helmet } from 'react-helmet'
|
import { Helmet } from 'react-helmet'
|
||||||
import { APP_NAME } from '@/constants/app.constant'
|
import { APP_NAME } from '@/constants/app.constant'
|
||||||
|
import IntranetDashboard from './intranet/Dashboard'
|
||||||
|
|
||||||
const Dashboard = () => {
|
const Dashboard = () => {
|
||||||
const { translate } = useLocalization()
|
const { translate } = useLocalization()
|
||||||
|
|
@ -12,6 +13,7 @@ const Dashboard = () => {
|
||||||
title={translate('::' + 'Dashboard')}
|
title={translate('::' + 'Dashboard')}
|
||||||
defaultTitle={APP_NAME}
|
defaultTitle={APP_NAME}
|
||||||
/>
|
/>
|
||||||
|
<IntranetDashboard />
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ function fallbackRender({ error, resetErrorBoundary }: { error: Error; resetErro
|
||||||
<Alert showIcon className="mb-4" type="danger">
|
<Alert showIcon className="mb-4" type="danger">
|
||||||
<h5>{error.name ?? 'Hata!'}</h5>
|
<h5>{error.name ?? 'Hata!'}</h5>
|
||||||
<div>{error.message}</div>
|
<div>{error.message}</div>
|
||||||
<Button size="xs" className="mt-2" variant="default" onClick={resetErrorBoundary}>
|
<Button size="sm" className="mt-2" variant="default" onClick={resetErrorBoundary}>
|
||||||
<FaArrowLeft />
|
<FaArrowLeft />
|
||||||
</Button>
|
</Button>
|
||||||
</Alert>
|
</Alert>
|
||||||
|
|
|
||||||
|
|
@ -746,7 +746,7 @@ const FileManager = () => {
|
||||||
<FaBuilding className="text-gray-500 flex-shrink-0" />
|
<FaBuilding className="text-gray-500 flex-shrink-0" />
|
||||||
{isHostContext ? (
|
{isHostContext ? (
|
||||||
<Select
|
<Select
|
||||||
size="xs"
|
size="sm"
|
||||||
isLoading={tenantsLoading}
|
isLoading={tenantsLoading}
|
||||||
options={[
|
options={[
|
||||||
{ value: '', label: 'Host' },
|
{ value: '', label: 'Host' },
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ const Breadcrumb = forwardRef<HTMLDivElement, BreadcrumbProps>((props, ref) => {
|
||||||
<div key={item.path} className="flex items-center">
|
<div key={item.path} className="flex items-center">
|
||||||
{index > 0 && <FaChevronRight className="mx-2 h-4 w-4 text-gray-400" />}
|
{index > 0 && <FaChevronRight className="mx-2 h-4 w-4 text-gray-400" />}
|
||||||
<Button
|
<Button
|
||||||
size="xs"
|
size="sm"
|
||||||
onClick={() => onNavigate(item)}
|
onClick={() => onNavigate(item)}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'flex items-center px-2 py-1 rounded hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors',
|
'flex items-center px-2 py-1 rounded hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors',
|
||||||
|
|
|
||||||
|
|
@ -316,7 +316,7 @@ const FileUploadModal = forwardRef<HTMLDivElement, FileUploadModalProps>((props,
|
||||||
{(file.status === 'pending' || file.status === 'error') && (
|
{(file.status === 'pending' || file.status === 'error') && (
|
||||||
<Button
|
<Button
|
||||||
variant="plain"
|
variant="plain"
|
||||||
size="xs"
|
size="sm"
|
||||||
icon={<FaTimes />}
|
icon={<FaTimes />}
|
||||||
onClick={() => removeFile(file.id)}
|
onClick={() => removeFile(file.id)}
|
||||||
disabled={uploading}
|
disabled={uploading}
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,7 @@ function ChartTabAnnotations(props: FormEditProps) {
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Add"
|
title="Add"
|
||||||
icon={<FaFileMedical />}
|
icon={<FaFileMedical />}
|
||||||
onClick={async (e) => {
|
onClick={async (e) => {
|
||||||
|
|
@ -118,7 +118,7 @@ function ChartTabAnnotations(props: FormEditProps) {
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Edit"
|
title="Edit"
|
||||||
icon={<FaEdit />}
|
icon={<FaEdit />}
|
||||||
onClick={async (e) => {
|
onClick={async (e) => {
|
||||||
|
|
@ -136,7 +136,7 @@ function ChartTabAnnotations(props: FormEditProps) {
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Delete"
|
title="Delete"
|
||||||
icon={<FaTrash />}
|
icon={<FaTrash />}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ function ChartTabAxis(props: FormEditProps) {
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Add"
|
title="Add"
|
||||||
icon={<FaPlus />}
|
icon={<FaPlus />}
|
||||||
onClick={async (e) => {
|
onClick={async (e) => {
|
||||||
|
|
@ -111,7 +111,7 @@ function ChartTabAxis(props: FormEditProps) {
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Edit"
|
title="Edit"
|
||||||
icon={<FaEdit />}
|
icon={<FaEdit />}
|
||||||
onClick={async (e) => {
|
onClick={async (e) => {
|
||||||
|
|
@ -129,7 +129,7 @@ function ChartTabAxis(props: FormEditProps) {
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Delete"
|
title="Delete"
|
||||||
icon={<FaTrash />}
|
icon={<FaTrash />}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ function ChartTabPanes(props: FormEditProps) {
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Add"
|
title="Add"
|
||||||
icon={<FaFileMedical />}
|
icon={<FaFileMedical />}
|
||||||
onClick={async (e) => {
|
onClick={async (e) => {
|
||||||
|
|
@ -107,7 +107,7 @@ function ChartTabPanes(props: FormEditProps) {
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Edit"
|
title="Edit"
|
||||||
icon={<FaEdit />}
|
icon={<FaEdit />}
|
||||||
onClick={async (e) => {
|
onClick={async (e) => {
|
||||||
|
|
@ -125,7 +125,7 @@ function ChartTabPanes(props: FormEditProps) {
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Delete"
|
title="Delete"
|
||||||
icon={<FaTrash />}
|
icon={<FaTrash />}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
|
|
|
||||||
|
|
@ -139,7 +139,7 @@ function ChartTabSeries(props: FormEditProps & { listFormCode: string }) {
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Add"
|
title="Add"
|
||||||
icon={<FaPlus />}
|
icon={<FaPlus />}
|
||||||
onClick={async (e) => {
|
onClick={async (e) => {
|
||||||
|
|
@ -173,7 +173,7 @@ function ChartTabSeries(props: FormEditProps & { listFormCode: string }) {
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Edit"
|
title="Edit"
|
||||||
icon={<FaEdit />}
|
icon={<FaEdit />}
|
||||||
onClick={async (e) => {
|
onClick={async (e) => {
|
||||||
|
|
@ -191,7 +191,7 @@ function ChartTabSeries(props: FormEditProps & { listFormCode: string }) {
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Delete"
|
title="Delete"
|
||||||
icon={<FaTrash />}
|
icon={<FaTrash />}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ function FormCustomization({
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Add"
|
title="Add"
|
||||||
icon={<FaFileMedical />}
|
icon={<FaFileMedical />}
|
||||||
onClick={async (e) => {
|
onClick={async (e) => {
|
||||||
|
|
@ -89,7 +89,7 @@ function FormCustomization({
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Edit"
|
title="Edit"
|
||||||
icon={<FaEdit />}
|
icon={<FaEdit />}
|
||||||
onClick={async (e) => {
|
onClick={async (e) => {
|
||||||
|
|
@ -104,7 +104,7 @@ function FormCustomization({
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Delete"
|
title="Delete"
|
||||||
icon={<FaTrash />}
|
icon={<FaTrash />}
|
||||||
onClick={async (e) => {
|
onClick={async (e) => {
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ function FormTabCommands() {
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Add"
|
title="Add"
|
||||||
icon={<FaFileMedical />}
|
icon={<FaFileMedical />}
|
||||||
onClick={async (e) => {
|
onClick={async (e) => {
|
||||||
|
|
@ -75,7 +75,7 @@ function FormTabCommands() {
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Edit"
|
title="Edit"
|
||||||
icon={<FaEdit />}
|
icon={<FaEdit />}
|
||||||
onClick={async (e) => {
|
onClick={async (e) => {
|
||||||
|
|
@ -93,7 +93,7 @@ function FormTabCommands() {
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Delete"
|
title="Delete"
|
||||||
icon={<FaTrash />}
|
icon={<FaTrash />}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
|
|
|
||||||
|
|
@ -135,7 +135,7 @@ function FormTabDatabaseDelete({
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Add"
|
title="Add"
|
||||||
icon={<FaFileMedical />}
|
icon={<FaFileMedical />}
|
||||||
onClick={async (e) => {
|
onClick={async (e) => {
|
||||||
|
|
@ -167,7 +167,7 @@ function FormTabDatabaseDelete({
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Edit"
|
title="Edit"
|
||||||
icon={<FaEdit />}
|
icon={<FaEdit />}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|
@ -187,7 +187,7 @@ function FormTabDatabaseDelete({
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Delete"
|
title="Delete"
|
||||||
icon={<FaTrash />}
|
icon={<FaTrash />}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|
|
||||||
|
|
@ -133,7 +133,7 @@ function FormTabDatabaseInsert({
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Add"
|
title="Add"
|
||||||
icon={<FaFileMedical />}
|
icon={<FaFileMedical />}
|
||||||
onClick={async (e) => {
|
onClick={async (e) => {
|
||||||
|
|
@ -165,7 +165,7 @@ function FormTabDatabaseInsert({
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Edit"
|
title="Edit"
|
||||||
icon={<FaEdit />}
|
icon={<FaEdit />}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|
@ -185,7 +185,7 @@ function FormTabDatabaseInsert({
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Delete"
|
title="Delete"
|
||||||
icon={<FaTrash />}
|
icon={<FaTrash />}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|
@ -232,7 +232,7 @@ function FormTabDatabaseInsert({
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Add"
|
title="Add"
|
||||||
icon={<FaFileMedical />}
|
icon={<FaFileMedical />}
|
||||||
onClick={async (e) => {
|
onClick={async (e) => {
|
||||||
|
|
@ -264,7 +264,7 @@ function FormTabDatabaseInsert({
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Edit"
|
title="Edit"
|
||||||
icon={<FaEdit />}
|
icon={<FaEdit />}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|
@ -283,7 +283,7 @@ function FormTabDatabaseInsert({
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Delete"
|
title="Delete"
|
||||||
icon={<FaTrash />}
|
icon={<FaTrash />}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,7 @@ function FormTabDatabaseSelect({
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Add"
|
title="Add"
|
||||||
icon={<FaFileMedical />}
|
icon={<FaFileMedical />}
|
||||||
onClick={async (e) => {
|
onClick={async (e) => {
|
||||||
|
|
@ -120,7 +120,7 @@ function FormTabDatabaseSelect({
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Edit"
|
title="Edit"
|
||||||
icon={<FaEdit />}
|
icon={<FaEdit />}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|
@ -140,7 +140,7 @@ function FormTabDatabaseSelect({
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Delete"
|
title="Delete"
|
||||||
icon={<FaTrash />}
|
icon={<FaTrash />}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|
|
||||||
|
|
@ -135,7 +135,7 @@ function FormTabDatabaseUpdate({
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Add"
|
title="Add"
|
||||||
icon={<FaFileMedical />}
|
icon={<FaFileMedical />}
|
||||||
onClick={async (e) => {
|
onClick={async (e) => {
|
||||||
|
|
@ -167,7 +167,7 @@ function FormTabDatabaseUpdate({
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Edit"
|
title="Edit"
|
||||||
icon={<FaEdit />}
|
icon={<FaEdit />}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|
@ -187,7 +187,7 @@ function FormTabDatabaseUpdate({
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Delete"
|
title="Delete"
|
||||||
icon={<FaTrash />}
|
icon={<FaTrash />}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ function FormTabEditForm(props: { listFormCode: string }) {
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Add"
|
title="Add"
|
||||||
icon={<FaFileMedical />}
|
icon={<FaFileMedical />}
|
||||||
onClick={async (e) => {
|
onClick={async (e) => {
|
||||||
|
|
@ -71,7 +71,7 @@ function FormTabEditForm(props: { listFormCode: string }) {
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Edit"
|
title="Edit"
|
||||||
icon={<FaEdit />}
|
icon={<FaEdit />}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|
@ -89,7 +89,7 @@ function FormTabEditForm(props: { listFormCode: string }) {
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Delete"
|
title="Delete"
|
||||||
icon={<FaTrash />}
|
icon={<FaTrash />}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ function FormTabExtraFilters(props: { listFormCode: string }) {
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Add"
|
title="Add"
|
||||||
icon={<FaFileMedical />}
|
icon={<FaFileMedical />}
|
||||||
onClick={async (e) => {
|
onClick={async (e) => {
|
||||||
|
|
@ -71,7 +71,7 @@ function FormTabExtraFilters(props: { listFormCode: string }) {
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Edit"
|
title="Edit"
|
||||||
icon={<FaEdit />}
|
icon={<FaEdit />}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|
@ -89,7 +89,7 @@ function FormTabExtraFilters(props: { listFormCode: string }) {
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Delete"
|
title="Delete"
|
||||||
icon={<FaTrash />}
|
icon={<FaTrash />}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ function FormTabSubForm() {
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Add"
|
title="Add"
|
||||||
icon={<FaFileMedical />}
|
icon={<FaFileMedical />}
|
||||||
onClick={async (e) => {
|
onClick={async (e) => {
|
||||||
|
|
@ -71,7 +71,7 @@ function FormTabSubForm() {
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Edit"
|
title="Edit"
|
||||||
icon={<FaEdit />}
|
icon={<FaEdit />}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|
@ -89,7 +89,7 @@ function FormTabSubForm() {
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Delete"
|
title="Delete"
|
||||||
icon={<FaTrash />}
|
icon={<FaTrash />}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ function FormTabWidgets(props: { listFormCode: string }) {
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Add"
|
title="Add"
|
||||||
icon={<FaFileMedical />}
|
icon={<FaFileMedical />}
|
||||||
onClick={async (e) => {
|
onClick={async (e) => {
|
||||||
|
|
@ -71,7 +71,7 @@ function FormTabWidgets(props: { listFormCode: string }) {
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Edit"
|
title="Edit"
|
||||||
icon={<FaEdit />}
|
icon={<FaEdit />}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|
@ -89,7 +89,7 @@ function FormTabWidgets(props: { listFormCode: string }) {
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Delete"
|
title="Delete"
|
||||||
icon={<FaTrash />}
|
icon={<FaTrash />}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,7 @@ function FormFieldTabConditionalFormatting({
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Add"
|
title="Add"
|
||||||
icon={<FaPlusSquare />}
|
icon={<FaPlusSquare />}
|
||||||
onClick={() => setItemIndex(-1)}
|
onClick={() => setItemIndex(-1)}
|
||||||
|
|
@ -109,7 +109,7 @@ function FormFieldTabConditionalFormatting({
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Edit"
|
title="Edit"
|
||||||
icon={<FaEdit />}
|
icon={<FaEdit />}
|
||||||
onClick={async (e) => {
|
onClick={async (e) => {
|
||||||
|
|
@ -121,7 +121,7 @@ function FormFieldTabConditionalFormatting({
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Delete"
|
title="Delete"
|
||||||
icon={<FaTrashAlt />}
|
icon={<FaTrashAlt />}
|
||||||
onClick={async (e) => {
|
onClick={async (e) => {
|
||||||
|
|
|
||||||
|
|
@ -101,7 +101,7 @@ function FormFieldTabValidationRules({
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Add"
|
title="Add"
|
||||||
icon={<FaPlusSquare />}
|
icon={<FaPlusSquare />}
|
||||||
onClick={() => setItemIndex(-1)}
|
onClick={() => setItemIndex(-1)}
|
||||||
|
|
@ -125,7 +125,7 @@ function FormFieldTabValidationRules({
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Edit"
|
title="Edit"
|
||||||
icon={<FaEdit />}
|
icon={<FaEdit />}
|
||||||
onClick={async (e) => {
|
onClick={async (e) => {
|
||||||
|
|
@ -137,7 +137,7 @@ function FormFieldTabValidationRules({
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Delete"
|
title="Delete"
|
||||||
icon={<FaTrashAlt />}
|
icon={<FaTrashAlt />}
|
||||||
onClick={async (e) => {
|
onClick={async (e) => {
|
||||||
|
|
|
||||||
|
|
@ -404,7 +404,7 @@ function FormFields({
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Add"
|
title="Add"
|
||||||
icon={<FaFileMedical />}
|
icon={<FaFileMedical />}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|
@ -416,7 +416,7 @@ function FormFields({
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Copy"
|
title="Copy"
|
||||||
icon={<FaCopy />}
|
icon={<FaCopy />}
|
||||||
onClick={async (e) => {
|
onClick={async (e) => {
|
||||||
|
|
@ -429,7 +429,7 @@ function FormFields({
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Tüm Sütunları Ekle"
|
title="Tüm Sütunları Ekle"
|
||||||
icon={<FaTable />}
|
icon={<FaTable />}
|
||||||
loading={isAddingAllColumns}
|
loading={isAddingAllColumns}
|
||||||
|
|
@ -461,7 +461,7 @@ function FormFields({
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Delete"
|
title="Delete"
|
||||||
icon={<FaMinus />}
|
icon={<FaMinus />}
|
||||||
onClick={async (e) => {
|
onClick={async (e) => {
|
||||||
|
|
|
||||||
|
|
@ -420,7 +420,7 @@ function JsonRowOpDialogAxis({
|
||||||
shape="circle"
|
shape="circle"
|
||||||
type="button"
|
type="button"
|
||||||
className="mt-7"
|
className="mt-7"
|
||||||
size="xs"
|
size="sm"
|
||||||
icon={<FaMinus />}
|
icon={<FaMinus />}
|
||||||
onClick={() => remove(index)}
|
onClick={() => remove(index)}
|
||||||
/>
|
/>
|
||||||
|
|
@ -430,7 +430,7 @@ function JsonRowOpDialogAxis({
|
||||||
: null}
|
: null}
|
||||||
<div>
|
<div>
|
||||||
<Button
|
<Button
|
||||||
size="xs"
|
size="sm"
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
push({
|
push({
|
||||||
|
|
|
||||||
|
|
@ -430,7 +430,7 @@ function JsonRowOpDialogEditForm({
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="solid"
|
variant="solid"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Options"
|
title="Options"
|
||||||
icon={<FaTag />}
|
icon={<FaTag />}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
|
|
@ -584,7 +584,7 @@ function JsonRowOpDialogEditForm({
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="solid"
|
variant="solid"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Options"
|
title="Options"
|
||||||
icon={<FaTag />}
|
icon={<FaTag />}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
|
|
@ -769,7 +769,7 @@ function JsonRowOpDialogEditForm({
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Add"
|
title="Add"
|
||||||
icon={<FaCalendarMinus />}
|
icon={<FaCalendarMinus />}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|
@ -780,7 +780,7 @@ function JsonRowOpDialogEditForm({
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Add"
|
title="Add"
|
||||||
icon={<FaCalendarPlus />}
|
icon={<FaCalendarPlus />}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|
@ -795,7 +795,7 @@ function JsonRowOpDialogEditForm({
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Add"
|
title="Add"
|
||||||
icon={<FaCalendarPlus />}
|
icon={<FaCalendarPlus />}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|
|
||||||
|
|
@ -250,7 +250,7 @@ function JsonRowOpDialogSubForm({
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Add"
|
title="Add"
|
||||||
icon={<FaCalendarMinus />}
|
icon={<FaCalendarMinus />}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|
@ -261,7 +261,7 @@ function JsonRowOpDialogSubForm({
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Add"
|
title="Add"
|
||||||
icon={<FaCalendarPlus />}
|
icon={<FaCalendarPlus />}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|
@ -276,7 +276,7 @@ function JsonRowOpDialogSubForm({
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Add"
|
title="Add"
|
||||||
icon={<FaCalendarPlus />}
|
icon={<FaCalendarPlus />}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|
|
||||||
|
|
@ -122,7 +122,7 @@ const WizardFileManager = () => {
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<FaSearch className="absolute left-2 top-1/2 -translate-y-1/2 text-gray-400 text-xs pointer-events-none" />
|
<FaSearch className="absolute left-2 top-1/2 -translate-y-1/2 text-gray-400 text-xs pointer-events-none" />
|
||||||
<Input
|
<Input
|
||||||
size="xs"
|
size="sm"
|
||||||
className="pl-6 w-44"
|
className="pl-6 w-44"
|
||||||
placeholder={translate('::App.Platform.Search') || 'Search...'}
|
placeholder={translate('::App.Platform.Search') || 'Search...'}
|
||||||
value={search}
|
value={search}
|
||||||
|
|
@ -130,7 +130,7 @@ const WizardFileManager = () => {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Button
|
<Button
|
||||||
size="xs"
|
size="sm"
|
||||||
variant="default"
|
variant="default"
|
||||||
title={translate('::App.Platform.Refresh') || 'Yenile'}
|
title={translate('::App.Platform.Refresh') || 'Yenile'}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
|
|
@ -139,7 +139,7 @@ const WizardFileManager = () => {
|
||||||
<FaSync />
|
<FaSync />
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
size="xs"
|
size="sm"
|
||||||
variant="default"
|
variant="default"
|
||||||
icon={<FcAcceptDatabase />}
|
icon={<FcAcceptDatabase />}
|
||||||
onClick={() => setShowDbMigrateDialog(true)}
|
onClick={() => setShowDbMigrateDialog(true)}
|
||||||
|
|
@ -148,7 +148,7 @@ const WizardFileManager = () => {
|
||||||
{translate('::ListForms.ListForm.DbMigrate') || 'DB Migrate'}
|
{translate('::ListForms.ListForm.DbMigrate') || 'DB Migrate'}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
size="xs"
|
size="sm"
|
||||||
variant="solid"
|
variant="solid"
|
||||||
onClick={() => navigate(ROUTES_ENUM.protected.saas.listFormManagement.wizard)}
|
onClick={() => navigate(ROUTES_ENUM.protected.saas.listFormManagement.wizard)}
|
||||||
className="flex items-center"
|
className="flex items-center"
|
||||||
|
|
|
||||||
|
|
@ -471,7 +471,7 @@ const OrganizationUnits = () => {
|
||||||
<div className="flex gap-1">
|
<div className="flex gap-1">
|
||||||
<Button
|
<Button
|
||||||
variant="solid"
|
variant="solid"
|
||||||
size="xs"
|
size="sm"
|
||||||
title={translate('::Abp.Identity.OrganizationUnit.AddUnit')}
|
title={translate('::Abp.Identity.OrganizationUnit.AddUnit')}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|
@ -486,7 +486,7 @@ const OrganizationUnits = () => {
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
variant="solid"
|
variant="solid"
|
||||||
size="xs"
|
size="sm"
|
||||||
title={translate('::Abp.Identity.OrganizationUnit.MoveAllUsers')}
|
title={translate('::Abp.Identity.OrganizationUnit.MoveAllUsers')}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|
@ -576,7 +576,7 @@ const OrganizationUnits = () => {
|
||||||
<Button
|
<Button
|
||||||
className="mr-auto"
|
className="mr-auto"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setDeleteRow({
|
setDeleteRow({
|
||||||
id: user.id ?? '',
|
id: user.id ?? '',
|
||||||
|
|
@ -647,7 +647,7 @@ const OrganizationUnits = () => {
|
||||||
<Button
|
<Button
|
||||||
className="mr-auto"
|
className="mr-auto"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setDeleteRow({
|
setDeleteRow({
|
||||||
id: role.id ?? '',
|
id: role.id ?? '',
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,7 @@ const NotificationSettings = () => {
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Reset"
|
title="Reset"
|
||||||
icon={<FaHistory />}
|
icon={<FaHistory />}
|
||||||
onClick={async (e) => {
|
onClick={async (e) => {
|
||||||
|
|
|
||||||
|
|
@ -232,7 +232,7 @@ function UserDetails() {
|
||||||
component={Input}
|
component={Input}
|
||||||
/>
|
/>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
<FormItem size="xs" label={translate('::RocketUsername')}>
|
<FormItem size="sm" label={translate('::RocketUsername')}>
|
||||||
<Field
|
<Field
|
||||||
type="text"
|
type="text"
|
||||||
name="rocketUsername"
|
name="rocketUsername"
|
||||||
|
|
@ -1340,7 +1340,7 @@ function UserDetails() {
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Add"
|
title="Add"
|
||||||
icon={<FaFileAlt />}
|
icon={<FaFileAlt />}
|
||||||
onClick={async (e) => {
|
onClick={async (e) => {
|
||||||
|
|
@ -1362,7 +1362,7 @@ function UserDetails() {
|
||||||
shape="circle"
|
shape="circle"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
title="Delete"
|
title="Delete"
|
||||||
icon={<FaTrashAlt />}
|
icon={<FaTrashAlt />}
|
||||||
onClick={() => setConfirmDeleteClaim(claim)}
|
onClick={() => setConfirmDeleteClaim(claim)}
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ function BranchSeed({
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Button size="xs" variant="solid" onClick={handleRunSeed} loading={isLoading}>
|
<Button size="sm" variant="solid" onClick={handleRunSeed} loading={isLoading}>
|
||||||
{isLoading ? 'Seed Çalıştırılıyor...' : 'Seed İşlemini Başlat'}
|
{isLoading ? 'Seed Çalıştırılıyor...' : 'Seed İşlemini Başlat'}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -908,17 +908,16 @@ GO`,
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
<Button
|
<Button
|
||||||
size="xs"
|
size="sm"
|
||||||
variant="default"
|
variant="default"
|
||||||
icon={<FcAcceptDatabase />}
|
icon={<FcAcceptDatabase />}
|
||||||
onClick={() => setShowDbMigrateConfirmDialog(true)}
|
onClick={() => setShowDbMigrateConfirmDialog(true)}
|
||||||
className="shadow-sm px-2 py-1"
|
|
||||||
title={translate('::App.DbMigrate.StartMessage') || 'Run DB Migration'}
|
title={translate('::App.DbMigrate.StartMessage') || 'Run DB Migration'}
|
||||||
>
|
>
|
||||||
{translate('::ListForms.ListForm.DbMigrate') || 'DB Migrate'}
|
{translate('::ListForms.ListForm.DbMigrate') || 'DB Migrate'}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
size="xs"
|
size="sm"
|
||||||
variant="default"
|
variant="default"
|
||||||
icon={<FaFolderOpen />}
|
icon={<FaFolderOpen />}
|
||||||
onClick={handleOpenSqlDataFilesDialog}
|
onClick={handleOpenSqlDataFilesDialog}
|
||||||
|
|
@ -931,7 +930,7 @@ GO`,
|
||||||
|
|
||||||
<div className="flex flex-wrap items-center gap-2 sm:gap-3">
|
<div className="flex flex-wrap items-center gap-2 sm:gap-3">
|
||||||
<Button
|
<Button
|
||||||
size="xs"
|
size="sm"
|
||||||
variant="default"
|
variant="default"
|
||||||
icon={<FaCopy />}
|
icon={<FaCopy />}
|
||||||
onClick={handleOpenCopyDialog}
|
onClick={handleOpenCopyDialog}
|
||||||
|
|
@ -945,7 +944,7 @@ GO`,
|
||||||
{translate('::App.Platform.CopySelectedObjects') || 'Copy Selected Objects'}
|
{translate('::App.Platform.CopySelectedObjects') || 'Copy Selected Objects'}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
size="xs"
|
size="sm"
|
||||||
variant="default"
|
variant="default"
|
||||||
icon={<FaFileAlt />}
|
icon={<FaFileAlt />}
|
||||||
onClick={handleNewQuery}
|
onClick={handleNewQuery}
|
||||||
|
|
@ -954,7 +953,7 @@ GO`,
|
||||||
{translate('::App.Platform.NewQuery') || 'New Query'}
|
{translate('::App.Platform.NewQuery') || 'New Query'}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
size="xs"
|
size="sm"
|
||||||
variant="solid"
|
variant="solid"
|
||||||
color="blue-600"
|
color="blue-600"
|
||||||
icon={<FaPlay />}
|
icon={<FaPlay />}
|
||||||
|
|
|
||||||
|
|
@ -1646,14 +1646,14 @@ const SqlTableDesignerDialog = ({
|
||||||
<>
|
<>
|
||||||
<div className="flex items-center justify-between py-2">
|
<div className="flex items-center justify-between py-2">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Button size="xs" variant="solid" color="blue-600" onClick={addFullAuditedColumns}>
|
<Button size="sm" variant="solid" color="blue-600" onClick={addFullAuditedColumns}>
|
||||||
{translate('::App.SqlQueryManager.AddFullAuditedColumns')}
|
{translate('::App.SqlQueryManager.AddFullAuditedColumns')}
|
||||||
</Button>
|
</Button>
|
||||||
<Button size="xs" variant="solid" color="green-600" onClick={addMultiTenantColumns}>
|
<Button size="sm" variant="solid" color="green-600" onClick={addMultiTenantColumns}>
|
||||||
{translate('::App.SqlQueryManager.AddMultiTenantColumns')}
|
{translate('::App.SqlQueryManager.AddMultiTenantColumns')}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
size="xs"
|
size="sm"
|
||||||
variant="solid"
|
variant="solid"
|
||||||
color="amber-600"
|
color="amber-600"
|
||||||
onClick={importColumnsFromRememberedCreateTable}
|
onClick={importColumnsFromRememberedCreateTable}
|
||||||
|
|
@ -1664,7 +1664,7 @@ const SqlTableDesignerDialog = ({
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Button
|
<Button
|
||||||
size="xs"
|
size="sm"
|
||||||
variant="solid"
|
variant="solid"
|
||||||
color="red-600"
|
color="red-600"
|
||||||
icon={<FaTrash />}
|
icon={<FaTrash />}
|
||||||
|
|
@ -1673,7 +1673,7 @@ const SqlTableDesignerDialog = ({
|
||||||
{translate('::App.SqlQueryManager.ClearAllColumns')}
|
{translate('::App.SqlQueryManager.ClearAllColumns')}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
size="xs"
|
size="sm"
|
||||||
variant="solid"
|
variant="solid"
|
||||||
color="blue-600"
|
color="blue-600"
|
||||||
icon={<FaPlus />}
|
icon={<FaPlus />}
|
||||||
|
|
|
||||||
|
|
@ -141,7 +141,7 @@ const FormButtons = (props: {
|
||||||
<Button
|
<Button
|
||||||
key={'toolbarButton-' + i}
|
key={'toolbarButton-' + i}
|
||||||
variant="default"
|
variant="default"
|
||||||
size="xs"
|
size="sm"
|
||||||
icon={hasValidIcon ? <IconComp className="text-gray-400" /> : null}
|
icon={hasValidIcon ? <IconComp className="text-gray-400" /> : null}
|
||||||
onClick={item.options?.onClick}
|
onClick={item.options?.onClick}
|
||||||
>
|
>
|
||||||
|
|
@ -161,7 +161,7 @@ const FormButtons = (props: {
|
||||||
<Button
|
<Button
|
||||||
key={'commandColumnButton-' + i}
|
key={'commandColumnButton-' + i}
|
||||||
variant="default"
|
variant="default"
|
||||||
size="xs"
|
size="sm"
|
||||||
title={item.hint}
|
title={item.hint}
|
||||||
onClick={(e: any) => {
|
onClick={(e: any) => {
|
||||||
if (item.onClick) {
|
if (item.onClick) {
|
||||||
|
|
@ -180,7 +180,7 @@ const FormButtons = (props: {
|
||||||
|
|
||||||
{!isSubForm && (
|
{!isSubForm && (
|
||||||
<Button
|
<Button
|
||||||
size="xs"
|
size="sm"
|
||||||
variant="default"
|
variant="default"
|
||||||
className="dx-button dx-button-mode-contained dx-button-normal"
|
className="dx-button dx-button-mode-contained dx-button-normal"
|
||||||
icon={<FaChevronLeft />}
|
icon={<FaChevronLeft />}
|
||||||
|
|
@ -197,7 +197,7 @@ const FormButtons = (props: {
|
||||||
)}
|
)}
|
||||||
{mode != 'new' && (
|
{mode != 'new' && (
|
||||||
<Button
|
<Button
|
||||||
size="xs"
|
size="sm"
|
||||||
variant="default"
|
variant="default"
|
||||||
className="dx-button dx-button-mode-contained dx-button-normal"
|
className="dx-button dx-button-mode-contained dx-button-normal"
|
||||||
icon={<FaTrashAlt />}
|
icon={<FaTrashAlt />}
|
||||||
|
|
@ -211,7 +211,7 @@ const FormButtons = (props: {
|
||||||
)}
|
)}
|
||||||
{mode != 'new' && (
|
{mode != 'new' && (
|
||||||
<Button
|
<Button
|
||||||
size="xs"
|
size="sm"
|
||||||
variant="default"
|
variant="default"
|
||||||
className="dx-button dx-button-mode-contained dx-button-normal"
|
className="dx-button dx-button-mode-contained dx-button-normal"
|
||||||
icon={<FaPlusCircle />}
|
icon={<FaPlusCircle />}
|
||||||
|
|
@ -228,7 +228,7 @@ const FormButtons = (props: {
|
||||||
)}
|
)}
|
||||||
{mode == 'view' && (
|
{mode == 'view' && (
|
||||||
<Button
|
<Button
|
||||||
size="xs"
|
size="sm"
|
||||||
variant="default"
|
variant="default"
|
||||||
className="dx-button dx-button-mode-contained dx-button-normal"
|
className="dx-button dx-button-mode-contained dx-button-normal"
|
||||||
icon={<FaPencilAlt />}
|
icon={<FaPencilAlt />}
|
||||||
|
|
@ -249,7 +249,7 @@ const FormButtons = (props: {
|
||||||
)}
|
)}
|
||||||
{(mode == 'edit' || (onActionView && mode == 'new')) && (
|
{(mode == 'edit' || (onActionView && mode == 'new')) && (
|
||||||
<Button
|
<Button
|
||||||
size="xs"
|
size="sm"
|
||||||
variant="default"
|
variant="default"
|
||||||
className="dx-button dx-button-mode-contained dx-button-normal"
|
className="dx-button dx-button-mode-contained dx-button-normal"
|
||||||
icon={<FaEye />}
|
icon={<FaEye />}
|
||||||
|
|
@ -270,7 +270,7 @@ const FormButtons = (props: {
|
||||||
)}
|
)}
|
||||||
{(mode == 'edit' || mode == 'new') && (
|
{(mode == 'edit' || mode == 'new') && (
|
||||||
<Button
|
<Button
|
||||||
size="xs"
|
size="sm"
|
||||||
variant="default"
|
variant="default"
|
||||||
className="dx-button dx-button-mode-contained dx-button-normal"
|
className="dx-button dx-button-mode-contained dx-button-normal"
|
||||||
icon={<FaSave />}
|
icon={<FaSave />}
|
||||||
|
|
@ -281,7 +281,7 @@ const FormButtons = (props: {
|
||||||
)}
|
)}
|
||||||
{checkPermission(gridDto?.gridOptions.permissionDto.c) && !isSubForm && (
|
{checkPermission(gridDto?.gridOptions.permissionDto.c) && !isSubForm && (
|
||||||
<Button
|
<Button
|
||||||
size="xs"
|
size="sm"
|
||||||
variant="default"
|
variant="default"
|
||||||
className="dx-button dx-button-mode-contained dx-button-normal"
|
className="dx-button dx-button-mode-contained dx-button-normal"
|
||||||
icon={<FaCog />}
|
icon={<FaCog />}
|
||||||
|
|
|
||||||
|
|
@ -345,7 +345,7 @@ export const NoteList: React.FC<NoteListProps> = ({
|
||||||
<div className="flex items-center justify-end mb-2">
|
<div className="flex items-center justify-end mb-2">
|
||||||
<Button
|
<Button
|
||||||
variant="solid"
|
variant="solid"
|
||||||
size="xs"
|
size="sm"
|
||||||
type="button"
|
type="button"
|
||||||
onClick={onAddNote}
|
onClick={onAddNote}
|
||||||
disabled={!onAddNote}
|
disabled={!onAddNote}
|
||||||
|
|
@ -400,7 +400,7 @@ export const NoteList: React.FC<NoteListProps> = ({
|
||||||
{user?.id === note.creatorId && (
|
{user?.id === note.creatorId && (
|
||||||
<Button
|
<Button
|
||||||
variant="plain"
|
variant="plain"
|
||||||
size="xs"
|
size="sm"
|
||||||
onClick={() => onDeleteNote?.(note.id as string)}
|
onClick={() => onDeleteNote?.(note.id as string)}
|
||||||
title={translate('::Delete')}
|
title={translate('::Delete')}
|
||||||
className="text-red-400 hover:text-red-600"
|
className="text-red-400 hover:text-red-600"
|
||||||
|
|
@ -430,7 +430,7 @@ export const NoteList: React.FC<NoteListProps> = ({
|
||||||
<span className="truncate max-w-[150px]">{file.FileName}</span>
|
<span className="truncate max-w-[150px]">{file.FileName}</span>
|
||||||
<Button
|
<Button
|
||||||
variant="plain"
|
variant="plain"
|
||||||
size="xs"
|
size="sm"
|
||||||
onClick={() => onDownloadFile?.(file)}
|
onClick={() => onDownloadFile?.(file)}
|
||||||
title={translate('::Download')}
|
title={translate('::Download')}
|
||||||
className="text-blue-500 hover:text-blue-700 ml-1"
|
className="text-blue-500 hover:text-blue-700 ml-1"
|
||||||
|
|
@ -452,7 +452,7 @@ export const NoteList: React.FC<NoteListProps> = ({
|
||||||
<TabContent value="audit">
|
<TabContent value="audit">
|
||||||
<div className="flex items-center justify-end mb-2">
|
<div className="flex items-center justify-end mb-2">
|
||||||
<Button
|
<Button
|
||||||
size="xs"
|
size="sm"
|
||||||
variant="default"
|
variant="default"
|
||||||
type="button"
|
type="button"
|
||||||
onClick={loadAuditLogs}
|
onClick={loadAuditLogs}
|
||||||
|
|
|
||||||
|
|
@ -245,7 +245,7 @@ export const NoteModal: React.FC<NoteModalProps> = ({
|
||||||
</div>
|
</div>
|
||||||
<Button
|
<Button
|
||||||
variant="plain"
|
variant="plain"
|
||||||
size="xs"
|
size="sm"
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => removeFile(index)}
|
onClick={() => removeFile(index)}
|
||||||
className="text-red-500 hover:text-red-700"
|
className="text-red-500 hover:text-red-700"
|
||||||
|
|
|
||||||
|
|
@ -164,7 +164,7 @@ export const NotePanel: React.FC<NotePanelProps> = ({
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<Button variant="plain" size="xs" onClick={onToggle} title="Paneli kapat">
|
<Button variant="plain" size="sm" onClick={onToggle} title="Paneli kapat">
|
||||||
<FaTimes />
|
<FaTimes />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
625
ui/src/views/intranet/Dashboard.tsx
Normal file
625
ui/src/views/intranet/Dashboard.tsx
Normal file
|
|
@ -0,0 +1,625 @@
|
||||||
|
import React, { useState, useEffect } from 'react'
|
||||||
|
import { AnimatePresence } from 'framer-motion'
|
||||||
|
import dayjs from 'dayjs'
|
||||||
|
import relativeTime from 'dayjs/plugin/relativeTime'
|
||||||
|
import isBetween from 'dayjs/plugin/isBetween'
|
||||||
|
import localizedFormat from 'dayjs/plugin/localizedFormat'
|
||||||
|
|
||||||
|
// Widgets
|
||||||
|
import TodayBirthdays from './widgets/TodayBirthdays'
|
||||||
|
import RecentDocuments from './widgets/RecentDocuments'
|
||||||
|
import Surveys from './widgets/Surveys'
|
||||||
|
|
||||||
|
// Modals
|
||||||
|
import SurveyModal from './widgets/SurveyModal'
|
||||||
|
import AnnouncementModal from './widgets/AnnouncementModal'
|
||||||
|
|
||||||
|
// Social Wall
|
||||||
|
import SocialWall from './SocialWall'
|
||||||
|
import { Container } from '@/components/shared'
|
||||||
|
import { usePermission } from '@/utils/hooks/usePermission'
|
||||||
|
import {
|
||||||
|
AnnouncementDto,
|
||||||
|
IntranetDashboardDto,
|
||||||
|
SurveyAnswerDto,
|
||||||
|
SurveyDto,
|
||||||
|
} from '@/proxy/intranet/models'
|
||||||
|
import { intranetService } from '@/services/intranet.service'
|
||||||
|
import Announcements from './widgets/Announcements'
|
||||||
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
|
import useLocale from '@/utils/hooks/useLocale'
|
||||||
|
import { currentLocalDate } from '@/utils/dateUtils'
|
||||||
|
import { useStoreState } from '@/store/store'
|
||||||
|
|
||||||
|
dayjs.extend(relativeTime)
|
||||||
|
dayjs.extend(isBetween)
|
||||||
|
dayjs.extend(localizedFormat)
|
||||||
|
|
||||||
|
const WIDGET_ORDER_KEY = 'dashboard-widget-order'
|
||||||
|
|
||||||
|
const IntranetDashboard: React.FC = () => {
|
||||||
|
const { checkPermission } = usePermission()
|
||||||
|
const [selectedAnnouncement, setSelectedAnnouncement] = useState<AnnouncementDto | null>(null)
|
||||||
|
const [selectedSurvey, setSelectedSurvey] = useState<SurveyDto | null>(null)
|
||||||
|
const [showSurveyModal, setShowSurveyModal] = useState(false)
|
||||||
|
const [isDesignMode, setIsDesignMode] = useState(false)
|
||||||
|
const [widgetOrder, setWidgetOrder] = useState<Record<string, string[]>>({
|
||||||
|
left: [],
|
||||||
|
center: [],
|
||||||
|
right: [],
|
||||||
|
})
|
||||||
|
|
||||||
|
const [intranetDashboard, setIntranetDashboard] = useState<IntranetDashboardDto>()
|
||||||
|
const { translate } = useLocalization()
|
||||||
|
const currentLocale = useLocale()
|
||||||
|
|
||||||
|
const fetchIntranetDashboard = async () => {
|
||||||
|
const dashboard = await intranetService.getDashboard()
|
||||||
|
if (dashboard.data) {
|
||||||
|
setIntranetDashboard(dashboard.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchIntranetDashboard()
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
// Drag state'leri birleştirildi
|
||||||
|
const [dragState, setDragState] = useState<{
|
||||||
|
draggedId: string | null
|
||||||
|
targetColumn: string | null
|
||||||
|
targetIndex: number | null
|
||||||
|
}>({
|
||||||
|
draggedId: null,
|
||||||
|
targetColumn: null,
|
||||||
|
targetIndex: null,
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleTakeSurvey = (survey: SurveyDto) => {
|
||||||
|
setSelectedSurvey(survey)
|
||||||
|
setShowSurveyModal(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSubmitSurvey = (answers: SurveyAnswerDto[]) => {
|
||||||
|
setShowSurveyModal(false)
|
||||||
|
setSelectedSurvey(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Widget metadata (component'lar yerine sadece meta bilgiler)
|
||||||
|
const widgetMetadata = [
|
||||||
|
{ id: 'today-birthdays', permission: 'AbpIdentity.Users.Widget', column: 'left' },
|
||||||
|
{ id: 'documents', permission: 'App.Files.Widget', column: 'left' },
|
||||||
|
{ id: 'active-surveys', permission: 'App.Intranet.Survey.Widget', column: 'left' },
|
||||||
|
{ id: 'social-wall', permission: 'App.Intranet.SocialPost.Widget', column: 'center' },
|
||||||
|
{
|
||||||
|
id: 'announcements',
|
||||||
|
permission: 'App.Intranet.Announcement.Widget',
|
||||||
|
column: 'right',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
// If permissions arrive after mount, initialize default order when needed
|
||||||
|
const grantedPolicies = useStoreState((state) => state.abpConfig?.config?.auth.grantedPolicies)
|
||||||
|
|
||||||
|
const initializeDefaultOrder = () => {
|
||||||
|
const defaultOrder = {
|
||||||
|
left: widgetMetadata
|
||||||
|
.filter((w) => w.column === 'left' && checkPermission(w.permission))
|
||||||
|
.map((w) => w.id),
|
||||||
|
center: widgetMetadata
|
||||||
|
.filter((w) => w.column === 'center' && checkPermission(w.permission))
|
||||||
|
.map((w) => w.id),
|
||||||
|
right: widgetMetadata
|
||||||
|
.filter((w) => w.column === 'right' && checkPermission(w.permission))
|
||||||
|
.map((w) => w.id),
|
||||||
|
}
|
||||||
|
setWidgetOrder(defaultOrder)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Widget sıralamasını yükle — grantedPolicies gelince çalış ki checkPermission doğru çalışsın
|
||||||
|
useEffect(() => {
|
||||||
|
if (!grantedPolicies) return
|
||||||
|
|
||||||
|
const savedOrder = localStorage.getItem(WIDGET_ORDER_KEY)
|
||||||
|
if (savedOrder) {
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(savedOrder) as Record<string, unknown[]>
|
||||||
|
const order: Record<string, string[]> = {
|
||||||
|
left: [...new Set((parsed.left || []) as string[])],
|
||||||
|
center: [...new Set((parsed.center || []) as string[])],
|
||||||
|
right: [...new Set((parsed.right || []) as string[])],
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kaydedilmiş düzende olmayan ama izni olan widgetları varsayılan kolonuna ekle
|
||||||
|
const allAssigned = new Set([...order.left, ...order.center, ...order.right])
|
||||||
|
widgetMetadata.forEach((w) => {
|
||||||
|
if (!allAssigned.has(w.id) && checkPermission(w.permission)) {
|
||||||
|
order[w.column as keyof typeof order].push(w.id)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
setWidgetOrder(order)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Widget order parse error:', error)
|
||||||
|
initializeDefaultOrder()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
initializeDefaultOrder()
|
||||||
|
}
|
||||||
|
}, [grantedPolicies])
|
||||||
|
|
||||||
|
// Widget sıralamasını kaydet
|
||||||
|
const saveWidgetOrder = (newOrder: Record<string, string[]>) => {
|
||||||
|
setWidgetOrder(newOrder)
|
||||||
|
localStorage.setItem(WIDGET_ORDER_KEY, JSON.stringify(newOrder))
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDragStart = (e: React.DragEvent, widgetId: string, column: string) => {
|
||||||
|
setDragState({ draggedId: widgetId, targetColumn: null, targetIndex: null })
|
||||||
|
e.dataTransfer.effectAllowed = 'move'
|
||||||
|
e.dataTransfer.setData('widgetId', widgetId)
|
||||||
|
e.dataTransfer.setData('sourceColumn', column)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDragEnterWidget = (e: React.DragEvent, column: string, index: number) => {
|
||||||
|
// Sadece widget'ın üst kısmına yakınsa indicator göster
|
||||||
|
const rect = (e.currentTarget as HTMLElement).getBoundingClientRect()
|
||||||
|
const mouseY = e.clientY
|
||||||
|
const widgetTop = rect.top
|
||||||
|
const widgetHeight = rect.height
|
||||||
|
const threshold = widgetHeight * 0.3 // Üst %30'luk alan
|
||||||
|
|
||||||
|
if (mouseY - widgetTop < threshold) {
|
||||||
|
// Üst kısma yakın - indicator göster
|
||||||
|
setDragState((prev) => ({ ...prev, targetColumn: column, targetIndex: index }))
|
||||||
|
} else {
|
||||||
|
// Widget'ın ortasında veya altında - indicator gösterme
|
||||||
|
setDragState((prev) => ({ ...prev, targetColumn: column, targetIndex: null }))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDragEnterColumn = (column: string) => {
|
||||||
|
setDragState((prev) => ({ ...prev, targetColumn: column, targetIndex: null }))
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDragLeaveColumn = () => {
|
||||||
|
setDragState((prev) => ({ ...prev, targetColumn: null, targetIndex: null }))
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDrop = (e: React.DragEvent, targetColumn: string, targetIndex?: number) => {
|
||||||
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
|
||||||
|
const widgetId = e.dataTransfer.getData('widgetId')
|
||||||
|
const sourceColumn = e.dataTransfer.getData('sourceColumn')
|
||||||
|
|
||||||
|
if (!widgetId || !sourceColumn) return
|
||||||
|
|
||||||
|
const newOrder = { ...widgetOrder }
|
||||||
|
|
||||||
|
// ÖNCE tüm kolonlardan bu widget'ı kaldır (duplicate önleme)
|
||||||
|
Object.keys(newOrder).forEach((col) => {
|
||||||
|
newOrder[col] = newOrder[col].filter((id) => id !== widgetId)
|
||||||
|
})
|
||||||
|
|
||||||
|
// SONRA hedef kolona ekle
|
||||||
|
if (targetIndex !== undefined) {
|
||||||
|
newOrder[targetColumn].splice(targetIndex, 0, widgetId)
|
||||||
|
} else {
|
||||||
|
newOrder[targetColumn].push(widgetId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Duplicate'leri temizle
|
||||||
|
Object.keys(newOrder).forEach((col) => {
|
||||||
|
newOrder[col] = [...new Set(newOrder[col])]
|
||||||
|
})
|
||||||
|
|
||||||
|
saveWidgetOrder(newOrder)
|
||||||
|
setDragState({ draggedId: null, targetColumn: null, targetIndex: null })
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDragEnd = () => {
|
||||||
|
setDragState({ draggedId: null, targetColumn: null, targetIndex: null })
|
||||||
|
}
|
||||||
|
|
||||||
|
// Widget component'ını render et
|
||||||
|
const renderWidgetComponent = (widgetId: string) => {
|
||||||
|
switch (widgetId) {
|
||||||
|
case 'today-birthdays':
|
||||||
|
return <TodayBirthdays employees={intranetDashboard?.birthdays || []} />
|
||||||
|
case 'documents':
|
||||||
|
return <RecentDocuments documents={intranetDashboard?.documents || []} />
|
||||||
|
case 'announcements':
|
||||||
|
return (
|
||||||
|
<Announcements
|
||||||
|
announcements={intranetDashboard?.announcements || []}
|
||||||
|
onAnnouncementClick={setSelectedAnnouncement}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
case 'active-surveys':
|
||||||
|
return (
|
||||||
|
<Surveys
|
||||||
|
surveys={intranetDashboard?.surveys || []}
|
||||||
|
onTakeSurvey={handleTakeSurvey}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
case 'social-wall':
|
||||||
|
return <SocialWall posts={intranetDashboard?.socialPosts || []} />
|
||||||
|
default:
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Widget'ları render et
|
||||||
|
const renderWidgets = (column: 'left' | 'center' | 'right') => {
|
||||||
|
const columnWidgets = widgetOrder[column] || []
|
||||||
|
|
||||||
|
// Duplicate'leri filtrele
|
||||||
|
const uniqueWidgets = [...new Set(columnWidgets)]
|
||||||
|
|
||||||
|
return uniqueWidgets
|
||||||
|
.map((widgetId, index) => {
|
||||||
|
const metadata = widgetMetadata.find((w) => w.id === widgetId)
|
||||||
|
if (!metadata || !checkPermission(metadata.permission)) return null
|
||||||
|
|
||||||
|
const isDragging = dragState.draggedId === widgetId
|
||||||
|
const isDropTarget = dragState.targetColumn === column && dragState.targetIndex === index
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div key={`${column}-${widgetId}-${index}`} className="relative group">
|
||||||
|
{/* Drop indicator - SADECE widget'ların arasına (üst %30'luk alana) gelince göster */}
|
||||||
|
{isDesignMode && isDropTarget && !isDragging && (
|
||||||
|
<div className="absolute -top-5 left-0 right-0 z-20 animate-in fade-in slide-in-from-top-2 duration-300">
|
||||||
|
{/* Çizgi */}
|
||||||
|
<div className="h-2 bg-gradient-to-r from-transparent via-blue-500 to-transparent rounded-full shadow-lg" />
|
||||||
|
{/* Badge */}
|
||||||
|
<div className="absolute -top-4 left-1/2 -translate-x-1/2 bg-gradient-to-r from-blue-500 to-blue-600 text-white text-xs px-4 py-2 rounded-full whitespace-nowrap shadow-xl font-semibold flex items-center gap-2 border-2 border-white dark:border-gray-800">
|
||||||
|
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
strokeWidth={2}
|
||||||
|
d="M19 14l-7 7m0 0l-7-7m7 7V3"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<span>Buraya Bırak</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div
|
||||||
|
draggable={isDesignMode}
|
||||||
|
onDragStart={(e) => {
|
||||||
|
if (isDesignMode) {
|
||||||
|
handleDragStart(e, widgetId, column)
|
||||||
|
// Drag ghost image'i gizle
|
||||||
|
const ghost = document.createElement('div')
|
||||||
|
ghost.style.opacity = '0'
|
||||||
|
e.dataTransfer.setDragImage(ghost, 0, 0)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onDragOver={(e) => {
|
||||||
|
if (!isDesignMode) return
|
||||||
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
// Throttle: Sadece düzenli aralıklarla güncelle
|
||||||
|
const now = Date.now()
|
||||||
|
if (
|
||||||
|
!e.currentTarget.dataset.lastUpdate ||
|
||||||
|
now - parseInt(e.currentTarget.dataset.lastUpdate) > 150
|
||||||
|
) {
|
||||||
|
e.currentTarget.dataset.lastUpdate = now.toString()
|
||||||
|
handleDragEnterWidget(e, column, index)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onDragLeave={(e) => {
|
||||||
|
// Widget'tan çıkınca indicator'ı kaldır
|
||||||
|
if (isDesignMode) {
|
||||||
|
setDragState((prev) => ({
|
||||||
|
...prev,
|
||||||
|
targetColumn: prev.targetColumn,
|
||||||
|
targetIndex: null,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onDrop={(e) => {
|
||||||
|
if (!isDesignMode) return
|
||||||
|
e.stopPropagation()
|
||||||
|
|
||||||
|
// Drop pozisyonunu hesapla
|
||||||
|
const rect = (e.currentTarget as HTMLElement).getBoundingClientRect()
|
||||||
|
const mouseY = e.clientY
|
||||||
|
const widgetTop = rect.top
|
||||||
|
const widgetHeight = rect.height
|
||||||
|
const threshold = widgetHeight * 0.3
|
||||||
|
|
||||||
|
if (mouseY - widgetTop < threshold) {
|
||||||
|
// Üst kısma bırak - mevcut index'e ekle
|
||||||
|
handleDrop(e, column, index)
|
||||||
|
} else {
|
||||||
|
// Alt kısma bırak - sonraki index'e ekle
|
||||||
|
handleDrop(e, column, index + 1)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onDragEnd={handleDragEnd}
|
||||||
|
className={`
|
||||||
|
relative
|
||||||
|
${
|
||||||
|
isDesignMode
|
||||||
|
? `border-2 border-dashed rounded-lg cursor-move
|
||||||
|
${
|
||||||
|
isDragging
|
||||||
|
? 'border-blue-400 opacity-70 bg-blue-50/30 dark:bg-blue-900/10'
|
||||||
|
: 'border-gray-300 dark:border-gray-600 hover:border-blue-400 dark:hover:border-blue-500 hover:shadow-md'
|
||||||
|
}
|
||||||
|
transition-all duration-300 ease-out`
|
||||||
|
: 'border-0 transition-none'
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
style={{
|
||||||
|
touchAction: 'none',
|
||||||
|
transition:
|
||||||
|
'border-color 0.3s ease-out, opacity 0.3s ease-out, box-shadow 0.3s ease-out',
|
||||||
|
willChange: isDragging ? 'opacity' : 'auto',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* Dragging overlay - daha minimal */}
|
||||||
|
{isDesignMode && isDragging && (
|
||||||
|
<div className="absolute inset-0 bg-white/60 dark:bg-gray-900/40 rounded-lg z-10 flex items-center justify-center backdrop-blur-[1px] transition-opacity duration-300">
|
||||||
|
<div className="bg-gradient-to-r from-blue-500 to-blue-600 text-white px-4 py-2 rounded-lg font-medium shadow-lg flex items-center gap-2">
|
||||||
|
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
strokeWidth={2}
|
||||||
|
d="M7 16V4m0 0L3 8m4-4l4 4m6 0v12m0 0l4-4m-4 4l-4-4"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<span>Taşınıyor</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div
|
||||||
|
className={`${isDesignMode ? 'p-1.5' : ''} transition-all duration-500 ease-out`}
|
||||||
|
>
|
||||||
|
{renderWidgetComponent(widgetId)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.filter(Boolean)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container>
|
||||||
|
<div className="mx-auto space-y-4">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div className="flex items-center gap-4">
|
||||||
|
{/* Design Mode Toggle */}
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<label
|
||||||
|
htmlFor="design-mode-toggle"
|
||||||
|
className="text-sm font-medium text-gray-700 dark:text-gray-300 cursor-pointer"
|
||||||
|
>
|
||||||
|
🎨 {translate('::App.Platform.Intranet.Dashboard.DesignMode')}
|
||||||
|
</label>
|
||||||
|
<button
|
||||||
|
id="design-mode-toggle"
|
||||||
|
onClick={() => setIsDesignMode(!isDesignMode)}
|
||||||
|
className={`
|
||||||
|
relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2
|
||||||
|
${isDesignMode ? 'bg-blue-600' : 'bg-gray-300 dark:bg-gray-600'}
|
||||||
|
`}
|
||||||
|
role="switch"
|
||||||
|
aria-checked={isDesignMode}
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className={`
|
||||||
|
inline-block h-4 w-4 transform rounded-full bg-white transition-transform
|
||||||
|
${isDesignMode ? 'translate-x-6' : 'translate-x-1'}
|
||||||
|
`}
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Reset Button - Sadece design mode aktifken görünsün */}
|
||||||
|
{isDesignMode && (
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
localStorage.removeItem(WIDGET_ORDER_KEY)
|
||||||
|
initializeDefaultOrder()
|
||||||
|
}}
|
||||||
|
className="text-sm text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200 transition-colors flex items-center gap-1"
|
||||||
|
title="Widget düzenini varsayılana döndür"
|
||||||
|
>
|
||||||
|
🔄 {translate('::App.Platform.Intranet.Dashboard.Reset')}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p className="text-gray-600 dark:text-gray-400 mt-1">
|
||||||
|
<span className="font-medium">{translate('::AI.Welcome')},</span>{' '}
|
||||||
|
{currentLocalDate(new Date(), currentLocale || 'tr')}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-1 lg:grid-cols-12">
|
||||||
|
<div
|
||||||
|
className={`lg:col-span-3 space-y-6 min-h-[100px] rounded-xl p-1
|
||||||
|
${
|
||||||
|
isDesignMode && dragState.targetColumn === 'left' && dragState.targetIndex === null
|
||||||
|
? 'bg-blue-50/80 dark:bg-blue-900/20 ring-2 ring-blue-300 dark:ring-blue-600 shadow-lg'
|
||||||
|
: 'bg-transparent'
|
||||||
|
}
|
||||||
|
transition-all duration-700 ease-out
|
||||||
|
`}
|
||||||
|
onDragOver={(e) => {
|
||||||
|
if (!isDesignMode) return
|
||||||
|
e.preventDefault()
|
||||||
|
// Throttle: Sadece her 150ms'de bir güncelle
|
||||||
|
const now = Date.now()
|
||||||
|
const target = e.currentTarget as HTMLElement
|
||||||
|
if (
|
||||||
|
!target.dataset.lastColumnUpdate ||
|
||||||
|
now - parseInt(target.dataset.lastColumnUpdate) > 150
|
||||||
|
) {
|
||||||
|
target.dataset.lastColumnUpdate = now.toString()
|
||||||
|
handleDragEnterColumn('left')
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onDragLeave={() => {
|
||||||
|
if (isDesignMode) handleDragLeaveColumn()
|
||||||
|
}}
|
||||||
|
onDrop={(e) => {
|
||||||
|
if (!isDesignMode) return
|
||||||
|
e.stopPropagation()
|
||||||
|
const columnWidgets = widgetOrder['left'] || []
|
||||||
|
handleDrop(e, 'left', columnWidgets.length)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{renderWidgets('left')}
|
||||||
|
{isDesignMode &&
|
||||||
|
dragState.targetColumn === 'left' &&
|
||||||
|
widgetOrder['left']?.length === 0 && (
|
||||||
|
<div className="flex items-center justify-center h-40 border-2 border-dashed border-blue-300 dark:border-blue-600 rounded-xl bg-blue-50/50 dark:bg-blue-900/10 transition-all duration-500 ease-out">
|
||||||
|
<p className="text-blue-600 dark:text-blue-400 font-medium flex items-center gap-2">
|
||||||
|
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
strokeWidth={2}
|
||||||
|
d="M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<span>Widget'ı buraya bırakın</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
className={`lg:col-span-6 space-y-6 min-h-[100px] rounded-xl p-1
|
||||||
|
${
|
||||||
|
isDesignMode &&
|
||||||
|
dragState.targetColumn === 'center' &&
|
||||||
|
dragState.targetIndex === null
|
||||||
|
? 'bg-blue-50/80 dark:bg-blue-900/20 ring-2 ring-blue-300 dark:ring-blue-600 shadow-lg'
|
||||||
|
: 'bg-transparent'
|
||||||
|
}
|
||||||
|
transition-all duration-700 ease-out
|
||||||
|
`}
|
||||||
|
onDragOver={(e) => {
|
||||||
|
if (!isDesignMode) return
|
||||||
|
e.preventDefault()
|
||||||
|
const now = Date.now()
|
||||||
|
const target = e.currentTarget as HTMLElement
|
||||||
|
if (
|
||||||
|
!target.dataset.lastColumnUpdate ||
|
||||||
|
now - parseInt(target.dataset.lastColumnUpdate) > 150
|
||||||
|
) {
|
||||||
|
target.dataset.lastColumnUpdate = now.toString()
|
||||||
|
handleDragEnterColumn('center')
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onDragLeave={() => {
|
||||||
|
if (isDesignMode) handleDragLeaveColumn()
|
||||||
|
}}
|
||||||
|
onDrop={(e) => {
|
||||||
|
if (!isDesignMode) return
|
||||||
|
e.stopPropagation()
|
||||||
|
const columnWidgets = widgetOrder['center'] || []
|
||||||
|
handleDrop(e, 'center', columnWidgets.length)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{renderWidgets('center')}
|
||||||
|
{isDesignMode &&
|
||||||
|
dragState.targetColumn === 'center' &&
|
||||||
|
widgetOrder['center']?.length === 0 && (
|
||||||
|
<div className="flex items-center justify-center rounded-xl bg-blue-50/50 dark:bg-blue-900/10 transition-all duration-500 ease-out">
|
||||||
|
<p className="text-blue-600 dark:text-blue-400 font-medium flex items-center gap-2">
|
||||||
|
<span>Widget'ı buraya bırakın</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
className={`lg:col-span-3 space-y-6 min-h-[100px] rounded-xl p-1
|
||||||
|
${
|
||||||
|
isDesignMode && dragState.targetColumn === 'right' && dragState.targetIndex === null
|
||||||
|
? 'bg-blue-50/80 dark:bg-blue-900/20 ring-2 ring-blue-300 dark:ring-blue-600 shadow-lg'
|
||||||
|
: 'bg-transparent'
|
||||||
|
}
|
||||||
|
transition-all duration-700 ease-out
|
||||||
|
`}
|
||||||
|
onDragOver={(e) => {
|
||||||
|
if (!isDesignMode) return
|
||||||
|
e.preventDefault()
|
||||||
|
const now = Date.now()
|
||||||
|
const target = e.currentTarget as HTMLElement
|
||||||
|
if (
|
||||||
|
!target.dataset.lastColumnUpdate ||
|
||||||
|
now - parseInt(target.dataset.lastColumnUpdate) > 150
|
||||||
|
) {
|
||||||
|
target.dataset.lastColumnUpdate = now.toString()
|
||||||
|
handleDragEnterColumn('right')
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onDragLeave={() => {
|
||||||
|
if (isDesignMode) handleDragLeaveColumn()
|
||||||
|
}}
|
||||||
|
onDrop={(e) => {
|
||||||
|
if (!isDesignMode) return
|
||||||
|
e.stopPropagation()
|
||||||
|
const columnWidgets = widgetOrder['right'] || []
|
||||||
|
handleDrop(e, 'right', columnWidgets.length)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{renderWidgets('right')}
|
||||||
|
{isDesignMode &&
|
||||||
|
dragState.targetColumn === 'right' &&
|
||||||
|
widgetOrder['right']?.length === 0 && (
|
||||||
|
<div className="flex items-center justify-center h-40 border-2 border-dashed border-blue-300 dark:border-blue-600 rounded-xl bg-blue-50/50 dark:bg-blue-900/10 transition-all duration-500 ease-out">
|
||||||
|
<p className="text-blue-600 dark:text-blue-400 font-medium flex items-center gap-2">
|
||||||
|
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
strokeWidth={2}
|
||||||
|
d="M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<span>Widget'ı buraya bırakın</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<AnimatePresence>
|
||||||
|
{showSurveyModal && selectedSurvey && (
|
||||||
|
<SurveyModal
|
||||||
|
survey={selectedSurvey}
|
||||||
|
onClose={() => setShowSurveyModal(false)}
|
||||||
|
onSubmit={handleSubmitSurvey}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
|
|
||||||
|
<AnimatePresence>
|
||||||
|
{selectedAnnouncement && (
|
||||||
|
<AnnouncementModal
|
||||||
|
announcement={selectedAnnouncement}
|
||||||
|
onClose={() => setSelectedAnnouncement(null)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
|
</Container>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default IntranetDashboard
|
||||||
466
ui/src/views/intranet/SocialWall/CreatePost.tsx
Normal file
466
ui/src/views/intranet/SocialWall/CreatePost.tsx
Normal file
|
|
@ -0,0 +1,466 @@
|
||||||
|
import React, { useState, useRef } from 'react'
|
||||||
|
import { motion, AnimatePresence } from 'framer-motion'
|
||||||
|
import classNames from 'classnames'
|
||||||
|
import EmojiPicker, { EmojiClickData } from 'emoji-picker-react'
|
||||||
|
import {
|
||||||
|
FaChartBar,
|
||||||
|
FaSmile,
|
||||||
|
FaTimes,
|
||||||
|
FaImages,
|
||||||
|
FaMapMarkerAlt
|
||||||
|
} from 'react-icons/fa'
|
||||||
|
import MediaManager from './MediaManager'
|
||||||
|
import LocationPicker from './LocationPicker'
|
||||||
|
import { SocialMediaDto } from '@/proxy/intranet/models'
|
||||||
|
|
||||||
|
interface CreatePostProps {
|
||||||
|
onCreatePost: (post: {
|
||||||
|
content: string
|
||||||
|
location?: string
|
||||||
|
media?: {
|
||||||
|
type: 'mixed' | 'poll'
|
||||||
|
mediaItems?: SocialMediaDto[]
|
||||||
|
poll?: {
|
||||||
|
question: string
|
||||||
|
options: Array<{ text: string }>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
|
import { useStoreState } from '@/store/store'
|
||||||
|
import { Avatar } from '@/components/ui'
|
||||||
|
import { AVATAR_URL } from '@/constants/app.constant'
|
||||||
|
const CreatePost: React.FC<CreatePostProps> = ({ onCreatePost }) => {
|
||||||
|
const { translate } = useLocalization();
|
||||||
|
const [content, setContent] = useState('')
|
||||||
|
const [mediaType, setMediaType] = useState<'media' | 'poll' | null>(null)
|
||||||
|
const [mediaItems, setMediaItems] = useState<SocialMediaDto[]>([])
|
||||||
|
const [location, setLocation] = useState<string | null>(null)
|
||||||
|
const [pollQuestion, setPollQuestion] = useState('')
|
||||||
|
const [pollOptions, setPollOptions] = useState(['', ''])
|
||||||
|
const [isExpanded, setIsExpanded] = useState(false)
|
||||||
|
const [showEmojiPicker, setShowEmojiPicker] = useState(false)
|
||||||
|
const [showMediaManager, setShowMediaManager] = useState(false)
|
||||||
|
const [showLocationPicker, setShowLocationPicker] = useState(false)
|
||||||
|
const textareaRef = useRef<HTMLTextAreaElement>(null)
|
||||||
|
const emojiPickerRef = useRef<HTMLDivElement>(null)
|
||||||
|
const { user, tenant } = useStoreState((state) => state.auth)
|
||||||
|
|
||||||
|
const handleSubmit = (e: React.FormEvent) => {
|
||||||
|
e.preventDefault()
|
||||||
|
|
||||||
|
if (!content.trim() && mediaItems.length === 0 && !mediaType) return
|
||||||
|
|
||||||
|
let media = undefined
|
||||||
|
|
||||||
|
if (mediaType === 'media' && mediaItems.length > 0) {
|
||||||
|
media = {
|
||||||
|
type: 'mixed' as const,
|
||||||
|
mediaItems
|
||||||
|
}
|
||||||
|
} else if (mediaType === 'poll' && pollQuestion && pollOptions.filter(o => o.trim()).length >= 2) {
|
||||||
|
media = {
|
||||||
|
type: 'poll' as const,
|
||||||
|
poll: {
|
||||||
|
question: pollQuestion,
|
||||||
|
options: pollOptions.filter(o => o.trim()).map(text => ({ text }))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onCreatePost({
|
||||||
|
content,
|
||||||
|
media,
|
||||||
|
location: location || undefined
|
||||||
|
})
|
||||||
|
|
||||||
|
// Reset form
|
||||||
|
setContent('')
|
||||||
|
setMediaType(null)
|
||||||
|
setMediaItems([])
|
||||||
|
setLocation(null)
|
||||||
|
setPollQuestion('')
|
||||||
|
setPollOptions(['', ''])
|
||||||
|
setIsExpanded(false)
|
||||||
|
setShowEmojiPicker(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleEmojiClick = (emojiData: EmojiClickData) => {
|
||||||
|
const emoji = emojiData.emoji
|
||||||
|
const textarea = textareaRef.current
|
||||||
|
if (!textarea) return
|
||||||
|
|
||||||
|
const start = textarea.selectionStart
|
||||||
|
const end = textarea.selectionEnd
|
||||||
|
const text = content
|
||||||
|
const before = text.substring(0, start)
|
||||||
|
const after = text.substring(end)
|
||||||
|
|
||||||
|
setContent(before + emoji + after)
|
||||||
|
|
||||||
|
// Set cursor position after emoji
|
||||||
|
setTimeout(() => {
|
||||||
|
textarea.selectionStart = textarea.selectionEnd = start + emoji.length
|
||||||
|
textarea.focus()
|
||||||
|
}, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
const addPollOption = () => {
|
||||||
|
if (pollOptions.length < 6) {
|
||||||
|
setPollOptions([...pollOptions, ''])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const removePollOption = (index: number) => {
|
||||||
|
if (pollOptions.length > 2) {
|
||||||
|
setPollOptions(pollOptions.filter((_, i) => i !== index))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const updatePollOption = (index: number, value: string) => {
|
||||||
|
const newOptions = [...pollOptions]
|
||||||
|
newOptions[index] = value
|
||||||
|
setPollOptions(newOptions)
|
||||||
|
}
|
||||||
|
|
||||||
|
const clearMedia = () => {
|
||||||
|
setMediaType(null)
|
||||||
|
setMediaItems([])
|
||||||
|
setPollQuestion('')
|
||||||
|
setPollOptions(['', ''])
|
||||||
|
}
|
||||||
|
|
||||||
|
const removeMediaItem = (id: string | undefined) => {
|
||||||
|
if (!id) return
|
||||||
|
setMediaItems(mediaItems.filter((m) => m.id !== id))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close emoji picker when clicking outside
|
||||||
|
React.useEffect(() => {
|
||||||
|
const handleClickOutside = (event: MouseEvent) => {
|
||||||
|
if (emojiPickerRef.current && !emojiPickerRef.current.contains(event.target as Node)) {
|
||||||
|
setShowEmojiPicker(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (showEmojiPicker) {
|
||||||
|
document.addEventListener('mousedown', handleClickOutside)
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener('mousedown', handleClickOutside)
|
||||||
|
}
|
||||||
|
}, [showEmojiPicker])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 p-4 mb-6">
|
||||||
|
<form onSubmit={handleSubmit}>
|
||||||
|
{/* Text Input */}
|
||||||
|
<div className="flex gap-3 mb-4">
|
||||||
|
<Avatar size={32} shape="circle" src={AVATAR_URL(user.id, tenant.tenantId)} />
|
||||||
|
<div className="flex-1">
|
||||||
|
<textarea
|
||||||
|
ref={textareaRef}
|
||||||
|
value={content}
|
||||||
|
onChange={(e) => setContent(e.target.value)}
|
||||||
|
onFocus={() => setIsExpanded(true)}
|
||||||
|
placeholder={translate('::App.Platform.Intranet.SocialWall.CreatePost.Placeholder')}
|
||||||
|
className={classNames(
|
||||||
|
'w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500 resize-none transition-all',
|
||||||
|
isExpanded ? 'min-h-[120px]' : 'min-h-[48px]'
|
||||||
|
)}
|
||||||
|
rows={isExpanded ? 4 : 1}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Media Preview */}
|
||||||
|
<AnimatePresence>
|
||||||
|
{mediaType === 'media' && mediaItems.length > 0 && (
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, height: 0 }}
|
||||||
|
animate={{ opacity: 1, height: 'auto' }}
|
||||||
|
exit={{ opacity: 0, height: 0 }}
|
||||||
|
className="mb-4"
|
||||||
|
>
|
||||||
|
<div className="flex items-center justify-between mb-2">
|
||||||
|
<h4 className="text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||||
|
{translate('::App.Platform.Intranet.SocialWall.CreatePost.MediaTitle')} ({mediaItems.length})
|
||||||
|
</h4>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => {
|
||||||
|
clearMedia()
|
||||||
|
}}
|
||||||
|
className="text-sm text-red-600 hover:text-red-700 font-medium"
|
||||||
|
title={translate('::App.Platform.Intranet.SocialWall.CreatePost.RemoveAllMediaTitle')}
|
||||||
|
>
|
||||||
|
{translate('::Cancel')}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="grid grid-cols-4 gap-2">
|
||||||
|
{mediaItems.map((item) => (
|
||||||
|
<div key={item.id} className="relative group">
|
||||||
|
{item.type === 'image' ? (
|
||||||
|
<img
|
||||||
|
src={item.urls?.[0]}
|
||||||
|
alt="Preview"
|
||||||
|
className="w-full h-24 object-cover rounded-lg"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<div className="w-full h-24 bg-gray-900 rounded-lg relative">
|
||||||
|
<video src={item.urls?.[0]} className="w-full h-full object-cover rounded-lg" />
|
||||||
|
<div className="absolute inset-0 flex items-center justify-center">
|
||||||
|
<div className="w-10 h-10 bg-black bg-opacity-50 rounded-full flex items-center justify-center">
|
||||||
|
<div className="w-0 h-0 border-t-8 border-t-transparent border-l-12 border-l-white border-b-8 border-b-transparent ml-1"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => removeMediaItem(item.id)}
|
||||||
|
className="absolute -top-2 -right-2 p-1 bg-red-600 text-white rounded-full opacity-0 group-hover:opacity-100 transition-opacity"
|
||||||
|
>
|
||||||
|
<FaTimes className="w-4 h-4" />
|
||||||
|
</button>
|
||||||
|
<div className="absolute bottom-1 left-1 px-2 py-0.5 bg-black bg-opacity-70 text-white text-xs rounded">
|
||||||
|
{item.type === 'image' ? '📷' : '🎥'}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setShowMediaManager(true)}
|
||||||
|
className="h-24 border-2 border-dashed border-gray-300 dark:border-gray-600 rounded-lg flex items-center justify-center hover:border-blue-500 hover:bg-blue-50 dark:hover:bg-blue-900/20 transition-colors"
|
||||||
|
>
|
||||||
|
<FaImages className="w-6 h-6 text-gray-400" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{location && (
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, height: 0 }}
|
||||||
|
animate={{ opacity: 1, height: 'auto' }}
|
||||||
|
exit={{ opacity: 0, height: 0 }}
|
||||||
|
className="mb-4"
|
||||||
|
>
|
||||||
|
<div className="flex items-center justify-between mb-2">
|
||||||
|
<h4 className="text-sm font-medium text-gray-700 dark:text-gray-300">{translate('::App.Platform.Intranet.SocialWall.CreatePost.Location')}</h4>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setLocation(null)}
|
||||||
|
className="text-sm text-red-600 hover:text-red-700 font-medium"
|
||||||
|
title={translate('::App.Platform.Intranet.SocialWall.CreatePost.RemoveLocationTitle')}
|
||||||
|
>
|
||||||
|
{translate('::Cancel')}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="p-3 border border-gray-300 dark:border-gray-600 rounded-lg bg-gray-50 dark:bg-gray-700">
|
||||||
|
<div className="flex items-start gap-2">
|
||||||
|
<FaMapMarkerAlt className="w-5 h-5 text-blue-600 mt-0.5 flex-shrink-0" />
|
||||||
|
<div className="flex-1 min-w-0">
|
||||||
|
<h3 className="font-semibold text-gray-900 dark:text-gray-100 mb-1">
|
||||||
|
{JSON.parse(location).name}
|
||||||
|
</h3>
|
||||||
|
<p className="text-sm text-gray-600 dark:text-gray-400 line-clamp-2">
|
||||||
|
{JSON.parse(location).address}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{mediaType === 'poll' && (
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, height: 0 }}
|
||||||
|
animate={{ opacity: 1, height: 'auto' }}
|
||||||
|
exit={{ opacity: 0, height: 0 }}
|
||||||
|
className="mb-4"
|
||||||
|
>
|
||||||
|
<div className="flex items-center justify-between mb-2">
|
||||||
|
<h4 className="text-sm font-medium text-gray-700 dark:text-gray-300">{translate('::App.Platform.Intranet.SocialWall.CreatePost.Poll')}</h4>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => {
|
||||||
|
clearMedia()
|
||||||
|
}}
|
||||||
|
className="text-sm text-red-600 hover:text-red-700 font-medium"
|
||||||
|
title={translate('::App.Platform.Intranet.SocialWall.CreatePost.RemovePollTitle')}
|
||||||
|
>
|
||||||
|
{translate('::Cancel')}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={pollQuestion}
|
||||||
|
onChange={(e) => setPollQuestion(e.target.value)}
|
||||||
|
placeholder={translate('::App.Platform.Intranet.SocialWall.CreatePost.PollQuestionPlaceholder')}
|
||||||
|
className="w-full px-4 py-2 mb-3 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||||
|
/>
|
||||||
|
<div className="space-y-2">
|
||||||
|
{pollOptions.map((option, index) => (
|
||||||
|
<div key={index} className="flex gap-2">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={option}
|
||||||
|
onChange={(e) => updatePollOption(index, e.target.value)}
|
||||||
|
placeholder={translate('::App.Platform.Intranet.SocialWall.CreatePost.PollOptionPlaceholder')}
|
||||||
|
className="flex-1 px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||||
|
/>
|
||||||
|
{pollOptions.length > 2 && (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => removePollOption(index)}
|
||||||
|
className="p-2 text-gray-500 hover:text-red-600"
|
||||||
|
>
|
||||||
|
<FaTimes className="w-5 h-5" />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
{pollOptions.length < 6 && (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={addPollOption}
|
||||||
|
className="mt-2 text-sm text-blue-600 hover:text-blue-700 font-medium"
|
||||||
|
>
|
||||||
|
+ {translate('::App.Platform.Intranet.SocialWall.CreatePost.AddOption')}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
|
|
||||||
|
{/* Actions */}
|
||||||
|
<AnimatePresence>
|
||||||
|
{isExpanded && (
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, height: 0 }}
|
||||||
|
animate={{ opacity: 1, height: 'auto' }}
|
||||||
|
exit={{ opacity: 0, height: 0 }}
|
||||||
|
className="flex items-center justify-between pt-3 border-t border-gray-200 dark:border-gray-700"
|
||||||
|
>
|
||||||
|
<div className="flex gap-2 relative">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => {
|
||||||
|
if (mediaType === 'media' && mediaItems.length > 0) {
|
||||||
|
// Eğer zaten medya varsa, yöneticiyi aç
|
||||||
|
setShowMediaManager(true)
|
||||||
|
} else {
|
||||||
|
// Başka bir tip seçiliyse temizle ve medya modunu aç
|
||||||
|
clearMedia()
|
||||||
|
setMediaType('media')
|
||||||
|
setShowMediaManager(true)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
className={classNames(
|
||||||
|
'p-2 rounded-full transition-colors',
|
||||||
|
mediaType === 'media'
|
||||||
|
? 'bg-blue-100 text-blue-600 dark:bg-blue-900 dark:text-blue-400'
|
||||||
|
: 'text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700'
|
||||||
|
)}
|
||||||
|
title={mediaType === 'media' ? translate('::App.Platform.Intranet.SocialWall.CreatePost.EditMediaTitle') : translate('::App.Platform.Intranet.SocialWall.CreatePost.AddMediaTitle')}
|
||||||
|
>
|
||||||
|
<FaImages className="w-5 h-5" />
|
||||||
|
{mediaType === 'media' && mediaItems.length > 0 && (
|
||||||
|
<span className="absolute -top-1 -right-1 w-4 h-4 bg-blue-600 text-white text-xs rounded-full flex items-center justify-center">
|
||||||
|
{mediaItems.length}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => {
|
||||||
|
// Başka bir tip seçiliyse temizle
|
||||||
|
if (mediaType !== 'poll') {
|
||||||
|
clearMedia()
|
||||||
|
}
|
||||||
|
setMediaType(mediaType === 'poll' ? null : 'poll')
|
||||||
|
}}
|
||||||
|
className={classNames(
|
||||||
|
'p-2 rounded-full transition-colors',
|
||||||
|
mediaType === 'poll'
|
||||||
|
? 'bg-blue-100 text-blue-600 dark:bg-blue-900 dark:text-blue-400'
|
||||||
|
: 'text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700'
|
||||||
|
)}
|
||||||
|
title={mediaType === 'poll' ? translate('::App.Platform.Intranet.SocialWall.CreatePost.RemovePollTitle') : translate('::App.Platform.Intranet.SocialWall.CreatePost.AddPollTitle')}
|
||||||
|
>
|
||||||
|
<FaChartBar className="w-5 h-5" />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setShowEmojiPicker(!showEmojiPicker)}
|
||||||
|
className="p-2 text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-full transition-colors"
|
||||||
|
title={translate('::App.Platform.Intranet.SocialWall.CreatePost.AddEmojiTitle')}
|
||||||
|
>
|
||||||
|
<FaSmile className="w-5 h-5" />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setShowLocationPicker(true)}
|
||||||
|
className={classNames(
|
||||||
|
'p-2 rounded-full transition-colors',
|
||||||
|
location
|
||||||
|
? 'bg-blue-100 text-blue-600 dark:bg-blue-900 dark:text-blue-400'
|
||||||
|
: 'text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700'
|
||||||
|
)}
|
||||||
|
title={location ? translate('::App.Platform.Intranet.SocialWall.CreatePost.EditLocationTitle') : translate('::App.Platform.Intranet.SocialWall.CreatePost.AddLocationTitle')}
|
||||||
|
>
|
||||||
|
<FaMapMarkerAlt className="w-5 h-5" />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{/* Emoji Picker */}
|
||||||
|
{showEmojiPicker && (
|
||||||
|
<div ref={emojiPickerRef} className="absolute bottom-12 left-0 z-50">
|
||||||
|
<EmojiPicker
|
||||||
|
onEmojiClick={handleEmojiClick}
|
||||||
|
autoFocusSearch={false}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
disabled={!content.trim() && mediaItems.length === 0 && !mediaType}
|
||||||
|
className="px-6 py-2 bg-blue-600 text-white font-medium rounded-full hover:bg-blue-700 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors"
|
||||||
|
>
|
||||||
|
{translate('::App.Platform.Intranet.SocialWall.CreatePost.Submit')}
|
||||||
|
</button>
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{/* Media Manager Modal */}
|
||||||
|
<AnimatePresence>
|
||||||
|
{showMediaManager && (
|
||||||
|
<MediaManager
|
||||||
|
media={mediaItems}
|
||||||
|
onChange={setMediaItems}
|
||||||
|
onClose={() => setShowMediaManager(false)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
|
|
||||||
|
{/* Location Picker Modal */}
|
||||||
|
<AnimatePresence>
|
||||||
|
{showLocationPicker && (
|
||||||
|
<LocationPicker
|
||||||
|
onSelect={setLocation}
|
||||||
|
onClose={() => setShowLocationPicker(false)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CreatePost
|
||||||
109
ui/src/views/intranet/SocialWall/LocationMap.tsx
Normal file
109
ui/src/views/intranet/SocialWall/LocationMap.tsx
Normal file
|
|
@ -0,0 +1,109 @@
|
||||||
|
import React from 'react'
|
||||||
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
|
import { FaExternalLinkAlt, FaMapMarkerAlt } from 'react-icons/fa'
|
||||||
|
|
||||||
|
interface LocationData {
|
||||||
|
id: string
|
||||||
|
name: string
|
||||||
|
address: string
|
||||||
|
lat: number
|
||||||
|
lng: number
|
||||||
|
placeId?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface LocationMapProps {
|
||||||
|
location: string // JSON string
|
||||||
|
className?: string
|
||||||
|
showDirections?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const LocationMap: React.FC<LocationMapProps> = ({
|
||||||
|
location,
|
||||||
|
className = '',
|
||||||
|
showDirections = true
|
||||||
|
}) => {
|
||||||
|
const locationData: LocationData = JSON.parse(location)
|
||||||
|
|
||||||
|
const handleOpenGoogleMaps = () => {
|
||||||
|
const url = `https://www.google.com/maps/search/?api=1&query=${locationData.lat},${locationData.lng}&query_place_id=${locationData.placeId || ''}`
|
||||||
|
window.open(url, '_blank')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Google Maps Static API URL (gerçek uygulamada API key eklenecek)
|
||||||
|
const getMapImageUrl = () => {
|
||||||
|
const { lat, lng } = locationData
|
||||||
|
const zoom = 15
|
||||||
|
const size = '600x300'
|
||||||
|
const marker = `color:red|${lat},${lng}`
|
||||||
|
|
||||||
|
// Production'da gerçek API key kullanılacak
|
||||||
|
// const apiKey = 'YOUR_GOOGLE_MAPS_API_KEY'
|
||||||
|
// return `https://maps.googleapis.com/maps/api/staticmap?center=${lat},${lng}&zoom=${zoom}&size=${size}&markers=${marker}&key=${apiKey}`
|
||||||
|
|
||||||
|
// Demo için OpenStreetMap kullanıyoruz
|
||||||
|
return `https://www.openstreetmap.org/export/embed.html?bbox=${lng - 0.01},${lat - 0.01},${lng + 0.01},${lat + 0.01}&layer=mapnik&marker=${lat},${lng}`
|
||||||
|
}
|
||||||
|
|
||||||
|
const { translate } = useLocalization();
|
||||||
|
return (
|
||||||
|
<div className={`relative rounded-lg overflow-hidden bg-gray-200 dark:bg-gray-700 ${className}`}>
|
||||||
|
{/* Map Container */}
|
||||||
|
<div className="relative w-full h-64 group">
|
||||||
|
{/* OpenStreetMap iframe for demo */}
|
||||||
|
<iframe
|
||||||
|
title={`Map of ${locationData.name}`}
|
||||||
|
src={getMapImageUrl()}
|
||||||
|
className="w-full h-full border-0"
|
||||||
|
allowFullScreen
|
||||||
|
loading="lazy"
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Overlay with location info */}
|
||||||
|
<div className="absolute inset-0 bg-gradient-to-t from-black/60 via-transparent to-transparent pointer-events-none" />
|
||||||
|
|
||||||
|
{/* Location Info */}
|
||||||
|
<div className="absolute bottom-0 left-0 right-0 p-4 text-white pointer-events-none">
|
||||||
|
<div className="flex items-start gap-2">
|
||||||
|
<FaMapMarkerAlt className="w-5 h-5 mt-0.5 flex-shrink-0" />
|
||||||
|
<div className="flex-1 min-w-0">
|
||||||
|
<h3 className="font-bold text-lg mb-1 drop-shadow-lg">{locationData.name}</h3>
|
||||||
|
<p className="text-sm text-white/90 drop-shadow-md line-clamp-2">
|
||||||
|
{locationData.address}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Click to open overlay - invisible but clickable */}
|
||||||
|
<button
|
||||||
|
onClick={handleOpenGoogleMaps}
|
||||||
|
className="absolute inset-0 w-full h-full cursor-pointer group"
|
||||||
|
aria-label={translate('::App.Platform.Intranet.SocialWall.LocationMap.OpenInGoogleMaps')}
|
||||||
|
>
|
||||||
|
<span className="sr-only">{translate('::App.Platform.Intranet.SocialWall.LocationMap.OpenInGoogleMaps')}</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{/* Hover Effect */}
|
||||||
|
<div className="absolute inset-0 bg-blue-600/0 group-hover:bg-blue-600/10 transition-colors duration-200" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Directions Button */}
|
||||||
|
{showDirections && (
|
||||||
|
<div className="p-3 bg-white dark:bg-gray-800 border-t border-gray-200 dark:border-gray-700">
|
||||||
|
<button
|
||||||
|
onClick={handleOpenGoogleMaps}
|
||||||
|
className="w-full flex items-center justify-center gap-2 px-4 py-2.5 bg-blue-600 hover:bg-blue-700 text-white font-medium rounded-lg transition-colors"
|
||||||
|
>
|
||||||
|
<FaExternalLinkAlt className="w-5 h-5" />
|
||||||
|
<span>{translate('::App.Platform.Intranet.SocialWall.LocationMap.OpenInGoogleMaps')}</span>
|
||||||
|
</button>
|
||||||
|
<p className="text-xs text-gray-500 dark:text-gray-400 mt-2 text-center">
|
||||||
|
{translate('::App.Platform.Intranet.SocialWall.LocationMap.ClickForDirections')}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default LocationMap
|
||||||
388
ui/src/views/intranet/SocialWall/LocationPicker.tsx
Normal file
388
ui/src/views/intranet/SocialWall/LocationPicker.tsx
Normal file
|
|
@ -0,0 +1,388 @@
|
||||||
|
import React, { useState, useEffect, useRef } from 'react'
|
||||||
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
|
import { motion } from 'framer-motion'
|
||||||
|
import { FaTimes, FaSearch, FaMapMarkerAlt } from 'react-icons/fa'
|
||||||
|
import classNames from 'classnames'
|
||||||
|
|
||||||
|
interface LocationPickerProps {
|
||||||
|
onSelect: (location: string) => void
|
||||||
|
onClose: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
interface LocationData {
|
||||||
|
id: string
|
||||||
|
name: string
|
||||||
|
address: string
|
||||||
|
lat: number
|
||||||
|
lng: number
|
||||||
|
placeId?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Google Maps API key - .env dosyasından alınmalı
|
||||||
|
const GOOGLE_API_KEY = import.meta.env.VITE_GOOGLE_MAPS_API_KEY || ''
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
google: any
|
||||||
|
initGoogleMaps?: () => void
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const LocationPicker: React.FC<LocationPickerProps> = ({ onSelect, onClose }) => {
|
||||||
|
const { translate } = useLocalization();
|
||||||
|
const [searchQuery, setSearchQuery] = useState('')
|
||||||
|
const [locations, setLocations] = useState<LocationData[]>([])
|
||||||
|
const [selectedLocation, setSelectedLocation] = useState<LocationData | null>(null)
|
||||||
|
const [isLoading, setIsLoading] = useState(false)
|
||||||
|
const [error, setError] = useState<string | null>(null)
|
||||||
|
const [isGoogleLoaded, setIsGoogleLoaded] = useState(false)
|
||||||
|
const searchInputRef = useRef<HTMLInputElement>(null)
|
||||||
|
const autocompleteServiceRef = useRef<any>(null)
|
||||||
|
const placesServiceRef = useRef<any>(null)
|
||||||
|
const debounceTimerRef = useRef<NodeJS.Timeout>()
|
||||||
|
const scriptLoadedRef = useRef(false)
|
||||||
|
|
||||||
|
// Google Maps SDK'yı yükle
|
||||||
|
useEffect(() => {
|
||||||
|
if (scriptLoadedRef.current) return
|
||||||
|
|
||||||
|
const loadGoogleMaps = () => {
|
||||||
|
if (window.google && window.google.maps && window.google.maps.places) {
|
||||||
|
setIsGoogleLoaded(true)
|
||||||
|
autocompleteServiceRef.current = new window.google.maps.places.AutocompleteService()
|
||||||
|
const mapDiv = document.createElement('div')
|
||||||
|
const map = new window.google.maps.Map(mapDiv)
|
||||||
|
placesServiceRef.current = new window.google.maps.places.PlacesService(map)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!GOOGLE_API_KEY) {
|
||||||
|
setError(translate('::App.Platform.Intranet.SocialWall.LocationPicker.ApiKeyError'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Script zaten yüklendiyse sadece bekle
|
||||||
|
const existingScript = document.querySelector('script[src*="maps.googleapis.com"]')
|
||||||
|
if (existingScript) {
|
||||||
|
const checkInterval = setInterval(() => {
|
||||||
|
if (window.google && window.google.maps && window.google.maps.places) {
|
||||||
|
clearInterval(checkInterval)
|
||||||
|
setIsGoogleLoaded(true)
|
||||||
|
autocompleteServiceRef.current = new window.google.maps.places.AutocompleteService()
|
||||||
|
const mapDiv = document.createElement('div')
|
||||||
|
const map = new window.google.maps.Map(mapDiv)
|
||||||
|
placesServiceRef.current = new window.google.maps.places.PlacesService(map)
|
||||||
|
}
|
||||||
|
}, 100)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Yeni script ekle
|
||||||
|
const script = document.createElement('script')
|
||||||
|
script.src = `https://maps.googleapis.com/maps/api/js?key=${GOOGLE_API_KEY}&libraries=places&language=tr`
|
||||||
|
script.async = true
|
||||||
|
script.defer = true
|
||||||
|
|
||||||
|
script.onload = () => {
|
||||||
|
if (window.google && window.google.maps && window.google.maps.places) {
|
||||||
|
setIsGoogleLoaded(true)
|
||||||
|
autocompleteServiceRef.current = new window.google.maps.places.AutocompleteService()
|
||||||
|
const mapDiv = document.createElement('div')
|
||||||
|
const map = new window.google.maps.Map(mapDiv)
|
||||||
|
placesServiceRef.current = new window.google.maps.places.PlacesService(map)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
script.onerror = () => {
|
||||||
|
setError(translate('::App.Platform.Intranet.SocialWall.LocationPicker.GoogleMapsLoadError'))
|
||||||
|
}
|
||||||
|
|
||||||
|
document.head.appendChild(script)
|
||||||
|
scriptLoadedRef.current = true
|
||||||
|
}
|
||||||
|
|
||||||
|
loadGoogleMaps()
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
searchInputRef.current?.focus()
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
// Google Places Autocomplete ile konum arama
|
||||||
|
useEffect(() => {
|
||||||
|
if (debounceTimerRef.current) {
|
||||||
|
clearTimeout(debounceTimerRef.current)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (searchQuery.trim() === '') {
|
||||||
|
setLocations([])
|
||||||
|
setError(null)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isGoogleLoaded) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
debounceTimerRef.current = setTimeout(async () => {
|
||||||
|
setIsLoading(true)
|
||||||
|
setError(null)
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Google Places Autocomplete Service kullan (CORS yok)
|
||||||
|
autocompleteServiceRef.current.getPlacePredictions(
|
||||||
|
{
|
||||||
|
input: searchQuery,
|
||||||
|
componentRestrictions: { country: 'tr' },
|
||||||
|
language: 'tr'
|
||||||
|
},
|
||||||
|
async (predictions: any, status: any) => {
|
||||||
|
if (status === window.google.maps.places.PlacesServiceStatus.ZERO_RESULTS) {
|
||||||
|
setLocations([])
|
||||||
|
setIsLoading(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status !== window.google.maps.places.PlacesServiceStatus.OK) {
|
||||||
|
setError(translate('::App.Platform.Intranet.SocialWall.LocationPicker.SearchFailed'))
|
||||||
|
setIsLoading(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!predictions || predictions.length === 0) {
|
||||||
|
setLocations([])
|
||||||
|
setIsLoading(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Her bir prediction için detaylı bilgi al
|
||||||
|
const detailedLocations: LocationData[] = []
|
||||||
|
let completed = 0
|
||||||
|
|
||||||
|
predictions.forEach((prediction: any) => {
|
||||||
|
placesServiceRef.current.getDetails(
|
||||||
|
{
|
||||||
|
placeId: prediction.place_id,
|
||||||
|
fields: ['name', 'formatted_address', 'geometry', 'place_id']
|
||||||
|
},
|
||||||
|
(place: any, placeStatus: any) => {
|
||||||
|
completed++
|
||||||
|
|
||||||
|
if (placeStatus === window.google.maps.places.PlacesServiceStatus.OK && place) {
|
||||||
|
detailedLocations.push({
|
||||||
|
id: place.place_id,
|
||||||
|
name: place.name,
|
||||||
|
address: place.formatted_address,
|
||||||
|
lat: place.geometry.location.lat(),
|
||||||
|
lng: place.geometry.location.lng(),
|
||||||
|
placeId: place.place_id
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tüm istekler tamamlandıysa state'i güncelle
|
||||||
|
if (completed === predictions.length) {
|
||||||
|
setLocations(detailedLocations)
|
||||||
|
setIsLoading(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Location search error:', err)
|
||||||
|
setError(translate('::App.Platform.Intranet.SocialWall.LocationPicker.SearchError'))
|
||||||
|
setIsLoading(false)
|
||||||
|
}
|
||||||
|
}, 500) // 500ms debounce
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (debounceTimerRef.current) {
|
||||||
|
clearTimeout(debounceTimerRef.current)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [searchQuery, isGoogleLoaded])
|
||||||
|
|
||||||
|
const handleSelect = (location: LocationData) => {
|
||||||
|
setSelectedLocation(location)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleConfirm = () => {
|
||||||
|
if (selectedLocation) {
|
||||||
|
onSelect(JSON.stringify(selectedLocation))
|
||||||
|
onClose()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, scale: 0.9 }}
|
||||||
|
animate={{ opacity: 1, scale: 1 }}
|
||||||
|
exit={{ opacity: 0, scale: 0.9 }}
|
||||||
|
className="bg-white dark:bg-gray-800 rounded-lg shadow-xl w-full max-w-2xl max-h-[90vh] overflow-hidden flex flex-col"
|
||||||
|
>
|
||||||
|
{/* Header */}
|
||||||
|
<div className="flex items-center justify-between p-4 border-b border-gray-200 dark:border-gray-700">
|
||||||
|
<h2 className="text-xl font-bold text-gray-900 dark:text-white">{translate('::App.Platform.Intranet.SocialWall.LocationPicker.AddLocation')}</h2>
|
||||||
|
<button
|
||||||
|
onClick={onClose}
|
||||||
|
className="p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-full transition-colors"
|
||||||
|
>
|
||||||
|
<FaTimes className="w-5 h-5 text-gray-500 dark:text-gray-400" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Search */}
|
||||||
|
<div className="p-4 border-b border-gray-200 dark:border-gray-700">
|
||||||
|
<div className="relative">
|
||||||
|
<FaSearch className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-gray-400" />
|
||||||
|
<input
|
||||||
|
ref={searchInputRef}
|
||||||
|
type="text"
|
||||||
|
value={searchQuery}
|
||||||
|
onChange={(e) => setSearchQuery(e.target.value)}
|
||||||
|
placeholder={translate('::App.Platform.Intranet.SocialWall.LocationPicker.SearchPlaceholder')}
|
||||||
|
disabled={!isGoogleLoaded}
|
||||||
|
className="w-full pl-10 pr-4 py-3 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500 disabled:bg-gray-100 dark:disabled:bg-gray-600 disabled:cursor-not-allowed"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{!isGoogleLoaded && (
|
||||||
|
<p className="text-xs text-gray-500 dark:text-gray-400 mt-2">
|
||||||
|
{translate('::App.Platform.Intranet.SocialWall.LocationPicker.LoadingGoogleMaps')}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Location List */}
|
||||||
|
<div className="flex-1 overflow-y-auto p-4">
|
||||||
|
{!isGoogleLoaded ? (
|
||||||
|
<div className="text-center py-12">
|
||||||
|
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto mb-4"></div>
|
||||||
|
<p className="text-gray-500 dark:text-gray-400">{translate('::App.Platform.Intranet.SocialWall.LocationPicker.LoadingGoogleMaps')}</p>
|
||||||
|
</div>
|
||||||
|
) : isLoading ? (
|
||||||
|
<div className="text-center py-12">
|
||||||
|
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto mb-4"></div>
|
||||||
|
<p className="text-gray-500 dark:text-gray-400">{translate('::App.Platform.Intranet.SocialWall.LocationPicker.SearchingLocations')}</p>
|
||||||
|
</div>
|
||||||
|
) : error ? (
|
||||||
|
<div className="text-center py-12">
|
||||||
|
<FaMapMarkerAlt className="w-16 h-16 mx-auto mb-4 text-red-400" />
|
||||||
|
<p className="text-red-500 dark:text-red-400">{error}</p>
|
||||||
|
</div>
|
||||||
|
) : searchQuery.trim() === '' ? (
|
||||||
|
<div className="text-center py-12">
|
||||||
|
<FaSearch className="w-16 h-16 mx-auto mb-4 text-gray-400" />
|
||||||
|
<p className="text-gray-500 dark:text-gray-400">
|
||||||
|
{translate('::App.Platform.Intranet.SocialWall.LocationPicker.TypeToSearch')}
|
||||||
|
</p>
|
||||||
|
<p className="text-sm text-gray-400 dark:text-gray-500 mt-2">
|
||||||
|
{translate('::App.Platform.Intranet.SocialWall.LocationPicker.Example')}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
) : locations.length === 0 ? (
|
||||||
|
<div className="text-center py-12">
|
||||||
|
<FaMapMarkerAlt className="w-16 h-16 mx-auto mb-4 text-gray-400" />
|
||||||
|
<p className="text-gray-500 dark:text-gray-400">
|
||||||
|
{translate('::App.Platform.Intranet.SocialWall.LocationPicker.NotFound')}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="space-y-2">
|
||||||
|
{locations.map((location) => (
|
||||||
|
<button
|
||||||
|
key={location.id}
|
||||||
|
onClick={() => handleSelect(location)}
|
||||||
|
className={classNames(
|
||||||
|
'w-full text-left p-3 rounded-lg transition-all hover:bg-gray-50 dark:hover:bg-gray-700',
|
||||||
|
selectedLocation?.id === location.id
|
||||||
|
? 'bg-blue-50 dark:bg-blue-900/30 border-2 border-blue-500'
|
||||||
|
: 'border-2 border-transparent'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div className="flex items-start gap-3">
|
||||||
|
<div className="mt-1">
|
||||||
|
<FaMapMarkerAlt
|
||||||
|
className={classNames(
|
||||||
|
'w-5 h-5',
|
||||||
|
selectedLocation?.id === location.id
|
||||||
|
? 'text-blue-600'
|
||||||
|
: 'text-gray-400'
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="flex-1 min-w-0">
|
||||||
|
<h3
|
||||||
|
className={classNames(
|
||||||
|
'font-semibold mb-1',
|
||||||
|
selectedLocation?.id === location.id
|
||||||
|
? 'text-blue-600 dark:text-blue-400'
|
||||||
|
: 'text-gray-900 dark:text-gray-100'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{location.name}
|
||||||
|
</h3>
|
||||||
|
<p className="text-sm text-gray-600 dark:text-gray-400 line-clamp-2">
|
||||||
|
{location.address}
|
||||||
|
</p>
|
||||||
|
<p className="text-xs text-gray-500 dark:text-gray-500 mt-1">
|
||||||
|
{location.lat.toFixed(4)}, {location.lng.toFixed(4)}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
{selectedLocation?.id === location.id && (
|
||||||
|
<div className="mt-1">
|
||||||
|
<div className="w-5 h-5 bg-blue-600 rounded-full flex items-center justify-center">
|
||||||
|
<svg className="w-3 h-3 text-white" fill="currentColor" viewBox="0 0 20 20">
|
||||||
|
<path
|
||||||
|
fillRule="evenodd"
|
||||||
|
d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z"
|
||||||
|
clipRule="evenodd"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Footer */}
|
||||||
|
<div className="flex items-center justify-between p-4 border-t border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-750">
|
||||||
|
<div className="text-sm text-gray-600 dark:text-gray-400">
|
||||||
|
{selectedLocation ? (
|
||||||
|
<span className="flex items-center gap-2">
|
||||||
|
<FaMapMarkerAlt className="w-4 h-4 text-blue-600" />
|
||||||
|
<span className="font-medium text-gray-900 dark:text-gray-100">
|
||||||
|
{selectedLocation.name}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
) : (
|
||||||
|
<span>{translate('::App.Platform.Intranet.SocialWall.LocationPicker.SelectLocation')}</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<button
|
||||||
|
onClick={onClose}
|
||||||
|
className="px-4 py-2 text-gray-700 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-700 rounded-lg transition-colors"
|
||||||
|
>
|
||||||
|
{translate('::Cancel')}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={handleConfirm}
|
||||||
|
disabled={!selectedLocation}
|
||||||
|
className="px-6 py-2 bg-blue-600 text-white font-medium rounded-lg hover:bg-blue-700 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors"
|
||||||
|
>
|
||||||
|
{translate('::ListForms.Wizard.Add')}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default LocationPicker
|
||||||
67
ui/src/views/intranet/SocialWall/MediaLightbox.tsx
Normal file
67
ui/src/views/intranet/SocialWall/MediaLightbox.tsx
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
import React from 'react'
|
||||||
|
import Lightbox from 'yet-another-react-lightbox'
|
||||||
|
import 'yet-another-react-lightbox/styles.css'
|
||||||
|
import Video from 'yet-another-react-lightbox/plugins/video'
|
||||||
|
import Zoom from 'yet-another-react-lightbox/plugins/zoom'
|
||||||
|
import Counter from 'yet-another-react-lightbox/plugins/counter'
|
||||||
|
import 'yet-another-react-lightbox/plugins/counter.css'
|
||||||
|
import { SocialMediaDto } from '@/proxy/intranet/models'
|
||||||
|
|
||||||
|
interface MediaLightboxProps {
|
||||||
|
isOpen: boolean
|
||||||
|
onClose: () => void
|
||||||
|
media: SocialMediaDto
|
||||||
|
startIndex?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
const MediaLightbox: React.FC<MediaLightboxProps> = ({
|
||||||
|
isOpen,
|
||||||
|
onClose,
|
||||||
|
media,
|
||||||
|
startIndex = 0
|
||||||
|
}) => {
|
||||||
|
const slides = React.useMemo(() => {
|
||||||
|
if (media.type === 'video' && media.urls && media.urls.length > 0) {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
type: 'video' as const,
|
||||||
|
sources: [
|
||||||
|
{
|
||||||
|
src: media.urls[0],
|
||||||
|
type: 'video/mp4'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
const urls = media.urls || []
|
||||||
|
return urls.map((url) => ({
|
||||||
|
src: url
|
||||||
|
}))
|
||||||
|
}, [media])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Lightbox
|
||||||
|
open={isOpen}
|
||||||
|
close={onClose}
|
||||||
|
slides={slides}
|
||||||
|
index={startIndex}
|
||||||
|
plugins={[Video, Zoom, Counter]}
|
||||||
|
counter={{ container: { style: { top: 'unset', bottom: 0 } } }}
|
||||||
|
zoom={{
|
||||||
|
maxZoomPixelRatio: 3,
|
||||||
|
scrollToZoom: true
|
||||||
|
}}
|
||||||
|
video={{
|
||||||
|
controls: true,
|
||||||
|
autoPlay: false
|
||||||
|
}}
|
||||||
|
styles={{
|
||||||
|
container: { backgroundColor: 'rgba(0, 0, 0, 0.95)' }
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MediaLightbox
|
||||||
240
ui/src/views/intranet/SocialWall/MediaManager.tsx
Normal file
240
ui/src/views/intranet/SocialWall/MediaManager.tsx
Normal file
|
|
@ -0,0 +1,240 @@
|
||||||
|
import React, { useState } from 'react'
|
||||||
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
|
import { motion } from 'framer-motion'
|
||||||
|
import { FaTimes, FaLink, FaUpload } from 'react-icons/fa'
|
||||||
|
import classNames from 'classnames'
|
||||||
|
import { SocialMediaDto } from '@/proxy/intranet/models'
|
||||||
|
|
||||||
|
interface MediaManagerProps {
|
||||||
|
media: SocialMediaDto[]
|
||||||
|
onChange: (media: SocialMediaDto[]) => void
|
||||||
|
onClose: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const MediaManager: React.FC<MediaManagerProps> = ({ media, onChange, onClose }) => {
|
||||||
|
const { translate } = useLocalization();
|
||||||
|
const [activeTab, setActiveTab] = useState<'upload' | 'url'>('upload')
|
||||||
|
const [urlInput, setUrlInput] = useState('')
|
||||||
|
const [mediaType, setMediaType] = useState<'image' | 'video'>('image')
|
||||||
|
|
||||||
|
const handleFileSelect = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const files = e.target.files
|
||||||
|
if (!files) return
|
||||||
|
|
||||||
|
const newMedia: SocialMediaDto[] = Array.from(files).map((file) => ({
|
||||||
|
id: Math.random().toString(36).substr(2, 9),
|
||||||
|
type: file.type.startsWith('video/') ? 'video' : 'image',
|
||||||
|
urls: [URL.createObjectURL(file)],
|
||||||
|
file
|
||||||
|
}))
|
||||||
|
|
||||||
|
onChange([...media, ...newMedia])
|
||||||
|
e.target.value = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleUrlAdd = () => {
|
||||||
|
if (!urlInput.trim()) return
|
||||||
|
|
||||||
|
const newMedia: SocialMediaDto = {
|
||||||
|
id: Math.random().toString(36).substr(2, 9),
|
||||||
|
type: mediaType,
|
||||||
|
urls: [urlInput]
|
||||||
|
}
|
||||||
|
|
||||||
|
onChange([...media, newMedia])
|
||||||
|
setUrlInput('')
|
||||||
|
}
|
||||||
|
|
||||||
|
const removeMedia = (id: string | undefined) => {
|
||||||
|
if (!id) return
|
||||||
|
onChange(media.filter((m) => m.id !== id))
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, scale: 0.9 }}
|
||||||
|
animate={{ opacity: 1, scale: 1 }}
|
||||||
|
exit={{ opacity: 0, scale: 0.9 }}
|
||||||
|
className="bg-white dark:bg-gray-800 rounded-lg shadow-xl w-full max-w-3xl max-h-[90vh] overflow-hidden"
|
||||||
|
>
|
||||||
|
{/* Header */}
|
||||||
|
<div className="flex items-center justify-between p-4 border-b border-gray-200 dark:border-gray-700">
|
||||||
|
<h2 className="text-xl font-bold text-gray-900 dark:text-white">{translate('::App.Platform.Intranet.SocialWall.MediaManager.AddMedia')}</h2>
|
||||||
|
<button
|
||||||
|
onClick={onClose}
|
||||||
|
className="p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-full transition-colors"
|
||||||
|
>
|
||||||
|
<FaTimes className="w-5 h-5 text-gray-500 dark:text-gray-400" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Tabs */}
|
||||||
|
<div className="flex border-b border-gray-200 dark:border-gray-700 px-4">
|
||||||
|
<button
|
||||||
|
onClick={() => setActiveTab('upload')}
|
||||||
|
className={classNames(
|
||||||
|
'px-4 py-3 font-medium border-b-2 transition-colors',
|
||||||
|
activeTab === 'upload'
|
||||||
|
? 'border-blue-600 text-blue-600'
|
||||||
|
: 'border-transparent text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-200'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<FaUpload className="w-5 h-5" />
|
||||||
|
<span>{translate('::App.Platform.Intranet.SocialWall.MediaManager.SelectFromComputer')}</span>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => setActiveTab('url')}
|
||||||
|
className={classNames(
|
||||||
|
'px-4 py-3 font-medium border-b-2 transition-colors',
|
||||||
|
activeTab === 'url'
|
||||||
|
? 'border-blue-600 text-blue-600'
|
||||||
|
: 'border-transparent text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-200'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<FaLink className="w-5 h-5" />
|
||||||
|
<span>{translate('::App.Platform.Intranet.SocialWall.MediaManager.AddByUrl')}</span>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Content */}
|
||||||
|
<div className="p-4 overflow-y-auto max-h-[calc(90vh-240px)]">
|
||||||
|
{activeTab === 'upload' ? (
|
||||||
|
<div>
|
||||||
|
<label className="block">
|
||||||
|
<div className="border-2 border-dashed border-gray-300 dark:border-gray-600 rounded-lg p-8 text-center hover:border-blue-500 hover:bg-blue-50 dark:hover:bg-blue-900/20 transition-colors cursor-pointer">
|
||||||
|
<FaUpload className="w-12 h-12 mx-auto mb-4 text-gray-400" />
|
||||||
|
<p className="text-gray-700 dark:text-gray-300 font-medium mb-1">
|
||||||
|
{translate('::App.Platform.Intranet.SocialWall.MediaManager.ClickToSelectFile')}
|
||||||
|
</p>
|
||||||
|
<p className="text-sm text-gray-500 dark:text-gray-400">
|
||||||
|
{translate('::App.Platform.Intranet.SocialWall.MediaManager.ImageOrVideoFormats')}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
type="file"
|
||||||
|
accept="image/*,video/*"
|
||||||
|
multiple
|
||||||
|
onChange={handleFileSelect}
|
||||||
|
className="hidden"
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div>
|
||||||
|
<div className="mb-4">
|
||||||
|
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||||
|
{translate('::App.Platform.Intranet.SocialWall.MediaManager.MediaType')}
|
||||||
|
</label>
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<button
|
||||||
|
onClick={() => setMediaType('image')}
|
||||||
|
className={classNames(
|
||||||
|
'flex-1 py-2 px-4 rounded-lg font-medium transition-colors',
|
||||||
|
mediaType === 'image'
|
||||||
|
? 'bg-blue-600 text-white'
|
||||||
|
: 'bg-gray-100 dark:bg-gray-700 text-gray-700 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-600'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{translate('::App.Platform.Intranet.SocialWall.MediaManager.Image')}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => setMediaType('video')}
|
||||||
|
className={classNames(
|
||||||
|
'flex-1 py-2 px-4 rounded-lg font-medium transition-colors',
|
||||||
|
mediaType === 'video'
|
||||||
|
? 'bg-blue-600 text-white'
|
||||||
|
: 'bg-gray-100 dark:bg-gray-700 text-gray-700 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-600'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{translate('::App.Platform.Intranet.SocialWall.MediaManager.Video')}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<input
|
||||||
|
type="url"
|
||||||
|
value={urlInput}
|
||||||
|
onChange={(e) => setUrlInput(e.target.value)}
|
||||||
|
onKeyPress={(e) => e.key === 'Enter' && handleUrlAdd()}
|
||||||
|
placeholder={mediaType === 'image' ? translate('::App.Platform.Intranet.SocialWall.MediaManager.EnterImageUrl') : translate('::App.Platform.Intranet.SocialWall.MediaManager.EnterVideoUrl')}
|
||||||
|
className="flex-1 px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
onClick={handleUrlAdd}
|
||||||
|
disabled={!urlInput.trim()}
|
||||||
|
className="px-6 py-2 bg-blue-600 text-white font-medium rounded-lg hover:bg-blue-700 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors"
|
||||||
|
>
|
||||||
|
{translate('::ListForms.Wizard.Add')}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Media Preview */}
|
||||||
|
{media.length > 0 && (
|
||||||
|
<div className="mt-6">
|
||||||
|
<h3 className="text-sm font-medium text-gray-700 dark:text-gray-300 mb-3">
|
||||||
|
{translate('::App.Platform.Intranet.SocialWall.MediaManager.AddedMedia')} ({media.length})
|
||||||
|
</h3>
|
||||||
|
<div className="grid grid-cols-4 gap-3">
|
||||||
|
{media.map((item) => (
|
||||||
|
<div key={item.id} className="relative group">
|
||||||
|
{item.type === 'image' ? (
|
||||||
|
<img
|
||||||
|
src={item.urls?.[0]}
|
||||||
|
alt="Media preview"
|
||||||
|
className="w-full h-24 object-cover rounded-lg"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<div className="w-full h-24 bg-gray-900 rounded-lg flex items-center justify-center">
|
||||||
|
<video src={item.urls?.[0]} className="w-full h-full object-cover rounded-lg" />
|
||||||
|
<div className="absolute inset-0 flex items-center justify-center">
|
||||||
|
<div className="w-10 h-10 bg-black bg-opacity-50 rounded-full flex items-center justify-center">
|
||||||
|
<div className="w-0 h-0 border-t-8 border-t-transparent border-l-12 border-l-white border-b-8 border-b-transparent ml-1"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<button
|
||||||
|
onClick={() => removeMedia(item.id)}
|
||||||
|
className="absolute -top-2 -right-2 p-1 bg-red-600 text-white rounded-full opacity-0 group-hover:opacity-100 transition-opacity"
|
||||||
|
>
|
||||||
|
<FaTimes className="w-4 h-4" />
|
||||||
|
</button>
|
||||||
|
<div className="absolute bottom-1 left-1 px-2 py-0.5 bg-black bg-opacity-70 text-white text-xs rounded">
|
||||||
|
{item.type === 'image' ? translate('::App.Platform.Intranet.SocialWall.MediaManager.ImageIcon') : translate('::App.Platform.Intranet.SocialWall.MediaManager.VideoIcon')}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Footer */}
|
||||||
|
<div className="flex items-center justify-end gap-2 p-4 border-t border-gray-200 dark:border-gray-700">
|
||||||
|
<button
|
||||||
|
onClick={onClose}
|
||||||
|
className="px-4 py-2 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors"
|
||||||
|
>
|
||||||
|
{translate('::Cancel')}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={onClose}
|
||||||
|
disabled={media.length === 0}
|
||||||
|
className="px-6 py-2 bg-blue-600 text-white font-medium rounded-lg hover:bg-blue-700 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors"
|
||||||
|
>
|
||||||
|
{translate('::App.Platform.Intranet.SocialWall.MediaManager.Done', { count: media.length })}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MediaManager
|
||||||
409
ui/src/views/intranet/SocialWall/PostItem.tsx
Normal file
409
ui/src/views/intranet/SocialWall/PostItem.tsx
Normal file
|
|
@ -0,0 +1,409 @@
|
||||||
|
import React, { useState, useRef, useEffect } from 'react'
|
||||||
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
|
import { motion, AnimatePresence } from 'framer-motion'
|
||||||
|
import classNames from 'classnames'
|
||||||
|
import dayjs from 'dayjs'
|
||||||
|
import relativeTime from 'dayjs/plugin/relativeTime'
|
||||||
|
import 'dayjs/locale/tr'
|
||||||
|
import { FaHeart, FaRegHeart, FaRegCommentAlt, FaTrash, FaPaperPlane } from 'react-icons/fa'
|
||||||
|
import MediaLightbox from './MediaLightbox'
|
||||||
|
import LocationMap from './LocationMap'
|
||||||
|
import UserProfileCard from './UserProfileCard'
|
||||||
|
import { SocialPostDto } from '@/proxy/intranet/models'
|
||||||
|
import { useStoreState } from '@/store/store'
|
||||||
|
import { AVATAR_URL } from '@/constants/app.constant'
|
||||||
|
import { Avatar } from '@/components/ui'
|
||||||
|
|
||||||
|
dayjs.extend(relativeTime)
|
||||||
|
dayjs.locale('tr')
|
||||||
|
|
||||||
|
interface PostItemProps {
|
||||||
|
post: SocialPostDto
|
||||||
|
onLike: (postId: string) => void
|
||||||
|
onComment: (postId: string, content: string) => void
|
||||||
|
onDelete: (postId: string) => void
|
||||||
|
onVote: (postId: string, optionId: string) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const PostItem: React.FC<PostItemProps> = ({ post, onLike, onComment, onDelete, onVote }) => {
|
||||||
|
const { translate } = useLocalization()
|
||||||
|
const [showComments, setShowComments] = useState(false)
|
||||||
|
const [commentText, setCommentText] = useState('')
|
||||||
|
const [showAllImages, setShowAllImages] = useState(false)
|
||||||
|
const [lightboxOpen, setLightboxOpen] = useState(false)
|
||||||
|
const [lightboxIndex, setLightboxIndex] = useState(0)
|
||||||
|
const [showUserCard, setShowUserCard] = useState(false)
|
||||||
|
const [hoveredCommentAuthor, setHoveredCommentAuthor] = useState<string | null>(null)
|
||||||
|
const videoRef = useRef<HTMLVideoElement>(null)
|
||||||
|
const { user } = useStoreState((state) => state.auth)
|
||||||
|
|
||||||
|
// Intersection Observer for video autoplay/pause
|
||||||
|
useEffect(() => {
|
||||||
|
const video = videoRef.current
|
||||||
|
if (!video) return
|
||||||
|
|
||||||
|
const observer = new IntersectionObserver(
|
||||||
|
(entries) => {
|
||||||
|
entries.forEach((entry) => {
|
||||||
|
if (entry.isIntersecting) {
|
||||||
|
// Video ekranda görünür - oynat
|
||||||
|
video.play().catch((err) => {
|
||||||
|
console.log('Video autoplay failed:', err)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// Video ekrandan çıktı - durdur
|
||||||
|
video.pause()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
threshold: 0.5, // Video %50 görünür olduğunda oynat
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
observer.observe(video)
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
observer.disconnect()
|
||||||
|
}
|
||||||
|
}, [post.media?.type])
|
||||||
|
|
||||||
|
const handleSubmitComment = (e: React.FormEvent) => {
|
||||||
|
e.preventDefault()
|
||||||
|
if (commentText.trim()) {
|
||||||
|
onComment(post.id, commentText)
|
||||||
|
setCommentText('')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getImageLayout = (images: string[]) => {
|
||||||
|
const count = images.length
|
||||||
|
if (count === 1) return 'single'
|
||||||
|
if (count === 2) return 'double'
|
||||||
|
if (count === 3) return 'triple'
|
||||||
|
return 'multiple'
|
||||||
|
}
|
||||||
|
|
||||||
|
const renderMedia = () => {
|
||||||
|
if (!post.media) return null
|
||||||
|
|
||||||
|
switch (post.media.type) {
|
||||||
|
case 'image':
|
||||||
|
if (post.media.urls && post.media.urls.length > 0) {
|
||||||
|
const layout = getImageLayout(post.media.urls)
|
||||||
|
const displayImages = showAllImages ? post.media.urls : post.media.urls.slice(0, 4)
|
||||||
|
const hasMore = post.media.urls.length > 4
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
className={classNames('mt-3 rounded-lg overflow-hidden', {
|
||||||
|
'grid gap-1': layout !== 'single',
|
||||||
|
'grid-cols-2': layout === 'double' || layout === 'multiple',
|
||||||
|
'grid-cols-3': layout === 'triple',
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{displayImages.map((url, index) => (
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
className={classNames('relative', {
|
||||||
|
'col-span-2': layout === 'triple' && index === 0,
|
||||||
|
'aspect-video': layout === 'single',
|
||||||
|
'aspect-square': layout !== 'single',
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src={url}
|
||||||
|
alt={`Post image ${index + 1}`}
|
||||||
|
className="w-full h-full object-cover cursor-pointer hover:opacity-90 transition-opacity"
|
||||||
|
onClick={() => {
|
||||||
|
setLightboxIndex(index)
|
||||||
|
setLightboxOpen(true)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{hasMore && index === 3 && !showAllImages && post.media?.urls && (
|
||||||
|
<div
|
||||||
|
className="absolute inset-0 bg-black bg-opacity-60 flex items-center justify-center cursor-pointer"
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation()
|
||||||
|
setShowAllImages(true)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span className="text-white text-2xl font-bold">
|
||||||
|
+{post.media.urls.length - 4}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<MediaLightbox
|
||||||
|
isOpen={lightboxOpen}
|
||||||
|
onClose={() => setLightboxOpen(false)}
|
||||||
|
media={{ type: 'image', urls: post.media.urls }}
|
||||||
|
startIndex={lightboxIndex}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'video':
|
||||||
|
if (post.media.urls && post.media.urls.length > 0) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
className="mt-3 rounded-lg overflow-hidden cursor-pointer relative group"
|
||||||
|
onClick={() => setLightboxOpen(true)}
|
||||||
|
>
|
||||||
|
<video
|
||||||
|
ref={videoRef}
|
||||||
|
src={post.media.urls[0]}
|
||||||
|
className="w-full max-h-96 object-cover"
|
||||||
|
controls
|
||||||
|
playsInline
|
||||||
|
muted
|
||||||
|
loop
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<MediaLightbox
|
||||||
|
isOpen={lightboxOpen}
|
||||||
|
onClose={() => setLightboxOpen(false)}
|
||||||
|
media={{ type: 'video', urls: [post.media.urls[0]] }}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'poll':
|
||||||
|
if (post.media.pollQuestion && post.media.pollOptions) {
|
||||||
|
const isExpired = post.media.pollEndsAt ? new Date() > post.media.pollEndsAt : false
|
||||||
|
const hasVoted = !!post.media.pollUserVoteId
|
||||||
|
const totalVotes = post.media.pollTotalVotes || 0
|
||||||
|
const pollUserVoteId = post.media.pollUserVoteId
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="mt-3 p-4 bg-gray-50 dark:bg-gray-700 rounded-lg">
|
||||||
|
<h4 className="font-medium text-gray-900 dark:text-gray-100 mb-3">
|
||||||
|
{post.media.pollQuestion}
|
||||||
|
</h4>
|
||||||
|
<div className="space-y-2">
|
||||||
|
{post.media.pollOptions.map((option) => {
|
||||||
|
const percentage = totalVotes > 0 ? (option.votes / totalVotes) * 100 : 0
|
||||||
|
const isSelected = pollUserVoteId === option.id
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
key={option.id}
|
||||||
|
onClick={() => !hasVoted && !isExpired && onVote(post.id, option.id)}
|
||||||
|
disabled={hasVoted || isExpired}
|
||||||
|
className={classNames(
|
||||||
|
'w-full text-left p-3 rounded-lg relative overflow-hidden transition-all',
|
||||||
|
{
|
||||||
|
'bg-blue-100 dark:bg-blue-900 border-2 border-blue-500': isSelected,
|
||||||
|
'bg-white dark:bg-gray-600 hover:bg-gray-50 dark:hover:bg-gray-500':
|
||||||
|
!isSelected && !hasVoted && !isExpired,
|
||||||
|
'bg-white dark:bg-gray-600 cursor-not-allowed': hasVoted || isExpired,
|
||||||
|
},
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{hasVoted && (
|
||||||
|
<div
|
||||||
|
className="absolute inset-y-0 left-0 bg-blue-200 dark:bg-blue-800 transition-all"
|
||||||
|
style={{ width: `${percentage}%` }}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<div className="relative z-10 flex justify-between items-center">
|
||||||
|
<span className="font-medium text-gray-900 dark:text-gray-100">
|
||||||
|
{option.text}
|
||||||
|
</span>
|
||||||
|
{hasVoted && (
|
||||||
|
<span className="text-sm font-semibold text-gray-700 dark:text-gray-200">
|
||||||
|
{percentage.toFixed(0)}%
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
<div className="mt-3 text-sm text-gray-600 dark:text-gray-400">
|
||||||
|
{totalVotes} oy •{' '}
|
||||||
|
{isExpired
|
||||||
|
? 'Sona erdi'
|
||||||
|
: post.media.pollEndsAt
|
||||||
|
? dayjs(post.media.pollEndsAt).fromNow() + ' bitiyor'
|
||||||
|
: ''}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
exit={{ opacity: 0, y: -20 }}
|
||||||
|
className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 p-4 mb-4"
|
||||||
|
>
|
||||||
|
{/* Header */}
|
||||||
|
<div className="flex items-start justify-between mb-3">
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<div
|
||||||
|
className="relative"
|
||||||
|
onMouseEnter={() => setShowUserCard(true)}
|
||||||
|
onMouseLeave={() => setShowUserCard(false)}
|
||||||
|
>
|
||||||
|
<Avatar size={32} shape="circle" src={AVATAR_URL(post.user.id, post.user.tenantId)} />
|
||||||
|
<AnimatePresence>
|
||||||
|
{showUserCard && (
|
||||||
|
<UserProfileCard
|
||||||
|
user={{
|
||||||
|
id: post.user.id || '',
|
||||||
|
name: post.user.fullName || '',
|
||||||
|
title: post.user.jobPositions?.[0]?.name || '',
|
||||||
|
email: post.user.email,
|
||||||
|
phoneNumber: post.user.phoneNumber,
|
||||||
|
department: post.user.departments?.[0]?.name,
|
||||||
|
tenantId: post.user.tenantId || '',
|
||||||
|
}}
|
||||||
|
position="bottom"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 className="text-sm text-gray-900 dark:text-gray-100">{post.user.fullName}</h3>
|
||||||
|
<p className="text-sm text-gray-600 dark:text-gray-400">
|
||||||
|
{post.user.jobPositions?.[0]?.name || ''} • {dayjs(post.creationTime).fromNow()}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{post.isOwnPost && (
|
||||||
|
<button
|
||||||
|
onClick={() => onDelete(post.id)}
|
||||||
|
className="p-2 text-gray-500 hover:text-red-600 hover:bg-red-50 dark:hover:bg-red-900/20 rounded-full transition-colors"
|
||||||
|
title={translate('::App.Platform.Intranet.SocialWall.PostItem.DeletePost')}
|
||||||
|
>
|
||||||
|
<FaTrash className="w-5 h-5" />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Content */}
|
||||||
|
<div className="mb-3">
|
||||||
|
<p className="text-gray-800 dark:text-gray-200 whitespace-pre-wrap">{post.content}</p>
|
||||||
|
{renderMedia()}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Actions */}
|
||||||
|
<div className="flex items-center gap-6 pt-3 border-t border-gray-100 dark:border-gray-700">
|
||||||
|
<button
|
||||||
|
onClick={() => onLike(post.id)}
|
||||||
|
className={classNames(
|
||||||
|
'flex items-center gap-2 transition-colors',
|
||||||
|
post.isLiked
|
||||||
|
? 'text-red-600 hover:text-red-700'
|
||||||
|
: 'text-gray-600 dark:text-gray-400 hover:text-red-600',
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{post.isLiked ? <FaHeart className="w-5 h-5" /> : <FaRegHeart className="w-5 h-5" />}
|
||||||
|
<span className="text-sm font-medium">{post.likeCount}</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
onClick={() => setShowComments(!showComments)}
|
||||||
|
className="flex items-center gap-2 text-gray-600 dark:text-gray-400 hover:text-blue-600 transition-colors"
|
||||||
|
>
|
||||||
|
<FaRegCommentAlt className="w-5 h-5" />
|
||||||
|
<span className="text-sm font-medium">{post.comments.length}</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Comments Section */}
|
||||||
|
<AnimatePresence>
|
||||||
|
{showComments && (
|
||||||
|
<motion.div
|
||||||
|
initial={{ height: 0, opacity: 0 }}
|
||||||
|
animate={{ height: 'auto', opacity: 1 }}
|
||||||
|
exit={{ height: 0, opacity: 0 }}
|
||||||
|
className="mt-4 pt-4 border-t border-gray-100 dark:border-gray-700"
|
||||||
|
>
|
||||||
|
{/* Comment Form */}
|
||||||
|
<form onSubmit={handleSubmitComment} className="mb-4">
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={commentText}
|
||||||
|
onChange={(e) => setCommentText(e.target.value)}
|
||||||
|
placeholder={translate(
|
||||||
|
'::App.Platform.Intranet.SocialWall.PostItem.CommentPlaceholder',
|
||||||
|
)}
|
||||||
|
className="flex-1 px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-full bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
disabled={!commentText.trim()}
|
||||||
|
className="p-2 bg-blue-600 text-white rounded-full hover:bg-blue-700 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors"
|
||||||
|
>
|
||||||
|
<FaPaperPlane className="w-5 h-5" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{/* Comments List */}
|
||||||
|
<div className="space-y-3">
|
||||||
|
{post.comments.map((comment) => (
|
||||||
|
<div key={comment.id} className="flex gap-3">
|
||||||
|
<div
|
||||||
|
className="relative"
|
||||||
|
onMouseEnter={() => setHoveredCommentAuthor(comment.id)}
|
||||||
|
onMouseLeave={() => setHoveredCommentAuthor(null)}
|
||||||
|
>
|
||||||
|
<Avatar
|
||||||
|
size={32}
|
||||||
|
shape="circle"
|
||||||
|
src={AVATAR_URL(comment.creator.id, comment.creator.tenantId)}
|
||||||
|
/>
|
||||||
|
<AnimatePresence>
|
||||||
|
{hoveredCommentAuthor === comment.id && (
|
||||||
|
<UserProfileCard
|
||||||
|
user={{
|
||||||
|
id: comment.creator.id || '',
|
||||||
|
name: comment.creator.fullName || '',
|
||||||
|
title: comment.creator.jobPositions?.[0]?.name || '',
|
||||||
|
tenantId: comment.creator.tenantId || '',
|
||||||
|
}}
|
||||||
|
position="bottom"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
|
</div>
|
||||||
|
<div className="flex-1">
|
||||||
|
<div className="bg-gray-100 dark:bg-gray-700 rounded-lg px-4 py-2">
|
||||||
|
<h4 className="font-semibold text-sm text-gray-900 dark:text-gray-100">
|
||||||
|
{comment.creator.fullName}
|
||||||
|
</h4>
|
||||||
|
<p className="text-sm text-gray-800 dark:text-gray-200">{comment.content}</p>
|
||||||
|
</div>
|
||||||
|
<p className="text-xs text-gray-500 dark:text-gray-400 mt-1 ml-4">
|
||||||
|
{dayjs(comment.creationTime).fromNow()}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
|
</motion.div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PostItem
|
||||||
100
ui/src/views/intranet/SocialWall/UserProfileCard.tsx
Normal file
100
ui/src/views/intranet/SocialWall/UserProfileCard.tsx
Normal file
|
|
@ -0,0 +1,100 @@
|
||||||
|
import React from 'react'
|
||||||
|
import { motion } from 'framer-motion'
|
||||||
|
import { FaEnvelope, FaPhone, FaBriefcase, FaMapMarkerAlt } from 'react-icons/fa'
|
||||||
|
import { AVATAR_URL } from '@/constants/app.constant'
|
||||||
|
import { Avatar } from '@/components/ui'
|
||||||
|
|
||||||
|
interface UserProfileCardProps {
|
||||||
|
user: {
|
||||||
|
id: string
|
||||||
|
name: string
|
||||||
|
title: string
|
||||||
|
email?: string
|
||||||
|
phoneNumber?: string
|
||||||
|
department?: string
|
||||||
|
location?: string
|
||||||
|
tenantId: string
|
||||||
|
}
|
||||||
|
position?: 'top' | 'bottom'
|
||||||
|
}
|
||||||
|
|
||||||
|
const UserProfileCard: React.FC<UserProfileCardProps> = ({ user, position = 'bottom' }) => {
|
||||||
|
return (
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, scale: 0.95, y: position === 'bottom' ? -10 : 10 }}
|
||||||
|
animate={{ opacity: 1, scale: 1, y: 0 }}
|
||||||
|
exit={{ opacity: 0, scale: 0.95, y: position === 'bottom' ? -10 : 10 }}
|
||||||
|
transition={{ duration: 0.15 }}
|
||||||
|
className={`absolute left-0 ${
|
||||||
|
position === 'bottom' ? 'top-full mt-2' : 'bottom-full mb-2'
|
||||||
|
} z-50 w-72 bg-white dark:bg-gray-800 rounded-lg shadow-xl border border-gray-200 dark:border-gray-700 p-4`}
|
||||||
|
>
|
||||||
|
{/* Header */}
|
||||||
|
<div className="flex items-start gap-3 mb-3 pb-3 border-b border-gray-200 dark:border-gray-700">
|
||||||
|
<Avatar size={48} shape="circle" src={AVATAR_URL(user.id, user.tenantId)} />
|
||||||
|
|
||||||
|
<div className="flex-1 min-w-0">
|
||||||
|
<h3 className="font-bold text-gray-900 dark:text-gray-100 text-lg mb-1">
|
||||||
|
{user.name}
|
||||||
|
</h3>
|
||||||
|
<p className="text-sm text-gray-600 dark:text-gray-400 flex items-center gap-1">
|
||||||
|
<FaBriefcase className="w-4 h-4" />
|
||||||
|
{user.title}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Contact Info */}
|
||||||
|
<div className="space-y-2">
|
||||||
|
{user.email && (
|
||||||
|
<div className="flex items-center gap-2 text-sm">
|
||||||
|
<FaEnvelope className="w-4 h-4 text-gray-400 flex-shrink-0" />
|
||||||
|
<a
|
||||||
|
href={`mailto:${user.email}`}
|
||||||
|
className="text-blue-600 dark:text-blue-400 hover:underline truncate"
|
||||||
|
>
|
||||||
|
{user.email}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{user.phoneNumber && (
|
||||||
|
<div className="flex items-center gap-2 text-sm">
|
||||||
|
<FaPhone className="w-4 h-4 text-gray-400 flex-shrink-0" />
|
||||||
|
<a
|
||||||
|
href={`tel:${user.phoneNumber}`}
|
||||||
|
className="text-gray-700 dark:text-gray-300 hover:text-blue-600 dark:hover:text-blue-400"
|
||||||
|
>
|
||||||
|
{user.phoneNumber}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{user.department && (
|
||||||
|
<div className="flex items-center gap-2 text-sm">
|
||||||
|
<FaBriefcase className="w-4 h-4 text-gray-400 flex-shrink-0" />
|
||||||
|
<span className="text-gray-700 dark:text-gray-300">{user.department}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{user.location && (
|
||||||
|
<div className="flex items-center gap-2 text-sm">
|
||||||
|
<FaMapMarkerAlt className="w-4 h-4 text-gray-400 flex-shrink-0" />
|
||||||
|
<span className="text-gray-700 dark:text-gray-300">{user.location}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Arrow indicator */}
|
||||||
|
<div
|
||||||
|
className={`absolute left-6 ${
|
||||||
|
position === 'bottom' ? '-top-2' : '-bottom-2'
|
||||||
|
} w-4 h-4 bg-white dark:bg-gray-800 border-l border-t border-gray-200 dark:border-gray-700 transform ${
|
||||||
|
position === 'bottom' ? 'rotate-45' : '-rotate-135'
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
|
</motion.div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UserProfileCard
|
||||||
222
ui/src/views/intranet/SocialWall/index.tsx
Normal file
222
ui/src/views/intranet/SocialWall/index.tsx
Normal file
|
|
@ -0,0 +1,222 @@
|
||||||
|
import React, { useState } from 'react'
|
||||||
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
|
import { AnimatePresence } from 'framer-motion'
|
||||||
|
import PostItem from './PostItem'
|
||||||
|
import CreatePost from './CreatePost'
|
||||||
|
import { SocialMediaDto, SocialPostDto } from '@/proxy/intranet/models'
|
||||||
|
import { useStoreState } from '@/store/store'
|
||||||
|
import { IdentityUserDto } from '@/proxy/admin/models'
|
||||||
|
|
||||||
|
const SocialWall: React.FC<{ posts: SocialPostDto[] }> = ({ posts }) => {
|
||||||
|
// const [posts, setPosts] = useState<SocialPost[]>(mockSocialPosts)
|
||||||
|
const [filter, setFilter] = useState<'all' | 'mine'>('all')
|
||||||
|
const { translate } = useLocalization()
|
||||||
|
|
||||||
|
// Ali Öztürk'ü "Siz" kullanıcısı olarak kullan
|
||||||
|
const { user } = useStoreState((state) => state.auth)
|
||||||
|
const currentUserAuthor: IdentityUserDto = {
|
||||||
|
id: user?.id || '0',
|
||||||
|
userName: user.userName || 'unknown',
|
||||||
|
name: user?.name || 'Siz',
|
||||||
|
email: user?.email || '',
|
||||||
|
isActive: true,
|
||||||
|
emailConfirmed: true,
|
||||||
|
phoneNumberConfirmed: true,
|
||||||
|
lockoutEnabled: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleCreatePost = (postData: {
|
||||||
|
content: string
|
||||||
|
location?: string
|
||||||
|
media?: {
|
||||||
|
type: 'mixed' | 'poll'
|
||||||
|
mediaItems?: SocialMediaDto[]
|
||||||
|
poll?: {
|
||||||
|
question: string
|
||||||
|
options: Array<{ text: string }>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}) => {
|
||||||
|
let mediaForPost = undefined
|
||||||
|
|
||||||
|
if (postData.media) {
|
||||||
|
if (postData.media.type === 'mixed' && postData.media.mediaItems) {
|
||||||
|
// Convert MediaItems to post format
|
||||||
|
const images = postData.media.mediaItems.filter((m) => m.type === 'image')
|
||||||
|
const videos = postData.media.mediaItems.filter((m) => m.type === 'video')
|
||||||
|
|
||||||
|
if (images.length > 0 && videos.length === 0) {
|
||||||
|
mediaForPost = {
|
||||||
|
type: 'image' as const,
|
||||||
|
urls: images.map((i) => i.urls?.[0]).filter((url) => url !== undefined) as string[],
|
||||||
|
}
|
||||||
|
} else if (videos.length > 0 && images.length === 0) {
|
||||||
|
mediaForPost = {
|
||||||
|
type: 'video' as const,
|
||||||
|
urls: videos[0].urls || [],
|
||||||
|
}
|
||||||
|
} else if (images.length > 0 || videos.length > 0) {
|
||||||
|
// Mixed media - use first image for now
|
||||||
|
mediaForPost = {
|
||||||
|
type: 'image' as const,
|
||||||
|
urls: images.map((i) => i.urls?.[0]).filter((url) => url !== undefined) as string[],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (postData.media.type === 'poll' && postData.media.poll) {
|
||||||
|
mediaForPost = {
|
||||||
|
type: 'poll' as const,
|
||||||
|
pollQuestion: postData.media.poll.question,
|
||||||
|
pollOptions: postData.media.poll.options.map((opt, index) => ({
|
||||||
|
id: `opt-${index}`,
|
||||||
|
text: opt.text,
|
||||||
|
votes: 0,
|
||||||
|
})),
|
||||||
|
pollTotalVotes: 0,
|
||||||
|
pollEndsAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const newPost: SocialPostDto = {
|
||||||
|
id: Date.now().toString(),
|
||||||
|
user: currentUserAuthor,
|
||||||
|
content: postData.content,
|
||||||
|
creationTime: new Date(),
|
||||||
|
media: mediaForPost,
|
||||||
|
locationJson: postData.location,
|
||||||
|
likeCount: 0,
|
||||||
|
isLiked: false,
|
||||||
|
likeUsers: [],
|
||||||
|
comments: [],
|
||||||
|
isOwnPost: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
// setPosts([newPost, ...posts])
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleLike = (postId: string) => {
|
||||||
|
// setPosts(
|
||||||
|
// posts.map((post) => {
|
||||||
|
// if (post.id === postId) {
|
||||||
|
// return {
|
||||||
|
// ...post,
|
||||||
|
// likeCount: post.isLiked ? post.likeCount - 1 : post.likeCount + 1,
|
||||||
|
// isLiked: !post.isLiked
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return post
|
||||||
|
// })
|
||||||
|
// )
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleComment = (postId: string, content: string) => {
|
||||||
|
// setPosts(
|
||||||
|
// posts.map((post) => {
|
||||||
|
// if (post.id === postId) {
|
||||||
|
// const commentAuthor = currentUserAuthor
|
||||||
|
// const newComment = {
|
||||||
|
// id: Date.now().toString(),
|
||||||
|
// creator: commentAuthor,
|
||||||
|
// content,
|
||||||
|
// creationTime: new Date()
|
||||||
|
// }
|
||||||
|
// return {
|
||||||
|
// ...post,
|
||||||
|
// comments: [...post.comments, newComment]
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return post
|
||||||
|
// })
|
||||||
|
// )
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDelete = (postId: string) => {
|
||||||
|
if (window.confirm(translate('::App.Platform.Intranet.SocialWall.DeleteConfirm'))) {
|
||||||
|
// setPosts(posts.filter((post) => post.id !== postId))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleVote = (postId: string, optionId: string) => {
|
||||||
|
// setPosts(
|
||||||
|
// posts.map((post) => {
|
||||||
|
// if (post.id === postId && post.media?.type === 'poll' && post.media.pollOptions) {
|
||||||
|
// // If user already voted, don't allow voting again
|
||||||
|
// if (post.media.pollUserVoteId) {
|
||||||
|
// return post
|
||||||
|
// }
|
||||||
|
// return {
|
||||||
|
// ...post,
|
||||||
|
// media: {
|
||||||
|
// ...post.media,
|
||||||
|
// pollOptions: post.media.pollOptions.map((opt) =>
|
||||||
|
// opt.id === optionId ? { ...opt, votes: opt.votes + 1 } : opt
|
||||||
|
// ),
|
||||||
|
// pollTotalVotes: (post.media.pollTotalVotes || 0) + 1,
|
||||||
|
// pollUserVoteId: optionId
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return post
|
||||||
|
// })
|
||||||
|
// )
|
||||||
|
}
|
||||||
|
|
||||||
|
const filteredPosts = filter === 'mine' ? posts.filter((post) => post.isOwnPost) : posts
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="mx-auto px-4">
|
||||||
|
{/* Filter Tabs */}
|
||||||
|
<div className="flex gap-4 mb-6 border-b border-gray-200 dark:border-gray-700">
|
||||||
|
<button
|
||||||
|
onClick={() => setFilter('all')}
|
||||||
|
className={`pb-3 px-1 border-b-2 transition-colors font-medium ${
|
||||||
|
filter === 'all'
|
||||||
|
? 'border-blue-600 text-blue-600'
|
||||||
|
: 'border-transparent text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-200'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{translate('::App.Platform.Intranet.SocialWall.AllPosts')}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => setFilter('mine')}
|
||||||
|
className={`pb-3 px-1 border-b-2 transition-colors font-medium ${
|
||||||
|
filter === 'mine'
|
||||||
|
? 'border-blue-600 text-blue-600'
|
||||||
|
: 'border-transparent text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-200'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{translate('::App.Platform.Intranet.SocialWall.MyPosts')}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Create Post */}
|
||||||
|
<CreatePost onCreatePost={handleCreatePost} />
|
||||||
|
|
||||||
|
{/* Posts Feed */}
|
||||||
|
<AnimatePresence>
|
||||||
|
{filteredPosts.length > 0 ? (
|
||||||
|
filteredPosts.map((post) => (
|
||||||
|
<PostItem
|
||||||
|
key={post.id}
|
||||||
|
post={post}
|
||||||
|
onLike={handleLike}
|
||||||
|
onComment={handleComment}
|
||||||
|
onDelete={handleDelete}
|
||||||
|
onVote={handleVote}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<div className="text-center py-12">
|
||||||
|
<p className="text-gray-500 dark:text-gray-400 text-lg">
|
||||||
|
{filter === 'mine'
|
||||||
|
? translate('::App.Platform.Intranet.SocialWall.NoMyPosts')
|
||||||
|
: translate('::App.Platform.Intranet.SocialWall.NoPosts')}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SocialWall
|
||||||
211
ui/src/views/intranet/widgets/AnnouncementModal.tsx
Normal file
211
ui/src/views/intranet/widgets/AnnouncementModal.tsx
Normal file
|
|
@ -0,0 +1,211 @@
|
||||||
|
import React from 'react'
|
||||||
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
|
import { motion } from 'framer-motion'
|
||||||
|
import { FaTimes, FaEye, FaClipboard } from 'react-icons/fa'
|
||||||
|
import { AnnouncementDto } from '@/proxy/intranet/models'
|
||||||
|
import useLocale from '@/utils/hooks/useLocale'
|
||||||
|
import { currentLocalDate } from '@/utils/dateUtils'
|
||||||
|
import Avatar from '@/components/ui/Avatar/Avatar'
|
||||||
|
import { AVATAR_URL } from '@/constants/app.constant'
|
||||||
|
|
||||||
|
interface AnnouncementModalProps {
|
||||||
|
announcement: AnnouncementDto
|
||||||
|
onClose: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const AnnouncementModal: React.FC<AnnouncementModalProps> = ({
|
||||||
|
announcement,
|
||||||
|
onClose,
|
||||||
|
}) => {
|
||||||
|
const { translate } = useLocalization()
|
||||||
|
const currentLocale = useLocale()
|
||||||
|
const getCategoryColor = (category: string) => {
|
||||||
|
const colors: Record<string, string> = {
|
||||||
|
general: 'bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300',
|
||||||
|
hr: 'bg-purple-100 dark:bg-purple-900/30 text-purple-700 dark:text-purple-300',
|
||||||
|
it: 'bg-orange-100 dark:bg-orange-900/30 text-orange-700 dark:text-orange-300',
|
||||||
|
event: 'bg-green-100 dark:bg-green-900/30 text-green-700 dark:text-green-300',
|
||||||
|
urgent: 'bg-red-100 dark:bg-red-900/30 text-red-700 dark:text-red-300',
|
||||||
|
}
|
||||||
|
return colors[category] || colors.general
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0 }}
|
||||||
|
animate={{ opacity: 1 }}
|
||||||
|
exit={{ opacity: 0 }}
|
||||||
|
className="fixed inset-0 bg-black/50 z-40"
|
||||||
|
onClick={onClose}
|
||||||
|
/>
|
||||||
|
<div className="fixed inset-0 z-50 flex items-center justify-center p-4 overflow-y-auto">
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, scale: 0.95, y: 20 }}
|
||||||
|
animate={{ opacity: 1, scale: 1, y: 0 }}
|
||||||
|
exit={{ opacity: 0, scale: 0.95, y: 20 }}
|
||||||
|
className="bg-white dark:bg-gray-800 rounded-lg shadow-xl max-w-3xl w-full"
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
>
|
||||||
|
{/* Header */}
|
||||||
|
<div className="p-4 border-b border-gray-200 dark:border-gray-700">
|
||||||
|
<div className="flex items-start justify-between">
|
||||||
|
<div className="flex-1">
|
||||||
|
<div className="flex items-center gap-3 mb-3">
|
||||||
|
<span
|
||||||
|
className={`px-3 py-1 text-xs font-medium rounded-full ${getCategoryColor(announcement.category)}`}
|
||||||
|
>
|
||||||
|
{announcement.category === 'general' &&
|
||||||
|
`📢 ${translate('::App.Platform.Intranet.AnnouncementDetailModal.Category.General')}`}
|
||||||
|
{announcement.category === 'hr' &&
|
||||||
|
`👥 ${translate('::App.Platform.Intranet.AnnouncementDetailModal.Category.HR')}`}
|
||||||
|
{announcement.category === 'it' &&
|
||||||
|
`💻 ${translate('::App.Platform.Intranet.AnnouncementDetailModal.Category.IT')}`}
|
||||||
|
{announcement.category === 'event' &&
|
||||||
|
`🎉 ${translate('::App.Platform.Intranet.AnnouncementDetailModal.Category.Event')}`}
|
||||||
|
{announcement.category === 'urgent' &&
|
||||||
|
`🚨 ${translate('::App.Platform.Intranet.AnnouncementDetailModal.Category.Urgent')}`}
|
||||||
|
</span>
|
||||||
|
{announcement.isPinned && (
|
||||||
|
<span className="text-yellow-500 text-sm">
|
||||||
|
📌 {translate('::App.Platform.Intranet.AnnouncementDetailModal.Pinned')}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<h2 className="text-2xl font-bold text-gray-900 dark:text-white">
|
||||||
|
{announcement.title}
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
onClick={onClose}
|
||||||
|
className="p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors"
|
||||||
|
>
|
||||||
|
<FaTimes className="w-6 h-6 text-gray-500" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Author Info */}
|
||||||
|
<div className="flex items-center gap-3 mt-4">
|
||||||
|
<Avatar
|
||||||
|
size={32}
|
||||||
|
shape="circle"
|
||||||
|
src={AVATAR_URL(announcement.user.id, announcement.user.tenantId)}
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<p className="font-semibold text-gray-900 dark:text-white">
|
||||||
|
{announcement.user.fullName}
|
||||||
|
</p>
|
||||||
|
<div className="flex items-center gap-3 text-sm text-gray-600 dark:text-gray-400">
|
||||||
|
<span>{currentLocalDate(announcement.publishDate, currentLocale || 'tr')}</span>
|
||||||
|
<span>•</span>
|
||||||
|
<span className="flex items-center gap-1">
|
||||||
|
<FaEye className="w-4 h-4" />
|
||||||
|
{announcement.viewCount}{' '}
|
||||||
|
{translate('::App.Platform.Intranet.AnnouncementDetailModal.Views')}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Content */}
|
||||||
|
<div className="p-6 max-h-[60vh] overflow-y-auto">
|
||||||
|
{/* Image if exists */}
|
||||||
|
{announcement.imageUrl && (
|
||||||
|
<img
|
||||||
|
src={announcement.imageUrl}
|
||||||
|
alt={announcement.title}
|
||||||
|
className="w-full rounded-lg mb-6"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Full Content */}
|
||||||
|
<div className="prose prose-sm dark:prose-invert max-w-none">
|
||||||
|
<p className="text-gray-700 dark:text-gray-300 whitespace-pre-line">
|
||||||
|
{announcement.content}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Attachments */}
|
||||||
|
{announcement.attachments && announcement.attachments.length > 0 && (
|
||||||
|
<div className="mt-6 pt-6 border-t border-gray-200 dark:border-gray-700">
|
||||||
|
<h3 className="text-sm font-semibold text-gray-900 dark:text-white mb-3 flex items-center gap-2">
|
||||||
|
<FaClipboard className="w-5 h-5" />
|
||||||
|
{translate('::App.Platform.Intranet.AnnouncementDetailModal.Attachments')} (
|
||||||
|
{announcement.attachments.length})
|
||||||
|
</h3>
|
||||||
|
<div className="space-y-2">
|
||||||
|
{announcement.attachments.map((attachment, idx) => (
|
||||||
|
<a
|
||||||
|
key={idx}
|
||||||
|
href={attachment.url}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="flex items-center gap-3 p-3 bg-gray-50 dark:bg-gray-700/50 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors"
|
||||||
|
>
|
||||||
|
<FaClipboard className="w-5 h-5 text-gray-400" />
|
||||||
|
<div className="flex-1 min-w-0">
|
||||||
|
<p className="text-sm font-medium text-gray-900 dark:text-white truncate">
|
||||||
|
{attachment.name}
|
||||||
|
</p>
|
||||||
|
<p className="text-xs text-gray-500 dark:text-gray-400">
|
||||||
|
{attachment.size}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<span className="text-sm text-blue-600 dark:text-blue-400">
|
||||||
|
{translate('::App.Platform.Intranet.AnnouncementDetailModal.Download')}
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Departments */}
|
||||||
|
{announcement.departments && announcement.departments.length > 0 && (
|
||||||
|
<div className="mt-6 pt-6 border-t border-gray-200 dark:border-gray-700">
|
||||||
|
<h3 className="text-sm font-semibold text-gray-900 dark:text-white mb-3">
|
||||||
|
{translate('::App.Platform.Intranet.AnnouncementDetailModal.TargetDepartments')}
|
||||||
|
</h3>
|
||||||
|
<div className="flex flex-wrap gap-2">
|
||||||
|
{announcement.departments?.map((dept, idx) => (
|
||||||
|
<span
|
||||||
|
key={idx}
|
||||||
|
className="px-3 py-1 bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300 text-sm rounded-full"
|
||||||
|
>
|
||||||
|
{dept}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Expiry Date */}
|
||||||
|
{announcement.expiryDate && (
|
||||||
|
<div className="mt-6 pt-6 border-t border-gray-200 dark:border-gray-700">
|
||||||
|
<p className="text-sm text-gray-600 dark:text-gray-400">
|
||||||
|
<span className="font-medium">
|
||||||
|
{translate('::App.Platform.Intranet.AnnouncementDetailModal.ExpiryDate')}:
|
||||||
|
</span>{' '}
|
||||||
|
{currentLocalDate(announcement.expiryDate, currentLocale || 'tr')}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Footer */}
|
||||||
|
<div className="p-6 border-t border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-700/50">
|
||||||
|
<button
|
||||||
|
onClick={onClose}
|
||||||
|
className="w-full px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg transition-colors"
|
||||||
|
>
|
||||||
|
{translate('::App.Platform.Close')}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AnnouncementModal
|
||||||
105
ui/src/views/intranet/widgets/Announcements.tsx
Normal file
105
ui/src/views/intranet/widgets/Announcements.tsx
Normal file
|
|
@ -0,0 +1,105 @@
|
||||||
|
import React from 'react'
|
||||||
|
import { FaBell, FaClipboardCheck, FaEye } from 'react-icons/fa'
|
||||||
|
import dayjs from 'dayjs'
|
||||||
|
import { AnnouncementDto } from '@/proxy/intranet/models'
|
||||||
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
|
import { Avatar } from '@/components/ui'
|
||||||
|
import { AVATAR_URL } from '@/constants/app.constant'
|
||||||
|
|
||||||
|
interface AnnouncementsProps {
|
||||||
|
announcements: AnnouncementDto[]
|
||||||
|
onAnnouncementClick: (announcement: AnnouncementDto) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const Announcements: React.FC<AnnouncementsProps> = ({ announcements, onAnnouncementClick }) => {
|
||||||
|
const pinnedAnnouncements = announcements.filter((a) => a.isPinned).slice(0, 3)
|
||||||
|
const { translate } = useLocalization()
|
||||||
|
|
||||||
|
const getCategoryColor = (category: string) => {
|
||||||
|
const colors: Record<string, string> = {
|
||||||
|
general: 'bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300',
|
||||||
|
hr: 'bg-purple-100 dark:bg-purple-900/30 text-purple-700 dark:text-purple-300',
|
||||||
|
it: 'bg-orange-100 dark:bg-orange-900/30 text-orange-700 dark:text-orange-300',
|
||||||
|
event: 'bg-green-100 dark:bg-green-900/30 text-green-700 dark:text-green-300',
|
||||||
|
urgent: 'bg-red-100 dark:bg-red-900/30 text-red-700 dark:text-red-300',
|
||||||
|
}
|
||||||
|
return colors[category] || colors.general
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
|
||||||
|
<div className="p-4 border-b border-gray-200 dark:border-gray-700">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<h2 className="text-base font-semibold text-gray-900 dark:text-white flex items-center gap-2">
|
||||||
|
<FaBell className="w-5 h-5" />
|
||||||
|
{translate('::App.Platform.Intranet.Widgets.Announcements.Title')}
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="divide-y divide-gray-200 dark:divide-gray-700">
|
||||||
|
{pinnedAnnouncements.map((announcement) => (
|
||||||
|
<div
|
||||||
|
key={announcement.id}
|
||||||
|
onClick={() => onAnnouncementClick(announcement)}
|
||||||
|
className="p-6 hover:bg-gray-50 dark:hover:bg-gray-700/50 cursor-pointer transition-colors"
|
||||||
|
>
|
||||||
|
<div className="flex items-start gap-4">
|
||||||
|
<div className="flex-1 min-w-0">
|
||||||
|
<div className="flex items-center gap-2 mb-2">
|
||||||
|
<h3 className="text-base font-semibold text-gray-900 dark:text-white">
|
||||||
|
{announcement.title}
|
||||||
|
</h3>
|
||||||
|
{announcement.category && (
|
||||||
|
<span
|
||||||
|
className={`px-2 py-1 text-center text-xs rounded-full ${getCategoryColor(announcement.category)}`}
|
||||||
|
>
|
||||||
|
{(() => {
|
||||||
|
const key = `::App.Platform.Intranet.Widgets.Announcements.Category.${announcement.category.charAt(0).toUpperCase() + announcement.category.slice(1)}`
|
||||||
|
const translated = translate(key)
|
||||||
|
return translated === key ? announcement.category : translated
|
||||||
|
})()}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<p className="text-sm text-gray-600 dark:text-gray-400 line-clamp-2">
|
||||||
|
{announcement.excerpt}
|
||||||
|
</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(announcement.user.id, announcement.user.tenantId)}
|
||||||
|
/>
|
||||||
|
<span>{announcement.user.fullName}</span>
|
||||||
|
<span>•</span>
|
||||||
|
<span>{dayjs(announcement.publishDate).fromNow()}</span>
|
||||||
|
<span>•</span>
|
||||||
|
<span className="flex items-center gap-1">
|
||||||
|
<FaEye className="w-3 h-3" />
|
||||||
|
{announcement.viewCount}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
|
||||||
|
{pinnedAnnouncements.length === 0 && (
|
||||||
|
<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">
|
||||||
|
<FaClipboardCheck className="w-8 h-8 text-gray-400" />
|
||||||
|
</div>
|
||||||
|
<h3 className="text-lg font-medium text-gray-900 dark:text-white mb-2">
|
||||||
|
{translate('::App.Platform.Intranet.Widgets.Announcements.NoActive')}
|
||||||
|
</h3>
|
||||||
|
<p className="text-sm text-gray-500 dark:text-gray-400">
|
||||||
|
{translate('::App.Platform.Intranet.Widgets.Announcements.WillAppearHere')}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Announcements
|
||||||
84
ui/src/views/intranet/widgets/RecentDocuments.tsx
Normal file
84
ui/src/views/intranet/widgets/RecentDocuments.tsx
Normal file
|
|
@ -0,0 +1,84 @@
|
||||||
|
import React from 'react'
|
||||||
|
import { FaFileAlt, FaDownload } from 'react-icons/fa'
|
||||||
|
import dayjs from 'dayjs'
|
||||||
|
import { DocumentDto } from '@/proxy/intranet/models'
|
||||||
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
|
import { getFileIcon, getFileType } from '@/proxy/intranet/utils'
|
||||||
|
|
||||||
|
const formatFileSize = (bytes: number): string => {
|
||||||
|
if (bytes === 0) return '0 B'
|
||||||
|
const k = 1024
|
||||||
|
const sizes = ['B', 'KB', 'MB', 'GB']
|
||||||
|
const i = Math.floor(Math.log(bytes) / Math.log(k))
|
||||||
|
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`
|
||||||
|
}
|
||||||
|
|
||||||
|
const RecentDocuments: React.FC<{ documents: DocumentDto[] }> = ({ documents }) => {
|
||||||
|
const { translate } = useLocalization();
|
||||||
|
return (
|
||||||
|
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
|
||||||
|
<div className="p-4 border-b border-gray-200 dark:border-gray-700">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<h2 className="text-base font-semibold text-gray-900 dark:text-white flex items-center gap-2">
|
||||||
|
<FaFileAlt className="w-5 h-5" />
|
||||||
|
{translate('::App.Platform.Intranet.Widgets.RecentDocuments.Title')}
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="divide-y divide-gray-200 dark:divide-gray-700">
|
||||||
|
{documents.length > 0 ? (
|
||||||
|
documents.slice(0, 3).map((doc) => (
|
||||||
|
<div
|
||||||
|
key={doc.id}
|
||||||
|
className="p-4 hover:bg-gray-50 dark:hover:bg-gray-700/50 transition-colors"
|
||||||
|
>
|
||||||
|
<div className="flex items-start gap-3">
|
||||||
|
<div className="p-2 bg-blue-100 dark:bg-blue-900/30 rounded-lg">
|
||||||
|
{getFileIcon(doc.extension)}
|
||||||
|
</div>
|
||||||
|
<div className="flex-1 min-w-0">
|
||||||
|
<h4 className="text-sm font-medium text-gray-900 dark:text-white truncate">
|
||||||
|
{doc.name}
|
||||||
|
</h4>
|
||||||
|
<p className="text-xs text-gray-600 dark:text-gray-400 mt-1">
|
||||||
|
{getFileType(doc.extension)}
|
||||||
|
<span className="mx-1">•</span>
|
||||||
|
{formatFileSize(doc.size)}
|
||||||
|
</p>
|
||||||
|
<div className="text-xs text-gray-500 dark:text-gray-400 mt-1 flex items-center gap-2">
|
||||||
|
<span>{dayjs(doc.modifiedAt).fromNow()}</span>
|
||||||
|
{doc.isReadOnly && (
|
||||||
|
<>
|
||||||
|
<span>•</span>
|
||||||
|
<span className="text-orange-500">🔒 {translate('::App.Platform.Intranet.Widgets.RecentDocuments.ReadOnly')}</span>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation()
|
||||||
|
const link = document.createElement('a')
|
||||||
|
link.href = `/cdn/${doc.path}`
|
||||||
|
link.download = doc.name
|
||||||
|
link.click()
|
||||||
|
}}
|
||||||
|
className="p-2 hover:bg-blue-100 dark:hover:bg-blue-900/30 rounded-lg transition-colors group"
|
||||||
|
title={translate('::App.Platform.Intranet.Widgets.RecentDocuments.Download')}
|
||||||
|
>
|
||||||
|
<FaDownload className="w-5 h-5 text-gray-600 dark:text-gray-400 group-hover:text-blue-600 dark:group-hover:text-blue-400 transition-colors" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<div className="p-4 text-center text-sm text-gray-500 dark:text-gray-400">
|
||||||
|
{translate('::App.Platform.Intranet.Widgets.RecentDocuments.NoDocuments')}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default RecentDocuments
|
||||||
275
ui/src/views/intranet/widgets/SurveyModal.tsx
Normal file
275
ui/src/views/intranet/widgets/SurveyModal.tsx
Normal file
|
|
@ -0,0 +1,275 @@
|
||||||
|
import React, { useState } from 'react'
|
||||||
|
import { motion } from 'framer-motion'
|
||||||
|
import { FaTimes } from 'react-icons/fa'
|
||||||
|
import { SurveyAnswerDto, SurveyDto, SurveyQuestionDto } from '@/proxy/intranet/models'
|
||||||
|
|
||||||
|
interface SurveyModalProps {
|
||||||
|
survey: SurveyDto
|
||||||
|
onClose: () => void
|
||||||
|
onSubmit: (answers: SurveyAnswerDto[]) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
|
const SurveyModal: React.FC<SurveyModalProps> = ({ survey, onClose, onSubmit }) => {
|
||||||
|
const { translate } = useLocalization();
|
||||||
|
const [answers, setAnswers] = useState<{ [questionId: string]: any }>({})
|
||||||
|
const [errors, setErrors] = useState<{ [questionId: string]: string }>({})
|
||||||
|
|
||||||
|
const handleAnswerChange = (questionId: string, value: any) => {
|
||||||
|
setAnswers((prev) => ({
|
||||||
|
...prev,
|
||||||
|
[questionId]: value,
|
||||||
|
}))
|
||||||
|
|
||||||
|
// Clear error when user provides an answer
|
||||||
|
if (errors[questionId]) {
|
||||||
|
setErrors((prev) => ({
|
||||||
|
...prev,
|
||||||
|
[questionId]: '',
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const validateAnswers = (): boolean => {
|
||||||
|
const newErrors: { [questionId: string]: string } = {}
|
||||||
|
|
||||||
|
survey.questions.forEach((question) => {
|
||||||
|
if (question.isRequired && (!answers[question.id] || answers[question.id] === '')) {
|
||||||
|
newErrors[question.id] = translate('::App.Platform.Intranet.SurveyModal.RequiredField')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
setErrors(newErrors)
|
||||||
|
return Object.keys(newErrors).length === 0
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSubmit = (e: React.FormEvent) => {
|
||||||
|
e.preventDefault()
|
||||||
|
|
||||||
|
if (!validateAnswers()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const surveyAnswers: SurveyAnswerDto[] = survey.questions.map((question) => ({
|
||||||
|
questionId: question.id,
|
||||||
|
questionType: question.type,
|
||||||
|
value:
|
||||||
|
answers[question.id] ||
|
||||||
|
(question.type === 'multiple-choice' ? '' : question.type === 'rating' ? 0 : ''),
|
||||||
|
}))
|
||||||
|
|
||||||
|
onSubmit(surveyAnswers)
|
||||||
|
}
|
||||||
|
|
||||||
|
const renderQuestion = (question: SurveyQuestionDto, index: number) => {
|
||||||
|
const questionNumber = index + 1
|
||||||
|
const hasError = !!errors[question.id]
|
||||||
|
|
||||||
|
switch (question.type) {
|
||||||
|
case 'rating':
|
||||||
|
return (
|
||||||
|
<div key={question.id} className="space-y-2">
|
||||||
|
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||||
|
{questionNumber}. {question.questionText} {question.isRequired && '*'}
|
||||||
|
</label>
|
||||||
|
{hasError && (
|
||||||
|
<p className="text-sm text-red-600 dark:text-red-400">{errors[question.id]}</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
|
||||||
|
case 'multiple-choice':
|
||||||
|
return (
|
||||||
|
<div key={question.id} className="space-y-2">
|
||||||
|
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||||
|
{questionNumber}. {question.questionText} {question.isRequired && '*'}
|
||||||
|
</label>
|
||||||
|
<div className="space-y-2">
|
||||||
|
{question.options?.map((option) => (
|
||||||
|
<label
|
||||||
|
key={option.id}
|
||||||
|
className={`flex items-center gap-3 p-3 border rounded-lg cursor-pointer transition-colors ${
|
||||||
|
answers[question.id] === option.id
|
||||||
|
? 'bg-blue-50 border-blue-500 dark:bg-blue-900/20 dark:border-blue-400'
|
||||||
|
: 'border-gray-300 dark:border-gray-600 hover:bg-gray-50 dark:hover:bg-gray-700'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
name={`question-${question.id}`}
|
||||||
|
value={option.id}
|
||||||
|
checked={answers[question.id] === option.id}
|
||||||
|
onChange={(e) => handleAnswerChange(question.id, e.target.value)}
|
||||||
|
className="w-4 h-4 text-blue-600"
|
||||||
|
/>
|
||||||
|
<span className="text-sm text-gray-900 dark:text-white">{option.text}</span>
|
||||||
|
</label>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
{hasError && (
|
||||||
|
<p className="text-sm text-red-600 dark:text-red-400">{errors[question.id]}</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
|
||||||
|
case 'yes-no':
|
||||||
|
return (
|
||||||
|
<div key={question.id} className="space-y-2">
|
||||||
|
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||||
|
{questionNumber}. {question.questionText} {question.isRequired && '*'}
|
||||||
|
</label>
|
||||||
|
<div className="flex gap-4">
|
||||||
|
{['yes', 'no'].map((value) => (
|
||||||
|
<label
|
||||||
|
key={value}
|
||||||
|
className={`flex items-center gap-2 px-4 py-2 border rounded-lg cursor-pointer transition-colors ${
|
||||||
|
answers[question.id] === value
|
||||||
|
? 'bg-blue-50 border-blue-500 dark:bg-blue-900/20 dark:border-blue-400'
|
||||||
|
: 'border-gray-300 dark:border-gray-600 hover:bg-gray-50 dark:hover:bg-gray-700'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
name={`question-${question.id}`}
|
||||||
|
value={value}
|
||||||
|
checked={answers[question.id] === value}
|
||||||
|
onChange={(e) => handleAnswerChange(question.id, e.target.value)}
|
||||||
|
className="w-4 h-4 text-blue-600"
|
||||||
|
/>
|
||||||
|
<span className="text-sm text-gray-900 dark:text-white">
|
||||||
|
{value === 'yes' ? 'Evet' : 'Hayır'}
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
{hasError && (
|
||||||
|
<p className="text-sm text-red-600 dark:text-red-400">{errors[question.id]}</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
|
||||||
|
case 'text':
|
||||||
|
return (
|
||||||
|
<div key={question.id} className="space-y-2">
|
||||||
|
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||||
|
{questionNumber}. {question.questionText} {question.isRequired && '*'}
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={answers[question.id] || ''}
|
||||||
|
onChange={(e) => handleAnswerChange(question.id, e.target.value)}
|
||||||
|
className={`w-full px-4 py-2 border rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-blue-500 ${
|
||||||
|
hasError ? 'border-red-500' : 'border-gray-300 dark:border-gray-600'
|
||||||
|
}`}
|
||||||
|
placeholder={translate('::App.Platform.Intranet.SurveyModal.AnswerPlaceholder')}
|
||||||
|
/>
|
||||||
|
{hasError && (
|
||||||
|
<p className="text-sm text-red-600 dark:text-red-400">{errors[question.id]}</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
|
||||||
|
case 'textarea':
|
||||||
|
return (
|
||||||
|
<div key={question.id} className="space-y-2">
|
||||||
|
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||||
|
{questionNumber}. {question.questionText} {question.isRequired && '*'}
|
||||||
|
</label>
|
||||||
|
<textarea
|
||||||
|
rows={4}
|
||||||
|
value={answers[question.id] || ''}
|
||||||
|
onChange={(e) => handleAnswerChange(question.id, e.target.value)}
|
||||||
|
className={`w-full px-4 py-2 border rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-blue-500 ${
|
||||||
|
hasError ? 'border-red-500' : 'border-gray-300 dark:border-gray-600'
|
||||||
|
}`}
|
||||||
|
placeholder={translate('::App.Platform.Intranet.SurveyModal.CommentPlaceholder')}
|
||||||
|
/>
|
||||||
|
{hasError && (
|
||||||
|
<p className="text-sm text-red-600 dark:text-red-400">{errors[question.id]}</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
|
||||||
|
default:
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0 }}
|
||||||
|
animate={{ opacity: 1 }}
|
||||||
|
exit={{ opacity: 0 }}
|
||||||
|
className="fixed inset-0 bg-black/50 z-40"
|
||||||
|
onClick={onClose}
|
||||||
|
/>
|
||||||
|
<div className="fixed inset-0 z-50 flex items-center justify-center p-4">
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, scale: 0.95, y: 20 }}
|
||||||
|
animate={{ opacity: 1, scale: 1, y: 0 }}
|
||||||
|
exit={{ opacity: 0, scale: 0.95, y: 20 }}
|
||||||
|
className="bg-white dark:bg-gray-800 rounded-lg shadow-xl max-w-2xl w-full max-h-[90vh] overflow-y-auto"
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
>
|
||||||
|
<div className="p-4 border-b border-gray-200 dark:border-gray-700 flex items-center justify-between sticky top-0 bg-white dark:bg-gray-800 z-10">
|
||||||
|
<div>
|
||||||
|
<h2 className="text-xl font-semibold text-gray-900 dark:text-white">
|
||||||
|
{survey.title}
|
||||||
|
</h2>
|
||||||
|
<p className="text-sm text-gray-600 dark:text-gray-400 mt-1">{survey.description}</p>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
onClick={onClose}
|
||||||
|
className="p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors"
|
||||||
|
>
|
||||||
|
<FaTimes className="w-5 h-5 text-gray-500" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form onSubmit={handleSubmit} className="p-6 space-y-6">
|
||||||
|
<div className="space-y-6">
|
||||||
|
{survey.questions
|
||||||
|
.sort((a, b) => a.order - b.order)
|
||||||
|
.map((question, index) => renderQuestion(question, index))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{!survey.isAnonymous && (
|
||||||
|
<div className="bg-blue-50 dark:bg-blue-900/20 rounded-lg p-3">
|
||||||
|
<p className="text-sm text-blue-700 dark:text-blue-300">
|
||||||
|
ℹ️ Bu anket isim belirtilerek doldurulmaktadır. Yanıtlarınız kaydedilecektir.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{survey.isAnonymous && (
|
||||||
|
<div className="bg-green-50 dark:bg-green-900/20 rounded-lg p-3">
|
||||||
|
<p className="text-sm text-green-700 dark:text-green-300">
|
||||||
|
✅ Bu anket anonimdir. Kimlik bilgileriniz kaydedilmeyecektir.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="flex gap-3 pt-4 border-t border-gray-200 dark:border-gray-700">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={onClose}
|
||||||
|
className="flex-1 px-4 py-2 border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors"
|
||||||
|
>
|
||||||
|
{translate('::Cancel')}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
className="flex-1 px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg transition-colors"
|
||||||
|
>
|
||||||
|
{translate('::App.Platform.Intranet.SurveyModal.Submit')}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SurveyModal
|
||||||
149
ui/src/views/intranet/widgets/Surveys.tsx
Normal file
149
ui/src/views/intranet/widgets/Surveys.tsx
Normal file
|
|
@ -0,0 +1,149 @@
|
||||||
|
import React from 'react'
|
||||||
|
import { FaClipboardCheck, FaQuestionCircle, FaUsers, FaClock, FaArrowRight } from 'react-icons/fa'
|
||||||
|
import dayjs from 'dayjs'
|
||||||
|
import { SurveyDto } from '@/proxy/intranet/models'
|
||||||
|
import useLocale from '@/utils/hooks/useLocale'
|
||||||
|
import { currentLocalDate } from '@/utils/dateUtils'
|
||||||
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
|
|
||||||
|
interface SurveysProps {
|
||||||
|
surveys?: SurveyDto[]
|
||||||
|
onTakeSurvey: (survey: SurveyDto) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const Surveys: React.FC<SurveysProps> = ({ surveys, onTakeSurvey }) => {
|
||||||
|
const currentLocale = useLocale()
|
||||||
|
const { translate } = useLocalization()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="bg-gradient-to-br from-white to-gray-50 dark:from-gray-800 dark:to-gray-850 rounded-xl shadow-lg border border-gray-200/50 dark:border-gray-700/50 overflow-hidden">
|
||||||
|
{/* Header with gradient */}
|
||||||
|
|
||||||
|
<div className="p-4 border-b border-gray-200 dark:border-gray-700">
|
||||||
|
<h2 className="text-base font-semibold text-gray-900 dark:text-white flex items-center gap-2">
|
||||||
|
<FaClipboardCheck className="w-5 h-5" />
|
||||||
|
{translate('::App.Platform.Intranet.Widgets.ActiveSurveys.Title')}
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="p-6 space-y-4">
|
||||||
|
{surveys?.map((survey, index) => {
|
||||||
|
const daysLeft = dayjs(survey.deadline).diff(dayjs(), 'day')
|
||||||
|
const urgency = daysLeft <= 3 ? 'urgent' : daysLeft <= 7 ? 'warning' : 'normal'
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={survey.id}
|
||||||
|
onClick={() => onTakeSurvey(survey)}
|
||||||
|
className="group relative p-5 rounded-xl bg-white dark:bg-gray-750 border border-gray-200 dark:border-gray-600 hover:border-purple-300 dark:hover:border-purple-500 cursor-pointer transition-all duration-300 hover:shadow-lg hover:-translate-y-1"
|
||||||
|
>
|
||||||
|
{/* Background gradient on hover */}
|
||||||
|
<div className="absolute inset-0 bg-gradient-to-r from-purple-50 to-pink-50 dark:from-purple-900/10 dark:to-pink-900/10 rounded-xl opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
|
||||||
|
|
||||||
|
<div className="relative">
|
||||||
|
{/* Survey Title */}
|
||||||
|
<div className="flex items-start justify-between mb-3">
|
||||||
|
<h4 className="text-base font-semibold text-gray-900 dark:text-white group-hover:text-purple-700 dark:group-hover:text-purple-300 transition-colors">
|
||||||
|
{survey.title}
|
||||||
|
</h4>
|
||||||
|
<div
|
||||||
|
className={`px-2 py-1 text-center rounded-full text-xs font-medium ${
|
||||||
|
urgency === 'urgent'
|
||||||
|
? 'bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-300'
|
||||||
|
: urgency === 'warning'
|
||||||
|
? 'bg-amber-100 text-amber-700 dark:bg-amber-900/30 dark:text-amber-300'
|
||||||
|
: 'bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-300'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{daysLeft > 0 ? translate('::App.Platform.Intranet.Widgets.ActiveSurveys.DaysLeft', { count: daysLeft }) : translate('::App.Platform.Intranet.Widgets.ActiveSurveys.LastDay')}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Survey Stats */}
|
||||||
|
<div className="grid grid-cols-3 gap-4 mb-4">
|
||||||
|
<div className="flex items-center gap-2 text-sm">
|
||||||
|
<div className="p-1.5 bg-blue-100 dark:bg-blue-900/30 rounded-lg">
|
||||||
|
<FaQuestionCircle className="w-3 h-3 text-blue-600 dark:text-blue-400" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="text-xs text-gray-500 dark:text-gray-400">{translate('::App.Platform.Intranet.Widgets.ActiveSurveys.Questions')}</p>
|
||||||
|
<p className="font-semibold text-gray-900 dark:text-white">
|
||||||
|
{survey.questions.length}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex items-center gap-2 text-sm">
|
||||||
|
<div className="p-1.5 bg-green-100 dark:bg-green-900/30 rounded-lg">
|
||||||
|
<FaUsers className="w-3 h-3 text-green-600 dark:text-green-400" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="text-xs text-gray-500 dark:text-gray-400">{translate('::App.Platform.Intranet.Widgets.ActiveSurveys.Responses')}</p>
|
||||||
|
<p className="font-semibold text-gray-900 dark:text-white">
|
||||||
|
{survey.responses}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex items-center gap-2 text-sm">
|
||||||
|
<div className="p-1.5 bg-purple-100 dark:bg-purple-900/30 rounded-lg">
|
||||||
|
<FaClock className="w-3 h-3 text-purple-600 dark:text-purple-400" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="text-xs text-gray-500 dark:text-gray-400">{translate('::App.Platform.Intranet.Widgets.ActiveSurveys.Duration')}</p>
|
||||||
|
<p className="font-semibold text-gray-900 dark:text-white">~5dk</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Progress Bar */}
|
||||||
|
<div className="mb-4">
|
||||||
|
<div className="flex justify-between text-xs mb-1">
|
||||||
|
<span className="text-gray-600 dark:text-gray-400">{translate('::App.Platform.Intranet.Widgets.ActiveSurveys.CompletionRate')}</span>
|
||||||
|
<span className="text-gray-800 dark:text-gray-200 font-medium">
|
||||||
|
{Math.round((survey.responses / 100) * 100)}%
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="w-full bg-gray-200 dark:bg-gray-600 rounded-full h-2">
|
||||||
|
<div
|
||||||
|
className="bg-gradient-to-r from-purple-500 to-pink-500 h-2 rounded-full transition-all duration-500"
|
||||||
|
style={{ width: `${Math.min((survey.responses / 100) * 100, 100)}%` }}
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Deadline */}
|
||||||
|
<p className="text-sm text-gray-600 dark:text-gray-400 mb-4">
|
||||||
|
<FaClock className="inline w-3 h-3 mr-1" />
|
||||||
|
{currentLocalDate(survey.deadline, currentLocale || 'tr')}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{/* Action Button */}
|
||||||
|
<button className="w-full flex items-center justify-center gap-2 px-4 py-3 bg-gradient-to-r from-purple-600 to-pink-600 hover:from-purple-700 hover:to-pink-700 text-white text-sm font-medium rounded-lg transition-all duration-300 transform group-hover:scale-[1.02] shadow-sm hover:shadow-md">
|
||||||
|
{translate('::App.Platform.Intranet.Widgets.ActiveSurveys.FillSurvey')}
|
||||||
|
<FaArrowRight className="w-3 h-3 transition-transform group-hover:translate-x-1" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
|
||||||
|
{surveys?.length === 0 && (
|
||||||
|
<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">
|
||||||
|
<FaClipboardCheck className="w-8 h-8 text-gray-400" />
|
||||||
|
</div>
|
||||||
|
<h3 className="text-lg font-medium text-gray-900 dark:text-white mb-2">
|
||||||
|
{translate('::App.Platform.Intranet.Widgets.ActiveSurveys.NoActive')}
|
||||||
|
</h3>
|
||||||
|
<p className="text-sm text-gray-500 dark:text-gray-400">
|
||||||
|
{translate('::App.Platform.Intranet.Widgets.ActiveSurveys.WillAppearHere')}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Surveys
|
||||||
58
ui/src/views/intranet/widgets/TodayBirthdays.tsx
Normal file
58
ui/src/views/intranet/widgets/TodayBirthdays.tsx
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
import React from 'react'
|
||||||
|
import dayjs from 'dayjs'
|
||||||
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
|
import { UserInfoViewModel } from '@/proxy/admin/models'
|
||||||
|
import { Avatar } from '@/components/ui'
|
||||||
|
import { AVATAR_URL } from '@/constants/app.constant'
|
||||||
|
|
||||||
|
const TodayBirthdays: React.FC<{ employees: UserInfoViewModel[] }> = ({ employees }) => {
|
||||||
|
const today = dayjs()
|
||||||
|
const { translate } = useLocalization();
|
||||||
|
|
||||||
|
console.log('TodayBirthdays rendered with employees:', employees)
|
||||||
|
return (
|
||||||
|
<div className="bg-gradient-to-br from-pink-50 to-purple-50 dark:from-pink-900/20 dark:to-purple-900/20 rounded-lg shadow-sm border border-pink-200 dark:border-pink-800">
|
||||||
|
<div className="p-4 border-b border-pink-200 dark:border-pink-700">
|
||||||
|
<h2 className="text-base font-semibold text-gray-900 dark:text-white flex items-center gap-2">
|
||||||
|
🎂 {translate('::App.Platform.Intranet.Widgets.TodayBirthdays.Title')}
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
<div className="p-2 space-y-3">
|
||||||
|
{employees.length > 0 ? (
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||||
|
{employees.map((birthday, index) => (
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
className="flex items-center gap-2 p-2"
|
||||||
|
>
|
||||||
|
<Avatar
|
||||||
|
size={48}
|
||||||
|
shape="circle"
|
||||||
|
src={AVATAR_URL(birthday.id, birthday.tenantId)}
|
||||||
|
alt={birthday.fullName}
|
||||||
|
/>
|
||||||
|
<div className="flex-1">
|
||||||
|
<p className="text-sm font-semibold text-gray-900 dark:text-white">
|
||||||
|
{birthday.fullName}
|
||||||
|
</p>
|
||||||
|
<p className="text-xs text-gray-600 dark:text-gray-400">
|
||||||
|
{translate('::App.Platform.Intranet.Widgets.TodayBirthdays.Age', { age: today.diff(dayjs(birthday.birthDate), 'year') })} 🎉
|
||||||
|
</p>
|
||||||
|
<p className="text-xs text-gray-500 dark:text-gray-500 mt-1">
|
||||||
|
{birthday.department?.name}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<p className="text-sm text-gray-500 dark:text-gray-400 text-center py-4">
|
||||||
|
{translate('::App.Platform.Intranet.Widgets.TodayBirthdays.NoBirthday')}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TodayBirthdays
|
||||||
|
|
@ -341,7 +341,7 @@ const Chart = (props: ChartProps) => {
|
||||||
className="p-1 pl-6 pr-2 border border-1 outline-none text-xs text-gray-700 dark:text-gray-200 placeholder-gray-400 rounded"
|
className="p-1 pl-6 pr-2 border border-1 outline-none text-xs text-gray-700 dark:text-gray-200 placeholder-gray-400 rounded"
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
size="xs"
|
size="sm"
|
||||||
variant={'default'}
|
variant={'default'}
|
||||||
className="text-sm flex items-center gap-1"
|
className="text-sm flex items-center gap-1"
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
|
|
@ -353,7 +353,7 @@ const Chart = (props: ChartProps) => {
|
||||||
<FaSyncAlt className="w-3 h-3" /> {translate('::App.Platform.Refresh')}
|
<FaSyncAlt className="w-3 h-3" /> {translate('::App.Platform.Refresh')}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
size="xs"
|
size="sm"
|
||||||
variant="default"
|
variant="default"
|
||||||
className="text-sm flex items-center gap-1"
|
className="text-sm flex items-center gap-1"
|
||||||
onClick={() => setOpenDrawer(true)}
|
onClick={() => setOpenDrawer(true)}
|
||||||
|
|
@ -364,7 +364,7 @@ const Chart = (props: ChartProps) => {
|
||||||
|
|
||||||
{checkPermission(gridDto?.gridOptions.permissionDto.u) && (
|
{checkPermission(gridDto?.gridOptions.permissionDto.u) && (
|
||||||
<Button
|
<Button
|
||||||
size="xs"
|
size="sm"
|
||||||
variant={'default'}
|
variant={'default'}
|
||||||
className="text-sm"
|
className="text-sm"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|
|
||||||
|
|
@ -187,7 +187,7 @@ const ChartDrawer = ({
|
||||||
</span>
|
</span>
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
size="sm"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
icon={<FaMinus />}
|
icon={<FaMinus />}
|
||||||
className="text-red-500 hover:bg-red-100"
|
className="text-red-500 hover:bg-red-100"
|
||||||
|
|
|
||||||
|
|
@ -160,7 +160,7 @@ const List: React.FC = () => {
|
||||||
gridDto?.gridOptions?.schedulerOptionDto?.textExpr &&
|
gridDto?.gridOptions?.schedulerOptionDto?.textExpr &&
|
||||||
gridDto?.gridOptions?.schedulerOptionDto?.startDateExpr && (
|
gridDto?.gridOptions?.schedulerOptionDto?.startDateExpr && (
|
||||||
<Button
|
<Button
|
||||||
size="xs"
|
size="sm"
|
||||||
variant={viewMode === 'scheduler' ? 'solid' : 'default'}
|
variant={viewMode === 'scheduler' ? 'solid' : 'default'}
|
||||||
onClick={() => setLayout('scheduler')}
|
onClick={() => setLayout('scheduler')}
|
||||||
onMouseEnter={() => preload.scheduler()}
|
onMouseEnter={() => preload.scheduler()}
|
||||||
|
|
@ -173,7 +173,7 @@ const List: React.FC = () => {
|
||||||
gridDto?.gridOptions?.ganttOptionDto?.parentIdExpr &&
|
gridDto?.gridOptions?.ganttOptionDto?.parentIdExpr &&
|
||||||
gridDto?.gridOptions?.ganttOptionDto?.titleExpr && (
|
gridDto?.gridOptions?.ganttOptionDto?.titleExpr && (
|
||||||
<Button
|
<Button
|
||||||
size="xs"
|
size="sm"
|
||||||
variant={viewMode === 'gantt' ? 'solid' : 'default'}
|
variant={viewMode === 'gantt' ? 'solid' : 'default'}
|
||||||
onClick={() => setLayout('gantt')}
|
onClick={() => setLayout('gantt')}
|
||||||
onMouseEnter={() => preload.gantt()}
|
onMouseEnter={() => preload.gantt()}
|
||||||
|
|
@ -185,7 +185,7 @@ const List: React.FC = () => {
|
||||||
{gridDto?.gridOptions?.layoutDto.tree &&
|
{gridDto?.gridOptions?.layoutDto.tree &&
|
||||||
gridDto?.gridOptions?.treeOptionDto?.parentIdExpr && (
|
gridDto?.gridOptions?.treeOptionDto?.parentIdExpr && (
|
||||||
<Button
|
<Button
|
||||||
size="xs"
|
size="sm"
|
||||||
variant={viewMode === 'tree' ? 'solid' : 'default'}
|
variant={viewMode === 'tree' ? 'solid' : 'default'}
|
||||||
onClick={() => setLayout('tree')}
|
onClick={() => setLayout('tree')}
|
||||||
onMouseEnter={() => preload.tree()}
|
onMouseEnter={() => preload.tree()}
|
||||||
|
|
@ -195,7 +195,7 @@ const List: React.FC = () => {
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
size="xs"
|
size="sm"
|
||||||
variant={viewMode === 'grid' ? 'solid' : 'default'}
|
variant={viewMode === 'grid' ? 'solid' : 'default'}
|
||||||
onClick={() => setLayout('grid')}
|
onClick={() => setLayout('grid')}
|
||||||
onMouseEnter={() => preload.grid()}
|
onMouseEnter={() => preload.grid()}
|
||||||
|
|
@ -205,7 +205,7 @@ const List: React.FC = () => {
|
||||||
|
|
||||||
{gridDto.gridOptions.layoutDto.pivot && (
|
{gridDto.gridOptions.layoutDto.pivot && (
|
||||||
<Button
|
<Button
|
||||||
size="xs"
|
size="sm"
|
||||||
variant={viewMode === 'pivot' ? 'solid' : 'default'}
|
variant={viewMode === 'pivot' ? 'solid' : 'default'}
|
||||||
onClick={() => setLayout('pivot')}
|
onClick={() => setLayout('pivot')}
|
||||||
onMouseEnter={() => preload.pivot()}
|
onMouseEnter={() => preload.pivot()}
|
||||||
|
|
@ -216,7 +216,7 @@ const List: React.FC = () => {
|
||||||
|
|
||||||
{gridDto.gridOptions.layoutDto.chart && (
|
{gridDto.gridOptions.layoutDto.chart && (
|
||||||
<Button
|
<Button
|
||||||
size="xs"
|
size="sm"
|
||||||
variant={viewMode === 'chart' ? 'solid' : 'default'}
|
variant={viewMode === 'chart' ? 'solid' : 'default'}
|
||||||
onClick={() => setLayout('chart')}
|
onClick={() => setLayout('chart')}
|
||||||
onMouseEnter={() => preload.chart()}
|
onMouseEnter={() => preload.chart()}
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue