Intranet AppService
This commit is contained in:
parent
e29a924e87
commit
bdf67ec1da
62 changed files with 1397 additions and 798 deletions
|
|
@ -7,7 +7,7 @@ public class FileItemDto
|
||||||
{
|
{
|
||||||
public string Id { get; set; } = string.Empty;
|
public string Id { get; set; } = string.Empty;
|
||||||
public string Name { get; set; } = string.Empty;
|
public string Name { get; set; } = string.Empty;
|
||||||
public string Type { get; set; } = string.Empty; // "file" or "folder"
|
public string Type { get; set; } = string.Empty;
|
||||||
public long? Size { get; set; }
|
public long? Size { get; set; }
|
||||||
public string Extension { get; set; } = string.Empty;
|
public string Extension { get; set; } = string.Empty;
|
||||||
public string MimeType { get; set; } = string.Empty;
|
public string MimeType { get; set; } = string.Empty;
|
||||||
|
|
@ -16,7 +16,7 @@ public class FileItemDto
|
||||||
public string Path { get; set; } = string.Empty;
|
public string Path { get; set; } = string.Empty;
|
||||||
public string ParentId { get; set; } = string.Empty;
|
public string ParentId { get; set; } = string.Empty;
|
||||||
public bool IsReadOnly { get; set; }
|
public bool IsReadOnly { get; set; }
|
||||||
public int? ChildCount { get; set; } // Klasörler için öğe sayısı
|
public int? ChildCount { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class GetFilesDto
|
public class GetFilesDto
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
using System;
|
||||||
|
using Volo.Abp.Application.Dtos;
|
||||||
|
|
||||||
|
namespace Kurs.Platform.Intranet;
|
||||||
|
|
||||||
|
public class CurrencyDto : FullAuditedEntityDto<Guid>
|
||||||
|
{
|
||||||
|
public string Code { get; set; } // TRY, USD, EUR
|
||||||
|
public string Symbol { get; set; } // ₺, $, etc.
|
||||||
|
public string Name { get; set; } // Turkish lira, US dollar, ...
|
||||||
|
public decimal Rate { get; set; } // TRY başına değer
|
||||||
|
public bool IsActive { get; set; }
|
||||||
|
public DateTime? LastUpdated { get; set; }
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Volo.Abp.Application.Dtos;
|
||||||
|
|
||||||
|
namespace Kurs.Platform.Intranet;
|
||||||
|
|
||||||
|
public class DepartmentDto : FullAuditedEntityDto<Guid>
|
||||||
|
{
|
||||||
|
public Guid? TenantId { get; set; }
|
||||||
|
public string Code { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string Description { get; set; }
|
||||||
|
public Guid? ParentDepartmentId { get; set; }
|
||||||
|
public string ParentDepartmentName { get; set; }
|
||||||
|
public Guid? ManagerId { get; set; }
|
||||||
|
public string ManagerName { get; set; }
|
||||||
|
public Guid? CostCenterId { get; set; }
|
||||||
|
public string CostCenterName { get; set; }
|
||||||
|
public decimal Budget { get; set; }
|
||||||
|
public bool IsActive { get; set; }
|
||||||
|
public List<DepartmentDto> SubDepartments { get; set; } = [];
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
using System;
|
||||||
|
using Volo.Abp.Application.Dtos;
|
||||||
|
|
||||||
|
namespace Kurs.Platform.Intranet;
|
||||||
|
|
||||||
|
public class EmployeeDto : FullAuditedEntityDto<Guid>
|
||||||
|
{
|
||||||
|
public Guid? TenantId { get; set; }
|
||||||
|
|
||||||
|
public string Code { get; set; }
|
||||||
|
public string FullName { get; set; }
|
||||||
|
public string Avatar { get; set; }
|
||||||
|
public string NationalId { get; set; }
|
||||||
|
public DateTime BirthDate { get; set; }
|
||||||
|
public string Gender { get; set; }
|
||||||
|
public string MaritalStatus { get; set; }
|
||||||
|
|
||||||
|
// Embedded Address
|
||||||
|
public string Country { get; set; }
|
||||||
|
public string City { get; set; }
|
||||||
|
public string District { get; set; }
|
||||||
|
public string Street { get; set; }
|
||||||
|
public string PostalCode { get; set; }
|
||||||
|
public string Phone { get; set; }
|
||||||
|
public string PersonalPhone { get; set; }
|
||||||
|
public string Email { get; set; }
|
||||||
|
public string Address1 { get; set; }
|
||||||
|
public string Address2 { get; set; }
|
||||||
|
|
||||||
|
// Emergency contact
|
||||||
|
public string EmergencyContactName { get; set; }
|
||||||
|
public string EmergencyContactRelationship { get; set; }
|
||||||
|
public string EmergencyContactPhone { get; set; }
|
||||||
|
|
||||||
|
public DateTime HireDate { get; set; }
|
||||||
|
public DateTime? TerminationDate { get; set; }
|
||||||
|
|
||||||
|
public Guid? EmploymentTypeId { get; set; }
|
||||||
|
public EmploymentTypeDto EmploymentType { get; set; }
|
||||||
|
|
||||||
|
public Guid? JobPositionId { get; set; }
|
||||||
|
public JobPositionDto JobPosition { get; set; }
|
||||||
|
|
||||||
|
public Guid? DepartmentId { get; set; }
|
||||||
|
public DepartmentDto Department { get; set; }
|
||||||
|
|
||||||
|
public string WorkLocation { get; set; }
|
||||||
|
|
||||||
|
public Guid? ManagerId { get; set; }
|
||||||
|
public EmployeeDto Manager { get; set; }
|
||||||
|
|
||||||
|
public decimal BaseSalary { get; set; }
|
||||||
|
public Guid? CurrencyId { get; set; }
|
||||||
|
|
||||||
|
public string PayrollGroup { get; set; } // e.g., Monthly, Biweekly, Weekly
|
||||||
|
public Guid? BankAccountId { get; set; }
|
||||||
|
public Guid? BadgeId { get; set; }
|
||||||
|
|
||||||
|
public string EmployeeStatus { get; set; }
|
||||||
|
public bool IsActive { get; set; }
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
using System;
|
||||||
|
using Volo.Abp.Application.Dtos;
|
||||||
|
|
||||||
|
namespace Kurs.Platform.Intranet;
|
||||||
|
|
||||||
|
public class EmploymentTypeDto : FullAuditedEntityDto<Guid>
|
||||||
|
{
|
||||||
|
public Guid? TenantId { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Kurs.Platform.Public;
|
namespace Kurs.Platform.Intranet;
|
||||||
|
|
||||||
public class EventCommentDto
|
public class EventCommentDto
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Kurs.Platform.Public;
|
namespace Kurs.Platform.Intranet;
|
||||||
|
|
||||||
public class EventDto
|
public class EventDto
|
||||||
{
|
{
|
||||||
public string Id { get; set; }
|
public string Id { get; set; }
|
||||||
public string CategoryName { get; set; }
|
public string CategoryName { get; set; }
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Kurs.Platform.Public;
|
namespace Kurs.Platform.Intranet;
|
||||||
|
|
||||||
public class EventOrganizerDto
|
public class EventOrganizerDto
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
using System;
|
||||||
|
using Volo.Abp.Application.Dtos;
|
||||||
|
|
||||||
|
namespace Kurs.Platform.Intranet;
|
||||||
|
|
||||||
|
public class ExpenseDto : FullAuditedEntityDto<Guid>
|
||||||
|
{
|
||||||
|
public Guid? TenantId { get; set; }
|
||||||
|
|
||||||
|
public Guid? EmployeeId { get; set; }
|
||||||
|
public EmployeeDto Employee { get; set; }
|
||||||
|
|
||||||
|
public string Category { get; set; }
|
||||||
|
public decimal Amount { get; set; }
|
||||||
|
|
||||||
|
public Guid? CurrencyId { get; set; }
|
||||||
|
public string CurrencyCode { get; set; }
|
||||||
|
|
||||||
|
public DateTime RequestDate { get; set; }
|
||||||
|
public string Description { get; set; }
|
||||||
|
public string Project { get; set; }
|
||||||
|
public string Status { get; set; }
|
||||||
|
|
||||||
|
public Guid? ApproverId { get; set; }
|
||||||
|
public EmployeeDto Approver { get; set; }
|
||||||
|
|
||||||
|
public DateTime? ApprovalDate { get; set; }
|
||||||
|
public string RejectionReason { get; set; }
|
||||||
|
public string Notes { get; set; }
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Kurs.Platform.Intranet;
|
||||||
|
|
||||||
|
public class ExpensesDto
|
||||||
|
{
|
||||||
|
public decimal TotalRequested { get; set; }
|
||||||
|
public decimal TotalApproved { get; set; }
|
||||||
|
public List<ExpenseDto> Last5Expenses { get; set; } = [];
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Volo.Abp.Application.Services;
|
using Volo.Abp.Application.Services;
|
||||||
|
|
||||||
namespace Kurs.Platform.Public;
|
namespace Kurs.Platform.Intranet;
|
||||||
|
|
||||||
public interface IIntranetAppService : IApplicationService
|
public interface IIntranetAppService : IApplicationService
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,16 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Kurs.Platform.FileManagement;
|
||||||
|
|
||||||
namespace Kurs.Platform.Public;
|
namespace Kurs.Platform.Intranet;
|
||||||
|
|
||||||
public class IntranetDashboardDto
|
public class IntranetDashboardDto
|
||||||
{
|
{
|
||||||
public List<EventDto> Events { get; set; } = [];
|
public List<EventDto> Events { get; set; } = [];
|
||||||
|
public List<EmployeeDto> Birthdays { get; set; } = [];
|
||||||
|
public List<VisitorDto> Visitors { get; set; } = [];
|
||||||
|
public List<ReservationDto> Reservations { get; set; } = [];
|
||||||
|
public List<TrainingDto> Trainings { get; set; } = [];
|
||||||
|
public ExpensesDto Expenses { get; set; } = new ExpensesDto();
|
||||||
|
public List<FileItemDto> Documents { get; set; } = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
using System;
|
||||||
|
using Volo.Abp.Application.Dtos;
|
||||||
|
|
||||||
|
namespace Kurs.Platform.Intranet;
|
||||||
|
|
||||||
|
public class JobPositionDto : FullAuditedEntityDto<Guid>
|
||||||
|
{
|
||||||
|
public Guid? TenantId { get; set; }
|
||||||
|
public string Code { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string Description { get; set; }
|
||||||
|
public Guid? DepartmentId { get; set; }
|
||||||
|
public string DepartmentName { get; set; }
|
||||||
|
public string Level { get; set; }
|
||||||
|
public decimal MinSalary { get; set; }
|
||||||
|
public decimal MaxSalary { get; set; }
|
||||||
|
public Guid? CurrencyId { get; set; }
|
||||||
|
public string CurrencyName { get; set; }
|
||||||
|
public string RequiredSkills { get; set; }
|
||||||
|
public string Responsibilities { get; set; }
|
||||||
|
public string Qualifications { get; set; }
|
||||||
|
public bool IsActive { get; set; }
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
using System;
|
||||||
|
using Volo.Abp.Application.Dtos;
|
||||||
|
|
||||||
|
namespace Kurs.Platform.Intranet;
|
||||||
|
|
||||||
|
public class ReservationDto : FullAuditedEntityDto<Guid>
|
||||||
|
{
|
||||||
|
public Guid? TenantId { get; set; }
|
||||||
|
|
||||||
|
public string Type { get; set; } // room | vehicle | equipment
|
||||||
|
public string ResourceName { get; set; }
|
||||||
|
|
||||||
|
public Guid? EmployeeId { get; set; }
|
||||||
|
public string EmployeeName { get; set; } // Optional: ilişkili personel ismi
|
||||||
|
|
||||||
|
public DateTime StartDate { get; set; }
|
||||||
|
public DateTime EndDate { get; set; }
|
||||||
|
public string Purpose { get; set; } // Amaç
|
||||||
|
public int? Participants { get; set; } // Katılımcı Sayısı
|
||||||
|
public string Notes { get; set; }
|
||||||
|
public string Status { get; set; } // pending | approved | rejected | completed
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
using System;
|
||||||
|
using Volo.Abp.Application.Dtos;
|
||||||
|
|
||||||
|
namespace Kurs.Platform.Intranet;
|
||||||
|
|
||||||
|
public class TrainingDto : FullAuditedEntityDto<Guid>
|
||||||
|
{
|
||||||
|
public Guid? TenantId { get; set; }
|
||||||
|
|
||||||
|
public string Title { get; set; }
|
||||||
|
public string Description { get; set; }
|
||||||
|
public string Instructor { get; set; }
|
||||||
|
public string Category { get; set; } // technical | soft-skills | management | compliance | other
|
||||||
|
public string Type { get; set; } // online | classroom | hybrid
|
||||||
|
public int Duration { get; set; } // saat veya gün olarak
|
||||||
|
public DateTime StartDate { get; set; }
|
||||||
|
public DateTime EndDate { get; set; }
|
||||||
|
public int MaxParticipants { get; set; }
|
||||||
|
public int Enrolled { get; set; }
|
||||||
|
public string Status { get; set; } // upcoming | ongoing | completed
|
||||||
|
public string Location { get; set; }
|
||||||
|
public string Thumbnail { get; set; }
|
||||||
|
|
||||||
|
// İlişkili veriler
|
||||||
|
public int CertificateCount { get; set; } // optional: ilişkili sertifika sayısı
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
using System;
|
||||||
|
using Volo.Abp.Application.Dtos;
|
||||||
|
|
||||||
|
namespace Kurs.Platform.Intranet;
|
||||||
|
|
||||||
|
public class VisitorDto : FullAuditedEntityDto<Guid>
|
||||||
|
{
|
||||||
|
public Guid? TenantId { get; set; }
|
||||||
|
|
||||||
|
public string FullName { get; set; }
|
||||||
|
public string CompanyName { get; set; }
|
||||||
|
public string Email { get; set; }
|
||||||
|
public string Phone { get; set; }
|
||||||
|
public string Purpose { get; set; }
|
||||||
|
public DateTime VisitDate { get; set; }
|
||||||
|
public DateTime? CheckIn { get; set; }
|
||||||
|
public DateTime? CheckOut { get; set; }
|
||||||
|
public Guid? EmployeeId { get; set; }
|
||||||
|
public EmployeeDto Employee { get; set; }
|
||||||
|
public string Status { get; set; }
|
||||||
|
public string BadgeNumber { get; set; }
|
||||||
|
public string Photo { get; set; }
|
||||||
|
}
|
||||||
|
|
@ -26,13 +26,14 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
||||||
private const string FileMetadataSuffix = ".metadata.json";
|
private const string FileMetadataSuffix = ".metadata.json";
|
||||||
private const string FolderMarkerSuffix = ".folder";
|
private const string FolderMarkerSuffix = ".folder";
|
||||||
private const string IndexFileName = "index.json";
|
private const string IndexFileName = "index.json";
|
||||||
|
|
||||||
// Protected system folders that cannot be deleted, renamed, or moved
|
// Protected system folders that cannot be deleted, renamed, or moved
|
||||||
private static readonly HashSet<string> ProtectedFolders = new(StringComparer.OrdinalIgnoreCase)
|
private static readonly HashSet<string> ProtectedFolders = new(StringComparer.OrdinalIgnoreCase)
|
||||||
{
|
{
|
||||||
BlobContainerNames.Avatar,
|
BlobContainerNames.Avatar,
|
||||||
BlobContainerNames.Import,
|
BlobContainerNames.Import,
|
||||||
BlobContainerNames.Activity
|
BlobContainerNames.Activity,
|
||||||
|
BlobContainerNames.Intranet
|
||||||
};
|
};
|
||||||
|
|
||||||
public FileManagementAppService(
|
public FileManagementAppService(
|
||||||
|
|
@ -52,11 +53,6 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
||||||
return $"files/{tenantId}/";
|
return $"files/{tenantId}/";
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GenerateFileId()
|
|
||||||
{
|
|
||||||
return Guid.NewGuid().ToString("N");
|
|
||||||
}
|
|
||||||
|
|
||||||
private string EncodePathAsId(string path)
|
private string EncodePathAsId(string path)
|
||||||
{
|
{
|
||||||
// Path'deki '/' karakterlerini '|' ile değiştir URL-safe hale getirmek için
|
// Path'deki '/' karakterlerini '|' ile değiştir URL-safe hale getirmek için
|
||||||
|
|
@ -74,13 +70,13 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
||||||
// Get the root folder name from path
|
// Get the root folder name from path
|
||||||
var pathParts = path.Split('/', StringSplitOptions.RemoveEmptyEntries);
|
var pathParts = path.Split('/', StringSplitOptions.RemoveEmptyEntries);
|
||||||
if (pathParts.Length == 0) return false;
|
if (pathParts.Length == 0) return false;
|
||||||
|
|
||||||
var rootFolder = pathParts[0];
|
var rootFolder = pathParts[0];
|
||||||
var isProtected = ProtectedFolders.Contains(rootFolder);
|
var isProtected = ProtectedFolders.Contains(rootFolder);
|
||||||
|
|
||||||
Logger.LogInformation($"IsProtectedFolder - Path: '{path}', RootFolder: '{rootFolder}', IsProtected: {isProtected}");
|
Logger.LogInformation($"IsProtectedFolder - Path: '{path}', RootFolder: '{rootFolder}', IsProtected: {isProtected}");
|
||||||
Logger.LogInformation($"Protected folders: {string.Join(", ", ProtectedFolders)}");
|
Logger.LogInformation($"Protected folders: {string.Join(", ", ProtectedFolders)}");
|
||||||
|
|
||||||
return isProtected;
|
return isProtected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -88,14 +84,14 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
||||||
{
|
{
|
||||||
var decodedPath = DecodeIdAsPath(id);
|
var decodedPath = DecodeIdAsPath(id);
|
||||||
Logger.LogInformation($"ValidateNotProtectedFolder - ID: {id}, DecodedPath: {decodedPath}, Operation: {operation}");
|
Logger.LogInformation($"ValidateNotProtectedFolder - ID: {id}, DecodedPath: {decodedPath}, Operation: {operation}");
|
||||||
|
|
||||||
if (IsProtectedFolder(decodedPath))
|
if (IsProtectedFolder(decodedPath))
|
||||||
{
|
{
|
||||||
var folderName = decodedPath.Split('/')[0];
|
var folderName = decodedPath.Split('/')[0];
|
||||||
Logger.LogWarning($"Blocked {operation} operation on protected folder: {folderName}");
|
Logger.LogWarning($"Blocked {operation} operation on protected folder: {folderName}");
|
||||||
throw new UserFriendlyException($"Cannot {operation} system folder '{folderName}'. This folder is protected.");
|
throw new UserFriendlyException($"Cannot {operation} system folder '{folderName}'. This folder is protected.");
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.LogInformation($"Folder {decodedPath} is not protected, allowing {operation}");
|
Logger.LogInformation($"Folder {decodedPath} is not protected, allowing {operation}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -108,7 +104,7 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
||||||
{
|
{
|
||||||
var items = new List<FileMetadata>();
|
var items = new List<FileMetadata>();
|
||||||
var cdnBasePath = _configuration["App:CdnPath"];
|
var cdnBasePath = _configuration["App:CdnPath"];
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(cdnBasePath))
|
if (string.IsNullOrEmpty(cdnBasePath))
|
||||||
{
|
{
|
||||||
Logger.LogWarning("CDN path is not configured");
|
Logger.LogWarning("CDN path is not configured");
|
||||||
|
|
@ -117,7 +113,7 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
||||||
|
|
||||||
var tenantId = _currentTenant.Id?.ToString() ?? "host";
|
var tenantId = _currentTenant.Id?.ToString() ?? "host";
|
||||||
var fullPath = Path.Combine(cdnBasePath, tenantId);
|
var fullPath = Path.Combine(cdnBasePath, tenantId);
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(folderPath))
|
if (!string.IsNullOrEmpty(folderPath))
|
||||||
{
|
{
|
||||||
fullPath = Path.Combine(fullPath, folderPath);
|
fullPath = Path.Combine(fullPath, folderPath);
|
||||||
|
|
@ -137,7 +133,7 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
||||||
{
|
{
|
||||||
var dirInfo = new DirectoryInfo(dir);
|
var dirInfo = new DirectoryInfo(dir);
|
||||||
var relativePath = string.IsNullOrEmpty(folderPath) ? dirInfo.Name : $"{folderPath}/{dirInfo.Name}";
|
var relativePath = string.IsNullOrEmpty(folderPath) ? dirInfo.Name : $"{folderPath}/{dirInfo.Name}";
|
||||||
|
|
||||||
// Klasör içindeki öğe sayısını hesapla
|
// Klasör içindeki öğe sayısını hesapla
|
||||||
var childCount = 0;
|
var childCount = 0;
|
||||||
try
|
try
|
||||||
|
|
@ -151,7 +147,7 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
||||||
Logger.LogWarning(ex, "Error counting items in folder: {FolderPath}", dir);
|
Logger.LogWarning(ex, "Error counting items in folder: {FolderPath}", dir);
|
||||||
childCount = 0;
|
childCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
items.Add(new FileMetadata
|
items.Add(new FileMetadata
|
||||||
{
|
{
|
||||||
Id = EncodePathAsId(relativePath),
|
Id = EncodePathAsId(relativePath),
|
||||||
|
|
@ -173,7 +169,7 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
||||||
{
|
{
|
||||||
var fileInfo = new FileInfo(file);
|
var fileInfo = new FileInfo(file);
|
||||||
var relativePath = string.IsNullOrEmpty(folderPath) ? fileInfo.Name : $"{folderPath}/{fileInfo.Name}";
|
var relativePath = string.IsNullOrEmpty(folderPath) ? fileInfo.Name : $"{folderPath}/{fileInfo.Name}";
|
||||||
|
|
||||||
items.Add(new FileMetadata
|
items.Add(new FileMetadata
|
||||||
{
|
{
|
||||||
Id = EncodePathAsId(relativePath),
|
Id = EncodePathAsId(relativePath),
|
||||||
|
|
@ -198,24 +194,6 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<List<FileMetadata>> GetCustomFoldersAsync()
|
|
||||||
{
|
|
||||||
var indexPath = GetTenantPrefix() + IndexFileName;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var indexBytes = await _blobContainer.GetAllBytesOrNullAsync(indexPath);
|
|
||||||
if (indexBytes == null) return new List<FileMetadata>();
|
|
||||||
|
|
||||||
var indexJson = Encoding.UTF8.GetString(indexBytes);
|
|
||||||
return JsonSerializer.Deserialize<List<FileMetadata>>(indexJson) ?? new List<FileMetadata>();
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return new List<FileMetadata>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task SaveFolderIndexAsync(List<FileMetadata> items, string? parentId = null)
|
private async Task SaveFolderIndexAsync(List<FileMetadata> items, string? parentId = null)
|
||||||
{
|
{
|
||||||
var indexPath = GetTenantPrefix() + (string.IsNullOrEmpty(parentId) ? IndexFileName : $"{parentId}/{IndexFileName}");
|
var indexPath = GetTenantPrefix() + (string.IsNullOrEmpty(parentId) ? IndexFileName : $"{parentId}/{IndexFileName}");
|
||||||
|
|
@ -244,13 +222,12 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
||||||
{
|
{
|
||||||
var items = await GetFolderIndexAsync(parentId);
|
var items = await GetFolderIndexAsync(parentId);
|
||||||
|
|
||||||
var result = items.Select(metadata => {
|
var result = items.Select(metadata =>
|
||||||
|
{
|
||||||
var isRootLevel = string.IsNullOrEmpty(parentId);
|
var isRootLevel = string.IsNullOrEmpty(parentId);
|
||||||
var isProtected = IsProtectedFolder(metadata.Path);
|
var isProtected = IsProtectedFolder(metadata.Path);
|
||||||
var finalIsReadOnly = metadata.IsReadOnly || (isRootLevel && isProtected);
|
var finalIsReadOnly = metadata.IsReadOnly || (isRootLevel && isProtected);
|
||||||
|
|
||||||
Logger.LogInformation($"Item: {metadata.Name}, Path: {metadata.Path}, IsRootLevel: {isRootLevel}, IsProtected: {isProtected}, FinalIsReadOnly: {finalIsReadOnly}");
|
|
||||||
|
|
||||||
return new FileItemDto
|
return new FileItemDto
|
||||||
{
|
{
|
||||||
Id = metadata.Id,
|
Id = metadata.Id,
|
||||||
|
|
@ -283,7 +260,7 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
||||||
|
|
||||||
var tenantId = _currentTenant.Id?.ToString() ?? "host";
|
var tenantId = _currentTenant.Id?.ToString() ?? "host";
|
||||||
var parentPath = Path.Combine(cdnBasePath, tenantId);
|
var parentPath = Path.Combine(cdnBasePath, tenantId);
|
||||||
|
|
||||||
string? decodedParentId = null;
|
string? decodedParentId = null;
|
||||||
if (!string.IsNullOrEmpty(input.ParentId))
|
if (!string.IsNullOrEmpty(input.ParentId))
|
||||||
{
|
{
|
||||||
|
|
@ -309,7 +286,7 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
||||||
Directory.CreateDirectory(folderPath);
|
Directory.CreateDirectory(folderPath);
|
||||||
|
|
||||||
var newFolderPath = string.IsNullOrEmpty(decodedParentId) ? input.Name : $"{decodedParentId}/{input.Name}";
|
var newFolderPath = string.IsNullOrEmpty(decodedParentId) ? input.Name : $"{decodedParentId}/{input.Name}";
|
||||||
|
|
||||||
var metadata = new FileMetadata
|
var metadata = new FileMetadata
|
||||||
{
|
{
|
||||||
Id = EncodePathAsId(newFolderPath),
|
Id = EncodePathAsId(newFolderPath),
|
||||||
|
|
@ -338,10 +315,6 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
||||||
|
|
||||||
public async Task<FileItemDto> UploadFileAsync([FromForm] UploadFileDto input)
|
public async Task<FileItemDto> UploadFileAsync([FromForm] UploadFileDto input)
|
||||||
{
|
{
|
||||||
// Debug logging
|
|
||||||
Logger.LogInformation("UploadFileAsync called with: FileName={FileName}, ParentId={ParentId}, FilesCount={FilesCount}",
|
|
||||||
input.FileName, input.ParentId, input.Files?.Length ?? 0);
|
|
||||||
|
|
||||||
ValidateFileName(input.FileName);
|
ValidateFileName(input.FileName);
|
||||||
|
|
||||||
// Decode parent ID if provided
|
// Decode parent ID if provided
|
||||||
|
|
@ -371,7 +344,7 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
||||||
|
|
||||||
var tenantId = _currentTenant.Id?.ToString() ?? "host";
|
var tenantId = _currentTenant.Id?.ToString() ?? "host";
|
||||||
var fullCdnPath = Path.Combine(cdnBasePath, tenantId);
|
var fullCdnPath = Path.Combine(cdnBasePath, tenantId);
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(decodedParentId))
|
if (!string.IsNullOrEmpty(decodedParentId))
|
||||||
{
|
{
|
||||||
fullCdnPath = Path.Combine(fullCdnPath, decodedParentId);
|
fullCdnPath = Path.Combine(fullCdnPath, decodedParentId);
|
||||||
|
|
@ -416,7 +389,6 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
||||||
};
|
};
|
||||||
|
|
||||||
// File system'e kaydedildi, index güncellemeye gerek yok
|
// File system'e kaydedildi, index güncellemeye gerek yok
|
||||||
|
|
||||||
return new FileItemDto
|
return new FileItemDto
|
||||||
{
|
{
|
||||||
Id = metadata.Id,
|
Id = metadata.Id,
|
||||||
|
|
@ -437,7 +409,7 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
||||||
{
|
{
|
||||||
// Check if this is a protected system folder
|
// Check if this is a protected system folder
|
||||||
ValidateNotProtectedFolder(id, "rename");
|
ValidateNotProtectedFolder(id, "rename");
|
||||||
|
|
||||||
ValidateFileName(input.Name);
|
ValidateFileName(input.Name);
|
||||||
|
|
||||||
var metadata = await FindItemMetadataAsync(id);
|
var metadata = await FindItemMetadataAsync(id);
|
||||||
|
|
@ -566,7 +538,7 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
||||||
{
|
{
|
||||||
// Check if this is a protected system folder
|
// Check if this is a protected system folder
|
||||||
ValidateNotProtectedFolder(id, "delete");
|
ValidateNotProtectedFolder(id, "delete");
|
||||||
|
|
||||||
var cdnBasePath = _configuration["App:CdnPath"];
|
var cdnBasePath = _configuration["App:CdnPath"];
|
||||||
if (string.IsNullOrEmpty(cdnBasePath))
|
if (string.IsNullOrEmpty(cdnBasePath))
|
||||||
{
|
{
|
||||||
|
|
@ -615,7 +587,7 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
||||||
{
|
{
|
||||||
// Check if this is a protected system folder
|
// Check if this is a protected system folder
|
||||||
ValidateNotProtectedFolder(itemId, "delete");
|
ValidateNotProtectedFolder(itemId, "delete");
|
||||||
|
|
||||||
var actualPath = DecodeIdAsPath(itemId);
|
var actualPath = DecodeIdAsPath(itemId);
|
||||||
var fullPath = Path.Combine(cdnBasePath, tenantId, actualPath);
|
var fullPath = Path.Combine(cdnBasePath, tenantId, actualPath);
|
||||||
|
|
||||||
|
|
@ -661,7 +633,7 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
||||||
|
|
||||||
var tenantId = _currentTenant.Id?.ToString() ?? "host";
|
var tenantId = _currentTenant.Id?.ToString() ?? "host";
|
||||||
var basePath = Path.Combine(cdnBasePath, tenantId);
|
var basePath = Path.Combine(cdnBasePath, tenantId);
|
||||||
|
|
||||||
string? targetPath = null;
|
string? targetPath = null;
|
||||||
if (!string.IsNullOrEmpty(input.TargetFolderId))
|
if (!string.IsNullOrEmpty(input.TargetFolderId))
|
||||||
{
|
{
|
||||||
|
|
@ -680,11 +652,11 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
||||||
|
|
||||||
// Get source item name
|
// Get source item name
|
||||||
var sourceItemName = Path.GetFileName(sourcePath);
|
var sourceItemName = Path.GetFileName(sourcePath);
|
||||||
|
|
||||||
// Generate unique name if item already exists in target
|
// Generate unique name if item already exists in target
|
||||||
var targetItemPath = string.IsNullOrEmpty(targetPath) ? sourceItemName : $"{targetPath}/{sourceItemName}";
|
var targetItemPath = string.IsNullOrEmpty(targetPath) ? sourceItemName : $"{targetPath}/{sourceItemName}";
|
||||||
var targetFullPath = Path.Combine(basePath, targetItemPath);
|
var targetFullPath = Path.Combine(basePath, targetItemPath);
|
||||||
|
|
||||||
var uniqueTargetPath = GetUniqueItemPath(targetFullPath, sourceItemName);
|
var uniqueTargetPath = GetUniqueItemPath(targetFullPath, sourceItemName);
|
||||||
var finalTargetPath = uniqueTargetPath.Replace(basePath + Path.DirectorySeparatorChar, "").Replace(Path.DirectorySeparatorChar, '/');
|
var finalTargetPath = uniqueTargetPath.Replace(basePath + Path.DirectorySeparatorChar, "").Replace(Path.DirectorySeparatorChar, '/');
|
||||||
|
|
||||||
|
|
@ -692,7 +664,7 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
||||||
{
|
{
|
||||||
// Copy directory recursively
|
// Copy directory recursively
|
||||||
CopyDirectory(sourceFullPath, uniqueTargetPath);
|
CopyDirectory(sourceFullPath, uniqueTargetPath);
|
||||||
|
|
||||||
var dirInfo = new DirectoryInfo(uniqueTargetPath);
|
var dirInfo = new DirectoryInfo(uniqueTargetPath);
|
||||||
copiedItems.Add(new FileItemDto
|
copiedItems.Add(new FileItemDto
|
||||||
{
|
{
|
||||||
|
|
@ -714,12 +686,12 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
||||||
{
|
{
|
||||||
Directory.CreateDirectory(targetDir);
|
Directory.CreateDirectory(targetDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
File.Copy(sourceFullPath, uniqueTargetPath);
|
File.Copy(sourceFullPath, uniqueTargetPath);
|
||||||
|
|
||||||
var fileInfo = new FileInfo(uniqueTargetPath);
|
var fileInfo = new FileInfo(uniqueTargetPath);
|
||||||
var extension = fileInfo.Extension;
|
var extension = fileInfo.Extension;
|
||||||
|
|
||||||
copiedItems.Add(new FileItemDto
|
copiedItems.Add(new FileItemDto
|
||||||
{
|
{
|
||||||
Id = EncodePathAsId(finalTargetPath),
|
Id = EncodePathAsId(finalTargetPath),
|
||||||
|
|
@ -769,7 +741,7 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
||||||
|
|
||||||
var tenantId = _currentTenant.Id?.ToString() ?? "host";
|
var tenantId = _currentTenant.Id?.ToString() ?? "host";
|
||||||
var basePath = Path.Combine(cdnBasePath, tenantId);
|
var basePath = Path.Combine(cdnBasePath, tenantId);
|
||||||
|
|
||||||
string? targetPath = null;
|
string? targetPath = null;
|
||||||
if (!string.IsNullOrEmpty(input.TargetFolderId))
|
if (!string.IsNullOrEmpty(input.TargetFolderId))
|
||||||
{
|
{
|
||||||
|
|
@ -791,11 +763,11 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
||||||
|
|
||||||
// Get source item name
|
// Get source item name
|
||||||
var sourceItemName = Path.GetFileName(sourcePath);
|
var sourceItemName = Path.GetFileName(sourcePath);
|
||||||
|
|
||||||
// Generate target path
|
// Generate target path
|
||||||
var targetItemPath = string.IsNullOrEmpty(targetPath) ? sourceItemName : $"{targetPath}/{sourceItemName}";
|
var targetItemPath = string.IsNullOrEmpty(targetPath) ? sourceItemName : $"{targetPath}/{sourceItemName}";
|
||||||
var targetFullPath = Path.Combine(basePath, targetItemPath);
|
var targetFullPath = Path.Combine(basePath, targetItemPath);
|
||||||
|
|
||||||
// Check if moving to same location
|
// Check if moving to same location
|
||||||
if (Path.GetFullPath(sourceFullPath) == Path.GetFullPath(targetFullPath))
|
if (Path.GetFullPath(sourceFullPath) == Path.GetFullPath(targetFullPath))
|
||||||
{
|
{
|
||||||
|
|
@ -815,9 +787,9 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
||||||
{
|
{
|
||||||
Directory.CreateDirectory(targetDir);
|
Directory.CreateDirectory(targetDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
Directory.Move(sourceFullPath, uniqueTargetPath);
|
Directory.Move(sourceFullPath, uniqueTargetPath);
|
||||||
|
|
||||||
var dirInfo = new DirectoryInfo(uniqueTargetPath);
|
var dirInfo = new DirectoryInfo(uniqueTargetPath);
|
||||||
movedItems.Add(new FileItemDto
|
movedItems.Add(new FileItemDto
|
||||||
{
|
{
|
||||||
|
|
@ -839,12 +811,12 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
||||||
{
|
{
|
||||||
Directory.CreateDirectory(targetDir);
|
Directory.CreateDirectory(targetDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
File.Move(sourceFullPath, uniqueTargetPath);
|
File.Move(sourceFullPath, uniqueTargetPath);
|
||||||
|
|
||||||
var fileInfo = new FileInfo(uniqueTargetPath);
|
var fileInfo = new FileInfo(uniqueTargetPath);
|
||||||
var extension = fileInfo.Extension;
|
var extension = fileInfo.Extension;
|
||||||
|
|
||||||
movedItems.Add(new FileItemDto
|
movedItems.Add(new FileItemDto
|
||||||
{
|
{
|
||||||
Id = EncodePathAsId(finalTargetPath),
|
Id = EncodePathAsId(finalTargetPath),
|
||||||
|
|
@ -949,10 +921,10 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
||||||
|
|
||||||
var nameWithoutExt = Path.GetFileNameWithoutExtension(originalFileName);
|
var nameWithoutExt = Path.GetFileNameWithoutExtension(originalFileName);
|
||||||
var extension = Path.GetExtension(originalFileName);
|
var extension = Path.GetExtension(originalFileName);
|
||||||
|
|
||||||
var counter = 1;
|
var counter = 1;
|
||||||
string uniqueName;
|
string uniqueName;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
uniqueName = $"{nameWithoutExt} ({counter}){extension}";
|
uniqueName = $"{nameWithoutExt} ({counter}){extension}";
|
||||||
|
|
@ -1070,19 +1042,19 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
||||||
// Decode the folderId to get the actual path
|
// Decode the folderId to get the actual path
|
||||||
var decodedPath = DecodeIdAsPath(folderId);
|
var decodedPath = DecodeIdAsPath(folderId);
|
||||||
Logger.LogInformation($"GetFolderPath - FolderId: {folderId}, DecodedPath: {decodedPath}");
|
Logger.LogInformation($"GetFolderPath - FolderId: {folderId}, DecodedPath: {decodedPath}");
|
||||||
|
|
||||||
// Split path into parts and build breadcrumb
|
// Split path into parts and build breadcrumb
|
||||||
var pathParts = decodedPath.Split('/', StringSplitOptions.RemoveEmptyEntries);
|
var pathParts = decodedPath.Split('/', StringSplitOptions.RemoveEmptyEntries);
|
||||||
var currentEncodedPath = "";
|
var currentEncodedPath = "";
|
||||||
|
|
||||||
for (int i = 0; i < pathParts.Length; i++)
|
for (int i = 0; i < pathParts.Length; i++)
|
||||||
{
|
{
|
||||||
// Build the path up to current level
|
// Build the path up to current level
|
||||||
var pathUpToCurrent = string.Join("/", pathParts.Take(i + 1));
|
var pathUpToCurrent = string.Join("/", pathParts.Take(i + 1));
|
||||||
currentEncodedPath = EncodePathAsId(pathUpToCurrent);
|
currentEncodedPath = EncodePathAsId(pathUpToCurrent);
|
||||||
|
|
||||||
Logger.LogInformation($"PathItem {i}: Name='{pathParts[i]}', Id='{currentEncodedPath}', PathUpToCurrent='{pathUpToCurrent}'");
|
Logger.LogInformation($"PathItem {i}: Name='{pathParts[i]}', Id='{currentEncodedPath}', PathUpToCurrent='{pathUpToCurrent}'");
|
||||||
|
|
||||||
pathItems.Add(new PathItemDto
|
pathItems.Add(new PathItemDto
|
||||||
{
|
{
|
||||||
Id = currentEncodedPath,
|
Id = currentEncodedPath,
|
||||||
|
|
@ -1104,10 +1076,10 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
||||||
var directory = Path.GetDirectoryName(targetPath) ?? "";
|
var directory = Path.GetDirectoryName(targetPath) ?? "";
|
||||||
var nameWithoutExt = Path.GetFileNameWithoutExtension(originalName);
|
var nameWithoutExt = Path.GetFileNameWithoutExtension(originalName);
|
||||||
var extension = Path.GetExtension(originalName);
|
var extension = Path.GetExtension(originalName);
|
||||||
|
|
||||||
var counter = 1;
|
var counter = 1;
|
||||||
string newPath;
|
string newPath;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
var newName = $"{nameWithoutExt} ({counter}){extension}";
|
var newName = $"{nameWithoutExt} ({counter}){extension}";
|
||||||
|
|
|
||||||
|
|
@ -1,47 +1,216 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Kurs.Platform.BlobStoring;
|
||||||
using Kurs.Platform.Entities;
|
using Kurs.Platform.Entities;
|
||||||
|
using Kurs.Platform.FileManagement;
|
||||||
|
using Kurs.Platform.Intranet;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using Volo.Abp.Domain.Repositories;
|
using Volo.Abp.Domain.Repositories;
|
||||||
|
using Volo.Abp.MultiTenancy;
|
||||||
|
|
||||||
namespace Kurs.Platform.Public;
|
namespace Kurs.Platform.Public;
|
||||||
|
|
||||||
[Authorize]
|
[Authorize]
|
||||||
public class IntranetAppService : PlatformAppService, IIntranetAppService
|
public class IntranetAppService : PlatformAppService, IIntranetAppService
|
||||||
{
|
{
|
||||||
|
private readonly ICurrentTenant _currentTenant;
|
||||||
|
private readonly BlobManager _blobContainer;
|
||||||
|
private readonly IConfiguration _configuration;
|
||||||
|
|
||||||
private readonly IRepository<Event, Guid> _eventRepository;
|
private readonly IRepository<Event, Guid> _eventRepository;
|
||||||
private readonly IRepository<EventCategory, Guid> _eventCategoryRepository;
|
|
||||||
private readonly IRepository<EventType, Guid> _eventTypeRepository;
|
|
||||||
private readonly IRepository<EventPhoto, Guid> _eventPhotoRepository;
|
|
||||||
private readonly IRepository<EventComment, Guid> _eventCommentRepository;
|
|
||||||
private readonly IRepository<Employee, Guid> _employeeRepository;
|
private readonly IRepository<Employee, Guid> _employeeRepository;
|
||||||
|
private readonly IRepository<Visitor, Guid> _visitorRepository;
|
||||||
|
private readonly IRepository<Reservation, Guid> _reservationRepository;
|
||||||
|
private readonly IRepository<Training, Guid> _trainingRepository;
|
||||||
|
private readonly IRepository<Expense, Guid> _expenseRepository;
|
||||||
|
|
||||||
public IntranetAppService(
|
public IntranetAppService(
|
||||||
|
ICurrentTenant currentTenant,
|
||||||
|
BlobManager blobContainer,
|
||||||
|
IConfiguration configuration,
|
||||||
|
|
||||||
IRepository<Event, Guid> eventRepository,
|
IRepository<Event, Guid> eventRepository,
|
||||||
IRepository<EventCategory, Guid> eventCategoryRepository,
|
IRepository<Employee, Guid> employeeRepository,
|
||||||
IRepository<EventType, Guid> eventTypeRepository,
|
IRepository<Visitor, Guid> visitorRepository,
|
||||||
IRepository<EventPhoto, Guid> eventPhotoRepository,
|
IRepository<Reservation, Guid> reservationRepository,
|
||||||
IRepository<EventComment, Guid> eventCommentRepository,
|
IRepository<Training, Guid> trainingRepository,
|
||||||
IRepository<Employee, Guid> employeeRepository)
|
IRepository<Expense, Guid> expenseRepository
|
||||||
|
)
|
||||||
{
|
{
|
||||||
|
_currentTenant = currentTenant;
|
||||||
|
_blobContainer = blobContainer;
|
||||||
|
_configuration = configuration;
|
||||||
|
|
||||||
_eventRepository = eventRepository;
|
_eventRepository = eventRepository;
|
||||||
_eventCategoryRepository = eventCategoryRepository;
|
|
||||||
_eventTypeRepository = eventTypeRepository;
|
|
||||||
_eventPhotoRepository = eventPhotoRepository;
|
|
||||||
_eventCommentRepository = eventCommentRepository;
|
|
||||||
_employeeRepository = employeeRepository;
|
_employeeRepository = employeeRepository;
|
||||||
|
_visitorRepository = visitorRepository;
|
||||||
|
_reservationRepository = reservationRepository;
|
||||||
|
_trainingRepository = trainingRepository;
|
||||||
|
_expenseRepository = expenseRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IntranetDashboardDto> GetIntranetDashboardAsync()
|
public async Task<IntranetDashboardDto> GetIntranetDashboardAsync()
|
||||||
{
|
{
|
||||||
return new IntranetDashboardDto
|
return new IntranetDashboardDto
|
||||||
{
|
{
|
||||||
Events = await GetUpcomingEventsAsync()
|
Events = await GetUpcomingEventsAsync(),
|
||||||
|
Birthdays = await GetBirthdaysAsync(),
|
||||||
|
Visitors = await GetVisitorsAsync(),
|
||||||
|
Reservations = await GetReservationsAsync(),
|
||||||
|
Trainings = await GetTrainingsAsync(),
|
||||||
|
Expenses = await GetExpensesAsync(),
|
||||||
|
Documents = await GetIntranetDocumentsAsync(BlobContainerNames.Intranet)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<ExpensesDto> GetExpensesAsync()
|
||||||
|
{
|
||||||
|
var queryable = await _expenseRepository.GetQueryableAsync();
|
||||||
|
|
||||||
|
var today = DateTime.Today;
|
||||||
|
var oneMonthAgo = today.AddMonths(-1);
|
||||||
|
|
||||||
|
// Son 1 ay içerisindeki kayıtlar
|
||||||
|
var lastMonthExpenses = queryable
|
||||||
|
.Where(a => a.RequestDate >= oneMonthAgo && a.RequestDate <= today);
|
||||||
|
|
||||||
|
// Son 1 aydaki toplam talep miktarı
|
||||||
|
var totalRequested = lastMonthExpenses.Sum(a => a.Amount);
|
||||||
|
|
||||||
|
// Son 1 aydaki onaylanan harcamaların toplamı
|
||||||
|
var totalApproved = lastMonthExpenses
|
||||||
|
.Where(a => a.Status == "approved")
|
||||||
|
.Sum(a => a.Amount);
|
||||||
|
|
||||||
|
// Son 5 kayıt
|
||||||
|
var last5Expenses = queryable
|
||||||
|
.OrderByDescending(a => a.RequestDate)
|
||||||
|
.Take(5)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
// Map işlemleri
|
||||||
|
var last5Dtos = ObjectMapper.Map<List<Expense>, List<ExpenseDto>>(last5Expenses);
|
||||||
|
|
||||||
|
// Dönüş DTO'su
|
||||||
|
return new ExpensesDto
|
||||||
|
{
|
||||||
|
TotalRequested = totalRequested,
|
||||||
|
TotalApproved = totalApproved,
|
||||||
|
Last5Expenses = last5Dtos
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<List<TrainingDto>> GetTrainingsAsync()
|
||||||
|
{
|
||||||
|
var trainings = await _trainingRepository.GetListAsync(a => a.StartDate >= DateTime.Today);
|
||||||
|
|
||||||
|
return ObjectMapper.Map<List<Training>, List<TrainingDto>>(trainings);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<List<ReservationDto>> GetReservationsAsync()
|
||||||
|
{
|
||||||
|
var reservations = await _reservationRepository.GetListAsync(a => a.StartDate >= DateTime.Today);
|
||||||
|
|
||||||
|
return ObjectMapper.Map<List<Reservation>, List<ReservationDto>>(reservations);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<List<VisitorDto>> GetVisitorsAsync()
|
||||||
|
{
|
||||||
|
var visitors = await _visitorRepository.GetListAsync(a => a.VisitDate >= DateTime.Today);
|
||||||
|
|
||||||
|
return ObjectMapper.Map<List<Visitor>, List<VisitorDto>>(visitors);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<List<EmployeeDto>> GetBirthdaysAsync()
|
||||||
|
{
|
||||||
|
var today = DateTime.Now;
|
||||||
|
|
||||||
|
var employees = await _employeeRepository
|
||||||
|
.WithDetailsAsync(e => e.EmploymentType, e => e.JobPosition, e => e.Department)
|
||||||
|
.ContinueWith(t => t.Result
|
||||||
|
.Where(e => e.BirthDate.Day == today.Day && e.BirthDate.Month == today.Month)
|
||||||
|
.ToList());
|
||||||
|
|
||||||
|
return ObjectMapper.Map<List<Employee>, List<EmployeeDto>>(employees);
|
||||||
|
}
|
||||||
|
|
||||||
private async Task<List<EventDto>> GetUpcomingEventsAsync()
|
private async Task<List<EventDto>> GetUpcomingEventsAsync()
|
||||||
{
|
{
|
||||||
var events = await _eventRepository
|
var events = await _eventRepository
|
||||||
|
|
@ -74,7 +243,7 @@ public class IntranetAppService : PlatformAppService, IIntranetAppService
|
||||||
Avatar = employee.Avatar
|
Avatar = employee.Avatar
|
||||||
},
|
},
|
||||||
Participants = evt.ParticipantsCount,
|
Participants = evt.ParticipantsCount,
|
||||||
Photos = [],
|
Photos = [],
|
||||||
Comments = [],
|
Comments = [],
|
||||||
Likes = evt.Likes,
|
Likes = evt.Likes,
|
||||||
IsPublished = evt.isPublished
|
IsPublished = evt.isPublished
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
using AutoMapper;
|
||||||
|
using Kurs.Platform.Entities;
|
||||||
|
|
||||||
|
namespace Kurs.Platform.Intranet;
|
||||||
|
|
||||||
|
public class IntranetAutoMapperProfile : Profile
|
||||||
|
{
|
||||||
|
public IntranetAutoMapperProfile()
|
||||||
|
{
|
||||||
|
CreateMap<Employee, EmployeeDto>();
|
||||||
|
CreateMap<EmploymentType, EmploymentTypeDto>();
|
||||||
|
CreateMap<Department, DepartmentDto>();
|
||||||
|
CreateMap<JobPosition, JobPositionDto>();
|
||||||
|
CreateMap<Visitor, VisitorDto>();
|
||||||
|
CreateMap<Reservation, ReservationDto>();
|
||||||
|
CreateMap<Training, TrainingDto>();
|
||||||
|
CreateMap<Currency, CurrencyDto>();
|
||||||
|
CreateMap<Expense, ExpenseDto>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -41204,9 +41204,9 @@ public class ListFormSeeder : IDataSeedContributor, ITransientDependency
|
||||||
RoleId = null,
|
RoleId = null,
|
||||||
UserId = null,
|
UserId = null,
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
SourceDbType = DbType.Date,
|
SourceDbType = DbType.DateTime,
|
||||||
FieldName = "VisitDate",
|
FieldName = "VisitDate",
|
||||||
Width = 100,
|
Width = 150,
|
||||||
ListOrderNo = 7,
|
ListOrderNo = 7,
|
||||||
Visible = true,
|
Visible = true,
|
||||||
IsActive = true,
|
IsActive = true,
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ namespace Kurs.Platform.BlobStoring;
|
||||||
|
|
||||||
public static class BlobContainerNames
|
public static class BlobContainerNames
|
||||||
{
|
{
|
||||||
|
public const string Intranet = "intranet";
|
||||||
public const string Avatar = "avatar";
|
public const string Avatar = "avatar";
|
||||||
public const string Import = "import";
|
public const string Import = "import";
|
||||||
public const string Activity = "activity";
|
public const string Activity = "activity";
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
// Domain/Entities/Visitor.cs
|
|
||||||
using System;
|
using System;
|
||||||
using Volo.Abp.Domain.Entities.Auditing;
|
using Volo.Abp.Domain.Entities.Auditing;
|
||||||
using Volo.Abp.MultiTenancy;
|
using Volo.Abp.MultiTenancy;
|
||||||
|
|
@ -17,7 +16,9 @@ public class Visitor : FullAuditedEntity<Guid>, IMultiTenant
|
||||||
public DateTime VisitDate { get; set; }
|
public DateTime VisitDate { get; set; }
|
||||||
public DateTime? CheckIn { get; set; }
|
public DateTime? CheckIn { get; set; }
|
||||||
public DateTime? CheckOut { get; set; }
|
public DateTime? CheckOut { get; set; }
|
||||||
public Guid? EmployeeId { get; set; } // HrEmployee referansı
|
public Guid? EmployeeId { get; set; }
|
||||||
public Employee Employee { get; set; }
|
public Employee Employee { get; set; }
|
||||||
public string Status { get; set; } //checked-in, checked-out, scheduled
|
public string Status { get; set; }
|
||||||
|
public string BadgeNumber { get; set; }
|
||||||
|
public string Photo { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore;
|
||||||
namespace Kurs.Platform.Migrations
|
namespace Kurs.Platform.Migrations
|
||||||
{
|
{
|
||||||
[DbContext(typeof(PlatformDbContext))]
|
[DbContext(typeof(PlatformDbContext))]
|
||||||
[Migration("20251028200151_Initial")]
|
[Migration("20251029074530_Initial")]
|
||||||
partial class Initial
|
partial class Initial
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|
@ -9058,6 +9058,9 @@ namespace Kurs.Platform.Migrations
|
||||||
b.Property<Guid>("Id")
|
b.Property<Guid>("Id")
|
||||||
.HasColumnType("uniqueidentifier");
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<string>("BadgeNumber")
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
b.Property<DateTime?>("CheckIn")
|
b.Property<DateTime?>("CheckIn")
|
||||||
.HasColumnType("datetime2");
|
.HasColumnType("datetime2");
|
||||||
|
|
||||||
|
|
@ -9115,6 +9118,9 @@ namespace Kurs.Platform.Migrations
|
||||||
.HasMaxLength(20)
|
.HasMaxLength(20)
|
||||||
.HasColumnType("nvarchar(20)");
|
.HasColumnType("nvarchar(20)");
|
||||||
|
|
||||||
|
b.Property<string>("Photo")
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
b.Property<string>("Purpose")
|
b.Property<string>("Purpose")
|
||||||
.HasMaxLength(250)
|
.HasMaxLength(250)
|
||||||
.HasColumnType("nvarchar(250)");
|
.HasColumnType("nvarchar(250)");
|
||||||
|
|
@ -4462,6 +4462,8 @@ namespace Kurs.Platform.Migrations
|
||||||
CheckOut = table.Column<DateTime>(type: "datetime2", nullable: true),
|
CheckOut = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||||
EmployeeId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
EmployeeId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||||
Status = table.Column<string>(type: "nvarchar(20)", maxLength: 20, nullable: false),
|
Status = table.Column<string>(type: "nvarchar(20)", maxLength: 20, nullable: false),
|
||||||
|
BadgeNumber = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||||
|
Photo = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||||
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
|
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||||
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||||
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
|
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||||
|
|
@ -9055,6 +9055,9 @@ namespace Kurs.Platform.Migrations
|
||||||
b.Property<Guid>("Id")
|
b.Property<Guid>("Id")
|
||||||
.HasColumnType("uniqueidentifier");
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<string>("BadgeNumber")
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
b.Property<DateTime?>("CheckIn")
|
b.Property<DateTime?>("CheckIn")
|
||||||
.HasColumnType("datetime2");
|
.HasColumnType("datetime2");
|
||||||
|
|
||||||
|
|
@ -9112,6 +9115,9 @@ namespace Kurs.Platform.Migrations
|
||||||
.HasMaxLength(20)
|
.HasMaxLength(20)
|
||||||
.HasColumnType("nvarchar(20)");
|
.HasColumnType("nvarchar(20)");
|
||||||
|
|
||||||
|
b.Property<string>("Photo")
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
b.Property<string>("Purpose")
|
b.Property<string>("Purpose")
|
||||||
.HasMaxLength(250)
|
.HasMaxLength(250)
|
||||||
.HasColumnType("nvarchar(250)");
|
.HasColumnType("nvarchar(250)");
|
||||||
|
|
|
||||||
|
|
@ -100,9 +100,7 @@
|
||||||
"props": null,
|
"props": null,
|
||||||
"description": null,
|
"description": null,
|
||||||
"isActive": true,
|
"isActive": true,
|
||||||
"dependencies": [
|
"dependencies": ["AxiosListComponent"]
|
||||||
"AxiosListComponent"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"ReportCategories": [
|
"ReportCategories": [
|
||||||
|
|
@ -1509,7 +1507,7 @@
|
||||||
{
|
{
|
||||||
"CategoryName": "Spor",
|
"CategoryName": "Spor",
|
||||||
"TypeName": "Futbol Turnuvası",
|
"TypeName": "Futbol Turnuvası",
|
||||||
"Date": "2025-11-15T10:00:00",
|
"Date": "2025-11-05T10:00:00",
|
||||||
"Name": "Yaz Futbol Turnuvası 2025",
|
"Name": "Yaz Futbol Turnuvası 2025",
|
||||||
"Description": "Tüm departmanların katılımıyla düzenlenen geleneksel yaz futbol turnuvası.",
|
"Description": "Tüm departmanların katılımıyla düzenlenen geleneksel yaz futbol turnuvası.",
|
||||||
"Place": "Şirket Kampüsü Spor Alanı",
|
"Place": "Şirket Kampüsü Spor Alanı",
|
||||||
|
|
@ -1524,7 +1522,7 @@
|
||||||
{
|
{
|
||||||
"CategoryName": "Kültür",
|
"CategoryName": "Kültür",
|
||||||
"TypeName": "Kültürel Sanat Günü",
|
"TypeName": "Kültürel Sanat Günü",
|
||||||
"Date": "2025-11-17T10:00:00",
|
"Date": "2025-11-01T10:00:00",
|
||||||
"Name": "Kültür Gezisi: Kapadokya",
|
"Name": "Kültür Gezisi: Kapadokya",
|
||||||
"Description": "Çalışanlarımıza özel, rehber eşliğinde 2 günlük kültürel gezi.",
|
"Description": "Çalışanlarımıza özel, rehber eşliğinde 2 günlük kültürel gezi.",
|
||||||
"Place": "Kapadokya, Nevşehir",
|
"Place": "Kapadokya, Nevşehir",
|
||||||
|
|
@ -1539,7 +1537,7 @@
|
||||||
{
|
{
|
||||||
"CategoryName": "Müzik",
|
"CategoryName": "Müzik",
|
||||||
"TypeName": "Caz Akşamı",
|
"TypeName": "Caz Akşamı",
|
||||||
"Date": "2025-11-18T10:00:00",
|
"Date": "2025-11-09T10:00:00",
|
||||||
"Name": "Müzik Dinletisi: Jazz Akşamı",
|
"Name": "Müzik Dinletisi: Jazz Akşamı",
|
||||||
"Description": "Caz müziğinin en güzel örneklerinin canlı performanslarla sunulacağı özel akşam.",
|
"Description": "Caz müziğinin en güzel örneklerinin canlı performanslarla sunulacağı özel akşam.",
|
||||||
"Place": "Şirket Konferans Salonu",
|
"Place": "Şirket Konferans Salonu",
|
||||||
|
|
@ -2408,12 +2406,7 @@
|
||||||
"minSalary": 80000,
|
"minSalary": 80000,
|
||||||
"maxSalary": 120000,
|
"maxSalary": 120000,
|
||||||
"currencyCode": "USD",
|
"currencyCode": "USD",
|
||||||
"requiredSkills": [
|
"requiredSkills": ["JavaScript", "TypeScript", "React", "Node.js"],
|
||||||
"JavaScript",
|
|
||||||
"TypeScript",
|
|
||||||
"React",
|
|
||||||
"Node.js"
|
|
||||||
],
|
|
||||||
"responsibilities": [
|
"responsibilities": [
|
||||||
"Develop frontend and backend applications",
|
"Develop frontend and backend applications",
|
||||||
"Write clean and maintainable code",
|
"Write clean and maintainable code",
|
||||||
|
|
@ -2858,7 +2851,7 @@
|
||||||
"fullName": "Ali Öztürk",
|
"fullName": "Ali Öztürk",
|
||||||
"avatar": "https://i.pravatar.cc/150?img=12",
|
"avatar": "https://i.pravatar.cc/150?img=12",
|
||||||
"nationalId": "12345678901",
|
"nationalId": "12345678901",
|
||||||
"birthDate": "10-10-1988",
|
"birthDate": "2020-10-29",
|
||||||
"gender": "Male",
|
"gender": "Male",
|
||||||
"maritalStatus": "Married",
|
"maritalStatus": "Married",
|
||||||
"country": "TR",
|
"country": "TR",
|
||||||
|
|
@ -2898,7 +2891,7 @@
|
||||||
"fullName": "Ayşe Kaya",
|
"fullName": "Ayşe Kaya",
|
||||||
"avatar": "https://i.pravatar.cc/150?img=5",
|
"avatar": "https://i.pravatar.cc/150?img=5",
|
||||||
"nationalId": "12345678902",
|
"nationalId": "12345678902",
|
||||||
"birthDate": "02-08-1990",
|
"birthDate": "2015-10-30",
|
||||||
"gender": "Female",
|
"gender": "Female",
|
||||||
"maritalStatus": "Single",
|
"maritalStatus": "Single",
|
||||||
"country": "TR",
|
"country": "TR",
|
||||||
|
|
@ -2938,7 +2931,7 @@
|
||||||
"fullName": "Mehmet Yılmaz",
|
"fullName": "Mehmet Yılmaz",
|
||||||
"avatar": "https://i.pravatar.cc/150?img=8",
|
"avatar": "https://i.pravatar.cc/150?img=8",
|
||||||
"nationalId": "12345678903",
|
"nationalId": "12345678903",
|
||||||
"birthDate": "12-03-1987",
|
"birthDate": "2010-10-31",
|
||||||
"gender": "Male",
|
"gender": "Male",
|
||||||
"maritalStatus": "Married",
|
"maritalStatus": "Married",
|
||||||
"country": "TR",
|
"country": "TR",
|
||||||
|
|
@ -2978,7 +2971,7 @@
|
||||||
"fullName": "Selin Demir",
|
"fullName": "Selin Demir",
|
||||||
"avatar": "https://i.pravatar.cc/150?img=9",
|
"avatar": "https://i.pravatar.cc/150?img=9",
|
||||||
"nationalId": "12345678904",
|
"nationalId": "12345678904",
|
||||||
"birthDate": "05-05-1993",
|
"birthDate": "2000-11-01",
|
||||||
"gender": "Female",
|
"gender": "Female",
|
||||||
"maritalStatus": "Single",
|
"maritalStatus": "Single",
|
||||||
"country": "TR",
|
"country": "TR",
|
||||||
|
|
@ -3018,7 +3011,7 @@
|
||||||
"fullName": "Ahmet Çelik",
|
"fullName": "Ahmet Çelik",
|
||||||
"avatar": "https://i.pravatar.cc/150?img=33",
|
"avatar": "https://i.pravatar.cc/150?img=33",
|
||||||
"nationalId": "12345678905",
|
"nationalId": "12345678905",
|
||||||
"birthDate": "10-09-1985",
|
"birthDate": "1999-11-02",
|
||||||
"gender": "Male",
|
"gender": "Male",
|
||||||
"maritalStatus": "Married",
|
"maritalStatus": "Married",
|
||||||
"country": "TR",
|
"country": "TR",
|
||||||
|
|
@ -3058,7 +3051,7 @@
|
||||||
"fullName": "Zeynep Arslan",
|
"fullName": "Zeynep Arslan",
|
||||||
"avatar": "https://i.pravatar.cc/150?img=10",
|
"avatar": "https://i.pravatar.cc/150?img=10",
|
||||||
"nationalId": "12345678906",
|
"nationalId": "12345678906",
|
||||||
"birthDate": "01-01-1995",
|
"birthDate": "1995-11-03",
|
||||||
"gender": "Female",
|
"gender": "Female",
|
||||||
"maritalStatus": "Single",
|
"maritalStatus": "Single",
|
||||||
"country": "TR",
|
"country": "TR",
|
||||||
|
|
@ -3098,7 +3091,7 @@
|
||||||
"fullName": "Burak Koç",
|
"fullName": "Burak Koç",
|
||||||
"avatar": "https://i.pravatar.cc/150?img=14",
|
"avatar": "https://i.pravatar.cc/150?img=14",
|
||||||
"nationalId": "12345678907",
|
"nationalId": "12345678907",
|
||||||
"birthDate": "08-06-1991",
|
"birthDate": "1980-11-04",
|
||||||
"gender": "Male",
|
"gender": "Male",
|
||||||
"maritalStatus": "Married",
|
"maritalStatus": "Married",
|
||||||
"country": "TR",
|
"country": "TR",
|
||||||
|
|
@ -3138,7 +3131,7 @@
|
||||||
"fullName": "Elif Şahin",
|
"fullName": "Elif Şahin",
|
||||||
"avatar": "https://i.pravatar.cc/150?img=20",
|
"avatar": "https://i.pravatar.cc/150?img=20",
|
||||||
"nationalId": "12345678908",
|
"nationalId": "12345678908",
|
||||||
"birthDate": "05-11-1989",
|
"birthDate": "1989-11-05",
|
||||||
"gender": "Female",
|
"gender": "Female",
|
||||||
"maritalStatus": "Married",
|
"maritalStatus": "Married",
|
||||||
"country": "TR",
|
"country": "TR",
|
||||||
|
|
@ -3178,7 +3171,7 @@
|
||||||
"fullName": "Canan Öztürk",
|
"fullName": "Canan Öztürk",
|
||||||
"avatar": "https://i.pravatar.cc/150?img=25",
|
"avatar": "https://i.pravatar.cc/150?img=25",
|
||||||
"nationalId": "12345678909",
|
"nationalId": "12345678909",
|
||||||
"birthDate": "04-04-1992",
|
"birthDate": "1992-11-06",
|
||||||
"gender": "Female",
|
"gender": "Female",
|
||||||
"maritalStatus": "Single",
|
"maritalStatus": "Single",
|
||||||
"country": "TR",
|
"country": "TR",
|
||||||
|
|
@ -3218,7 +3211,7 @@
|
||||||
"fullName": "Murat Aydın",
|
"fullName": "Murat Aydın",
|
||||||
"avatar": "https://i.pravatar.cc/150?img=30",
|
"avatar": "https://i.pravatar.cc/150?img=30",
|
||||||
"nationalId": "12345678910",
|
"nationalId": "12345678910",
|
||||||
"birthDate": "03-12-1984",
|
"birthDate": "1984-11-07",
|
||||||
"gender": "Male",
|
"gender": "Male",
|
||||||
"maritalStatus": "Married",
|
"maritalStatus": "Married",
|
||||||
"country": "TR",
|
"country": "TR",
|
||||||
|
|
@ -3561,8 +3554,8 @@
|
||||||
"category": "technical",
|
"category": "technical",
|
||||||
"type": "online",
|
"type": "online",
|
||||||
"duration": 16,
|
"duration": 16,
|
||||||
"startDate": "01-11-2024",
|
"startDate": "2025-10-29",
|
||||||
"endDate": "08-11-2024",
|
"endDate": "2025-11-08",
|
||||||
"maxParticipants": 20,
|
"maxParticipants": 20,
|
||||||
"enrolled": 15,
|
"enrolled": 15,
|
||||||
"status": "upcoming",
|
"status": "upcoming",
|
||||||
|
|
@ -3576,8 +3569,8 @@
|
||||||
"category": "soft-skills",
|
"category": "soft-skills",
|
||||||
"type": "classroom",
|
"type": "classroom",
|
||||||
"duration": 8,
|
"duration": 8,
|
||||||
"startDate": "05-10-2024",
|
"startDate": "2024-11-05",
|
||||||
"endDate": "05-10-2024",
|
"endDate": "2024-12-05",
|
||||||
"maxParticipants": 15,
|
"maxParticipants": 15,
|
||||||
"enrolled": 12,
|
"enrolled": 12,
|
||||||
"status": "ongoing",
|
"status": "ongoing",
|
||||||
|
|
@ -3591,8 +3584,8 @@
|
||||||
"category": "management",
|
"category": "management",
|
||||||
"type": "hybrid",
|
"type": "hybrid",
|
||||||
"duration": 24,
|
"duration": 24,
|
||||||
"startDate": "10-09-2024",
|
"startDate": "2025-10-29",
|
||||||
"endDate": "03-09-2024",
|
"endDate": "2025-11-03",
|
||||||
"maxParticipants": 25,
|
"maxParticipants": 25,
|
||||||
"enrolled": 25,
|
"enrolled": 25,
|
||||||
"status": "completed",
|
"status": "completed",
|
||||||
|
|
@ -3606,8 +3599,8 @@
|
||||||
"category": "compliance",
|
"category": "compliance",
|
||||||
"type": "online",
|
"type": "online",
|
||||||
"duration": 12,
|
"duration": 12,
|
||||||
"startDate": "05-11-2024",
|
"startDate": "2024-11-05",
|
||||||
"endDate": "02-11-2024",
|
"endDate": "2024-11-30",
|
||||||
"maxParticipants": 50,
|
"maxParticipants": 50,
|
||||||
"enrolled": 8,
|
"enrolled": 8,
|
||||||
"status": "upcoming",
|
"status": "upcoming",
|
||||||
|
|
@ -3620,8 +3613,8 @@
|
||||||
"type": "room",
|
"type": "room",
|
||||||
"resourceName": "Toplantı Salonu A",
|
"resourceName": "Toplantı Salonu A",
|
||||||
"employeeCode": "EMP-001",
|
"employeeCode": "EMP-001",
|
||||||
"startDate": "10-10-2024 09:00:00",
|
"startDate": "10-10-2025 09:00:00",
|
||||||
"endDate": "10-10-2024 11:00:00",
|
"endDate": "10-10-2025 11:00:00",
|
||||||
"purpose": "Sprint Planning Toplantısı",
|
"purpose": "Sprint Planning Toplantısı",
|
||||||
"status": "approved",
|
"status": "approved",
|
||||||
"participants": 8,
|
"participants": 8,
|
||||||
|
|
@ -3631,8 +3624,8 @@
|
||||||
"type": "vehicle",
|
"type": "vehicle",
|
||||||
"resourceName": "Şirket Aracı - 34 ABC 123",
|
"resourceName": "Şirket Aracı - 34 ABC 123",
|
||||||
"employeeCode": "EMP-001",
|
"employeeCode": "EMP-001",
|
||||||
"startDate": "11-10-2024 08:00:00",
|
"startDate": "11-10-2025 08:00:00",
|
||||||
"endDate": "11-10-2024 18:00:00",
|
"endDate": "11-10-2025 18:00:00",
|
||||||
"purpose": "Müşteri Ziyareti",
|
"purpose": "Müşteri Ziyareti",
|
||||||
"status": "pending",
|
"status": "pending",
|
||||||
"notes": "Ankara çıkışı"
|
"notes": "Ankara çıkışı"
|
||||||
|
|
@ -3641,8 +3634,8 @@
|
||||||
"type": "equipment",
|
"type": "equipment",
|
||||||
"resourceName": "Kamera ve Tripod Seti",
|
"resourceName": "Kamera ve Tripod Seti",
|
||||||
"employeeCode": "EMP-001",
|
"employeeCode": "EMP-001",
|
||||||
"startDate": "09-10-2024 14:00:00",
|
"startDate": "09-10-2025 14:00:00",
|
||||||
"endDate": "09-10-2024 17:00:00",
|
"endDate": "09-10-2025 17:00:00",
|
||||||
"purpose": "Ürün Tanıtım Videosu Çekimi",
|
"purpose": "Ürün Tanıtım Videosu Çekimi",
|
||||||
"status": "approved"
|
"status": "approved"
|
||||||
},
|
},
|
||||||
|
|
@ -3650,8 +3643,8 @@
|
||||||
"type": "room",
|
"type": "room",
|
||||||
"resourceName": "Eğitim Salonu B",
|
"resourceName": "Eğitim Salonu B",
|
||||||
"employeeCode": "EMP-001",
|
"employeeCode": "EMP-001",
|
||||||
"startDate": "05-10-2024 09:00:00",
|
"startDate": "05-10-2025 09:00:00",
|
||||||
"endDate": "05-10-2024 17:00:00",
|
"endDate": "05-10-2025 17:00:00",
|
||||||
"purpose": "Etkili İletişim Eğitimi",
|
"purpose": "Etkili İletişim Eğitimi",
|
||||||
"status": "approved",
|
"status": "approved",
|
||||||
"participants": 15,
|
"participants": 15,
|
||||||
|
|
@ -3783,33 +3776,36 @@
|
||||||
"companyName": "ABC Teknoloji",
|
"companyName": "ABC Teknoloji",
|
||||||
"email": "ali.veli@abc.com",
|
"email": "ali.veli@abc.com",
|
||||||
"phone": "5321112233",
|
"phone": "5321112233",
|
||||||
"visitDate": "2025-10-05",
|
"visitDate": "2025-10-29T09:00:00",
|
||||||
"checkIn": "05-10-2025",
|
"checkIn": "2025-10-29T09:15:00",
|
||||||
"employeeCode": "EMP-001",
|
"employeeCode": "EMP-001",
|
||||||
"purpose": "İş Ortaklığı Görüşmesi",
|
"purpose": "İş Ortaklığı Görüşmesi",
|
||||||
"status": "checked-in"
|
"status": "checked-in",
|
||||||
|
"photo": "https://i.pravatar.cc/150?img=12"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fullName": "Fatma Yıldız",
|
"fullName": "Fatma Yıldız",
|
||||||
"companyName": "XYZ Danışmanlık",
|
"companyName": "XYZ Danışmanlık",
|
||||||
"email": "fatma@xyz.com",
|
"email": "fatma@xyz.com",
|
||||||
"phone": "5332223344",
|
"phone": "5332223344",
|
||||||
"visitDate": "01-10-2024",
|
"visitDate": "2025-10-30T10:30:00",
|
||||||
"employeeCode": "EMP-002",
|
"employeeCode": "EMP-002",
|
||||||
"purpose": "Eğitim Danışmanlığı",
|
"purpose": "Eğitim Danışmanlığı",
|
||||||
"status": "scheduled"
|
"status": "scheduled",
|
||||||
|
"photo": "https://i.pravatar.cc/150?img=13"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fullName": "Mehmet Kara",
|
"fullName": "Mehmet Kara",
|
||||||
"companyName": "DEF Yazılım",
|
"companyName": "DEF Yazılım",
|
||||||
"email": "mehmet@def.com",
|
"email": "mehmet@def.com",
|
||||||
"phone": "5343334455",
|
"phone": "5343334455",
|
||||||
"visitDate": "08-10-2024",
|
"visitDate": "2025-10-31T14:00:00",
|
||||||
"checkIn": "08-10-2024",
|
"checkIn": "2025-10-31T14:10:00",
|
||||||
"checkOut": "10-10-2024",
|
"checkOut": "2025-10-31T16:00:00",
|
||||||
"employeeCode": "EMP-003",
|
"employeeCode": "EMP-003",
|
||||||
"purpose": "Teknik Sunum",
|
"purpose": "Teknik Sunum",
|
||||||
"status": "checked-out"
|
"status": "checked-out",
|
||||||
|
"photo": "https://i.pravatar.cc/150?img=14"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"ExpenseRequests": [
|
"ExpenseRequests": [
|
||||||
|
|
@ -3818,19 +3814,19 @@
|
||||||
"category": "travel",
|
"category": "travel",
|
||||||
"amount": 850,
|
"amount": 850,
|
||||||
"currencyCode": "TRY",
|
"currencyCode": "TRY",
|
||||||
"requestDate": "08-10-2024",
|
"requestDate": "2025-10-04",
|
||||||
"description": "Ankara ofis ziyareti - uçak bileti",
|
"description": "Ankara ofis ziyareti - uçak bileti",
|
||||||
"project": "Intranet v2",
|
"project": "Intranet v2",
|
||||||
"status": "approved",
|
"status": "approved",
|
||||||
"approverCode": "EMP-004",
|
"approverCode": "EMP-004",
|
||||||
"approvalDate": "10-10-2024"
|
"approvalDate": "2025-10-10"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"employeeCode": "EMP-002",
|
"employeeCode": "EMP-002",
|
||||||
"category": "meal",
|
"category": "meal",
|
||||||
"amount": 320,
|
"amount": 320,
|
||||||
"currencyCode": "TRY",
|
"currencyCode": "TRY",
|
||||||
"requestDate": "07-10-2024",
|
"requestDate": "2025-10-07",
|
||||||
"description": "Müşteri toplantısı - öğle yemeği",
|
"description": "Müşteri toplantısı - öğle yemeği",
|
||||||
"project": null,
|
"project": null,
|
||||||
"status": "pending",
|
"status": "pending",
|
||||||
|
|
@ -3842,12 +3838,12 @@
|
||||||
"category": "accommodation",
|
"category": "accommodation",
|
||||||
"amount": 1200,
|
"amount": 1200,
|
||||||
"currencyCode": "TRY",
|
"currencyCode": "TRY",
|
||||||
"requestDate": "04-10-2024",
|
"requestDate": "2025-10-04",
|
||||||
"description": "İzmir workshop - otel konaklaması (2 gece)",
|
"description": "İzmir workshop - otel konaklaması (2 gece)",
|
||||||
"project": "UX Workshop",
|
"project": "UX Workshop",
|
||||||
"status": "approved",
|
"status": "approved",
|
||||||
"approverCode": "EMP-005",
|
"approverCode": "EMP-005",
|
||||||
"approvalDate": "05-10-2024"
|
"approvalDate": "2025-10-05"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Surveys": [
|
"Surveys": [
|
||||||
|
|
@ -4105,9 +4101,7 @@
|
||||||
{
|
{
|
||||||
"postContent": "CI/CD pipeline güncellememiz tamamlandı! Deployment süremiz %40 azaldı. Otomasyonun gücü 💪",
|
"postContent": "CI/CD pipeline güncellememiz tamamlandı! Deployment süremiz %40 azaldı. Otomasyonun gücü 💪",
|
||||||
"type": "video",
|
"type": "video",
|
||||||
"urls": [
|
"urls": ["https://www.w3schools.com/html/mov_bbb.mp4"]
|
||||||
"https://www.w3schools.com/html/mov_bbb.mp4"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"SocialPollOptions": [
|
"SocialPollOptions": [
|
||||||
|
|
@ -4188,4 +4182,4 @@
|
||||||
"employeeCode": "EMP-003"
|
"employeeCode": "EMP-003"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1293,7 +1293,8 @@ public class TenantDataSeeder : IDataSeedContributor, ITransientDependency
|
||||||
CheckIn = item.CheckIn,
|
CheckIn = item.CheckIn,
|
||||||
CheckOut = item.CheckOut,
|
CheckOut = item.CheckOut,
|
||||||
EmployeeId = employee != null ? employee.Id : null,
|
EmployeeId = employee != null ? employee.Id : null,
|
||||||
Status = item.Status
|
Status = item.Status,
|
||||||
|
Photo = item.Photo
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -201,6 +201,7 @@ public class VisitorSeedDto
|
||||||
public DateTime? CheckOut { get; set; }
|
public DateTime? CheckOut { get; set; }
|
||||||
public string EmployeeCode { get; set; }
|
public string EmployeeCode { get; set; }
|
||||||
public string Status { get; set; }
|
public string Status { get; set; }
|
||||||
|
public string Photo { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AnnouncementSeedDto
|
public class AnnouncementSeedDto
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { useState, useRef, useEffect } from "react";
|
import React, { useState, useRef, useEffect } from "react";
|
||||||
import { FaChevronDown, FaTimes } from "react-icons/fa";
|
import { FaChevronDown, FaTimes } from "react-icons/fa";
|
||||||
import { mockEmployees } from "../../mocks/mockEmployees";
|
import { mockEmployees } from "../../mocks/mockEmployees";
|
||||||
import { HrEmployee } from "../../types/hr";
|
import { EmployeeDto } from "../../types/hr";
|
||||||
|
|
||||||
interface MultiSelectEmployeeProps {
|
interface MultiSelectEmployeeProps {
|
||||||
selectedEmployees: string[];
|
selectedEmployees: string[];
|
||||||
|
|
@ -40,7 +40,7 @@ const MultiSelectEmployee: React.FC<MultiSelectEmployeeProps> = ({
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const filteredEmployees = mockEmployees.filter(
|
const filteredEmployees = mockEmployees.filter(
|
||||||
(employee: HrEmployee) =>
|
(employee: EmployeeDto) =>
|
||||||
employee.fullName.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
employee.fullName.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||||
employee.code.toLowerCase().includes(searchTerm.toLowerCase())
|
employee.code.toLowerCase().includes(searchTerm.toLowerCase())
|
||||||
);
|
);
|
||||||
|
|
@ -58,7 +58,7 @@ const MultiSelectEmployee: React.FC<MultiSelectEmployeeProps> = ({
|
||||||
onChange(selectedEmployees.filter((id) => id !== employeeId));
|
onChange(selectedEmployees.filter((id) => id !== employeeId));
|
||||||
};
|
};
|
||||||
|
|
||||||
const selectedEmployeeObjects = mockEmployees.filter((emp: HrEmployee) =>
|
const selectedEmployeeObjects = mockEmployees.filter((emp: EmployeeDto) =>
|
||||||
selectedEmployees.includes(emp.id)
|
selectedEmployees.includes(emp.id)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -79,7 +79,7 @@ const MultiSelectEmployee: React.FC<MultiSelectEmployeeProps> = ({
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div className="flex flex-wrap gap-1 flex-1">
|
<div className="flex flex-wrap gap-1 flex-1">
|
||||||
{selectedEmployeeObjects.length > 0 ? (
|
{selectedEmployeeObjects.length > 0 ? (
|
||||||
selectedEmployeeObjects.map((employee: HrEmployee) => (
|
selectedEmployeeObjects.map((employee: EmployeeDto) => (
|
||||||
<span
|
<span
|
||||||
key={employee.id}
|
key={employee.id}
|
||||||
className="inline-flex items-center px-2 py-1 rounded-md text-xs font-medium bg-blue-100 text-blue-800"
|
className="inline-flex items-center px-2 py-1 rounded-md text-xs font-medium bg-blue-100 text-blue-800"
|
||||||
|
|
@ -127,7 +127,7 @@ const MultiSelectEmployee: React.FC<MultiSelectEmployeeProps> = ({
|
||||||
{/* Options List */}
|
{/* Options List */}
|
||||||
<div className="max-h-48 overflow-y-auto">
|
<div className="max-h-48 overflow-y-auto">
|
||||||
{filteredEmployees.length > 0 ? (
|
{filteredEmployees.length > 0 ? (
|
||||||
filteredEmployees.map((employee: HrEmployee) => (
|
filteredEmployees.map((employee: EmployeeDto) => (
|
||||||
<div
|
<div
|
||||||
key={employee.id}
|
key={employee.id}
|
||||||
className={`
|
className={`
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { HrDepartment } from '../types/hr'
|
import { DepartmentDto } from '../types/hr'
|
||||||
|
|
||||||
export const mockDepartments: HrDepartment[] = [
|
export const mockDepartments: DepartmentDto[] = [
|
||||||
{
|
{
|
||||||
id: '1',
|
id: '1',
|
||||||
code: 'ÜRT',
|
code: 'ÜRT',
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import {
|
import {
|
||||||
HrEmployee,
|
EmployeeDto,
|
||||||
EmployeeStatusEnum,
|
EmployeeStatusEnum,
|
||||||
EmploymentTypeEnum,
|
EmploymentTypeEnum,
|
||||||
GenderEnum,
|
GenderEnum,
|
||||||
|
|
@ -9,7 +9,7 @@ import { mockBanks } from "./mockBanks";
|
||||||
import { mockDepartments } from "./mockDepartments";
|
import { mockDepartments } from "./mockDepartments";
|
||||||
import { mockJobPositions } from "./mockJobPositions";
|
import { mockJobPositions } from "./mockJobPositions";
|
||||||
|
|
||||||
export const mockEmployees: HrEmployee[] = [
|
export const mockEmployees: EmployeeDto[] = [
|
||||||
{
|
{
|
||||||
id: "1",
|
id: "1",
|
||||||
code: "EMP-001",
|
code: "EMP-001",
|
||||||
|
|
|
||||||
|
|
@ -1,117 +1,14 @@
|
||||||
import { EventDto } from '@/proxy/intranet/models'
|
import { DocumentDto, EventDto, ExpenseDto, ReservationDto, TrainingDto, VisitorDto } from '@/proxy/intranet/models'
|
||||||
import { mockEmployees } from './mockEmployees'
|
import { mockEmployees } from './mockEmployees'
|
||||||
import {
|
import {
|
||||||
Announcement,
|
Announcement,
|
||||||
Visitor,
|
|
||||||
Document,
|
|
||||||
Certificate,
|
Certificate,
|
||||||
ExpenseRequest,
|
|
||||||
Training,
|
|
||||||
Reservation,
|
|
||||||
MealMenu,
|
MealMenu,
|
||||||
ShuttleRoute,
|
ShuttleRoute,
|
||||||
Survey,
|
Survey,
|
||||||
SocialPost,
|
SocialPost,
|
||||||
} from '@/types/intranet'
|
} from '@/types/intranet'
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
///////EKLENENLER//////////
|
|
||||||
export const mockTrainings: Training[] = [
|
|
||||||
{
|
|
||||||
id: 'tr1',
|
|
||||||
title: 'React & TypeScript İleri Seviye',
|
|
||||||
description:
|
|
||||||
'Modern React uygulamaları geliştirmek için TypeScript kullanımı, hooks, context API ve performans optimizasyonu',
|
|
||||||
instructor: 'Mehmet Demir',
|
|
||||||
category: 'technical',
|
|
||||||
type: 'online',
|
|
||||||
duration: 16,
|
|
||||||
startDate: new Date('2024-11-01'),
|
|
||||||
endDate: new Date('2024-11-08'),
|
|
||||||
maxParticipants: 20,
|
|
||||||
enrolled: 15,
|
|
||||||
status: 'upcoming',
|
|
||||||
thumbnail: 'https://images.unsplash.com/photo-1633356122544-f134324a6cee?w=400&h=300&fit=crop',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'tr2',
|
|
||||||
title: 'Etkili İletişim ve Sunum Teknikleri',
|
|
||||||
description:
|
|
||||||
'İş hayatında etkili iletişim kurma, profesyonel sunum hazırlama ve konuşma becerileri geliştirme',
|
|
||||||
instructor: 'Ayşe Kara',
|
|
||||||
category: 'soft-skills',
|
|
||||||
type: 'classroom',
|
|
||||||
duration: 8,
|
|
||||||
startDate: new Date('2024-10-25'),
|
|
||||||
endDate: new Date('2024-10-25'),
|
|
||||||
maxParticipants: 15,
|
|
||||||
enrolled: 12,
|
|
||||||
status: 'ongoing',
|
|
||||||
location: 'Eğitim Salonu A',
|
|
||||||
thumbnail: 'https://images.unsplash.com/photo-1557804506-669a67965ba0?w=400&h=300&fit=crop',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'tr3',
|
|
||||||
title: 'Agile & Scrum Master Eğitimi',
|
|
||||||
description:
|
|
||||||
'Çevik yazılım geliştirme metodolojileri, Scrum framework ve sertifikasyon hazırlığı',
|
|
||||||
instructor: 'Can Öztürk',
|
|
||||||
category: 'management',
|
|
||||||
type: 'hybrid',
|
|
||||||
duration: 24,
|
|
||||||
startDate: new Date('2024-09-15'),
|
|
||||||
endDate: new Date('2024-09-30'),
|
|
||||||
maxParticipants: 25,
|
|
||||||
enrolled: 25,
|
|
||||||
status: 'completed',
|
|
||||||
thumbnail: 'https://images.unsplash.com/photo-1552664730-d307ca884978?w=400&h=300&fit=crop',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'tr4',
|
|
||||||
title: 'Siber Güvenlik ve Veri Koruma',
|
|
||||||
description: 'KVKK uyumluluğu, siber güvenlik tehditleri ve kurumsal veri koruma stratejileri',
|
|
||||||
instructor: 'Zeynep Arslan',
|
|
||||||
category: 'compliance',
|
|
||||||
type: 'online',
|
|
||||||
duration: 12,
|
|
||||||
startDate: new Date('2024-11-15'),
|
|
||||||
endDate: new Date('2024-11-22'),
|
|
||||||
maxParticipants: 50,
|
|
||||||
enrolled: 8,
|
|
||||||
status: 'upcoming',
|
|
||||||
thumbnail: 'https://images.unsplash.com/photo-1550751827-4bd374c3f58b?w=400&h=300&fit=crop',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
export const mockCertificates: Certificate[] = [
|
|
||||||
{
|
|
||||||
id: 'cert1',
|
|
||||||
employee: mockEmployees[0],
|
|
||||||
trainingTitle: 'Agile & Scrum Master Eğitimi',
|
|
||||||
issueDate: new Date('2024-09-30'),
|
|
||||||
expiryDate: new Date('2026-09-30'),
|
|
||||||
certificateUrl: '/certificates/cert1.pdf',
|
|
||||||
score: 95,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'cert2',
|
|
||||||
employee: mockEmployees[2],
|
|
||||||
trainingTitle: 'React & TypeScript İleri Seviye',
|
|
||||||
issueDate: new Date('2024-08-15'),
|
|
||||||
certificateUrl: '/certificates/cert2.pdf',
|
|
||||||
score: 88,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'cert3',
|
|
||||||
employee: mockEmployees[4],
|
|
||||||
trainingTitle: 'Siber Güvenlik ve Veri Koruma',
|
|
||||||
issueDate: new Date('2024-07-20'),
|
|
||||||
expiryDate: new Date('2025-07-20'),
|
|
||||||
certificateUrl: '/certificates/cert3.pdf',
|
|
||||||
score: 92,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
export const mockMealMenus: MealMenu[] = [
|
export const mockMealMenus: MealMenu[] = [
|
||||||
{
|
{
|
||||||
id: 'menu1',
|
id: 'menu1',
|
||||||
|
|
@ -175,7 +72,7 @@ export const mockMealMenus: MealMenu[] = [
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
export const mockReservations: Reservation[] = [
|
export const mockReservations: ReservationDto[] = [
|
||||||
{
|
{
|
||||||
id: 'res1',
|
id: 'res1',
|
||||||
type: 'room',
|
type: 'room',
|
||||||
|
|
@ -334,143 +231,6 @@ export const mockAnnouncements: Announcement[] = [
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
export const mockVisitors: Visitor[] = [
|
|
||||||
{
|
|
||||||
id: 'vis1',
|
|
||||||
fullName: 'Ali Veli',
|
|
||||||
company: 'ABC Teknoloji',
|
|
||||||
email: 'ali.veli@abc.com',
|
|
||||||
phone: '+90 532 111 22 33',
|
|
||||||
visitDate: new Date('2025-10-25T10:00:00'),
|
|
||||||
checkIn: new Date('2025-10-25T10:15:00'),
|
|
||||||
host: mockEmployees[1],
|
|
||||||
purpose: 'İş Ortaklığı Görüşmesi',
|
|
||||||
status: 'checked-in',
|
|
||||||
badgeNumber: 'V-001',
|
|
||||||
photo: 'https://i.pravatar.cc/150?img=60',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'vis2',
|
|
||||||
fullName: 'Fatma Yıldız',
|
|
||||||
company: 'XYZ Danışmanlık',
|
|
||||||
email: 'fatma@xyz.com',
|
|
||||||
phone: '+90 533 222 33 44',
|
|
||||||
visitDate: new Date('2024-10-21T14:00:00'),
|
|
||||||
host: mockEmployees[2],
|
|
||||||
purpose: 'Eğitim Danışmanlığı',
|
|
||||||
status: 'scheduled',
|
|
||||||
photo: 'https://i.pravatar.cc/150?img=47',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'vis3',
|
|
||||||
fullName: 'Mehmet Kara',
|
|
||||||
company: 'DEF Yazılım',
|
|
||||||
email: 'mehmet@def.com',
|
|
||||||
phone: '+90 534 333 44 55',
|
|
||||||
visitDate: new Date('2024-10-18T11:00:00'),
|
|
||||||
checkIn: new Date('2024-10-18T11:05:00'),
|
|
||||||
checkOut: new Date('2024-10-18T13:30:00'),
|
|
||||||
host: mockEmployees[3],
|
|
||||||
purpose: 'Teknik Sunum',
|
|
||||||
status: 'checked-out',
|
|
||||||
badgeNumber: 'V-002',
|
|
||||||
photo: 'https://i.pravatar.cc/150?img=68',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
export const mockExpenseRequests: ExpenseRequest[] = [
|
|
||||||
{
|
|
||||||
id: 'exp1',
|
|
||||||
employee: mockEmployees[0],
|
|
||||||
category: 'travel',
|
|
||||||
amount: 850,
|
|
||||||
currency: 'TRY',
|
|
||||||
date: new Date('2024-10-15'),
|
|
||||||
description: 'Ankara ofis ziyareti - uçak bileti',
|
|
||||||
project: 'Intranet v2',
|
|
||||||
receipts: [{ name: 'ucak_bileti.pdf', url: '#', size: '234 KB' }],
|
|
||||||
status: 'approved',
|
|
||||||
approver: mockEmployees[4],
|
|
||||||
approvalDate: new Date('2024-10-16T10:00:00'),
|
|
||||||
creationTime: new Date('2024-10-15T18:00:00'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'exp2',
|
|
||||||
employee: mockEmployees[2],
|
|
||||||
category: 'meal',
|
|
||||||
amount: 320,
|
|
||||||
currency: 'TRY',
|
|
||||||
date: new Date('2024-10-17'),
|
|
||||||
description: 'Müşteri toplantısı - öğle yemeği',
|
|
||||||
receipts: [{ name: 'restoran_fisi.jpg', url: '#', size: '156 KB' }],
|
|
||||||
status: 'pending',
|
|
||||||
creationTime: new Date('2024-10-17T20:00:00'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'exp3',
|
|
||||||
employee: mockEmployees[1],
|
|
||||||
category: 'accommodation',
|
|
||||||
amount: 1200,
|
|
||||||
currency: 'TRY',
|
|
||||||
date: new Date('2024-10-14'),
|
|
||||||
description: 'İzmir workshop - otel konaklaması (2 gece)',
|
|
||||||
project: 'UX Workshop',
|
|
||||||
receipts: [{ name: 'otel_fatura.pdf', url: '#', size: '445 KB' }],
|
|
||||||
status: 'approved',
|
|
||||||
approver: mockEmployees[4],
|
|
||||||
approvalDate: new Date('2024-10-15T09:00:00'),
|
|
||||||
creationTime: new Date('2024-10-14T22:00:00'),
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
export const mockDocuments: Document[] = [
|
|
||||||
{
|
|
||||||
id: 'doc1',
|
|
||||||
name: 'Çalışan El Kitabı 2024',
|
|
||||||
type: 'pdf',
|
|
||||||
category: 'policy',
|
|
||||||
size: '3.2 MB',
|
|
||||||
uploadedBy: mockEmployees[3],
|
|
||||||
uploadDate: new Date('2024-01-15'),
|
|
||||||
version: '2.0',
|
|
||||||
url: '#',
|
|
||||||
description: 'Şirket politikaları ve prosedürleri',
|
|
||||||
departments: ['Tüm Departmanlar'],
|
|
||||||
downloadCount: 234,
|
|
||||||
tags: ['politika', 'prosedür', 'çalışan hakları'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'doc2',
|
|
||||||
name: 'İzin Talep Formu',
|
|
||||||
type: 'doc',
|
|
||||||
category: 'form',
|
|
||||||
size: '124 KB',
|
|
||||||
uploadedBy: mockEmployees[3],
|
|
||||||
uploadDate: new Date('2024-02-01'),
|
|
||||||
version: '1.5',
|
|
||||||
url: '#',
|
|
||||||
description: 'İzin talepleri için kullanılacak form',
|
|
||||||
departments: ['Tüm Departmanlar'],
|
|
||||||
downloadCount: 567,
|
|
||||||
tags: ['form', 'izin', 'HR'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'doc3',
|
|
||||||
name: 'Yazılım Geliştirme Standartları',
|
|
||||||
type: 'pdf',
|
|
||||||
category: 'procedure',
|
|
||||||
size: '1.8 MB',
|
|
||||||
uploadedBy: mockEmployees[4],
|
|
||||||
uploadDate: new Date('2024-03-10'),
|
|
||||||
version: '3.1',
|
|
||||||
url: '#',
|
|
||||||
description: 'Kod standartları ve best practices',
|
|
||||||
departments: ['Yazılım Geliştirme'],
|
|
||||||
downloadCount: 89,
|
|
||||||
tags: ['development', 'standards', 'coding'],
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
export const mockSurveys: Survey[] = [
|
export const mockSurveys: Survey[] = [
|
||||||
{
|
{
|
||||||
id: 'survey1',
|
id: 'survey1',
|
||||||
|
|
@ -992,3 +752,279 @@ export const mockEvents: EventDto[] = [
|
||||||
isPublished: true,
|
isPublished: true,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
export const mockVisitors: VisitorDto[] = [
|
||||||
|
{
|
||||||
|
id: 'vis1',
|
||||||
|
fullName: 'Ali Veli',
|
||||||
|
companyName: 'ABC Teknoloji',
|
||||||
|
email: 'ali.veli@abc.com',
|
||||||
|
phone: '+90 532 111 22 33',
|
||||||
|
visitDate: new Date('2025-10-25T10:00:00'),
|
||||||
|
checkIn: new Date('2025-10-25T10:15:00'),
|
||||||
|
employeeId: mockEmployees[1].id,
|
||||||
|
employee: mockEmployees[1],
|
||||||
|
purpose: 'İş Ortaklığı Görüşmesi',
|
||||||
|
status: 'checked-in',
|
||||||
|
badgeNumber: 'V-001',
|
||||||
|
photo: 'https://i.pravatar.cc/150?img=60',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'vis2',
|
||||||
|
fullName: 'Fatma Yıldız',
|
||||||
|
companyName: 'XYZ Danışmanlık',
|
||||||
|
email: 'fatma@xyz.com',
|
||||||
|
phone: '+90 533 222 33 44',
|
||||||
|
visitDate: new Date('2024-10-21T14:00:00'),
|
||||||
|
employeeId: mockEmployees[2].id,
|
||||||
|
employee: mockEmployees[2],
|
||||||
|
purpose: 'Eğitim Danışmanlığı',
|
||||||
|
status: 'scheduled',
|
||||||
|
photo: 'https://i.pravatar.cc/150?img=47',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'vis3',
|
||||||
|
fullName: 'Mehmet Kara',
|
||||||
|
companyName: 'DEF Yazılım',
|
||||||
|
email: 'mehmet@def.com',
|
||||||
|
phone: '+90 534 333 44 55',
|
||||||
|
visitDate: new Date('2024-10-18T11:00:00'),
|
||||||
|
checkIn: new Date('2024-10-18T11:05:00'),
|
||||||
|
checkOut: new Date('2024-10-18T13:30:00'),
|
||||||
|
employeeId: mockEmployees[3].id,
|
||||||
|
employee: mockEmployees[3],
|
||||||
|
purpose: 'Teknik Sunum',
|
||||||
|
status: 'checked-out',
|
||||||
|
badgeNumber: 'V-002',
|
||||||
|
photo: 'https://i.pravatar.cc/150?img=68',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
export const mockTrainings: TrainingDto[] = [
|
||||||
|
{
|
||||||
|
id: 'tr1',
|
||||||
|
title: 'React & TypeScript İleri Seviye',
|
||||||
|
description:
|
||||||
|
'Modern React uygulamaları geliştirmek için TypeScript kullanımı, hooks, context API ve performans optimizasyonu',
|
||||||
|
instructor: 'Mehmet Demir',
|
||||||
|
category: 'technical',
|
||||||
|
type: 'online',
|
||||||
|
duration: 16,
|
||||||
|
startDate: new Date('2024-11-01'),
|
||||||
|
endDate: new Date('2024-11-08'),
|
||||||
|
maxParticipants: 20,
|
||||||
|
enrolled: 15,
|
||||||
|
status: 'upcoming',
|
||||||
|
thumbnail: 'https://images.unsplash.com/photo-1633356122544-f134324a6cee?w=400&h=300&fit=crop',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'tr2',
|
||||||
|
title: 'Etkili İletişim ve Sunum Teknikleri',
|
||||||
|
description:
|
||||||
|
'İş hayatında etkili iletişim kurma, profesyonel sunum hazırlama ve konuşma becerileri geliştirme',
|
||||||
|
instructor: 'Ayşe Kara',
|
||||||
|
category: 'soft-skills',
|
||||||
|
type: 'classroom',
|
||||||
|
duration: 8,
|
||||||
|
startDate: new Date('2024-10-25'),
|
||||||
|
endDate: new Date('2024-10-25'),
|
||||||
|
maxParticipants: 15,
|
||||||
|
enrolled: 12,
|
||||||
|
status: 'ongoing',
|
||||||
|
location: 'Eğitim Salonu A',
|
||||||
|
thumbnail: 'https://images.unsplash.com/photo-1557804506-669a67965ba0?w=400&h=300&fit=crop',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'tr3',
|
||||||
|
title: 'Agile & Scrum Master Eğitimi',
|
||||||
|
description:
|
||||||
|
'Çevik yazılım geliştirme metodolojileri, Scrum framework ve sertifikasyon hazırlığı',
|
||||||
|
instructor: 'Can Öztürk',
|
||||||
|
category: 'management',
|
||||||
|
type: 'hybrid',
|
||||||
|
duration: 24,
|
||||||
|
startDate: new Date('2024-09-15'),
|
||||||
|
endDate: new Date('2024-09-30'),
|
||||||
|
maxParticipants: 25,
|
||||||
|
enrolled: 25,
|
||||||
|
status: 'completed',
|
||||||
|
thumbnail: 'https://images.unsplash.com/photo-1552664730-d307ca884978?w=400&h=300&fit=crop',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'tr4',
|
||||||
|
title: 'Siber Güvenlik ve Veri Koruma',
|
||||||
|
description: 'KVKK uyumluluğu, siber güvenlik tehditleri ve kurumsal veri koruma stratejileri',
|
||||||
|
instructor: 'Zeynep Arslan',
|
||||||
|
category: 'compliance',
|
||||||
|
type: 'online',
|
||||||
|
duration: 12,
|
||||||
|
startDate: new Date('2024-11-15'),
|
||||||
|
endDate: new Date('2024-11-22'),
|
||||||
|
maxParticipants: 50,
|
||||||
|
enrolled: 8,
|
||||||
|
status: 'upcoming',
|
||||||
|
thumbnail: 'https://images.unsplash.com/photo-1550751827-4bd374c3f58b?w=400&h=300&fit=crop',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
export const mockCertificates: Certificate[] = [
|
||||||
|
{
|
||||||
|
id: 'cert1',
|
||||||
|
employee: mockEmployees[0],
|
||||||
|
trainingTitle: 'Agile & Scrum Master Eğitimi',
|
||||||
|
issueDate: new Date('2024-09-30'),
|
||||||
|
expiryDate: new Date('2026-09-30'),
|
||||||
|
certificateUrl: '/certificates/cert1.pdf',
|
||||||
|
score: 95,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'cert2',
|
||||||
|
employee: mockEmployees[2],
|
||||||
|
trainingTitle: 'React & TypeScript İleri Seviye',
|
||||||
|
issueDate: new Date('2024-08-15'),
|
||||||
|
certificateUrl: '/certificates/cert2.pdf',
|
||||||
|
score: 88,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'cert3',
|
||||||
|
employee: mockEmployees[4],
|
||||||
|
trainingTitle: 'Siber Güvenlik ve Veri Koruma',
|
||||||
|
issueDate: new Date('2024-07-20'),
|
||||||
|
expiryDate: new Date('2025-07-20'),
|
||||||
|
certificateUrl: '/certificates/cert3.pdf',
|
||||||
|
score: 92,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
export const mockExpenseRequests: ExpenseDto[] = [
|
||||||
|
{
|
||||||
|
id: 'exp1',
|
||||||
|
employee: mockEmployees[0],
|
||||||
|
category: 'travel',
|
||||||
|
amount: 850,
|
||||||
|
currency: 'TRY',
|
||||||
|
date: new Date('2024-10-15'),
|
||||||
|
description: 'Ankara ofis ziyareti - uçak bileti',
|
||||||
|
project: 'Intranet v2',
|
||||||
|
receipts: [{ name: 'ucak_bileti.pdf', url: '#', size: '234 KB' }],
|
||||||
|
status: 'approved',
|
||||||
|
approver: mockEmployees[4],
|
||||||
|
approvalDate: new Date('2024-10-16T10:00:00'),
|
||||||
|
creationTime: new Date('2024-10-15T18:00:00'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'exp2',
|
||||||
|
employee: mockEmployees[2],
|
||||||
|
category: 'meal',
|
||||||
|
amount: 320,
|
||||||
|
currency: 'TRY',
|
||||||
|
date: new Date('2024-10-17'),
|
||||||
|
description: 'Müşteri toplantısı - öğle yemeği',
|
||||||
|
receipts: [{ name: 'restoran_fisi.jpg', url: '#', size: '156 KB' }],
|
||||||
|
status: 'pending',
|
||||||
|
creationTime: new Date('2024-10-17T20:00:00'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'exp3',
|
||||||
|
employee: mockEmployees[1],
|
||||||
|
category: 'accommodation',
|
||||||
|
amount: 1200,
|
||||||
|
currency: 'TRY',
|
||||||
|
date: new Date('2024-10-14'),
|
||||||
|
description: 'İzmir workshop - otel konaklaması (2 gece)',
|
||||||
|
project: 'UX Workshop',
|
||||||
|
receipts: [{ name: 'otel_fatura.pdf', url: '#', size: '445 KB' }],
|
||||||
|
status: 'approved',
|
||||||
|
approver: mockEmployees[4],
|
||||||
|
approvalDate: new Date('2024-10-15T09:00:00'),
|
||||||
|
creationTime: new Date('2024-10-14T22:00:00'),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
export const mockDocuments: DocumentDto[] = [
|
||||||
|
{
|
||||||
|
id: '1',
|
||||||
|
name: 'Çalışan El Kitabı 2024.pdf',
|
||||||
|
type: 'file',
|
||||||
|
size: 3355443, // 3.2 MB
|
||||||
|
extension: '.pdf',
|
||||||
|
mimeType: 'application/pdf',
|
||||||
|
createdAt: new Date('2024-01-15T10:30:00'),
|
||||||
|
modifiedAt: new Date('2024-01-15T10:30:00'),
|
||||||
|
path: 'Çalışan El Kitabı 2024.pdf',
|
||||||
|
parentId: '',
|
||||||
|
isReadOnly: false,
|
||||||
|
childCount: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2',
|
||||||
|
name: 'İzin Talep Formu.docx',
|
||||||
|
type: 'file',
|
||||||
|
size: 126976, // 124 KB
|
||||||
|
extension: '.docx',
|
||||||
|
mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||||
|
createdAt: new Date('2024-02-01T09:00:00'),
|
||||||
|
modifiedAt: new Date('2024-02-01T09:00:00'),
|
||||||
|
path: 'İzin Talep Formu.docx',
|
||||||
|
parentId: '',
|
||||||
|
isReadOnly: false,
|
||||||
|
childCount: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '3',
|
||||||
|
name: 'Yazılım Geliştirme Standartları.pdf',
|
||||||
|
type: 'file',
|
||||||
|
size: 1887437, // 1.8 MB
|
||||||
|
extension: '.pdf',
|
||||||
|
mimeType: 'application/pdf',
|
||||||
|
createdAt: new Date('2024-03-10T14:20:00'),
|
||||||
|
modifiedAt: new Date('2024-03-10T14:20:00'),
|
||||||
|
path: 'Yazılım Geliştirme Standartları.pdf',
|
||||||
|
parentId: '',
|
||||||
|
isReadOnly: false,
|
||||||
|
childCount: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '4',
|
||||||
|
name: 'Masraf Raporu Şablonu.xlsx',
|
||||||
|
type: 'file',
|
||||||
|
size: 245760, // 240 KB
|
||||||
|
extension: '.xlsx',
|
||||||
|
mimeType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||||
|
createdAt: new Date('2024-04-05T11:15:00'),
|
||||||
|
modifiedAt: new Date('2024-04-05T11:15:00'),
|
||||||
|
path: 'Masraf Raporu Şablonu.xlsx',
|
||||||
|
parentId: '',
|
||||||
|
isReadOnly: false,
|
||||||
|
childCount: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '5',
|
||||||
|
name: 'Şirket Sunumu 2024.pptx',
|
||||||
|
type: 'file',
|
||||||
|
size: 5242880, // 5 MB
|
||||||
|
extension: '.pptx',
|
||||||
|
mimeType: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
||||||
|
createdAt: new Date('2024-05-20T16:45:00'),
|
||||||
|
modifiedAt: new Date('2024-06-10T10:30:00'),
|
||||||
|
path: 'Şirket Sunumu 2024.pptx',
|
||||||
|
parentId: '',
|
||||||
|
isReadOnly: false,
|
||||||
|
childCount: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '6',
|
||||||
|
name: 'İK Politikaları.pdf',
|
||||||
|
type: 'file',
|
||||||
|
size: 2097152, // 2 MB
|
||||||
|
extension: '.pdf',
|
||||||
|
mimeType: 'application/pdf',
|
||||||
|
createdAt: new Date('2024-01-10T08:00:00'),
|
||||||
|
modifiedAt: new Date('2024-01-10T08:00:00'),
|
||||||
|
path: 'İK Politikaları.pdf',
|
||||||
|
parentId: '',
|
||||||
|
isReadOnly: true,
|
||||||
|
childCount: 0,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { HrJobPosition, JobLevelEnum } from "../types/hr";
|
import { JobPositionDto, JobLevelEnum } from "../types/hr";
|
||||||
import { mockDepartments } from "./mockDepartments";
|
import { mockDepartments } from "./mockDepartments";
|
||||||
|
|
||||||
export const mockJobPositions: HrJobPosition[] = [
|
export const mockJobPositions: JobPositionDto[] = [
|
||||||
{
|
{
|
||||||
id: "1",
|
id: "1",
|
||||||
code: "DEV-001",
|
code: "DEV-001",
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,27 @@
|
||||||
import { HrEmployee } from '@/types/hr'
|
import { Address, BankAccount } from '@/types/common'
|
||||||
|
import {
|
||||||
|
EmployeeStatusEnum,
|
||||||
|
EmploymentTypeEnum,
|
||||||
|
GenderEnum,
|
||||||
|
HrCostCenter,
|
||||||
|
HrDisciplinaryAction,
|
||||||
|
HrEmergencyContact,
|
||||||
|
HrLeave,
|
||||||
|
HrPerformanceEvaluation,
|
||||||
|
HrTraining,
|
||||||
|
HrWorkSchedule,
|
||||||
|
JobLevelEnum,
|
||||||
|
MaritalStatusEnum,
|
||||||
|
} from '@/types/hr'
|
||||||
|
|
||||||
export interface IntranetDashboardDto {
|
export interface IntranetDashboardDto {
|
||||||
events: EventDto[];
|
events: EventDto[]
|
||||||
|
birthdays: EmployeeDto[]
|
||||||
|
visitors: VisitorDto[]
|
||||||
|
reservations: ReservationDto[]
|
||||||
|
trainings: TrainingDto[]
|
||||||
|
expenses: ExpensesDto
|
||||||
|
documents: DocumentDto[]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Etkinlik
|
// Etkinlik
|
||||||
|
|
@ -13,7 +33,7 @@ export interface EventDto {
|
||||||
name: string
|
name: string
|
||||||
description: string
|
description: string
|
||||||
place: string
|
place: string
|
||||||
organizer: HrEmployee
|
organizer: EmployeeDto
|
||||||
participants: number
|
participants: number
|
||||||
photos: string[]
|
photos: string[]
|
||||||
comments: EventCommentDto[]
|
comments: EventCommentDto[]
|
||||||
|
|
@ -24,8 +44,183 @@ export interface EventDto {
|
||||||
// Etkinlik Yorumu
|
// Etkinlik Yorumu
|
||||||
export interface EventCommentDto {
|
export interface EventCommentDto {
|
||||||
id: string
|
id: string
|
||||||
author: HrEmployee
|
author: EmployeeDto
|
||||||
content: string
|
content: string
|
||||||
creationTime: Date
|
creationTime: Date
|
||||||
likes: number
|
likes: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface EmployeeDto {
|
||||||
|
// İnsan Kaynakları Çalışanı
|
||||||
|
id: string
|
||||||
|
code: string
|
||||||
|
firstName: string
|
||||||
|
lastName: string
|
||||||
|
fullName: string
|
||||||
|
email: string
|
||||||
|
phone?: string
|
||||||
|
personalPhone?: string
|
||||||
|
avatar?: string // Avatar URL
|
||||||
|
nationalId: string
|
||||||
|
birthDate: Date
|
||||||
|
gender: GenderEnum
|
||||||
|
maritalStatus: MaritalStatusEnum
|
||||||
|
address: Address
|
||||||
|
emergencyContact: HrEmergencyContact
|
||||||
|
hireDate: Date
|
||||||
|
terminationDate?: Date
|
||||||
|
employmentType: EmploymentTypeEnum
|
||||||
|
jobPositionId: string
|
||||||
|
jobPosition?: JobPositionDto
|
||||||
|
departmentId: string
|
||||||
|
department?: DepartmentDto
|
||||||
|
managerId?: string
|
||||||
|
manager?: EmployeeDto
|
||||||
|
baseSalary: number
|
||||||
|
currency: string
|
||||||
|
payrollGroup: string
|
||||||
|
bankAccountId: string
|
||||||
|
bankAccount?: BankAccount
|
||||||
|
workLocation: string
|
||||||
|
workSchedule?: HrWorkSchedule
|
||||||
|
badgeNumber?: string
|
||||||
|
employeeStatus: EmployeeStatusEnum
|
||||||
|
isActive: boolean
|
||||||
|
leaves: HrLeave[]
|
||||||
|
evaluations: HrPerformanceEvaluation[]
|
||||||
|
trainings: HrTraining[]
|
||||||
|
disciplinaryActions: HrDisciplinaryAction[]
|
||||||
|
creationTime: Date
|
||||||
|
lastModificationTime: Date
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DepartmentDto {
|
||||||
|
// İnsan Kaynakları Departmanı
|
||||||
|
id: string
|
||||||
|
code: string
|
||||||
|
name: string
|
||||||
|
description?: string
|
||||||
|
parentDepartmentId?: string
|
||||||
|
parentDepartment?: DepartmentDto
|
||||||
|
subDepartments: DepartmentDto[]
|
||||||
|
managerId?: string
|
||||||
|
manager?: EmployeeDto
|
||||||
|
costCenterId?: string
|
||||||
|
costCenter?: HrCostCenter
|
||||||
|
budget: number
|
||||||
|
isActive: boolean
|
||||||
|
creationTime: Date
|
||||||
|
lastModificationTime: Date
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface JobPositionDto {
|
||||||
|
// İnsan Kaynakları İş Pozisyonu
|
||||||
|
id: string
|
||||||
|
code: string
|
||||||
|
name: string
|
||||||
|
description?: string
|
||||||
|
departmentId: string
|
||||||
|
department?: DepartmentDto
|
||||||
|
level: JobLevelEnum
|
||||||
|
minSalary: number
|
||||||
|
maxSalary: number
|
||||||
|
currency: string
|
||||||
|
requiredSkills: string[]
|
||||||
|
responsibilities: string[]
|
||||||
|
qualifications: string[]
|
||||||
|
isActive: boolean
|
||||||
|
employees: EmployeeDto[]
|
||||||
|
creationTime: Date
|
||||||
|
lastModificationTime: Date
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ziyaretçi
|
||||||
|
export interface VisitorDto {
|
||||||
|
id: string
|
||||||
|
fullName: string
|
||||||
|
companyName: string
|
||||||
|
email: string
|
||||||
|
phone: string
|
||||||
|
purpose: string
|
||||||
|
visitDate: Date
|
||||||
|
checkIn?: Date
|
||||||
|
checkOut?: Date
|
||||||
|
employeeId: string
|
||||||
|
employee: EmployeeDto
|
||||||
|
status: 'scheduled' | 'checked-in' | 'checked-out' | 'cancelled'
|
||||||
|
badgeNumber?: string
|
||||||
|
photo?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rezervasyon
|
||||||
|
export interface ReservationDto {
|
||||||
|
id: string
|
||||||
|
type: 'room' | 'vehicle' | 'equipment'
|
||||||
|
resourceName: string
|
||||||
|
bookedBy: EmployeeDto
|
||||||
|
startDate: Date
|
||||||
|
endDate: Date
|
||||||
|
purpose: string
|
||||||
|
status: 'pending' | 'approved' | 'rejected' | 'completed'
|
||||||
|
participants?: number
|
||||||
|
notes?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Eğitim
|
||||||
|
export interface TrainingDto {
|
||||||
|
id: string
|
||||||
|
title: string
|
||||||
|
description: string
|
||||||
|
instructor: string
|
||||||
|
category: 'technical' | 'soft-skills' | 'management' | 'compliance' | 'other'
|
||||||
|
type: 'online' | 'classroom' | 'hybrid'
|
||||||
|
duration: number // saat
|
||||||
|
startDate: Date
|
||||||
|
endDate: Date
|
||||||
|
maxParticipants: number
|
||||||
|
enrolled: number
|
||||||
|
status: 'upcoming' | 'ongoing' | 'completed'
|
||||||
|
location?: string
|
||||||
|
thumbnail?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Harcama
|
||||||
|
export interface ExpensesDto {
|
||||||
|
totalRequested: number
|
||||||
|
totalApproved: number
|
||||||
|
last5Expenses: ExpenseDto[]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Harcama
|
||||||
|
export interface ExpenseDto {
|
||||||
|
id: string
|
||||||
|
employee: EmployeeDto
|
||||||
|
category: 'travel' | 'meal' | 'accommodation' | 'transport' | 'other'
|
||||||
|
amount: number
|
||||||
|
currency: string
|
||||||
|
date: Date
|
||||||
|
description: string
|
||||||
|
project?: string
|
||||||
|
receipts: { name: string; url: string; size: string }[]
|
||||||
|
status: 'pending' | 'approved' | 'rejected'
|
||||||
|
approver?: EmployeeDto
|
||||||
|
approvalDate?: Date
|
||||||
|
notes?: string
|
||||||
|
creationTime: Date
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,8 @@ import {
|
||||||
CrmSalesTarget,
|
CrmSalesTarget,
|
||||||
CrmTerritory,
|
CrmTerritory,
|
||||||
} from './crm'
|
} from './crm'
|
||||||
import { HrEmployee } from './hr'
|
|
||||||
import { SupplierCardTypeEnum, MmSupplierPerformance, SupplierTypeEnum } from './mm'
|
import { SupplierCardTypeEnum, MmSupplierPerformance, SupplierTypeEnum } from './mm'
|
||||||
|
import { EmployeeDto } from '@/proxy/intranet/models'
|
||||||
|
|
||||||
export interface DashboardStats {
|
export interface DashboardStats {
|
||||||
// Gösterge Paneli İstatistikleri
|
// Gösterge Paneli İstatistikleri
|
||||||
|
|
@ -107,7 +107,7 @@ export interface Team {
|
||||||
name: string
|
name: string
|
||||||
description?: string
|
description?: string
|
||||||
managerId: string
|
managerId: string
|
||||||
manager?: HrEmployee
|
manager?: EmployeeDto
|
||||||
members: TeamMember[]
|
members: TeamMember[]
|
||||||
territories?: CrmTerritory[]
|
territories?: CrmTerritory[]
|
||||||
targets?: CrmSalesTarget[]
|
targets?: CrmSalesTarget[]
|
||||||
|
|
@ -122,7 +122,7 @@ export interface TeamMember {
|
||||||
id: string
|
id: string
|
||||||
teamId: string
|
teamId: string
|
||||||
employeeId: string
|
employeeId: string
|
||||||
employee?: HrEmployee
|
employee?: EmployeeDto
|
||||||
role: TeamRoleEnum
|
role: TeamRoleEnum
|
||||||
joinDate: Date
|
joinDate: Date
|
||||||
isActive: boolean
|
isActive: boolean
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { Address, BusinessParty, Contact, PaymentTerms, PriorityEnum } from './common'
|
import { Address, BusinessParty, Contact, PaymentTerms, PriorityEnum } from './common'
|
||||||
import { HrEmployee } from './hr'
|
import { EmployeeDto } from './hr'
|
||||||
import { MmDelivery, MmMaterial, MmUnit } from './mm'
|
import { MmDelivery, MmMaterial, MmUnit } from './mm'
|
||||||
|
|
||||||
export interface CrmSalesOrder {
|
export interface CrmSalesOrder {
|
||||||
|
|
@ -86,7 +86,7 @@ export interface CrmOpportunity {
|
||||||
expectedCloseDate: Date
|
expectedCloseDate: Date
|
||||||
actualCloseDate?: Date
|
actualCloseDate?: Date
|
||||||
assignedTo: string
|
assignedTo: string
|
||||||
assigned?: HrEmployee
|
assigned?: EmployeeDto
|
||||||
teamId?: string
|
teamId?: string
|
||||||
leadSource: LeadSourceEnum
|
leadSource: LeadSourceEnum
|
||||||
campaignId?: string
|
campaignId?: string
|
||||||
|
|
@ -115,7 +115,7 @@ export interface CrmActivity {
|
||||||
endTime?: Date
|
endTime?: Date
|
||||||
duration?: number // minutes
|
duration?: number // minutes
|
||||||
assignedTo: string
|
assignedTo: string
|
||||||
assigned?: HrEmployee
|
assigned?: EmployeeDto
|
||||||
participants: string[]
|
participants: string[]
|
||||||
status: ActivityStatusEnum
|
status: ActivityStatusEnum
|
||||||
priority: PriorityEnum
|
priority: PriorityEnum
|
||||||
|
|
|
||||||
|
|
@ -1,49 +1,6 @@
|
||||||
|
import { DepartmentDto, EmployeeDto, JobPositionDto } from '@/proxy/intranet/models'
|
||||||
import { Address, BankAccount } from './common'
|
import { Address, BankAccount } from './common'
|
||||||
|
|
||||||
export interface HrEmployee {
|
|
||||||
// İnsan Kaynakları Çalışanı
|
|
||||||
id: string
|
|
||||||
code: string
|
|
||||||
firstName: string
|
|
||||||
lastName: string
|
|
||||||
fullName: string
|
|
||||||
email: string
|
|
||||||
phone?: string
|
|
||||||
personalPhone?: string
|
|
||||||
avatar?: string // Avatar URL
|
|
||||||
nationalId: string
|
|
||||||
birthDate: Date
|
|
||||||
gender: GenderEnum
|
|
||||||
maritalStatus: MaritalStatusEnum
|
|
||||||
address: Address
|
|
||||||
emergencyContact: HrEmergencyContact
|
|
||||||
hireDate: Date
|
|
||||||
terminationDate?: Date
|
|
||||||
employmentType: EmploymentTypeEnum
|
|
||||||
jobPositionId: string
|
|
||||||
jobPosition?: HrJobPosition
|
|
||||||
departmentId: string
|
|
||||||
department?: HrDepartment
|
|
||||||
managerId?: string
|
|
||||||
manager?: HrEmployee
|
|
||||||
baseSalary: number
|
|
||||||
currency: string
|
|
||||||
payrollGroup: string
|
|
||||||
bankAccountId: string
|
|
||||||
bankAccount?: BankAccount
|
|
||||||
workLocation: string
|
|
||||||
workSchedule?: HrWorkSchedule
|
|
||||||
badgeNumber?: string
|
|
||||||
employeeStatus: EmployeeStatusEnum
|
|
||||||
isActive: boolean
|
|
||||||
leaves: HrLeave[]
|
|
||||||
evaluations: HrPerformanceEvaluation[]
|
|
||||||
trainings: HrTraining[]
|
|
||||||
disciplinaryActions: HrDisciplinaryAction[]
|
|
||||||
creationTime: Date
|
|
||||||
lastModificationTime: Date
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface HrCostCenter {
|
export interface HrCostCenter {
|
||||||
// İnsan Kaynakları Masraf Merkezi
|
// İnsan Kaynakları Masraf Merkezi
|
||||||
id: string
|
id: string
|
||||||
|
|
@ -54,9 +11,9 @@ export interface HrCostCenter {
|
||||||
parentCostCenter?: HrCostCenter
|
parentCostCenter?: HrCostCenter
|
||||||
subCostCenters: HrCostCenter[]
|
subCostCenters: HrCostCenter[]
|
||||||
responsibleEmployeeId?: string
|
responsibleEmployeeId?: string
|
||||||
responsibleEmployee?: HrEmployee
|
responsibleEmployee?: EmployeeDto
|
||||||
departmentId?: string
|
departmentId?: string
|
||||||
department?: HrDepartment
|
department?: DepartmentDto
|
||||||
costCenterType: CostCenterType
|
costCenterType: CostCenterType
|
||||||
budgetedAmount: number
|
budgetedAmount: number
|
||||||
actualAmount: number
|
actualAmount: number
|
||||||
|
|
@ -67,51 +24,11 @@ export interface HrCostCenter {
|
||||||
lastModificationTime: Date
|
lastModificationTime: Date
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface HrDepartment {
|
|
||||||
// İnsan Kaynakları Departmanı
|
|
||||||
id: string
|
|
||||||
code: string
|
|
||||||
name: string
|
|
||||||
description?: string
|
|
||||||
parentDepartmentId?: string
|
|
||||||
parentDepartment?: HrDepartment
|
|
||||||
subDepartments: HrDepartment[]
|
|
||||||
managerId?: string
|
|
||||||
manager?: HrEmployee
|
|
||||||
costCenterId?: string
|
|
||||||
costCenter?: HrCostCenter
|
|
||||||
budget: number
|
|
||||||
isActive: boolean
|
|
||||||
creationTime: Date
|
|
||||||
lastModificationTime: Date
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface HrJobPosition {
|
|
||||||
// İnsan Kaynakları İş Pozisyonu
|
|
||||||
id: string
|
|
||||||
code: string
|
|
||||||
name: string
|
|
||||||
description?: string
|
|
||||||
departmentId: string
|
|
||||||
department?: HrDepartment
|
|
||||||
level: JobLevelEnum
|
|
||||||
minSalary: number
|
|
||||||
maxSalary: number
|
|
||||||
currency: string
|
|
||||||
requiredSkills: string[]
|
|
||||||
responsibilities: string[]
|
|
||||||
qualifications: string[]
|
|
||||||
isActive: boolean
|
|
||||||
employees: HrEmployee[]
|
|
||||||
creationTime: Date
|
|
||||||
lastModificationTime: Date
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface HrLeave {
|
export interface HrLeave {
|
||||||
// İnsan Kaynakları İzni
|
// İnsan Kaynakları İzni
|
||||||
id: string
|
id: string
|
||||||
employeeId: string
|
employeeId: string
|
||||||
employee?: HrEmployee
|
employee?: EmployeeDto
|
||||||
leaveType: LeaveTypeEnum
|
leaveType: LeaveTypeEnum
|
||||||
startDate: Date
|
startDate: Date
|
||||||
endDate: Date
|
endDate: Date
|
||||||
|
|
@ -132,9 +49,9 @@ export interface HrPerformanceEvaluation {
|
||||||
// İnsan Kaynakları Performans Değerlendirmesi
|
// İnsan Kaynakları Performans Değerlendirmesi
|
||||||
id: string
|
id: string
|
||||||
employeeId: string
|
employeeId: string
|
||||||
employee?: HrEmployee
|
employee?: EmployeeDto
|
||||||
evaluatorId: string
|
evaluatorId: string
|
||||||
evaluator?: HrEmployee
|
evaluator?: EmployeeDto
|
||||||
evaluationPeriod: string
|
evaluationPeriod: string
|
||||||
evaluationType: EvaluationTypeEnum
|
evaluationType: EvaluationTypeEnum
|
||||||
overallRating: number
|
overallRating: number
|
||||||
|
|
@ -202,7 +119,7 @@ export interface HrTrainingParticipant {
|
||||||
id: string
|
id: string
|
||||||
trainingId: string
|
trainingId: string
|
||||||
employeeId: string
|
employeeId: string
|
||||||
employee?: HrEmployee
|
employee?: EmployeeDto
|
||||||
enrollmentDate: Date
|
enrollmentDate: Date
|
||||||
completionDate?: Date
|
completionDate?: Date
|
||||||
status: ParticipationStatusEnum
|
status: ParticipationStatusEnum
|
||||||
|
|
@ -236,7 +153,7 @@ export interface HrDisciplinaryAction {
|
||||||
// İnsan Kaynakları Disiplin Cezası
|
// İnsan Kaynakları Disiplin Cezası
|
||||||
id: string
|
id: string
|
||||||
employeeId: string
|
employeeId: string
|
||||||
employee?: HrEmployee
|
employee?: EmployeeDto
|
||||||
actionType: DisciplinaryActionTypeEnum
|
actionType: DisciplinaryActionTypeEnum
|
||||||
reason: string
|
reason: string
|
||||||
description: string
|
description: string
|
||||||
|
|
@ -272,7 +189,7 @@ export interface HrOvertime {
|
||||||
// İnsan Kaynakları Fazla Mesai
|
// İnsan Kaynakları Fazla Mesai
|
||||||
id: string
|
id: string
|
||||||
employeeId: string
|
employeeId: string
|
||||||
employee?: HrEmployee
|
employee?: EmployeeDto
|
||||||
date: Date
|
date: Date
|
||||||
startTime: string
|
startTime: string
|
||||||
endTime: string
|
endTime: string
|
||||||
|
|
@ -280,7 +197,7 @@ export interface HrOvertime {
|
||||||
reason: string
|
reason: string
|
||||||
status: LeaveStatusEnum
|
status: LeaveStatusEnum
|
||||||
approvedBy?: string
|
approvedBy?: string
|
||||||
approver?: HrEmployee
|
approver?: EmployeeDto
|
||||||
rate?: number
|
rate?: number
|
||||||
amount?: number
|
amount?: number
|
||||||
creationTime: Date
|
creationTime: Date
|
||||||
|
|
@ -291,7 +208,7 @@ export interface HrPayroll {
|
||||||
// İnsan Kaynakları Maaş Bordrosu
|
// İnsan Kaynakları Maaş Bordrosu
|
||||||
id: string
|
id: string
|
||||||
employeeId: string
|
employeeId: string
|
||||||
employee?: HrEmployee
|
employee?: EmployeeDto
|
||||||
period: string
|
period: string
|
||||||
baseSalary: number
|
baseSalary: number
|
||||||
allowances: HrPayrollAllowance[] // İnsan Kaynakları Maaş Ek Ödemeleri
|
allowances: HrPayrollAllowance[] // İnsan Kaynakları Maaş Ek Ödemeleri
|
||||||
|
|
@ -346,7 +263,7 @@ export interface HrOrganizationChart {
|
||||||
// İnsan Kaynakları Organizasyon Şeması
|
// İnsan Kaynakları Organizasyon Şeması
|
||||||
id: string
|
id: string
|
||||||
employeeId: string
|
employeeId: string
|
||||||
employee?: HrEmployee
|
employee?: EmployeeDto
|
||||||
parentId?: string
|
parentId?: string
|
||||||
parent?: HrOrganizationChart
|
parent?: HrOrganizationChart
|
||||||
children?: HrOrganizationChart[]
|
children?: HrOrganizationChart[]
|
||||||
|
|
@ -359,7 +276,7 @@ export interface HrEmployeeBadge {
|
||||||
// İnsan Kaynakları Çalışan Rozeti
|
// İnsan Kaynakları Çalışan Rozeti
|
||||||
id: string
|
id: string
|
||||||
employeeId: string
|
employeeId: string
|
||||||
employee?: HrEmployee
|
employee?: EmployeeDto
|
||||||
badgeId: string
|
badgeId: string
|
||||||
badge?: HrBadge
|
badge?: HrBadge
|
||||||
earnedDate: Date
|
earnedDate: Date
|
||||||
|
|
@ -454,9 +371,9 @@ export interface HrEvaluation360Participant {
|
||||||
id: string
|
id: string
|
||||||
campaignId: string
|
campaignId: string
|
||||||
evaluatedEmployeeId: string // Değerlendirilen kişi
|
evaluatedEmployeeId: string // Değerlendirilen kişi
|
||||||
evaluatedEmployee?: HrEmployee
|
evaluatedEmployee?: EmployeeDto
|
||||||
evaluatorId: string // Değerlendiren kişi
|
evaluatorId: string // Değerlendiren kişi
|
||||||
evaluator?: HrEmployee
|
evaluator?: EmployeeDto
|
||||||
evaluatorType: AssessorTypeEnum
|
evaluatorType: AssessorTypeEnum
|
||||||
status: ParticipantStatusEnum
|
status: ParticipantStatusEnum
|
||||||
invitedDate: Date
|
invitedDate: Date
|
||||||
|
|
@ -484,7 +401,7 @@ export interface HrEvaluation360Result {
|
||||||
id: string
|
id: string
|
||||||
campaignId: string
|
campaignId: string
|
||||||
employeeId: string
|
employeeId: string
|
||||||
employee?: HrEmployee
|
employee?: EmployeeDto
|
||||||
participants: HrEvaluation360Participant[] // Bu sonuca katkıda bulunan değerlendiriciler
|
participants: HrEvaluation360Participant[] // Bu sonuca katkıda bulunan değerlendiriciler
|
||||||
overallScore: number
|
overallScore: number
|
||||||
maxPossibleScore: number
|
maxPossibleScore: number
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { HrEmployee } from './hr'
|
import { EmployeeDto } from "@/proxy/intranet/models"
|
||||||
|
|
||||||
// Duyuru
|
// Duyuru
|
||||||
export interface Announcement {
|
export interface Announcement {
|
||||||
|
|
@ -7,7 +7,7 @@ export interface Announcement {
|
||||||
content: string
|
content: string
|
||||||
excerpt: string
|
excerpt: string
|
||||||
category: 'general' | 'hr' | 'it' | 'event' | 'urgent'
|
category: 'general' | 'hr' | 'it' | 'event' | 'urgent'
|
||||||
author: HrEmployee
|
author: EmployeeDto
|
||||||
publishDate: Date
|
publishDate: Date
|
||||||
expiryDate?: Date
|
expiryDate?: Date
|
||||||
isPinned: boolean
|
isPinned: boolean
|
||||||
|
|
@ -17,32 +17,14 @@ export interface Announcement {
|
||||||
imageUrl?: string
|
imageUrl?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Harcama
|
|
||||||
export interface ExpenseRequest {
|
|
||||||
id: string
|
|
||||||
employee: HrEmployee
|
|
||||||
category: 'travel' | 'meal' | 'accommodation' | 'transport' | 'other'
|
|
||||||
amount: number
|
|
||||||
currency: string
|
|
||||||
date: Date
|
|
||||||
description: string
|
|
||||||
project?: string
|
|
||||||
receipts: { name: string; url: string; size: string }[]
|
|
||||||
status: 'pending' | 'approved' | 'rejected'
|
|
||||||
approver?: HrEmployee
|
|
||||||
approvalDate?: Date
|
|
||||||
notes?: string
|
|
||||||
creationTime: Date
|
|
||||||
}
|
|
||||||
|
|
||||||
// Görev
|
// Görev
|
||||||
export interface Task {
|
export interface Task {
|
||||||
id: string
|
id: string
|
||||||
title: string
|
title: string
|
||||||
description: string
|
description: string
|
||||||
project: string
|
project: string
|
||||||
assignedTo: HrEmployee[]
|
assignedTo: EmployeeDto[]
|
||||||
assignedBy: HrEmployee
|
assignedBy: EmployeeDto
|
||||||
priority: 'low' | 'medium' | 'high' | 'urgent'
|
priority: 'low' | 'medium' | 'high' | 'urgent'
|
||||||
status: 'todo' | 'in-progress' | 'review' | 'done'
|
status: 'todo' | 'in-progress' | 'review' | 'done'
|
||||||
dueDate: Date
|
dueDate: Date
|
||||||
|
|
@ -52,45 +34,10 @@ export interface Task {
|
||||||
comments: number
|
comments: number
|
||||||
}
|
}
|
||||||
|
|
||||||
// Doküman
|
|
||||||
export interface Document {
|
|
||||||
id: string
|
|
||||||
name: string
|
|
||||||
type: 'pdf' | 'doc' | 'xls' | 'ppt' | 'other'
|
|
||||||
category: 'policy' | 'procedure' | 'form' | 'template' | 'report' | 'other'
|
|
||||||
size: string
|
|
||||||
uploadedBy: HrEmployee
|
|
||||||
uploadDate: Date
|
|
||||||
version: string
|
|
||||||
url: string
|
|
||||||
description: string
|
|
||||||
departments: string[]
|
|
||||||
downloadCount: number
|
|
||||||
tags: string[]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Eğitim
|
|
||||||
export interface Training {
|
|
||||||
id: string
|
|
||||||
title: string
|
|
||||||
description: string
|
|
||||||
instructor: string
|
|
||||||
category: 'technical' | 'soft-skills' | 'management' | 'compliance' | 'other'
|
|
||||||
type: 'online' | 'classroom' | 'hybrid'
|
|
||||||
duration: number // saat
|
|
||||||
startDate: Date
|
|
||||||
endDate: Date
|
|
||||||
maxParticipants: number
|
|
||||||
enrolled: number
|
|
||||||
status: 'upcoming' | 'ongoing' | 'completed'
|
|
||||||
location?: string
|
|
||||||
thumbnail?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sertifika
|
// Sertifika
|
||||||
export interface Certificate {
|
export interface Certificate {
|
||||||
id: string
|
id: string
|
||||||
employee: HrEmployee
|
employee: EmployeeDto
|
||||||
trainingTitle: string
|
trainingTitle: string
|
||||||
issueDate: Date
|
issueDate: Date
|
||||||
expiryDate?: Date
|
expiryDate?: Date
|
||||||
|
|
@ -98,20 +45,6 @@ export interface Certificate {
|
||||||
score?: number
|
score?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rezervasyon
|
|
||||||
export interface Reservation {
|
|
||||||
id: string
|
|
||||||
type: 'room' | 'vehicle' | 'equipment'
|
|
||||||
resourceName: string
|
|
||||||
bookedBy: HrEmployee
|
|
||||||
startDate: Date
|
|
||||||
endDate: Date
|
|
||||||
purpose: string
|
|
||||||
status: 'pending' | 'approved' | 'rejected' | 'completed'
|
|
||||||
participants?: number
|
|
||||||
notes?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Yemek Menüsü
|
// Yemek Menüsü
|
||||||
export interface MealMenu {
|
export interface MealMenu {
|
||||||
id: string
|
id: string
|
||||||
|
|
@ -141,7 +74,7 @@ export interface Survey {
|
||||||
id: string
|
id: string
|
||||||
title: string
|
title: string
|
||||||
description: string
|
description: string
|
||||||
creatorId: HrEmployee
|
creatorId: EmployeeDto
|
||||||
creationTime: Date
|
creationTime: Date
|
||||||
deadline: Date
|
deadline: Date
|
||||||
questions: SurveyQuestion[]
|
questions: SurveyQuestion[]
|
||||||
|
|
@ -190,33 +123,16 @@ export interface SurveyAnswer {
|
||||||
value: string | number | string[]
|
value: string | number | string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ziyaretçi
|
|
||||||
export interface Visitor {
|
|
||||||
id: string
|
|
||||||
fullName: string
|
|
||||||
company: string
|
|
||||||
email: string
|
|
||||||
phone: string
|
|
||||||
visitDate: Date
|
|
||||||
checkIn?: Date
|
|
||||||
checkOut?: Date
|
|
||||||
host: HrEmployee
|
|
||||||
purpose: string
|
|
||||||
status: 'scheduled' | 'checked-in' | 'checked-out' | 'cancelled'
|
|
||||||
badgeNumber?: string
|
|
||||||
photo?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sosyal Duvar - Ana Interface
|
// Sosyal Duvar - Ana Interface
|
||||||
export interface SocialPost {
|
export interface SocialPost {
|
||||||
id: string
|
id: string
|
||||||
creator: HrEmployee
|
creator: EmployeeDto
|
||||||
content: string
|
content: string
|
||||||
locationJson?: string
|
locationJson?: string
|
||||||
media?: SocialMedia
|
media?: SocialMedia
|
||||||
likeCount: number
|
likeCount: number
|
||||||
isLiked: boolean
|
isLiked: boolean
|
||||||
likeUsers: HrEmployee[]
|
likeUsers: EmployeeDto[]
|
||||||
comments: SocialComment[]
|
comments: SocialComment[]
|
||||||
isOwnPost: boolean
|
isOwnPost: boolean
|
||||||
creationTime: Date
|
creationTime: Date
|
||||||
|
|
@ -247,7 +163,7 @@ export interface SocialPollOption {
|
||||||
// Sosyal Duvar - Comment Interface
|
// Sosyal Duvar - Comment Interface
|
||||||
export interface SocialComment {
|
export interface SocialComment {
|
||||||
id: string
|
id: string
|
||||||
creator: HrEmployee
|
creator: EmployeeDto
|
||||||
content: string
|
content: string
|
||||||
creationTime: Date
|
creationTime: Date
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { Address, BusinessParty, PaymentTerms, PriorityEnum } from './common'
|
import { Address, BusinessParty, PaymentTerms, PriorityEnum } from './common'
|
||||||
import { HrDepartment } from './hr'
|
import { DepartmentDto } from './hr'
|
||||||
import { WmWarehouse, WmZone, WmLocation } from './wm'
|
import { WmWarehouse, WmZone, WmLocation } from './wm'
|
||||||
|
|
||||||
export interface MmMaterial {
|
export interface MmMaterial {
|
||||||
|
|
@ -460,7 +460,7 @@ export interface MmApprovalWorkflow {
|
||||||
id: string
|
id: string
|
||||||
name: string
|
name: string
|
||||||
departmentId: string
|
departmentId: string
|
||||||
department?: HrDepartment
|
department?: DepartmentDto
|
||||||
requestType: RequestTypeEnum
|
requestType: RequestTypeEnum
|
||||||
amountThreshold: number
|
amountThreshold: number
|
||||||
approvalLevels: MmApprovalWorkflowLevel[]
|
approvalLevels: MmApprovalWorkflowLevel[]
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { PriorityEnum } from './common'
|
import { PriorityEnum } from './common'
|
||||||
import { HrDepartment } from './hr'
|
import { DepartmentDto } from './hr'
|
||||||
import { MmMaterial } from './mm'
|
import { MmMaterial } from './mm'
|
||||||
|
|
||||||
export type CalendarView = 'month' | 'week' | 'day'
|
export type CalendarView = 'month' | 'week' | 'day'
|
||||||
|
|
@ -19,7 +19,7 @@ export interface PmWorkCenter {
|
||||||
warrantyExpiry?: Date
|
warrantyExpiry?: Date
|
||||||
location: string
|
location: string
|
||||||
departmentId: string
|
departmentId: string
|
||||||
department?: HrDepartment
|
department?: DepartmentDto
|
||||||
status: WorkCenterStatusEnum
|
status: WorkCenterStatusEnum
|
||||||
criticality: CriticalityLevelEnum
|
criticality: CriticalityLevelEnum
|
||||||
specifications: PmWorkCenterSpecification[]
|
specifications: PmWorkCenterSpecification[]
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { BusinessParty, PriorityEnum } from './common'
|
import { BusinessParty, PriorityEnum } from './common'
|
||||||
import { HrEmployee } from './hr'
|
import { EmployeeDto } from './hr'
|
||||||
|
|
||||||
export interface PsProject {
|
export interface PsProject {
|
||||||
// Proje
|
// Proje
|
||||||
|
|
@ -13,7 +13,7 @@ export interface PsProject {
|
||||||
customerId?: string
|
customerId?: string
|
||||||
customer?: BusinessParty
|
customer?: BusinessParty
|
||||||
projectManagerId: string
|
projectManagerId: string
|
||||||
projectManager?: HrEmployee
|
projectManager?: EmployeeDto
|
||||||
startDate: Date
|
startDate: Date
|
||||||
endDate: Date
|
endDate: Date
|
||||||
actualStartDate?: Date
|
actualStartDate?: Date
|
||||||
|
|
@ -71,7 +71,7 @@ export interface PsProjectTask {
|
||||||
status: TaskStatusEnum
|
status: TaskStatusEnum
|
||||||
priority: PriorityEnum
|
priority: PriorityEnum
|
||||||
assignedTo?: string
|
assignedTo?: string
|
||||||
assignee?: HrEmployee
|
assignee?: EmployeeDto
|
||||||
startDate: Date
|
startDate: Date
|
||||||
endDate: Date
|
endDate: Date
|
||||||
actualStartDate?: Date
|
actualStartDate?: Date
|
||||||
|
|
@ -183,7 +183,7 @@ export interface PsTaskDailyUpdate {
|
||||||
taskId: string
|
taskId: string
|
||||||
task?: PsProjectTask
|
task?: PsProjectTask
|
||||||
employeeId: string
|
employeeId: string
|
||||||
employee?: HrEmployee
|
employee?: EmployeeDto
|
||||||
date: Date
|
date: Date
|
||||||
hoursWorked: number
|
hoursWorked: number
|
||||||
description: string
|
description: string
|
||||||
|
|
@ -205,7 +205,7 @@ export interface PsGanttTask {
|
||||||
startDate: Date
|
startDate: Date
|
||||||
endDate: Date
|
endDate: Date
|
||||||
progress: number
|
progress: number
|
||||||
assignee?: HrEmployee
|
assignee?: EmployeeDto
|
||||||
parentId?: string
|
parentId?: string
|
||||||
children?: PsGanttTask[]
|
children?: PsGanttTask[]
|
||||||
dependencies?: string[]
|
dependencies?: string[]
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { FaSave, FaTimes } from "react-icons/fa";
|
import { FaSave, FaTimes } from "react-icons/fa";
|
||||||
import { HrDepartment } from "../../../types/hr";
|
import { DepartmentDto } from "../../../types/hr";
|
||||||
import { mockEmployees } from "../../../mocks/mockEmployees";
|
import { mockEmployees } from "../../../mocks/mockEmployees";
|
||||||
import { mockDepartments } from "../../../mocks/mockDepartments";
|
import { mockDepartments } from "../../../mocks/mockDepartments";
|
||||||
import { mockCostCenters } from "../../../mocks/mockCostCenters";
|
import { mockCostCenters } from "../../../mocks/mockCostCenters";
|
||||||
|
|
@ -8,8 +8,8 @@ import { mockCostCenters } from "../../../mocks/mockCostCenters";
|
||||||
interface DepartmentFormModalProps {
|
interface DepartmentFormModalProps {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
onSave: (department: Partial<HrDepartment>) => void;
|
onSave: (department: Partial<DepartmentDto>) => void;
|
||||||
department?: HrDepartment;
|
department?: DepartmentDto;
|
||||||
title: string;
|
title: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import {
|
||||||
FaList,
|
FaList,
|
||||||
FaTh,
|
FaTh,
|
||||||
} from 'react-icons/fa'
|
} from 'react-icons/fa'
|
||||||
import { HrDepartment } from '../../../types/hr'
|
import { DepartmentDto } from '../../../types/hr'
|
||||||
import DataTable, { Column } from '../../../components/common/DataTable'
|
import DataTable, { Column } from '../../../components/common/DataTable'
|
||||||
import { mockDepartments } from '../../../mocks/mockDepartments'
|
import { mockDepartments } from '../../../mocks/mockDepartments'
|
||||||
import { mockEmployees } from '../../../mocks/mockEmployees'
|
import { mockEmployees } from '../../../mocks/mockEmployees'
|
||||||
|
|
@ -21,7 +21,7 @@ import Widget from '../../../components/common/Widget'
|
||||||
import { Container } from '@/components/shared'
|
import { Container } from '@/components/shared'
|
||||||
|
|
||||||
const DepartmentManagement: React.FC = () => {
|
const DepartmentManagement: React.FC = () => {
|
||||||
const [departments, setDepartments] = useState<HrDepartment[]>(mockDepartments)
|
const [departments, setDepartments] = useState<DepartmentDto[]>(mockDepartments)
|
||||||
const [searchTerm, setSearchTerm] = useState('')
|
const [searchTerm, setSearchTerm] = useState('')
|
||||||
const [selectedParent, setSelectedParent] = useState<string>('all')
|
const [selectedParent, setSelectedParent] = useState<string>('all')
|
||||||
const [viewMode, setViewMode] = useState<'list' | 'cards'>('list')
|
const [viewMode, setViewMode] = useState<'list' | 'cards'>('list')
|
||||||
|
|
@ -29,7 +29,7 @@ const DepartmentManagement: React.FC = () => {
|
||||||
// Modal states
|
// Modal states
|
||||||
const [isFormModalOpen, setIsFormModalOpen] = useState(false)
|
const [isFormModalOpen, setIsFormModalOpen] = useState(false)
|
||||||
const [isViewModalOpen, setIsViewModalOpen] = useState(false)
|
const [isViewModalOpen, setIsViewModalOpen] = useState(false)
|
||||||
const [selectedDepartment, setSelectedDepartment] = useState<HrDepartment | undefined>()
|
const [selectedDepartment, setSelectedDepartment] = useState<DepartmentDto | undefined>()
|
||||||
const [modalTitle, setModalTitle] = useState('')
|
const [modalTitle, setModalTitle] = useState('')
|
||||||
|
|
||||||
const handleAdd = () => {
|
const handleAdd = () => {
|
||||||
|
|
@ -38,13 +38,13 @@ const DepartmentManagement: React.FC = () => {
|
||||||
setIsFormModalOpen(true)
|
setIsFormModalOpen(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleEdit = (department: HrDepartment) => {
|
const handleEdit = (department: DepartmentDto) => {
|
||||||
setSelectedDepartment(department)
|
setSelectedDepartment(department)
|
||||||
setModalTitle('Departman Düzenle')
|
setModalTitle('Departman Düzenle')
|
||||||
setIsFormModalOpen(true)
|
setIsFormModalOpen(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleView = (department: HrDepartment) => {
|
const handleView = (department: DepartmentDto) => {
|
||||||
setSelectedDepartment(department)
|
setSelectedDepartment(department)
|
||||||
setIsViewModalOpen(true)
|
setIsViewModalOpen(true)
|
||||||
}
|
}
|
||||||
|
|
@ -55,7 +55,7 @@ const DepartmentManagement: React.FC = () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleSave = (departmentData: Partial<HrDepartment>) => {
|
const handleSave = (departmentData: Partial<DepartmentDto>) => {
|
||||||
if (selectedDepartment) {
|
if (selectedDepartment) {
|
||||||
// Edit existing department
|
// Edit existing department
|
||||||
setDepartments((prev) =>
|
setDepartments((prev) =>
|
||||||
|
|
@ -67,13 +67,13 @@ const DepartmentManagement: React.FC = () => {
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
// Add new department
|
// Add new department
|
||||||
const newDepartment: HrDepartment = {
|
const newDepartment: DepartmentDto = {
|
||||||
id: `dept_${Date.now()}`,
|
id: `dept_${Date.now()}`,
|
||||||
...departmentData,
|
...departmentData,
|
||||||
subDepartments: [],
|
subDepartments: [],
|
||||||
creationTime: new Date(),
|
creationTime: new Date(),
|
||||||
lastModificationTime: new Date(),
|
lastModificationTime: new Date(),
|
||||||
} as HrDepartment
|
} as DepartmentDto
|
||||||
setDepartments((prev) => [...prev, newDepartment])
|
setDepartments((prev) => [...prev, newDepartment])
|
||||||
}
|
}
|
||||||
setIsFormModalOpen(false)
|
setIsFormModalOpen(false)
|
||||||
|
|
@ -89,7 +89,7 @@ const DepartmentManagement: React.FC = () => {
|
||||||
setSelectedDepartment(undefined)
|
setSelectedDepartment(undefined)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleEditFromView = (department: HrDepartment) => {
|
const handleEditFromView = (department: DepartmentDto) => {
|
||||||
setIsViewModalOpen(false)
|
setIsViewModalOpen(false)
|
||||||
handleEdit(department)
|
handleEdit(department)
|
||||||
}
|
}
|
||||||
|
|
@ -117,7 +117,7 @@ const DepartmentManagement: React.FC = () => {
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
|
||||||
const columns: Column<HrDepartment>[] = [
|
const columns: Column<DepartmentDto>[] = [
|
||||||
{
|
{
|
||||||
key: 'code',
|
key: 'code',
|
||||||
header: 'Departman Kodu',
|
header: 'Departman Kodu',
|
||||||
|
|
@ -131,17 +131,17 @@ const DepartmentManagement: React.FC = () => {
|
||||||
{
|
{
|
||||||
key: 'parentDepartment',
|
key: 'parentDepartment',
|
||||||
header: 'Üst Departman',
|
header: 'Üst Departman',
|
||||||
render: (department: HrDepartment) => department.parentDepartment?.name || '-',
|
render: (department: DepartmentDto) => department.parentDepartment?.name || '-',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'manager',
|
key: 'manager',
|
||||||
header: 'Yönetici',
|
header: 'Yönetici',
|
||||||
render: (department: HrDepartment) => department.manager?.fullName || '-',
|
render: (department: DepartmentDto) => department.manager?.fullName || '-',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'employeeCount',
|
key: 'employeeCount',
|
||||||
header: 'Personel Sayısı',
|
header: 'Personel Sayısı',
|
||||||
render: (department: HrDepartment) => (
|
render: (department: DepartmentDto) => (
|
||||||
<div className="flex items-center gap-1">
|
<div className="flex items-center gap-1">
|
||||||
<FaUsers className="w-4 h-4 text-gray-500" />
|
<FaUsers className="w-4 h-4 text-gray-500" />
|
||||||
<span>{mockEmployees.filter((a) => a.departmentId == department.id).length || 0}</span>
|
<span>{mockEmployees.filter((a) => a.departmentId == department.id).length || 0}</span>
|
||||||
|
|
@ -151,7 +151,7 @@ const DepartmentManagement: React.FC = () => {
|
||||||
{
|
{
|
||||||
key: 'costCenter',
|
key: 'costCenter',
|
||||||
header: 'Maliyet Merkezi',
|
header: 'Maliyet Merkezi',
|
||||||
render: (department: HrDepartment) => (
|
render: (department: DepartmentDto) => (
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<span className="font-medium">{department.costCenter?.code || '-'}</span>
|
<span className="font-medium">{department.costCenter?.code || '-'}</span>
|
||||||
<span className="text-xs text-gray-500">{department.costCenter?.name || '-'}</span>
|
<span className="text-xs text-gray-500">{department.costCenter?.name || '-'}</span>
|
||||||
|
|
@ -161,7 +161,7 @@ const DepartmentManagement: React.FC = () => {
|
||||||
{
|
{
|
||||||
key: 'budget',
|
key: 'budget',
|
||||||
header: 'Bütçe',
|
header: 'Bütçe',
|
||||||
render: (department: HrDepartment) => (
|
render: (department: DepartmentDto) => (
|
||||||
<div className="flex items-center gap-1">
|
<div className="flex items-center gap-1">
|
||||||
<FaDollarSign className="w-4 h-4 text-gray-500" />
|
<FaDollarSign className="w-4 h-4 text-gray-500" />
|
||||||
<span>{department.budget ? `₺${department.budget.toLocaleString()}` : '-'}</span>
|
<span>{department.budget ? `₺${department.budget.toLocaleString()}` : '-'}</span>
|
||||||
|
|
@ -171,7 +171,7 @@ const DepartmentManagement: React.FC = () => {
|
||||||
{
|
{
|
||||||
key: 'status',
|
key: 'status',
|
||||||
header: 'Durum',
|
header: 'Durum',
|
||||||
render: (department: HrDepartment) => (
|
render: (department: DepartmentDto) => (
|
||||||
<span
|
<span
|
||||||
className={`px-2 py-1 text-xs font-medium rounded-full ${
|
className={`px-2 py-1 text-xs font-medium rounded-full ${
|
||||||
department.isActive ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'
|
department.isActive ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'
|
||||||
|
|
@ -184,7 +184,7 @@ const DepartmentManagement: React.FC = () => {
|
||||||
{
|
{
|
||||||
key: 'actions',
|
key: 'actions',
|
||||||
header: 'İşlemler',
|
header: 'İşlemler',
|
||||||
render: (department: HrDepartment) => (
|
render: (department: DepartmentDto) => (
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<button
|
<button
|
||||||
onClick={() => handleView(department)}
|
onClick={() => handleView(department)}
|
||||||
|
|
|
||||||
|
|
@ -8,14 +8,14 @@ import {
|
||||||
FaCalendar,
|
FaCalendar,
|
||||||
FaEdit,
|
FaEdit,
|
||||||
} from "react-icons/fa";
|
} from "react-icons/fa";
|
||||||
import { HrDepartment } from "../../../types/hr";
|
import { DepartmentDto } from "../../../types/hr";
|
||||||
import { mockEmployees } from "../../../mocks/mockEmployees";
|
import { mockEmployees } from "../../../mocks/mockEmployees";
|
||||||
|
|
||||||
interface DepartmentViewModalProps {
|
interface DepartmentViewModalProps {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
department: HrDepartment | null;
|
department: DepartmentDto | null;
|
||||||
onEdit?: (department: HrDepartment) => void;
|
onEdit?: (department: DepartmentDto) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const DepartmentViewModal: React.FC<DepartmentViewModalProps> = ({
|
const DepartmentViewModal: React.FC<DepartmentViewModalProps> = ({
|
||||||
|
|
|
||||||
|
|
@ -10,22 +10,22 @@ import {
|
||||||
FaTrash,
|
FaTrash,
|
||||||
FaPlus,
|
FaPlus,
|
||||||
} from 'react-icons/fa'
|
} from 'react-icons/fa'
|
||||||
import { HrEmployee, EmployeeStatusEnum } from '../../../types/hr'
|
import { EmployeeDto, EmployeeStatusEnum } from '../../../types/hr'
|
||||||
import { mockEmployees } from '../../../mocks/mockEmployees'
|
import { mockEmployees } from '../../../mocks/mockEmployees'
|
||||||
import { getEmployeeStatusColor, getEmployeeStatusText } from '../../../utils/erp'
|
import { getEmployeeStatusColor, getEmployeeStatusText } from '../../../utils/erp'
|
||||||
import { Container } from '@/components/shared'
|
import { Container } from '@/components/shared'
|
||||||
|
|
||||||
const EmployeeCards: React.FC = () => {
|
const EmployeeCards: React.FC = () => {
|
||||||
const [employees] = useState<HrEmployee[]>(mockEmployees)
|
const [employees] = useState<EmployeeDto[]>(mockEmployees)
|
||||||
const [selectedDepartment, setSelectedDepartment] = useState<string>('all')
|
const [selectedDepartment, setSelectedDepartment] = useState<string>('all')
|
||||||
const [selectedStatus, setSelectedStatus] = useState<string>('all')
|
const [selectedStatus, setSelectedStatus] = useState<string>('all')
|
||||||
|
|
||||||
const handleEdit = (employee: HrEmployee) => {
|
const handleEdit = (employee: EmployeeDto) => {
|
||||||
console.log('Edit employee:', employee)
|
console.log('Edit employee:', employee)
|
||||||
// Implement edit functionality
|
// Implement edit functionality
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleView = (employee: HrEmployee) => {
|
const handleView = (employee: EmployeeDto) => {
|
||||||
console.log('View employee:', employee)
|
console.log('View employee:', employee)
|
||||||
// Implement view functionality
|
// Implement view functionality
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,13 +14,13 @@ import LoadingSpinner from '../../../components/common/LoadingSpinner'
|
||||||
import { mockDepartments } from '../../../mocks/mockDepartments'
|
import { mockDepartments } from '../../../mocks/mockDepartments'
|
||||||
import { mockJobPositions } from '../../../mocks/mockJobPositions'
|
import { mockJobPositions } from '../../../mocks/mockJobPositions'
|
||||||
import {
|
import {
|
||||||
HrDepartment,
|
DepartmentDto,
|
||||||
HrEmployee,
|
EmployeeDto,
|
||||||
EmployeeStatusEnum,
|
EmployeeStatusEnum,
|
||||||
EmploymentTypeEnum,
|
EmploymentTypeEnum,
|
||||||
GenderEnum,
|
GenderEnum,
|
||||||
JobLevelEnum,
|
JobLevelEnum,
|
||||||
HrJobPosition,
|
JobPositionDto,
|
||||||
MaritalStatusEnum,
|
MaritalStatusEnum,
|
||||||
} from '../../../types/hr'
|
} from '../../../types/hr'
|
||||||
import { mockEmployees } from '../../../mocks/mockEmployees'
|
import { mockEmployees } from '../../../mocks/mockEmployees'
|
||||||
|
|
@ -48,11 +48,11 @@ const EmployeeForm: React.FC = () => {
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
const [saving, setSaving] = useState(false)
|
const [saving, setSaving] = useState(false)
|
||||||
const [errors, setErrors] = useState<ValidationErrors>({})
|
const [errors, setErrors] = useState<ValidationErrors>({})
|
||||||
const [departments, setDepartments] = useState<HrDepartment[]>([])
|
const [departments, setDepartments] = useState<DepartmentDto[]>([])
|
||||||
const [jobPositions, setJobPositions] = useState<HrJobPosition[]>([])
|
const [jobPositions, setJobPositions] = useState<JobPositionDto[]>([])
|
||||||
const [managers, setManagers] = useState<HrEmployee[]>([])
|
const [managers, setManagers] = useState<EmployeeDto[]>([])
|
||||||
|
|
||||||
const [formData, setFormData] = useState<HrEmployee>({
|
const [formData, setFormData] = useState<EmployeeDto>({
|
||||||
id: '',
|
id: '',
|
||||||
code: '',
|
code: '',
|
||||||
firstName: '',
|
firstName: '',
|
||||||
|
|
@ -187,7 +187,7 @@ const EmployeeForm: React.FC = () => {
|
||||||
return Object.keys(newErrors).length === 0
|
return Object.keys(newErrors).length === 0
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleInputChange = (field: keyof HrEmployee, value: string | number | boolean) => {
|
const handleInputChange = (field: keyof EmployeeDto, value: string | number | boolean) => {
|
||||||
setFormData((prev) => ({
|
setFormData((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
[field]: value,
|
[field]: value,
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ import {
|
||||||
FaBriefcase,
|
FaBriefcase,
|
||||||
} from 'react-icons/fa'
|
} from 'react-icons/fa'
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import { EmployeeStatusEnum, HrEmployee } from '../../../types/hr'
|
import { EmployeeStatusEnum, EmployeeDto } from '../../../types/hr'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import { mockEmployees } from '../../../mocks/mockEmployees'
|
import { mockEmployees } from '../../../mocks/mockEmployees'
|
||||||
import EmployeeView from './EmployeeView'
|
import EmployeeView from './EmployeeView'
|
||||||
|
|
@ -45,7 +45,7 @@ const EmployeeList: React.FC = () => {
|
||||||
|
|
||||||
// Modal states
|
// Modal states
|
||||||
const [isViewModalOpen, setIsViewModalOpen] = useState(false)
|
const [isViewModalOpen, setIsViewModalOpen] = useState(false)
|
||||||
const [selectedEmployee, setSelectedEmployee] = useState<HrEmployee | null>(null)
|
const [selectedEmployee, setSelectedEmployee] = useState<EmployeeDto | null>(null)
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: employees,
|
data: employees,
|
||||||
|
|
@ -69,7 +69,7 @@ const EmployeeList: React.FC = () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
// Modal handlers
|
// Modal handlers
|
||||||
const handleViewEmployee = (employee: HrEmployee) => {
|
const handleViewEmployee = (employee: EmployeeDto) => {
|
||||||
setSelectedEmployee(employee)
|
setSelectedEmployee(employee)
|
||||||
setIsViewModalOpen(true)
|
setIsViewModalOpen(true)
|
||||||
}
|
}
|
||||||
|
|
@ -79,7 +79,7 @@ const EmployeeList: React.FC = () => {
|
||||||
setSelectedEmployee(null)
|
setSelectedEmployee(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleEditFromView = (employee: HrEmployee) => {
|
const handleEditFromView = (employee: EmployeeDto) => {
|
||||||
setIsViewModalOpen(false)
|
setIsViewModalOpen(false)
|
||||||
// Navigate to edit page - you can replace this with a modal if preferred
|
// Navigate to edit page - you can replace this with a modal if preferred
|
||||||
window.location.href = ROUTES_ENUM.protected.hr.employeesEdit.replace(':id', employee.id)
|
window.location.href = ROUTES_ENUM.protected.hr.employeesEdit.replace(':id', employee.id)
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ import {
|
||||||
FaAward,
|
FaAward,
|
||||||
FaHistory,
|
FaHistory,
|
||||||
} from "react-icons/fa";
|
} from "react-icons/fa";
|
||||||
import { HrEmployee } from "../../../types/hr";
|
import { EmployeeDto } from "../../../types/hr";
|
||||||
import {
|
import {
|
||||||
getEmployeeStatusColor,
|
getEmployeeStatusColor,
|
||||||
getEmployeeStatusIcon,
|
getEmployeeStatusIcon,
|
||||||
|
|
@ -29,8 +29,8 @@ import {
|
||||||
interface EmployeeViewModalProps {
|
interface EmployeeViewModalProps {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
employee: HrEmployee | null;
|
employee: EmployeeDto | null;
|
||||||
onEdit?: (employee: HrEmployee) => void;
|
onEdit?: (employee: EmployeeDto) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const EmployeeViewModal: React.FC<EmployeeViewModalProps> = ({
|
const EmployeeViewModal: React.FC<EmployeeViewModalProps> = ({
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { useState, useEffect } from 'react'
|
import React, { useState, useEffect } from 'react'
|
||||||
import { FaSave, FaTimes, FaPlus, FaTrash } from 'react-icons/fa'
|
import { FaSave, FaTimes, FaPlus, FaTrash } from 'react-icons/fa'
|
||||||
import { HrJobPosition, JobLevelEnum } from '../../../types/hr'
|
import { JobPositionDto, JobLevelEnum } from '../../../types/hr'
|
||||||
import { mockDepartments } from '../../../mocks/mockDepartments'
|
import { mockDepartments } from '../../../mocks/mockDepartments'
|
||||||
import { getJobLevelText } from '@/utils/erp'
|
import { getJobLevelText } from '@/utils/erp'
|
||||||
import { mockCurrencies } from '@/mocks/mockCurrencies'
|
import { mockCurrencies } from '@/mocks/mockCurrencies'
|
||||||
|
|
@ -8,8 +8,8 @@ import { mockCurrencies } from '@/mocks/mockCurrencies'
|
||||||
interface JobPositionFormModalProps {
|
interface JobPositionFormModalProps {
|
||||||
isOpen: boolean
|
isOpen: boolean
|
||||||
onClose: () => void
|
onClose: () => void
|
||||||
onSave: (position: Partial<HrJobPosition>) => void
|
onSave: (position: Partial<JobPositionDto>) => void
|
||||||
position?: HrJobPosition
|
position?: JobPositionDto
|
||||||
title: string
|
title: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,13 @@ import {
|
||||||
FaDollarSign,
|
FaDollarSign,
|
||||||
FaClock,
|
FaClock,
|
||||||
} from "react-icons/fa";
|
} from "react-icons/fa";
|
||||||
import { HrJobPosition } from "../../../types/hr";
|
import { JobPositionDto } from "../../../types/hr";
|
||||||
import { getJobLevelColor, getJobLevelText } from "../../../utils/erp";
|
import { getJobLevelColor, getJobLevelText } from "../../../utils/erp";
|
||||||
|
|
||||||
interface JobPositionViewModalProps {
|
interface JobPositionViewModalProps {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
position: HrJobPosition | null | undefined;
|
position: JobPositionDto | null | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const JobPositionViewModal: React.FC<JobPositionViewModalProps> = ({
|
const JobPositionViewModal: React.FC<JobPositionViewModalProps> = ({
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ import {
|
||||||
FaTh,
|
FaTh,
|
||||||
FaList,
|
FaList,
|
||||||
} from 'react-icons/fa'
|
} from 'react-icons/fa'
|
||||||
import { HrJobPosition, JobLevelEnum } from '../../../types/hr'
|
import { JobPositionDto, JobLevelEnum } from '../../../types/hr'
|
||||||
import DataTable, { Column } from '../../../components/common/DataTable'
|
import DataTable, { Column } from '../../../components/common/DataTable'
|
||||||
import { mockJobPositions } from '../../../mocks/mockJobPositions'
|
import { mockJobPositions } from '../../../mocks/mockJobPositions'
|
||||||
import JobPositionFormModal from './JobPositionFormModal'
|
import JobPositionFormModal from './JobPositionFormModal'
|
||||||
|
|
@ -20,7 +20,7 @@ import { getJobLevelColor, getJobLevelText } from '../../../utils/erp'
|
||||||
import { Container } from '@/components/shared'
|
import { Container } from '@/components/shared'
|
||||||
|
|
||||||
const JobPositions: React.FC = () => {
|
const JobPositions: React.FC = () => {
|
||||||
const [positions, setPositions] = useState<HrJobPosition[]>(mockJobPositions)
|
const [positions, setPositions] = useState<JobPositionDto[]>(mockJobPositions)
|
||||||
const [searchTerm, setSearchTerm] = useState('')
|
const [searchTerm, setSearchTerm] = useState('')
|
||||||
const [selectedLevel, setSelectedLevel] = useState<string>('all')
|
const [selectedLevel, setSelectedLevel] = useState<string>('all')
|
||||||
const [selectedDepartment, setSelectedDepartment] = useState<string>('all')
|
const [selectedDepartment, setSelectedDepartment] = useState<string>('all')
|
||||||
|
|
@ -29,7 +29,7 @@ const JobPositions: React.FC = () => {
|
||||||
// Modal states
|
// Modal states
|
||||||
const [isFormModalOpen, setIsFormModalOpen] = useState(false)
|
const [isFormModalOpen, setIsFormModalOpen] = useState(false)
|
||||||
const [isViewModalOpen, setIsViewModalOpen] = useState(false)
|
const [isViewModalOpen, setIsViewModalOpen] = useState(false)
|
||||||
const [selectedPosition, setSelectedPosition] = useState<HrJobPosition | undefined>(undefined)
|
const [selectedPosition, setSelectedPosition] = useState<JobPositionDto | undefined>(undefined)
|
||||||
const [modalTitle, setModalTitle] = useState('')
|
const [modalTitle, setModalTitle] = useState('')
|
||||||
|
|
||||||
const handleAdd = () => {
|
const handleAdd = () => {
|
||||||
|
|
@ -38,13 +38,13 @@ const JobPositions: React.FC = () => {
|
||||||
setIsFormModalOpen(true)
|
setIsFormModalOpen(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleEdit = (position: HrJobPosition) => {
|
const handleEdit = (position: JobPositionDto) => {
|
||||||
setSelectedPosition(position)
|
setSelectedPosition(position)
|
||||||
setModalTitle('İş Pozisyonu Düzenle')
|
setModalTitle('İş Pozisyonu Düzenle')
|
||||||
setIsFormModalOpen(true)
|
setIsFormModalOpen(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleView = (position: HrJobPosition) => {
|
const handleView = (position: JobPositionDto) => {
|
||||||
setSelectedPosition(position)
|
setSelectedPosition(position)
|
||||||
setIsViewModalOpen(true)
|
setIsViewModalOpen(true)
|
||||||
}
|
}
|
||||||
|
|
@ -55,7 +55,7 @@ const JobPositions: React.FC = () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleSavePosition = (positionData: Partial<HrJobPosition>) => {
|
const handleSavePosition = (positionData: Partial<JobPositionDto>) => {
|
||||||
if (selectedPosition) {
|
if (selectedPosition) {
|
||||||
// Edit existing position
|
// Edit existing position
|
||||||
const updatedPosition = {
|
const updatedPosition = {
|
||||||
|
|
@ -66,13 +66,13 @@ const JobPositions: React.FC = () => {
|
||||||
setPositions(positions.map((p) => (p.id === selectedPosition.id ? updatedPosition : p)))
|
setPositions(positions.map((p) => (p.id === selectedPosition.id ? updatedPosition : p)))
|
||||||
} else {
|
} else {
|
||||||
// Add new position
|
// Add new position
|
||||||
const newPosition: HrJobPosition = {
|
const newPosition: JobPositionDto = {
|
||||||
id: `jp-${Date.now()}`,
|
id: `jp-${Date.now()}`,
|
||||||
...positionData,
|
...positionData,
|
||||||
employees: [],
|
employees: [],
|
||||||
creationTime: new Date(),
|
creationTime: new Date(),
|
||||||
lastModificationTime: new Date(),
|
lastModificationTime: new Date(),
|
||||||
} as HrJobPosition
|
} as JobPositionDto
|
||||||
setPositions([...positions, newPosition])
|
setPositions([...positions, newPosition])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -106,7 +106,7 @@ const JobPositions: React.FC = () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
// Card component for individual position
|
// Card component for individual position
|
||||||
const PositionCard: React.FC<{ position: HrJobPosition }> = ({ position }) => (
|
const PositionCard: React.FC<{ position: JobPositionDto }> = ({ position }) => (
|
||||||
<div className="bg-white rounded-lg shadow-sm border hover:shadow-md transition-shadow p-4">
|
<div className="bg-white rounded-lg shadow-sm border hover:shadow-md transition-shadow p-4">
|
||||||
<div className="flex items-start justify-between mb-4">
|
<div className="flex items-start justify-between mb-4">
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
|
|
@ -201,7 +201,7 @@ const JobPositions: React.FC = () => {
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
const columns: Column<HrJobPosition>[] = [
|
const columns: Column<JobPositionDto>[] = [
|
||||||
{
|
{
|
||||||
key: 'code',
|
key: 'code',
|
||||||
header: 'Pozisyon Kodu',
|
header: 'Pozisyon Kodu',
|
||||||
|
|
@ -211,7 +211,7 @@ const JobPositions: React.FC = () => {
|
||||||
key: 'title',
|
key: 'title',
|
||||||
header: 'Pozisyon Adı',
|
header: 'Pozisyon Adı',
|
||||||
sortable: true,
|
sortable: true,
|
||||||
render: (position: HrJobPosition) => (
|
render: (position: JobPositionDto) => (
|
||||||
<div>
|
<div>
|
||||||
<div className="font-medium text-gray-900">{position.name}</div>
|
<div className="font-medium text-gray-900">{position.name}</div>
|
||||||
<div className="text-sm text-gray-500 truncate max-w-xs">{position.description}</div>
|
<div className="text-sm text-gray-500 truncate max-w-xs">{position.description}</div>
|
||||||
|
|
@ -221,7 +221,7 @@ const JobPositions: React.FC = () => {
|
||||||
{
|
{
|
||||||
key: 'department',
|
key: 'department',
|
||||||
header: 'Departman',
|
header: 'Departman',
|
||||||
render: (position: HrJobPosition) => (
|
render: (position: JobPositionDto) => (
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<FaBuilding className="w-4 h-4 text-gray-500" />
|
<FaBuilding className="w-4 h-4 text-gray-500" />
|
||||||
<span>{position.department?.name || '-'}</span>
|
<span>{position.department?.name || '-'}</span>
|
||||||
|
|
@ -231,7 +231,7 @@ const JobPositions: React.FC = () => {
|
||||||
{
|
{
|
||||||
key: 'level',
|
key: 'level',
|
||||||
header: 'Seviye',
|
header: 'Seviye',
|
||||||
render: (position: HrJobPosition) => (
|
render: (position: JobPositionDto) => (
|
||||||
<span
|
<span
|
||||||
className={`px-2 py-1 text-xs font-medium rounded-full ${getJobLevelColor(
|
className={`px-2 py-1 text-xs font-medium rounded-full ${getJobLevelColor(
|
||||||
position.level,
|
position.level,
|
||||||
|
|
@ -244,7 +244,7 @@ const JobPositions: React.FC = () => {
|
||||||
{
|
{
|
||||||
key: 'employeeCount',
|
key: 'employeeCount',
|
||||||
header: 'Personel Sayısı',
|
header: 'Personel Sayısı',
|
||||||
render: (position: HrJobPosition) => (
|
render: (position: JobPositionDto) => (
|
||||||
<div className="flex items-center gap-1">
|
<div className="flex items-center gap-1">
|
||||||
<FaUsers className="w-4 h-4 text-gray-500" />
|
<FaUsers className="w-4 h-4 text-gray-500" />
|
||||||
<span>{position.employees?.length || 0}</span>
|
<span>{position.employees?.length || 0}</span>
|
||||||
|
|
@ -254,7 +254,7 @@ const JobPositions: React.FC = () => {
|
||||||
{
|
{
|
||||||
key: 'salary',
|
key: 'salary',
|
||||||
header: 'Maaş Aralığı',
|
header: 'Maaş Aralığı',
|
||||||
render: (position: HrJobPosition) => (
|
render: (position: JobPositionDto) => (
|
||||||
<div className="flex items-center gap-1">
|
<div className="flex items-center gap-1">
|
||||||
<FaDollarSign className="w-4 h-4 text-gray-500" />
|
<FaDollarSign className="w-4 h-4 text-gray-500" />
|
||||||
<div className="text-sm">
|
<div className="text-sm">
|
||||||
|
|
@ -267,7 +267,7 @@ const JobPositions: React.FC = () => {
|
||||||
{
|
{
|
||||||
key: 'skills',
|
key: 'skills',
|
||||||
header: 'Gerekli Yetenekler',
|
header: 'Gerekli Yetenekler',
|
||||||
render: (position: HrJobPosition) => (
|
render: (position: JobPositionDto) => (
|
||||||
<div className="flex flex-wrap gap-1 max-w-xs">
|
<div className="flex flex-wrap gap-1 max-w-xs">
|
||||||
{position.requiredSkills?.slice(0, 3).map((skill, index) => (
|
{position.requiredSkills?.slice(0, 3).map((skill, index) => (
|
||||||
<span key={index} className="px-2 py-1 text-xs bg-blue-50 text-blue-700 rounded">
|
<span key={index} className="px-2 py-1 text-xs bg-blue-50 text-blue-700 rounded">
|
||||||
|
|
@ -285,7 +285,7 @@ const JobPositions: React.FC = () => {
|
||||||
{
|
{
|
||||||
key: 'status',
|
key: 'status',
|
||||||
header: 'Durum',
|
header: 'Durum',
|
||||||
render: (position: HrJobPosition) => (
|
render: (position: JobPositionDto) => (
|
||||||
<span
|
<span
|
||||||
className={`px-2 py-1 text-xs font-medium rounded-full ${
|
className={`px-2 py-1 text-xs font-medium rounded-full ${
|
||||||
position.isActive ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'
|
position.isActive ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'
|
||||||
|
|
@ -298,7 +298,7 @@ const JobPositions: React.FC = () => {
|
||||||
{
|
{
|
||||||
key: 'actions',
|
key: 'actions',
|
||||||
header: 'İşlemler',
|
header: 'İşlemler',
|
||||||
render: (position: HrJobPosition) => (
|
render: (position: JobPositionDto) => (
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<button
|
<button
|
||||||
onClick={() => handleView(position)}
|
onClick={() => handleView(position)}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ import {
|
||||||
FaMapMarkerAlt,
|
FaMapMarkerAlt,
|
||||||
FaBriefcase,
|
FaBriefcase,
|
||||||
} from 'react-icons/fa'
|
} from 'react-icons/fa'
|
||||||
import { HrEmployee, HrOrganizationChart as OrgChart } from '../../../types/hr'
|
import { EmployeeDto, HrOrganizationChart as OrgChart } from '../../../types/hr'
|
||||||
import { mockEmployees } from '../../../mocks/mockEmployees'
|
import { mockEmployees } from '../../../mocks/mockEmployees'
|
||||||
import { mockDepartments } from '../../../mocks/mockDepartments'
|
import { mockDepartments } from '../../../mocks/mockDepartments'
|
||||||
import Widget from '../../../components/common/Widget'
|
import Widget from '../../../components/common/Widget'
|
||||||
|
|
@ -76,22 +76,22 @@ const generateOrganizationData = (): OrgChart[] => {
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TreeNode {
|
interface TreeNode {
|
||||||
employee: HrEmployee
|
employee: EmployeeDto
|
||||||
children: TreeNode[]
|
children: TreeNode[]
|
||||||
level: number
|
level: number
|
||||||
}
|
}
|
||||||
|
|
||||||
const OrganizationChart: React.FC = () => {
|
const OrganizationChart: React.FC = () => {
|
||||||
const [employees] = useState<HrEmployee[]>(mockEmployees)
|
const [employees] = useState<EmployeeDto[]>(mockEmployees)
|
||||||
const [organizationData] = useState<OrgChart[]>(generateOrganizationData())
|
const [organizationData] = useState<OrgChart[]>(generateOrganizationData())
|
||||||
const [expandedNodes, setExpandedNodes] = useState<Set<string>>(new Set())
|
const [expandedNodes, setExpandedNodes] = useState<Set<string>>(new Set())
|
||||||
const [orgTree, setOrgTree] = useState<TreeNode[]>([])
|
const [orgTree, setOrgTree] = useState<TreeNode[]>([])
|
||||||
const [viewMode, setViewMode] = useState<'tree' | 'cards'>('tree')
|
const [viewMode, setViewMode] = useState<'tree' | 'cards'>('tree')
|
||||||
const [selectedEmployee, setSelectedEmployee] = useState<HrEmployee | null>(null)
|
const [selectedEmployee, setSelectedEmployee] = useState<EmployeeDto | null>(null)
|
||||||
const [showModal, setShowModal] = useState(false)
|
const [showModal, setShowModal] = useState(false)
|
||||||
const [selectedDepartment, setSelectedDepartment] = useState<string>('all')
|
const [selectedDepartment, setSelectedDepartment] = useState<string>('all')
|
||||||
|
|
||||||
const handleViewEmployee = (employee: HrEmployee) => {
|
const handleViewEmployee = (employee: EmployeeDto) => {
|
||||||
setSelectedEmployee(employee)
|
setSelectedEmployee(employee)
|
||||||
setShowModal(true)
|
setShowModal(true)
|
||||||
}
|
}
|
||||||
|
|
@ -278,7 +278,7 @@ const OrganizationChart: React.FC = () => {
|
||||||
acc[level].push(employee)
|
acc[level].push(employee)
|
||||||
return acc
|
return acc
|
||||||
},
|
},
|
||||||
{} as Record<number, HrEmployee[]>,
|
{} as Record<number, EmployeeDto[]>,
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ import { Announcement, Survey, SurveyAnswer } from '@/types/intranet'
|
||||||
import { Container } from '@/components/shared'
|
import { Container } from '@/components/shared'
|
||||||
import { usePermission } from '@/utils/hooks/usePermission'
|
import { usePermission } from '@/utils/hooks/usePermission'
|
||||||
import { IntranetDashboardDto } from '@/proxy/intranet/models'
|
import { IntranetDashboardDto } from '@/proxy/intranet/models'
|
||||||
import { intranetService, IntranetService } from '@/services/intranet.service'
|
import { intranetService } from '@/services/intranet.service'
|
||||||
|
|
||||||
dayjs.locale('tr')
|
dayjs.locale('tr')
|
||||||
dayjs.extend(relativeTime)
|
dayjs.extend(relativeTime)
|
||||||
|
|
@ -247,19 +247,36 @@ const IntranetDashboard: React.FC = () => {
|
||||||
case 'upcoming-events':
|
case 'upcoming-events':
|
||||||
return <UpcomingEvents events={intranetDashboard?.events || []} />
|
return <UpcomingEvents events={intranetDashboard?.events || []} />
|
||||||
case 'today-birthdays':
|
case 'today-birthdays':
|
||||||
return <TodayBirthdays />
|
return <TodayBirthdays employees={intranetDashboard?.birthdays || []} />
|
||||||
case 'recent-documents':
|
case 'visitors':
|
||||||
return <RecentDocuments />
|
return <Visitors visitors={intranetDashboard?.visitors || []} />
|
||||||
case 'upcoming-trainings':
|
|
||||||
return <UpcomingTrainings />
|
|
||||||
case 'active-reservations':
|
case 'active-reservations':
|
||||||
return <ActiveReservations onNewReservation={() => setShowReservationModal(true)} />
|
return (
|
||||||
|
<ActiveReservations
|
||||||
|
reservations={intranetDashboard?.reservations || []}
|
||||||
|
onNewReservation={() => setShowReservationModal(true)}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
case 'upcoming-trainings':
|
||||||
|
return <UpcomingTrainings trainings={intranetDashboard?.trainings || []} />
|
||||||
|
case 'expense-management':
|
||||||
|
return (
|
||||||
|
<ExpenseManagement
|
||||||
|
expenses={
|
||||||
|
intranetDashboard?.expenses || {
|
||||||
|
totalRequested: 0,
|
||||||
|
totalApproved: 0,
|
||||||
|
last5Expenses: [],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onNewExpense={() => setShowExpenseModal(true)}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
|
||||||
|
case 'recent-documents':
|
||||||
|
return <RecentDocuments documents={intranetDashboard?.documents || []} />
|
||||||
case 'active-surveys':
|
case 'active-surveys':
|
||||||
return <ActiveSurveys onTakeSurvey={handleTakeSurvey} />
|
return <ActiveSurveys onTakeSurvey={handleTakeSurvey} />
|
||||||
case 'visitors':
|
|
||||||
return <Visitors />
|
|
||||||
case 'expense-management':
|
|
||||||
return <ExpenseManagement onNewExpense={() => setShowExpenseModal(true)} />
|
|
||||||
case 'social-wall':
|
case 'social-wall':
|
||||||
return <SocialWall />
|
return <SocialWall />
|
||||||
case 'important-announcements':
|
case 'important-announcements':
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import PostItem from './PostItem'
|
||||||
import { SocialMedia } from '@/types/intranet'
|
import { SocialMedia } from '@/types/intranet'
|
||||||
import CreatePost from './CreatePost'
|
import CreatePost from './CreatePost'
|
||||||
import { SocialPost } from '@/types/intranet'
|
import { SocialPost } from '@/types/intranet'
|
||||||
import { HrEmployee } from '@/types/hr'
|
import { EmployeeDto } from '@/types/hr'
|
||||||
import { mockSocialPosts } from '@/mocks/mockIntranet'
|
import { mockSocialPosts } from '@/mocks/mockIntranet'
|
||||||
import { mockEmployees } from '@/mocks/mockEmployees'
|
import { mockEmployees } from '@/mocks/mockEmployees'
|
||||||
|
|
||||||
|
|
@ -13,7 +13,7 @@ const SocialWall: React.FC = () => {
|
||||||
const [filter, setFilter] = useState<'all' | 'mine'>('all')
|
const [filter, setFilter] = useState<'all' | 'mine'>('all')
|
||||||
|
|
||||||
// Ali Öztürk'ü "Siz" kullanıcısı olarak kullan
|
// Ali Öztürk'ü "Siz" kullanıcısı olarak kullan
|
||||||
const currentUserAuthor: HrEmployee = { ...mockEmployees[0], fullName: 'Siz' }
|
const currentUserAuthor: EmployeeDto = { ...mockEmployees[0], fullName: 'Siz' }
|
||||||
|
|
||||||
const handleCreatePost = (postData: {
|
const handleCreatePost = (postData: {
|
||||||
content: string
|
content: string
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,17 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { FaKey, FaPlus } from 'react-icons/fa'
|
import { FaKey, FaPlus } from 'react-icons/fa'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import { mockReservations } from '../../../mocks/mockIntranet'
|
import { ReservationDto } from '@/proxy/intranet/models'
|
||||||
|
|
||||||
interface ActiveReservationsProps {
|
interface ActiveReservationsProps {
|
||||||
|
reservations: ReservationDto[]
|
||||||
onNewReservation: () => void
|
onNewReservation: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
const ActiveReservations: React.FC<ActiveReservationsProps> = ({ onNewReservation }) => {
|
const ActiveReservations: React.FC<ActiveReservationsProps> = ({
|
||||||
|
reservations,
|
||||||
|
onNewReservation,
|
||||||
|
}) => {
|
||||||
return (
|
return (
|
||||||
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
|
<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="p-4 border-b border-gray-200 dark:border-gray-700">
|
||||||
|
|
@ -17,7 +21,7 @@ const ActiveReservations: React.FC<ActiveReservationsProps> = ({ onNewReservatio
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-4 space-y-3">
|
<div className="p-4 space-y-3">
|
||||||
{mockReservations
|
{reservations
|
||||||
.filter((r) => r.status === 'approved')
|
.filter((r) => r.status === 'approved')
|
||||||
.slice(0, 3)
|
.slice(0, 3)
|
||||||
.map((reservation) => (
|
.map((reservation) => (
|
||||||
|
|
@ -30,15 +34,20 @@ const ActiveReservations: React.FC<ActiveReservationsProps> = ({ onNewReservatio
|
||||||
{reservation.resourceName}
|
{reservation.resourceName}
|
||||||
</h4>
|
</h4>
|
||||||
<span className="text-xs px-2 py-1 bg-green-100 dark:bg-green-900/50 text-green-700 dark:text-green-300 rounded-full">
|
<span className="text-xs px-2 py-1 bg-green-100 dark:bg-green-900/50 text-green-700 dark:text-green-300 rounded-full">
|
||||||
{reservation.type === 'room' ? '🏢' : reservation.type === 'vehicle' ? '🚗' : '⚙️'}
|
{reservation.type === 'room'
|
||||||
|
? '🏢'
|
||||||
|
: reservation.type === 'vehicle'
|
||||||
|
? '🚗'
|
||||||
|
: '⚙️'}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-xs text-gray-600 dark:text-gray-400">
|
<p className="text-xs text-gray-600 dark:text-gray-400">
|
||||||
{dayjs(reservation.startDate).format('DD MMM HH:mm')} - {dayjs(reservation.endDate).format('HH:mm')}
|
{dayjs(reservation.startDate).format('DD MMM HH:mm')} -{' '}
|
||||||
|
{dayjs(reservation.endDate).format('HH:mm')}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
{mockReservations.filter((r) => r.status === 'approved').length === 0 && (
|
{reservations.filter((r) => r.status === 'approved').length === 0 && (
|
||||||
<p className="text-sm text-gray-500 dark:text-gray-400 text-center py-4">
|
<p className="text-sm text-gray-500 dark:text-gray-400 text-center py-4">
|
||||||
Aktif rezervasyon yok
|
Aktif rezervasyon yok
|
||||||
</p>
|
</p>
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,13 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { FaDollarSign, FaPlus } from 'react-icons/fa'
|
import { FaDollarSign, FaPlus } from 'react-icons/fa'
|
||||||
import { mockExpenseRequests } from '../../../mocks/mockIntranet'
|
import { ExpensesDto } from '@/proxy/intranet/models'
|
||||||
|
|
||||||
interface ExpenseManagementProps {
|
interface ExpenseManagementProps {
|
||||||
|
expenses: ExpensesDto
|
||||||
onNewExpense: () => void
|
onNewExpense: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
const ExpenseManagement: React.FC<ExpenseManagementProps> = ({ onNewExpense }) => {
|
const ExpenseManagement: React.FC<ExpenseManagementProps> = ({ expenses, onNewExpense }) => {
|
||||||
return (
|
return (
|
||||||
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
|
<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="p-4 border-b border-gray-200 dark:border-gray-700">
|
||||||
|
|
@ -19,13 +20,17 @@ const ExpenseManagement: React.FC<ExpenseManagementProps> = ({ onNewExpense }) =
|
||||||
{/* Harcama özeti */}
|
{/* Harcama özeti */}
|
||||||
<div className="p-3 bg-emerald-50 dark:bg-emerald-900/20 rounded-lg border border-emerald-200 dark:border-emerald-800 mb-4">
|
<div className="p-3 bg-emerald-50 dark:bg-emerald-900/20 rounded-lg border border-emerald-200 dark:border-emerald-800 mb-4">
|
||||||
<p className="text-xs text-gray-600 dark:text-gray-400">Bu Ay Toplam</p>
|
<p className="text-xs text-gray-600 dark:text-gray-400">Bu Ay Toplam</p>
|
||||||
<p className="text-2xl font-bold text-emerald-600 dark:text-emerald-400">₺2,370</p>
|
<p className="text-2xl font-bold text-emerald-600 dark:text-emerald-400">
|
||||||
<p className="text-xs text-gray-500 dark:text-gray-400 mt-1">₺2,050 onaylandı</p>
|
{expenses.totalRequested.toLocaleString('tr-TR')}
|
||||||
|
</p>
|
||||||
|
<p className="text-xs text-gray-500 dark:text-gray-400 mt-1">
|
||||||
|
{expenses.totalApproved.toLocaleString('tr-TR')} onaylandı
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Son harcama talepleri */}
|
{/* Son harcama talepleri */}
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
{mockExpenseRequests.slice(0, 3).map((expense) => (
|
{expenses.last5Expenses.slice(0, 3).map((expense) => (
|
||||||
<div
|
<div
|
||||||
key={expense.id}
|
key={expense.id}
|
||||||
className="p-3 rounded-lg bg-gray-50 dark:bg-gray-900/20 border border-gray-200 dark:border-gray-700"
|
className="p-3 rounded-lg bg-gray-50 dark:bg-gray-900/20 border border-gray-200 dark:border-gray-700"
|
||||||
|
|
@ -33,10 +38,16 @@ const ExpenseManagement: React.FC<ExpenseManagementProps> = ({ onNewExpense }) =
|
||||||
<div className="flex items-start justify-between mb-1">
|
<div className="flex items-start justify-between mb-1">
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<h4 className="text-sm font-medium text-gray-900 dark:text-white">
|
<h4 className="text-sm font-medium text-gray-900 dark:text-white">
|
||||||
{expense.category === 'travel' ? '✈️' :
|
{expense.category === 'travel'
|
||||||
expense.category === 'meal' ? '🍽️' :
|
? '✈️'
|
||||||
expense.category === 'accommodation' ? '🏨' :
|
: expense.category === 'meal'
|
||||||
expense.category === 'transport' ? '🚗' : '📋'} {expense.description}
|
? '🍽️'
|
||||||
|
: expense.category === 'accommodation'
|
||||||
|
? '🏨'
|
||||||
|
: expense.category === 'transport'
|
||||||
|
? '🚗'
|
||||||
|
: '📋'}{' '}
|
||||||
|
{expense.description}
|
||||||
</h4>
|
</h4>
|
||||||
<p className="text-xs font-semibold text-emerald-600 dark:text-emerald-400 mt-1">
|
<p className="text-xs font-semibold text-emerald-600 dark:text-emerald-400 mt-1">
|
||||||
₺{expense.amount.toLocaleString('tr-TR')}
|
₺{expense.amount.toLocaleString('tr-TR')}
|
||||||
|
|
@ -51,8 +62,11 @@ const ExpenseManagement: React.FC<ExpenseManagementProps> = ({ onNewExpense }) =
|
||||||
: 'bg-red-100 dark:bg-red-900/30 text-red-700 dark:text-red-300'
|
: 'bg-red-100 dark:bg-red-900/30 text-red-700 dark:text-red-300'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{expense.status === 'approved' ? 'Onaylandı' :
|
{expense.status === 'approved'
|
||||||
expense.status === 'pending' ? 'Bekliyor' : 'Reddedildi'}
|
? 'Onaylandı'
|
||||||
|
: expense.status === 'pending'
|
||||||
|
? 'Bekliyor'
|
||||||
|
: 'Reddedildi'}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,86 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { FaFileAlt, FaDownload } from 'react-icons/fa'
|
import {
|
||||||
|
FaFileAlt,
|
||||||
|
FaDownload,
|
||||||
|
FaFilePdf,
|
||||||
|
FaFileWord,
|
||||||
|
FaFileExcel,
|
||||||
|
FaFilePowerpoint,
|
||||||
|
FaFileImage,
|
||||||
|
FaFileArchive,
|
||||||
|
FaFileCode,
|
||||||
|
} from 'react-icons/fa'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import { mockDocuments } from '../../../mocks/mockIntranet'
|
import { DocumentDto } from '@/proxy/intranet/models'
|
||||||
|
|
||||||
const RecentDocuments: React.FC = () => {
|
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" />
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 }) => {
|
||||||
return (
|
return (
|
||||||
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
|
<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="p-4 border-b border-gray-200 dark:border-gray-700">
|
||||||
|
|
@ -15,39 +92,41 @@ const RecentDocuments: React.FC = () => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="divide-y divide-gray-200 dark:divide-gray-700">
|
<div className="divide-y divide-gray-200 dark:divide-gray-700">
|
||||||
{mockDocuments.slice(0, 3).map((doc) => (
|
{documents.slice(0, 3).map((doc) => (
|
||||||
<div
|
<div
|
||||||
key={doc.id}
|
key={doc.id}
|
||||||
className="p-4 hover:bg-gray-50 dark:hover:bg-gray-700/50 transition-colors"
|
className="p-4 hover:bg-gray-50 dark:hover:bg-gray-700/50 transition-colors"
|
||||||
>
|
>
|
||||||
<div className="flex items-start gap-3">
|
<div className="flex items-start gap-3">
|
||||||
<div className="p-2 bg-blue-100 dark:bg-blue-900/30 rounded-lg">
|
<div className="p-2 bg-blue-100 dark:bg-blue-900/30 rounded-lg">
|
||||||
<FaFileAlt className="w-4 h-4 text-blue-600 dark:text-blue-400" />
|
{getFileIcon(doc.extension)}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1 min-w-0">
|
<div className="flex-1 min-w-0">
|
||||||
<h4 className="text-sm font-medium text-gray-900 dark:text-white truncate">
|
<h4 className="text-sm font-medium text-gray-900 dark:text-white truncate">
|
||||||
{doc.name}
|
{doc.name}
|
||||||
</h4>
|
</h4>
|
||||||
<p className="text-xs text-gray-600 dark:text-gray-400 mt-1">
|
<p className="text-xs text-gray-600 dark:text-gray-400 mt-1">
|
||||||
{doc.category === 'policy' && '📋 Politika'}
|
{getFileType(doc.extension)}
|
||||||
{doc.category === 'procedure' && '📝 Prosedür'}
|
|
||||||
{doc.category === 'form' && '📄 Form'}
|
|
||||||
{doc.category === 'template' && '📋 Şablon'}
|
|
||||||
{doc.category === 'report' && '📊 Rapor'}
|
|
||||||
{doc.category === 'other' && '📄 Diğer'}
|
|
||||||
<span className="mx-1">•</span>
|
<span className="mx-1">•</span>
|
||||||
{doc.size}
|
{formatFileSize(doc.size)}
|
||||||
</p>
|
</p>
|
||||||
<div className="text-xs text-gray-500 dark:text-gray-400 mt-1 flex items-center gap-2">
|
<div className="text-xs text-gray-500 dark:text-gray-400 mt-1 flex items-center gap-2">
|
||||||
<span>{dayjs(doc.uploadDate).fromNow()}</span>
|
<span>{dayjs(doc.modifiedAt).fromNow()}</span>
|
||||||
<span>•</span>
|
{doc.isReadOnly && (
|
||||||
<span>{doc.downloadCount} indirme</span>
|
<>
|
||||||
|
<span>•</span>
|
||||||
|
<span className="text-orange-500">🔒 Salt okunur</span>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
window.open(doc.url, '_blank')
|
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"
|
className="p-2 hover:bg-blue-100 dark:hover:bg-blue-900/30 rounded-lg transition-colors group"
|
||||||
title="İndir"
|
title="İndir"
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,9 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import { mockEmployees } from '@/mocks/mockEmployees'
|
import { EmployeeDto } from '@/proxy/intranet/models'
|
||||||
|
|
||||||
const TodayBirthdays: React.FC = () => {
|
const TodayBirthdays: React.FC<{ employees: EmployeeDto[] }> = ({ employees }) => {
|
||||||
const today = dayjs()
|
const today = dayjs()
|
||||||
const todayBirthdays = mockEmployees.filter((b) => {
|
|
||||||
return (
|
|
||||||
dayjs(b.birthDate).month() === today.month() && dayjs(b.birthDate).date() === today.date()
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
return (
|
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="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">
|
||||||
|
|
@ -18,30 +13,32 @@ const TodayBirthdays: React.FC = () => {
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-4 space-y-3">
|
<div className="p-4 space-y-3">
|
||||||
{todayBirthdays.length > 0 ? (
|
{employees.length > 0 ? (
|
||||||
todayBirthdays.map((birthday, index) => (
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
|
||||||
<div
|
{employees.map((birthday, index) => (
|
||||||
key={index}
|
<div
|
||||||
className="flex items-center gap-3 p-3 bg-white/50 dark:bg-gray-800/50 rounded-lg"
|
key={index}
|
||||||
>
|
className="flex items-center gap-3 p-3 border border-pink-100 dark:border-pink-800 rounded-lg"
|
||||||
<img
|
>
|
||||||
src={birthday.avatar}
|
<img
|
||||||
alt={birthday.fullName}
|
src={birthday.avatar}
|
||||||
className="w-12 h-12 rounded-full border-2 border-pink-300 dark:border-pink-700"
|
alt={birthday.fullName}
|
||||||
/>
|
className="w-12 h-12 rounded-full border-2 border-pink-300 dark:border-pink-700"
|
||||||
<div className="flex-1">
|
/>
|
||||||
<p className="text-sm font-semibold text-gray-900 dark:text-white">
|
<div className="flex-1">
|
||||||
{birthday.fullName}
|
<p className="text-sm font-semibold text-gray-900 dark:text-white">
|
||||||
</p>
|
{birthday.fullName}
|
||||||
<p className="text-xs text-gray-600 dark:text-gray-400">
|
</p>
|
||||||
{today.diff(dayjs(birthday.birthDate), 'year')} yaşında 🎉
|
<p className="text-xs text-gray-600 dark:text-gray-400">
|
||||||
</p>
|
{today.diff(dayjs(birthday.birthDate), 'year')} yaşında 🎉
|
||||||
<p className="text-xs text-gray-500 dark:text-gray-500 mt-1">
|
</p>
|
||||||
{birthday.department?.name || 'Genel'}
|
<p className="text-xs text-gray-500 dark:text-gray-500 mt-1">
|
||||||
</p>
|
{birthday.department?.name || 'Genel'}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
))}
|
||||||
))
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<p className="text-sm text-gray-500 dark:text-gray-400 text-center py-4">
|
<p className="text-sm text-gray-500 dark:text-gray-400 text-center py-4">
|
||||||
Bugün doğan yok
|
Bugün doğan yok
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { FaGraduationCap } from 'react-icons/fa'
|
import { FaGraduationCap } from 'react-icons/fa'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import { mockTrainings } from '../../../mocks/mockIntranet'
|
import { TrainingDto } from '@/proxy/intranet/models'
|
||||||
|
|
||||||
const UpcomingTrainings: React.FC = () => {
|
const UpcomingTrainings: React.FC<{ trainings: TrainingDto[] }> = ({ trainings }) => {
|
||||||
return (
|
return (
|
||||||
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
|
<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="p-4 border-b border-gray-200 dark:border-gray-700">
|
||||||
|
|
@ -13,7 +13,7 @@ const UpcomingTrainings: React.FC = () => {
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-4 space-y-3">
|
<div className="p-4 space-y-3">
|
||||||
{mockTrainings
|
{trainings
|
||||||
.filter((t) => t.status === 'upcoming')
|
.filter((t) => t.status === 'upcoming')
|
||||||
.slice(0, 3)
|
.slice(0, 3)
|
||||||
.map((training) => (
|
.map((training) => (
|
||||||
|
|
@ -29,7 +29,8 @@ const UpcomingTrainings: React.FC = () => {
|
||||||
</p>
|
</p>
|
||||||
<div className="flex items-center justify-between text-xs">
|
<div className="flex items-center justify-between text-xs">
|
||||||
<span className="text-gray-500 dark:text-gray-400">
|
<span className="text-gray-500 dark:text-gray-400">
|
||||||
{dayjs(training.startDate).format('DD MMM')} - {dayjs(training.endDate).format('DD MMM')}
|
{dayjs(training.startDate).format('DD MMM')} -{' '}
|
||||||
|
{dayjs(training.endDate).format('DD MMM')}
|
||||||
</span>
|
</span>
|
||||||
<span className="text-blue-600 dark:text-blue-400 font-medium">
|
<span className="text-blue-600 dark:text-blue-400 font-medium">
|
||||||
{training.enrolled}/{training.maxParticipants}
|
{training.enrolled}/{training.maxParticipants}
|
||||||
|
|
@ -37,7 +38,7 @@ const UpcomingTrainings: React.FC = () => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
{mockTrainings.filter((t) => t.status === 'upcoming').length === 0 && (
|
{trainings.filter((t) => t.status === 'upcoming').length === 0 && (
|
||||||
<p className="text-sm text-gray-500 dark:text-gray-400 text-center py-4">
|
<p className="text-sm text-gray-500 dark:text-gray-400 text-center py-4">
|
||||||
Yaklaşan eğitim yok
|
Yaklaşan eğitim yok
|
||||||
</p>
|
</p>
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,9 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { FaUser, FaUserCheck, FaUserClock } from 'react-icons/fa'
|
import { FaUser, FaUserCheck, FaUserClock } from 'react-icons/fa'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import { mockVisitors } from '../../../mocks/mockIntranet'
|
import { VisitorDto } from '@/proxy/intranet/models'
|
||||||
|
|
||||||
const Visitors: React.FC = () => {
|
|
||||||
const todayVisitors = mockVisitors.filter((visitor) =>
|
|
||||||
dayjs(visitor.visitDate).isSame(dayjs(), 'day')
|
|
||||||
)
|
|
||||||
|
|
||||||
|
const Visitors: React.FC<{ visitors: VisitorDto[] }> = ({ visitors }) => {
|
||||||
const getStatusIcon = (status: string) => {
|
const getStatusIcon = (status: string) => {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case 'checked-in':
|
case 'checked-in':
|
||||||
|
|
@ -56,15 +52,20 @@ const Visitors: React.FC = () => {
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-4 space-y-3">
|
<div className="p-4 space-y-3">
|
||||||
{todayVisitors.length > 0 ? (
|
{visitors.length > 0 ? (
|
||||||
todayVisitors.map((visitor) => (
|
visitors.map((visitor) => (
|
||||||
<div
|
<div
|
||||||
key={visitor.id}
|
key={visitor.id}
|
||||||
className={`p-3 rounded-lg border ${getStatusColor(visitor.status)}`}
|
className={`p-3 rounded-lg border ${getStatusColor(visitor.status)}`}
|
||||||
>
|
>
|
||||||
<div className="flex items-start gap-3">
|
<div className="flex items-start gap-3">
|
||||||
<img
|
<img
|
||||||
src={visitor.photo}
|
src={visitor.photo ?? '/img/others/default-profile.png'}
|
||||||
|
onError={(e) => {
|
||||||
|
console.log('Image load error, using default profile image.')
|
||||||
|
e.currentTarget.onerror = null
|
||||||
|
e.currentTarget.src = '/img/others/default-profile.png'
|
||||||
|
}}
|
||||||
alt={visitor.fullName}
|
alt={visitor.fullName}
|
||||||
className="w-10 h-10 rounded-full border-2 border-gray-300 dark:border-gray-600"
|
className="w-10 h-10 rounded-full border-2 border-gray-300 dark:border-gray-600"
|
||||||
/>
|
/>
|
||||||
|
|
@ -73,16 +74,12 @@ const Visitors: React.FC = () => {
|
||||||
<h4 className="text-sm font-medium text-gray-900 dark:text-white truncate">
|
<h4 className="text-sm font-medium text-gray-900 dark:text-white truncate">
|
||||||
{visitor.fullName}
|
{visitor.fullName}
|
||||||
</h4>
|
</h4>
|
||||||
<div className="flex items-center gap-1">
|
<div className="flex items-center gap-1">{getStatusIcon(visitor.status)}</div>
|
||||||
{getStatusIcon(visitor.status)}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<p className="text-xs text-gray-600 dark:text-gray-400 truncate">
|
<p className="text-xs text-gray-600 dark:text-gray-400 truncate">
|
||||||
{visitor.company}
|
{visitor.companyName}
|
||||||
</p>
|
|
||||||
<p className="text-xs text-gray-500 dark:text-gray-500 mt-1">
|
|
||||||
{visitor.purpose}
|
|
||||||
</p>
|
</p>
|
||||||
|
<p className="text-xs text-gray-500 dark:text-gray-500 mt-1">{visitor.purpose}</p>
|
||||||
<div className="flex items-center justify-between mt-2">
|
<div className="flex items-center justify-between mt-2">
|
||||||
<span className="text-xs text-gray-500 dark:text-gray-500">
|
<span className="text-xs text-gray-500 dark:text-gray-500">
|
||||||
{dayjs(visitor.visitDate).format('HH:mm')}
|
{dayjs(visitor.visitDate).format('HH:mm')}
|
||||||
|
|
@ -91,9 +88,9 @@ const Visitors: React.FC = () => {
|
||||||
{getStatusText(visitor.status)}
|
{getStatusText(visitor.status)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{visitor.host && (
|
{visitor.employee && (
|
||||||
<p className="text-xs text-gray-500 dark:text-gray-500 mt-1">
|
<p className="text-xs text-gray-500 dark:text-gray-500 mt-1">
|
||||||
Karşılayan: {visitor.host.fullName}
|
Karşılayan: {visitor.employee.fullName}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -110,4 +107,4 @@ const Visitors: React.FC = () => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Visitors
|
export default Visitors
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ import {
|
||||||
} from '../../../types/pm'
|
} from '../../../types/pm'
|
||||||
import { mockWorkCenters } from '../../../mocks/mockWorkCenters'
|
import { mockWorkCenters } from '../../../mocks/mockWorkCenters'
|
||||||
import { mockDepartments } from '../../../mocks/mockDepartments'
|
import { mockDepartments } from '../../../mocks/mockDepartments'
|
||||||
import { HrDepartment } from '../../../types/hr'
|
import { DepartmentDto } from '../../../types/hr'
|
||||||
import { Container } from '@/components/shared'
|
import { Container } from '@/components/shared'
|
||||||
import { ROUTES_ENUM } from '@/routes/route.constant'
|
import { ROUTES_ENUM } from '@/routes/route.constant'
|
||||||
import { getCriticalityLevelText, getWorkCenterStatusText } from '@/utils/erp'
|
import { getCriticalityLevelText, getWorkCenterStatusText } from '@/utils/erp'
|
||||||
|
|
@ -35,7 +35,7 @@ const WorkCenterForm: React.FC = () => {
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
const [saving, setSaving] = useState(false)
|
const [saving, setSaving] = useState(false)
|
||||||
const [errors, setErrors] = useState<ValidationErrors>({})
|
const [errors, setErrors] = useState<ValidationErrors>({})
|
||||||
const [departments, setDepartments] = useState<HrDepartment[]>([])
|
const [departments, setDepartments] = useState<DepartmentDto[]>([])
|
||||||
|
|
||||||
const [formData, setFormData] = useState<PmWorkCenter>({
|
const [formData, setFormData] = useState<PmWorkCenter>({
|
||||||
id: '',
|
id: '',
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ import {
|
||||||
FaDownload,
|
FaDownload,
|
||||||
} from 'react-icons/fa'
|
} from 'react-icons/fa'
|
||||||
import LoadingSpinner from '../../../components/common/LoadingSpinner'
|
import LoadingSpinner from '../../../components/common/LoadingSpinner'
|
||||||
import { HrEmployee } from '../../../types/hr'
|
import { EmployeeDto } from '../../../types/hr'
|
||||||
import { mockEmployees } from '../../../mocks/mockEmployees'
|
import { mockEmployees } from '../../../mocks/mockEmployees'
|
||||||
import { mockBusinessParties } from '../../../mocks/mockBusinessParties'
|
import { mockBusinessParties } from '../../../mocks/mockBusinessParties'
|
||||||
import {
|
import {
|
||||||
|
|
@ -114,7 +114,7 @@ const ProjectForm: React.FC = () => {
|
||||||
const [saving, setSaving] = useState(false)
|
const [saving, setSaving] = useState(false)
|
||||||
const [errors, setErrors] = useState<ValidationErrors>({})
|
const [errors, setErrors] = useState<ValidationErrors>({})
|
||||||
const [customers, setCustomers] = useState<BusinessParty[]>([])
|
const [customers, setCustomers] = useState<BusinessParty[]>([])
|
||||||
const [projectManagers, setProjectManagers] = useState<HrEmployee[]>([])
|
const [projectManagers, setProjectManagers] = useState<EmployeeDto[]>([])
|
||||||
const [activeTab, setActiveTab] = useState('overview')
|
const [activeTab, setActiveTab] = useState('overview')
|
||||||
|
|
||||||
// Additional states for the new features
|
// Additional states for the new features
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue