Intranet AppService

This commit is contained in:
Sedat ÖZTÜRK 2025-10-29 13:20:21 +03:00
parent e29a924e87
commit bdf67ec1da
62 changed files with 1397 additions and 798 deletions

View file

@ -7,7 +7,7 @@ public class FileItemDto
{ {
public string Id { get; set; } = string.Empty; public string Id { get; set; } = string.Empty;
public string Name { get; set; } = string.Empty; public string Name { get; set; } = string.Empty;
public string Type { get; set; } = string.Empty; // "file" or "folder" public string Type { get; set; } = string.Empty;
public long? Size { get; set; } public long? Size { get; set; }
public string Extension { get; set; } = string.Empty; public string Extension { get; set; } = string.Empty;
public string MimeType { get; set; } = string.Empty; public string MimeType { get; set; } = string.Empty;
@ -16,7 +16,7 @@ public class FileItemDto
public string Path { get; set; } = string.Empty; public string Path { get; set; } = string.Empty;
public string ParentId { get; set; } = string.Empty; public string ParentId { get; set; } = string.Empty;
public bool IsReadOnly { get; set; } public bool IsReadOnly { get; set; }
public int? ChildCount { get; set; } // Klasörler için öğe sayısı public int? ChildCount { get; set; }
} }
public class GetFilesDto public class GetFilesDto

View file

@ -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; }
}

View file

@ -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; } = [];
}

View file

@ -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; }
}

View file

@ -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; }
}

View file

@ -1,6 +1,6 @@
using System; using System;
namespace Kurs.Platform.Public; namespace Kurs.Platform.Intranet;
public class EventCommentDto public class EventCommentDto
{ {

View file

@ -1,7 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace Kurs.Platform.Public; namespace Kurs.Platform.Intranet;
public class EventDto public class EventDto
{ {

View file

@ -1,6 +1,6 @@
using System; using System;
namespace Kurs.Platform.Public; namespace Kurs.Platform.Intranet;
public class EventOrganizerDto public class EventOrganizerDto
{ {

View file

@ -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; }
}

View file

@ -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; } = [];
}

View file

@ -1,7 +1,7 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.Application.Services; using Volo.Abp.Application.Services;
namespace Kurs.Platform.Public; namespace Kurs.Platform.Intranet;
public interface IIntranetAppService : IApplicationService public interface IIntranetAppService : IApplicationService
{ {

View file

@ -1,8 +1,16 @@
using System.Collections.Generic; using System.Collections.Generic;
using Kurs.Platform.FileManagement;
namespace Kurs.Platform.Public; namespace Kurs.Platform.Intranet;
public class IntranetDashboardDto public class IntranetDashboardDto
{ {
public List<EventDto> Events { get; set; } = []; public List<EventDto> Events { get; set; } = [];
public List<EmployeeDto> Birthdays { get; set; } = [];
public List<VisitorDto> Visitors { get; set; } = [];
public List<ReservationDto> Reservations { get; set; } = [];
public List<TrainingDto> Trainings { get; set; } = [];
public ExpensesDto Expenses { get; set; } = new ExpensesDto();
public List<FileItemDto> Documents { get; set; } = [];
} }

View file

@ -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; }
}

View file

@ -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
}

View file

@ -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ı
}

View file

@ -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; }
}

View file

@ -32,7 +32,8 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
{ {
BlobContainerNames.Avatar, BlobContainerNames.Avatar,
BlobContainerNames.Import, BlobContainerNames.Import,
BlobContainerNames.Activity BlobContainerNames.Activity,
BlobContainerNames.Intranet
}; };
public FileManagementAppService( public FileManagementAppService(
@ -52,11 +53,6 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
return $"files/{tenantId}/"; return $"files/{tenantId}/";
} }
private string GenerateFileId()
{
return Guid.NewGuid().ToString("N");
}
private string EncodePathAsId(string path) private string EncodePathAsId(string path)
{ {
// Path'deki '/' karakterlerini '|' ile değiştir URL-safe hale getirmek için // Path'deki '/' karakterlerini '|' ile değiştir URL-safe hale getirmek için
@ -198,24 +194,6 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
} }
} }
private async Task<List<FileMetadata>> GetCustomFoldersAsync()
{
var indexPath = GetTenantPrefix() + IndexFileName;
try
{
var indexBytes = await _blobContainer.GetAllBytesOrNullAsync(indexPath);
if (indexBytes == null) return new List<FileMetadata>();
var indexJson = Encoding.UTF8.GetString(indexBytes);
return JsonSerializer.Deserialize<List<FileMetadata>>(indexJson) ?? new List<FileMetadata>();
}
catch
{
return new List<FileMetadata>();
}
}
private async Task SaveFolderIndexAsync(List<FileMetadata> items, string? parentId = null) private async Task SaveFolderIndexAsync(List<FileMetadata> items, string? parentId = null)
{ {
var indexPath = GetTenantPrefix() + (string.IsNullOrEmpty(parentId) ? IndexFileName : $"{parentId}/{IndexFileName}"); var indexPath = GetTenantPrefix() + (string.IsNullOrEmpty(parentId) ? IndexFileName : $"{parentId}/{IndexFileName}");
@ -244,13 +222,12 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
{ {
var items = await GetFolderIndexAsync(parentId); var items = await GetFolderIndexAsync(parentId);
var result = items.Select(metadata => { var result = items.Select(metadata =>
{
var isRootLevel = string.IsNullOrEmpty(parentId); var isRootLevel = string.IsNullOrEmpty(parentId);
var isProtected = IsProtectedFolder(metadata.Path); var isProtected = IsProtectedFolder(metadata.Path);
var finalIsReadOnly = metadata.IsReadOnly || (isRootLevel && isProtected); var finalIsReadOnly = metadata.IsReadOnly || (isRootLevel && isProtected);
Logger.LogInformation($"Item: {metadata.Name}, Path: {metadata.Path}, IsRootLevel: {isRootLevel}, IsProtected: {isProtected}, FinalIsReadOnly: {finalIsReadOnly}");
return new FileItemDto return new FileItemDto
{ {
Id = metadata.Id, Id = metadata.Id,
@ -338,10 +315,6 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
public async Task<FileItemDto> UploadFileAsync([FromForm] UploadFileDto input) public async Task<FileItemDto> UploadFileAsync([FromForm] UploadFileDto input)
{ {
// Debug logging
Logger.LogInformation("UploadFileAsync called with: FileName={FileName}, ParentId={ParentId}, FilesCount={FilesCount}",
input.FileName, input.ParentId, input.Files?.Length ?? 0);
ValidateFileName(input.FileName); ValidateFileName(input.FileName);
// Decode parent ID if provided // Decode parent ID if provided
@ -416,7 +389,6 @@ public class FileManagementAppService : ApplicationService, IFileManagementAppSe
}; };
// File system'e kaydedildi, index güncellemeye gerek yok // File system'e kaydedildi, index güncellemeye gerek yok
return new FileItemDto return new FileItemDto
{ {
Id = metadata.Id, Id = metadata.Id,

View file

@ -1,47 +1,216 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Kurs.Platform.BlobStoring;
using Kurs.Platform.Entities; using Kurs.Platform.Entities;
using Kurs.Platform.FileManagement;
using Kurs.Platform.Intranet;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Volo.Abp.Domain.Repositories; using Volo.Abp.Domain.Repositories;
using Volo.Abp.MultiTenancy;
namespace Kurs.Platform.Public; namespace Kurs.Platform.Public;
[Authorize] [Authorize]
public class IntranetAppService : PlatformAppService, IIntranetAppService public class IntranetAppService : PlatformAppService, IIntranetAppService
{ {
private readonly ICurrentTenant _currentTenant;
private readonly BlobManager _blobContainer;
private readonly IConfiguration _configuration;
private readonly IRepository<Event, Guid> _eventRepository; private readonly IRepository<Event, Guid> _eventRepository;
private readonly IRepository<EventCategory, Guid> _eventCategoryRepository;
private readonly IRepository<EventType, Guid> _eventTypeRepository;
private readonly IRepository<EventPhoto, Guid> _eventPhotoRepository;
private readonly IRepository<EventComment, Guid> _eventCommentRepository;
private readonly IRepository<Employee, Guid> _employeeRepository; private readonly IRepository<Employee, Guid> _employeeRepository;
private readonly IRepository<Visitor, Guid> _visitorRepository;
private readonly IRepository<Reservation, Guid> _reservationRepository;
private readonly IRepository<Training, Guid> _trainingRepository;
private readonly IRepository<Expense, Guid> _expenseRepository;
public IntranetAppService( public IntranetAppService(
ICurrentTenant currentTenant,
BlobManager blobContainer,
IConfiguration configuration,
IRepository<Event, Guid> eventRepository, IRepository<Event, Guid> eventRepository,
IRepository<EventCategory, Guid> eventCategoryRepository, IRepository<Employee, Guid> employeeRepository,
IRepository<EventType, Guid> eventTypeRepository, IRepository<Visitor, Guid> visitorRepository,
IRepository<EventPhoto, Guid> eventPhotoRepository, IRepository<Reservation, Guid> reservationRepository,
IRepository<EventComment, Guid> eventCommentRepository, IRepository<Training, Guid> trainingRepository,
IRepository<Employee, Guid> employeeRepository) IRepository<Expense, Guid> expenseRepository
)
{ {
_currentTenant = currentTenant;
_blobContainer = blobContainer;
_configuration = configuration;
_eventRepository = eventRepository; _eventRepository = eventRepository;
_eventCategoryRepository = eventCategoryRepository;
_eventTypeRepository = eventTypeRepository;
_eventPhotoRepository = eventPhotoRepository;
_eventCommentRepository = eventCommentRepository;
_employeeRepository = employeeRepository; _employeeRepository = employeeRepository;
_visitorRepository = visitorRepository;
_reservationRepository = reservationRepository;
_trainingRepository = trainingRepository;
_expenseRepository = expenseRepository;
} }
public async Task<IntranetDashboardDto> GetIntranetDashboardAsync() public async Task<IntranetDashboardDto> GetIntranetDashboardAsync()
{ {
return new IntranetDashboardDto return new IntranetDashboardDto
{ {
Events = await GetUpcomingEventsAsync() Events = await GetUpcomingEventsAsync(),
Birthdays = await GetBirthdaysAsync(),
Visitors = await GetVisitorsAsync(),
Reservations = await GetReservationsAsync(),
Trainings = await GetTrainingsAsync(),
Expenses = await GetExpensesAsync(),
Documents = await GetIntranetDocumentsAsync(BlobContainerNames.Intranet)
}; };
} }
public async Task<List<FileItemDto>> GetIntranetDocumentsAsync(string folderPath)
{
var items = new List<FileItemDto>();
var cdnBasePath = _configuration["App:CdnPath"];
if (string.IsNullOrEmpty(cdnBasePath))
{
Logger.LogWarning("CDN path is not configured");
return items;
}
var tenantId = _currentTenant.Id?.ToString() ?? "host";
var fullPath = Path.Combine(cdnBasePath, tenantId);
if (!string.IsNullOrEmpty(folderPath))
{
fullPath = Path.Combine(fullPath, folderPath);
}
if (!Directory.Exists(fullPath))
{
Logger.LogWarning($"Directory not found: {fullPath}");
return items;
}
var files = Directory.GetFiles(fullPath);
foreach (var file in files)
{
var fileInfo = new FileInfo(file);
var relativePath = string.IsNullOrEmpty(folderPath) ? fileInfo.Name : $"{folderPath}/{fileInfo.Name}";
items.Add(new FileItemDto
{
Id = Guid.NewGuid().ToString(),
Name = fileInfo.Name,
Type = "file",
Size = fileInfo.Length,
Extension = fileInfo.Extension,
MimeType = GetMimeType(fileInfo.Extension),
CreatedAt = fileInfo.CreationTime,
ModifiedAt = fileInfo.LastWriteTime,
Path = relativePath,
ParentId = string.Empty,
IsReadOnly = false,
ChildCount = 0
});
}
return items.OrderBy(x => x.Name).ToList();
}
private string GetMimeType(string extension)
{
return extension.ToLowerInvariant() switch
{
".pdf" => "application/pdf",
".doc" => "application/msword",
".docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
".xls" => "application/vnd.ms-excel",
".xlsx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
".ppt" => "application/vnd.ms-powerpoint",
".pptx" => "application/vnd.openxmlformats-officedocument.presentationml.presentation",
".jpg" or ".jpeg" => "image/jpeg",
".png" => "image/png",
".gif" => "image/gif",
".txt" => "text/plain",
".zip" => "application/zip",
".rar" => "application/x-rar-compressed",
_ => "application/octet-stream"
};
}
private async Task<ExpensesDto> GetExpensesAsync()
{
var queryable = await _expenseRepository.GetQueryableAsync();
var today = DateTime.Today;
var oneMonthAgo = today.AddMonths(-1);
// Son 1 ay içerisindeki kayıtlar
var lastMonthExpenses = queryable
.Where(a => a.RequestDate >= oneMonthAgo && a.RequestDate <= today);
// Son 1 aydaki toplam talep miktarı
var totalRequested = lastMonthExpenses.Sum(a => a.Amount);
// Son 1 aydaki onaylanan harcamaların toplamı
var totalApproved = lastMonthExpenses
.Where(a => a.Status == "approved")
.Sum(a => a.Amount);
// Son 5 kayıt
var last5Expenses = queryable
.OrderByDescending(a => a.RequestDate)
.Take(5)
.ToList();
// Map işlemleri
var last5Dtos = ObjectMapper.Map<List<Expense>, List<ExpenseDto>>(last5Expenses);
// Dönüş DTO'su
return new ExpensesDto
{
TotalRequested = totalRequested,
TotalApproved = totalApproved,
Last5Expenses = last5Dtos
};
}
private async Task<List<TrainingDto>> GetTrainingsAsync()
{
var trainings = await _trainingRepository.GetListAsync(a => a.StartDate >= DateTime.Today);
return ObjectMapper.Map<List<Training>, List<TrainingDto>>(trainings);
}
private async Task<List<ReservationDto>> GetReservationsAsync()
{
var reservations = await _reservationRepository.GetListAsync(a => a.StartDate >= DateTime.Today);
return ObjectMapper.Map<List<Reservation>, List<ReservationDto>>(reservations);
}
private async Task<List<VisitorDto>> GetVisitorsAsync()
{
var visitors = await _visitorRepository.GetListAsync(a => a.VisitDate >= DateTime.Today);
return ObjectMapper.Map<List<Visitor>, List<VisitorDto>>(visitors);
}
private async Task<List<EmployeeDto>> GetBirthdaysAsync()
{
var today = DateTime.Now;
var employees = await _employeeRepository
.WithDetailsAsync(e => e.EmploymentType, e => e.JobPosition, e => e.Department)
.ContinueWith(t => t.Result
.Where(e => e.BirthDate.Day == today.Day && e.BirthDate.Month == today.Month)
.ToList());
return ObjectMapper.Map<List<Employee>, List<EmployeeDto>>(employees);
}
private async Task<List<EventDto>> GetUpcomingEventsAsync() private async Task<List<EventDto>> GetUpcomingEventsAsync()
{ {
var events = await _eventRepository var events = await _eventRepository
@ -74,7 +243,7 @@ public class IntranetAppService : PlatformAppService, IIntranetAppService
Avatar = employee.Avatar Avatar = employee.Avatar
}, },
Participants = evt.ParticipantsCount, Participants = evt.ParticipantsCount,
Photos = [], Photos = [],
Comments = [], Comments = [],
Likes = evt.Likes, Likes = evt.Likes,
IsPublished = evt.isPublished IsPublished = evt.isPublished

View file

@ -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>();
}
}

View file

@ -41204,9 +41204,9 @@ public class ListFormSeeder : IDataSeedContributor, ITransientDependency
RoleId = null, RoleId = null,
UserId = null, UserId = null,
CultureName = LanguageCodes.En, CultureName = LanguageCodes.En,
SourceDbType = DbType.Date, SourceDbType = DbType.DateTime,
FieldName = "VisitDate", FieldName = "VisitDate",
Width = 100, Width = 150,
ListOrderNo = 7, ListOrderNo = 7,
Visible = true, Visible = true,
IsActive = true, IsActive = true,

View file

@ -2,6 +2,7 @@ namespace Kurs.Platform.BlobStoring;
public static class BlobContainerNames public static class BlobContainerNames
{ {
public const string Intranet = "intranet";
public const string Avatar = "avatar"; public const string Avatar = "avatar";
public const string Import = "import"; public const string Import = "import";
public const string Activity = "activity"; public const string Activity = "activity";

View file

@ -1,4 +1,3 @@
// Domain/Entities/Visitor.cs
using System; using System;
using Volo.Abp.Domain.Entities.Auditing; using Volo.Abp.Domain.Entities.Auditing;
using Volo.Abp.MultiTenancy; using Volo.Abp.MultiTenancy;
@ -17,7 +16,9 @@ public class Visitor : FullAuditedEntity<Guid>, IMultiTenant
public DateTime VisitDate { get; set; } public DateTime VisitDate { get; set; }
public DateTime? CheckIn { get; set; } public DateTime? CheckIn { get; set; }
public DateTime? CheckOut { get; set; } public DateTime? CheckOut { get; set; }
public Guid? EmployeeId { get; set; } // HrEmployee referansı public Guid? EmployeeId { get; set; }
public Employee Employee { get; set; } public Employee Employee { get; set; }
public string Status { get; set; } //checked-in, checked-out, scheduled public string Status { get; set; }
public string BadgeNumber { get; set; }
public string Photo { get; set; }
} }

View file

@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore;
namespace Kurs.Platform.Migrations namespace Kurs.Platform.Migrations
{ {
[DbContext(typeof(PlatformDbContext))] [DbContext(typeof(PlatformDbContext))]
[Migration("20251028200151_Initial")] [Migration("20251029074530_Initial")]
partial class Initial partial class Initial
{ {
/// <inheritdoc /> /// <inheritdoc />
@ -9058,6 +9058,9 @@ namespace Kurs.Platform.Migrations
b.Property<Guid>("Id") b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier"); .HasColumnType("uniqueidentifier");
b.Property<string>("BadgeNumber")
.HasColumnType("nvarchar(max)");
b.Property<DateTime?>("CheckIn") b.Property<DateTime?>("CheckIn")
.HasColumnType("datetime2"); .HasColumnType("datetime2");
@ -9115,6 +9118,9 @@ namespace Kurs.Platform.Migrations
.HasMaxLength(20) .HasMaxLength(20)
.HasColumnType("nvarchar(20)"); .HasColumnType("nvarchar(20)");
b.Property<string>("Photo")
.HasColumnType("nvarchar(max)");
b.Property<string>("Purpose") b.Property<string>("Purpose")
.HasMaxLength(250) .HasMaxLength(250)
.HasColumnType("nvarchar(250)"); .HasColumnType("nvarchar(250)");

View file

@ -4462,6 +4462,8 @@ namespace Kurs.Platform.Migrations
CheckOut = table.Column<DateTime>(type: "datetime2", nullable: true), CheckOut = table.Column<DateTime>(type: "datetime2", nullable: true),
EmployeeId = table.Column<Guid>(type: "uniqueidentifier", nullable: true), EmployeeId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
Status = table.Column<string>(type: "nvarchar(20)", maxLength: 20, nullable: false), Status = table.Column<string>(type: "nvarchar(20)", maxLength: 20, nullable: false),
BadgeNumber = table.Column<string>(type: "nvarchar(max)", nullable: true),
Photo = table.Column<string>(type: "nvarchar(max)", nullable: true),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false), CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true), CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true), LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),

View file

@ -9055,6 +9055,9 @@ namespace Kurs.Platform.Migrations
b.Property<Guid>("Id") b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier"); .HasColumnType("uniqueidentifier");
b.Property<string>("BadgeNumber")
.HasColumnType("nvarchar(max)");
b.Property<DateTime?>("CheckIn") b.Property<DateTime?>("CheckIn")
.HasColumnType("datetime2"); .HasColumnType("datetime2");
@ -9112,6 +9115,9 @@ namespace Kurs.Platform.Migrations
.HasMaxLength(20) .HasMaxLength(20)
.HasColumnType("nvarchar(20)"); .HasColumnType("nvarchar(20)");
b.Property<string>("Photo")
.HasColumnType("nvarchar(max)");
b.Property<string>("Purpose") b.Property<string>("Purpose")
.HasMaxLength(250) .HasMaxLength(250)
.HasColumnType("nvarchar(250)"); .HasColumnType("nvarchar(250)");

View file

@ -100,9 +100,7 @@
"props": null, "props": null,
"description": null, "description": null,
"isActive": true, "isActive": true,
"dependencies": [ "dependencies": ["AxiosListComponent"]
"AxiosListComponent"
]
} }
], ],
"ReportCategories": [ "ReportCategories": [
@ -1509,7 +1507,7 @@
{ {
"CategoryName": "Spor", "CategoryName": "Spor",
"TypeName": "Futbol Turnuvası", "TypeName": "Futbol Turnuvası",
"Date": "2025-11-15T10:00:00", "Date": "2025-11-05T10:00:00",
"Name": "Yaz Futbol Turnuvası 2025", "Name": "Yaz Futbol Turnuvası 2025",
"Description": "Tüm departmanların katılımıyla düzenlenen geleneksel yaz futbol turnuvası.", "Description": "Tüm departmanların katılımıyla düzenlenen geleneksel yaz futbol turnuvası.",
"Place": "Şirket Kampüsü Spor Alanı", "Place": "Şirket Kampüsü Spor Alanı",
@ -1524,7 +1522,7 @@
{ {
"CategoryName": "Kültür", "CategoryName": "Kültür",
"TypeName": "Kültürel Sanat Günü", "TypeName": "Kültürel Sanat Günü",
"Date": "2025-11-17T10:00:00", "Date": "2025-11-01T10:00:00",
"Name": "Kültür Gezisi: Kapadokya", "Name": "Kültür Gezisi: Kapadokya",
"Description": "Çalışanlarımıza özel, rehber eşliğinde 2 günlük kültürel gezi.", "Description": "Çalışanlarımıza özel, rehber eşliğinde 2 günlük kültürel gezi.",
"Place": "Kapadokya, Nevşehir", "Place": "Kapadokya, Nevşehir",
@ -1539,7 +1537,7 @@
{ {
"CategoryName": "Müzik", "CategoryName": "Müzik",
"TypeName": "Caz Akşamı", "TypeName": "Caz Akşamı",
"Date": "2025-11-18T10:00:00", "Date": "2025-11-09T10:00:00",
"Name": "Müzik Dinletisi: Jazz Akşamı", "Name": "Müzik Dinletisi: Jazz Akşamı",
"Description": "Caz müziğinin en güzel örneklerinin canlı performanslarla sunulacağı özel akşam.", "Description": "Caz müziğinin en güzel örneklerinin canlı performanslarla sunulacağı özel akşam.",
"Place": "Şirket Konferans Salonu", "Place": "Şirket Konferans Salonu",
@ -2408,12 +2406,7 @@
"minSalary": 80000, "minSalary": 80000,
"maxSalary": 120000, "maxSalary": 120000,
"currencyCode": "USD", "currencyCode": "USD",
"requiredSkills": [ "requiredSkills": ["JavaScript", "TypeScript", "React", "Node.js"],
"JavaScript",
"TypeScript",
"React",
"Node.js"
],
"responsibilities": [ "responsibilities": [
"Develop frontend and backend applications", "Develop frontend and backend applications",
"Write clean and maintainable code", "Write clean and maintainable code",
@ -2858,7 +2851,7 @@
"fullName": "Ali Öztürk", "fullName": "Ali Öztürk",
"avatar": "https://i.pravatar.cc/150?img=12", "avatar": "https://i.pravatar.cc/150?img=12",
"nationalId": "12345678901", "nationalId": "12345678901",
"birthDate": "10-10-1988", "birthDate": "2020-10-29",
"gender": "Male", "gender": "Male",
"maritalStatus": "Married", "maritalStatus": "Married",
"country": "TR", "country": "TR",
@ -2898,7 +2891,7 @@
"fullName": "Ayşe Kaya", "fullName": "Ayşe Kaya",
"avatar": "https://i.pravatar.cc/150?img=5", "avatar": "https://i.pravatar.cc/150?img=5",
"nationalId": "12345678902", "nationalId": "12345678902",
"birthDate": "02-08-1990", "birthDate": "2015-10-30",
"gender": "Female", "gender": "Female",
"maritalStatus": "Single", "maritalStatus": "Single",
"country": "TR", "country": "TR",
@ -2938,7 +2931,7 @@
"fullName": "Mehmet Yılmaz", "fullName": "Mehmet Yılmaz",
"avatar": "https://i.pravatar.cc/150?img=8", "avatar": "https://i.pravatar.cc/150?img=8",
"nationalId": "12345678903", "nationalId": "12345678903",
"birthDate": "12-03-1987", "birthDate": "2010-10-31",
"gender": "Male", "gender": "Male",
"maritalStatus": "Married", "maritalStatus": "Married",
"country": "TR", "country": "TR",
@ -2978,7 +2971,7 @@
"fullName": "Selin Demir", "fullName": "Selin Demir",
"avatar": "https://i.pravatar.cc/150?img=9", "avatar": "https://i.pravatar.cc/150?img=9",
"nationalId": "12345678904", "nationalId": "12345678904",
"birthDate": "05-05-1993", "birthDate": "2000-11-01",
"gender": "Female", "gender": "Female",
"maritalStatus": "Single", "maritalStatus": "Single",
"country": "TR", "country": "TR",
@ -3018,7 +3011,7 @@
"fullName": "Ahmet Çelik", "fullName": "Ahmet Çelik",
"avatar": "https://i.pravatar.cc/150?img=33", "avatar": "https://i.pravatar.cc/150?img=33",
"nationalId": "12345678905", "nationalId": "12345678905",
"birthDate": "10-09-1985", "birthDate": "1999-11-02",
"gender": "Male", "gender": "Male",
"maritalStatus": "Married", "maritalStatus": "Married",
"country": "TR", "country": "TR",
@ -3058,7 +3051,7 @@
"fullName": "Zeynep Arslan", "fullName": "Zeynep Arslan",
"avatar": "https://i.pravatar.cc/150?img=10", "avatar": "https://i.pravatar.cc/150?img=10",
"nationalId": "12345678906", "nationalId": "12345678906",
"birthDate": "01-01-1995", "birthDate": "1995-11-03",
"gender": "Female", "gender": "Female",
"maritalStatus": "Single", "maritalStatus": "Single",
"country": "TR", "country": "TR",
@ -3098,7 +3091,7 @@
"fullName": "Burak Koç", "fullName": "Burak Koç",
"avatar": "https://i.pravatar.cc/150?img=14", "avatar": "https://i.pravatar.cc/150?img=14",
"nationalId": "12345678907", "nationalId": "12345678907",
"birthDate": "08-06-1991", "birthDate": "1980-11-04",
"gender": "Male", "gender": "Male",
"maritalStatus": "Married", "maritalStatus": "Married",
"country": "TR", "country": "TR",
@ -3138,7 +3131,7 @@
"fullName": "Elif Şahin", "fullName": "Elif Şahin",
"avatar": "https://i.pravatar.cc/150?img=20", "avatar": "https://i.pravatar.cc/150?img=20",
"nationalId": "12345678908", "nationalId": "12345678908",
"birthDate": "05-11-1989", "birthDate": "1989-11-05",
"gender": "Female", "gender": "Female",
"maritalStatus": "Married", "maritalStatus": "Married",
"country": "TR", "country": "TR",
@ -3178,7 +3171,7 @@
"fullName": "Canan Öztürk", "fullName": "Canan Öztürk",
"avatar": "https://i.pravatar.cc/150?img=25", "avatar": "https://i.pravatar.cc/150?img=25",
"nationalId": "12345678909", "nationalId": "12345678909",
"birthDate": "04-04-1992", "birthDate": "1992-11-06",
"gender": "Female", "gender": "Female",
"maritalStatus": "Single", "maritalStatus": "Single",
"country": "TR", "country": "TR",
@ -3218,7 +3211,7 @@
"fullName": "Murat Aydın", "fullName": "Murat Aydın",
"avatar": "https://i.pravatar.cc/150?img=30", "avatar": "https://i.pravatar.cc/150?img=30",
"nationalId": "12345678910", "nationalId": "12345678910",
"birthDate": "03-12-1984", "birthDate": "1984-11-07",
"gender": "Male", "gender": "Male",
"maritalStatus": "Married", "maritalStatus": "Married",
"country": "TR", "country": "TR",
@ -3561,8 +3554,8 @@
"category": "technical", "category": "technical",
"type": "online", "type": "online",
"duration": 16, "duration": 16,
"startDate": "01-11-2024", "startDate": "2025-10-29",
"endDate": "08-11-2024", "endDate": "2025-11-08",
"maxParticipants": 20, "maxParticipants": 20,
"enrolled": 15, "enrolled": 15,
"status": "upcoming", "status": "upcoming",
@ -3576,8 +3569,8 @@
"category": "soft-skills", "category": "soft-skills",
"type": "classroom", "type": "classroom",
"duration": 8, "duration": 8,
"startDate": "05-10-2024", "startDate": "2024-11-05",
"endDate": "05-10-2024", "endDate": "2024-12-05",
"maxParticipants": 15, "maxParticipants": 15,
"enrolled": 12, "enrolled": 12,
"status": "ongoing", "status": "ongoing",
@ -3591,8 +3584,8 @@
"category": "management", "category": "management",
"type": "hybrid", "type": "hybrid",
"duration": 24, "duration": 24,
"startDate": "10-09-2024", "startDate": "2025-10-29",
"endDate": "03-09-2024", "endDate": "2025-11-03",
"maxParticipants": 25, "maxParticipants": 25,
"enrolled": 25, "enrolled": 25,
"status": "completed", "status": "completed",
@ -3606,8 +3599,8 @@
"category": "compliance", "category": "compliance",
"type": "online", "type": "online",
"duration": 12, "duration": 12,
"startDate": "05-11-2024", "startDate": "2024-11-05",
"endDate": "02-11-2024", "endDate": "2024-11-30",
"maxParticipants": 50, "maxParticipants": 50,
"enrolled": 8, "enrolled": 8,
"status": "upcoming", "status": "upcoming",
@ -3620,8 +3613,8 @@
"type": "room", "type": "room",
"resourceName": "Toplantı Salonu A", "resourceName": "Toplantı Salonu A",
"employeeCode": "EMP-001", "employeeCode": "EMP-001",
"startDate": "10-10-2024 09:00:00", "startDate": "10-10-2025 09:00:00",
"endDate": "10-10-2024 11:00:00", "endDate": "10-10-2025 11:00:00",
"purpose": "Sprint Planning Toplantısı", "purpose": "Sprint Planning Toplantısı",
"status": "approved", "status": "approved",
"participants": 8, "participants": 8,
@ -3631,8 +3624,8 @@
"type": "vehicle", "type": "vehicle",
"resourceName": "Şirket Aracı - 34 ABC 123", "resourceName": "Şirket Aracı - 34 ABC 123",
"employeeCode": "EMP-001", "employeeCode": "EMP-001",
"startDate": "11-10-2024 08:00:00", "startDate": "11-10-2025 08:00:00",
"endDate": "11-10-2024 18:00:00", "endDate": "11-10-2025 18:00:00",
"purpose": "Müşteri Ziyareti", "purpose": "Müşteri Ziyareti",
"status": "pending", "status": "pending",
"notes": "Ankara çıkışı" "notes": "Ankara çıkışı"
@ -3641,8 +3634,8 @@
"type": "equipment", "type": "equipment",
"resourceName": "Kamera ve Tripod Seti", "resourceName": "Kamera ve Tripod Seti",
"employeeCode": "EMP-001", "employeeCode": "EMP-001",
"startDate": "09-10-2024 14:00:00", "startDate": "09-10-2025 14:00:00",
"endDate": "09-10-2024 17:00:00", "endDate": "09-10-2025 17:00:00",
"purpose": "Ürün Tanıtım Videosu Çekimi", "purpose": "Ürün Tanıtım Videosu Çekimi",
"status": "approved" "status": "approved"
}, },
@ -3650,8 +3643,8 @@
"type": "room", "type": "room",
"resourceName": "Eğitim Salonu B", "resourceName": "Eğitim Salonu B",
"employeeCode": "EMP-001", "employeeCode": "EMP-001",
"startDate": "05-10-2024 09:00:00", "startDate": "05-10-2025 09:00:00",
"endDate": "05-10-2024 17:00:00", "endDate": "05-10-2025 17:00:00",
"purpose": "Etkili İletişim Eğitimi", "purpose": "Etkili İletişim Eğitimi",
"status": "approved", "status": "approved",
"participants": 15, "participants": 15,
@ -3783,33 +3776,36 @@
"companyName": "ABC Teknoloji", "companyName": "ABC Teknoloji",
"email": "ali.veli@abc.com", "email": "ali.veli@abc.com",
"phone": "5321112233", "phone": "5321112233",
"visitDate": "2025-10-05", "visitDate": "2025-10-29T09:00:00",
"checkIn": "05-10-2025", "checkIn": "2025-10-29T09:15:00",
"employeeCode": "EMP-001", "employeeCode": "EMP-001",
"purpose": "İş Ortaklığı Görüşmesi", "purpose": "İş Ortaklığı Görüşmesi",
"status": "checked-in" "status": "checked-in",
"photo": "https://i.pravatar.cc/150?img=12"
}, },
{ {
"fullName": "Fatma Yıldız", "fullName": "Fatma Yıldız",
"companyName": "XYZ Danışmanlık", "companyName": "XYZ Danışmanlık",
"email": "fatma@xyz.com", "email": "fatma@xyz.com",
"phone": "5332223344", "phone": "5332223344",
"visitDate": "01-10-2024", "visitDate": "2025-10-30T10:30:00",
"employeeCode": "EMP-002", "employeeCode": "EMP-002",
"purpose": "Eğitim Danışmanlığı", "purpose": "Eğitim Danışmanlığı",
"status": "scheduled" "status": "scheduled",
"photo": "https://i.pravatar.cc/150?img=13"
}, },
{ {
"fullName": "Mehmet Kara", "fullName": "Mehmet Kara",
"companyName": "DEF Yazılım", "companyName": "DEF Yazılım",
"email": "mehmet@def.com", "email": "mehmet@def.com",
"phone": "5343334455", "phone": "5343334455",
"visitDate": "08-10-2024", "visitDate": "2025-10-31T14:00:00",
"checkIn": "08-10-2024", "checkIn": "2025-10-31T14:10:00",
"checkOut": "10-10-2024", "checkOut": "2025-10-31T16:00:00",
"employeeCode": "EMP-003", "employeeCode": "EMP-003",
"purpose": "Teknik Sunum", "purpose": "Teknik Sunum",
"status": "checked-out" "status": "checked-out",
"photo": "https://i.pravatar.cc/150?img=14"
} }
], ],
"ExpenseRequests": [ "ExpenseRequests": [
@ -3818,19 +3814,19 @@
"category": "travel", "category": "travel",
"amount": 850, "amount": 850,
"currencyCode": "TRY", "currencyCode": "TRY",
"requestDate": "08-10-2024", "requestDate": "2025-10-04",
"description": "Ankara ofis ziyareti - uçak bileti", "description": "Ankara ofis ziyareti - uçak bileti",
"project": "Intranet v2", "project": "Intranet v2",
"status": "approved", "status": "approved",
"approverCode": "EMP-004", "approverCode": "EMP-004",
"approvalDate": "10-10-2024" "approvalDate": "2025-10-10"
}, },
{ {
"employeeCode": "EMP-002", "employeeCode": "EMP-002",
"category": "meal", "category": "meal",
"amount": 320, "amount": 320,
"currencyCode": "TRY", "currencyCode": "TRY",
"requestDate": "07-10-2024", "requestDate": "2025-10-07",
"description": "Müşteri toplantısı - öğle yemeği", "description": "Müşteri toplantısı - öğle yemeği",
"project": null, "project": null,
"status": "pending", "status": "pending",
@ -3842,12 +3838,12 @@
"category": "accommodation", "category": "accommodation",
"amount": 1200, "amount": 1200,
"currencyCode": "TRY", "currencyCode": "TRY",
"requestDate": "04-10-2024", "requestDate": "2025-10-04",
"description": "İzmir workshop - otel konaklaması (2 gece)", "description": "İzmir workshop - otel konaklaması (2 gece)",
"project": "UX Workshop", "project": "UX Workshop",
"status": "approved", "status": "approved",
"approverCode": "EMP-005", "approverCode": "EMP-005",
"approvalDate": "05-10-2024" "approvalDate": "2025-10-05"
} }
], ],
"Surveys": [ "Surveys": [
@ -4105,9 +4101,7 @@
{ {
"postContent": "CI/CD pipeline güncellememiz tamamlandı! Deployment süremiz %40 azaldı. Otomasyonun gücü 💪", "postContent": "CI/CD pipeline güncellememiz tamamlandı! Deployment süremiz %40 azaldı. Otomasyonun gücü 💪",
"type": "video", "type": "video",
"urls": [ "urls": ["https://www.w3schools.com/html/mov_bbb.mp4"]
"https://www.w3schools.com/html/mov_bbb.mp4"
]
} }
], ],
"SocialPollOptions": [ "SocialPollOptions": [

View file

@ -1293,7 +1293,8 @@ public class TenantDataSeeder : IDataSeedContributor, ITransientDependency
CheckIn = item.CheckIn, CheckIn = item.CheckIn,
CheckOut = item.CheckOut, CheckOut = item.CheckOut,
EmployeeId = employee != null ? employee.Id : null, EmployeeId = employee != null ? employee.Id : null,
Status = item.Status Status = item.Status,
Photo = item.Photo
}); });
} }

View file

@ -201,6 +201,7 @@ public class VisitorSeedDto
public DateTime? CheckOut { get; set; } public DateTime? CheckOut { get; set; }
public string EmployeeCode { get; set; } public string EmployeeCode { get; set; }
public string Status { get; set; } public string Status { get; set; }
public string Photo { get; set; }
} }
public class AnnouncementSeedDto public class AnnouncementSeedDto

View file

@ -1,7 +1,7 @@
import React, { useState, useRef, useEffect } from "react"; import React, { useState, useRef, useEffect } from "react";
import { FaChevronDown, FaTimes } from "react-icons/fa"; import { FaChevronDown, FaTimes } from "react-icons/fa";
import { mockEmployees } from "../../mocks/mockEmployees"; import { mockEmployees } from "../../mocks/mockEmployees";
import { HrEmployee } from "../../types/hr"; import { EmployeeDto } from "../../types/hr";
interface MultiSelectEmployeeProps { interface MultiSelectEmployeeProps {
selectedEmployees: string[]; selectedEmployees: string[];
@ -40,7 +40,7 @@ const MultiSelectEmployee: React.FC<MultiSelectEmployeeProps> = ({
}, []); }, []);
const filteredEmployees = mockEmployees.filter( const filteredEmployees = mockEmployees.filter(
(employee: HrEmployee) => (employee: EmployeeDto) =>
employee.fullName.toLowerCase().includes(searchTerm.toLowerCase()) || employee.fullName.toLowerCase().includes(searchTerm.toLowerCase()) ||
employee.code.toLowerCase().includes(searchTerm.toLowerCase()) employee.code.toLowerCase().includes(searchTerm.toLowerCase())
); );
@ -58,7 +58,7 @@ const MultiSelectEmployee: React.FC<MultiSelectEmployeeProps> = ({
onChange(selectedEmployees.filter((id) => id !== employeeId)); onChange(selectedEmployees.filter((id) => id !== employeeId));
}; };
const selectedEmployeeObjects = mockEmployees.filter((emp: HrEmployee) => const selectedEmployeeObjects = mockEmployees.filter((emp: EmployeeDto) =>
selectedEmployees.includes(emp.id) selectedEmployees.includes(emp.id)
); );
@ -79,7 +79,7 @@ const MultiSelectEmployee: React.FC<MultiSelectEmployeeProps> = ({
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div className="flex flex-wrap gap-1 flex-1"> <div className="flex flex-wrap gap-1 flex-1">
{selectedEmployeeObjects.length > 0 ? ( {selectedEmployeeObjects.length > 0 ? (
selectedEmployeeObjects.map((employee: HrEmployee) => ( selectedEmployeeObjects.map((employee: EmployeeDto) => (
<span <span
key={employee.id} key={employee.id}
className="inline-flex items-center px-2 py-1 rounded-md text-xs font-medium bg-blue-100 text-blue-800" className="inline-flex items-center px-2 py-1 rounded-md text-xs font-medium bg-blue-100 text-blue-800"
@ -127,7 +127,7 @@ const MultiSelectEmployee: React.FC<MultiSelectEmployeeProps> = ({
{/* Options List */} {/* Options List */}
<div className="max-h-48 overflow-y-auto"> <div className="max-h-48 overflow-y-auto">
{filteredEmployees.length > 0 ? ( {filteredEmployees.length > 0 ? (
filteredEmployees.map((employee: HrEmployee) => ( filteredEmployees.map((employee: EmployeeDto) => (
<div <div
key={employee.id} key={employee.id}
className={` className={`

View file

@ -1,6 +1,6 @@
import { HrDepartment } from '../types/hr' import { DepartmentDto } from '../types/hr'
export const mockDepartments: HrDepartment[] = [ export const mockDepartments: DepartmentDto[] = [
{ {
id: '1', id: '1',
code: 'ÜRT', code: 'ÜRT',

View file

@ -1,5 +1,5 @@
import { import {
HrEmployee, EmployeeDto,
EmployeeStatusEnum, EmployeeStatusEnum,
EmploymentTypeEnum, EmploymentTypeEnum,
GenderEnum, GenderEnum,
@ -9,7 +9,7 @@ import { mockBanks } from "./mockBanks";
import { mockDepartments } from "./mockDepartments"; import { mockDepartments } from "./mockDepartments";
import { mockJobPositions } from "./mockJobPositions"; import { mockJobPositions } from "./mockJobPositions";
export const mockEmployees: HrEmployee[] = [ export const mockEmployees: EmployeeDto[] = [
{ {
id: "1", id: "1",
code: "EMP-001", code: "EMP-001",

View file

@ -1,117 +1,14 @@
import { EventDto } from '@/proxy/intranet/models' import { DocumentDto, EventDto, ExpenseDto, ReservationDto, TrainingDto, VisitorDto } from '@/proxy/intranet/models'
import { mockEmployees } from './mockEmployees' import { mockEmployees } from './mockEmployees'
import { import {
Announcement, Announcement,
Visitor,
Document,
Certificate, Certificate,
ExpenseRequest,
Training,
Reservation,
MealMenu, MealMenu,
ShuttleRoute, ShuttleRoute,
Survey, Survey,
SocialPost, SocialPost,
} from '@/types/intranet' } from '@/types/intranet'
/////////////////////////////////////////////////////////////////////////////////////
///////EKLENENLER//////////
export const mockTrainings: Training[] = [
{
id: 'tr1',
title: 'React & TypeScript İleri Seviye',
description:
'Modern React uygulamaları geliştirmek için TypeScript kullanımı, hooks, context API ve performans optimizasyonu',
instructor: 'Mehmet Demir',
category: 'technical',
type: 'online',
duration: 16,
startDate: new Date('2024-11-01'),
endDate: new Date('2024-11-08'),
maxParticipants: 20,
enrolled: 15,
status: 'upcoming',
thumbnail: 'https://images.unsplash.com/photo-1633356122544-f134324a6cee?w=400&h=300&fit=crop',
},
{
id: 'tr2',
title: 'Etkili İletişim ve Sunum Teknikleri',
description:
'İş hayatında etkili iletişim kurma, profesyonel sunum hazırlama ve konuşma becerileri geliştirme',
instructor: 'Ayşe Kara',
category: 'soft-skills',
type: 'classroom',
duration: 8,
startDate: new Date('2024-10-25'),
endDate: new Date('2024-10-25'),
maxParticipants: 15,
enrolled: 12,
status: 'ongoing',
location: 'Eğitim Salonu A',
thumbnail: 'https://images.unsplash.com/photo-1557804506-669a67965ba0?w=400&h=300&fit=crop',
},
{
id: 'tr3',
title: 'Agile & Scrum Master Eğitimi',
description:
'Çevik yazılım geliştirme metodolojileri, Scrum framework ve sertifikasyon hazırlığı',
instructor: 'Can Öztürk',
category: 'management',
type: 'hybrid',
duration: 24,
startDate: new Date('2024-09-15'),
endDate: new Date('2024-09-30'),
maxParticipants: 25,
enrolled: 25,
status: 'completed',
thumbnail: 'https://images.unsplash.com/photo-1552664730-d307ca884978?w=400&h=300&fit=crop',
},
{
id: 'tr4',
title: 'Siber Güvenlik ve Veri Koruma',
description: 'KVKK uyumluluğu, siber güvenlik tehditleri ve kurumsal veri koruma stratejileri',
instructor: 'Zeynep Arslan',
category: 'compliance',
type: 'online',
duration: 12,
startDate: new Date('2024-11-15'),
endDate: new Date('2024-11-22'),
maxParticipants: 50,
enrolled: 8,
status: 'upcoming',
thumbnail: 'https://images.unsplash.com/photo-1550751827-4bd374c3f58b?w=400&h=300&fit=crop',
},
]
export const mockCertificates: Certificate[] = [
{
id: 'cert1',
employee: mockEmployees[0],
trainingTitle: 'Agile & Scrum Master Eğitimi',
issueDate: new Date('2024-09-30'),
expiryDate: new Date('2026-09-30'),
certificateUrl: '/certificates/cert1.pdf',
score: 95,
},
{
id: 'cert2',
employee: mockEmployees[2],
trainingTitle: 'React & TypeScript İleri Seviye',
issueDate: new Date('2024-08-15'),
certificateUrl: '/certificates/cert2.pdf',
score: 88,
},
{
id: 'cert3',
employee: mockEmployees[4],
trainingTitle: 'Siber Güvenlik ve Veri Koruma',
issueDate: new Date('2024-07-20'),
expiryDate: new Date('2025-07-20'),
certificateUrl: '/certificates/cert3.pdf',
score: 92,
},
]
export const mockMealMenus: MealMenu[] = [ export const mockMealMenus: MealMenu[] = [
{ {
id: 'menu1', id: 'menu1',
@ -175,7 +72,7 @@ export const mockMealMenus: MealMenu[] = [
}, },
] ]
export const mockReservations: Reservation[] = [ export const mockReservations: ReservationDto[] = [
{ {
id: 'res1', id: 'res1',
type: 'room', type: 'room',
@ -334,143 +231,6 @@ export const mockAnnouncements: Announcement[] = [
}, },
] ]
export const mockVisitors: Visitor[] = [
{
id: 'vis1',
fullName: 'Ali Veli',
company: 'ABC Teknoloji',
email: 'ali.veli@abc.com',
phone: '+90 532 111 22 33',
visitDate: new Date('2025-10-25T10:00:00'),
checkIn: new Date('2025-10-25T10:15:00'),
host: mockEmployees[1],
purpose: 'İş Ortaklığı Görüşmesi',
status: 'checked-in',
badgeNumber: 'V-001',
photo: 'https://i.pravatar.cc/150?img=60',
},
{
id: 'vis2',
fullName: 'Fatma Yıldız',
company: 'XYZ Danışmanlık',
email: 'fatma@xyz.com',
phone: '+90 533 222 33 44',
visitDate: new Date('2024-10-21T14:00:00'),
host: mockEmployees[2],
purpose: 'Eğitim Danışmanlığı',
status: 'scheduled',
photo: 'https://i.pravatar.cc/150?img=47',
},
{
id: 'vis3',
fullName: 'Mehmet Kara',
company: 'DEF Yazılım',
email: 'mehmet@def.com',
phone: '+90 534 333 44 55',
visitDate: new Date('2024-10-18T11:00:00'),
checkIn: new Date('2024-10-18T11:05:00'),
checkOut: new Date('2024-10-18T13:30:00'),
host: mockEmployees[3],
purpose: 'Teknik Sunum',
status: 'checked-out',
badgeNumber: 'V-002',
photo: 'https://i.pravatar.cc/150?img=68',
},
]
export const mockExpenseRequests: ExpenseRequest[] = [
{
id: 'exp1',
employee: mockEmployees[0],
category: 'travel',
amount: 850,
currency: 'TRY',
date: new Date('2024-10-15'),
description: 'Ankara ofis ziyareti - uçak bileti',
project: 'Intranet v2',
receipts: [{ name: 'ucak_bileti.pdf', url: '#', size: '234 KB' }],
status: 'approved',
approver: mockEmployees[4],
approvalDate: new Date('2024-10-16T10:00:00'),
creationTime: new Date('2024-10-15T18:00:00'),
},
{
id: 'exp2',
employee: mockEmployees[2],
category: 'meal',
amount: 320,
currency: 'TRY',
date: new Date('2024-10-17'),
description: 'Müşteri toplantısı - öğle yemeği',
receipts: [{ name: 'restoran_fisi.jpg', url: '#', size: '156 KB' }],
status: 'pending',
creationTime: new Date('2024-10-17T20:00:00'),
},
{
id: 'exp3',
employee: mockEmployees[1],
category: 'accommodation',
amount: 1200,
currency: 'TRY',
date: new Date('2024-10-14'),
description: 'İzmir workshop - otel konaklaması (2 gece)',
project: 'UX Workshop',
receipts: [{ name: 'otel_fatura.pdf', url: '#', size: '445 KB' }],
status: 'approved',
approver: mockEmployees[4],
approvalDate: new Date('2024-10-15T09:00:00'),
creationTime: new Date('2024-10-14T22:00:00'),
},
]
export const mockDocuments: Document[] = [
{
id: 'doc1',
name: 'Çalışan El Kitabı 2024',
type: 'pdf',
category: 'policy',
size: '3.2 MB',
uploadedBy: mockEmployees[3],
uploadDate: new Date('2024-01-15'),
version: '2.0',
url: '#',
description: 'Şirket politikaları ve prosedürleri',
departments: ['Tüm Departmanlar'],
downloadCount: 234,
tags: ['politika', 'prosedür', 'çalışan hakları'],
},
{
id: 'doc2',
name: 'İzin Talep Formu',
type: 'doc',
category: 'form',
size: '124 KB',
uploadedBy: mockEmployees[3],
uploadDate: new Date('2024-02-01'),
version: '1.5',
url: '#',
description: 'İzin talepleri için kullanılacak form',
departments: ['Tüm Departmanlar'],
downloadCount: 567,
tags: ['form', 'izin', 'HR'],
},
{
id: 'doc3',
name: 'Yazılım Geliştirme Standartları',
type: 'pdf',
category: 'procedure',
size: '1.8 MB',
uploadedBy: mockEmployees[4],
uploadDate: new Date('2024-03-10'),
version: '3.1',
url: '#',
description: 'Kod standartları ve best practices',
departments: ['Yazılım Geliştirme'],
downloadCount: 89,
tags: ['development', 'standards', 'coding'],
},
]
export const mockSurveys: Survey[] = [ export const mockSurveys: Survey[] = [
{ {
id: 'survey1', id: 'survey1',
@ -992,3 +752,279 @@ export const mockEvents: EventDto[] = [
isPublished: true, isPublished: true,
}, },
] ]
export const mockVisitors: VisitorDto[] = [
{
id: 'vis1',
fullName: 'Ali Veli',
companyName: 'ABC Teknoloji',
email: 'ali.veli@abc.com',
phone: '+90 532 111 22 33',
visitDate: new Date('2025-10-25T10:00:00'),
checkIn: new Date('2025-10-25T10:15:00'),
employeeId: mockEmployees[1].id,
employee: mockEmployees[1],
purpose: 'İş Ortaklığı Görüşmesi',
status: 'checked-in',
badgeNumber: 'V-001',
photo: 'https://i.pravatar.cc/150?img=60',
},
{
id: 'vis2',
fullName: 'Fatma Yıldız',
companyName: 'XYZ Danışmanlık',
email: 'fatma@xyz.com',
phone: '+90 533 222 33 44',
visitDate: new Date('2024-10-21T14:00:00'),
employeeId: mockEmployees[2].id,
employee: mockEmployees[2],
purpose: 'Eğitim Danışmanlığı',
status: 'scheduled',
photo: 'https://i.pravatar.cc/150?img=47',
},
{
id: 'vis3',
fullName: 'Mehmet Kara',
companyName: 'DEF Yazılım',
email: 'mehmet@def.com',
phone: '+90 534 333 44 55',
visitDate: new Date('2024-10-18T11:00:00'),
checkIn: new Date('2024-10-18T11:05:00'),
checkOut: new Date('2024-10-18T13:30:00'),
employeeId: mockEmployees[3].id,
employee: mockEmployees[3],
purpose: 'Teknik Sunum',
status: 'checked-out',
badgeNumber: 'V-002',
photo: 'https://i.pravatar.cc/150?img=68',
},
]
export const mockTrainings: TrainingDto[] = [
{
id: 'tr1',
title: 'React & TypeScript İleri Seviye',
description:
'Modern React uygulamaları geliştirmek için TypeScript kullanımı, hooks, context API ve performans optimizasyonu',
instructor: 'Mehmet Demir',
category: 'technical',
type: 'online',
duration: 16,
startDate: new Date('2024-11-01'),
endDate: new Date('2024-11-08'),
maxParticipants: 20,
enrolled: 15,
status: 'upcoming',
thumbnail: 'https://images.unsplash.com/photo-1633356122544-f134324a6cee?w=400&h=300&fit=crop',
},
{
id: 'tr2',
title: 'Etkili İletişim ve Sunum Teknikleri',
description:
'İş hayatında etkili iletişim kurma, profesyonel sunum hazırlama ve konuşma becerileri geliştirme',
instructor: 'Ayşe Kara',
category: 'soft-skills',
type: 'classroom',
duration: 8,
startDate: new Date('2024-10-25'),
endDate: new Date('2024-10-25'),
maxParticipants: 15,
enrolled: 12,
status: 'ongoing',
location: 'Eğitim Salonu A',
thumbnail: 'https://images.unsplash.com/photo-1557804506-669a67965ba0?w=400&h=300&fit=crop',
},
{
id: 'tr3',
title: 'Agile & Scrum Master Eğitimi',
description:
'Çevik yazılım geliştirme metodolojileri, Scrum framework ve sertifikasyon hazırlığı',
instructor: 'Can Öztürk',
category: 'management',
type: 'hybrid',
duration: 24,
startDate: new Date('2024-09-15'),
endDate: new Date('2024-09-30'),
maxParticipants: 25,
enrolled: 25,
status: 'completed',
thumbnail: 'https://images.unsplash.com/photo-1552664730-d307ca884978?w=400&h=300&fit=crop',
},
{
id: 'tr4',
title: 'Siber Güvenlik ve Veri Koruma',
description: 'KVKK uyumluluğu, siber güvenlik tehditleri ve kurumsal veri koruma stratejileri',
instructor: 'Zeynep Arslan',
category: 'compliance',
type: 'online',
duration: 12,
startDate: new Date('2024-11-15'),
endDate: new Date('2024-11-22'),
maxParticipants: 50,
enrolled: 8,
status: 'upcoming',
thumbnail: 'https://images.unsplash.com/photo-1550751827-4bd374c3f58b?w=400&h=300&fit=crop',
},
]
export const mockCertificates: Certificate[] = [
{
id: 'cert1',
employee: mockEmployees[0],
trainingTitle: 'Agile & Scrum Master Eğitimi',
issueDate: new Date('2024-09-30'),
expiryDate: new Date('2026-09-30'),
certificateUrl: '/certificates/cert1.pdf',
score: 95,
},
{
id: 'cert2',
employee: mockEmployees[2],
trainingTitle: 'React & TypeScript İleri Seviye',
issueDate: new Date('2024-08-15'),
certificateUrl: '/certificates/cert2.pdf',
score: 88,
},
{
id: 'cert3',
employee: mockEmployees[4],
trainingTitle: 'Siber Güvenlik ve Veri Koruma',
issueDate: new Date('2024-07-20'),
expiryDate: new Date('2025-07-20'),
certificateUrl: '/certificates/cert3.pdf',
score: 92,
},
]
export const mockExpenseRequests: ExpenseDto[] = [
{
id: 'exp1',
employee: mockEmployees[0],
category: 'travel',
amount: 850,
currency: 'TRY',
date: new Date('2024-10-15'),
description: 'Ankara ofis ziyareti - uçak bileti',
project: 'Intranet v2',
receipts: [{ name: 'ucak_bileti.pdf', url: '#', size: '234 KB' }],
status: 'approved',
approver: mockEmployees[4],
approvalDate: new Date('2024-10-16T10:00:00'),
creationTime: new Date('2024-10-15T18:00:00'),
},
{
id: 'exp2',
employee: mockEmployees[2],
category: 'meal',
amount: 320,
currency: 'TRY',
date: new Date('2024-10-17'),
description: 'Müşteri toplantısı - öğle yemeği',
receipts: [{ name: 'restoran_fisi.jpg', url: '#', size: '156 KB' }],
status: 'pending',
creationTime: new Date('2024-10-17T20:00:00'),
},
{
id: 'exp3',
employee: mockEmployees[1],
category: 'accommodation',
amount: 1200,
currency: 'TRY',
date: new Date('2024-10-14'),
description: 'İzmir workshop - otel konaklaması (2 gece)',
project: 'UX Workshop',
receipts: [{ name: 'otel_fatura.pdf', url: '#', size: '445 KB' }],
status: 'approved',
approver: mockEmployees[4],
approvalDate: new Date('2024-10-15T09:00:00'),
creationTime: new Date('2024-10-14T22:00:00'),
},
]
export const mockDocuments: DocumentDto[] = [
{
id: '1',
name: 'Çalışan El Kitabı 2024.pdf',
type: 'file',
size: 3355443, // 3.2 MB
extension: '.pdf',
mimeType: 'application/pdf',
createdAt: new Date('2024-01-15T10:30:00'),
modifiedAt: new Date('2024-01-15T10:30:00'),
path: 'Çalışan El Kitabı 2024.pdf',
parentId: '',
isReadOnly: false,
childCount: 0,
},
{
id: '2',
name: 'İzin Talep Formu.docx',
type: 'file',
size: 126976, // 124 KB
extension: '.docx',
mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
createdAt: new Date('2024-02-01T09:00:00'),
modifiedAt: new Date('2024-02-01T09:00:00'),
path: 'İzin Talep Formu.docx',
parentId: '',
isReadOnly: false,
childCount: 0,
},
{
id: '3',
name: 'Yazılım Geliştirme Standartları.pdf',
type: 'file',
size: 1887437, // 1.8 MB
extension: '.pdf',
mimeType: 'application/pdf',
createdAt: new Date('2024-03-10T14:20:00'),
modifiedAt: new Date('2024-03-10T14:20:00'),
path: 'Yazılım Geliştirme Standartları.pdf',
parentId: '',
isReadOnly: false,
childCount: 0,
},
{
id: '4',
name: 'Masraf Raporu Şablonu.xlsx',
type: 'file',
size: 245760, // 240 KB
extension: '.xlsx',
mimeType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
createdAt: new Date('2024-04-05T11:15:00'),
modifiedAt: new Date('2024-04-05T11:15:00'),
path: 'Masraf Raporu Şablonu.xlsx',
parentId: '',
isReadOnly: false,
childCount: 0,
},
{
id: '5',
name: 'Şirket Sunumu 2024.pptx',
type: 'file',
size: 5242880, // 5 MB
extension: '.pptx',
mimeType: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
createdAt: new Date('2024-05-20T16:45:00'),
modifiedAt: new Date('2024-06-10T10:30:00'),
path: 'Şirket Sunumu 2024.pptx',
parentId: '',
isReadOnly: false,
childCount: 0,
},
{
id: '6',
name: 'İK Politikaları.pdf',
type: 'file',
size: 2097152, // 2 MB
extension: '.pdf',
mimeType: 'application/pdf',
createdAt: new Date('2024-01-10T08:00:00'),
modifiedAt: new Date('2024-01-10T08:00:00'),
path: 'İK Politikaları.pdf',
parentId: '',
isReadOnly: true,
childCount: 0,
},
]

View file

@ -1,7 +1,7 @@
import { HrJobPosition, JobLevelEnum } from "../types/hr"; import { JobPositionDto, JobLevelEnum } from "../types/hr";
import { mockDepartments } from "./mockDepartments"; import { mockDepartments } from "./mockDepartments";
export const mockJobPositions: HrJobPosition[] = [ export const mockJobPositions: JobPositionDto[] = [
{ {
id: "1", id: "1",
code: "DEV-001", code: "DEV-001",

View file

@ -1,7 +1,27 @@
import { HrEmployee } from '@/types/hr' import { Address, BankAccount } from '@/types/common'
import {
EmployeeStatusEnum,
EmploymentTypeEnum,
GenderEnum,
HrCostCenter,
HrDisciplinaryAction,
HrEmergencyContact,
HrLeave,
HrPerformanceEvaluation,
HrTraining,
HrWorkSchedule,
JobLevelEnum,
MaritalStatusEnum,
} from '@/types/hr'
export interface IntranetDashboardDto { export interface IntranetDashboardDto {
events: EventDto[]; events: EventDto[]
birthdays: EmployeeDto[]
visitors: VisitorDto[]
reservations: ReservationDto[]
trainings: TrainingDto[]
expenses: ExpensesDto
documents: DocumentDto[]
} }
// Etkinlik // Etkinlik
@ -13,7 +33,7 @@ export interface EventDto {
name: string name: string
description: string description: string
place: string place: string
organizer: HrEmployee organizer: EmployeeDto
participants: number participants: number
photos: string[] photos: string[]
comments: EventCommentDto[] comments: EventCommentDto[]
@ -24,8 +44,183 @@ export interface EventDto {
// Etkinlik Yorumu // Etkinlik Yorumu
export interface EventCommentDto { export interface EventCommentDto {
id: string id: string
author: HrEmployee author: EmployeeDto
content: string content: string
creationTime: Date creationTime: Date
likes: number likes: number
} }
export interface EmployeeDto {
// İnsan Kaynakları Çalışanı
id: string
code: string
firstName: string
lastName: string
fullName: string
email: string
phone?: string
personalPhone?: string
avatar?: string // Avatar URL
nationalId: string
birthDate: Date
gender: GenderEnum
maritalStatus: MaritalStatusEnum
address: Address
emergencyContact: HrEmergencyContact
hireDate: Date
terminationDate?: Date
employmentType: EmploymentTypeEnum
jobPositionId: string
jobPosition?: JobPositionDto
departmentId: string
department?: DepartmentDto
managerId?: string
manager?: EmployeeDto
baseSalary: number
currency: string
payrollGroup: string
bankAccountId: string
bankAccount?: BankAccount
workLocation: string
workSchedule?: HrWorkSchedule
badgeNumber?: string
employeeStatus: EmployeeStatusEnum
isActive: boolean
leaves: HrLeave[]
evaluations: HrPerformanceEvaluation[]
trainings: HrTraining[]
disciplinaryActions: HrDisciplinaryAction[]
creationTime: Date
lastModificationTime: Date
}
export interface DepartmentDto {
// İnsan Kaynakları Departmanı
id: string
code: string
name: string
description?: string
parentDepartmentId?: string
parentDepartment?: DepartmentDto
subDepartments: DepartmentDto[]
managerId?: string
manager?: EmployeeDto
costCenterId?: string
costCenter?: HrCostCenter
budget: number
isActive: boolean
creationTime: Date
lastModificationTime: Date
}
export interface JobPositionDto {
// İnsan Kaynakları İş Pozisyonu
id: string
code: string
name: string
description?: string
departmentId: string
department?: DepartmentDto
level: JobLevelEnum
minSalary: number
maxSalary: number
currency: string
requiredSkills: string[]
responsibilities: string[]
qualifications: string[]
isActive: boolean
employees: EmployeeDto[]
creationTime: Date
lastModificationTime: Date
}
// Ziyaretçi
export interface VisitorDto {
id: string
fullName: string
companyName: string
email: string
phone: string
purpose: string
visitDate: Date
checkIn?: Date
checkOut?: Date
employeeId: string
employee: EmployeeDto
status: 'scheduled' | 'checked-in' | 'checked-out' | 'cancelled'
badgeNumber?: string
photo?: string
}
// Rezervasyon
export interface ReservationDto {
id: string
type: 'room' | 'vehicle' | 'equipment'
resourceName: string
bookedBy: EmployeeDto
startDate: Date
endDate: Date
purpose: string
status: 'pending' | 'approved' | 'rejected' | 'completed'
participants?: number
notes?: string
}
// Eğitim
export interface TrainingDto {
id: string
title: string
description: string
instructor: string
category: 'technical' | 'soft-skills' | 'management' | 'compliance' | 'other'
type: 'online' | 'classroom' | 'hybrid'
duration: number // saat
startDate: Date
endDate: Date
maxParticipants: number
enrolled: number
status: 'upcoming' | 'ongoing' | 'completed'
location?: string
thumbnail?: string
}
// Harcama
export interface ExpensesDto {
totalRequested: number
totalApproved: number
last5Expenses: ExpenseDto[]
}
// Harcama
export interface ExpenseDto {
id: string
employee: EmployeeDto
category: 'travel' | 'meal' | 'accommodation' | 'transport' | 'other'
amount: number
currency: string
date: Date
description: string
project?: string
receipts: { name: string; url: string; size: string }[]
status: 'pending' | 'approved' | 'rejected'
approver?: EmployeeDto
approvalDate?: Date
notes?: string
creationTime: Date
}
// Doküman (FileItemDto ile uyumlu)
export interface DocumentDto {
id: string
name: string
type: string // "file" or "folder"
size: number
extension: string
mimeType: string
createdAt: Date
modifiedAt: Date
path: string
parentId: string
isReadOnly: boolean
childCount: number
}

View file

@ -8,8 +8,8 @@ import {
CrmSalesTarget, CrmSalesTarget,
CrmTerritory, CrmTerritory,
} from './crm' } from './crm'
import { HrEmployee } from './hr'
import { SupplierCardTypeEnum, MmSupplierPerformance, SupplierTypeEnum } from './mm' import { SupplierCardTypeEnum, MmSupplierPerformance, SupplierTypeEnum } from './mm'
import { EmployeeDto } from '@/proxy/intranet/models'
export interface DashboardStats { export interface DashboardStats {
// Gösterge Paneli İstatistikleri // Gösterge Paneli İstatistikleri
@ -107,7 +107,7 @@ export interface Team {
name: string name: string
description?: string description?: string
managerId: string managerId: string
manager?: HrEmployee manager?: EmployeeDto
members: TeamMember[] members: TeamMember[]
territories?: CrmTerritory[] territories?: CrmTerritory[]
targets?: CrmSalesTarget[] targets?: CrmSalesTarget[]
@ -122,7 +122,7 @@ export interface TeamMember {
id: string id: string
teamId: string teamId: string
employeeId: string employeeId: string
employee?: HrEmployee employee?: EmployeeDto
role: TeamRoleEnum role: TeamRoleEnum
joinDate: Date joinDate: Date
isActive: boolean isActive: boolean

View file

@ -1,5 +1,5 @@
import { Address, BusinessParty, Contact, PaymentTerms, PriorityEnum } from './common' import { Address, BusinessParty, Contact, PaymentTerms, PriorityEnum } from './common'
import { HrEmployee } from './hr' import { EmployeeDto } from './hr'
import { MmDelivery, MmMaterial, MmUnit } from './mm' import { MmDelivery, MmMaterial, MmUnit } from './mm'
export interface CrmSalesOrder { export interface CrmSalesOrder {
@ -86,7 +86,7 @@ export interface CrmOpportunity {
expectedCloseDate: Date expectedCloseDate: Date
actualCloseDate?: Date actualCloseDate?: Date
assignedTo: string assignedTo: string
assigned?: HrEmployee assigned?: EmployeeDto
teamId?: string teamId?: string
leadSource: LeadSourceEnum leadSource: LeadSourceEnum
campaignId?: string campaignId?: string
@ -115,7 +115,7 @@ export interface CrmActivity {
endTime?: Date endTime?: Date
duration?: number // minutes duration?: number // minutes
assignedTo: string assignedTo: string
assigned?: HrEmployee assigned?: EmployeeDto
participants: string[] participants: string[]
status: ActivityStatusEnum status: ActivityStatusEnum
priority: PriorityEnum priority: PriorityEnum

View file

@ -1,49 +1,6 @@
import { DepartmentDto, EmployeeDto, JobPositionDto } from '@/proxy/intranet/models'
import { Address, BankAccount } from './common' import { Address, BankAccount } from './common'
export interface HrEmployee {
// İnsan Kaynakları Çalışanı
id: string
code: string
firstName: string
lastName: string
fullName: string
email: string
phone?: string
personalPhone?: string
avatar?: string // Avatar URL
nationalId: string
birthDate: Date
gender: GenderEnum
maritalStatus: MaritalStatusEnum
address: Address
emergencyContact: HrEmergencyContact
hireDate: Date
terminationDate?: Date
employmentType: EmploymentTypeEnum
jobPositionId: string
jobPosition?: HrJobPosition
departmentId: string
department?: HrDepartment
managerId?: string
manager?: HrEmployee
baseSalary: number
currency: string
payrollGroup: string
bankAccountId: string
bankAccount?: BankAccount
workLocation: string
workSchedule?: HrWorkSchedule
badgeNumber?: string
employeeStatus: EmployeeStatusEnum
isActive: boolean
leaves: HrLeave[]
evaluations: HrPerformanceEvaluation[]
trainings: HrTraining[]
disciplinaryActions: HrDisciplinaryAction[]
creationTime: Date
lastModificationTime: Date
}
export interface HrCostCenter { export interface HrCostCenter {
// İnsan Kaynakları Masraf Merkezi // İnsan Kaynakları Masraf Merkezi
id: string id: string
@ -54,9 +11,9 @@ export interface HrCostCenter {
parentCostCenter?: HrCostCenter parentCostCenter?: HrCostCenter
subCostCenters: HrCostCenter[] subCostCenters: HrCostCenter[]
responsibleEmployeeId?: string responsibleEmployeeId?: string
responsibleEmployee?: HrEmployee responsibleEmployee?: EmployeeDto
departmentId?: string departmentId?: string
department?: HrDepartment department?: DepartmentDto
costCenterType: CostCenterType costCenterType: CostCenterType
budgetedAmount: number budgetedAmount: number
actualAmount: number actualAmount: number
@ -67,51 +24,11 @@ export interface HrCostCenter {
lastModificationTime: Date lastModificationTime: Date
} }
export interface HrDepartment {
// İnsan Kaynakları Departmanı
id: string
code: string
name: string
description?: string
parentDepartmentId?: string
parentDepartment?: HrDepartment
subDepartments: HrDepartment[]
managerId?: string
manager?: HrEmployee
costCenterId?: string
costCenter?: HrCostCenter
budget: number
isActive: boolean
creationTime: Date
lastModificationTime: Date
}
export interface HrJobPosition {
// İnsan Kaynakları İş Pozisyonu
id: string
code: string
name: string
description?: string
departmentId: string
department?: HrDepartment
level: JobLevelEnum
minSalary: number
maxSalary: number
currency: string
requiredSkills: string[]
responsibilities: string[]
qualifications: string[]
isActive: boolean
employees: HrEmployee[]
creationTime: Date
lastModificationTime: Date
}
export interface HrLeave { export interface HrLeave {
// İnsan Kaynakları İzni // İnsan Kaynakları İzni
id: string id: string
employeeId: string employeeId: string
employee?: HrEmployee employee?: EmployeeDto
leaveType: LeaveTypeEnum leaveType: LeaveTypeEnum
startDate: Date startDate: Date
endDate: Date endDate: Date
@ -132,9 +49,9 @@ export interface HrPerformanceEvaluation {
// İnsan Kaynakları Performans Değerlendirmesi // İnsan Kaynakları Performans Değerlendirmesi
id: string id: string
employeeId: string employeeId: string
employee?: HrEmployee employee?: EmployeeDto
evaluatorId: string evaluatorId: string
evaluator?: HrEmployee evaluator?: EmployeeDto
evaluationPeriod: string evaluationPeriod: string
evaluationType: EvaluationTypeEnum evaluationType: EvaluationTypeEnum
overallRating: number overallRating: number
@ -202,7 +119,7 @@ export interface HrTrainingParticipant {
id: string id: string
trainingId: string trainingId: string
employeeId: string employeeId: string
employee?: HrEmployee employee?: EmployeeDto
enrollmentDate: Date enrollmentDate: Date
completionDate?: Date completionDate?: Date
status: ParticipationStatusEnum status: ParticipationStatusEnum
@ -236,7 +153,7 @@ export interface HrDisciplinaryAction {
// İnsan Kaynakları Disiplin Cezası // İnsan Kaynakları Disiplin Cezası
id: string id: string
employeeId: string employeeId: string
employee?: HrEmployee employee?: EmployeeDto
actionType: DisciplinaryActionTypeEnum actionType: DisciplinaryActionTypeEnum
reason: string reason: string
description: string description: string
@ -272,7 +189,7 @@ export interface HrOvertime {
// İnsan Kaynakları Fazla Mesai // İnsan Kaynakları Fazla Mesai
id: string id: string
employeeId: string employeeId: string
employee?: HrEmployee employee?: EmployeeDto
date: Date date: Date
startTime: string startTime: string
endTime: string endTime: string
@ -280,7 +197,7 @@ export interface HrOvertime {
reason: string reason: string
status: LeaveStatusEnum status: LeaveStatusEnum
approvedBy?: string approvedBy?: string
approver?: HrEmployee approver?: EmployeeDto
rate?: number rate?: number
amount?: number amount?: number
creationTime: Date creationTime: Date
@ -291,7 +208,7 @@ export interface HrPayroll {
// İnsan Kaynakları Maaş Bordrosu // İnsan Kaynakları Maaş Bordrosu
id: string id: string
employeeId: string employeeId: string
employee?: HrEmployee employee?: EmployeeDto
period: string period: string
baseSalary: number baseSalary: number
allowances: HrPayrollAllowance[] // İnsan Kaynakları Maaş Ek Ödemeleri allowances: HrPayrollAllowance[] // İnsan Kaynakları Maaş Ek Ödemeleri
@ -346,7 +263,7 @@ export interface HrOrganizationChart {
// İnsan Kaynakları Organizasyon Şeması // İnsan Kaynakları Organizasyon Şeması
id: string id: string
employeeId: string employeeId: string
employee?: HrEmployee employee?: EmployeeDto
parentId?: string parentId?: string
parent?: HrOrganizationChart parent?: HrOrganizationChart
children?: HrOrganizationChart[] children?: HrOrganizationChart[]
@ -359,7 +276,7 @@ export interface HrEmployeeBadge {
// İnsan Kaynakları Çalışan Rozeti // İnsan Kaynakları Çalışan Rozeti
id: string id: string
employeeId: string employeeId: string
employee?: HrEmployee employee?: EmployeeDto
badgeId: string badgeId: string
badge?: HrBadge badge?: HrBadge
earnedDate: Date earnedDate: Date
@ -454,9 +371,9 @@ export interface HrEvaluation360Participant {
id: string id: string
campaignId: string campaignId: string
evaluatedEmployeeId: string // Değerlendirilen kişi evaluatedEmployeeId: string // Değerlendirilen kişi
evaluatedEmployee?: HrEmployee evaluatedEmployee?: EmployeeDto
evaluatorId: string // Değerlendiren kişi evaluatorId: string // Değerlendiren kişi
evaluator?: HrEmployee evaluator?: EmployeeDto
evaluatorType: AssessorTypeEnum evaluatorType: AssessorTypeEnum
status: ParticipantStatusEnum status: ParticipantStatusEnum
invitedDate: Date invitedDate: Date
@ -484,7 +401,7 @@ export interface HrEvaluation360Result {
id: string id: string
campaignId: string campaignId: string
employeeId: string employeeId: string
employee?: HrEmployee employee?: EmployeeDto
participants: HrEvaluation360Participant[] // Bu sonuca katkıda bulunan değerlendiriciler participants: HrEvaluation360Participant[] // Bu sonuca katkıda bulunan değerlendiriciler
overallScore: number overallScore: number
maxPossibleScore: number maxPossibleScore: number

View file

@ -1,4 +1,4 @@
import { HrEmployee } from './hr' import { EmployeeDto } from "@/proxy/intranet/models"
// Duyuru // Duyuru
export interface Announcement { export interface Announcement {
@ -7,7 +7,7 @@ export interface Announcement {
content: string content: string
excerpt: string excerpt: string
category: 'general' | 'hr' | 'it' | 'event' | 'urgent' category: 'general' | 'hr' | 'it' | 'event' | 'urgent'
author: HrEmployee author: EmployeeDto
publishDate: Date publishDate: Date
expiryDate?: Date expiryDate?: Date
isPinned: boolean isPinned: boolean
@ -17,32 +17,14 @@ export interface Announcement {
imageUrl?: string imageUrl?: string
} }
// Harcama
export interface ExpenseRequest {
id: string
employee: HrEmployee
category: 'travel' | 'meal' | 'accommodation' | 'transport' | 'other'
amount: number
currency: string
date: Date
description: string
project?: string
receipts: { name: string; url: string; size: string }[]
status: 'pending' | 'approved' | 'rejected'
approver?: HrEmployee
approvalDate?: Date
notes?: string
creationTime: Date
}
// Görev // Görev
export interface Task { export interface Task {
id: string id: string
title: string title: string
description: string description: string
project: string project: string
assignedTo: HrEmployee[] assignedTo: EmployeeDto[]
assignedBy: HrEmployee assignedBy: EmployeeDto
priority: 'low' | 'medium' | 'high' | 'urgent' priority: 'low' | 'medium' | 'high' | 'urgent'
status: 'todo' | 'in-progress' | 'review' | 'done' status: 'todo' | 'in-progress' | 'review' | 'done'
dueDate: Date dueDate: Date
@ -52,45 +34,10 @@ export interface Task {
comments: number comments: number
} }
// Doküman
export interface Document {
id: string
name: string
type: 'pdf' | 'doc' | 'xls' | 'ppt' | 'other'
category: 'policy' | 'procedure' | 'form' | 'template' | 'report' | 'other'
size: string
uploadedBy: HrEmployee
uploadDate: Date
version: string
url: string
description: string
departments: string[]
downloadCount: number
tags: string[]
}
// Eğitim
export interface Training {
id: string
title: string
description: string
instructor: string
category: 'technical' | 'soft-skills' | 'management' | 'compliance' | 'other'
type: 'online' | 'classroom' | 'hybrid'
duration: number // saat
startDate: Date
endDate: Date
maxParticipants: number
enrolled: number
status: 'upcoming' | 'ongoing' | 'completed'
location?: string
thumbnail?: string
}
// Sertifika // Sertifika
export interface Certificate { export interface Certificate {
id: string id: string
employee: HrEmployee employee: EmployeeDto
trainingTitle: string trainingTitle: string
issueDate: Date issueDate: Date
expiryDate?: Date expiryDate?: Date
@ -98,20 +45,6 @@ export interface Certificate {
score?: number score?: number
} }
// Rezervasyon
export interface Reservation {
id: string
type: 'room' | 'vehicle' | 'equipment'
resourceName: string
bookedBy: HrEmployee
startDate: Date
endDate: Date
purpose: string
status: 'pending' | 'approved' | 'rejected' | 'completed'
participants?: number
notes?: string
}
// Yemek Menüsü // Yemek Menüsü
export interface MealMenu { export interface MealMenu {
id: string id: string
@ -141,7 +74,7 @@ export interface Survey {
id: string id: string
title: string title: string
description: string description: string
creatorId: HrEmployee creatorId: EmployeeDto
creationTime: Date creationTime: Date
deadline: Date deadline: Date
questions: SurveyQuestion[] questions: SurveyQuestion[]
@ -190,33 +123,16 @@ export interface SurveyAnswer {
value: string | number | string[] value: string | number | string[]
} }
// Ziyaretçi
export interface Visitor {
id: string
fullName: string
company: string
email: string
phone: string
visitDate: Date
checkIn?: Date
checkOut?: Date
host: HrEmployee
purpose: string
status: 'scheduled' | 'checked-in' | 'checked-out' | 'cancelled'
badgeNumber?: string
photo?: string
}
// Sosyal Duvar - Ana Interface // Sosyal Duvar - Ana Interface
export interface SocialPost { export interface SocialPost {
id: string id: string
creator: HrEmployee creator: EmployeeDto
content: string content: string
locationJson?: string locationJson?: string
media?: SocialMedia media?: SocialMedia
likeCount: number likeCount: number
isLiked: boolean isLiked: boolean
likeUsers: HrEmployee[] likeUsers: EmployeeDto[]
comments: SocialComment[] comments: SocialComment[]
isOwnPost: boolean isOwnPost: boolean
creationTime: Date creationTime: Date
@ -247,7 +163,7 @@ export interface SocialPollOption {
// Sosyal Duvar - Comment Interface // Sosyal Duvar - Comment Interface
export interface SocialComment { export interface SocialComment {
id: string id: string
creator: HrEmployee creator: EmployeeDto
content: string content: string
creationTime: Date creationTime: Date
} }

View file

@ -1,5 +1,5 @@
import { Address, BusinessParty, PaymentTerms, PriorityEnum } from './common' import { Address, BusinessParty, PaymentTerms, PriorityEnum } from './common'
import { HrDepartment } from './hr' import { DepartmentDto } from './hr'
import { WmWarehouse, WmZone, WmLocation } from './wm' import { WmWarehouse, WmZone, WmLocation } from './wm'
export interface MmMaterial { export interface MmMaterial {
@ -460,7 +460,7 @@ export interface MmApprovalWorkflow {
id: string id: string
name: string name: string
departmentId: string departmentId: string
department?: HrDepartment department?: DepartmentDto
requestType: RequestTypeEnum requestType: RequestTypeEnum
amountThreshold: number amountThreshold: number
approvalLevels: MmApprovalWorkflowLevel[] approvalLevels: MmApprovalWorkflowLevel[]

View file

@ -1,5 +1,5 @@
import { PriorityEnum } from './common' import { PriorityEnum } from './common'
import { HrDepartment } from './hr' import { DepartmentDto } from './hr'
import { MmMaterial } from './mm' import { MmMaterial } from './mm'
export type CalendarView = 'month' | 'week' | 'day' export type CalendarView = 'month' | 'week' | 'day'
@ -19,7 +19,7 @@ export interface PmWorkCenter {
warrantyExpiry?: Date warrantyExpiry?: Date
location: string location: string
departmentId: string departmentId: string
department?: HrDepartment department?: DepartmentDto
status: WorkCenterStatusEnum status: WorkCenterStatusEnum
criticality: CriticalityLevelEnum criticality: CriticalityLevelEnum
specifications: PmWorkCenterSpecification[] specifications: PmWorkCenterSpecification[]

View file

@ -1,5 +1,5 @@
import { BusinessParty, PriorityEnum } from './common' import { BusinessParty, PriorityEnum } from './common'
import { HrEmployee } from './hr' import { EmployeeDto } from './hr'
export interface PsProject { export interface PsProject {
// Proje // Proje
@ -13,7 +13,7 @@ export interface PsProject {
customerId?: string customerId?: string
customer?: BusinessParty customer?: BusinessParty
projectManagerId: string projectManagerId: string
projectManager?: HrEmployee projectManager?: EmployeeDto
startDate: Date startDate: Date
endDate: Date endDate: Date
actualStartDate?: Date actualStartDate?: Date
@ -71,7 +71,7 @@ export interface PsProjectTask {
status: TaskStatusEnum status: TaskStatusEnum
priority: PriorityEnum priority: PriorityEnum
assignedTo?: string assignedTo?: string
assignee?: HrEmployee assignee?: EmployeeDto
startDate: Date startDate: Date
endDate: Date endDate: Date
actualStartDate?: Date actualStartDate?: Date
@ -183,7 +183,7 @@ export interface PsTaskDailyUpdate {
taskId: string taskId: string
task?: PsProjectTask task?: PsProjectTask
employeeId: string employeeId: string
employee?: HrEmployee employee?: EmployeeDto
date: Date date: Date
hoursWorked: number hoursWorked: number
description: string description: string
@ -205,7 +205,7 @@ export interface PsGanttTask {
startDate: Date startDate: Date
endDate: Date endDate: Date
progress: number progress: number
assignee?: HrEmployee assignee?: EmployeeDto
parentId?: string parentId?: string
children?: PsGanttTask[] children?: PsGanttTask[]
dependencies?: string[] dependencies?: string[]

View file

@ -1,6 +1,6 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
import { FaSave, FaTimes } from "react-icons/fa"; import { FaSave, FaTimes } from "react-icons/fa";
import { HrDepartment } from "../../../types/hr"; import { DepartmentDto } from "../../../types/hr";
import { mockEmployees } from "../../../mocks/mockEmployees"; import { mockEmployees } from "../../../mocks/mockEmployees";
import { mockDepartments } from "../../../mocks/mockDepartments"; import { mockDepartments } from "../../../mocks/mockDepartments";
import { mockCostCenters } from "../../../mocks/mockCostCenters"; import { mockCostCenters } from "../../../mocks/mockCostCenters";
@ -8,8 +8,8 @@ import { mockCostCenters } from "../../../mocks/mockCostCenters";
interface DepartmentFormModalProps { interface DepartmentFormModalProps {
isOpen: boolean; isOpen: boolean;
onClose: () => void; onClose: () => void;
onSave: (department: Partial<HrDepartment>) => void; onSave: (department: Partial<DepartmentDto>) => void;
department?: HrDepartment; department?: DepartmentDto;
title: string; title: string;
} }

View file

@ -10,7 +10,7 @@ import {
FaList, FaList,
FaTh, FaTh,
} from 'react-icons/fa' } from 'react-icons/fa'
import { HrDepartment } from '../../../types/hr' import { DepartmentDto } from '../../../types/hr'
import DataTable, { Column } from '../../../components/common/DataTable' import DataTable, { Column } from '../../../components/common/DataTable'
import { mockDepartments } from '../../../mocks/mockDepartments' import { mockDepartments } from '../../../mocks/mockDepartments'
import { mockEmployees } from '../../../mocks/mockEmployees' import { mockEmployees } from '../../../mocks/mockEmployees'
@ -21,7 +21,7 @@ import Widget from '../../../components/common/Widget'
import { Container } from '@/components/shared' import { Container } from '@/components/shared'
const DepartmentManagement: React.FC = () => { const DepartmentManagement: React.FC = () => {
const [departments, setDepartments] = useState<HrDepartment[]>(mockDepartments) const [departments, setDepartments] = useState<DepartmentDto[]>(mockDepartments)
const [searchTerm, setSearchTerm] = useState('') const [searchTerm, setSearchTerm] = useState('')
const [selectedParent, setSelectedParent] = useState<string>('all') const [selectedParent, setSelectedParent] = useState<string>('all')
const [viewMode, setViewMode] = useState<'list' | 'cards'>('list') const [viewMode, setViewMode] = useState<'list' | 'cards'>('list')
@ -29,7 +29,7 @@ const DepartmentManagement: React.FC = () => {
// Modal states // Modal states
const [isFormModalOpen, setIsFormModalOpen] = useState(false) const [isFormModalOpen, setIsFormModalOpen] = useState(false)
const [isViewModalOpen, setIsViewModalOpen] = useState(false) const [isViewModalOpen, setIsViewModalOpen] = useState(false)
const [selectedDepartment, setSelectedDepartment] = useState<HrDepartment | undefined>() const [selectedDepartment, setSelectedDepartment] = useState<DepartmentDto | undefined>()
const [modalTitle, setModalTitle] = useState('') const [modalTitle, setModalTitle] = useState('')
const handleAdd = () => { const handleAdd = () => {
@ -38,13 +38,13 @@ const DepartmentManagement: React.FC = () => {
setIsFormModalOpen(true) setIsFormModalOpen(true)
} }
const handleEdit = (department: HrDepartment) => { const handleEdit = (department: DepartmentDto) => {
setSelectedDepartment(department) setSelectedDepartment(department)
setModalTitle('Departman Düzenle') setModalTitle('Departman Düzenle')
setIsFormModalOpen(true) setIsFormModalOpen(true)
} }
const handleView = (department: HrDepartment) => { const handleView = (department: DepartmentDto) => {
setSelectedDepartment(department) setSelectedDepartment(department)
setIsViewModalOpen(true) setIsViewModalOpen(true)
} }
@ -55,7 +55,7 @@ const DepartmentManagement: React.FC = () => {
} }
} }
const handleSave = (departmentData: Partial<HrDepartment>) => { const handleSave = (departmentData: Partial<DepartmentDto>) => {
if (selectedDepartment) { if (selectedDepartment) {
// Edit existing department // Edit existing department
setDepartments((prev) => setDepartments((prev) =>
@ -67,13 +67,13 @@ const DepartmentManagement: React.FC = () => {
) )
} else { } else {
// Add new department // Add new department
const newDepartment: HrDepartment = { const newDepartment: DepartmentDto = {
id: `dept_${Date.now()}`, id: `dept_${Date.now()}`,
...departmentData, ...departmentData,
subDepartments: [], subDepartments: [],
creationTime: new Date(), creationTime: new Date(),
lastModificationTime: new Date(), lastModificationTime: new Date(),
} as HrDepartment } as DepartmentDto
setDepartments((prev) => [...prev, newDepartment]) setDepartments((prev) => [...prev, newDepartment])
} }
setIsFormModalOpen(false) setIsFormModalOpen(false)
@ -89,7 +89,7 @@ const DepartmentManagement: React.FC = () => {
setSelectedDepartment(undefined) setSelectedDepartment(undefined)
} }
const handleEditFromView = (department: HrDepartment) => { const handleEditFromView = (department: DepartmentDto) => {
setIsViewModalOpen(false) setIsViewModalOpen(false)
handleEdit(department) handleEdit(department)
} }
@ -117,7 +117,7 @@ const DepartmentManagement: React.FC = () => {
return true return true
}) })
const columns: Column<HrDepartment>[] = [ const columns: Column<DepartmentDto>[] = [
{ {
key: 'code', key: 'code',
header: 'Departman Kodu', header: 'Departman Kodu',
@ -131,17 +131,17 @@ const DepartmentManagement: React.FC = () => {
{ {
key: 'parentDepartment', key: 'parentDepartment',
header: 'Üst Departman', header: 'Üst Departman',
render: (department: HrDepartment) => department.parentDepartment?.name || '-', render: (department: DepartmentDto) => department.parentDepartment?.name || '-',
}, },
{ {
key: 'manager', key: 'manager',
header: 'Yönetici', header: 'Yönetici',
render: (department: HrDepartment) => department.manager?.fullName || '-', render: (department: DepartmentDto) => department.manager?.fullName || '-',
}, },
{ {
key: 'employeeCount', key: 'employeeCount',
header: 'Personel Sayısı', header: 'Personel Sayısı',
render: (department: HrDepartment) => ( render: (department: DepartmentDto) => (
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
<FaUsers className="w-4 h-4 text-gray-500" /> <FaUsers className="w-4 h-4 text-gray-500" />
<span>{mockEmployees.filter((a) => a.departmentId == department.id).length || 0}</span> <span>{mockEmployees.filter((a) => a.departmentId == department.id).length || 0}</span>
@ -151,7 +151,7 @@ const DepartmentManagement: React.FC = () => {
{ {
key: 'costCenter', key: 'costCenter',
header: 'Maliyet Merkezi', header: 'Maliyet Merkezi',
render: (department: HrDepartment) => ( render: (department: DepartmentDto) => (
<div className="flex flex-col"> <div className="flex flex-col">
<span className="font-medium">{department.costCenter?.code || '-'}</span> <span className="font-medium">{department.costCenter?.code || '-'}</span>
<span className="text-xs text-gray-500">{department.costCenter?.name || '-'}</span> <span className="text-xs text-gray-500">{department.costCenter?.name || '-'}</span>
@ -161,7 +161,7 @@ const DepartmentManagement: React.FC = () => {
{ {
key: 'budget', key: 'budget',
header: 'Bütçe', header: 'Bütçe',
render: (department: HrDepartment) => ( render: (department: DepartmentDto) => (
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
<FaDollarSign className="w-4 h-4 text-gray-500" /> <FaDollarSign className="w-4 h-4 text-gray-500" />
<span>{department.budget ? `${department.budget.toLocaleString()}` : '-'}</span> <span>{department.budget ? `${department.budget.toLocaleString()}` : '-'}</span>
@ -171,7 +171,7 @@ const DepartmentManagement: React.FC = () => {
{ {
key: 'status', key: 'status',
header: 'Durum', header: 'Durum',
render: (department: HrDepartment) => ( render: (department: DepartmentDto) => (
<span <span
className={`px-2 py-1 text-xs font-medium rounded-full ${ className={`px-2 py-1 text-xs font-medium rounded-full ${
department.isActive ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800' department.isActive ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'
@ -184,7 +184,7 @@ const DepartmentManagement: React.FC = () => {
{ {
key: 'actions', key: 'actions',
header: 'İşlemler', header: 'İşlemler',
render: (department: HrDepartment) => ( render: (department: DepartmentDto) => (
<div className="flex gap-2"> <div className="flex gap-2">
<button <button
onClick={() => handleView(department)} onClick={() => handleView(department)}

View file

@ -8,14 +8,14 @@ import {
FaCalendar, FaCalendar,
FaEdit, FaEdit,
} from "react-icons/fa"; } from "react-icons/fa";
import { HrDepartment } from "../../../types/hr"; import { DepartmentDto } from "../../../types/hr";
import { mockEmployees } from "../../../mocks/mockEmployees"; import { mockEmployees } from "../../../mocks/mockEmployees";
interface DepartmentViewModalProps { interface DepartmentViewModalProps {
isOpen: boolean; isOpen: boolean;
onClose: () => void; onClose: () => void;
department: HrDepartment | null; department: DepartmentDto | null;
onEdit?: (department: HrDepartment) => void; onEdit?: (department: DepartmentDto) => void;
} }
const DepartmentViewModal: React.FC<DepartmentViewModalProps> = ({ const DepartmentViewModal: React.FC<DepartmentViewModalProps> = ({

View file

@ -10,22 +10,22 @@ import {
FaTrash, FaTrash,
FaPlus, FaPlus,
} from 'react-icons/fa' } from 'react-icons/fa'
import { HrEmployee, EmployeeStatusEnum } from '../../../types/hr' import { EmployeeDto, EmployeeStatusEnum } from '../../../types/hr'
import { mockEmployees } from '../../../mocks/mockEmployees' import { mockEmployees } from '../../../mocks/mockEmployees'
import { getEmployeeStatusColor, getEmployeeStatusText } from '../../../utils/erp' import { getEmployeeStatusColor, getEmployeeStatusText } from '../../../utils/erp'
import { Container } from '@/components/shared' import { Container } from '@/components/shared'
const EmployeeCards: React.FC = () => { const EmployeeCards: React.FC = () => {
const [employees] = useState<HrEmployee[]>(mockEmployees) const [employees] = useState<EmployeeDto[]>(mockEmployees)
const [selectedDepartment, setSelectedDepartment] = useState<string>('all') const [selectedDepartment, setSelectedDepartment] = useState<string>('all')
const [selectedStatus, setSelectedStatus] = useState<string>('all') const [selectedStatus, setSelectedStatus] = useState<string>('all')
const handleEdit = (employee: HrEmployee) => { const handleEdit = (employee: EmployeeDto) => {
console.log('Edit employee:', employee) console.log('Edit employee:', employee)
// Implement edit functionality // Implement edit functionality
} }
const handleView = (employee: HrEmployee) => { const handleView = (employee: EmployeeDto) => {
console.log('View employee:', employee) console.log('View employee:', employee)
// Implement view functionality // Implement view functionality
} }

View file

@ -14,13 +14,13 @@ import LoadingSpinner from '../../../components/common/LoadingSpinner'
import { mockDepartments } from '../../../mocks/mockDepartments' import { mockDepartments } from '../../../mocks/mockDepartments'
import { mockJobPositions } from '../../../mocks/mockJobPositions' import { mockJobPositions } from '../../../mocks/mockJobPositions'
import { import {
HrDepartment, DepartmentDto,
HrEmployee, EmployeeDto,
EmployeeStatusEnum, EmployeeStatusEnum,
EmploymentTypeEnum, EmploymentTypeEnum,
GenderEnum, GenderEnum,
JobLevelEnum, JobLevelEnum,
HrJobPosition, JobPositionDto,
MaritalStatusEnum, MaritalStatusEnum,
} from '../../../types/hr' } from '../../../types/hr'
import { mockEmployees } from '../../../mocks/mockEmployees' import { mockEmployees } from '../../../mocks/mockEmployees'
@ -48,11 +48,11 @@ const EmployeeForm: React.FC = () => {
const [loading, setLoading] = useState(false) const [loading, setLoading] = useState(false)
const [saving, setSaving] = useState(false) const [saving, setSaving] = useState(false)
const [errors, setErrors] = useState<ValidationErrors>({}) const [errors, setErrors] = useState<ValidationErrors>({})
const [departments, setDepartments] = useState<HrDepartment[]>([]) const [departments, setDepartments] = useState<DepartmentDto[]>([])
const [jobPositions, setJobPositions] = useState<HrJobPosition[]>([]) const [jobPositions, setJobPositions] = useState<JobPositionDto[]>([])
const [managers, setManagers] = useState<HrEmployee[]>([]) const [managers, setManagers] = useState<EmployeeDto[]>([])
const [formData, setFormData] = useState<HrEmployee>({ const [formData, setFormData] = useState<EmployeeDto>({
id: '', id: '',
code: '', code: '',
firstName: '', firstName: '',
@ -187,7 +187,7 @@ const EmployeeForm: React.FC = () => {
return Object.keys(newErrors).length === 0 return Object.keys(newErrors).length === 0
} }
const handleInputChange = (field: keyof HrEmployee, value: string | number | boolean) => { const handleInputChange = (field: keyof EmployeeDto, value: string | number | boolean) => {
setFormData((prev) => ({ setFormData((prev) => ({
...prev, ...prev,
[field]: value, [field]: value,

View file

@ -20,7 +20,7 @@ import {
FaBriefcase, FaBriefcase,
} from 'react-icons/fa' } from 'react-icons/fa'
import classNames from 'classnames' import classNames from 'classnames'
import { EmployeeStatusEnum, HrEmployee } from '../../../types/hr' import { EmployeeStatusEnum, EmployeeDto } from '../../../types/hr'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { mockEmployees } from '../../../mocks/mockEmployees' import { mockEmployees } from '../../../mocks/mockEmployees'
import EmployeeView from './EmployeeView' import EmployeeView from './EmployeeView'
@ -45,7 +45,7 @@ const EmployeeList: React.FC = () => {
// Modal states // Modal states
const [isViewModalOpen, setIsViewModalOpen] = useState(false) const [isViewModalOpen, setIsViewModalOpen] = useState(false)
const [selectedEmployee, setSelectedEmployee] = useState<HrEmployee | null>(null) const [selectedEmployee, setSelectedEmployee] = useState<EmployeeDto | null>(null)
const { const {
data: employees, data: employees,
@ -69,7 +69,7 @@ const EmployeeList: React.FC = () => {
}) })
// Modal handlers // Modal handlers
const handleViewEmployee = (employee: HrEmployee) => { const handleViewEmployee = (employee: EmployeeDto) => {
setSelectedEmployee(employee) setSelectedEmployee(employee)
setIsViewModalOpen(true) setIsViewModalOpen(true)
} }
@ -79,7 +79,7 @@ const EmployeeList: React.FC = () => {
setSelectedEmployee(null) setSelectedEmployee(null)
} }
const handleEditFromView = (employee: HrEmployee) => { const handleEditFromView = (employee: EmployeeDto) => {
setIsViewModalOpen(false) setIsViewModalOpen(false)
// Navigate to edit page - you can replace this with a modal if preferred // Navigate to edit page - you can replace this with a modal if preferred
window.location.href = ROUTES_ENUM.protected.hr.employeesEdit.replace(':id', employee.id) window.location.href = ROUTES_ENUM.protected.hr.employeesEdit.replace(':id', employee.id)

View file

@ -19,7 +19,7 @@ import {
FaAward, FaAward,
FaHistory, FaHistory,
} from "react-icons/fa"; } from "react-icons/fa";
import { HrEmployee } from "../../../types/hr"; import { EmployeeDto } from "../../../types/hr";
import { import {
getEmployeeStatusColor, getEmployeeStatusColor,
getEmployeeStatusIcon, getEmployeeStatusIcon,
@ -29,8 +29,8 @@ import {
interface EmployeeViewModalProps { interface EmployeeViewModalProps {
isOpen: boolean; isOpen: boolean;
onClose: () => void; onClose: () => void;
employee: HrEmployee | null; employee: EmployeeDto | null;
onEdit?: (employee: HrEmployee) => void; onEdit?: (employee: EmployeeDto) => void;
} }
const EmployeeViewModal: React.FC<EmployeeViewModalProps> = ({ const EmployeeViewModal: React.FC<EmployeeViewModalProps> = ({

View file

@ -1,6 +1,6 @@
import React, { useState, useEffect } from 'react' import React, { useState, useEffect } from 'react'
import { FaSave, FaTimes, FaPlus, FaTrash } from 'react-icons/fa' import { FaSave, FaTimes, FaPlus, FaTrash } from 'react-icons/fa'
import { HrJobPosition, JobLevelEnum } from '../../../types/hr' import { JobPositionDto, JobLevelEnum } from '../../../types/hr'
import { mockDepartments } from '../../../mocks/mockDepartments' import { mockDepartments } from '../../../mocks/mockDepartments'
import { getJobLevelText } from '@/utils/erp' import { getJobLevelText } from '@/utils/erp'
import { mockCurrencies } from '@/mocks/mockCurrencies' import { mockCurrencies } from '@/mocks/mockCurrencies'
@ -8,8 +8,8 @@ import { mockCurrencies } from '@/mocks/mockCurrencies'
interface JobPositionFormModalProps { interface JobPositionFormModalProps {
isOpen: boolean isOpen: boolean
onClose: () => void onClose: () => void
onSave: (position: Partial<HrJobPosition>) => void onSave: (position: Partial<JobPositionDto>) => void
position?: HrJobPosition position?: JobPositionDto
title: string title: string
} }

View file

@ -7,13 +7,13 @@ import {
FaDollarSign, FaDollarSign,
FaClock, FaClock,
} from "react-icons/fa"; } from "react-icons/fa";
import { HrJobPosition } from "../../../types/hr"; import { JobPositionDto } from "../../../types/hr";
import { getJobLevelColor, getJobLevelText } from "../../../utils/erp"; import { getJobLevelColor, getJobLevelText } from "../../../utils/erp";
interface JobPositionViewModalProps { interface JobPositionViewModalProps {
isOpen: boolean; isOpen: boolean;
onClose: () => void; onClose: () => void;
position: HrJobPosition | null | undefined; position: JobPositionDto | null | undefined;
} }
const JobPositionViewModal: React.FC<JobPositionViewModalProps> = ({ const JobPositionViewModal: React.FC<JobPositionViewModalProps> = ({

View file

@ -11,7 +11,7 @@ import {
FaTh, FaTh,
FaList, FaList,
} from 'react-icons/fa' } from 'react-icons/fa'
import { HrJobPosition, JobLevelEnum } from '../../../types/hr' import { JobPositionDto, JobLevelEnum } from '../../../types/hr'
import DataTable, { Column } from '../../../components/common/DataTable' import DataTable, { Column } from '../../../components/common/DataTable'
import { mockJobPositions } from '../../../mocks/mockJobPositions' import { mockJobPositions } from '../../../mocks/mockJobPositions'
import JobPositionFormModal from './JobPositionFormModal' import JobPositionFormModal from './JobPositionFormModal'
@ -20,7 +20,7 @@ import { getJobLevelColor, getJobLevelText } from '../../../utils/erp'
import { Container } from '@/components/shared' import { Container } from '@/components/shared'
const JobPositions: React.FC = () => { const JobPositions: React.FC = () => {
const [positions, setPositions] = useState<HrJobPosition[]>(mockJobPositions) const [positions, setPositions] = useState<JobPositionDto[]>(mockJobPositions)
const [searchTerm, setSearchTerm] = useState('') const [searchTerm, setSearchTerm] = useState('')
const [selectedLevel, setSelectedLevel] = useState<string>('all') const [selectedLevel, setSelectedLevel] = useState<string>('all')
const [selectedDepartment, setSelectedDepartment] = useState<string>('all') const [selectedDepartment, setSelectedDepartment] = useState<string>('all')
@ -29,7 +29,7 @@ const JobPositions: React.FC = () => {
// Modal states // Modal states
const [isFormModalOpen, setIsFormModalOpen] = useState(false) const [isFormModalOpen, setIsFormModalOpen] = useState(false)
const [isViewModalOpen, setIsViewModalOpen] = useState(false) const [isViewModalOpen, setIsViewModalOpen] = useState(false)
const [selectedPosition, setSelectedPosition] = useState<HrJobPosition | undefined>(undefined) const [selectedPosition, setSelectedPosition] = useState<JobPositionDto | undefined>(undefined)
const [modalTitle, setModalTitle] = useState('') const [modalTitle, setModalTitle] = useState('')
const handleAdd = () => { const handleAdd = () => {
@ -38,13 +38,13 @@ const JobPositions: React.FC = () => {
setIsFormModalOpen(true) setIsFormModalOpen(true)
} }
const handleEdit = (position: HrJobPosition) => { const handleEdit = (position: JobPositionDto) => {
setSelectedPosition(position) setSelectedPosition(position)
setModalTitle('İş Pozisyonu Düzenle') setModalTitle('İş Pozisyonu Düzenle')
setIsFormModalOpen(true) setIsFormModalOpen(true)
} }
const handleView = (position: HrJobPosition) => { const handleView = (position: JobPositionDto) => {
setSelectedPosition(position) setSelectedPosition(position)
setIsViewModalOpen(true) setIsViewModalOpen(true)
} }
@ -55,7 +55,7 @@ const JobPositions: React.FC = () => {
} }
} }
const handleSavePosition = (positionData: Partial<HrJobPosition>) => { const handleSavePosition = (positionData: Partial<JobPositionDto>) => {
if (selectedPosition) { if (selectedPosition) {
// Edit existing position // Edit existing position
const updatedPosition = { const updatedPosition = {
@ -66,13 +66,13 @@ const JobPositions: React.FC = () => {
setPositions(positions.map((p) => (p.id === selectedPosition.id ? updatedPosition : p))) setPositions(positions.map((p) => (p.id === selectedPosition.id ? updatedPosition : p)))
} else { } else {
// Add new position // Add new position
const newPosition: HrJobPosition = { const newPosition: JobPositionDto = {
id: `jp-${Date.now()}`, id: `jp-${Date.now()}`,
...positionData, ...positionData,
employees: [], employees: [],
creationTime: new Date(), creationTime: new Date(),
lastModificationTime: new Date(), lastModificationTime: new Date(),
} as HrJobPosition } as JobPositionDto
setPositions([...positions, newPosition]) setPositions([...positions, newPosition])
} }
} }
@ -106,7 +106,7 @@ const JobPositions: React.FC = () => {
}) })
// Card component for individual position // Card component for individual position
const PositionCard: React.FC<{ position: HrJobPosition }> = ({ position }) => ( const PositionCard: React.FC<{ position: JobPositionDto }> = ({ position }) => (
<div className="bg-white rounded-lg shadow-sm border hover:shadow-md transition-shadow p-4"> <div className="bg-white rounded-lg shadow-sm border hover:shadow-md transition-shadow p-4">
<div className="flex items-start justify-between mb-4"> <div className="flex items-start justify-between mb-4">
<div className="flex-1"> <div className="flex-1">
@ -201,7 +201,7 @@ const JobPositions: React.FC = () => {
</div> </div>
) )
const columns: Column<HrJobPosition>[] = [ const columns: Column<JobPositionDto>[] = [
{ {
key: 'code', key: 'code',
header: 'Pozisyon Kodu', header: 'Pozisyon Kodu',
@ -211,7 +211,7 @@ const JobPositions: React.FC = () => {
key: 'title', key: 'title',
header: 'Pozisyon Adı', header: 'Pozisyon Adı',
sortable: true, sortable: true,
render: (position: HrJobPosition) => ( render: (position: JobPositionDto) => (
<div> <div>
<div className="font-medium text-gray-900">{position.name}</div> <div className="font-medium text-gray-900">{position.name}</div>
<div className="text-sm text-gray-500 truncate max-w-xs">{position.description}</div> <div className="text-sm text-gray-500 truncate max-w-xs">{position.description}</div>
@ -221,7 +221,7 @@ const JobPositions: React.FC = () => {
{ {
key: 'department', key: 'department',
header: 'Departman', header: 'Departman',
render: (position: HrJobPosition) => ( render: (position: JobPositionDto) => (
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<FaBuilding className="w-4 h-4 text-gray-500" /> <FaBuilding className="w-4 h-4 text-gray-500" />
<span>{position.department?.name || '-'}</span> <span>{position.department?.name || '-'}</span>
@ -231,7 +231,7 @@ const JobPositions: React.FC = () => {
{ {
key: 'level', key: 'level',
header: 'Seviye', header: 'Seviye',
render: (position: HrJobPosition) => ( render: (position: JobPositionDto) => (
<span <span
className={`px-2 py-1 text-xs font-medium rounded-full ${getJobLevelColor( className={`px-2 py-1 text-xs font-medium rounded-full ${getJobLevelColor(
position.level, position.level,
@ -244,7 +244,7 @@ const JobPositions: React.FC = () => {
{ {
key: 'employeeCount', key: 'employeeCount',
header: 'Personel Sayısı', header: 'Personel Sayısı',
render: (position: HrJobPosition) => ( render: (position: JobPositionDto) => (
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
<FaUsers className="w-4 h-4 text-gray-500" /> <FaUsers className="w-4 h-4 text-gray-500" />
<span>{position.employees?.length || 0}</span> <span>{position.employees?.length || 0}</span>
@ -254,7 +254,7 @@ const JobPositions: React.FC = () => {
{ {
key: 'salary', key: 'salary',
header: 'Maaş Aralığı', header: 'Maaş Aralığı',
render: (position: HrJobPosition) => ( render: (position: JobPositionDto) => (
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
<FaDollarSign className="w-4 h-4 text-gray-500" /> <FaDollarSign className="w-4 h-4 text-gray-500" />
<div className="text-sm"> <div className="text-sm">
@ -267,7 +267,7 @@ const JobPositions: React.FC = () => {
{ {
key: 'skills', key: 'skills',
header: 'Gerekli Yetenekler', header: 'Gerekli Yetenekler',
render: (position: HrJobPosition) => ( render: (position: JobPositionDto) => (
<div className="flex flex-wrap gap-1 max-w-xs"> <div className="flex flex-wrap gap-1 max-w-xs">
{position.requiredSkills?.slice(0, 3).map((skill, index) => ( {position.requiredSkills?.slice(0, 3).map((skill, index) => (
<span key={index} className="px-2 py-1 text-xs bg-blue-50 text-blue-700 rounded"> <span key={index} className="px-2 py-1 text-xs bg-blue-50 text-blue-700 rounded">
@ -285,7 +285,7 @@ const JobPositions: React.FC = () => {
{ {
key: 'status', key: 'status',
header: 'Durum', header: 'Durum',
render: (position: HrJobPosition) => ( render: (position: JobPositionDto) => (
<span <span
className={`px-2 py-1 text-xs font-medium rounded-full ${ className={`px-2 py-1 text-xs font-medium rounded-full ${
position.isActive ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800' position.isActive ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'
@ -298,7 +298,7 @@ const JobPositions: React.FC = () => {
{ {
key: 'actions', key: 'actions',
header: 'İşlemler', header: 'İşlemler',
render: (position: HrJobPosition) => ( render: (position: JobPositionDto) => (
<div className="flex gap-2"> <div className="flex gap-2">
<button <button
onClick={() => handleView(position)} onClick={() => handleView(position)}

View file

@ -15,7 +15,7 @@ import {
FaMapMarkerAlt, FaMapMarkerAlt,
FaBriefcase, FaBriefcase,
} from 'react-icons/fa' } from 'react-icons/fa'
import { HrEmployee, HrOrganizationChart as OrgChart } from '../../../types/hr' import { EmployeeDto, HrOrganizationChart as OrgChart } from '../../../types/hr'
import { mockEmployees } from '../../../mocks/mockEmployees' import { mockEmployees } from '../../../mocks/mockEmployees'
import { mockDepartments } from '../../../mocks/mockDepartments' import { mockDepartments } from '../../../mocks/mockDepartments'
import Widget from '../../../components/common/Widget' import Widget from '../../../components/common/Widget'
@ -76,22 +76,22 @@ const generateOrganizationData = (): OrgChart[] => {
} }
interface TreeNode { interface TreeNode {
employee: HrEmployee employee: EmployeeDto
children: TreeNode[] children: TreeNode[]
level: number level: number
} }
const OrganizationChart: React.FC = () => { const OrganizationChart: React.FC = () => {
const [employees] = useState<HrEmployee[]>(mockEmployees) const [employees] = useState<EmployeeDto[]>(mockEmployees)
const [organizationData] = useState<OrgChart[]>(generateOrganizationData()) const [organizationData] = useState<OrgChart[]>(generateOrganizationData())
const [expandedNodes, setExpandedNodes] = useState<Set<string>>(new Set()) const [expandedNodes, setExpandedNodes] = useState<Set<string>>(new Set())
const [orgTree, setOrgTree] = useState<TreeNode[]>([]) const [orgTree, setOrgTree] = useState<TreeNode[]>([])
const [viewMode, setViewMode] = useState<'tree' | 'cards'>('tree') const [viewMode, setViewMode] = useState<'tree' | 'cards'>('tree')
const [selectedEmployee, setSelectedEmployee] = useState<HrEmployee | null>(null) const [selectedEmployee, setSelectedEmployee] = useState<EmployeeDto | null>(null)
const [showModal, setShowModal] = useState(false) const [showModal, setShowModal] = useState(false)
const [selectedDepartment, setSelectedDepartment] = useState<string>('all') const [selectedDepartment, setSelectedDepartment] = useState<string>('all')
const handleViewEmployee = (employee: HrEmployee) => { const handleViewEmployee = (employee: EmployeeDto) => {
setSelectedEmployee(employee) setSelectedEmployee(employee)
setShowModal(true) setShowModal(true)
} }
@ -278,7 +278,7 @@ const OrganizationChart: React.FC = () => {
acc[level].push(employee) acc[level].push(employee)
return acc return acc
}, },
{} as Record<number, HrEmployee[]>, {} as Record<number, EmployeeDto[]>,
) )
return ( return (

View file

@ -35,7 +35,7 @@ import { Announcement, Survey, SurveyAnswer } from '@/types/intranet'
import { Container } from '@/components/shared' import { Container } from '@/components/shared'
import { usePermission } from '@/utils/hooks/usePermission' import { usePermission } from '@/utils/hooks/usePermission'
import { IntranetDashboardDto } from '@/proxy/intranet/models' import { IntranetDashboardDto } from '@/proxy/intranet/models'
import { intranetService, IntranetService } from '@/services/intranet.service' import { intranetService } from '@/services/intranet.service'
dayjs.locale('tr') dayjs.locale('tr')
dayjs.extend(relativeTime) dayjs.extend(relativeTime)
@ -247,19 +247,36 @@ const IntranetDashboard: React.FC = () => {
case 'upcoming-events': case 'upcoming-events':
return <UpcomingEvents events={intranetDashboard?.events || []} /> return <UpcomingEvents events={intranetDashboard?.events || []} />
case 'today-birthdays': case 'today-birthdays':
return <TodayBirthdays /> return <TodayBirthdays employees={intranetDashboard?.birthdays || []} />
case 'recent-documents': case 'visitors':
return <RecentDocuments /> return <Visitors visitors={intranetDashboard?.visitors || []} />
case 'upcoming-trainings':
return <UpcomingTrainings />
case 'active-reservations': case 'active-reservations':
return <ActiveReservations onNewReservation={() => setShowReservationModal(true)} /> return (
<ActiveReservations
reservations={intranetDashboard?.reservations || []}
onNewReservation={() => setShowReservationModal(true)}
/>
)
case 'upcoming-trainings':
return <UpcomingTrainings trainings={intranetDashboard?.trainings || []} />
case 'expense-management':
return (
<ExpenseManagement
expenses={
intranetDashboard?.expenses || {
totalRequested: 0,
totalApproved: 0,
last5Expenses: [],
}
}
onNewExpense={() => setShowExpenseModal(true)}
/>
)
case 'recent-documents':
return <RecentDocuments documents={intranetDashboard?.documents || []} />
case 'active-surveys': case 'active-surveys':
return <ActiveSurveys onTakeSurvey={handleTakeSurvey} /> return <ActiveSurveys onTakeSurvey={handleTakeSurvey} />
case 'visitors':
return <Visitors />
case 'expense-management':
return <ExpenseManagement onNewExpense={() => setShowExpenseModal(true)} />
case 'social-wall': case 'social-wall':
return <SocialWall /> return <SocialWall />
case 'important-announcements': case 'important-announcements':

View file

@ -4,7 +4,7 @@ import PostItem from './PostItem'
import { SocialMedia } from '@/types/intranet' import { SocialMedia } from '@/types/intranet'
import CreatePost from './CreatePost' import CreatePost from './CreatePost'
import { SocialPost } from '@/types/intranet' import { SocialPost } from '@/types/intranet'
import { HrEmployee } from '@/types/hr' import { EmployeeDto } from '@/types/hr'
import { mockSocialPosts } from '@/mocks/mockIntranet' import { mockSocialPosts } from '@/mocks/mockIntranet'
import { mockEmployees } from '@/mocks/mockEmployees' import { mockEmployees } from '@/mocks/mockEmployees'
@ -13,7 +13,7 @@ const SocialWall: React.FC = () => {
const [filter, setFilter] = useState<'all' | 'mine'>('all') const [filter, setFilter] = useState<'all' | 'mine'>('all')
// Ali Öztürk'ü "Siz" kullanıcısı olarak kullan // Ali Öztürk'ü "Siz" kullanıcısı olarak kullan
const currentUserAuthor: HrEmployee = { ...mockEmployees[0], fullName: 'Siz' } const currentUserAuthor: EmployeeDto = { ...mockEmployees[0], fullName: 'Siz' }
const handleCreatePost = (postData: { const handleCreatePost = (postData: {
content: string content: string

View file

@ -1,13 +1,17 @@
import React from 'react' import React from 'react'
import { FaKey, FaPlus } from 'react-icons/fa' import { FaKey, FaPlus } from 'react-icons/fa'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { mockReservations } from '../../../mocks/mockIntranet' import { ReservationDto } from '@/proxy/intranet/models'
interface ActiveReservationsProps { interface ActiveReservationsProps {
reservations: ReservationDto[]
onNewReservation: () => void onNewReservation: () => void
} }
const ActiveReservations: React.FC<ActiveReservationsProps> = ({ onNewReservation }) => { const ActiveReservations: React.FC<ActiveReservationsProps> = ({
reservations,
onNewReservation,
}) => {
return ( return (
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700"> <div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
<div className="p-4 border-b border-gray-200 dark:border-gray-700"> <div className="p-4 border-b border-gray-200 dark:border-gray-700">
@ -17,7 +21,7 @@ const ActiveReservations: React.FC<ActiveReservationsProps> = ({ onNewReservatio
</h2> </h2>
</div> </div>
<div className="p-4 space-y-3"> <div className="p-4 space-y-3">
{mockReservations {reservations
.filter((r) => r.status === 'approved') .filter((r) => r.status === 'approved')
.slice(0, 3) .slice(0, 3)
.map((reservation) => ( .map((reservation) => (
@ -30,15 +34,20 @@ const ActiveReservations: React.FC<ActiveReservationsProps> = ({ onNewReservatio
{reservation.resourceName} {reservation.resourceName}
</h4> </h4>
<span className="text-xs px-2 py-1 bg-green-100 dark:bg-green-900/50 text-green-700 dark:text-green-300 rounded-full"> <span className="text-xs px-2 py-1 bg-green-100 dark:bg-green-900/50 text-green-700 dark:text-green-300 rounded-full">
{reservation.type === 'room' ? '🏢' : reservation.type === 'vehicle' ? '🚗' : '⚙️'} {reservation.type === 'room'
? '🏢'
: reservation.type === 'vehicle'
? '🚗'
: '⚙️'}
</span> </span>
</div> </div>
<p className="text-xs text-gray-600 dark:text-gray-400"> <p className="text-xs text-gray-600 dark:text-gray-400">
{dayjs(reservation.startDate).format('DD MMM HH:mm')} - {dayjs(reservation.endDate).format('HH:mm')} {dayjs(reservation.startDate).format('DD MMM HH:mm')} -{' '}
{dayjs(reservation.endDate).format('HH:mm')}
</p> </p>
</div> </div>
))} ))}
{mockReservations.filter((r) => r.status === 'approved').length === 0 && ( {reservations.filter((r) => r.status === 'approved').length === 0 && (
<p className="text-sm text-gray-500 dark:text-gray-400 text-center py-4"> <p className="text-sm text-gray-500 dark:text-gray-400 text-center py-4">
Aktif rezervasyon yok Aktif rezervasyon yok
</p> </p>

View file

@ -1,12 +1,13 @@
import React from 'react' import React from 'react'
import { FaDollarSign, FaPlus } from 'react-icons/fa' import { FaDollarSign, FaPlus } from 'react-icons/fa'
import { mockExpenseRequests } from '../../../mocks/mockIntranet' import { ExpensesDto } from '@/proxy/intranet/models'
interface ExpenseManagementProps { interface ExpenseManagementProps {
expenses: ExpensesDto
onNewExpense: () => void onNewExpense: () => void
} }
const ExpenseManagement: React.FC<ExpenseManagementProps> = ({ onNewExpense }) => { const ExpenseManagement: React.FC<ExpenseManagementProps> = ({ expenses, onNewExpense }) => {
return ( return (
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700"> <div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
<div className="p-4 border-b border-gray-200 dark:border-gray-700"> <div className="p-4 border-b border-gray-200 dark:border-gray-700">
@ -19,13 +20,17 @@ const ExpenseManagement: React.FC<ExpenseManagementProps> = ({ onNewExpense }) =
{/* Harcama özeti */} {/* Harcama özeti */}
<div className="p-3 bg-emerald-50 dark:bg-emerald-900/20 rounded-lg border border-emerald-200 dark:border-emerald-800 mb-4"> <div className="p-3 bg-emerald-50 dark:bg-emerald-900/20 rounded-lg border border-emerald-200 dark:border-emerald-800 mb-4">
<p className="text-xs text-gray-600 dark:text-gray-400">Bu Ay Toplam</p> <p className="text-xs text-gray-600 dark:text-gray-400">Bu Ay Toplam</p>
<p className="text-2xl font-bold text-emerald-600 dark:text-emerald-400">2,370</p> <p className="text-2xl font-bold text-emerald-600 dark:text-emerald-400">
<p className="text-xs text-gray-500 dark:text-gray-400 mt-1">2,050 onaylandı</p> {expenses.totalRequested.toLocaleString('tr-TR')}
</p>
<p className="text-xs text-gray-500 dark:text-gray-400 mt-1">
{expenses.totalApproved.toLocaleString('tr-TR')} onaylandı
</p>
</div> </div>
{/* Son harcama talepleri */} {/* Son harcama talepleri */}
<div className="space-y-2"> <div className="space-y-2">
{mockExpenseRequests.slice(0, 3).map((expense) => ( {expenses.last5Expenses.slice(0, 3).map((expense) => (
<div <div
key={expense.id} key={expense.id}
className="p-3 rounded-lg bg-gray-50 dark:bg-gray-900/20 border border-gray-200 dark:border-gray-700" className="p-3 rounded-lg bg-gray-50 dark:bg-gray-900/20 border border-gray-200 dark:border-gray-700"
@ -33,10 +38,16 @@ const ExpenseManagement: React.FC<ExpenseManagementProps> = ({ onNewExpense }) =
<div className="flex items-start justify-between mb-1"> <div className="flex items-start justify-between mb-1">
<div className="flex-1"> <div className="flex-1">
<h4 className="text-sm font-medium text-gray-900 dark:text-white"> <h4 className="text-sm font-medium text-gray-900 dark:text-white">
{expense.category === 'travel' ? '✈️' : {expense.category === 'travel'
expense.category === 'meal' ? '🍽️' : ? '✈️'
expense.category === 'accommodation' ? '🏨' : : expense.category === 'meal'
expense.category === 'transport' ? '🚗' : '📋'} {expense.description} ? '🍽️'
: expense.category === 'accommodation'
? '🏨'
: expense.category === 'transport'
? '🚗'
: '📋'}{' '}
{expense.description}
</h4> </h4>
<p className="text-xs font-semibold text-emerald-600 dark:text-emerald-400 mt-1"> <p className="text-xs font-semibold text-emerald-600 dark:text-emerald-400 mt-1">
{expense.amount.toLocaleString('tr-TR')} {expense.amount.toLocaleString('tr-TR')}
@ -51,8 +62,11 @@ const ExpenseManagement: React.FC<ExpenseManagementProps> = ({ onNewExpense }) =
: 'bg-red-100 dark:bg-red-900/30 text-red-700 dark:text-red-300' : 'bg-red-100 dark:bg-red-900/30 text-red-700 dark:text-red-300'
}`} }`}
> >
{expense.status === 'approved' ? 'Onaylandı' : {expense.status === 'approved'
expense.status === 'pending' ? 'Bekliyor' : 'Reddedildi'} ? 'Onaylandı'
: expense.status === 'pending'
? 'Bekliyor'
: 'Reddedildi'}
</span> </span>
</div> </div>
</div> </div>

View file

@ -1,9 +1,86 @@
import React from 'react' import React from 'react'
import { FaFileAlt, FaDownload } from 'react-icons/fa' import {
FaFileAlt,
FaDownload,
FaFilePdf,
FaFileWord,
FaFileExcel,
FaFilePowerpoint,
FaFileImage,
FaFileArchive,
FaFileCode,
} from 'react-icons/fa'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { mockDocuments } from '../../../mocks/mockIntranet' import { DocumentDto } from '@/proxy/intranet/models'
const RecentDocuments: React.FC = () => { const getFileIcon = (extension: string) => {
switch (extension.toLowerCase()) {
case '.pdf':
return <FaFilePdf className="w-4 h-4 text-red-600 dark:text-red-400" />
case '.doc':
case '.docx':
return <FaFileWord className="w-4 h-4 text-blue-600 dark:text-blue-400" />
case '.xls':
case '.xlsx':
return <FaFileExcel className="w-4 h-4 text-green-600 dark:text-green-400" />
case '.ppt':
case '.pptx':
return <FaFilePowerpoint className="w-4 h-4 text-orange-600 dark:text-orange-400" />
case '.jpg':
case '.jpeg':
case '.png':
case '.gif':
return <FaFileImage className="w-4 h-4 text-purple-600 dark:text-purple-400" />
case '.zip':
case '.rar':
return <FaFileArchive className="w-4 h-4 text-yellow-600 dark:text-yellow-400" />
case '.txt':
return <FaFileCode className="w-4 h-4 text-gray-600 dark:text-gray-400" />
default:
return <FaFileAlt className="w-4 h-4 text-gray-600 dark:text-gray-400" />
}
}
const getFileType = (extension: string) => {
switch (extension.toLowerCase()) {
case '.pdf':
return '📄 PDF'
case '.doc':
case '.docx':
return '📝 Word'
case '.xls':
case '.xlsx':
return '📊 Excel'
case '.ppt':
case '.pptx':
return '📽️ PowerPoint'
case '.jpg':
case '.jpeg':
return '🖼️ JPEG'
case '.png':
return '🖼️ PNG'
case '.gif':
return '🖼️ GIF'
case '.zip':
return '🗜️ ZIP'
case '.rar':
return '🗜️ RAR'
case '.txt':
return '📝 Text'
default:
return '📄 Dosya'
}
}
const formatFileSize = (bytes: number): string => {
if (bytes === 0) return '0 B'
const k = 1024
const sizes = ['B', 'KB', 'MB', 'GB']
const i = Math.floor(Math.log(bytes) / Math.log(k))
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`
}
const RecentDocuments: React.FC<{ documents: DocumentDto[] }> = ({ documents }) => {
return ( return (
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700"> <div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
<div className="p-4 border-b border-gray-200 dark:border-gray-700"> <div className="p-4 border-b border-gray-200 dark:border-gray-700">
@ -15,39 +92,41 @@ const RecentDocuments: React.FC = () => {
</div> </div>
</div> </div>
<div className="divide-y divide-gray-200 dark:divide-gray-700"> <div className="divide-y divide-gray-200 dark:divide-gray-700">
{mockDocuments.slice(0, 3).map((doc) => ( {documents.slice(0, 3).map((doc) => (
<div <div
key={doc.id} key={doc.id}
className="p-4 hover:bg-gray-50 dark:hover:bg-gray-700/50 transition-colors" className="p-4 hover:bg-gray-50 dark:hover:bg-gray-700/50 transition-colors"
> >
<div className="flex items-start gap-3"> <div className="flex items-start gap-3">
<div className="p-2 bg-blue-100 dark:bg-blue-900/30 rounded-lg"> <div className="p-2 bg-blue-100 dark:bg-blue-900/30 rounded-lg">
<FaFileAlt className="w-4 h-4 text-blue-600 dark:text-blue-400" /> {getFileIcon(doc.extension)}
</div> </div>
<div className="flex-1 min-w-0"> <div className="flex-1 min-w-0">
<h4 className="text-sm font-medium text-gray-900 dark:text-white truncate"> <h4 className="text-sm font-medium text-gray-900 dark:text-white truncate">
{doc.name} {doc.name}
</h4> </h4>
<p className="text-xs text-gray-600 dark:text-gray-400 mt-1"> <p className="text-xs text-gray-600 dark:text-gray-400 mt-1">
{doc.category === 'policy' && '📋 Politika'} {getFileType(doc.extension)}
{doc.category === 'procedure' && '📝 Prosedür'}
{doc.category === 'form' && '📄 Form'}
{doc.category === 'template' && '📋 Şablon'}
{doc.category === 'report' && '📊 Rapor'}
{doc.category === 'other' && '📄 Diğer'}
<span className="mx-1"></span> <span className="mx-1"></span>
{doc.size} {formatFileSize(doc.size)}
</p> </p>
<div className="text-xs text-gray-500 dark:text-gray-400 mt-1 flex items-center gap-2"> <div className="text-xs text-gray-500 dark:text-gray-400 mt-1 flex items-center gap-2">
<span>{dayjs(doc.uploadDate).fromNow()}</span> <span>{dayjs(doc.modifiedAt).fromNow()}</span>
<span></span> {doc.isReadOnly && (
<span>{doc.downloadCount} indirme</span> <>
<span></span>
<span className="text-orange-500">🔒 Salt okunur</span>
</>
)}
</div> </div>
</div> </div>
<button <button
onClick={(e) => { onClick={(e) => {
e.stopPropagation() e.stopPropagation()
window.open(doc.url, '_blank') const link = document.createElement('a')
link.href = `/cdn/${doc.path}`
link.download = doc.name
link.click()
}} }}
className="p-2 hover:bg-blue-100 dark:hover:bg-blue-900/30 rounded-lg transition-colors group" className="p-2 hover:bg-blue-100 dark:hover:bg-blue-900/30 rounded-lg transition-colors group"
title="İndir" title="İndir"

View file

@ -1,14 +1,9 @@
import React from 'react' import React from 'react'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { mockEmployees } from '@/mocks/mockEmployees' import { EmployeeDto } from '@/proxy/intranet/models'
const TodayBirthdays: React.FC = () => { const TodayBirthdays: React.FC<{ employees: EmployeeDto[] }> = ({ employees }) => {
const today = dayjs() const today = dayjs()
const todayBirthdays = mockEmployees.filter((b) => {
return (
dayjs(b.birthDate).month() === today.month() && dayjs(b.birthDate).date() === today.date()
)
})
return ( return (
<div className="bg-gradient-to-br from-pink-50 to-purple-50 dark:from-pink-900/20 dark:to-purple-900/20 rounded-lg shadow-sm border border-pink-200 dark:border-pink-800"> <div className="bg-gradient-to-br from-pink-50 to-purple-50 dark:from-pink-900/20 dark:to-purple-900/20 rounded-lg shadow-sm border border-pink-200 dark:border-pink-800">
@ -18,30 +13,32 @@ const TodayBirthdays: React.FC = () => {
</h2> </h2>
</div> </div>
<div className="p-4 space-y-3"> <div className="p-4 space-y-3">
{todayBirthdays.length > 0 ? ( {employees.length > 0 ? (
todayBirthdays.map((birthday, index) => ( <div className="grid grid-cols-1 md:grid-cols-2 gap-3">
<div {employees.map((birthday, index) => (
key={index} <div
className="flex items-center gap-3 p-3 bg-white/50 dark:bg-gray-800/50 rounded-lg" key={index}
> className="flex items-center gap-3 p-3 border border-pink-100 dark:border-pink-800 rounded-lg"
<img >
src={birthday.avatar} <img
alt={birthday.fullName} src={birthday.avatar}
className="w-12 h-12 rounded-full border-2 border-pink-300 dark:border-pink-700" alt={birthday.fullName}
/> className="w-12 h-12 rounded-full border-2 border-pink-300 dark:border-pink-700"
<div className="flex-1"> />
<p className="text-sm font-semibold text-gray-900 dark:text-white"> <div className="flex-1">
{birthday.fullName} <p className="text-sm font-semibold text-gray-900 dark:text-white">
</p> {birthday.fullName}
<p className="text-xs text-gray-600 dark:text-gray-400"> </p>
{today.diff(dayjs(birthday.birthDate), 'year')} yaşında 🎉 <p className="text-xs text-gray-600 dark:text-gray-400">
</p> {today.diff(dayjs(birthday.birthDate), 'year')} yaşında 🎉
<p className="text-xs text-gray-500 dark:text-gray-500 mt-1"> </p>
{birthday.department?.name || 'Genel'} <p className="text-xs text-gray-500 dark:text-gray-500 mt-1">
</p> {birthday.department?.name || 'Genel'}
</p>
</div>
</div> </div>
</div> ))}
)) </div>
) : ( ) : (
<p className="text-sm text-gray-500 dark:text-gray-400 text-center py-4"> <p className="text-sm text-gray-500 dark:text-gray-400 text-center py-4">
Bugün doğan yok Bugün doğan yok

View file

@ -1,9 +1,9 @@
import React from 'react' import React from 'react'
import { FaGraduationCap } from 'react-icons/fa' import { FaGraduationCap } from 'react-icons/fa'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { mockTrainings } from '../../../mocks/mockIntranet' import { TrainingDto } from '@/proxy/intranet/models'
const UpcomingTrainings: React.FC = () => { const UpcomingTrainings: React.FC<{ trainings: TrainingDto[] }> = ({ trainings }) => {
return ( return (
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700"> <div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
<div className="p-4 border-b border-gray-200 dark:border-gray-700"> <div className="p-4 border-b border-gray-200 dark:border-gray-700">
@ -13,7 +13,7 @@ const UpcomingTrainings: React.FC = () => {
</h2> </h2>
</div> </div>
<div className="p-4 space-y-3"> <div className="p-4 space-y-3">
{mockTrainings {trainings
.filter((t) => t.status === 'upcoming') .filter((t) => t.status === 'upcoming')
.slice(0, 3) .slice(0, 3)
.map((training) => ( .map((training) => (
@ -29,7 +29,8 @@ const UpcomingTrainings: React.FC = () => {
</p> </p>
<div className="flex items-center justify-between text-xs"> <div className="flex items-center justify-between text-xs">
<span className="text-gray-500 dark:text-gray-400"> <span className="text-gray-500 dark:text-gray-400">
{dayjs(training.startDate).format('DD MMM')} - {dayjs(training.endDate).format('DD MMM')} {dayjs(training.startDate).format('DD MMM')} -{' '}
{dayjs(training.endDate).format('DD MMM')}
</span> </span>
<span className="text-blue-600 dark:text-blue-400 font-medium"> <span className="text-blue-600 dark:text-blue-400 font-medium">
{training.enrolled}/{training.maxParticipants} {training.enrolled}/{training.maxParticipants}
@ -37,7 +38,7 @@ const UpcomingTrainings: React.FC = () => {
</div> </div>
</div> </div>
))} ))}
{mockTrainings.filter((t) => t.status === 'upcoming').length === 0 && ( {trainings.filter((t) => t.status === 'upcoming').length === 0 && (
<p className="text-sm text-gray-500 dark:text-gray-400 text-center py-4"> <p className="text-sm text-gray-500 dark:text-gray-400 text-center py-4">
Yaklaşan eğitim yok Yaklaşan eğitim yok
</p> </p>

View file

@ -1,13 +1,9 @@
import React from 'react' import React from 'react'
import { FaUser, FaUserCheck, FaUserClock } from 'react-icons/fa' import { FaUser, FaUserCheck, FaUserClock } from 'react-icons/fa'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { mockVisitors } from '../../../mocks/mockIntranet' import { VisitorDto } from '@/proxy/intranet/models'
const Visitors: React.FC = () => {
const todayVisitors = mockVisitors.filter((visitor) =>
dayjs(visitor.visitDate).isSame(dayjs(), 'day')
)
const Visitors: React.FC<{ visitors: VisitorDto[] }> = ({ visitors }) => {
const getStatusIcon = (status: string) => { const getStatusIcon = (status: string) => {
switch (status) { switch (status) {
case 'checked-in': case 'checked-in':
@ -56,15 +52,20 @@ const Visitors: React.FC = () => {
</h2> </h2>
</div> </div>
<div className="p-4 space-y-3"> <div className="p-4 space-y-3">
{todayVisitors.length > 0 ? ( {visitors.length > 0 ? (
todayVisitors.map((visitor) => ( visitors.map((visitor) => (
<div <div
key={visitor.id} key={visitor.id}
className={`p-3 rounded-lg border ${getStatusColor(visitor.status)}`} className={`p-3 rounded-lg border ${getStatusColor(visitor.status)}`}
> >
<div className="flex items-start gap-3"> <div className="flex items-start gap-3">
<img <img
src={visitor.photo} src={visitor.photo ?? '/img/others/default-profile.png'}
onError={(e) => {
console.log('Image load error, using default profile image.')
e.currentTarget.onerror = null
e.currentTarget.src = '/img/others/default-profile.png'
}}
alt={visitor.fullName} alt={visitor.fullName}
className="w-10 h-10 rounded-full border-2 border-gray-300 dark:border-gray-600" className="w-10 h-10 rounded-full border-2 border-gray-300 dark:border-gray-600"
/> />
@ -73,16 +74,12 @@ const Visitors: React.FC = () => {
<h4 className="text-sm font-medium text-gray-900 dark:text-white truncate"> <h4 className="text-sm font-medium text-gray-900 dark:text-white truncate">
{visitor.fullName} {visitor.fullName}
</h4> </h4>
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">{getStatusIcon(visitor.status)}</div>
{getStatusIcon(visitor.status)}
</div>
</div> </div>
<p className="text-xs text-gray-600 dark:text-gray-400 truncate"> <p className="text-xs text-gray-600 dark:text-gray-400 truncate">
{visitor.company} {visitor.companyName}
</p>
<p className="text-xs text-gray-500 dark:text-gray-500 mt-1">
{visitor.purpose}
</p> </p>
<p className="text-xs text-gray-500 dark:text-gray-500 mt-1">{visitor.purpose}</p>
<div className="flex items-center justify-between mt-2"> <div className="flex items-center justify-between mt-2">
<span className="text-xs text-gray-500 dark:text-gray-500"> <span className="text-xs text-gray-500 dark:text-gray-500">
{dayjs(visitor.visitDate).format('HH:mm')} {dayjs(visitor.visitDate).format('HH:mm')}
@ -91,9 +88,9 @@ const Visitors: React.FC = () => {
{getStatusText(visitor.status)} {getStatusText(visitor.status)}
</span> </span>
</div> </div>
{visitor.host && ( {visitor.employee && (
<p className="text-xs text-gray-500 dark:text-gray-500 mt-1"> <p className="text-xs text-gray-500 dark:text-gray-500 mt-1">
Karşılayan: {visitor.host.fullName} Karşılayan: {visitor.employee.fullName}
</p> </p>
)} )}
</div> </div>

View file

@ -18,7 +18,7 @@ import {
} from '../../../types/pm' } from '../../../types/pm'
import { mockWorkCenters } from '../../../mocks/mockWorkCenters' import { mockWorkCenters } from '../../../mocks/mockWorkCenters'
import { mockDepartments } from '../../../mocks/mockDepartments' import { mockDepartments } from '../../../mocks/mockDepartments'
import { HrDepartment } from '../../../types/hr' import { DepartmentDto } from '../../../types/hr'
import { Container } from '@/components/shared' import { Container } from '@/components/shared'
import { ROUTES_ENUM } from '@/routes/route.constant' import { ROUTES_ENUM } from '@/routes/route.constant'
import { getCriticalityLevelText, getWorkCenterStatusText } from '@/utils/erp' import { getCriticalityLevelText, getWorkCenterStatusText } from '@/utils/erp'
@ -35,7 +35,7 @@ const WorkCenterForm: React.FC = () => {
const [loading, setLoading] = useState(false) const [loading, setLoading] = useState(false)
const [saving, setSaving] = useState(false) const [saving, setSaving] = useState(false)
const [errors, setErrors] = useState<ValidationErrors>({}) const [errors, setErrors] = useState<ValidationErrors>({})
const [departments, setDepartments] = useState<HrDepartment[]>([]) const [departments, setDepartments] = useState<DepartmentDto[]>([])
const [formData, setFormData] = useState<PmWorkCenter>({ const [formData, setFormData] = useState<PmWorkCenter>({
id: '', id: '',

View file

@ -24,7 +24,7 @@ import {
FaDownload, FaDownload,
} from 'react-icons/fa' } from 'react-icons/fa'
import LoadingSpinner from '../../../components/common/LoadingSpinner' import LoadingSpinner from '../../../components/common/LoadingSpinner'
import { HrEmployee } from '../../../types/hr' import { EmployeeDto } from '../../../types/hr'
import { mockEmployees } from '../../../mocks/mockEmployees' import { mockEmployees } from '../../../mocks/mockEmployees'
import { mockBusinessParties } from '../../../mocks/mockBusinessParties' import { mockBusinessParties } from '../../../mocks/mockBusinessParties'
import { import {
@ -114,7 +114,7 @@ const ProjectForm: React.FC = () => {
const [saving, setSaving] = useState(false) const [saving, setSaving] = useState(false)
const [errors, setErrors] = useState<ValidationErrors>({}) const [errors, setErrors] = useState<ValidationErrors>({})
const [customers, setCustomers] = useState<BusinessParty[]>([]) const [customers, setCustomers] = useState<BusinessParty[]>([])
const [projectManagers, setProjectManagers] = useState<HrEmployee[]>([]) const [projectManagers, setProjectManagers] = useState<EmployeeDto[]>([])
const [activeTab, setActiveTab] = useState('overview') const [activeTab, setActiveTab] = useState('overview')
// Additional states for the new features // Additional states for the new features