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 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 string Extension { 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 ParentId { get; set; } = string.Empty;
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
namespace Kurs.Platform.Public;
|
||||
namespace Kurs.Platform.Intranet;
|
||||
|
||||
public class EventCommentDto
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
using System;
|
||||
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 CategoryName { get; set; }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
using System;
|
||||
|
||||
namespace Kurs.Platform.Public;
|
||||
namespace Kurs.Platform.Intranet;
|
||||
|
||||
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 Volo.Abp.Application.Services;
|
||||
|
||||
namespace Kurs.Platform.Public;
|
||||
namespace Kurs.Platform.Intranet;
|
||||
|
||||
public interface IIntranetAppService : IApplicationService
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,8 +1,16 @@
|
|||
using System.Collections.Generic;
|
||||
using Kurs.Platform.FileManagement;
|
||||
|
||||
namespace Kurs.Platform.Public;
|
||||
namespace Kurs.Platform.Intranet;
|
||||
|
||||
public class IntranetDashboardDto
|
||||
{
|
||||
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 FolderMarkerSuffix = ".folder";
|
||||
private const string IndexFileName = "index.json";
|
||||
|
||||
|
||||
// Protected system folders that cannot be deleted, renamed, or moved
|
||||
private static readonly HashSet<string> ProtectedFolders = new(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
BlobContainerNames.Avatar,
|
||||
BlobContainerNames.Import,
|
||||
BlobContainerNames.Activity
|
||||
BlobContainerNames.Activity,
|
||||
BlobContainerNames.Intranet
|
||||
};
|
||||
|
||||
public FileManagementAppService(
|
||||
|
|
@ -52,11 +53,6 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
|||
return $"files/{tenantId}/";
|
||||
}
|
||||
|
||||
private string GenerateFileId()
|
||||
{
|
||||
return Guid.NewGuid().ToString("N");
|
||||
}
|
||||
|
||||
private string EncodePathAsId(string path)
|
||||
{
|
||||
// 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
|
||||
var pathParts = path.Split('/', StringSplitOptions.RemoveEmptyEntries);
|
||||
if (pathParts.Length == 0) return false;
|
||||
|
||||
|
||||
var rootFolder = pathParts[0];
|
||||
var isProtected = ProtectedFolders.Contains(rootFolder);
|
||||
|
||||
|
||||
Logger.LogInformation($"IsProtectedFolder - Path: '{path}', RootFolder: '{rootFolder}', IsProtected: {isProtected}");
|
||||
Logger.LogInformation($"Protected folders: {string.Join(", ", ProtectedFolders)}");
|
||||
|
||||
|
||||
return isProtected;
|
||||
}
|
||||
|
||||
|
|
@ -88,14 +84,14 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
|||
{
|
||||
var decodedPath = DecodeIdAsPath(id);
|
||||
Logger.LogInformation($"ValidateNotProtectedFolder - ID: {id}, DecodedPath: {decodedPath}, Operation: {operation}");
|
||||
|
||||
|
||||
if (IsProtectedFolder(decodedPath))
|
||||
{
|
||||
var folderName = decodedPath.Split('/')[0];
|
||||
Logger.LogWarning($"Blocked {operation} operation on protected folder: {folderName}");
|
||||
throw new UserFriendlyException($"Cannot {operation} system folder '{folderName}'. This folder is protected.");
|
||||
}
|
||||
|
||||
|
||||
Logger.LogInformation($"Folder {decodedPath} is not protected, allowing {operation}");
|
||||
}
|
||||
|
||||
|
|
@ -108,7 +104,7 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
|||
{
|
||||
var items = new List<FileMetadata>();
|
||||
var cdnBasePath = _configuration["App:CdnPath"];
|
||||
|
||||
|
||||
if (string.IsNullOrEmpty(cdnBasePath))
|
||||
{
|
||||
Logger.LogWarning("CDN path is not configured");
|
||||
|
|
@ -117,7 +113,7 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
|||
|
||||
var tenantId = _currentTenant.Id?.ToString() ?? "host";
|
||||
var fullPath = Path.Combine(cdnBasePath, tenantId);
|
||||
|
||||
|
||||
if (!string.IsNullOrEmpty(folderPath))
|
||||
{
|
||||
fullPath = Path.Combine(fullPath, folderPath);
|
||||
|
|
@ -137,7 +133,7 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
|||
{
|
||||
var dirInfo = new DirectoryInfo(dir);
|
||||
var relativePath = string.IsNullOrEmpty(folderPath) ? dirInfo.Name : $"{folderPath}/{dirInfo.Name}";
|
||||
|
||||
|
||||
// Klasör içindeki öğe sayısını hesapla
|
||||
var childCount = 0;
|
||||
try
|
||||
|
|
@ -151,7 +147,7 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
|||
Logger.LogWarning(ex, "Error counting items in folder: {FolderPath}", dir);
|
||||
childCount = 0;
|
||||
}
|
||||
|
||||
|
||||
items.Add(new FileMetadata
|
||||
{
|
||||
Id = EncodePathAsId(relativePath),
|
||||
|
|
@ -173,7 +169,7 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
|||
{
|
||||
var fileInfo = new FileInfo(file);
|
||||
var relativePath = string.IsNullOrEmpty(folderPath) ? fileInfo.Name : $"{folderPath}/{fileInfo.Name}";
|
||||
|
||||
|
||||
items.Add(new FileMetadata
|
||||
{
|
||||
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)
|
||||
{
|
||||
var indexPath = GetTenantPrefix() + (string.IsNullOrEmpty(parentId) ? IndexFileName : $"{parentId}/{IndexFileName}");
|
||||
|
|
@ -244,13 +222,12 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
|||
{
|
||||
var items = await GetFolderIndexAsync(parentId);
|
||||
|
||||
var result = items.Select(metadata => {
|
||||
var result = items.Select(metadata =>
|
||||
{
|
||||
var isRootLevel = string.IsNullOrEmpty(parentId);
|
||||
var isProtected = IsProtectedFolder(metadata.Path);
|
||||
var finalIsReadOnly = metadata.IsReadOnly || (isRootLevel && isProtected);
|
||||
|
||||
Logger.LogInformation($"Item: {metadata.Name}, Path: {metadata.Path}, IsRootLevel: {isRootLevel}, IsProtected: {isProtected}, FinalIsReadOnly: {finalIsReadOnly}");
|
||||
|
||||
|
||||
return new FileItemDto
|
||||
{
|
||||
Id = metadata.Id,
|
||||
|
|
@ -283,7 +260,7 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
|||
|
||||
var tenantId = _currentTenant.Id?.ToString() ?? "host";
|
||||
var parentPath = Path.Combine(cdnBasePath, tenantId);
|
||||
|
||||
|
||||
string? decodedParentId = null;
|
||||
if (!string.IsNullOrEmpty(input.ParentId))
|
||||
{
|
||||
|
|
@ -309,7 +286,7 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
|||
Directory.CreateDirectory(folderPath);
|
||||
|
||||
var newFolderPath = string.IsNullOrEmpty(decodedParentId) ? input.Name : $"{decodedParentId}/{input.Name}";
|
||||
|
||||
|
||||
var metadata = new FileMetadata
|
||||
{
|
||||
Id = EncodePathAsId(newFolderPath),
|
||||
|
|
@ -338,10 +315,6 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
|||
|
||||
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);
|
||||
|
||||
// Decode parent ID if provided
|
||||
|
|
@ -371,7 +344,7 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
|||
|
||||
var tenantId = _currentTenant.Id?.ToString() ?? "host";
|
||||
var fullCdnPath = Path.Combine(cdnBasePath, tenantId);
|
||||
|
||||
|
||||
if (!string.IsNullOrEmpty(decodedParentId))
|
||||
{
|
||||
fullCdnPath = Path.Combine(fullCdnPath, decodedParentId);
|
||||
|
|
@ -416,7 +389,6 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
|||
};
|
||||
|
||||
// File system'e kaydedildi, index güncellemeye gerek yok
|
||||
|
||||
return new FileItemDto
|
||||
{
|
||||
Id = metadata.Id,
|
||||
|
|
@ -437,7 +409,7 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
|||
{
|
||||
// Check if this is a protected system folder
|
||||
ValidateNotProtectedFolder(id, "rename");
|
||||
|
||||
|
||||
ValidateFileName(input.Name);
|
||||
|
||||
var metadata = await FindItemMetadataAsync(id);
|
||||
|
|
@ -566,7 +538,7 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
|||
{
|
||||
// Check if this is a protected system folder
|
||||
ValidateNotProtectedFolder(id, "delete");
|
||||
|
||||
|
||||
var cdnBasePath = _configuration["App:CdnPath"];
|
||||
if (string.IsNullOrEmpty(cdnBasePath))
|
||||
{
|
||||
|
|
@ -615,7 +587,7 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
|||
{
|
||||
// Check if this is a protected system folder
|
||||
ValidateNotProtectedFolder(itemId, "delete");
|
||||
|
||||
|
||||
var actualPath = DecodeIdAsPath(itemId);
|
||||
var fullPath = Path.Combine(cdnBasePath, tenantId, actualPath);
|
||||
|
||||
|
|
@ -661,7 +633,7 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
|||
|
||||
var tenantId = _currentTenant.Id?.ToString() ?? "host";
|
||||
var basePath = Path.Combine(cdnBasePath, tenantId);
|
||||
|
||||
|
||||
string? targetPath = null;
|
||||
if (!string.IsNullOrEmpty(input.TargetFolderId))
|
||||
{
|
||||
|
|
@ -680,11 +652,11 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
|||
|
||||
// Get source item name
|
||||
var sourceItemName = Path.GetFileName(sourcePath);
|
||||
|
||||
|
||||
// Generate unique name if item already exists in target
|
||||
var targetItemPath = string.IsNullOrEmpty(targetPath) ? sourceItemName : $"{targetPath}/{sourceItemName}";
|
||||
var targetFullPath = Path.Combine(basePath, targetItemPath);
|
||||
|
||||
|
||||
var uniqueTargetPath = GetUniqueItemPath(targetFullPath, sourceItemName);
|
||||
var finalTargetPath = uniqueTargetPath.Replace(basePath + Path.DirectorySeparatorChar, "").Replace(Path.DirectorySeparatorChar, '/');
|
||||
|
||||
|
|
@ -692,7 +664,7 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
|||
{
|
||||
// Copy directory recursively
|
||||
CopyDirectory(sourceFullPath, uniqueTargetPath);
|
||||
|
||||
|
||||
var dirInfo = new DirectoryInfo(uniqueTargetPath);
|
||||
copiedItems.Add(new FileItemDto
|
||||
{
|
||||
|
|
@ -714,12 +686,12 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
|||
{
|
||||
Directory.CreateDirectory(targetDir);
|
||||
}
|
||||
|
||||
|
||||
File.Copy(sourceFullPath, uniqueTargetPath);
|
||||
|
||||
|
||||
var fileInfo = new FileInfo(uniqueTargetPath);
|
||||
var extension = fileInfo.Extension;
|
||||
|
||||
|
||||
copiedItems.Add(new FileItemDto
|
||||
{
|
||||
Id = EncodePathAsId(finalTargetPath),
|
||||
|
|
@ -769,7 +741,7 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
|||
|
||||
var tenantId = _currentTenant.Id?.ToString() ?? "host";
|
||||
var basePath = Path.Combine(cdnBasePath, tenantId);
|
||||
|
||||
|
||||
string? targetPath = null;
|
||||
if (!string.IsNullOrEmpty(input.TargetFolderId))
|
||||
{
|
||||
|
|
@ -791,11 +763,11 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
|||
|
||||
// Get source item name
|
||||
var sourceItemName = Path.GetFileName(sourcePath);
|
||||
|
||||
|
||||
// Generate target path
|
||||
var targetItemPath = string.IsNullOrEmpty(targetPath) ? sourceItemName : $"{targetPath}/{sourceItemName}";
|
||||
var targetFullPath = Path.Combine(basePath, targetItemPath);
|
||||
|
||||
|
||||
// Check if moving to same location
|
||||
if (Path.GetFullPath(sourceFullPath) == Path.GetFullPath(targetFullPath))
|
||||
{
|
||||
|
|
@ -815,9 +787,9 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
|||
{
|
||||
Directory.CreateDirectory(targetDir);
|
||||
}
|
||||
|
||||
|
||||
Directory.Move(sourceFullPath, uniqueTargetPath);
|
||||
|
||||
|
||||
var dirInfo = new DirectoryInfo(uniqueTargetPath);
|
||||
movedItems.Add(new FileItemDto
|
||||
{
|
||||
|
|
@ -839,12 +811,12 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
|||
{
|
||||
Directory.CreateDirectory(targetDir);
|
||||
}
|
||||
|
||||
|
||||
File.Move(sourceFullPath, uniqueTargetPath);
|
||||
|
||||
|
||||
var fileInfo = new FileInfo(uniqueTargetPath);
|
||||
var extension = fileInfo.Extension;
|
||||
|
||||
|
||||
movedItems.Add(new FileItemDto
|
||||
{
|
||||
Id = EncodePathAsId(finalTargetPath),
|
||||
|
|
@ -949,10 +921,10 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
|||
|
||||
var nameWithoutExt = Path.GetFileNameWithoutExtension(originalFileName);
|
||||
var extension = Path.GetExtension(originalFileName);
|
||||
|
||||
|
||||
var counter = 1;
|
||||
string uniqueName;
|
||||
|
||||
|
||||
do
|
||||
{
|
||||
uniqueName = $"{nameWithoutExt} ({counter}){extension}";
|
||||
|
|
@ -1070,19 +1042,19 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
|||
// Decode the folderId to get the actual path
|
||||
var decodedPath = DecodeIdAsPath(folderId);
|
||||
Logger.LogInformation($"GetFolderPath - FolderId: {folderId}, DecodedPath: {decodedPath}");
|
||||
|
||||
|
||||
// Split path into parts and build breadcrumb
|
||||
var pathParts = decodedPath.Split('/', StringSplitOptions.RemoveEmptyEntries);
|
||||
var currentEncodedPath = "";
|
||||
|
||||
|
||||
for (int i = 0; i < pathParts.Length; i++)
|
||||
{
|
||||
// Build the path up to current level
|
||||
var pathUpToCurrent = string.Join("/", pathParts.Take(i + 1));
|
||||
currentEncodedPath = EncodePathAsId(pathUpToCurrent);
|
||||
|
||||
|
||||
Logger.LogInformation($"PathItem {i}: Name='{pathParts[i]}', Id='{currentEncodedPath}', PathUpToCurrent='{pathUpToCurrent}'");
|
||||
|
||||
|
||||
pathItems.Add(new PathItemDto
|
||||
{
|
||||
Id = currentEncodedPath,
|
||||
|
|
@ -1104,10 +1076,10 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
|
|||
var directory = Path.GetDirectoryName(targetPath) ?? "";
|
||||
var nameWithoutExt = Path.GetFileNameWithoutExtension(originalName);
|
||||
var extension = Path.GetExtension(originalName);
|
||||
|
||||
|
||||
var counter = 1;
|
||||
string newPath;
|
||||
|
||||
|
||||
do
|
||||
{
|
||||
var newName = $"{nameWithoutExt} ({counter}){extension}";
|
||||
|
|
|
|||
|
|
@ -1,47 +1,216 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Kurs.Platform.BlobStoring;
|
||||
using Kurs.Platform.Entities;
|
||||
using Kurs.Platform.FileManagement;
|
||||
using Kurs.Platform.Intranet;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Volo.Abp.Domain.Repositories;
|
||||
using Volo.Abp.MultiTenancy;
|
||||
|
||||
namespace Kurs.Platform.Public;
|
||||
|
||||
[Authorize]
|
||||
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<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<Visitor, Guid> _visitorRepository;
|
||||
private readonly IRepository<Reservation, Guid> _reservationRepository;
|
||||
private readonly IRepository<Training, Guid> _trainingRepository;
|
||||
private readonly IRepository<Expense, Guid> _expenseRepository;
|
||||
|
||||
public IntranetAppService(
|
||||
ICurrentTenant currentTenant,
|
||||
BlobManager blobContainer,
|
||||
IConfiguration configuration,
|
||||
|
||||
IRepository<Event, Guid> eventRepository,
|
||||
IRepository<EventCategory, Guid> eventCategoryRepository,
|
||||
IRepository<EventType, Guid> eventTypeRepository,
|
||||
IRepository<EventPhoto, Guid> eventPhotoRepository,
|
||||
IRepository<EventComment, Guid> eventCommentRepository,
|
||||
IRepository<Employee, Guid> employeeRepository)
|
||||
IRepository<Employee, Guid> employeeRepository,
|
||||
IRepository<Visitor, Guid> visitorRepository,
|
||||
IRepository<Reservation, Guid> reservationRepository,
|
||||
IRepository<Training, Guid> trainingRepository,
|
||||
IRepository<Expense, Guid> expenseRepository
|
||||
)
|
||||
{
|
||||
_currentTenant = currentTenant;
|
||||
_blobContainer = blobContainer;
|
||||
_configuration = configuration;
|
||||
|
||||
_eventRepository = eventRepository;
|
||||
_eventCategoryRepository = eventCategoryRepository;
|
||||
_eventTypeRepository = eventTypeRepository;
|
||||
_eventPhotoRepository = eventPhotoRepository;
|
||||
_eventCommentRepository = eventCommentRepository;
|
||||
_employeeRepository = employeeRepository;
|
||||
_visitorRepository = visitorRepository;
|
||||
_reservationRepository = reservationRepository;
|
||||
_trainingRepository = trainingRepository;
|
||||
_expenseRepository = expenseRepository;
|
||||
}
|
||||
|
||||
public async Task<IntranetDashboardDto> GetIntranetDashboardAsync()
|
||||
{
|
||||
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()
|
||||
{
|
||||
var events = await _eventRepository
|
||||
|
|
@ -74,7 +243,7 @@ public class IntranetAppService : PlatformAppService, IIntranetAppService
|
|||
Avatar = employee.Avatar
|
||||
},
|
||||
Participants = evt.ParticipantsCount,
|
||||
Photos = [],
|
||||
Photos = [],
|
||||
Comments = [],
|
||||
Likes = evt.Likes,
|
||||
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,
|
||||
UserId = null,
|
||||
CultureName = LanguageCodes.En,
|
||||
SourceDbType = DbType.Date,
|
||||
SourceDbType = DbType.DateTime,
|
||||
FieldName = "VisitDate",
|
||||
Width = 100,
|
||||
Width = 150,
|
||||
ListOrderNo = 7,
|
||||
Visible = true,
|
||||
IsActive = true,
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ namespace Kurs.Platform.BlobStoring;
|
|||
|
||||
public static class BlobContainerNames
|
||||
{
|
||||
public const string Intranet = "intranet";
|
||||
public const string Avatar = "avatar";
|
||||
public const string Import = "import";
|
||||
public const string Activity = "activity";
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
// Domain/Entities/Visitor.cs
|
||||
using System;
|
||||
using Volo.Abp.Domain.Entities.Auditing;
|
||||
using Volo.Abp.MultiTenancy;
|
||||
|
|
@ -17,7 +16,9 @@ public class Visitor : FullAuditedEntity<Guid>, IMultiTenant
|
|||
public DateTime VisitDate { get; set; }
|
||||
public DateTime? CheckIn { 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 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
|
||||
{
|
||||
[DbContext(typeof(PlatformDbContext))]
|
||||
[Migration("20251028200151_Initial")]
|
||||
[Migration("20251029074530_Initial")]
|
||||
partial class Initial
|
||||
{
|
||||
/// <inheritdoc />
|
||||
|
|
@ -9058,6 +9058,9 @@ namespace Kurs.Platform.Migrations
|
|||
b.Property<Guid>("Id")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<string>("BadgeNumber")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<DateTime?>("CheckIn")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
|
|
@ -9115,6 +9118,9 @@ namespace Kurs.Platform.Migrations
|
|||
.HasMaxLength(20)
|
||||
.HasColumnType("nvarchar(20)");
|
||||
|
||||
b.Property<string>("Photo")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Purpose")
|
||||
.HasMaxLength(250)
|
||||
.HasColumnType("nvarchar(250)");
|
||||
|
|
@ -4462,6 +4462,8 @@ namespace Kurs.Platform.Migrations
|
|||
CheckOut = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
EmployeeId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
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),
|
||||
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
|
|
@ -9055,6 +9055,9 @@ namespace Kurs.Platform.Migrations
|
|||
b.Property<Guid>("Id")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<string>("BadgeNumber")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<DateTime?>("CheckIn")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
|
|
@ -9112,6 +9115,9 @@ namespace Kurs.Platform.Migrations
|
|||
.HasMaxLength(20)
|
||||
.HasColumnType("nvarchar(20)");
|
||||
|
||||
b.Property<string>("Photo")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Purpose")
|
||||
.HasMaxLength(250)
|
||||
.HasColumnType("nvarchar(250)");
|
||||
|
|
|
|||
|
|
@ -100,9 +100,7 @@
|
|||
"props": null,
|
||||
"description": null,
|
||||
"isActive": true,
|
||||
"dependencies": [
|
||||
"AxiosListComponent"
|
||||
]
|
||||
"dependencies": ["AxiosListComponent"]
|
||||
}
|
||||
],
|
||||
"ReportCategories": [
|
||||
|
|
@ -1509,7 +1507,7 @@
|
|||
{
|
||||
"CategoryName": "Spor",
|
||||
"TypeName": "Futbol Turnuvası",
|
||||
"Date": "2025-11-15T10:00:00",
|
||||
"Date": "2025-11-05T10:00:00",
|
||||
"Name": "Yaz Futbol Turnuvası 2025",
|
||||
"Description": "Tüm departmanların katılımıyla düzenlenen geleneksel yaz futbol turnuvası.",
|
||||
"Place": "Şirket Kampüsü Spor Alanı",
|
||||
|
|
@ -1524,7 +1522,7 @@
|
|||
{
|
||||
"CategoryName": "Kültür",
|
||||
"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",
|
||||
"Description": "Çalışanlarımıza özel, rehber eşliğinde 2 günlük kültürel gezi.",
|
||||
"Place": "Kapadokya, Nevşehir",
|
||||
|
|
@ -1539,7 +1537,7 @@
|
|||
{
|
||||
"CategoryName": "Müzik",
|
||||
"TypeName": "Caz Akşamı",
|
||||
"Date": "2025-11-18T10:00:00",
|
||||
"Date": "2025-11-09T10:00:00",
|
||||
"Name": "Müzik Dinletisi: Jazz Akşamı",
|
||||
"Description": "Caz müziğinin en güzel örneklerinin canlı performanslarla sunulacağı özel akşam.",
|
||||
"Place": "Şirket Konferans Salonu",
|
||||
|
|
@ -2408,12 +2406,7 @@
|
|||
"minSalary": 80000,
|
||||
"maxSalary": 120000,
|
||||
"currencyCode": "USD",
|
||||
"requiredSkills": [
|
||||
"JavaScript",
|
||||
"TypeScript",
|
||||
"React",
|
||||
"Node.js"
|
||||
],
|
||||
"requiredSkills": ["JavaScript", "TypeScript", "React", "Node.js"],
|
||||
"responsibilities": [
|
||||
"Develop frontend and backend applications",
|
||||
"Write clean and maintainable code",
|
||||
|
|
@ -2858,7 +2851,7 @@
|
|||
"fullName": "Ali Öztürk",
|
||||
"avatar": "https://i.pravatar.cc/150?img=12",
|
||||
"nationalId": "12345678901",
|
||||
"birthDate": "10-10-1988",
|
||||
"birthDate": "2020-10-29",
|
||||
"gender": "Male",
|
||||
"maritalStatus": "Married",
|
||||
"country": "TR",
|
||||
|
|
@ -2898,7 +2891,7 @@
|
|||
"fullName": "Ayşe Kaya",
|
||||
"avatar": "https://i.pravatar.cc/150?img=5",
|
||||
"nationalId": "12345678902",
|
||||
"birthDate": "02-08-1990",
|
||||
"birthDate": "2015-10-30",
|
||||
"gender": "Female",
|
||||
"maritalStatus": "Single",
|
||||
"country": "TR",
|
||||
|
|
@ -2938,7 +2931,7 @@
|
|||
"fullName": "Mehmet Yılmaz",
|
||||
"avatar": "https://i.pravatar.cc/150?img=8",
|
||||
"nationalId": "12345678903",
|
||||
"birthDate": "12-03-1987",
|
||||
"birthDate": "2010-10-31",
|
||||
"gender": "Male",
|
||||
"maritalStatus": "Married",
|
||||
"country": "TR",
|
||||
|
|
@ -2978,7 +2971,7 @@
|
|||
"fullName": "Selin Demir",
|
||||
"avatar": "https://i.pravatar.cc/150?img=9",
|
||||
"nationalId": "12345678904",
|
||||
"birthDate": "05-05-1993",
|
||||
"birthDate": "2000-11-01",
|
||||
"gender": "Female",
|
||||
"maritalStatus": "Single",
|
||||
"country": "TR",
|
||||
|
|
@ -3018,7 +3011,7 @@
|
|||
"fullName": "Ahmet Çelik",
|
||||
"avatar": "https://i.pravatar.cc/150?img=33",
|
||||
"nationalId": "12345678905",
|
||||
"birthDate": "10-09-1985",
|
||||
"birthDate": "1999-11-02",
|
||||
"gender": "Male",
|
||||
"maritalStatus": "Married",
|
||||
"country": "TR",
|
||||
|
|
@ -3058,7 +3051,7 @@
|
|||
"fullName": "Zeynep Arslan",
|
||||
"avatar": "https://i.pravatar.cc/150?img=10",
|
||||
"nationalId": "12345678906",
|
||||
"birthDate": "01-01-1995",
|
||||
"birthDate": "1995-11-03",
|
||||
"gender": "Female",
|
||||
"maritalStatus": "Single",
|
||||
"country": "TR",
|
||||
|
|
@ -3098,7 +3091,7 @@
|
|||
"fullName": "Burak Koç",
|
||||
"avatar": "https://i.pravatar.cc/150?img=14",
|
||||
"nationalId": "12345678907",
|
||||
"birthDate": "08-06-1991",
|
||||
"birthDate": "1980-11-04",
|
||||
"gender": "Male",
|
||||
"maritalStatus": "Married",
|
||||
"country": "TR",
|
||||
|
|
@ -3138,7 +3131,7 @@
|
|||
"fullName": "Elif Şahin",
|
||||
"avatar": "https://i.pravatar.cc/150?img=20",
|
||||
"nationalId": "12345678908",
|
||||
"birthDate": "05-11-1989",
|
||||
"birthDate": "1989-11-05",
|
||||
"gender": "Female",
|
||||
"maritalStatus": "Married",
|
||||
"country": "TR",
|
||||
|
|
@ -3178,7 +3171,7 @@
|
|||
"fullName": "Canan Öztürk",
|
||||
"avatar": "https://i.pravatar.cc/150?img=25",
|
||||
"nationalId": "12345678909",
|
||||
"birthDate": "04-04-1992",
|
||||
"birthDate": "1992-11-06",
|
||||
"gender": "Female",
|
||||
"maritalStatus": "Single",
|
||||
"country": "TR",
|
||||
|
|
@ -3218,7 +3211,7 @@
|
|||
"fullName": "Murat Aydın",
|
||||
"avatar": "https://i.pravatar.cc/150?img=30",
|
||||
"nationalId": "12345678910",
|
||||
"birthDate": "03-12-1984",
|
||||
"birthDate": "1984-11-07",
|
||||
"gender": "Male",
|
||||
"maritalStatus": "Married",
|
||||
"country": "TR",
|
||||
|
|
@ -3561,8 +3554,8 @@
|
|||
"category": "technical",
|
||||
"type": "online",
|
||||
"duration": 16,
|
||||
"startDate": "01-11-2024",
|
||||
"endDate": "08-11-2024",
|
||||
"startDate": "2025-10-29",
|
||||
"endDate": "2025-11-08",
|
||||
"maxParticipants": 20,
|
||||
"enrolled": 15,
|
||||
"status": "upcoming",
|
||||
|
|
@ -3576,8 +3569,8 @@
|
|||
"category": "soft-skills",
|
||||
"type": "classroom",
|
||||
"duration": 8,
|
||||
"startDate": "05-10-2024",
|
||||
"endDate": "05-10-2024",
|
||||
"startDate": "2024-11-05",
|
||||
"endDate": "2024-12-05",
|
||||
"maxParticipants": 15,
|
||||
"enrolled": 12,
|
||||
"status": "ongoing",
|
||||
|
|
@ -3591,8 +3584,8 @@
|
|||
"category": "management",
|
||||
"type": "hybrid",
|
||||
"duration": 24,
|
||||
"startDate": "10-09-2024",
|
||||
"endDate": "03-09-2024",
|
||||
"startDate": "2025-10-29",
|
||||
"endDate": "2025-11-03",
|
||||
"maxParticipants": 25,
|
||||
"enrolled": 25,
|
||||
"status": "completed",
|
||||
|
|
@ -3606,8 +3599,8 @@
|
|||
"category": "compliance",
|
||||
"type": "online",
|
||||
"duration": 12,
|
||||
"startDate": "05-11-2024",
|
||||
"endDate": "02-11-2024",
|
||||
"startDate": "2024-11-05",
|
||||
"endDate": "2024-11-30",
|
||||
"maxParticipants": 50,
|
||||
"enrolled": 8,
|
||||
"status": "upcoming",
|
||||
|
|
@ -3620,8 +3613,8 @@
|
|||
"type": "room",
|
||||
"resourceName": "Toplantı Salonu A",
|
||||
"employeeCode": "EMP-001",
|
||||
"startDate": "10-10-2024 09:00:00",
|
||||
"endDate": "10-10-2024 11:00:00",
|
||||
"startDate": "10-10-2025 09:00:00",
|
||||
"endDate": "10-10-2025 11:00:00",
|
||||
"purpose": "Sprint Planning Toplantısı",
|
||||
"status": "approved",
|
||||
"participants": 8,
|
||||
|
|
@ -3631,8 +3624,8 @@
|
|||
"type": "vehicle",
|
||||
"resourceName": "Şirket Aracı - 34 ABC 123",
|
||||
"employeeCode": "EMP-001",
|
||||
"startDate": "11-10-2024 08:00:00",
|
||||
"endDate": "11-10-2024 18:00:00",
|
||||
"startDate": "11-10-2025 08:00:00",
|
||||
"endDate": "11-10-2025 18:00:00",
|
||||
"purpose": "Müşteri Ziyareti",
|
||||
"status": "pending",
|
||||
"notes": "Ankara çıkışı"
|
||||
|
|
@ -3641,8 +3634,8 @@
|
|||
"type": "equipment",
|
||||
"resourceName": "Kamera ve Tripod Seti",
|
||||
"employeeCode": "EMP-001",
|
||||
"startDate": "09-10-2024 14:00:00",
|
||||
"endDate": "09-10-2024 17:00:00",
|
||||
"startDate": "09-10-2025 14:00:00",
|
||||
"endDate": "09-10-2025 17:00:00",
|
||||
"purpose": "Ürün Tanıtım Videosu Çekimi",
|
||||
"status": "approved"
|
||||
},
|
||||
|
|
@ -3650,8 +3643,8 @@
|
|||
"type": "room",
|
||||
"resourceName": "Eğitim Salonu B",
|
||||
"employeeCode": "EMP-001",
|
||||
"startDate": "05-10-2024 09:00:00",
|
||||
"endDate": "05-10-2024 17:00:00",
|
||||
"startDate": "05-10-2025 09:00:00",
|
||||
"endDate": "05-10-2025 17:00:00",
|
||||
"purpose": "Etkili İletişim Eğitimi",
|
||||
"status": "approved",
|
||||
"participants": 15,
|
||||
|
|
@ -3783,33 +3776,36 @@
|
|||
"companyName": "ABC Teknoloji",
|
||||
"email": "ali.veli@abc.com",
|
||||
"phone": "5321112233",
|
||||
"visitDate": "2025-10-05",
|
||||
"checkIn": "05-10-2025",
|
||||
"visitDate": "2025-10-29T09:00:00",
|
||||
"checkIn": "2025-10-29T09:15:00",
|
||||
"employeeCode": "EMP-001",
|
||||
"purpose": "İş Ortaklığı Görüşmesi",
|
||||
"status": "checked-in"
|
||||
"status": "checked-in",
|
||||
"photo": "https://i.pravatar.cc/150?img=12"
|
||||
},
|
||||
{
|
||||
"fullName": "Fatma Yıldız",
|
||||
"companyName": "XYZ Danışmanlık",
|
||||
"email": "fatma@xyz.com",
|
||||
"phone": "5332223344",
|
||||
"visitDate": "01-10-2024",
|
||||
"visitDate": "2025-10-30T10:30:00",
|
||||
"employeeCode": "EMP-002",
|
||||
"purpose": "Eğitim Danışmanlığı",
|
||||
"status": "scheduled"
|
||||
"status": "scheduled",
|
||||
"photo": "https://i.pravatar.cc/150?img=13"
|
||||
},
|
||||
{
|
||||
"fullName": "Mehmet Kara",
|
||||
"companyName": "DEF Yazılım",
|
||||
"email": "mehmet@def.com",
|
||||
"phone": "5343334455",
|
||||
"visitDate": "08-10-2024",
|
||||
"checkIn": "08-10-2024",
|
||||
"checkOut": "10-10-2024",
|
||||
"visitDate": "2025-10-31T14:00:00",
|
||||
"checkIn": "2025-10-31T14:10:00",
|
||||
"checkOut": "2025-10-31T16:00:00",
|
||||
"employeeCode": "EMP-003",
|
||||
"purpose": "Teknik Sunum",
|
||||
"status": "checked-out"
|
||||
"status": "checked-out",
|
||||
"photo": "https://i.pravatar.cc/150?img=14"
|
||||
}
|
||||
],
|
||||
"ExpenseRequests": [
|
||||
|
|
@ -3818,19 +3814,19 @@
|
|||
"category": "travel",
|
||||
"amount": 850,
|
||||
"currencyCode": "TRY",
|
||||
"requestDate": "08-10-2024",
|
||||
"requestDate": "2025-10-04",
|
||||
"description": "Ankara ofis ziyareti - uçak bileti",
|
||||
"project": "Intranet v2",
|
||||
"status": "approved",
|
||||
"approverCode": "EMP-004",
|
||||
"approvalDate": "10-10-2024"
|
||||
"approvalDate": "2025-10-10"
|
||||
},
|
||||
{
|
||||
"employeeCode": "EMP-002",
|
||||
"category": "meal",
|
||||
"amount": 320,
|
||||
"currencyCode": "TRY",
|
||||
"requestDate": "07-10-2024",
|
||||
"requestDate": "2025-10-07",
|
||||
"description": "Müşteri toplantısı - öğle yemeği",
|
||||
"project": null,
|
||||
"status": "pending",
|
||||
|
|
@ -3842,12 +3838,12 @@
|
|||
"category": "accommodation",
|
||||
"amount": 1200,
|
||||
"currencyCode": "TRY",
|
||||
"requestDate": "04-10-2024",
|
||||
"requestDate": "2025-10-04",
|
||||
"description": "İzmir workshop - otel konaklaması (2 gece)",
|
||||
"project": "UX Workshop",
|
||||
"status": "approved",
|
||||
"approverCode": "EMP-005",
|
||||
"approvalDate": "05-10-2024"
|
||||
"approvalDate": "2025-10-05"
|
||||
}
|
||||
],
|
||||
"Surveys": [
|
||||
|
|
@ -4105,9 +4101,7 @@
|
|||
{
|
||||
"postContent": "CI/CD pipeline güncellememiz tamamlandı! Deployment süremiz %40 azaldı. Otomasyonun gücü 💪",
|
||||
"type": "video",
|
||||
"urls": [
|
||||
"https://www.w3schools.com/html/mov_bbb.mp4"
|
||||
]
|
||||
"urls": ["https://www.w3schools.com/html/mov_bbb.mp4"]
|
||||
}
|
||||
],
|
||||
"SocialPollOptions": [
|
||||
|
|
@ -4188,4 +4182,4 @@
|
|||
"employeeCode": "EMP-003"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1293,7 +1293,8 @@ public class TenantDataSeeder : IDataSeedContributor, ITransientDependency
|
|||
CheckIn = item.CheckIn,
|
||||
CheckOut = item.CheckOut,
|
||||
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 string EmployeeCode { get; set; }
|
||||
public string Status { get; set; }
|
||||
public string Photo { get; set; }
|
||||
}
|
||||
|
||||
public class AnnouncementSeedDto
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import React, { useState, useRef, useEffect } from "react";
|
||||
import { FaChevronDown, FaTimes } from "react-icons/fa";
|
||||
import { mockEmployees } from "../../mocks/mockEmployees";
|
||||
import { HrEmployee } from "../../types/hr";
|
||||
import { EmployeeDto } from "../../types/hr";
|
||||
|
||||
interface MultiSelectEmployeeProps {
|
||||
selectedEmployees: string[];
|
||||
|
|
@ -40,7 +40,7 @@ const MultiSelectEmployee: React.FC<MultiSelectEmployeeProps> = ({
|
|||
}, []);
|
||||
|
||||
const filteredEmployees = mockEmployees.filter(
|
||||
(employee: HrEmployee) =>
|
||||
(employee: EmployeeDto) =>
|
||||
employee.fullName.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));
|
||||
};
|
||||
|
||||
const selectedEmployeeObjects = mockEmployees.filter((emp: HrEmployee) =>
|
||||
const selectedEmployeeObjects = mockEmployees.filter((emp: EmployeeDto) =>
|
||||
selectedEmployees.includes(emp.id)
|
||||
);
|
||||
|
||||
|
|
@ -79,7 +79,7 @@ const MultiSelectEmployee: React.FC<MultiSelectEmployeeProps> = ({
|
|||
<div className="flex items-center justify-between">
|
||||
<div className="flex flex-wrap gap-1 flex-1">
|
||||
{selectedEmployeeObjects.length > 0 ? (
|
||||
selectedEmployeeObjects.map((employee: HrEmployee) => (
|
||||
selectedEmployeeObjects.map((employee: EmployeeDto) => (
|
||||
<span
|
||||
key={employee.id}
|
||||
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 */}
|
||||
<div className="max-h-48 overflow-y-auto">
|
||||
{filteredEmployees.length > 0 ? (
|
||||
filteredEmployees.map((employee: HrEmployee) => (
|
||||
filteredEmployees.map((employee: EmployeeDto) => (
|
||||
<div
|
||||
key={employee.id}
|
||||
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',
|
||||
code: 'ÜRT',
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import {
|
||||
HrEmployee,
|
||||
EmployeeDto,
|
||||
EmployeeStatusEnum,
|
||||
EmploymentTypeEnum,
|
||||
GenderEnum,
|
||||
|
|
@ -9,7 +9,7 @@ import { mockBanks } from "./mockBanks";
|
|||
import { mockDepartments } from "./mockDepartments";
|
||||
import { mockJobPositions } from "./mockJobPositions";
|
||||
|
||||
export const mockEmployees: HrEmployee[] = [
|
||||
export const mockEmployees: EmployeeDto[] = [
|
||||
{
|
||||
id: "1",
|
||||
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 {
|
||||
Announcement,
|
||||
Visitor,
|
||||
Document,
|
||||
Certificate,
|
||||
ExpenseRequest,
|
||||
Training,
|
||||
Reservation,
|
||||
MealMenu,
|
||||
ShuttleRoute,
|
||||
Survey,
|
||||
SocialPost,
|
||||
} 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[] = [
|
||||
{
|
||||
id: 'menu1',
|
||||
|
|
@ -175,7 +72,7 @@ export const mockMealMenus: MealMenu[] = [
|
|||
},
|
||||
]
|
||||
|
||||
export const mockReservations: Reservation[] = [
|
||||
export const mockReservations: ReservationDto[] = [
|
||||
{
|
||||
id: 'res1',
|
||||
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[] = [
|
||||
{
|
||||
id: 'survey1',
|
||||
|
|
@ -992,3 +752,279 @@ export const mockEvents: EventDto[] = [
|
|||
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";
|
||||
|
||||
export const mockJobPositions: HrJobPosition[] = [
|
||||
export const mockJobPositions: JobPositionDto[] = [
|
||||
{
|
||||
id: "1",
|
||||
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 {
|
||||
events: EventDto[];
|
||||
events: EventDto[]
|
||||
birthdays: EmployeeDto[]
|
||||
visitors: VisitorDto[]
|
||||
reservations: ReservationDto[]
|
||||
trainings: TrainingDto[]
|
||||
expenses: ExpensesDto
|
||||
documents: DocumentDto[]
|
||||
}
|
||||
|
||||
// Etkinlik
|
||||
|
|
@ -13,7 +33,7 @@ export interface EventDto {
|
|||
name: string
|
||||
description: string
|
||||
place: string
|
||||
organizer: HrEmployee
|
||||
organizer: EmployeeDto
|
||||
participants: number
|
||||
photos: string[]
|
||||
comments: EventCommentDto[]
|
||||
|
|
@ -24,8 +44,183 @@ export interface EventDto {
|
|||
// Etkinlik Yorumu
|
||||
export interface EventCommentDto {
|
||||
id: string
|
||||
author: HrEmployee
|
||||
author: EmployeeDto
|
||||
content: string
|
||||
creationTime: Date
|
||||
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,
|
||||
CrmTerritory,
|
||||
} from './crm'
|
||||
import { HrEmployee } from './hr'
|
||||
import { SupplierCardTypeEnum, MmSupplierPerformance, SupplierTypeEnum } from './mm'
|
||||
import { EmployeeDto } from '@/proxy/intranet/models'
|
||||
|
||||
export interface DashboardStats {
|
||||
// Gösterge Paneli İstatistikleri
|
||||
|
|
@ -107,7 +107,7 @@ export interface Team {
|
|||
name: string
|
||||
description?: string
|
||||
managerId: string
|
||||
manager?: HrEmployee
|
||||
manager?: EmployeeDto
|
||||
members: TeamMember[]
|
||||
territories?: CrmTerritory[]
|
||||
targets?: CrmSalesTarget[]
|
||||
|
|
@ -122,7 +122,7 @@ export interface TeamMember {
|
|||
id: string
|
||||
teamId: string
|
||||
employeeId: string
|
||||
employee?: HrEmployee
|
||||
employee?: EmployeeDto
|
||||
role: TeamRoleEnum
|
||||
joinDate: Date
|
||||
isActive: boolean
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { Address, BusinessParty, Contact, PaymentTerms, PriorityEnum } from './common'
|
||||
import { HrEmployee } from './hr'
|
||||
import { EmployeeDto } from './hr'
|
||||
import { MmDelivery, MmMaterial, MmUnit } from './mm'
|
||||
|
||||
export interface CrmSalesOrder {
|
||||
|
|
@ -86,7 +86,7 @@ export interface CrmOpportunity {
|
|||
expectedCloseDate: Date
|
||||
actualCloseDate?: Date
|
||||
assignedTo: string
|
||||
assigned?: HrEmployee
|
||||
assigned?: EmployeeDto
|
||||
teamId?: string
|
||||
leadSource: LeadSourceEnum
|
||||
campaignId?: string
|
||||
|
|
@ -115,7 +115,7 @@ export interface CrmActivity {
|
|||
endTime?: Date
|
||||
duration?: number // minutes
|
||||
assignedTo: string
|
||||
assigned?: HrEmployee
|
||||
assigned?: EmployeeDto
|
||||
participants: string[]
|
||||
status: ActivityStatusEnum
|
||||
priority: PriorityEnum
|
||||
|
|
|
|||
|
|
@ -1,49 +1,6 @@
|
|||
import { DepartmentDto, EmployeeDto, JobPositionDto } from '@/proxy/intranet/models'
|
||||
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 {
|
||||
// İnsan Kaynakları Masraf Merkezi
|
||||
id: string
|
||||
|
|
@ -54,9 +11,9 @@ export interface HrCostCenter {
|
|||
parentCostCenter?: HrCostCenter
|
||||
subCostCenters: HrCostCenter[]
|
||||
responsibleEmployeeId?: string
|
||||
responsibleEmployee?: HrEmployee
|
||||
responsibleEmployee?: EmployeeDto
|
||||
departmentId?: string
|
||||
department?: HrDepartment
|
||||
department?: DepartmentDto
|
||||
costCenterType: CostCenterType
|
||||
budgetedAmount: number
|
||||
actualAmount: number
|
||||
|
|
@ -67,51 +24,11 @@ export interface HrCostCenter {
|
|||
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 {
|
||||
// İnsan Kaynakları İzni
|
||||
id: string
|
||||
employeeId: string
|
||||
employee?: HrEmployee
|
||||
employee?: EmployeeDto
|
||||
leaveType: LeaveTypeEnum
|
||||
startDate: Date
|
||||
endDate: Date
|
||||
|
|
@ -132,9 +49,9 @@ export interface HrPerformanceEvaluation {
|
|||
// İnsan Kaynakları Performans Değerlendirmesi
|
||||
id: string
|
||||
employeeId: string
|
||||
employee?: HrEmployee
|
||||
employee?: EmployeeDto
|
||||
evaluatorId: string
|
||||
evaluator?: HrEmployee
|
||||
evaluator?: EmployeeDto
|
||||
evaluationPeriod: string
|
||||
evaluationType: EvaluationTypeEnum
|
||||
overallRating: number
|
||||
|
|
@ -202,7 +119,7 @@ export interface HrTrainingParticipant {
|
|||
id: string
|
||||
trainingId: string
|
||||
employeeId: string
|
||||
employee?: HrEmployee
|
||||
employee?: EmployeeDto
|
||||
enrollmentDate: Date
|
||||
completionDate?: Date
|
||||
status: ParticipationStatusEnum
|
||||
|
|
@ -236,7 +153,7 @@ export interface HrDisciplinaryAction {
|
|||
// İnsan Kaynakları Disiplin Cezası
|
||||
id: string
|
||||
employeeId: string
|
||||
employee?: HrEmployee
|
||||
employee?: EmployeeDto
|
||||
actionType: DisciplinaryActionTypeEnum
|
||||
reason: string
|
||||
description: string
|
||||
|
|
@ -272,7 +189,7 @@ export interface HrOvertime {
|
|||
// İnsan Kaynakları Fazla Mesai
|
||||
id: string
|
||||
employeeId: string
|
||||
employee?: HrEmployee
|
||||
employee?: EmployeeDto
|
||||
date: Date
|
||||
startTime: string
|
||||
endTime: string
|
||||
|
|
@ -280,7 +197,7 @@ export interface HrOvertime {
|
|||
reason: string
|
||||
status: LeaveStatusEnum
|
||||
approvedBy?: string
|
||||
approver?: HrEmployee
|
||||
approver?: EmployeeDto
|
||||
rate?: number
|
||||
amount?: number
|
||||
creationTime: Date
|
||||
|
|
@ -291,7 +208,7 @@ export interface HrPayroll {
|
|||
// İnsan Kaynakları Maaş Bordrosu
|
||||
id: string
|
||||
employeeId: string
|
||||
employee?: HrEmployee
|
||||
employee?: EmployeeDto
|
||||
period: string
|
||||
baseSalary: number
|
||||
allowances: HrPayrollAllowance[] // İnsan Kaynakları Maaş Ek Ödemeleri
|
||||
|
|
@ -346,7 +263,7 @@ export interface HrOrganizationChart {
|
|||
// İnsan Kaynakları Organizasyon Şeması
|
||||
id: string
|
||||
employeeId: string
|
||||
employee?: HrEmployee
|
||||
employee?: EmployeeDto
|
||||
parentId?: string
|
||||
parent?: HrOrganizationChart
|
||||
children?: HrOrganizationChart[]
|
||||
|
|
@ -359,7 +276,7 @@ export interface HrEmployeeBadge {
|
|||
// İnsan Kaynakları Çalışan Rozeti
|
||||
id: string
|
||||
employeeId: string
|
||||
employee?: HrEmployee
|
||||
employee?: EmployeeDto
|
||||
badgeId: string
|
||||
badge?: HrBadge
|
||||
earnedDate: Date
|
||||
|
|
@ -454,9 +371,9 @@ export interface HrEvaluation360Participant {
|
|||
id: string
|
||||
campaignId: string
|
||||
evaluatedEmployeeId: string // Değerlendirilen kişi
|
||||
evaluatedEmployee?: HrEmployee
|
||||
evaluatedEmployee?: EmployeeDto
|
||||
evaluatorId: string // Değerlendiren kişi
|
||||
evaluator?: HrEmployee
|
||||
evaluator?: EmployeeDto
|
||||
evaluatorType: AssessorTypeEnum
|
||||
status: ParticipantStatusEnum
|
||||
invitedDate: Date
|
||||
|
|
@ -484,7 +401,7 @@ export interface HrEvaluation360Result {
|
|||
id: string
|
||||
campaignId: string
|
||||
employeeId: string
|
||||
employee?: HrEmployee
|
||||
employee?: EmployeeDto
|
||||
participants: HrEvaluation360Participant[] // Bu sonuca katkıda bulunan değerlendiriciler
|
||||
overallScore: number
|
||||
maxPossibleScore: number
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { HrEmployee } from './hr'
|
||||
import { EmployeeDto } from "@/proxy/intranet/models"
|
||||
|
||||
// Duyuru
|
||||
export interface Announcement {
|
||||
|
|
@ -7,7 +7,7 @@ export interface Announcement {
|
|||
content: string
|
||||
excerpt: string
|
||||
category: 'general' | 'hr' | 'it' | 'event' | 'urgent'
|
||||
author: HrEmployee
|
||||
author: EmployeeDto
|
||||
publishDate: Date
|
||||
expiryDate?: Date
|
||||
isPinned: boolean
|
||||
|
|
@ -17,32 +17,14 @@ export interface Announcement {
|
|||
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
|
||||
export interface Task {
|
||||
id: string
|
||||
title: string
|
||||
description: string
|
||||
project: string
|
||||
assignedTo: HrEmployee[]
|
||||
assignedBy: HrEmployee
|
||||
assignedTo: EmployeeDto[]
|
||||
assignedBy: EmployeeDto
|
||||
priority: 'low' | 'medium' | 'high' | 'urgent'
|
||||
status: 'todo' | 'in-progress' | 'review' | 'done'
|
||||
dueDate: Date
|
||||
|
|
@ -52,45 +34,10 @@ export interface Task {
|
|||
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
|
||||
export interface Certificate {
|
||||
id: string
|
||||
employee: HrEmployee
|
||||
employee: EmployeeDto
|
||||
trainingTitle: string
|
||||
issueDate: Date
|
||||
expiryDate?: Date
|
||||
|
|
@ -98,20 +45,6 @@ export interface Certificate {
|
|||
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ü
|
||||
export interface MealMenu {
|
||||
id: string
|
||||
|
|
@ -141,7 +74,7 @@ export interface Survey {
|
|||
id: string
|
||||
title: string
|
||||
description: string
|
||||
creatorId: HrEmployee
|
||||
creatorId: EmployeeDto
|
||||
creationTime: Date
|
||||
deadline: Date
|
||||
questions: SurveyQuestion[]
|
||||
|
|
@ -190,33 +123,16 @@ export interface SurveyAnswer {
|
|||
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
|
||||
export interface SocialPost {
|
||||
id: string
|
||||
creator: HrEmployee
|
||||
creator: EmployeeDto
|
||||
content: string
|
||||
locationJson?: string
|
||||
media?: SocialMedia
|
||||
likeCount: number
|
||||
isLiked: boolean
|
||||
likeUsers: HrEmployee[]
|
||||
likeUsers: EmployeeDto[]
|
||||
comments: SocialComment[]
|
||||
isOwnPost: boolean
|
||||
creationTime: Date
|
||||
|
|
@ -247,7 +163,7 @@ export interface SocialPollOption {
|
|||
// Sosyal Duvar - Comment Interface
|
||||
export interface SocialComment {
|
||||
id: string
|
||||
creator: HrEmployee
|
||||
creator: EmployeeDto
|
||||
content: string
|
||||
creationTime: Date
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { Address, BusinessParty, PaymentTerms, PriorityEnum } from './common'
|
||||
import { HrDepartment } from './hr'
|
||||
import { DepartmentDto } from './hr'
|
||||
import { WmWarehouse, WmZone, WmLocation } from './wm'
|
||||
|
||||
export interface MmMaterial {
|
||||
|
|
@ -460,7 +460,7 @@ export interface MmApprovalWorkflow {
|
|||
id: string
|
||||
name: string
|
||||
departmentId: string
|
||||
department?: HrDepartment
|
||||
department?: DepartmentDto
|
||||
requestType: RequestTypeEnum
|
||||
amountThreshold: number
|
||||
approvalLevels: MmApprovalWorkflowLevel[]
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { PriorityEnum } from './common'
|
||||
import { HrDepartment } from './hr'
|
||||
import { DepartmentDto } from './hr'
|
||||
import { MmMaterial } from './mm'
|
||||
|
||||
export type CalendarView = 'month' | 'week' | 'day'
|
||||
|
|
@ -19,7 +19,7 @@ export interface PmWorkCenter {
|
|||
warrantyExpiry?: Date
|
||||
location: string
|
||||
departmentId: string
|
||||
department?: HrDepartment
|
||||
department?: DepartmentDto
|
||||
status: WorkCenterStatusEnum
|
||||
criticality: CriticalityLevelEnum
|
||||
specifications: PmWorkCenterSpecification[]
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { BusinessParty, PriorityEnum } from './common'
|
||||
import { HrEmployee } from './hr'
|
||||
import { EmployeeDto } from './hr'
|
||||
|
||||
export interface PsProject {
|
||||
// Proje
|
||||
|
|
@ -13,7 +13,7 @@ export interface PsProject {
|
|||
customerId?: string
|
||||
customer?: BusinessParty
|
||||
projectManagerId: string
|
||||
projectManager?: HrEmployee
|
||||
projectManager?: EmployeeDto
|
||||
startDate: Date
|
||||
endDate: Date
|
||||
actualStartDate?: Date
|
||||
|
|
@ -71,7 +71,7 @@ export interface PsProjectTask {
|
|||
status: TaskStatusEnum
|
||||
priority: PriorityEnum
|
||||
assignedTo?: string
|
||||
assignee?: HrEmployee
|
||||
assignee?: EmployeeDto
|
||||
startDate: Date
|
||||
endDate: Date
|
||||
actualStartDate?: Date
|
||||
|
|
@ -183,7 +183,7 @@ export interface PsTaskDailyUpdate {
|
|||
taskId: string
|
||||
task?: PsProjectTask
|
||||
employeeId: string
|
||||
employee?: HrEmployee
|
||||
employee?: EmployeeDto
|
||||
date: Date
|
||||
hoursWorked: number
|
||||
description: string
|
||||
|
|
@ -205,7 +205,7 @@ export interface PsGanttTask {
|
|||
startDate: Date
|
||||
endDate: Date
|
||||
progress: number
|
||||
assignee?: HrEmployee
|
||||
assignee?: EmployeeDto
|
||||
parentId?: string
|
||||
children?: PsGanttTask[]
|
||||
dependencies?: string[]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React, { useState, useEffect } from "react";
|
||||
import { FaSave, FaTimes } from "react-icons/fa";
|
||||
import { HrDepartment } from "../../../types/hr";
|
||||
import { DepartmentDto } from "../../../types/hr";
|
||||
import { mockEmployees } from "../../../mocks/mockEmployees";
|
||||
import { mockDepartments } from "../../../mocks/mockDepartments";
|
||||
import { mockCostCenters } from "../../../mocks/mockCostCenters";
|
||||
|
|
@ -8,8 +8,8 @@ import { mockCostCenters } from "../../../mocks/mockCostCenters";
|
|||
interface DepartmentFormModalProps {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
onSave: (department: Partial<HrDepartment>) => void;
|
||||
department?: HrDepartment;
|
||||
onSave: (department: Partial<DepartmentDto>) => void;
|
||||
department?: DepartmentDto;
|
||||
title: string;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import {
|
|||
FaList,
|
||||
FaTh,
|
||||
} from 'react-icons/fa'
|
||||
import { HrDepartment } from '../../../types/hr'
|
||||
import { DepartmentDto } from '../../../types/hr'
|
||||
import DataTable, { Column } from '../../../components/common/DataTable'
|
||||
import { mockDepartments } from '../../../mocks/mockDepartments'
|
||||
import { mockEmployees } from '../../../mocks/mockEmployees'
|
||||
|
|
@ -21,7 +21,7 @@ import Widget from '../../../components/common/Widget'
|
|||
import { Container } from '@/components/shared'
|
||||
|
||||
const DepartmentManagement: React.FC = () => {
|
||||
const [departments, setDepartments] = useState<HrDepartment[]>(mockDepartments)
|
||||
const [departments, setDepartments] = useState<DepartmentDto[]>(mockDepartments)
|
||||
const [searchTerm, setSearchTerm] = useState('')
|
||||
const [selectedParent, setSelectedParent] = useState<string>('all')
|
||||
const [viewMode, setViewMode] = useState<'list' | 'cards'>('list')
|
||||
|
|
@ -29,7 +29,7 @@ const DepartmentManagement: React.FC = () => {
|
|||
// Modal states
|
||||
const [isFormModalOpen, setIsFormModalOpen] = useState(false)
|
||||
const [isViewModalOpen, setIsViewModalOpen] = useState(false)
|
||||
const [selectedDepartment, setSelectedDepartment] = useState<HrDepartment | undefined>()
|
||||
const [selectedDepartment, setSelectedDepartment] = useState<DepartmentDto | undefined>()
|
||||
const [modalTitle, setModalTitle] = useState('')
|
||||
|
||||
const handleAdd = () => {
|
||||
|
|
@ -38,13 +38,13 @@ const DepartmentManagement: React.FC = () => {
|
|||
setIsFormModalOpen(true)
|
||||
}
|
||||
|
||||
const handleEdit = (department: HrDepartment) => {
|
||||
const handleEdit = (department: DepartmentDto) => {
|
||||
setSelectedDepartment(department)
|
||||
setModalTitle('Departman Düzenle')
|
||||
setIsFormModalOpen(true)
|
||||
}
|
||||
|
||||
const handleView = (department: HrDepartment) => {
|
||||
const handleView = (department: DepartmentDto) => {
|
||||
setSelectedDepartment(department)
|
||||
setIsViewModalOpen(true)
|
||||
}
|
||||
|
|
@ -55,7 +55,7 @@ const DepartmentManagement: React.FC = () => {
|
|||
}
|
||||
}
|
||||
|
||||
const handleSave = (departmentData: Partial<HrDepartment>) => {
|
||||
const handleSave = (departmentData: Partial<DepartmentDto>) => {
|
||||
if (selectedDepartment) {
|
||||
// Edit existing department
|
||||
setDepartments((prev) =>
|
||||
|
|
@ -67,13 +67,13 @@ const DepartmentManagement: React.FC = () => {
|
|||
)
|
||||
} else {
|
||||
// Add new department
|
||||
const newDepartment: HrDepartment = {
|
||||
const newDepartment: DepartmentDto = {
|
||||
id: `dept_${Date.now()}`,
|
||||
...departmentData,
|
||||
subDepartments: [],
|
||||
creationTime: new Date(),
|
||||
lastModificationTime: new Date(),
|
||||
} as HrDepartment
|
||||
} as DepartmentDto
|
||||
setDepartments((prev) => [...prev, newDepartment])
|
||||
}
|
||||
setIsFormModalOpen(false)
|
||||
|
|
@ -89,7 +89,7 @@ const DepartmentManagement: React.FC = () => {
|
|||
setSelectedDepartment(undefined)
|
||||
}
|
||||
|
||||
const handleEditFromView = (department: HrDepartment) => {
|
||||
const handleEditFromView = (department: DepartmentDto) => {
|
||||
setIsViewModalOpen(false)
|
||||
handleEdit(department)
|
||||
}
|
||||
|
|
@ -117,7 +117,7 @@ const DepartmentManagement: React.FC = () => {
|
|||
return true
|
||||
})
|
||||
|
||||
const columns: Column<HrDepartment>[] = [
|
||||
const columns: Column<DepartmentDto>[] = [
|
||||
{
|
||||
key: 'code',
|
||||
header: 'Departman Kodu',
|
||||
|
|
@ -131,17 +131,17 @@ const DepartmentManagement: React.FC = () => {
|
|||
{
|
||||
key: 'parentDepartment',
|
||||
header: 'Üst Departman',
|
||||
render: (department: HrDepartment) => department.parentDepartment?.name || '-',
|
||||
render: (department: DepartmentDto) => department.parentDepartment?.name || '-',
|
||||
},
|
||||
{
|
||||
key: 'manager',
|
||||
header: 'Yönetici',
|
||||
render: (department: HrDepartment) => department.manager?.fullName || '-',
|
||||
render: (department: DepartmentDto) => department.manager?.fullName || '-',
|
||||
},
|
||||
{
|
||||
key: 'employeeCount',
|
||||
header: 'Personel Sayısı',
|
||||
render: (department: HrDepartment) => (
|
||||
render: (department: DepartmentDto) => (
|
||||
<div className="flex items-center gap-1">
|
||||
<FaUsers className="w-4 h-4 text-gray-500" />
|
||||
<span>{mockEmployees.filter((a) => a.departmentId == department.id).length || 0}</span>
|
||||
|
|
@ -151,7 +151,7 @@ const DepartmentManagement: React.FC = () => {
|
|||
{
|
||||
key: 'costCenter',
|
||||
header: 'Maliyet Merkezi',
|
||||
render: (department: HrDepartment) => (
|
||||
render: (department: DepartmentDto) => (
|
||||
<div className="flex flex-col">
|
||||
<span className="font-medium">{department.costCenter?.code || '-'}</span>
|
||||
<span className="text-xs text-gray-500">{department.costCenter?.name || '-'}</span>
|
||||
|
|
@ -161,7 +161,7 @@ const DepartmentManagement: React.FC = () => {
|
|||
{
|
||||
key: 'budget',
|
||||
header: 'Bütçe',
|
||||
render: (department: HrDepartment) => (
|
||||
render: (department: DepartmentDto) => (
|
||||
<div className="flex items-center gap-1">
|
||||
<FaDollarSign className="w-4 h-4 text-gray-500" />
|
||||
<span>{department.budget ? `₺${department.budget.toLocaleString()}` : '-'}</span>
|
||||
|
|
@ -171,7 +171,7 @@ const DepartmentManagement: React.FC = () => {
|
|||
{
|
||||
key: 'status',
|
||||
header: 'Durum',
|
||||
render: (department: HrDepartment) => (
|
||||
render: (department: DepartmentDto) => (
|
||||
<span
|
||||
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'
|
||||
|
|
@ -184,7 +184,7 @@ const DepartmentManagement: React.FC = () => {
|
|||
{
|
||||
key: 'actions',
|
||||
header: 'İşlemler',
|
||||
render: (department: HrDepartment) => (
|
||||
render: (department: DepartmentDto) => (
|
||||
<div className="flex gap-2">
|
||||
<button
|
||||
onClick={() => handleView(department)}
|
||||
|
|
|
|||
|
|
@ -8,14 +8,14 @@ import {
|
|||
FaCalendar,
|
||||
FaEdit,
|
||||
} from "react-icons/fa";
|
||||
import { HrDepartment } from "../../../types/hr";
|
||||
import { DepartmentDto } from "../../../types/hr";
|
||||
import { mockEmployees } from "../../../mocks/mockEmployees";
|
||||
|
||||
interface DepartmentViewModalProps {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
department: HrDepartment | null;
|
||||
onEdit?: (department: HrDepartment) => void;
|
||||
department: DepartmentDto | null;
|
||||
onEdit?: (department: DepartmentDto) => void;
|
||||
}
|
||||
|
||||
const DepartmentViewModal: React.FC<DepartmentViewModalProps> = ({
|
||||
|
|
|
|||
|
|
@ -10,22 +10,22 @@ import {
|
|||
FaTrash,
|
||||
FaPlus,
|
||||
} from 'react-icons/fa'
|
||||
import { HrEmployee, EmployeeStatusEnum } from '../../../types/hr'
|
||||
import { EmployeeDto, EmployeeStatusEnum } from '../../../types/hr'
|
||||
import { mockEmployees } from '../../../mocks/mockEmployees'
|
||||
import { getEmployeeStatusColor, getEmployeeStatusText } from '../../../utils/erp'
|
||||
import { Container } from '@/components/shared'
|
||||
|
||||
const EmployeeCards: React.FC = () => {
|
||||
const [employees] = useState<HrEmployee[]>(mockEmployees)
|
||||
const [employees] = useState<EmployeeDto[]>(mockEmployees)
|
||||
const [selectedDepartment, setSelectedDepartment] = useState<string>('all')
|
||||
const [selectedStatus, setSelectedStatus] = useState<string>('all')
|
||||
|
||||
const handleEdit = (employee: HrEmployee) => {
|
||||
const handleEdit = (employee: EmployeeDto) => {
|
||||
console.log('Edit employee:', employee)
|
||||
// Implement edit functionality
|
||||
}
|
||||
|
||||
const handleView = (employee: HrEmployee) => {
|
||||
const handleView = (employee: EmployeeDto) => {
|
||||
console.log('View employee:', employee)
|
||||
// Implement view functionality
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,13 +14,13 @@ import LoadingSpinner from '../../../components/common/LoadingSpinner'
|
|||
import { mockDepartments } from '../../../mocks/mockDepartments'
|
||||
import { mockJobPositions } from '../../../mocks/mockJobPositions'
|
||||
import {
|
||||
HrDepartment,
|
||||
HrEmployee,
|
||||
DepartmentDto,
|
||||
EmployeeDto,
|
||||
EmployeeStatusEnum,
|
||||
EmploymentTypeEnum,
|
||||
GenderEnum,
|
||||
JobLevelEnum,
|
||||
HrJobPosition,
|
||||
JobPositionDto,
|
||||
MaritalStatusEnum,
|
||||
} from '../../../types/hr'
|
||||
import { mockEmployees } from '../../../mocks/mockEmployees'
|
||||
|
|
@ -48,11 +48,11 @@ const EmployeeForm: React.FC = () => {
|
|||
const [loading, setLoading] = useState(false)
|
||||
const [saving, setSaving] = useState(false)
|
||||
const [errors, setErrors] = useState<ValidationErrors>({})
|
||||
const [departments, setDepartments] = useState<HrDepartment[]>([])
|
||||
const [jobPositions, setJobPositions] = useState<HrJobPosition[]>([])
|
||||
const [managers, setManagers] = useState<HrEmployee[]>([])
|
||||
const [departments, setDepartments] = useState<DepartmentDto[]>([])
|
||||
const [jobPositions, setJobPositions] = useState<JobPositionDto[]>([])
|
||||
const [managers, setManagers] = useState<EmployeeDto[]>([])
|
||||
|
||||
const [formData, setFormData] = useState<HrEmployee>({
|
||||
const [formData, setFormData] = useState<EmployeeDto>({
|
||||
id: '',
|
||||
code: '',
|
||||
firstName: '',
|
||||
|
|
@ -187,7 +187,7 @@ const EmployeeForm: React.FC = () => {
|
|||
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) => ({
|
||||
...prev,
|
||||
[field]: value,
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import {
|
|||
FaBriefcase,
|
||||
} from 'react-icons/fa'
|
||||
import classNames from 'classnames'
|
||||
import { EmployeeStatusEnum, HrEmployee } from '../../../types/hr'
|
||||
import { EmployeeStatusEnum, EmployeeDto } from '../../../types/hr'
|
||||
import dayjs from 'dayjs'
|
||||
import { mockEmployees } from '../../../mocks/mockEmployees'
|
||||
import EmployeeView from './EmployeeView'
|
||||
|
|
@ -45,7 +45,7 @@ const EmployeeList: React.FC = () => {
|
|||
|
||||
// Modal states
|
||||
const [isViewModalOpen, setIsViewModalOpen] = useState(false)
|
||||
const [selectedEmployee, setSelectedEmployee] = useState<HrEmployee | null>(null)
|
||||
const [selectedEmployee, setSelectedEmployee] = useState<EmployeeDto | null>(null)
|
||||
|
||||
const {
|
||||
data: employees,
|
||||
|
|
@ -69,7 +69,7 @@ const EmployeeList: React.FC = () => {
|
|||
})
|
||||
|
||||
// Modal handlers
|
||||
const handleViewEmployee = (employee: HrEmployee) => {
|
||||
const handleViewEmployee = (employee: EmployeeDto) => {
|
||||
setSelectedEmployee(employee)
|
||||
setIsViewModalOpen(true)
|
||||
}
|
||||
|
|
@ -79,7 +79,7 @@ const EmployeeList: React.FC = () => {
|
|||
setSelectedEmployee(null)
|
||||
}
|
||||
|
||||
const handleEditFromView = (employee: HrEmployee) => {
|
||||
const handleEditFromView = (employee: EmployeeDto) => {
|
||||
setIsViewModalOpen(false)
|
||||
// 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)
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ import {
|
|||
FaAward,
|
||||
FaHistory,
|
||||
} from "react-icons/fa";
|
||||
import { HrEmployee } from "../../../types/hr";
|
||||
import { EmployeeDto } from "../../../types/hr";
|
||||
import {
|
||||
getEmployeeStatusColor,
|
||||
getEmployeeStatusIcon,
|
||||
|
|
@ -29,8 +29,8 @@ import {
|
|||
interface EmployeeViewModalProps {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
employee: HrEmployee | null;
|
||||
onEdit?: (employee: HrEmployee) => void;
|
||||
employee: EmployeeDto | null;
|
||||
onEdit?: (employee: EmployeeDto) => void;
|
||||
}
|
||||
|
||||
const EmployeeViewModal: React.FC<EmployeeViewModalProps> = ({
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React, { useState, useEffect } from 'react'
|
||||
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 { getJobLevelText } from '@/utils/erp'
|
||||
import { mockCurrencies } from '@/mocks/mockCurrencies'
|
||||
|
|
@ -8,8 +8,8 @@ import { mockCurrencies } from '@/mocks/mockCurrencies'
|
|||
interface JobPositionFormModalProps {
|
||||
isOpen: boolean
|
||||
onClose: () => void
|
||||
onSave: (position: Partial<HrJobPosition>) => void
|
||||
position?: HrJobPosition
|
||||
onSave: (position: Partial<JobPositionDto>) => void
|
||||
position?: JobPositionDto
|
||||
title: string
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,13 +7,13 @@ import {
|
|||
FaDollarSign,
|
||||
FaClock,
|
||||
} from "react-icons/fa";
|
||||
import { HrJobPosition } from "../../../types/hr";
|
||||
import { JobPositionDto } from "../../../types/hr";
|
||||
import { getJobLevelColor, getJobLevelText } from "../../../utils/erp";
|
||||
|
||||
interface JobPositionViewModalProps {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
position: HrJobPosition | null | undefined;
|
||||
position: JobPositionDto | null | undefined;
|
||||
}
|
||||
|
||||
const JobPositionViewModal: React.FC<JobPositionViewModalProps> = ({
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import {
|
|||
FaTh,
|
||||
FaList,
|
||||
} from 'react-icons/fa'
|
||||
import { HrJobPosition, JobLevelEnum } from '../../../types/hr'
|
||||
import { JobPositionDto, JobLevelEnum } from '../../../types/hr'
|
||||
import DataTable, { Column } from '../../../components/common/DataTable'
|
||||
import { mockJobPositions } from '../../../mocks/mockJobPositions'
|
||||
import JobPositionFormModal from './JobPositionFormModal'
|
||||
|
|
@ -20,7 +20,7 @@ import { getJobLevelColor, getJobLevelText } from '../../../utils/erp'
|
|||
import { Container } from '@/components/shared'
|
||||
|
||||
const JobPositions: React.FC = () => {
|
||||
const [positions, setPositions] = useState<HrJobPosition[]>(mockJobPositions)
|
||||
const [positions, setPositions] = useState<JobPositionDto[]>(mockJobPositions)
|
||||
const [searchTerm, setSearchTerm] = useState('')
|
||||
const [selectedLevel, setSelectedLevel] = useState<string>('all')
|
||||
const [selectedDepartment, setSelectedDepartment] = useState<string>('all')
|
||||
|
|
@ -29,7 +29,7 @@ const JobPositions: React.FC = () => {
|
|||
// Modal states
|
||||
const [isFormModalOpen, setIsFormModalOpen] = 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 handleAdd = () => {
|
||||
|
|
@ -38,13 +38,13 @@ const JobPositions: React.FC = () => {
|
|||
setIsFormModalOpen(true)
|
||||
}
|
||||
|
||||
const handleEdit = (position: HrJobPosition) => {
|
||||
const handleEdit = (position: JobPositionDto) => {
|
||||
setSelectedPosition(position)
|
||||
setModalTitle('İş Pozisyonu Düzenle')
|
||||
setIsFormModalOpen(true)
|
||||
}
|
||||
|
||||
const handleView = (position: HrJobPosition) => {
|
||||
const handleView = (position: JobPositionDto) => {
|
||||
setSelectedPosition(position)
|
||||
setIsViewModalOpen(true)
|
||||
}
|
||||
|
|
@ -55,7 +55,7 @@ const JobPositions: React.FC = () => {
|
|||
}
|
||||
}
|
||||
|
||||
const handleSavePosition = (positionData: Partial<HrJobPosition>) => {
|
||||
const handleSavePosition = (positionData: Partial<JobPositionDto>) => {
|
||||
if (selectedPosition) {
|
||||
// Edit existing position
|
||||
const updatedPosition = {
|
||||
|
|
@ -66,13 +66,13 @@ const JobPositions: React.FC = () => {
|
|||
setPositions(positions.map((p) => (p.id === selectedPosition.id ? updatedPosition : p)))
|
||||
} else {
|
||||
// Add new position
|
||||
const newPosition: HrJobPosition = {
|
||||
const newPosition: JobPositionDto = {
|
||||
id: `jp-${Date.now()}`,
|
||||
...positionData,
|
||||
employees: [],
|
||||
creationTime: new Date(),
|
||||
lastModificationTime: new Date(),
|
||||
} as HrJobPosition
|
||||
} as JobPositionDto
|
||||
setPositions([...positions, newPosition])
|
||||
}
|
||||
}
|
||||
|
|
@ -106,7 +106,7 @@ const JobPositions: React.FC = () => {
|
|||
})
|
||||
|
||||
// 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="flex items-start justify-between mb-4">
|
||||
<div className="flex-1">
|
||||
|
|
@ -201,7 +201,7 @@ const JobPositions: React.FC = () => {
|
|||
</div>
|
||||
)
|
||||
|
||||
const columns: Column<HrJobPosition>[] = [
|
||||
const columns: Column<JobPositionDto>[] = [
|
||||
{
|
||||
key: 'code',
|
||||
header: 'Pozisyon Kodu',
|
||||
|
|
@ -211,7 +211,7 @@ const JobPositions: React.FC = () => {
|
|||
key: 'title',
|
||||
header: 'Pozisyon Adı',
|
||||
sortable: true,
|
||||
render: (position: HrJobPosition) => (
|
||||
render: (position: JobPositionDto) => (
|
||||
<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>
|
||||
|
|
@ -221,7 +221,7 @@ const JobPositions: React.FC = () => {
|
|||
{
|
||||
key: 'department',
|
||||
header: 'Departman',
|
||||
render: (position: HrJobPosition) => (
|
||||
render: (position: JobPositionDto) => (
|
||||
<div className="flex items-center gap-2">
|
||||
<FaBuilding className="w-4 h-4 text-gray-500" />
|
||||
<span>{position.department?.name || '-'}</span>
|
||||
|
|
@ -231,7 +231,7 @@ const JobPositions: React.FC = () => {
|
|||
{
|
||||
key: 'level',
|
||||
header: 'Seviye',
|
||||
render: (position: HrJobPosition) => (
|
||||
render: (position: JobPositionDto) => (
|
||||
<span
|
||||
className={`px-2 py-1 text-xs font-medium rounded-full ${getJobLevelColor(
|
||||
position.level,
|
||||
|
|
@ -244,7 +244,7 @@ const JobPositions: React.FC = () => {
|
|||
{
|
||||
key: 'employeeCount',
|
||||
header: 'Personel Sayısı',
|
||||
render: (position: HrJobPosition) => (
|
||||
render: (position: JobPositionDto) => (
|
||||
<div className="flex items-center gap-1">
|
||||
<FaUsers className="w-4 h-4 text-gray-500" />
|
||||
<span>{position.employees?.length || 0}</span>
|
||||
|
|
@ -254,7 +254,7 @@ const JobPositions: React.FC = () => {
|
|||
{
|
||||
key: 'salary',
|
||||
header: 'Maaş Aralığı',
|
||||
render: (position: HrJobPosition) => (
|
||||
render: (position: JobPositionDto) => (
|
||||
<div className="flex items-center gap-1">
|
||||
<FaDollarSign className="w-4 h-4 text-gray-500" />
|
||||
<div className="text-sm">
|
||||
|
|
@ -267,7 +267,7 @@ const JobPositions: React.FC = () => {
|
|||
{
|
||||
key: 'skills',
|
||||
header: 'Gerekli Yetenekler',
|
||||
render: (position: HrJobPosition) => (
|
||||
render: (position: JobPositionDto) => (
|
||||
<div className="flex flex-wrap gap-1 max-w-xs">
|
||||
{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">
|
||||
|
|
@ -285,7 +285,7 @@ const JobPositions: React.FC = () => {
|
|||
{
|
||||
key: 'status',
|
||||
header: 'Durum',
|
||||
render: (position: HrJobPosition) => (
|
||||
render: (position: JobPositionDto) => (
|
||||
<span
|
||||
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'
|
||||
|
|
@ -298,7 +298,7 @@ const JobPositions: React.FC = () => {
|
|||
{
|
||||
key: 'actions',
|
||||
header: 'İşlemler',
|
||||
render: (position: HrJobPosition) => (
|
||||
render: (position: JobPositionDto) => (
|
||||
<div className="flex gap-2">
|
||||
<button
|
||||
onClick={() => handleView(position)}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import {
|
|||
FaMapMarkerAlt,
|
||||
FaBriefcase,
|
||||
} 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 { mockDepartments } from '../../../mocks/mockDepartments'
|
||||
import Widget from '../../../components/common/Widget'
|
||||
|
|
@ -76,22 +76,22 @@ const generateOrganizationData = (): OrgChart[] => {
|
|||
}
|
||||
|
||||
interface TreeNode {
|
||||
employee: HrEmployee
|
||||
employee: EmployeeDto
|
||||
children: TreeNode[]
|
||||
level: number
|
||||
}
|
||||
|
||||
const OrganizationChart: React.FC = () => {
|
||||
const [employees] = useState<HrEmployee[]>(mockEmployees)
|
||||
const [employees] = useState<EmployeeDto[]>(mockEmployees)
|
||||
const [organizationData] = useState<OrgChart[]>(generateOrganizationData())
|
||||
const [expandedNodes, setExpandedNodes] = useState<Set<string>>(new Set())
|
||||
const [orgTree, setOrgTree] = useState<TreeNode[]>([])
|
||||
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 [selectedDepartment, setSelectedDepartment] = useState<string>('all')
|
||||
|
||||
const handleViewEmployee = (employee: HrEmployee) => {
|
||||
const handleViewEmployee = (employee: EmployeeDto) => {
|
||||
setSelectedEmployee(employee)
|
||||
setShowModal(true)
|
||||
}
|
||||
|
|
@ -278,7 +278,7 @@ const OrganizationChart: React.FC = () => {
|
|||
acc[level].push(employee)
|
||||
return acc
|
||||
},
|
||||
{} as Record<number, HrEmployee[]>,
|
||||
{} as Record<number, EmployeeDto[]>,
|
||||
)
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ import { Announcement, Survey, SurveyAnswer } from '@/types/intranet'
|
|||
import { Container } from '@/components/shared'
|
||||
import { usePermission } from '@/utils/hooks/usePermission'
|
||||
import { IntranetDashboardDto } from '@/proxy/intranet/models'
|
||||
import { intranetService, IntranetService } from '@/services/intranet.service'
|
||||
import { intranetService } from '@/services/intranet.service'
|
||||
|
||||
dayjs.locale('tr')
|
||||
dayjs.extend(relativeTime)
|
||||
|
|
@ -247,19 +247,36 @@ const IntranetDashboard: React.FC = () => {
|
|||
case 'upcoming-events':
|
||||
return <UpcomingEvents events={intranetDashboard?.events || []} />
|
||||
case 'today-birthdays':
|
||||
return <TodayBirthdays />
|
||||
case 'recent-documents':
|
||||
return <RecentDocuments />
|
||||
case 'upcoming-trainings':
|
||||
return <UpcomingTrainings />
|
||||
return <TodayBirthdays employees={intranetDashboard?.birthdays || []} />
|
||||
case 'visitors':
|
||||
return <Visitors visitors={intranetDashboard?.visitors || []} />
|
||||
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':
|
||||
return <ActiveSurveys onTakeSurvey={handleTakeSurvey} />
|
||||
case 'visitors':
|
||||
return <Visitors />
|
||||
case 'expense-management':
|
||||
return <ExpenseManagement onNewExpense={() => setShowExpenseModal(true)} />
|
||||
case 'social-wall':
|
||||
return <SocialWall />
|
||||
case 'important-announcements':
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import PostItem from './PostItem'
|
|||
import { SocialMedia } from '@/types/intranet'
|
||||
import CreatePost from './CreatePost'
|
||||
import { SocialPost } from '@/types/intranet'
|
||||
import { HrEmployee } from '@/types/hr'
|
||||
import { EmployeeDto } from '@/types/hr'
|
||||
import { mockSocialPosts } from '@/mocks/mockIntranet'
|
||||
import { mockEmployees } from '@/mocks/mockEmployees'
|
||||
|
||||
|
|
@ -13,7 +13,7 @@ const SocialWall: React.FC = () => {
|
|||
const [filter, setFilter] = useState<'all' | 'mine'>('all')
|
||||
|
||||
// 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: {
|
||||
content: string
|
||||
|
|
|
|||
|
|
@ -1,13 +1,17 @@
|
|||
import React from 'react'
|
||||
import { FaKey, FaPlus } from 'react-icons/fa'
|
||||
import dayjs from 'dayjs'
|
||||
import { mockReservations } from '../../../mocks/mockIntranet'
|
||||
import { ReservationDto } from '@/proxy/intranet/models'
|
||||
|
||||
interface ActiveReservationsProps {
|
||||
reservations: ReservationDto[]
|
||||
onNewReservation: () => void
|
||||
}
|
||||
|
||||
const ActiveReservations: React.FC<ActiveReservationsProps> = ({ onNewReservation }) => {
|
||||
const ActiveReservations: React.FC<ActiveReservationsProps> = ({
|
||||
reservations,
|
||||
onNewReservation,
|
||||
}) => {
|
||||
return (
|
||||
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
|
||||
<div className="p-4 border-b border-gray-200 dark:border-gray-700">
|
||||
|
|
@ -17,7 +21,7 @@ const ActiveReservations: React.FC<ActiveReservationsProps> = ({ onNewReservatio
|
|||
</h2>
|
||||
</div>
|
||||
<div className="p-4 space-y-3">
|
||||
{mockReservations
|
||||
{reservations
|
||||
.filter((r) => r.status === 'approved')
|
||||
.slice(0, 3)
|
||||
.map((reservation) => (
|
||||
|
|
@ -30,15 +34,20 @@ const ActiveReservations: React.FC<ActiveReservationsProps> = ({ onNewReservatio
|
|||
{reservation.resourceName}
|
||||
</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">
|
||||
{reservation.type === 'room' ? '🏢' : reservation.type === 'vehicle' ? '🚗' : '⚙️'}
|
||||
{reservation.type === 'room'
|
||||
? '🏢'
|
||||
: reservation.type === 'vehicle'
|
||||
? '🚗'
|
||||
: '⚙️'}
|
||||
</span>
|
||||
</div>
|
||||
<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>
|
||||
</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">
|
||||
Aktif rezervasyon yok
|
||||
</p>
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
import React from 'react'
|
||||
import { FaDollarSign, FaPlus } from 'react-icons/fa'
|
||||
import { mockExpenseRequests } from '../../../mocks/mockIntranet'
|
||||
import { ExpensesDto } from '@/proxy/intranet/models'
|
||||
|
||||
interface ExpenseManagementProps {
|
||||
expenses: ExpensesDto
|
||||
onNewExpense: () => void
|
||||
}
|
||||
|
||||
const ExpenseManagement: React.FC<ExpenseManagementProps> = ({ onNewExpense }) => {
|
||||
const ExpenseManagement: React.FC<ExpenseManagementProps> = ({ expenses, onNewExpense }) => {
|
||||
return (
|
||||
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
|
||||
<div className="p-4 border-b border-gray-200 dark:border-gray-700">
|
||||
|
|
@ -19,13 +20,17 @@ const ExpenseManagement: React.FC<ExpenseManagementProps> = ({ onNewExpense }) =
|
|||
{/* 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">
|
||||
<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-xs text-gray-500 dark:text-gray-400 mt-1">₺2,050 onaylandı</p>
|
||||
<p className="text-2xl font-bold text-emerald-600 dark:text-emerald-400">
|
||||
{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>
|
||||
|
||||
{/* Son harcama talepleri */}
|
||||
<div className="space-y-2">
|
||||
{mockExpenseRequests.slice(0, 3).map((expense) => (
|
||||
{expenses.last5Expenses.slice(0, 3).map((expense) => (
|
||||
<div
|
||||
key={expense.id}
|
||||
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-1">
|
||||
<h4 className="text-sm font-medium text-gray-900 dark:text-white">
|
||||
{expense.category === 'travel' ? '✈️' :
|
||||
expense.category === 'meal' ? '🍽️' :
|
||||
expense.category === 'accommodation' ? '🏨' :
|
||||
expense.category === 'transport' ? '🚗' : '📋'} {expense.description}
|
||||
{expense.category === 'travel'
|
||||
? '✈️'
|
||||
: expense.category === 'meal'
|
||||
? '🍽️'
|
||||
: expense.category === 'accommodation'
|
||||
? '🏨'
|
||||
: expense.category === 'transport'
|
||||
? '🚗'
|
||||
: '📋'}{' '}
|
||||
{expense.description}
|
||||
</h4>
|
||||
<p className="text-xs font-semibold text-emerald-600 dark:text-emerald-400 mt-1">
|
||||
₺{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'
|
||||
}`}
|
||||
>
|
||||
{expense.status === 'approved' ? 'Onaylandı' :
|
||||
expense.status === 'pending' ? 'Bekliyor' : 'Reddedildi'}
|
||||
{expense.status === 'approved'
|
||||
? 'Onaylandı'
|
||||
: expense.status === 'pending'
|
||||
? 'Bekliyor'
|
||||
: 'Reddedildi'}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,86 @@
|
|||
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 { 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 (
|
||||
<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">
|
||||
|
|
@ -15,39 +92,41 @@ const RecentDocuments: React.FC = () => {
|
|||
</div>
|
||||
</div>
|
||||
<div className="divide-y divide-gray-200 dark:divide-gray-700">
|
||||
{mockDocuments.slice(0, 3).map((doc) => (
|
||||
{documents.slice(0, 3).map((doc) => (
|
||||
<div
|
||||
key={doc.id}
|
||||
className="p-4 hover:bg-gray-50 dark:hover:bg-gray-700/50 transition-colors"
|
||||
>
|
||||
<div className="flex items-start gap-3">
|
||||
<div className="p-2 bg-blue-100 dark:bg-blue-900/30 rounded-lg">
|
||||
<FaFileAlt className="w-4 h-4 text-blue-600 dark:text-blue-400" />
|
||||
{getFileIcon(doc.extension)}
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<h4 className="text-sm font-medium text-gray-900 dark:text-white truncate">
|
||||
{doc.name}
|
||||
</h4>
|
||||
<p className="text-xs text-gray-600 dark:text-gray-400 mt-1">
|
||||
{doc.category === 'policy' && '📋 Politika'}
|
||||
{doc.category === 'procedure' && '📝 Prosedür'}
|
||||
{doc.category === 'form' && '📄 Form'}
|
||||
{doc.category === 'template' && '📋 Şablon'}
|
||||
{doc.category === 'report' && '📊 Rapor'}
|
||||
{doc.category === 'other' && '📄 Diğer'}
|
||||
{getFileType(doc.extension)}
|
||||
<span className="mx-1">•</span>
|
||||
{doc.size}
|
||||
{formatFileSize(doc.size)}
|
||||
</p>
|
||||
<div className="text-xs text-gray-500 dark:text-gray-400 mt-1 flex items-center gap-2">
|
||||
<span>{dayjs(doc.uploadDate).fromNow()}</span>
|
||||
<span>•</span>
|
||||
<span>{doc.downloadCount} indirme</span>
|
||||
<span>{dayjs(doc.modifiedAt).fromNow()}</span>
|
||||
{doc.isReadOnly && (
|
||||
<>
|
||||
<span>•</span>
|
||||
<span className="text-orange-500">🔒 Salt okunur</span>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
onClick={(e) => {
|
||||
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"
|
||||
title="İndir"
|
||||
|
|
|
|||
|
|
@ -1,14 +1,9 @@
|
|||
import React from 'react'
|
||||
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 todayBirthdays = mockEmployees.filter((b) => {
|
||||
return (
|
||||
dayjs(b.birthDate).month() === today.month() && dayjs(b.birthDate).date() === today.date()
|
||||
)
|
||||
})
|
||||
|
||||
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">
|
||||
|
|
@ -18,30 +13,32 @@ const TodayBirthdays: React.FC = () => {
|
|||
</h2>
|
||||
</div>
|
||||
<div className="p-4 space-y-3">
|
||||
{todayBirthdays.length > 0 ? (
|
||||
todayBirthdays.map((birthday, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="flex items-center gap-3 p-3 bg-white/50 dark:bg-gray-800/50 rounded-lg"
|
||||
>
|
||||
<img
|
||||
src={birthday.avatar}
|
||||
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">
|
||||
{birthday.fullName}
|
||||
</p>
|
||||
<p className="text-xs text-gray-600 dark:text-gray-400">
|
||||
{today.diff(dayjs(birthday.birthDate), 'year')} yaşında 🎉
|
||||
</p>
|
||||
<p className="text-xs text-gray-500 dark:text-gray-500 mt-1">
|
||||
{birthday.department?.name || 'Genel'}
|
||||
</p>
|
||||
{employees.length > 0 ? (
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
|
||||
{employees.map((birthday, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="flex items-center gap-3 p-3 border border-pink-100 dark:border-pink-800 rounded-lg"
|
||||
>
|
||||
<img
|
||||
src={birthday.avatar}
|
||||
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">
|
||||
{birthday.fullName}
|
||||
</p>
|
||||
<p className="text-xs text-gray-600 dark:text-gray-400">
|
||||
{today.diff(dayjs(birthday.birthDate), 'year')} yaşında 🎉
|
||||
</p>
|
||||
<p className="text-xs text-gray-500 dark:text-gray-500 mt-1">
|
||||
{birthday.department?.name || 'Genel'}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<p className="text-sm text-gray-500 dark:text-gray-400 text-center py-4">
|
||||
Bugün doğan yok
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import React from 'react'
|
||||
import { FaGraduationCap } from 'react-icons/fa'
|
||||
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 (
|
||||
<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">
|
||||
|
|
@ -13,7 +13,7 @@ const UpcomingTrainings: React.FC = () => {
|
|||
</h2>
|
||||
</div>
|
||||
<div className="p-4 space-y-3">
|
||||
{mockTrainings
|
||||
{trainings
|
||||
.filter((t) => t.status === 'upcoming')
|
||||
.slice(0, 3)
|
||||
.map((training) => (
|
||||
|
|
@ -29,7 +29,8 @@ const UpcomingTrainings: React.FC = () => {
|
|||
</p>
|
||||
<div className="flex items-center justify-between text-xs">
|
||||
<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 className="text-blue-600 dark:text-blue-400 font-medium">
|
||||
{training.enrolled}/{training.maxParticipants}
|
||||
|
|
@ -37,7 +38,7 @@ const UpcomingTrainings: React.FC = () => {
|
|||
</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">
|
||||
Yaklaşan eğitim yok
|
||||
</p>
|
||||
|
|
|
|||
|
|
@ -1,13 +1,9 @@
|
|||
import React from 'react'
|
||||
import { FaUser, FaUserCheck, FaUserClock } from 'react-icons/fa'
|
||||
import dayjs from 'dayjs'
|
||||
import { mockVisitors } from '../../../mocks/mockIntranet'
|
||||
|
||||
const Visitors: React.FC = () => {
|
||||
const todayVisitors = mockVisitors.filter((visitor) =>
|
||||
dayjs(visitor.visitDate).isSame(dayjs(), 'day')
|
||||
)
|
||||
import { VisitorDto } from '@/proxy/intranet/models'
|
||||
|
||||
const Visitors: React.FC<{ visitors: VisitorDto[] }> = ({ visitors }) => {
|
||||
const getStatusIcon = (status: string) => {
|
||||
switch (status) {
|
||||
case 'checked-in':
|
||||
|
|
@ -56,15 +52,20 @@ const Visitors: React.FC = () => {
|
|||
</h2>
|
||||
</div>
|
||||
<div className="p-4 space-y-3">
|
||||
{todayVisitors.length > 0 ? (
|
||||
todayVisitors.map((visitor) => (
|
||||
{visitors.length > 0 ? (
|
||||
visitors.map((visitor) => (
|
||||
<div
|
||||
key={visitor.id}
|
||||
className={`p-3 rounded-lg border ${getStatusColor(visitor.status)}`}
|
||||
>
|
||||
<div className="flex items-start gap-3">
|
||||
<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}
|
||||
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">
|
||||
{visitor.fullName}
|
||||
</h4>
|
||||
<div className="flex items-center gap-1">
|
||||
{getStatusIcon(visitor.status)}
|
||||
</div>
|
||||
<div className="flex items-center gap-1">{getStatusIcon(visitor.status)}</div>
|
||||
</div>
|
||||
<p className="text-xs text-gray-600 dark:text-gray-400 truncate">
|
||||
{visitor.company}
|
||||
</p>
|
||||
<p className="text-xs text-gray-500 dark:text-gray-500 mt-1">
|
||||
{visitor.purpose}
|
||||
{visitor.companyName}
|
||||
</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">
|
||||
<span className="text-xs text-gray-500 dark:text-gray-500">
|
||||
{dayjs(visitor.visitDate).format('HH:mm')}
|
||||
|
|
@ -91,9 +88,9 @@ const Visitors: React.FC = () => {
|
|||
{getStatusText(visitor.status)}
|
||||
</span>
|
||||
</div>
|
||||
{visitor.host && (
|
||||
{visitor.employee && (
|
||||
<p className="text-xs text-gray-500 dark:text-gray-500 mt-1">
|
||||
Karşılayan: {visitor.host.fullName}
|
||||
Karşılayan: {visitor.employee.fullName}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
|
@ -110,4 +107,4 @@ const Visitors: React.FC = () => {
|
|||
)
|
||||
}
|
||||
|
||||
export default Visitors
|
||||
export default Visitors
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import {
|
|||
} from '../../../types/pm'
|
||||
import { mockWorkCenters } from '../../../mocks/mockWorkCenters'
|
||||
import { mockDepartments } from '../../../mocks/mockDepartments'
|
||||
import { HrDepartment } from '../../../types/hr'
|
||||
import { DepartmentDto } from '../../../types/hr'
|
||||
import { Container } from '@/components/shared'
|
||||
import { ROUTES_ENUM } from '@/routes/route.constant'
|
||||
import { getCriticalityLevelText, getWorkCenterStatusText } from '@/utils/erp'
|
||||
|
|
@ -35,7 +35,7 @@ const WorkCenterForm: React.FC = () => {
|
|||
const [loading, setLoading] = useState(false)
|
||||
const [saving, setSaving] = useState(false)
|
||||
const [errors, setErrors] = useState<ValidationErrors>({})
|
||||
const [departments, setDepartments] = useState<HrDepartment[]>([])
|
||||
const [departments, setDepartments] = useState<DepartmentDto[]>([])
|
||||
|
||||
const [formData, setFormData] = useState<PmWorkCenter>({
|
||||
id: '',
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ import {
|
|||
FaDownload,
|
||||
} from 'react-icons/fa'
|
||||
import LoadingSpinner from '../../../components/common/LoadingSpinner'
|
||||
import { HrEmployee } from '../../../types/hr'
|
||||
import { EmployeeDto } from '../../../types/hr'
|
||||
import { mockEmployees } from '../../../mocks/mockEmployees'
|
||||
import { mockBusinessParties } from '../../../mocks/mockBusinessParties'
|
||||
import {
|
||||
|
|
@ -114,7 +114,7 @@ const ProjectForm: React.FC = () => {
|
|||
const [saving, setSaving] = useState(false)
|
||||
const [errors, setErrors] = useState<ValidationErrors>({})
|
||||
const [customers, setCustomers] = useState<BusinessParty[]>([])
|
||||
const [projectManagers, setProjectManagers] = useState<HrEmployee[]>([])
|
||||
const [projectManagers, setProjectManagers] = useState<EmployeeDto[]>([])
|
||||
const [activeTab, setActiveTab] = useState('overview')
|
||||
|
||||
// Additional states for the new features
|
||||
|
|
|
|||
Loading…
Reference in a new issue