Intranet düzenlemeleri

This commit is contained in:
Sedat Öztürk 2025-10-20 21:38:21 +03:00
parent ee7114a2dc
commit ea5685439c
11 changed files with 639 additions and 635 deletions

View file

@ -1,230 +1,10 @@
// Intranet Mock Data Types and Sample Data
import { mockEmployees } from './mockEmployees' import { mockEmployees } from './mockEmployees'
import { mockEmployeeLeaves } from './mockEmployeeLeaves' import { mockEmployeeLeaves } from './mockEmployeeLeaves'
import { mockOvertimes } from './mockOvertimes' import { mockOvertimes } from './mockOvertimes'
import type { HrEmployee, HrOvertime } from '../types/hr' import { Announcement, CalendarEvent, Visitor, Document, Certificate, ExpenseRequest, Task, Birthday, WorkAnniversary, QuickLink, Training, Reservation, MealMenu, ShuttleRoute, Survey, SocialPost } from '@/types/intranet'
import { mockDepartments } from './mockDepartments'
// Duyuru
export interface Announcement {
id: string
title: string
content: string
excerpt: string
category: 'general' | 'hr' | 'it' | 'event' | 'urgent'
author: HrEmployee
publishDate: Date
expiryDate?: Date
isPinned: boolean
attachments?: { name: string; url: string; size: string }[]
departments?: string[]
viewCount: number
imageUrl?: string
}
// Etkinlik Yorumu
export interface EventComment {
id: string
author: HrEmployee
content: string
createdAt: Date
likes: number
}
// Etkinlik
export interface CalendarEvent {
id: string
title: string
description: string
type: 'social' | 'training' | 'company' | 'sport' | 'culture'
date: Date
location: string
organizer: HrEmployee
participants: number
photos: string[]
comments: EventComment[]
likes: number
isPublished: boolean
}
// 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
createdAt: Date
}
// Görev
export interface Task {
id: string
title: string
description: string
project: string
assignedTo: HrEmployee[]
assignedBy: HrEmployee
priority: 'low' | 'medium' | 'high' | 'urgent'
status: 'todo' | 'in-progress' | 'review' | 'done'
dueDate: Date
createdAt: Date
labels: string[]
attachments?: { name: string; url: string }[]
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[]
}
// Doğum günü
export interface Birthday {
employee: HrEmployee
date: Date
age?: number
}
// İş yıldönümü
export interface WorkAnniversary {
employee: HrEmployee
hireDate: Date
years: number
}
// Hızlı Erişim
export interface QuickLink {
id: string
name: string
description: string
icon: string
url: string
color: string
category: string
}
// Eğitim
export interface Training {
id: string
title: string
description: string
instructor: string
category: 'technical' | 'soft-skills' | 'management' | 'compliance' | 'other'
type: 'online' | 'classroom' | 'hybrid'
duration: number // saat
startDate: Date
endDate: Date
maxParticipants: number
enrolled: number
status: 'upcoming' | 'ongoing' | 'completed'
location?: string
thumbnail?: string
}
// Sertifika
export interface Certificate {
id: string
employee: HrEmployee
trainingTitle: string
issueDate: Date
expiryDate?: Date
certificateUrl: string
score?: number
}
// Rezervasyon
export interface Reservation {
id: string
type: 'room' | 'vehicle' | 'equipment'
resourceName: string
bookedBy: HrEmployee
startDate: Date
endDate: Date
purpose: string
status: 'pending' | 'approved' | 'rejected' | 'completed'
participants?: number
notes?: string
}
// Yemek Menüsü
export interface MealMenu {
id: string
date: Date
dayOfWeek: string
meals: {
type: 'breakfast' | 'lunch' | 'dinner'
items: string[]
calories?: number
}[]
}
// Servis
export interface ShuttleRoute {
id: string
name: string
route: string[]
departureTime: string
arrivalTime: string
capacity: number
available: number
type: 'morning' | 'evening'
}
// Anket
export interface Survey {
id: string
title: string
description: string
createdBy: HrEmployee
createdAt: Date
deadline: Date
totalQuestions: number
responses: number
targetAudience: string[]
status: 'draft' | 'active' | 'closed'
isAnonymous: boolean
}
// 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
}
// ============== SAMPLE DATA ============== // ============== SAMPLE DATA ==============
export const mockAnnouncements: Announcement[] = [ export const mockAnnouncements: Announcement[] = [
{ {
id: 'ann1', id: 'ann1',
@ -315,14 +95,14 @@ export const mockEvents: CalendarEvent[] = [
id: 'c1', id: 'c1',
author: mockEmployees[0], author: mockEmployees[0],
content: 'Muhteşem bir gündü! Yılın en güzel etkinliği 🎉', content: 'Muhteşem bir gündü! Yılın en güzel etkinliği 🎉',
createdAt: new Date('2025-07-16T10:30:00'), creationTime: new Date('2025-07-16T10:30:00'),
likes: 12, likes: 12,
}, },
{ {
id: 'c2', id: 'c2',
author: mockEmployees[2], author: mockEmployees[2],
content: 'Voleybol turnuvası harikaydı, gelecek yıl yine yapalım!', content: 'Voleybol turnuvası harikaydı, gelecek yıl yine yapalım!',
createdAt: new Date('2025-07-16T14:20:00'), creationTime: new Date('2025-07-16T14:20:00'),
likes: 8, likes: 8,
}, },
], ],
@ -348,14 +128,14 @@ export const mockEvents: CalendarEvent[] = [
id: 'c3', id: 'c3',
author: mockEmployees[1], author: mockEmployees[1],
content: 'Ekibimiz 2. oldu! Çok gurur duydum herkesle 💪', content: 'Ekibimiz 2. oldu! Çok gurur duydum herkesle 💪',
createdAt: new Date('2025-09-11T09:00:00'), creationTime: new Date('2025-09-11T09:00:00'),
likes: 15, likes: 15,
}, },
{ {
id: 'c4', id: 'c4',
author: mockEmployees[3], author: mockEmployees[3],
content: 'Gece boyunca kod yazmak ve pizza yemek priceless! 🍕', content: 'Gece boyunca kod yazmak ve pizza yemek priceless! 🍕',
createdAt: new Date('2025-09-11T11:45:00'), creationTime: new Date('2025-09-11T11:45:00'),
likes: 10, likes: 10,
}, },
], ],
@ -382,7 +162,7 @@ export const mockEvents: CalendarEvent[] = [
id: 'c5', id: 'c5',
author: mockEmployees[4], author: mockEmployees[4],
content: 'İT departmanı şampiyon oldu! Gelecek sene kupayı koruyacağız 🏆', content: 'İT departmanı şampiyon oldu! Gelecek sene kupayı koruyacağız 🏆',
createdAt: new Date('2025-06-21T08:30:00'), creationTime: new Date('2025-06-21T08:30:00'),
likes: 18, likes: 18,
}, },
], ],
@ -410,21 +190,21 @@ export const mockEvents: CalendarEvent[] = [
id: 'c6', id: 'c6',
author: mockEmployees[0], author: mockEmployees[0],
content: 'Yılın en şık gecesi! Organizasyon mükemmeldi 👏', content: 'Yılın en şık gecesi! Organizasyon mükemmeldi 👏',
createdAt: new Date('2024-12-29T10:00:00'), creationTime: new Date('2024-12-29T10:00:00'),
likes: 25, likes: 25,
}, },
{ {
id: 'c7', id: 'c7',
author: mockEmployees[1], author: mockEmployees[1],
content: 'Tombala hediyelerim harika, çok teşekkürler! 🎁', content: 'Tombala hediyelerim harika, çok teşekkürler! 🎁',
createdAt: new Date('2024-12-29T12:30:00'), creationTime: new Date('2024-12-29T12:30:00'),
likes: 14, likes: 14,
}, },
{ {
id: 'c8', id: 'c8',
author: mockEmployees[2], author: mockEmployees[2],
content: 'Müzik grubunuz süperdi, dans pistinden ayrılamadık! 🎵', content: 'Müzik grubunuz süperdi, dans pistinden ayrılamadık! 🎵',
createdAt: new Date('2024-12-29T15:20:00'), creationTime: new Date('2024-12-29T15:20:00'),
likes: 19, likes: 19,
}, },
], ],
@ -450,7 +230,7 @@ export const mockEvents: CalendarEvent[] = [
id: 'c9', id: 'c9',
author: mockEmployees[3], author: mockEmployees[3],
content: 'İlk defa ebru yaptım, çok huzurlu bir deneyimdi 🎨', content: 'İlk defa ebru yaptım, çok huzurlu bir deneyimdi 🎨',
createdAt: new Date('2025-05-13T09:15:00'), creationTime: new Date('2025-05-13T09:15:00'),
likes: 11, likes: 11,
}, },
], ],
@ -479,7 +259,7 @@ export const mockExpenseRequests: ExpenseRequest[] = [
status: 'approved', status: 'approved',
approver: mockEmployees[4], approver: mockEmployees[4],
approvalDate: new Date('2024-10-16T10:00:00'), approvalDate: new Date('2024-10-16T10:00:00'),
createdAt: new Date('2024-10-15T18:00:00'), creationTime: new Date('2024-10-15T18:00:00'),
}, },
{ {
id: 'exp2', id: 'exp2',
@ -491,7 +271,7 @@ export const mockExpenseRequests: ExpenseRequest[] = [
description: 'Müşteri toplantısı - öğle yemeği', description: 'Müşteri toplantısı - öğle yemeği',
receipts: [{ name: 'restoran_fisi.jpg', url: '#', size: '156 KB' }], receipts: [{ name: 'restoran_fisi.jpg', url: '#', size: '156 KB' }],
status: 'pending', status: 'pending',
createdAt: new Date('2024-10-17T20:00:00'), creationTime: new Date('2024-10-17T20:00:00'),
}, },
{ {
id: 'exp3', id: 'exp3',
@ -506,7 +286,7 @@ export const mockExpenseRequests: ExpenseRequest[] = [
status: 'approved', status: 'approved',
approver: mockEmployees[4], approver: mockEmployees[4],
approvalDate: new Date('2024-10-15T09:00:00'), approvalDate: new Date('2024-10-15T09:00:00'),
createdAt: new Date('2024-10-14T22:00:00'), creationTime: new Date('2024-10-14T22:00:00'),
}, },
] ]
@ -521,7 +301,7 @@ export const mockTasks: Task[] = [
priority: 'high', priority: 'high',
status: 'in-progress', status: 'in-progress',
dueDate: new Date('2024-10-25'), dueDate: new Date('2024-10-25'),
createdAt: new Date('2024-10-14'), creationTime: new Date('2024-10-14'),
labels: ['backend', 'api'], labels: ['backend', 'api'],
comments: 3, comments: 3,
}, },
@ -535,7 +315,7 @@ export const mockTasks: Task[] = [
priority: 'medium', priority: 'medium',
status: 'review', status: 'review',
dueDate: new Date('2024-10-22'), dueDate: new Date('2024-10-22'),
createdAt: new Date('2024-10-10'), creationTime: new Date('2024-10-10'),
labels: ['design', 'ui/ux'], labels: ['design', 'ui/ux'],
comments: 5, comments: 5,
}, },
@ -549,7 +329,7 @@ export const mockTasks: Task[] = [
priority: 'urgent', priority: 'urgent',
status: 'todo', status: 'todo',
dueDate: new Date('2024-10-20'), dueDate: new Date('2024-10-20'),
createdAt: new Date('2024-10-17'), creationTime: new Date('2024-10-17'),
labels: ['devops', 'infrastructure'], labels: ['devops', 'infrastructure'],
comments: 1, comments: 1,
}, },
@ -962,8 +742,8 @@ export const mockSurveys: Survey[] = [
id: 'survey1', id: 'survey1',
title: 'Çalışan Memnuniyet Anketi 2024', title: 'Çalışan Memnuniyet Anketi 2024',
description: 'Yıllık çalışan memnuniyeti ve bağlılık araştırması', description: 'Yıllık çalışan memnuniyeti ve bağlılık araştırması',
createdBy: mockEmployees[0], creatorId: mockEmployees[0],
createdAt: new Date('2024-10-01'), creationTime: new Date('2024-10-01'),
deadline: new Date('2024-10-31'), deadline: new Date('2024-10-31'),
totalQuestions: 25, totalQuestions: 25,
responses: 45, responses: 45,
@ -975,8 +755,8 @@ export const mockSurveys: Survey[] = [
id: 'survey2', id: 'survey2',
title: 'Eğitim İhtiyaç Analizi', title: 'Eğitim İhtiyaç Analizi',
description: '2025 yılı eğitim planlaması için ihtiyaç tespiti', description: '2025 yılı eğitim planlaması için ihtiyaç tespiti',
createdBy: mockEmployees[2], creatorId: mockEmployees[2],
createdAt: new Date('2024-10-10'), creationTime: new Date('2024-10-10'),
deadline: new Date('2024-11-15'), deadline: new Date('2024-11-15'),
totalQuestions: 15, totalQuestions: 15,
responses: 28, responses: 28,
@ -988,8 +768,8 @@ export const mockSurveys: Survey[] = [
id: 'survey3', id: 'survey3',
title: 'Kafeterya Memnuniyet Anketi', title: 'Kafeterya Memnuniyet Anketi',
description: 'Yemek kalitesi ve servis değerlendirmesi', description: 'Yemek kalitesi ve servis değerlendirmesi',
createdBy: mockEmployees[4], creatorId: mockEmployees[4],
createdAt: new Date('2024-09-15'), creationTime: new Date('2024-09-15'),
deadline: new Date('2024-09-30'), deadline: new Date('2024-09-30'),
totalQuestions: 10, totalQuestions: 10,
responses: 62, responses: 62,
@ -1043,3 +823,260 @@ export const mockVisitors: Visitor[] = [
photo: 'https://i.pravatar.cc/150?img=68', photo: 'https://i.pravatar.cc/150?img=68',
}, },
] ]
export const mockSocialPosts: SocialPost[] = [
{
id: '1',
author: {
id: 'user1',
name: 'Ahmet Yılmaz',
avatar: 'https://i.pravatar.cc/150?img=12',
title: 'Yazılım Geliştirici',
email: 'ahmet.yilmaz@sozsoft.com',
phone: '+90 532 123 45 67',
department: 'Yazılım Geliştirme',
location: 'İstanbul, Türkiye'
},
content:
'Yeni proje üzerinde çalışıyoruz! React ve TypeScript ile harika bir deneyim oluşturuyoruz. Ekip çalışması harika gidiyor! 🚀',
creationTime: new Date('2024-10-15T10:30:00'),
location: {
id: '1',
name: 'Taksim Meydanı',
address: 'Taksim, Gümüşsuyu Mahallesi, 34437 Beyoğlu/İstanbul',
lat: 41.0369,
lng: 28.9850,
placeId: 'ChIJBQRGmL25yhQRXwqRTHAwAAQ'
},
media: {
type: 'image',
url: 'https://images.unsplash.com/photo-1633356122544-f134324a6cee?w=800&q=80'
},
likes: {
count: 24,
isLiked: true,
users: [
{ id: 'user2', name: 'Ayşe Demir', avatar: 'https://i.pravatar.cc/150?img=5' },
{ id: 'user3', name: 'Mehmet Kaya', avatar: 'https://i.pravatar.cc/150?img=8' }
]
},
comments: [
{
id: 'c1',
author: {
id: 'user2',
name: 'Ayşe Demir',
avatar: 'https://i.pravatar.cc/150?img=5'
},
content: 'Harika görünüyor! Başarılar 👏',
creationTime: new Date('2024-10-15T11:00:00')
},
{
id: 'c2',
author: {
id: 'user3',
name: 'Mehmet Kaya',
avatar: 'https://i.pravatar.cc/150?img=8'
},
content: 'TypeScript gerçekten fark yaratıyor!',
creationTime: new Date('2024-10-15T11:30:00')
}
],
isOwnPost: false
},
{
id: '2',
author: {
id: 'currentUser',
name: 'Siz',
avatar: 'https://i.pravatar.cc/150?img=1',
title: 'Proje Yöneticisi'
},
content:
'Bu hafta sprint planlamasını yaptık. Ekibimizle birlikte yeni özellikleri değerlendirdik. Heyecan verici bir hafta olacak!',
creationTime: new Date('2024-10-16T09:00:00'),
media: {
type: 'poll',
poll: {
question: 'Hangi özelliği öncelikli olarak geliştirmeliyiz?',
options: [
{ id: 'p1', text: 'Kullanıcı profilleri', votes: 12 },
{ id: 'p2', text: 'Bildirim sistemi', votes: 8 },
{ id: 'p3', text: 'Mesajlaşma', votes: 15 },
{ id: 'p4', text: 'Raporlama', votes: 5 }
],
totalVotes: 40,
endsAt: new Date('2024-10-20T23:59:59'),
userVote: 'p3'
}
},
likes: {
count: 18,
isLiked: false,
users: []
},
comments: [
{
id: 'c3',
author: {
id: 'user4',
name: 'Fatma Şahin',
avatar: 'https://i.pravatar.cc/150?img=9'
},
content: 'Mesajlaşma özelliğine kesinlikle ihtiyacımız var!',
creationTime: new Date('2024-10-16T10:15:00')
}
],
isOwnPost: true
},
{
id: '3',
author: {
id: 'user5',
name: 'Zeynep Arslan',
avatar: 'https://i.pravatar.cc/150?img=10',
title: 'UI/UX Tasarımcı'
},
content:
'Yeni tasarım sistemimizin ilk prototipini hazırladık! Kullanıcı deneyimini iyileştirmek için çok çalıştık. Geri bildirimlerinizi bekliyorum! 🎨',
creationTime: new Date('2024-10-17T14:20:00'),
media: {
type: 'image',
urls: [
'https://images.unsplash.com/photo-1561070791-2526d30994b5?w=800&q=80',
'https://images.unsplash.com/photo-1586717799252-bd134ad00e26?w=800&q=80',
'https://images.unsplash.com/photo-1609921212029-bb5a28e60960?w=800&q=80'
]
},
likes: {
count: 42,
isLiked: true,
users: [
{ id: 'user1', name: 'Ahmet Yılmaz', avatar: 'https://i.pravatar.cc/150?img=12' }
]
},
comments: [
{
id: 'c4',
author: {
id: 'user6',
name: 'Can Öztürk',
avatar: 'https://i.pravatar.cc/150?img=11'
},
content: 'Tasarımlar çok şık! Renk paleti özellikle güzel 😍',
creationTime: new Date('2024-10-17T15:00:00')
},
{
id: 'c5',
author: {
id: 'user7',
name: 'Elif Yıldız',
avatar: 'https://i.pravatar.cc/150?img=20'
},
content: 'Dark mode opsiyonu da olacak mı?',
creationTime: new Date('2024-10-17T15:30:00')
}
],
isOwnPost: false
},
{
id: '4',
author: {
id: 'user8',
name: 'Burak Çelik',
avatar: 'https://i.pravatar.cc/150?img=13',
title: 'DevOps Mühendisi'
},
content:
'CI/CD pipeline güncellememiz tamamlandı! Deployment süremiz %40 azaldı. Otomasyonun gücü 💪',
creationTime: new Date('2024-10-18T08:45:00'),
media: {
type: 'video',
url: 'https://www.w3schools.com/html/mov_bbb.mp4'
},
likes: {
count: 31,
isLiked: false,
users: []
},
comments: [
{
id: 'c6',
author: {
id: 'user9',
name: 'Deniz Koç',
avatar: 'https://i.pravatar.cc/150?img=14'
},
content: 'Harika iş! Detayları paylaşabilir misin?',
creationTime: new Date('2024-10-18T09:15:00')
}
],
isOwnPost: false
},
{
id: '5',
author: {
id: 'user10',
name: 'Selin Aydın',
avatar: 'https://i.pravatar.cc/150?img=15',
title: 'İK Müdürü'
},
content:
'Ekip üyelerimize yeni eğitim programımızı duyurmak istiyorum! 🎓 React, TypeScript ve Modern Web Geliştirme konularında kapsamlı bir program hazırladık.',
creationTime: new Date('2024-10-14T16:00:00'),
likes: {
count: 56,
isLiked: true,
users: []
},
comments: [
{
id: 'c7',
author: {
id: 'user1',
name: 'Ahmet Yılmaz',
avatar: 'https://i.pravatar.cc/150?img=12'
},
content: 'Ne zaman başlıyor?',
creationTime: new Date('2024-10-14T16:30:00')
},
{
id: 'c8',
author: {
id: 'user10',
name: 'Selin Aydın',
avatar: 'https://i.pravatar.cc/150?img=15'
},
content: 'Gelecek hafta başlıyoruz! Kayıt linki mail ile paylaşılacak.',
creationTime: new Date('2024-10-14T17:00:00')
}
],
isOwnPost: false
},
{
id: '6',
author: {
id: 'user11',
name: 'Deniz Öztürk',
avatar: 'https://i.pravatar.cc/150?img=20',
title: 'Proje Yöneticisi'
},
content: 'Bugün müşteri ile harika bir toplantı yaptık! Yeni projenin detaylarını konuştuk. 🎯',
creationTime: new Date('2024-10-17T14:00:00'),
location: {
id: '4',
name: 'Sultanahmet Meydanı',
address: 'Sultanahmet Mahallesi, 34122 Fatih/İstanbul',
lat: 41.0058,
lng: 28.9768,
placeId: 'ChIJ7fVVZiy5yhQRzsXXXXXXXXk'
},
likes: {
count: 18,
isLiked: false,
users: []
},
comments: [],
isOwnPost: false
}
]

View file

@ -1,312 +0,0 @@
export interface SocialPost {
id: string
author: {
id: string
name: string
avatar: string
title: string
email?: string
phone?: string
department?: string
location?: string
}
content: string
createdAt: Date
location?: {
id: string
name: string
address: string
lat: number
lng: number
placeId?: string
}
media?: {
type: 'image' | 'video' | 'poll'
url?: string
urls?: string[]
poll?: {
question: string
options: Array<{
id: string
text: string
votes: number
}>
totalVotes: number
endsAt: Date
userVote?: string
}
}
likes: {
count: number
isLiked: boolean
users: Array<{ id: string; name: string; avatar: string }>
}
comments: Array<{
id: string
author: {
id: string
name: string
avatar: string
}
content: string
createdAt: Date
}>
isOwnPost: boolean
}
export const mockSocialPosts: SocialPost[] = [
{
id: '1',
author: {
id: 'user1',
name: 'Ahmet Yılmaz',
avatar: 'https://i.pravatar.cc/150?img=12',
title: 'Yazılım Geliştirici',
email: 'ahmet.yilmaz@sozsoft.com',
phone: '+90 532 123 45 67',
department: 'Yazılım Geliştirme',
location: 'İstanbul, Türkiye'
},
content:
'Yeni proje üzerinde çalışıyoruz! React ve TypeScript ile harika bir deneyim oluşturuyoruz. Ekip çalışması harika gidiyor! 🚀',
createdAt: new Date('2024-10-15T10:30:00'),
location: {
id: '1',
name: 'Taksim Meydanı',
address: 'Taksim, Gümüşsuyu Mahallesi, 34437 Beyoğlu/İstanbul',
lat: 41.0369,
lng: 28.9850,
placeId: 'ChIJBQRGmL25yhQRXwqRTHAwAAQ'
},
media: {
type: 'image',
url: 'https://images.unsplash.com/photo-1633356122544-f134324a6cee?w=800&q=80'
},
likes: {
count: 24,
isLiked: true,
users: [
{ id: 'user2', name: 'Ayşe Demir', avatar: 'https://i.pravatar.cc/150?img=5' },
{ id: 'user3', name: 'Mehmet Kaya', avatar: 'https://i.pravatar.cc/150?img=8' }
]
},
comments: [
{
id: 'c1',
author: {
id: 'user2',
name: 'Ayşe Demir',
avatar: 'https://i.pravatar.cc/150?img=5'
},
content: 'Harika görünüyor! Başarılar 👏',
createdAt: new Date('2024-10-15T11:00:00')
},
{
id: 'c2',
author: {
id: 'user3',
name: 'Mehmet Kaya',
avatar: 'https://i.pravatar.cc/150?img=8'
},
content: 'TypeScript gerçekten fark yaratıyor!',
createdAt: new Date('2024-10-15T11:30:00')
}
],
isOwnPost: false
},
{
id: '2',
author: {
id: 'currentUser',
name: 'Siz',
avatar: 'https://i.pravatar.cc/150?img=1',
title: 'Proje Yöneticisi'
},
content:
'Bu hafta sprint planlamasını yaptık. Ekibimizle birlikte yeni özellikleri değerlendirdik. Heyecan verici bir hafta olacak!',
createdAt: new Date('2024-10-16T09:00:00'),
media: {
type: 'poll',
poll: {
question: 'Hangi özelliği öncelikli olarak geliştirmeliyiz?',
options: [
{ id: 'p1', text: 'Kullanıcı profilleri', votes: 12 },
{ id: 'p2', text: 'Bildirim sistemi', votes: 8 },
{ id: 'p3', text: 'Mesajlaşma', votes: 15 },
{ id: 'p4', text: 'Raporlama', votes: 5 }
],
totalVotes: 40,
endsAt: new Date('2024-10-20T23:59:59'),
userVote: 'p3'
}
},
likes: {
count: 18,
isLiked: false,
users: []
},
comments: [
{
id: 'c3',
author: {
id: 'user4',
name: 'Fatma Şahin',
avatar: 'https://i.pravatar.cc/150?img=9'
},
content: 'Mesajlaşma özelliğine kesinlikle ihtiyacımız var!',
createdAt: new Date('2024-10-16T10:15:00')
}
],
isOwnPost: true
},
{
id: '3',
author: {
id: 'user5',
name: 'Zeynep Arslan',
avatar: 'https://i.pravatar.cc/150?img=10',
title: 'UI/UX Tasarımcı'
},
content:
'Yeni tasarım sistemimizin ilk prototipini hazırladık! Kullanıcı deneyimini iyileştirmek için çok çalıştık. Geri bildirimlerinizi bekliyorum! 🎨',
createdAt: new Date('2024-10-17T14:20:00'),
media: {
type: 'image',
urls: [
'https://images.unsplash.com/photo-1561070791-2526d30994b5?w=800&q=80',
'https://images.unsplash.com/photo-1586717799252-bd134ad00e26?w=800&q=80',
'https://images.unsplash.com/photo-1609921212029-bb5a28e60960?w=800&q=80'
]
},
likes: {
count: 42,
isLiked: true,
users: [
{ id: 'user1', name: 'Ahmet Yılmaz', avatar: 'https://i.pravatar.cc/150?img=12' }
]
},
comments: [
{
id: 'c4',
author: {
id: 'user6',
name: 'Can Öztürk',
avatar: 'https://i.pravatar.cc/150?img=11'
},
content: 'Tasarımlar çok şık! Renk paleti özellikle güzel 😍',
createdAt: new Date('2024-10-17T15:00:00')
},
{
id: 'c5',
author: {
id: 'user7',
name: 'Elif Yıldız',
avatar: 'https://i.pravatar.cc/150?img=20'
},
content: 'Dark mode opsiyonu da olacak mı?',
createdAt: new Date('2024-10-17T15:30:00')
}
],
isOwnPost: false
},
{
id: '4',
author: {
id: 'user8',
name: 'Burak Çelik',
avatar: 'https://i.pravatar.cc/150?img=13',
title: 'DevOps Mühendisi'
},
content:
'CI/CD pipeline güncellememiz tamamlandı! Deployment süremiz %40 azaldı. Otomasyonun gücü 💪',
createdAt: new Date('2024-10-18T08:45:00'),
media: {
type: 'video',
url: 'https://www.w3schools.com/html/mov_bbb.mp4'
},
likes: {
count: 31,
isLiked: false,
users: []
},
comments: [
{
id: 'c6',
author: {
id: 'user9',
name: 'Deniz Koç',
avatar: 'https://i.pravatar.cc/150?img=14'
},
content: 'Harika iş! Detayları paylaşabilir misin?',
createdAt: new Date('2024-10-18T09:15:00')
}
],
isOwnPost: false
},
{
id: '5',
author: {
id: 'user10',
name: 'Selin Aydın',
avatar: 'https://i.pravatar.cc/150?img=15',
title: 'İK Müdürü'
},
content:
'Ekip üyelerimize yeni eğitim programımızı duyurmak istiyorum! 🎓 React, TypeScript ve Modern Web Geliştirme konularında kapsamlı bir program hazırladık.',
createdAt: new Date('2024-10-14T16:00:00'),
likes: {
count: 56,
isLiked: true,
users: []
},
comments: [
{
id: 'c7',
author: {
id: 'user1',
name: 'Ahmet Yılmaz',
avatar: 'https://i.pravatar.cc/150?img=12'
},
content: 'Ne zaman başlıyor?',
createdAt: new Date('2024-10-14T16:30:00')
},
{
id: 'c8',
author: {
id: 'user10',
name: 'Selin Aydın',
avatar: 'https://i.pravatar.cc/150?img=15'
},
content: 'Gelecek hafta başlıyoruz! Kayıt linki mail ile paylaşılacak.',
createdAt: new Date('2024-10-14T17:00:00')
}
],
isOwnPost: false
},
{
id: '6',
author: {
id: 'user11',
name: 'Deniz Öztürk',
avatar: 'https://i.pravatar.cc/150?img=20',
title: 'Proje Yöneticisi'
},
content: 'Bugün müşteri ile harika bir toplantı yaptık! Yeni projenin detaylarını konuştuk. 🎯',
createdAt: new Date('2024-10-17T14:00:00'),
location: {
id: '4',
name: 'Sultanahmet Meydanı',
address: 'Sultanahmet Mahallesi, 34122 Fatih/İstanbul',
lat: 41.0058,
lng: 28.9768,
placeId: 'ChIJ7fVVZiy5yhQRzsXXXXXXXXk'
},
likes: {
count: 18,
isLiked: false,
users: []
},
comments: [],
isOwnPost: false
}
]

297
ui/src/types/intranet.ts Normal file
View file

@ -0,0 +1,297 @@
import { HrEmployee } from './hr'
// Duyuru
export interface Announcement {
id: string
title: string
content: string
excerpt: string
category: 'general' | 'hr' | 'it' | 'event' | 'urgent'
author: HrEmployee
publishDate: Date
expiryDate?: Date
isPinned: boolean
attachments?: { name: string; url: string; size: string }[]
departments?: string[]
viewCount: number
imageUrl?: string
}
// Etkinlik Yorumu
export interface EventComment {
id: string
author: HrEmployee
content: string
creationTime: Date
likes: number
}
// Etkinlik
export interface CalendarEvent {
id: string
title: string
description: string
type: 'social' | 'training' | 'company' | 'sport' | 'culture'
date: Date
location: string
organizer: HrEmployee
participants: number
photos: string[]
comments: EventComment[]
likes: number
isPublished: boolean
}
// Harcama
export interface ExpenseRequest {
id: string
employee: HrEmployee
category: 'travel' | 'meal' | 'accommodation' | 'transport' | 'other'
amount: number
currency: string
date: Date
description: string
project?: string
receipts: { name: string; url: string; size: string }[]
status: 'pending' | 'approved' | 'rejected'
approver?: HrEmployee
approvalDate?: Date
notes?: string
creationTime: Date
}
// Görev
export interface Task {
id: string
title: string
description: string
project: string
assignedTo: HrEmployee[]
assignedBy: HrEmployee
priority: 'low' | 'medium' | 'high' | 'urgent'
status: 'todo' | 'in-progress' | 'review' | 'done'
dueDate: Date
creationTime: Date
labels: string[]
attachments?: { name: string; url: string }[]
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[]
}
// Doğum günü
export interface Birthday {
employee: HrEmployee
date: Date
age?: number
}
// İş yıldönümü
export interface WorkAnniversary {
employee: HrEmployee
hireDate: Date
years: number
}
// Hızlı Erişim
export interface QuickLink {
id: string
name: string
description: string
icon: string
url: string
color: string
category: string
}
// Eğitim
export interface Training {
id: string
title: string
description: string
instructor: string
category: 'technical' | 'soft-skills' | 'management' | 'compliance' | 'other'
type: 'online' | 'classroom' | 'hybrid'
duration: number // saat
startDate: Date
endDate: Date
maxParticipants: number
enrolled: number
status: 'upcoming' | 'ongoing' | 'completed'
location?: string
thumbnail?: string
}
// Sertifika
export interface Certificate {
id: string
employee: HrEmployee
trainingTitle: string
issueDate: Date
expiryDate?: Date
certificateUrl: string
score?: number
}
// Rezervasyon
export interface Reservation {
id: string
type: 'room' | 'vehicle' | 'equipment'
resourceName: string
bookedBy: HrEmployee
startDate: Date
endDate: Date
purpose: string
status: 'pending' | 'approved' | 'rejected' | 'completed'
participants?: number
notes?: string
}
// Yemek Menüsü
export interface MealMenu {
id: string
date: Date
dayOfWeek: string
meals: {
type: 'breakfast' | 'lunch' | 'dinner'
items: string[]
calories?: number
}[]
}
// Servis
export interface ShuttleRoute {
id: string
name: string
route: string[]
departureTime: string
arrivalTime: string
capacity: number
available: number
type: 'morning' | 'evening'
}
// Anket
export interface Survey {
id: string
title: string
description: string
creatorId: HrEmployee
creationTime: Date
deadline: Date
totalQuestions: number
responses: number
targetAudience: string[]
status: 'draft' | 'active' | 'closed'
isAnonymous: boolean
}
// 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
}
export interface MediaItem {
id: string
type: 'image' | 'video'
url: string
file?: File
}
export interface LightboxMedia {
type: 'image' | 'video'
url?: string
urls?: string[]
}
export interface Location {
id: string
name: string
address: string
lat: number
lng: number
placeId?: string
}
export interface SocialPost {
id: string
author: {
id: string
name: string
avatar: string
title: string
email?: string
phone?: string
department?: string
location?: string
}
content: string
creationTime: Date
location?: {
id: string
name: string
address: string
lat: number
lng: number
placeId?: string
}
media?: {
type: 'image' | 'video' | 'poll'
url?: string
urls?: string[]
poll?: {
question: string
options: Array<{
id: string
text: string
votes: number
}>
totalVotes: number
endsAt: Date
userVote?: string
}
}
likes: {
count: number
isLiked: boolean
users: Array<{ id: string; name: string; avatar: string }>
}
comments: Array<{
id: string
author: {
id: string
name: string
avatar: string
}
content: string
creationTime: Date
}>
isOwnPost: boolean
}

View file

@ -3,14 +3,15 @@ import { motion, AnimatePresence } from 'framer-motion'
import classNames from 'classnames' import classNames from 'classnames'
import EmojiPicker, { EmojiClickData } from 'emoji-picker-react' import EmojiPicker, { EmojiClickData } from 'emoji-picker-react'
import { import {
HiOutlineChartBar, FaChartBar,
HiOutlineEmojiHappy, FaSmile,
HiX, FaTimes,
HiOutlineCollection, FaImages,
HiOutlineLocationMarker FaMapMarkerAlt
} from 'react-icons/hi' } from 'react-icons/fa'
import MediaManager, { MediaItem } from './MediaManager' import MediaManager from './MediaManager'
import LocationPicker, { Location } from './LocationPicker' import LocationPicker from './LocationPicker'
import { Location, MediaItem } from '@/types/intranet'
interface CreatePostProps { interface CreatePostProps {
onCreatePost: (post: { onCreatePost: (post: {
@ -220,7 +221,7 @@ const CreatePost: React.FC<CreatePostProps> = ({ onCreatePost }) => {
onClick={() => removeMediaItem(item.id)} onClick={() => removeMediaItem(item.id)}
className="absolute -top-2 -right-2 p-1 bg-red-600 text-white rounded-full opacity-0 group-hover:opacity-100 transition-opacity" className="absolute -top-2 -right-2 p-1 bg-red-600 text-white rounded-full opacity-0 group-hover:opacity-100 transition-opacity"
> >
<HiX className="w-4 h-4" /> <FaTimes className="w-4 h-4" />
</button> </button>
<div className="absolute bottom-1 left-1 px-2 py-0.5 bg-black bg-opacity-70 text-white text-xs rounded"> <div className="absolute bottom-1 left-1 px-2 py-0.5 bg-black bg-opacity-70 text-white text-xs rounded">
{item.type === 'image' ? '📷' : '🎥'} {item.type === 'image' ? '📷' : '🎥'}
@ -232,7 +233,7 @@ const CreatePost: React.FC<CreatePostProps> = ({ onCreatePost }) => {
onClick={() => setShowMediaManager(true)} onClick={() => setShowMediaManager(true)}
className="h-24 border-2 border-dashed border-gray-300 dark:border-gray-600 rounded-lg flex items-center justify-center hover:border-blue-500 hover:bg-blue-50 dark:hover:bg-blue-900/20 transition-colors" className="h-24 border-2 border-dashed border-gray-300 dark:border-gray-600 rounded-lg flex items-center justify-center hover:border-blue-500 hover:bg-blue-50 dark:hover:bg-blue-900/20 transition-colors"
> >
<HiOutlineCollection className="w-6 h-6 text-gray-400" /> <FaImages className="w-6 h-6 text-gray-400" />
</button> </button>
</div> </div>
</motion.div> </motion.div>
@ -258,7 +259,7 @@ const CreatePost: React.FC<CreatePostProps> = ({ onCreatePost }) => {
</div> </div>
<div className="p-3 border border-gray-300 dark:border-gray-600 rounded-lg bg-gray-50 dark:bg-gray-700"> <div className="p-3 border border-gray-300 dark:border-gray-600 rounded-lg bg-gray-50 dark:bg-gray-700">
<div className="flex items-start gap-2"> <div className="flex items-start gap-2">
<HiOutlineLocationMarker className="w-5 h-5 text-blue-600 mt-0.5 flex-shrink-0" /> <FaMapMarkerAlt className="w-5 h-5 text-blue-600 mt-0.5 flex-shrink-0" />
<div className="flex-1 min-w-0"> <div className="flex-1 min-w-0">
<h3 className="font-semibold text-gray-900 dark:text-gray-100 mb-1"> <h3 className="font-semibold text-gray-900 dark:text-gray-100 mb-1">
{location.name} {location.name}
@ -315,7 +316,7 @@ const CreatePost: React.FC<CreatePostProps> = ({ onCreatePost }) => {
onClick={() => removePollOption(index)} onClick={() => removePollOption(index)}
className="p-2 text-gray-500 hover:text-red-600" className="p-2 text-gray-500 hover:text-red-600"
> >
<HiX className="w-5 h-5" /> <FaTimes className="w-5 h-5" />
</button> </button>
)} )}
</div> </div>
@ -365,7 +366,7 @@ const CreatePost: React.FC<CreatePostProps> = ({ onCreatePost }) => {
)} )}
title={mediaType === 'media' ? 'Medyaları düzenle' : 'Medya ekle'} title={mediaType === 'media' ? 'Medyaları düzenle' : 'Medya ekle'}
> >
<HiOutlineCollection className="w-5 h-5" /> <FaImages className="w-5 h-5" />
{mediaType === 'media' && mediaItems.length > 0 && ( {mediaType === 'media' && mediaItems.length > 0 && (
<span className="absolute -top-1 -right-1 w-4 h-4 bg-blue-600 text-white text-xs rounded-full flex items-center justify-center"> <span className="absolute -top-1 -right-1 w-4 h-4 bg-blue-600 text-white text-xs rounded-full flex items-center justify-center">
{mediaItems.length} {mediaItems.length}
@ -389,7 +390,7 @@ const CreatePost: React.FC<CreatePostProps> = ({ onCreatePost }) => {
)} )}
title={mediaType === 'poll' ? 'Anketi kaldır' : 'Anket ekle'} title={mediaType === 'poll' ? 'Anketi kaldır' : 'Anket ekle'}
> >
<HiOutlineChartBar className="w-5 h-5" /> <FaChartBar className="w-5 h-5" />
</button> </button>
<button <button
type="button" type="button"
@ -397,7 +398,7 @@ const CreatePost: React.FC<CreatePostProps> = ({ onCreatePost }) => {
className="p-2 text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-full transition-colors" className="p-2 text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-full transition-colors"
title="Emoji ekle" title="Emoji ekle"
> >
<HiOutlineEmojiHappy className="w-5 h-5" /> <FaSmile className="w-5 h-5" />
</button> </button>
<button <button
type="button" type="button"
@ -410,7 +411,7 @@ const CreatePost: React.FC<CreatePostProps> = ({ onCreatePost }) => {
)} )}
title={location ? 'Konumu değiştir' : 'Konum ekle'} title={location ? 'Konumu değiştir' : 'Konum ekle'}
> >
<HiOutlineLocationMarker className="w-5 h-5" /> <FaMapMarkerAlt className="w-5 h-5" />
</button> </button>
{/* Emoji Picker */} {/* Emoji Picker */}

View file

@ -1,6 +1,6 @@
import React from 'react' import React from 'react'
import { HiOutlineExternalLink, HiOutlineLocationMarker } from 'react-icons/hi' import { FaExternalLinkAlt, FaMapMarkerAlt } from 'react-icons/fa'
import type { Location } from './LocationPicker' import { Location } from '@/types/intranet'
interface LocationMapProps { interface LocationMapProps {
location: Location location: Location
@ -52,7 +52,7 @@ const LocationMap: React.FC<LocationMapProps> = ({
{/* Location Info */} {/* Location Info */}
<div className="absolute bottom-0 left-0 right-0 p-4 text-white pointer-events-none"> <div className="absolute bottom-0 left-0 right-0 p-4 text-white pointer-events-none">
<div className="flex items-start gap-2"> <div className="flex items-start gap-2">
<HiOutlineLocationMarker className="w-5 h-5 mt-0.5 flex-shrink-0" /> <FaMapMarkerAlt className="w-5 h-5 mt-0.5 flex-shrink-0" />
<div className="flex-1 min-w-0"> <div className="flex-1 min-w-0">
<h3 className="font-bold text-lg mb-1 drop-shadow-lg">{location.name}</h3> <h3 className="font-bold text-lg mb-1 drop-shadow-lg">{location.name}</h3>
<p className="text-sm text-white/90 drop-shadow-md line-clamp-2"> <p className="text-sm text-white/90 drop-shadow-md line-clamp-2">
@ -82,7 +82,7 @@ const LocationMap: React.FC<LocationMapProps> = ({
onClick={handleOpenGoogleMaps} onClick={handleOpenGoogleMaps}
className="w-full flex items-center justify-center gap-2 px-4 py-2.5 bg-blue-600 hover:bg-blue-700 text-white font-medium rounded-lg transition-colors" className="w-full flex items-center justify-center gap-2 px-4 py-2.5 bg-blue-600 hover:bg-blue-700 text-white font-medium rounded-lg transition-colors"
> >
<HiOutlineExternalLink className="w-5 h-5" /> <FaExternalLinkAlt className="w-5 h-5" />
<span>Google Maps'te </span> <span>Google Maps'te </span>
</button> </button>
<p className="text-xs text-gray-500 dark:text-gray-400 mt-2 text-center"> <p className="text-xs text-gray-500 dark:text-gray-400 mt-2 text-center">

View file

@ -1,16 +1,8 @@
import React, { useState, useEffect, useRef } from 'react' import React, { useState, useEffect, useRef } from 'react'
import { motion } from 'framer-motion' import { motion } from 'framer-motion'
import { HiX, HiOutlineSearch, HiOutlineLocationMarker } from 'react-icons/hi' import { FaTimes, FaSearch, FaMapMarkerAlt } from 'react-icons/fa'
import classNames from 'classnames' import classNames from 'classnames'
import { Location } from '@/types/intranet'
export interface Location {
id: string
name: string
address: string
lat: number
lng: number
placeId?: string
}
interface LocationPickerProps { interface LocationPickerProps {
onSelect: (location: Location) => void onSelect: (location: Location) => void
@ -227,14 +219,14 @@ const LocationPicker: React.FC<LocationPickerProps> = ({ onSelect, onClose }) =>
onClick={onClose} onClick={onClose}
className="p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-full transition-colors" className="p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-full transition-colors"
> >
<HiX className="w-5 h-5 text-gray-500 dark:text-gray-400" /> <FaTimes className="w-5 h-5 text-gray-500 dark:text-gray-400" />
</button> </button>
</div> </div>
{/* Search */} {/* Search */}
<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">
<div className="relative"> <div className="relative">
<HiOutlineSearch className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-gray-400" /> <FaSearch className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-gray-400" />
<input <input
ref={searchInputRef} ref={searchInputRef}
type="text" type="text"
@ -266,12 +258,12 @@ const LocationPicker: React.FC<LocationPickerProps> = ({ onSelect, onClose }) =>
</div> </div>
) : error ? ( ) : error ? (
<div className="text-center py-12"> <div className="text-center py-12">
<HiOutlineLocationMarker className="w-16 h-16 mx-auto mb-4 text-red-400" /> <FaMapMarkerAlt className="w-16 h-16 mx-auto mb-4 text-red-400" />
<p className="text-red-500 dark:text-red-400">{error}</p> <p className="text-red-500 dark:text-red-400">{error}</p>
</div> </div>
) : searchQuery.trim() === '' ? ( ) : searchQuery.trim() === '' ? (
<div className="text-center py-12"> <div className="text-center py-12">
<HiOutlineSearch className="w-16 h-16 mx-auto mb-4 text-gray-400" /> <FaSearch className="w-16 h-16 mx-auto mb-4 text-gray-400" />
<p className="text-gray-500 dark:text-gray-400"> <p className="text-gray-500 dark:text-gray-400">
Aramak istediğiniz konumu yazın Aramak istediğiniz konumu yazın
</p> </p>
@ -281,7 +273,7 @@ const LocationPicker: React.FC<LocationPickerProps> = ({ onSelect, onClose }) =>
</div> </div>
) : locations.length === 0 ? ( ) : locations.length === 0 ? (
<div className="text-center py-12"> <div className="text-center py-12">
<HiOutlineLocationMarker className="w-16 h-16 mx-auto mb-4 text-gray-400" /> <FaMapMarkerAlt className="w-16 h-16 mx-auto mb-4 text-gray-400" />
<p className="text-gray-500 dark:text-gray-400"> <p className="text-gray-500 dark:text-gray-400">
Konum bulunamadı. Farklı bir arama yapın. Konum bulunamadı. Farklı bir arama yapın.
</p> </p>
@ -301,7 +293,7 @@ const LocationPicker: React.FC<LocationPickerProps> = ({ onSelect, onClose }) =>
> >
<div className="flex items-start gap-3"> <div className="flex items-start gap-3">
<div className="mt-1"> <div className="mt-1">
<HiOutlineLocationMarker <FaMapMarkerAlt
className={classNames( className={classNames(
'w-5 h-5', 'w-5 h-5',
selectedLocation?.id === location.id selectedLocation?.id === location.id
@ -353,7 +345,7 @@ const LocationPicker: React.FC<LocationPickerProps> = ({ onSelect, onClose }) =>
<div className="text-sm text-gray-600 dark:text-gray-400"> <div className="text-sm text-gray-600 dark:text-gray-400">
{selectedLocation ? ( {selectedLocation ? (
<span className="flex items-center gap-2"> <span className="flex items-center gap-2">
<HiOutlineLocationMarker className="w-4 h-4 text-blue-600" /> <FaMapMarkerAlt className="w-4 h-4 text-blue-600" />
<span className="font-medium text-gray-900 dark:text-gray-100"> <span className="font-medium text-gray-900 dark:text-gray-100">
{selectedLocation.name} {selectedLocation.name}
</span> </span>

View file

@ -5,12 +5,7 @@ import Video from 'yet-another-react-lightbox/plugins/video'
import Zoom from 'yet-another-react-lightbox/plugins/zoom' import Zoom from 'yet-another-react-lightbox/plugins/zoom'
import Counter from 'yet-another-react-lightbox/plugins/counter' import Counter from 'yet-another-react-lightbox/plugins/counter'
import 'yet-another-react-lightbox/plugins/counter.css' import 'yet-another-react-lightbox/plugins/counter.css'
import { LightboxMedia } from '@/types/intranet'
export interface LightboxMedia {
type: 'image' | 'video'
url?: string
urls?: string[]
}
interface MediaLightboxProps { interface MediaLightboxProps {
isOpen: boolean isOpen: boolean

View file

@ -1,14 +1,8 @@
import React, { useState } from 'react' import React, { useState } from 'react'
import { motion, AnimatePresence } from 'framer-motion' import { motion } from 'framer-motion'
import { HiX, HiPlus, HiOutlineLink, HiOutlineUpload } from 'react-icons/hi' import { FaTimes, FaLink, FaUpload } from 'react-icons/fa'
import classNames from 'classnames' import classNames from 'classnames'
import { MediaItem } from '@/types/intranet'
export interface MediaItem {
id: string
type: 'image' | 'video'
url: string
file?: File
}
interface MediaManagerProps { interface MediaManagerProps {
media: MediaItem[] media: MediaItem[]
@ -68,7 +62,7 @@ const MediaManager: React.FC<MediaManagerProps> = ({ media, onChange, onClose })
onClick={onClose} onClick={onClose}
className="p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-full transition-colors" className="p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-full transition-colors"
> >
<HiX className="w-5 h-5 text-gray-500 dark:text-gray-400" /> <FaTimes className="w-5 h-5 text-gray-500 dark:text-gray-400" />
</button> </button>
</div> </div>
@ -84,7 +78,7 @@ const MediaManager: React.FC<MediaManagerProps> = ({ media, onChange, onClose })
)} )}
> >
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<HiOutlineUpload className="w-5 h-5" /> <FaUpload className="w-5 h-5" />
<span>Bilgisayarımdan Seç</span> <span>Bilgisayarımdan Seç</span>
</div> </div>
</button> </button>
@ -98,7 +92,7 @@ const MediaManager: React.FC<MediaManagerProps> = ({ media, onChange, onClose })
)} )}
> >
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<HiOutlineLink className="w-5 h-5" /> <FaLink className="w-5 h-5" />
<span>URL ile Ekle</span> <span>URL ile Ekle</span>
</div> </div>
</button> </button>
@ -110,7 +104,7 @@ const MediaManager: React.FC<MediaManagerProps> = ({ media, onChange, onClose })
<div> <div>
<label className="block"> <label className="block">
<div className="border-2 border-dashed border-gray-300 dark:border-gray-600 rounded-lg p-8 text-center hover:border-blue-500 hover:bg-blue-50 dark:hover:bg-blue-900/20 transition-colors cursor-pointer"> <div className="border-2 border-dashed border-gray-300 dark:border-gray-600 rounded-lg p-8 text-center hover:border-blue-500 hover:bg-blue-50 dark:hover:bg-blue-900/20 transition-colors cursor-pointer">
<HiOutlineUpload className="w-12 h-12 mx-auto mb-4 text-gray-400" /> <FaUpload className="w-12 h-12 mx-auto mb-4 text-gray-400" />
<p className="text-gray-700 dark:text-gray-300 font-medium mb-1"> <p className="text-gray-700 dark:text-gray-300 font-medium mb-1">
Dosya seçmek için tıklayın Dosya seçmek için tıklayın
</p> </p>
@ -207,7 +201,7 @@ const MediaManager: React.FC<MediaManagerProps> = ({ media, onChange, onClose })
onClick={() => removeMedia(item.id)} onClick={() => removeMedia(item.id)}
className="absolute -top-2 -right-2 p-1 bg-red-600 text-white rounded-full opacity-0 group-hover:opacity-100 transition-opacity" className="absolute -top-2 -right-2 p-1 bg-red-600 text-white rounded-full opacity-0 group-hover:opacity-100 transition-opacity"
> >
<HiX className="w-4 h-4" /> <FaTimes className="w-4 h-4" />
</button> </button>
<div className="absolute bottom-1 left-1 px-2 py-0.5 bg-black bg-opacity-70 text-white text-xs rounded"> <div className="absolute bottom-1 left-1 px-2 py-0.5 bg-black bg-opacity-70 text-white text-xs rounded">
{item.type === 'image' ? '📷' : '🎥'} {item.type === 'image' ? '📷' : '🎥'}

View file

@ -5,16 +5,16 @@ import dayjs from 'dayjs'
import relativeTime from 'dayjs/plugin/relativeTime' import relativeTime from 'dayjs/plugin/relativeTime'
import 'dayjs/locale/tr' import 'dayjs/locale/tr'
import { import {
HiHeart, FaHeart,
HiOutlineHeart, FaRegHeart,
HiOutlineChatAlt2, FaRegCommentAlt,
HiOutlineTrash, FaTrash,
HiOutlinePaperAirplane, FaPaperPlane,
} from 'react-icons/hi' } from 'react-icons/fa'
import { SocialPost } from '../../../mocks/mockSocialPosts'
import MediaLightbox from './MediaLightbox' import MediaLightbox from './MediaLightbox'
import LocationMap from './LocationMap' import LocationMap from './LocationMap'
import UserProfileCard from './UserProfileCard' import UserProfileCard from './UserProfileCard'
import { SocialPost } from '@/types/intranet'
dayjs.extend(relativeTime) dayjs.extend(relativeTime)
dayjs.locale('tr') dayjs.locale('tr')
@ -296,7 +296,7 @@ const PostItem: React.FC<PostItemProps> = ({ post, onLike, onComment, onDelete,
{post.author.name} {post.author.name}
</h3> </h3>
<p className="text-sm text-gray-600 dark:text-gray-400"> <p className="text-sm text-gray-600 dark:text-gray-400">
{post.author.title} {dayjs(post.createdAt).fromNow()} {post.author.title} {dayjs(post.creationTime).fromNow()}
</p> </p>
</div> </div>
</div> </div>
@ -306,7 +306,7 @@ const PostItem: React.FC<PostItemProps> = ({ post, onLike, onComment, onDelete,
className="p-2 text-gray-500 hover:text-red-600 hover:bg-red-50 dark:hover:bg-red-900/20 rounded-full transition-colors" className="p-2 text-gray-500 hover:text-red-600 hover:bg-red-50 dark:hover:bg-red-900/20 rounded-full transition-colors"
title="Gönderiyi sil" title="Gönderiyi sil"
> >
<HiOutlineTrash className="w-5 h-5" /> <FaTrash className="w-5 h-5" />
</button> </button>
)} )}
</div> </div>
@ -336,9 +336,9 @@ const PostItem: React.FC<PostItemProps> = ({ post, onLike, onComment, onDelete,
)} )}
> >
{post.likes.isLiked ? ( {post.likes.isLiked ? (
<HiHeart className="w-5 h-5" /> <FaHeart className="w-5 h-5" />
) : ( ) : (
<HiOutlineHeart className="w-5 h-5" /> <FaRegHeart className="w-5 h-5" />
)} )}
<span className="text-sm font-medium">{post.likes.count}</span> <span className="text-sm font-medium">{post.likes.count}</span>
</button> </button>
@ -347,7 +347,7 @@ const PostItem: React.FC<PostItemProps> = ({ post, onLike, onComment, onDelete,
onClick={() => setShowComments(!showComments)} onClick={() => setShowComments(!showComments)}
className="flex items-center gap-2 text-gray-600 dark:text-gray-400 hover:text-blue-600 transition-colors" className="flex items-center gap-2 text-gray-600 dark:text-gray-400 hover:text-blue-600 transition-colors"
> >
<HiOutlineChatAlt2 className="w-5 h-5" /> <FaRegCommentAlt className="w-5 h-5" />
<span className="text-sm font-medium">{post.comments.length}</span> <span className="text-sm font-medium">{post.comments.length}</span>
</button> </button>
</div> </div>
@ -376,7 +376,7 @@ const PostItem: React.FC<PostItemProps> = ({ post, onLike, onComment, onDelete,
disabled={!commentText.trim()} disabled={!commentText.trim()}
className="p-2 bg-blue-600 text-white rounded-full hover:bg-blue-700 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors" className="p-2 bg-blue-600 text-white rounded-full hover:bg-blue-700 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors"
> >
<HiOutlinePaperAirplane className="w-5 h-5" /> <FaPaperPlane className="w-5 h-5" />
</button> </button>
</div> </div>
</form> </form>
@ -417,7 +417,7 @@ const PostItem: React.FC<PostItemProps> = ({ post, onLike, onComment, onDelete,
<p className="text-sm text-gray-800 dark:text-gray-200">{comment.content}</p> <p className="text-sm text-gray-800 dark:text-gray-200">{comment.content}</p>
</div> </div>
<p className="text-xs text-gray-500 dark:text-gray-400 mt-1 ml-4"> <p className="text-xs text-gray-500 dark:text-gray-400 mt-1 ml-4">
{dayjs(comment.createdAt).fromNow()} {dayjs(comment.creationTime).fromNow()}
</p> </p>
</div> </div>
</div> </div>

View file

@ -1,6 +1,6 @@
import React from 'react' import React from 'react'
import { motion } from 'framer-motion' import { motion } from 'framer-motion'
import { HiMail, HiPhone, HiBriefcase, HiLocationMarker } from 'react-icons/hi' import { FaEnvelope, FaPhone, FaBriefcase, FaMapMarkerAlt } from 'react-icons/fa'
interface UserProfileCardProps { interface UserProfileCardProps {
user: { user: {
@ -39,7 +39,7 @@ const UserProfileCard: React.FC<UserProfileCardProps> = ({ user, position = 'bot
{user.name} {user.name}
</h3> </h3>
<p className="text-sm text-gray-600 dark:text-gray-400 flex items-center gap-1"> <p className="text-sm text-gray-600 dark:text-gray-400 flex items-center gap-1">
<HiBriefcase className="w-4 h-4" /> <FaBriefcase className="w-4 h-4" />
{user.title} {user.title}
</p> </p>
</div> </div>
@ -49,7 +49,7 @@ const UserProfileCard: React.FC<UserProfileCardProps> = ({ user, position = 'bot
<div className="space-y-2"> <div className="space-y-2">
{user.email && ( {user.email && (
<div className="flex items-center gap-2 text-sm"> <div className="flex items-center gap-2 text-sm">
<HiMail className="w-4 h-4 text-gray-400 flex-shrink-0" /> <FaEnvelope className="w-4 h-4 text-gray-400 flex-shrink-0" />
<a <a
href={`mailto:${user.email}`} href={`mailto:${user.email}`}
className="text-blue-600 dark:text-blue-400 hover:underline truncate" className="text-blue-600 dark:text-blue-400 hover:underline truncate"
@ -61,7 +61,7 @@ const UserProfileCard: React.FC<UserProfileCardProps> = ({ user, position = 'bot
{user.phone && ( {user.phone && (
<div className="flex items-center gap-2 text-sm"> <div className="flex items-center gap-2 text-sm">
<HiPhone className="w-4 h-4 text-gray-400 flex-shrink-0" /> <FaPhone className="w-4 h-4 text-gray-400 flex-shrink-0" />
<a <a
href={`tel:${user.phone}`} href={`tel:${user.phone}`}
className="text-gray-700 dark:text-gray-300 hover:text-blue-600 dark:hover:text-blue-400" className="text-gray-700 dark:text-gray-300 hover:text-blue-600 dark:hover:text-blue-400"
@ -73,14 +73,14 @@ const UserProfileCard: React.FC<UserProfileCardProps> = ({ user, position = 'bot
{user.department && ( {user.department && (
<div className="flex items-center gap-2 text-sm"> <div className="flex items-center gap-2 text-sm">
<HiBriefcase className="w-4 h-4 text-gray-400 flex-shrink-0" /> <FaBriefcase className="w-4 h-4 text-gray-400 flex-shrink-0" />
<span className="text-gray-700 dark:text-gray-300">{user.department}</span> <span className="text-gray-700 dark:text-gray-300">{user.department}</span>
</div> </div>
)} )}
{user.location && ( {user.location && (
<div className="flex items-center gap-2 text-sm"> <div className="flex items-center gap-2 text-sm">
<HiLocationMarker className="w-4 h-4 text-gray-400 flex-shrink-0" /> <FaMapMarkerAlt className="w-4 h-4 text-gray-400 flex-shrink-0" />
<span className="text-gray-700 dark:text-gray-300">{user.location}</span> <span className="text-gray-700 dark:text-gray-300">{user.location}</span>
</div> </div>
)} )}

View file

@ -1,10 +1,10 @@
import React, { useState } from 'react' import React, { useState } from 'react'
import { AnimatePresence } from 'framer-motion' import { AnimatePresence } from 'framer-motion'
import { mockSocialPosts, SocialPost } from '../../../mocks/mockSocialPosts'
import PostItem from './PostItem' import PostItem from './PostItem'
import { MediaItem } from './MediaManager' import { MediaItem } from './MediaManager'
import CreatePost from './CreatePost' import CreatePost from './CreatePost'
import { Location } from './LocationPicker' import { Location, SocialPost } from '@/types/intranet'
import { mockSocialPosts } from '@/mocks/mockIntranetData'
const SocialWall: React.FC = () => { const SocialWall: React.FC = () => {
const [posts, setPosts] = useState<SocialPost[]>(mockSocialPosts) const [posts, setPosts] = useState<SocialPost[]>(mockSocialPosts)
@ -73,7 +73,7 @@ const SocialWall: React.FC = () => {
title: 'Çalışan' title: 'Çalışan'
}, },
content: postData.content, content: postData.content,
createdAt: new Date(), creationTime: new Date(),
media: mediaForPost, media: mediaForPost,
location: postData.location, location: postData.location,
likes: { likes: {
@ -118,7 +118,7 @@ const SocialWall: React.FC = () => {
avatar: 'https://i.pravatar.cc/150?img=1' avatar: 'https://i.pravatar.cc/150?img=1'
}, },
content, content,
createdAt: new Date() creationTime: new Date()
} }
return { return {
...post, ...post,