Intranet dil keylerin düzenlemesi
This commit is contained in:
parent
b0eafa5018
commit
265d203b95
28 changed files with 1441 additions and 201 deletions
File diff suppressed because it is too large
Load diff
|
|
@ -121,7 +121,7 @@ function RolesPermission({
|
|||
|
||||
setTimeout(async () => {
|
||||
getConfig(true)
|
||||
}, 6000)
|
||||
}, 3000)
|
||||
}
|
||||
|
||||
function getPermissionsWithGroupName(groups: PermissionGroupDto[]): PermissionWithGroupName[] {
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ function UsersPermission({
|
|||
|
||||
setTimeout(async () => {
|
||||
getConfig(true)
|
||||
}, 6000)
|
||||
}, 3000)
|
||||
}
|
||||
|
||||
function getPermissionsWithGroupName(groups: PermissionGroupDto[]): PermissionWithGroupName[] {
|
||||
|
|
|
|||
|
|
@ -28,7 +28,9 @@ interface CreatePostProps {
|
|||
}) => void
|
||||
}
|
||||
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
const CreatePost: React.FC<CreatePostProps> = ({ onCreatePost }) => {
|
||||
const { translate } = useLocalization();
|
||||
const [content, setContent] = useState('')
|
||||
const [mediaType, setMediaType] = useState<'media' | 'poll' | null>(null)
|
||||
const [mediaItems, setMediaItems] = useState<SocialMediaDto[]>([])
|
||||
|
|
@ -164,7 +166,7 @@ const CreatePost: React.FC<CreatePostProps> = ({ onCreatePost }) => {
|
|||
value={content}
|
||||
onChange={(e) => setContent(e.target.value)}
|
||||
onFocus={() => setIsExpanded(true)}
|
||||
placeholder="Ne düşünüyorsunuz?"
|
||||
placeholder={translate('::App.Platform.Intranet.SocialWall.CreatePost.Placeholder')}
|
||||
className={classNames(
|
||||
'w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500 resize-none transition-all',
|
||||
isExpanded ? 'min-h-[120px]' : 'min-h-[48px]'
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import React from 'react'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
import { FaExternalLinkAlt, FaMapMarkerAlt } from 'react-icons/fa'
|
||||
|
||||
interface LocationData {
|
||||
|
|
@ -43,6 +44,7 @@ const LocationMap: React.FC<LocationMapProps> = ({
|
|||
return `https://www.openstreetmap.org/export/embed.html?bbox=${lng - 0.01},${lat - 0.01},${lng + 0.01},${lat + 0.01}&layer=mapnik&marker=${lat},${lng}`
|
||||
}
|
||||
|
||||
const { translate } = useLocalization();
|
||||
return (
|
||||
<div className={`relative rounded-lg overflow-hidden bg-gray-200 dark:bg-gray-700 ${className}`}>
|
||||
{/* Map Container */}
|
||||
|
|
@ -76,9 +78,9 @@ const LocationMap: React.FC<LocationMapProps> = ({
|
|||
<button
|
||||
onClick={handleOpenGoogleMaps}
|
||||
className="absolute inset-0 w-full h-full cursor-pointer group"
|
||||
aria-label="Google Maps'te aç"
|
||||
aria-label={translate('::App.Platform.Intranet.SocialWall.LocationMap.OpenInGoogleMaps')}
|
||||
>
|
||||
<span className="sr-only">Google Maps'te aç</span>
|
||||
<span className="sr-only">{translate('::App.Platform.Intranet.SocialWall.LocationMap.OpenInGoogleMaps')}</span>
|
||||
</button>
|
||||
|
||||
{/* Hover Effect */}
|
||||
|
|
@ -93,10 +95,10 @@ const LocationMap: React.FC<LocationMapProps> = ({
|
|||
className="w-full flex items-center justify-center gap-2 px-4 py-2.5 bg-blue-600 hover:bg-blue-700 text-white font-medium rounded-lg transition-colors"
|
||||
>
|
||||
<FaExternalLinkAlt className="w-5 h-5" />
|
||||
<span>Google Maps'te Aç</span>
|
||||
<span>{translate('::App.Platform.Intranet.SocialWall.LocationMap.OpenInGoogleMaps')}</span>
|
||||
</button>
|
||||
<p className="text-xs text-gray-500 dark:text-gray-400 mt-2 text-center">
|
||||
Yol tarifi almak için tıklayın
|
||||
{translate('::App.Platform.Intranet.SocialWall.LocationMap.ClickForDirections')}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import React, { useState, useEffect, useRef } from 'react'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
import { motion } from 'framer-motion'
|
||||
import { FaTimes, FaSearch, FaMapMarkerAlt } from 'react-icons/fa'
|
||||
import classNames from 'classnames'
|
||||
|
|
@ -28,6 +29,7 @@ declare global {
|
|||
}
|
||||
|
||||
const LocationPicker: React.FC<LocationPickerProps> = ({ onSelect, onClose }) => {
|
||||
const { translate } = useLocalization();
|
||||
const [searchQuery, setSearchQuery] = useState('')
|
||||
const [locations, setLocations] = useState<LocationData[]>([])
|
||||
const [selectedLocation, setSelectedLocation] = useState<LocationData | null>(null)
|
||||
|
|
@ -55,7 +57,7 @@ const LocationPicker: React.FC<LocationPickerProps> = ({ onSelect, onClose }) =>
|
|||
}
|
||||
|
||||
if (!GOOGLE_API_KEY) {
|
||||
setError('Google Maps API anahtarı bulunamadı. Lütfen .env dosyasına VITE_GOOGLE_MAPS_API_KEY ekleyin.')
|
||||
setError(translate('::App.Platform.Intranet.SocialWall.LocationPicker.ApiKeyError'))
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -92,7 +94,7 @@ const LocationPicker: React.FC<LocationPickerProps> = ({ onSelect, onClose }) =>
|
|||
}
|
||||
|
||||
script.onerror = () => {
|
||||
setError('Google Maps yüklenemedi. Lütfen internet bağlantınızı kontrol edin.')
|
||||
setError(translate('::App.Platform.Intranet.SocialWall.LocationPicker.GoogleMapsLoadError'))
|
||||
}
|
||||
|
||||
document.head.appendChild(script)
|
||||
|
|
@ -142,7 +144,7 @@ const LocationPicker: React.FC<LocationPickerProps> = ({ onSelect, onClose }) =>
|
|||
}
|
||||
|
||||
if (status !== window.google.maps.places.PlacesServiceStatus.OK) {
|
||||
setError('Konum arama başarısız')
|
||||
setError(translate('::App.Platform.Intranet.SocialWall.LocationPicker.SearchFailed'))
|
||||
setIsLoading(false)
|
||||
return
|
||||
}
|
||||
|
|
@ -189,7 +191,7 @@ const LocationPicker: React.FC<LocationPickerProps> = ({ onSelect, onClose }) =>
|
|||
)
|
||||
} catch (err) {
|
||||
console.error('Location search error:', err)
|
||||
setError('Konum arama sırasında bir hata oluştu')
|
||||
setError(translate('::App.Platform.Intranet.SocialWall.LocationPicker.SearchError'))
|
||||
setIsLoading(false)
|
||||
}
|
||||
}, 500) // 500ms debounce
|
||||
|
|
@ -222,7 +224,7 @@ const LocationPicker: React.FC<LocationPickerProps> = ({ onSelect, onClose }) =>
|
|||
>
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between p-4 border-b border-gray-200 dark:border-gray-700">
|
||||
<h2 className="text-xl font-bold text-gray-900 dark:text-white">Konum Ekle</h2>
|
||||
<h2 className="text-xl font-bold text-gray-900 dark:text-white">{translate('::App.Platform.Intranet.SocialWall.LocationPicker.AddLocation')}</h2>
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-full transition-colors"
|
||||
|
|
@ -240,14 +242,14 @@ const LocationPicker: React.FC<LocationPickerProps> = ({ onSelect, onClose }) =>
|
|||
type="text"
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
placeholder="Konum ara..."
|
||||
placeholder={translate('::App.Platform.Intranet.SocialWall.LocationPicker.SearchPlaceholder')}
|
||||
disabled={!isGoogleLoaded}
|
||||
className="w-full pl-10 pr-4 py-3 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500 disabled:bg-gray-100 dark:disabled:bg-gray-600 disabled:cursor-not-allowed"
|
||||
/>
|
||||
</div>
|
||||
{!isGoogleLoaded && (
|
||||
<p className="text-xs text-gray-500 dark:text-gray-400 mt-2">
|
||||
Google Maps yükleniyor...
|
||||
{translate('::App.Platform.Intranet.SocialWall.LocationPicker.LoadingGoogleMaps')}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
|
@ -257,12 +259,12 @@ const LocationPicker: React.FC<LocationPickerProps> = ({ onSelect, onClose }) =>
|
|||
{!isGoogleLoaded ? (
|
||||
<div className="text-center py-12">
|
||||
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto mb-4"></div>
|
||||
<p className="text-gray-500 dark:text-gray-400">Google Maps yükleniyor...</p>
|
||||
<p className="text-gray-500 dark:text-gray-400">{translate('::App.Platform.Intranet.SocialWall.LocationPicker.LoadingGoogleMaps')}</p>
|
||||
</div>
|
||||
) : isLoading ? (
|
||||
<div className="text-center py-12">
|
||||
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto mb-4"></div>
|
||||
<p className="text-gray-500 dark:text-gray-400">Konumlar aranıyor...</p>
|
||||
<p className="text-gray-500 dark:text-gray-400">{translate('::App.Platform.Intranet.SocialWall.LocationPicker.SearchingLocations')}</p>
|
||||
</div>
|
||||
) : error ? (
|
||||
<div className="text-center py-12">
|
||||
|
|
@ -273,17 +275,17 @@ const LocationPicker: React.FC<LocationPickerProps> = ({ onSelect, onClose }) =>
|
|||
<div className="text-center py-12">
|
||||
<FaSearch className="w-16 h-16 mx-auto mb-4 text-gray-400" />
|
||||
<p className="text-gray-500 dark:text-gray-400">
|
||||
Aramak istediğiniz konumu yazın
|
||||
{translate('::App.Platform.Intranet.SocialWall.LocationPicker.TypeToSearch')}
|
||||
</p>
|
||||
<p className="text-sm text-gray-400 dark:text-gray-500 mt-2">
|
||||
Örn: Taksim, İstanbul
|
||||
{translate('::App.Platform.Intranet.SocialWall.LocationPicker.Example')}
|
||||
</p>
|
||||
</div>
|
||||
) : locations.length === 0 ? (
|
||||
<div className="text-center py-12">
|
||||
<FaMapMarkerAlt className="w-16 h-16 mx-auto mb-4 text-gray-400" />
|
||||
<p className="text-gray-500 dark:text-gray-400">
|
||||
Konum bulunamadı. Farklı bir arama yapın.
|
||||
{translate('::App.Platform.Intranet.SocialWall.LocationPicker.NotFound')}
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
|
|
@ -359,7 +361,7 @@ const LocationPicker: React.FC<LocationPickerProps> = ({ onSelect, onClose }) =>
|
|||
</span>
|
||||
</span>
|
||||
) : (
|
||||
<span>Bir konum seçin</span>
|
||||
<span>{translate('::App.Platform.Intranet.SocialWall.LocationPicker.SelectLocation')}</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
|
|
@ -367,14 +369,14 @@ const LocationPicker: React.FC<LocationPickerProps> = ({ onSelect, onClose }) =>
|
|||
onClick={onClose}
|
||||
className="px-4 py-2 text-gray-700 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-700 rounded-lg transition-colors"
|
||||
>
|
||||
İptal
|
||||
{translate('::App.Platform.Intranet.SocialWall.LocationPicker.Cancel')}
|
||||
</button>
|
||||
<button
|
||||
onClick={handleConfirm}
|
||||
disabled={!selectedLocation}
|
||||
className="px-6 py-2 bg-blue-600 text-white font-medium rounded-lg hover:bg-blue-700 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors"
|
||||
>
|
||||
Ekle
|
||||
{translate('::App.Platform.Intranet.SocialWall.LocationPicker.Add')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import React, { useState } from 'react'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
import { motion } from 'framer-motion'
|
||||
import { FaTimes, FaLink, FaUpload } from 'react-icons/fa'
|
||||
import classNames from 'classnames'
|
||||
|
|
@ -11,6 +12,7 @@ interface MediaManagerProps {
|
|||
}
|
||||
|
||||
const MediaManager: React.FC<MediaManagerProps> = ({ media, onChange, onClose }) => {
|
||||
const { translate } = useLocalization();
|
||||
const [activeTab, setActiveTab] = useState<'upload' | 'url'>('upload')
|
||||
const [urlInput, setUrlInput] = useState('')
|
||||
const [mediaType, setMediaType] = useState<'image' | 'video'>('image')
|
||||
|
|
@ -58,7 +60,7 @@ const MediaManager: React.FC<MediaManagerProps> = ({ media, onChange, onClose })
|
|||
>
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between p-4 border-b border-gray-200 dark:border-gray-700">
|
||||
<h2 className="text-xl font-bold text-gray-900 dark:text-white">Medya Ekle</h2>
|
||||
<h2 className="text-xl font-bold text-gray-900 dark:text-white">{translate('::App.Platform.Intranet.SocialWall.MediaManager.AddMedia')}</h2>
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-full transition-colors"
|
||||
|
|
@ -80,7 +82,7 @@ const MediaManager: React.FC<MediaManagerProps> = ({ media, onChange, onClose })
|
|||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<FaUpload className="w-5 h-5" />
|
||||
<span>Bilgisayarımdan Seç</span>
|
||||
<span>{translate('::App.Platform.Intranet.SocialWall.MediaManager.SelectFromComputer')}</span>
|
||||
</div>
|
||||
</button>
|
||||
<button
|
||||
|
|
@ -94,7 +96,7 @@ const MediaManager: React.FC<MediaManagerProps> = ({ media, onChange, onClose })
|
|||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<FaLink className="w-5 h-5" />
|
||||
<span>URL ile Ekle</span>
|
||||
<span>{translate('::App.Platform.Intranet.SocialWall.MediaManager.AddByUrl')}</span>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
|
|
@ -107,10 +109,10 @@ const MediaManager: React.FC<MediaManagerProps> = ({ media, onChange, onClose })
|
|||
<div className="border-2 border-dashed border-gray-300 dark:border-gray-600 rounded-lg p-8 text-center hover:border-blue-500 hover:bg-blue-50 dark:hover:bg-blue-900/20 transition-colors cursor-pointer">
|
||||
<FaUpload className="w-12 h-12 mx-auto mb-4 text-gray-400" />
|
||||
<p className="text-gray-700 dark:text-gray-300 font-medium mb-1">
|
||||
Dosya seçmek için tıklayın
|
||||
{translate('::App.Platform.Intranet.SocialWall.MediaManager.ClickToSelectFile')}
|
||||
</p>
|
||||
<p className="text-sm text-gray-500 dark:text-gray-400">
|
||||
Resim veya Video (PNG, JPG, GIF, MP4, MOV)
|
||||
{translate('::App.Platform.Intranet.SocialWall.MediaManager.ImageOrVideoFormats')}
|
||||
</p>
|
||||
</div>
|
||||
<input
|
||||
|
|
@ -126,7 +128,7 @@ const MediaManager: React.FC<MediaManagerProps> = ({ media, onChange, onClose })
|
|||
<div>
|
||||
<div className="mb-4">
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||
Medya Tipi
|
||||
{translate('::App.Platform.Intranet.SocialWall.MediaManager.MediaType')}
|
||||
</label>
|
||||
<div className="flex gap-2">
|
||||
<button
|
||||
|
|
@ -138,7 +140,7 @@ const MediaManager: React.FC<MediaManagerProps> = ({ media, onChange, onClose })
|
|||
: 'bg-gray-100 dark:bg-gray-700 text-gray-700 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-600'
|
||||
)}
|
||||
>
|
||||
Resim
|
||||
{translate('::App.Platform.Intranet.SocialWall.MediaManager.Image')}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setMediaType('video')}
|
||||
|
|
@ -149,7 +151,7 @@ const MediaManager: React.FC<MediaManagerProps> = ({ media, onChange, onClose })
|
|||
: 'bg-gray-100 dark:bg-gray-700 text-gray-700 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-600'
|
||||
)}
|
||||
>
|
||||
Video
|
||||
{translate('::App.Platform.Intranet.SocialWall.MediaManager.Video')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -159,7 +161,7 @@ const MediaManager: React.FC<MediaManagerProps> = ({ media, onChange, onClose })
|
|||
value={urlInput}
|
||||
onChange={(e) => setUrlInput(e.target.value)}
|
||||
onKeyPress={(e) => e.key === 'Enter' && handleUrlAdd()}
|
||||
placeholder={`${mediaType === 'image' ? 'Resim' : 'Video'} URL'si girin`}
|
||||
placeholder={mediaType === 'image' ? translate('::App.Platform.Intranet.SocialWall.MediaManager.EnterImageUrl') : translate('::App.Platform.Intranet.SocialWall.MediaManager.EnterVideoUrl')}
|
||||
className="flex-1 px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
/>
|
||||
<button
|
||||
|
|
@ -167,7 +169,7 @@ const MediaManager: React.FC<MediaManagerProps> = ({ media, onChange, onClose })
|
|||
disabled={!urlInput.trim()}
|
||||
className="px-6 py-2 bg-blue-600 text-white font-medium rounded-lg hover:bg-blue-700 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors"
|
||||
>
|
||||
Ekle
|
||||
{translate('::App.Platform.Intranet.SocialWall.MediaManager.Add')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -177,7 +179,7 @@ const MediaManager: React.FC<MediaManagerProps> = ({ media, onChange, onClose })
|
|||
{media.length > 0 && (
|
||||
<div className="mt-6">
|
||||
<h3 className="text-sm font-medium text-gray-700 dark:text-gray-300 mb-3">
|
||||
Eklenen Medyalar ({media.length})
|
||||
{translate('::App.Platform.Intranet.SocialWall.MediaManager.AddedMedia')} ({media.length})
|
||||
</h3>
|
||||
<div className="grid grid-cols-4 gap-3">
|
||||
{media.map((item) => (
|
||||
|
|
@ -205,7 +207,7 @@ const MediaManager: React.FC<MediaManagerProps> = ({ media, onChange, onClose })
|
|||
<FaTimes className="w-4 h-4" />
|
||||
</button>
|
||||
<div className="absolute bottom-1 left-1 px-2 py-0.5 bg-black bg-opacity-70 text-white text-xs rounded">
|
||||
{item.type === 'image' ? '📷' : '🎥'}
|
||||
{item.type === 'image' ? translate('::App.Platform.Intranet.SocialWall.MediaManager.ImageIcon') : translate('::App.Platform.Intranet.SocialWall.MediaManager.VideoIcon')}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
|
@ -220,14 +222,14 @@ const MediaManager: React.FC<MediaManagerProps> = ({ media, onChange, onClose })
|
|||
onClick={onClose}
|
||||
className="px-4 py-2 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors"
|
||||
>
|
||||
İptal
|
||||
{translate('::App.Platform.Intranet.SocialWall.MediaManager.Cancel')}
|
||||
</button>
|
||||
<button
|
||||
onClick={onClose}
|
||||
disabled={media.length === 0}
|
||||
className="px-6 py-2 bg-blue-600 text-white font-medium rounded-lg hover:bg-blue-700 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors"
|
||||
>
|
||||
Tamam ({media.length})
|
||||
{translate('::App.Platform.Intranet.SocialWall.MediaManager.Done', { count: media.length })}
|
||||
</button>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import React, { useState, useRef, useEffect } from 'react'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
import { motion, AnimatePresence } from 'framer-motion'
|
||||
import classNames from 'classnames'
|
||||
import dayjs from 'dayjs'
|
||||
|
|
@ -28,6 +29,7 @@ interface PostItemProps {
|
|||
}
|
||||
|
||||
const PostItem: React.FC<PostItemProps> = ({ post, onLike, onComment, onDelete, onVote }) => {
|
||||
const { translate } = useLocalization();
|
||||
const [showComments, setShowComments] = useState(false)
|
||||
const [commentText, setCommentText] = useState('')
|
||||
const [showAllImages, setShowAllImages] = useState(false)
|
||||
|
|
@ -269,7 +271,7 @@ const PostItem: React.FC<PostItemProps> = ({ post, onLike, onComment, onDelete,
|
|||
id: post.employee.id,
|
||||
name: post.employee.name,
|
||||
avatar: post.employee.avatar || 'https://i.pravatar.cc/150?img=1',
|
||||
title: post.employee.jobPosition?.name || 'Çalışan',
|
||||
title: post.employee.jobPosition?.name || translate('::App.Platform.Intranet.SocialWall.PostItem.Employee'),
|
||||
email: post.employee.email,
|
||||
phoneNumber: post.employee.phoneNumber,
|
||||
department: post.employee.department?.name,
|
||||
|
|
@ -285,7 +287,7 @@ const PostItem: React.FC<PostItemProps> = ({ post, onLike, onComment, onDelete,
|
|||
{post.employee.name}
|
||||
</h3>
|
||||
<p className="text-sm text-gray-600 dark:text-gray-400">
|
||||
{post.employee.jobPosition?.name || 'Çalışan'} • {dayjs(post.creationTime).fromNow()}
|
||||
{post.employee.jobPosition?.name || translate('::App.Platform.Intranet.SocialWall.PostItem.Employee')} • {dayjs(post.creationTime).fromNow()}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -293,7 +295,7 @@ const PostItem: React.FC<PostItemProps> = ({ post, onLike, onComment, onDelete,
|
|||
<button
|
||||
onClick={() => onDelete(post.id)}
|
||||
className="p-2 text-gray-500 hover:text-red-600 hover:bg-red-50 dark:hover:bg-red-900/20 rounded-full transition-colors"
|
||||
title="Gönderiyi sil"
|
||||
title={translate('::App.Platform.Intranet.SocialWall.PostItem.DeletePost')}
|
||||
>
|
||||
<FaTrash className="w-5 h-5" />
|
||||
</button>
|
||||
|
|
@ -357,7 +359,7 @@ const PostItem: React.FC<PostItemProps> = ({ post, onLike, onComment, onDelete,
|
|||
type="text"
|
||||
value={commentText}
|
||||
onChange={(e) => setCommentText(e.target.value)}
|
||||
placeholder="Yorum yazın..."
|
||||
placeholder={translate('::App.Platform.Intranet.SocialWall.PostItem.CommentPlaceholder')}
|
||||
className="flex-1 px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-full bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
/>
|
||||
<button
|
||||
|
|
@ -391,7 +393,7 @@ const PostItem: React.FC<PostItemProps> = ({ post, onLike, onComment, onDelete,
|
|||
id: comment.creator.id,
|
||||
name: comment.creator.name,
|
||||
avatar: comment.creator.avatar || 'https://i.pravatar.cc/150?img=1',
|
||||
title: comment.creator.jobPosition?.name || 'Çalışan'
|
||||
title: comment.creator.jobPosition?.name || translate('::App.Platform.Intranet.SocialWall.PostItem.Employee')
|
||||
}}
|
||||
position="bottom"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import React from 'react'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
import { motion } from 'framer-motion'
|
||||
import { FaTimes, FaEye, FaClipboard } from 'react-icons/fa'
|
||||
import dayjs from 'dayjs'
|
||||
import { AnnouncementDto } from '@/proxy/intranet/models'
|
||||
import useLocale from '@/utils/hooks/useLocale'
|
||||
import { currentLocalDate } from '@/utils/dateUtils'
|
||||
|
|
@ -12,6 +12,7 @@ interface AnnouncementDetailModalProps {
|
|||
}
|
||||
|
||||
const AnnouncementDetailModal: React.FC<AnnouncementDetailModalProps> = ({ announcement, onClose }) => {
|
||||
const { translate } = useLocalization();
|
||||
const currentLocale = useLocale()
|
||||
const getCategoryColor = (category: string) => {
|
||||
const colors: Record<string, string> = {
|
||||
|
|
@ -49,14 +50,14 @@ const AnnouncementDetailModal: React.FC<AnnouncementDetailModalProps> = ({ annou
|
|||
<span
|
||||
className={`px-3 py-1 text-xs font-medium rounded-full ${getCategoryColor(announcement.category)}`}
|
||||
>
|
||||
{announcement.category === 'general' && '📢 Genel'}
|
||||
{announcement.category === 'hr' && '👥 İnsan Kaynakları'}
|
||||
{announcement.category === 'it' && '💻 Bilgi Teknolojileri'}
|
||||
{announcement.category === 'event' && '🎉 Etkinlik'}
|
||||
{announcement.category === 'urgent' && '🚨 Acil'}
|
||||
{announcement.category === 'general' && `📢 ${translate('::App.Platform.Intranet.AnnouncementDetailModal.Category.General')}`}
|
||||
{announcement.category === 'hr' && `👥 ${translate('::App.Platform.Intranet.AnnouncementDetailModal.Category.HR')}`}
|
||||
{announcement.category === 'it' && `💻 ${translate('::App.Platform.Intranet.AnnouncementDetailModal.Category.IT')}`}
|
||||
{announcement.category === 'event' && `🎉 ${translate('::App.Platform.Intranet.AnnouncementDetailModal.Category.Event')}`}
|
||||
{announcement.category === 'urgent' && `🚨 ${translate('::App.Platform.Intranet.AnnouncementDetailModal.Category.Urgent')}`}
|
||||
</span>
|
||||
{announcement.isPinned && (
|
||||
<span className="text-yellow-500 text-sm">📌 Sabitlenmiş</span>
|
||||
<span className="text-yellow-500 text-sm">📌 {translate('::App.Platform.Intranet.AnnouncementDetailModal.Pinned')}</span>
|
||||
)}
|
||||
</div>
|
||||
<h2 className="text-2xl font-bold text-gray-900 dark:text-white">
|
||||
|
|
@ -89,7 +90,7 @@ const AnnouncementDetailModal: React.FC<AnnouncementDetailModalProps> = ({ annou
|
|||
<span>•</span>
|
||||
<span className="flex items-center gap-1">
|
||||
<FaEye className="w-4 h-4" />
|
||||
{announcement.viewCount} görüntülenme
|
||||
{announcement.viewCount} {translate('::App.Platform.Intranet.AnnouncementDetailModal.Views')}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -120,7 +121,7 @@ const AnnouncementDetailModal: React.FC<AnnouncementDetailModalProps> = ({ annou
|
|||
<div className="mt-6 pt-6 border-t border-gray-200 dark:border-gray-700">
|
||||
<h3 className="text-sm font-semibold text-gray-900 dark:text-white mb-3 flex items-center gap-2">
|
||||
<FaClipboard className="w-5 h-5" />
|
||||
Ekler ({announcement.attachments.length})
|
||||
{translate('::App.Platform.Intranet.AnnouncementDetailModal.Attachments')} ({announcement.attachments.length})
|
||||
</h3>
|
||||
<div className="space-y-2">
|
||||
{announcement.attachments.map((attachment, idx) => (
|
||||
|
|
@ -141,7 +142,7 @@ const AnnouncementDetailModal: React.FC<AnnouncementDetailModalProps> = ({ annou
|
|||
</p>
|
||||
</div>
|
||||
<span className="text-sm text-blue-600 dark:text-blue-400">
|
||||
İndir
|
||||
{translate('::App.Platform.Intranet.AnnouncementDetailModal.Download')}
|
||||
</span>
|
||||
</a>
|
||||
))}
|
||||
|
|
@ -154,7 +155,7 @@ const AnnouncementDetailModal: React.FC<AnnouncementDetailModalProps> = ({ annou
|
|||
announcement.departments.length > 0 && (
|
||||
<div className="mt-6 pt-6 border-t border-gray-200 dark:border-gray-700">
|
||||
<h3 className="text-sm font-semibold text-gray-900 dark:text-white mb-3">
|
||||
Hedef Departmanlar
|
||||
{translate('::App.Platform.Intranet.AnnouncementDetailModal.TargetDepartments')}
|
||||
</h3>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{announcement.departments?.map((dept, idx) => (
|
||||
|
|
@ -173,7 +174,7 @@ const AnnouncementDetailModal: React.FC<AnnouncementDetailModalProps> = ({ annou
|
|||
{announcement.expiryDate && (
|
||||
<div className="mt-6 pt-6 border-t border-gray-200 dark:border-gray-700">
|
||||
<p className="text-sm text-gray-600 dark:text-gray-400">
|
||||
<span className="font-medium">Son Geçerlilik Tarihi:</span>{' '}
|
||||
<span className="font-medium">{translate('::App.Platform.Intranet.AnnouncementDetailModal.ExpiryDate')}:</span>{' '}
|
||||
{currentLocalDate(announcement.expiryDate, currentLocale || 'tr')}
|
||||
</p>
|
||||
</div>
|
||||
|
|
@ -186,7 +187,7 @@ const AnnouncementDetailModal: React.FC<AnnouncementDetailModalProps> = ({ annou
|
|||
onClick={onClose}
|
||||
className="w-full px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg transition-colors"
|
||||
>
|
||||
Kapat
|
||||
{translate('::App.Platform.Intranet.AnnouncementDetailModal.Close')}
|
||||
</button>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import React from 'react'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
import { motion } from 'framer-motion'
|
||||
import { FaTimes } from 'react-icons/fa'
|
||||
|
||||
|
|
@ -8,6 +9,7 @@ interface ExpenseRequestModalProps {
|
|||
}
|
||||
|
||||
const ExpenseRequestModal: React.FC<ExpenseRequestModalProps> = ({ onClose, onSubmit }) => {
|
||||
const { translate } = useLocalization();
|
||||
return (
|
||||
<>
|
||||
<motion.div
|
||||
|
|
@ -27,7 +29,7 @@ const ExpenseRequestModal: React.FC<ExpenseRequestModalProps> = ({ onClose, onSu
|
|||
>
|
||||
<div className="p-4 border-b border-gray-200 dark:border-gray-700 flex items-center justify-between sticky top-0 bg-white dark:bg-gray-800 z-10">
|
||||
<h2 className="text-xl font-semibold text-gray-900 dark:text-white">
|
||||
Yeni Harcama Talebi
|
||||
{translate('::App.Platform.Intranet.ExpenseRequestModal.Title')}
|
||||
</h2>
|
||||
<button
|
||||
onClick={onClose}
|
||||
|
|
@ -46,29 +48,29 @@ const ExpenseRequestModal: React.FC<ExpenseRequestModalProps> = ({ onClose, onSu
|
|||
>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||
Harcama Kategorisi *
|
||||
{translate('::App.Platform.Intranet.ExpenseRequestModal.Category')}
|
||||
</label>
|
||||
<select
|
||||
required
|
||||
className="w-full px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-blue-500"
|
||||
>
|
||||
<option value="">Seçiniz</option>
|
||||
<option value="travel">✈️ Seyahat</option>
|
||||
<option value="meal">🍽️ Yemek</option>
|
||||
<option value="accommodation">🏨 Konaklama</option>
|
||||
<option value="transport">🚗 Ulaşım</option>
|
||||
<option value="other">📋 Diğer</option>
|
||||
<option value="">{translate('::App.Platform.Intranet.ExpenseRequestModal.Select')}</option>
|
||||
<option value="travel">✈️ {translate('::App.Platform.Intranet.ExpenseRequestModal.Travel')}</option>
|
||||
<option value="meal">🍽️ {translate('::App.Platform.Intranet.ExpenseRequestModal.Meal')}</option>
|
||||
<option value="accommodation">🏨 {translate('::App.Platform.Intranet.ExpenseRequestModal.Accommodation')}</option>
|
||||
<option value="transport">🚗 {translate('::App.Platform.Intranet.ExpenseRequestModal.Transport')}</option>
|
||||
<option value="other">📋 {translate('::App.Platform.Intranet.ExpenseRequestModal.Other')}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||
Açıklama *
|
||||
{translate('::App.Platform.Intranet.ExpenseRequestModal.Description')}
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
required
|
||||
placeholder="Harcama açıklaması..."
|
||||
placeholder={translate('::App.Platform.Intranet.ExpenseRequestModal.DescriptionPlaceholder')}
|
||||
className="w-full px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-blue-500"
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -76,7 +78,7 @@ const ExpenseRequestModal: React.FC<ExpenseRequestModalProps> = ({ onClose, onSu
|
|||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||
Tutar (₺) *
|
||||
{translate('::App.Platform.Intranet.ExpenseRequestModal.Amount')}
|
||||
</label>
|
||||
<input
|
||||
type="number"
|
||||
|
|
@ -89,7 +91,7 @@ const ExpenseRequestModal: React.FC<ExpenseRequestModalProps> = ({ onClose, onSu
|
|||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||
Tarih *
|
||||
{translate('::App.Platform.Intranet.ExpenseRequestModal.Date')}
|
||||
</label>
|
||||
<input
|
||||
type="date"
|
||||
|
|
@ -101,11 +103,11 @@ const ExpenseRequestModal: React.FC<ExpenseRequestModalProps> = ({ onClose, onSu
|
|||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||
Not
|
||||
{translate('::App.Platform.Intranet.ExpenseRequestModal.Note')}
|
||||
</label>
|
||||
<textarea
|
||||
rows={3}
|
||||
placeholder="Ek bilgi (opsiyonel)..."
|
||||
placeholder={translate('::App.Platform.Intranet.ExpenseRequestModal.NotePlaceholder')}
|
||||
className="w-full px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-blue-500"
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -116,13 +118,13 @@ const ExpenseRequestModal: React.FC<ExpenseRequestModalProps> = ({ onClose, onSu
|
|||
onClick={onClose}
|
||||
className="flex-1 px-4 py-2 border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors"
|
||||
>
|
||||
İptal
|
||||
{translate('::App.Platform.Intranet.ExpenseRequestModal.Cancel')}
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
className="flex-1 px-4 py-2 bg-emerald-600 hover:bg-emerald-700 text-white rounded-lg transition-colors"
|
||||
>
|
||||
Gönder
|
||||
{translate('::App.Platform.Intranet.ExpenseRequestModal.Submit')}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import React from 'react'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
import { motion } from 'framer-motion'
|
||||
import { FaTimes } from 'react-icons/fa'
|
||||
|
||||
|
|
@ -8,6 +9,7 @@ interface LeaveRequestModalProps {
|
|||
}
|
||||
|
||||
const LeaveRequestModal: React.FC<LeaveRequestModalProps> = ({ onClose, onSubmit }) => {
|
||||
const { translate } = useLocalization();
|
||||
return (
|
||||
<>
|
||||
<motion.div
|
||||
|
|
@ -27,7 +29,7 @@ const LeaveRequestModal: React.FC<LeaveRequestModalProps> = ({ onClose, onSubmit
|
|||
>
|
||||
<div className="p-4 border-b border-gray-200 dark:border-gray-700 flex items-center justify-between sticky top-0 bg-white dark:bg-gray-800 z-10">
|
||||
<h2 className="text-xl font-semibold text-gray-900 dark:text-white">
|
||||
Yeni İzin Talebi
|
||||
{translate('::App.Platform.Intranet.LeaveRequestModal.Title')}
|
||||
</h2>
|
||||
<button
|
||||
onClick={onClose}
|
||||
|
|
@ -46,24 +48,24 @@ const LeaveRequestModal: React.FC<LeaveRequestModalProps> = ({ onClose, onSubmit
|
|||
>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||
İzin Türü *
|
||||
{translate('::App.Platform.Intranet.LeaveRequestModal.LeaveType')}
|
||||
</label>
|
||||
<select
|
||||
required
|
||||
className="w-full px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-blue-500"
|
||||
>
|
||||
<option value="">Seçiniz</option>
|
||||
<option value="annual">🏖️ Yıllık İzin</option>
|
||||
<option value="sick">🏥 Hastalık İzni</option>
|
||||
<option value="unpaid">💼 Ücretsiz İzin</option>
|
||||
<option value="other">📋 Diğer</option>
|
||||
<option value="">{translate('::App.Platform.Intranet.LeaveRequestModal.Select')}</option>
|
||||
<option value="annual">🏖️ {translate('::App.Platform.Intranet.LeaveRequestModal.AnnualLeave')}</option>
|
||||
<option value="sick">🏥 {translate('::App.Platform.Intranet.LeaveRequestModal.SickLeave')}</option>
|
||||
<option value="unpaid">💼 {translate('::App.Platform.Intranet.LeaveRequestModal.UnpaidLeave')}</option>
|
||||
<option value="other">📋 {translate('::App.Platform.Intranet.LeaveRequestModal.Other')}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||
Başlangıç Tarihi *
|
||||
{translate('::App.Platform.Intranet.LeaveRequestModal.StartDate')}
|
||||
</label>
|
||||
<input
|
||||
type="date"
|
||||
|
|
@ -73,7 +75,7 @@ const LeaveRequestModal: React.FC<LeaveRequestModalProps> = ({ onClose, onSubmit
|
|||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||
Bitiş Tarihi *
|
||||
{translate('::App.Platform.Intranet.LeaveRequestModal.EndDate')}
|
||||
</label>
|
||||
<input
|
||||
type="date"
|
||||
|
|
@ -85,12 +87,12 @@ const LeaveRequestModal: React.FC<LeaveRequestModalProps> = ({ onClose, onSubmit
|
|||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||
Açıklama *
|
||||
{translate('::App.Platform.Intranet.LeaveRequestModal.Description')}
|
||||
</label>
|
||||
<textarea
|
||||
required
|
||||
rows={3}
|
||||
placeholder="İzin sebebinizi yazınız..."
|
||||
placeholder={translate('::App.Platform.Intranet.LeaveRequestModal.ReasonPlaceholder')}
|
||||
className="w-full px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-blue-500"
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -101,13 +103,13 @@ const LeaveRequestModal: React.FC<LeaveRequestModalProps> = ({ onClose, onSubmit
|
|||
onClick={onClose}
|
||||
className="flex-1 px-4 py-2 border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors"
|
||||
>
|
||||
İptal
|
||||
{translate('::App.Platform.Intranet.LeaveRequestModal.Cancel')}
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
className="flex-1 px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg transition-colors"
|
||||
>
|
||||
Gönder
|
||||
{translate('::App.Platform.Intranet.LeaveRequestModal.Submit')}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import React from 'react'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
import { motion } from 'framer-motion'
|
||||
import { FaTimes } from 'react-icons/fa'
|
||||
|
||||
|
|
@ -8,6 +9,7 @@ interface OvertimeRequestModalProps {
|
|||
}
|
||||
|
||||
const OvertimeRequestModal: React.FC<OvertimeRequestModalProps> = ({ onClose, onSubmit }) => {
|
||||
const { translate } = useLocalization();
|
||||
return (
|
||||
<>
|
||||
<motion.div
|
||||
|
|
@ -27,7 +29,7 @@ const OvertimeRequestModal: React.FC<OvertimeRequestModalProps> = ({ onClose, on
|
|||
>
|
||||
<div className="p-4 border-b border-gray-200 dark:border-gray-700 flex items-center justify-between sticky top-0 bg-white dark:bg-gray-800 z-10">
|
||||
<h2 className="text-xl font-semibold text-gray-900 dark:text-white">
|
||||
Yeni Mesai Talebi
|
||||
{translate('::App.Platform.Intranet.OvertimeRequestModal.Title')}
|
||||
</h2>
|
||||
<button
|
||||
onClick={onClose}
|
||||
|
|
@ -46,7 +48,7 @@ const OvertimeRequestModal: React.FC<OvertimeRequestModalProps> = ({ onClose, on
|
|||
>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||
Mesai Tarihi *
|
||||
{translate('::App.Platform.Intranet.OvertimeRequestModal.Date')}
|
||||
</label>
|
||||
<input
|
||||
type="date"
|
||||
|
|
@ -58,7 +60,7 @@ const OvertimeRequestModal: React.FC<OvertimeRequestModalProps> = ({ onClose, on
|
|||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||
Başlangıç Saati *
|
||||
{translate('::App.Platform.Intranet.OvertimeRequestModal.StartTime')}
|
||||
</label>
|
||||
<input
|
||||
type="time"
|
||||
|
|
@ -68,7 +70,7 @@ const OvertimeRequestModal: React.FC<OvertimeRequestModalProps> = ({ onClose, on
|
|||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||
Bitiş Saati *
|
||||
{translate('::App.Platform.Intranet.OvertimeRequestModal.EndTime')}
|
||||
</label>
|
||||
<input
|
||||
type="time"
|
||||
|
|
@ -80,12 +82,12 @@ const OvertimeRequestModal: React.FC<OvertimeRequestModalProps> = ({ onClose, on
|
|||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||
Açıklama *
|
||||
{translate('::App.Platform.Intranet.OvertimeRequestModal.Description')}
|
||||
</label>
|
||||
<textarea
|
||||
required
|
||||
rows={3}
|
||||
placeholder="Mesai sebebinizi yazınız..."
|
||||
placeholder={translate('::App.Platform.Intranet.OvertimeRequestModal.ReasonPlaceholder')}
|
||||
className="w-full px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-blue-500"
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -96,13 +98,13 @@ const OvertimeRequestModal: React.FC<OvertimeRequestModalProps> = ({ onClose, on
|
|||
onClick={onClose}
|
||||
className="flex-1 px-4 py-2 border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors"
|
||||
>
|
||||
İptal
|
||||
{translate('::App.Platform.Intranet.OvertimeRequestModal.Cancel')}
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
className="flex-1 px-4 py-2 bg-orange-600 hover:bg-orange-700 text-white rounded-lg transition-colors"
|
||||
>
|
||||
Gönder
|
||||
{translate('::App.Platform.Intranet.OvertimeRequestModal.Submit')}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import React from 'react'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
import { motion } from 'framer-motion'
|
||||
import { FaTimes } from 'react-icons/fa'
|
||||
|
||||
|
|
@ -8,6 +9,7 @@ interface ReservationRequestModalProps {
|
|||
}
|
||||
|
||||
const ReservationRequestModal: React.FC<ReservationRequestModalProps> = ({ onClose, onSubmit }) => {
|
||||
const { translate } = useLocalization();
|
||||
return (
|
||||
<>
|
||||
<motion.div
|
||||
|
|
@ -27,7 +29,7 @@ const ReservationRequestModal: React.FC<ReservationRequestModalProps> = ({ onClo
|
|||
>
|
||||
<div className="p-4 border-b border-gray-200 dark:border-gray-700 flex items-center justify-between sticky top-0 bg-white dark:bg-gray-800 z-10">
|
||||
<h2 className="text-xl font-semibold text-gray-900 dark:text-white">
|
||||
Yeni Rezervasyon Talebi
|
||||
{translate('::App.Platform.Intranet.ReservationRequestModal.Title')}
|
||||
</h2>
|
||||
<button
|
||||
onClick={onClose}
|
||||
|
|
@ -46,27 +48,27 @@ const ReservationRequestModal: React.FC<ReservationRequestModalProps> = ({ onClo
|
|||
>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||
Rezervasyon Türü *
|
||||
{translate('::App.Platform.Intranet.ReservationRequestModal.Type')}
|
||||
</label>
|
||||
<select
|
||||
required
|
||||
className="w-full px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-blue-500"
|
||||
>
|
||||
<option value="">Seçiniz</option>
|
||||
<option value="room">🏢 Toplantı Odası</option>
|
||||
<option value="vehicle">🚗 Şirket Aracı</option>
|
||||
<option value="equipment">⚙️ Ekipman</option>
|
||||
<option value="">{translate('::App.Platform.Intranet.ReservationRequestModal.Select')}</option>
|
||||
<option value="room">🏢 {translate('::App.Platform.Intranet.ReservationRequestModal.Room')}</option>
|
||||
<option value="vehicle">🚗 {translate('::App.Platform.Intranet.ReservationRequestModal.Vehicle')}</option>
|
||||
<option value="equipment">⚙️ {translate('::App.Platform.Intranet.ReservationRequestModal.Equipment')}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||
Kaynak Adı *
|
||||
{translate('::App.Platform.Intranet.ReservationRequestModal.ResourceName')}
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
required
|
||||
placeholder="Örn: Toplantı Salonu A, Şirket Aracı - Plaka, Kamera Seti..."
|
||||
placeholder={translate('::App.Platform.Intranet.ReservationRequestModal.ResourceNamePlaceholder')}
|
||||
className="w-full px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-blue-500"
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -74,7 +76,7 @@ const ReservationRequestModal: React.FC<ReservationRequestModalProps> = ({ onClo
|
|||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||
Başlangıç Tarihi *
|
||||
{translate('::App.Platform.Intranet.ReservationRequestModal.StartDate')}
|
||||
</label>
|
||||
<input
|
||||
type="datetime-local"
|
||||
|
|
@ -84,7 +86,7 @@ const ReservationRequestModal: React.FC<ReservationRequestModalProps> = ({ onClo
|
|||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||
Bitiş Tarihi *
|
||||
{translate('::App.Platform.Intranet.ReservationRequestModal.EndDate')}
|
||||
</label>
|
||||
<input
|
||||
type="datetime-local"
|
||||
|
|
@ -96,42 +98,42 @@ const ReservationRequestModal: React.FC<ReservationRequestModalProps> = ({ onClo
|
|||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||
Amaç *
|
||||
{translate('::App.Platform.Intranet.ReservationRequestModal.Purpose')}
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
required
|
||||
placeholder="Rezervasyon amacını belirtiniz..."
|
||||
placeholder={translate('::App.Platform.Intranet.ReservationRequestModal.PurposePlaceholder')}
|
||||
className="w-full px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-blue-500"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||
Katılımcı Sayısı
|
||||
{translate('::App.Platform.Intranet.ReservationRequestModal.ParticipantCount')}
|
||||
</label>
|
||||
<input
|
||||
type="number"
|
||||
min="1"
|
||||
placeholder="Toplantı odası için katılımcı sayısı (opsiyonel)"
|
||||
placeholder={translate('::App.Platform.Intranet.ReservationRequestModal.ParticipantCountPlaceholder')}
|
||||
className="w-full px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-blue-500"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||
Notlar
|
||||
{translate('::App.Platform.Intranet.ReservationRequestModal.Notes')}
|
||||
</label>
|
||||
<textarea
|
||||
rows={3}
|
||||
placeholder="Ek bilgi veya özel istekler (opsiyonel)..."
|
||||
placeholder={translate('::App.Platform.Intranet.ReservationRequestModal.NotesPlaceholder')}
|
||||
className="w-full px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-blue-500"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="bg-blue-50 dark:bg-blue-900/20 rounded-lg p-3">
|
||||
<p className="text-sm text-blue-700 dark:text-blue-300">
|
||||
ℹ️ Rezervasyon talebiniz yönetici onayına sunulacaktır.
|
||||
ℹ️ {translate('::App.Platform.Intranet.ReservationRequestModal.Info')}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
|
@ -141,13 +143,13 @@ const ReservationRequestModal: React.FC<ReservationRequestModalProps> = ({ onClo
|
|||
onClick={onClose}
|
||||
className="flex-1 px-4 py-2 border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors"
|
||||
>
|
||||
İptal
|
||||
{translate('::App.Platform.Intranet.ReservationRequestModal.Cancel')}
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
className="flex-1 px-4 py-2 bg-green-600 hover:bg-green-700 text-white rounded-lg transition-colors"
|
||||
>
|
||||
Gönder
|
||||
{translate('::App.Platform.Intranet.ReservationRequestModal.Submit')}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@ interface SurveyModalProps {
|
|||
onSubmit: (answers: SurveyAnswerDto[]) => void
|
||||
}
|
||||
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
const SurveyModal: React.FC<SurveyModalProps> = ({ survey, onClose, onSubmit }) => {
|
||||
const { translate } = useLocalization();
|
||||
const [answers, setAnswers] = useState<{ [questionId: string]: any }>({})
|
||||
const [errors, setErrors] = useState<{ [questionId: string]: string }>({})
|
||||
|
||||
|
|
@ -33,7 +35,7 @@ const SurveyModal: React.FC<SurveyModalProps> = ({ survey, onClose, onSubmit })
|
|||
|
||||
survey.questions.forEach((question) => {
|
||||
if (question.isRequired && (!answers[question.id] || answers[question.id] === '')) {
|
||||
newErrors[question.id] = 'Bu alan zorunludur'
|
||||
newErrors[question.id] = translate('::App.Platform.Intranet.SurveyModal.RequiredField')
|
||||
}
|
||||
})
|
||||
|
||||
|
|
@ -159,7 +161,7 @@ const SurveyModal: React.FC<SurveyModalProps> = ({ survey, onClose, onSubmit })
|
|||
className={`w-full px-4 py-2 border rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-blue-500 ${
|
||||
hasError ? 'border-red-500' : 'border-gray-300 dark:border-gray-600'
|
||||
}`}
|
||||
placeholder="Cevabınızı yazın..."
|
||||
placeholder={translate('::App.Platform.Intranet.SurveyModal.AnswerPlaceholder')}
|
||||
/>
|
||||
{hasError && (
|
||||
<p className="text-sm text-red-600 dark:text-red-400">{errors[question.id]}</p>
|
||||
|
|
@ -180,7 +182,7 @@ const SurveyModal: React.FC<SurveyModalProps> = ({ survey, onClose, onSubmit })
|
|||
className={`w-full px-4 py-2 border rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-blue-500 ${
|
||||
hasError ? 'border-red-500' : 'border-gray-300 dark:border-gray-600'
|
||||
}`}
|
||||
placeholder="Yorumlarınızı buraya yazabilirsiniz..."
|
||||
placeholder={translate('::App.Platform.Intranet.SurveyModal.CommentPlaceholder')}
|
||||
/>
|
||||
{hasError && (
|
||||
<p className="text-sm text-red-600 dark:text-red-400">{errors[question.id]}</p>
|
||||
|
|
@ -254,13 +256,13 @@ const SurveyModal: React.FC<SurveyModalProps> = ({ survey, onClose, onSubmit })
|
|||
onClick={onClose}
|
||||
className="flex-1 px-4 py-2 border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors"
|
||||
>
|
||||
İptal
|
||||
{translate('::App.Platform.Intranet.SurveyModal.Cancel')}
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
className="flex-1 px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg transition-colors"
|
||||
>
|
||||
Anketi Gönder
|
||||
{translate('::App.Platform.Intranet.SurveyModal.Submit')}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { FaKey, FaPlus } from 'react-icons/fa'
|
|||
import { ReservationDto } from '@/proxy/intranet/models'
|
||||
import useLocale from '@/utils/hooks/useLocale'
|
||||
import { currentLocalDate } from '@/utils/dateUtils'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
|
||||
interface ActiveReservationsProps {
|
||||
reservations: ReservationDto[]
|
||||
|
|
@ -14,13 +15,14 @@ const ActiveReservations: React.FC<ActiveReservationsProps> = ({
|
|||
onNewReservation,
|
||||
}) => {
|
||||
const currentLocale = useLocale()
|
||||
const { translate } = useLocalization()
|
||||
|
||||
return (
|
||||
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
|
||||
<div className="p-4 border-b border-gray-200 dark:border-gray-700">
|
||||
<h2 className="text-lg font-semibold text-gray-900 dark:text-white flex items-center gap-2">
|
||||
<FaKey className="w-5 h-5" />
|
||||
Aktif Rezervasyonlar
|
||||
{translate('::App.Platform.Intranet.Widgets.ActiveReservations.Title')}
|
||||
</h2>
|
||||
</div>
|
||||
<div className="p-4 space-y-3">
|
||||
|
|
@ -52,7 +54,7 @@ const ActiveReservations: React.FC<ActiveReservationsProps> = ({
|
|||
))}
|
||||
{reservations.filter((r) => r.status === 'approved').length === 0 && (
|
||||
<p className="text-sm text-gray-500 dark:text-gray-400 text-center py-4">
|
||||
Aktif rezervasyon yok
|
||||
{translate('::App.Platform.Intranet.Widgets.ActiveReservations.NoActive')}
|
||||
</p>
|
||||
)}
|
||||
|
||||
|
|
@ -61,7 +63,7 @@ const ActiveReservations: React.FC<ActiveReservationsProps> = ({
|
|||
className="w-full mt-3 px-4 py-2 bg-green-600 hover:bg-green-700 text-white text-sm rounded-lg transition-colors flex items-center justify-center gap-2"
|
||||
>
|
||||
<FaPlus className="w-4 h-4" />
|
||||
Yeni Rezervasyon
|
||||
{translate('::App.Platform.Intranet.Widgets.ActiveReservations.NewReservation')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import dayjs from 'dayjs'
|
|||
import { SurveyDto } from '@/proxy/intranet/models'
|
||||
import useLocale from '@/utils/hooks/useLocale'
|
||||
import { currentLocalDate } from '@/utils/dateUtils'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
|
||||
interface ActiveSurveysProps {
|
||||
surveys?: SurveyDto[]
|
||||
|
|
@ -12,6 +13,7 @@ interface ActiveSurveysProps {
|
|||
|
||||
const ActiveSurveys: React.FC<ActiveSurveysProps> = ({ surveys, onTakeSurvey }) => {
|
||||
const currentLocale = useLocale()
|
||||
const { translate } = useLocalization()
|
||||
|
||||
return (
|
||||
<div className="bg-gradient-to-br from-white to-gray-50 dark:from-gray-800 dark:to-gray-850 rounded-xl shadow-lg border border-gray-200/50 dark:border-gray-700/50 overflow-hidden">
|
||||
|
|
@ -20,7 +22,7 @@ const ActiveSurveys: React.FC<ActiveSurveysProps> = ({ surveys, onTakeSurvey })
|
|||
<div className="p-4 border-b border-gray-200 dark:border-gray-700">
|
||||
<h2 className="text-lg font-semibold text-gray-900 dark:text-white flex items-center gap-2">
|
||||
<FaClipboardCheck className="w-5 h-5" />
|
||||
Aktif Anketler
|
||||
{translate('::App.Platform.Intranet.Widgets.ActiveSurveys.Title')}
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
|
|
@ -53,7 +55,7 @@ const ActiveSurveys: React.FC<ActiveSurveysProps> = ({ surveys, onTakeSurvey })
|
|||
: 'bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-300'
|
||||
}`}
|
||||
>
|
||||
{daysLeft > 0 ? `${daysLeft} gün` : 'Son gün'}
|
||||
{daysLeft > 0 ? translate('::App.Platform.Intranet.Widgets.ActiveSurveys.DaysLeft', { count: daysLeft }) : translate('::App.Platform.Intranet.Widgets.ActiveSurveys.LastDay')}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -64,7 +66,7 @@ const ActiveSurveys: React.FC<ActiveSurveysProps> = ({ surveys, onTakeSurvey })
|
|||
<FaQuestionCircle className="w-3 h-3 text-blue-600 dark:text-blue-400" />
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-xs text-gray-500 dark:text-gray-400">Sorular</p>
|
||||
<p className="text-xs text-gray-500 dark:text-gray-400">{translate('::App.Platform.Intranet.Widgets.ActiveSurveys.Questions')}</p>
|
||||
<p className="font-semibold text-gray-900 dark:text-white">
|
||||
{survey.questions.length}
|
||||
</p>
|
||||
|
|
@ -76,7 +78,7 @@ const ActiveSurveys: React.FC<ActiveSurveysProps> = ({ surveys, onTakeSurvey })
|
|||
<FaUsers className="w-3 h-3 text-green-600 dark:text-green-400" />
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-xs text-gray-500 dark:text-gray-400">Yanıtlar</p>
|
||||
<p className="text-xs text-gray-500 dark:text-gray-400">{translate('::App.Platform.Intranet.Widgets.ActiveSurveys.Responses')}</p>
|
||||
<p className="font-semibold text-gray-900 dark:text-white">
|
||||
{survey.responses}
|
||||
</p>
|
||||
|
|
@ -88,7 +90,7 @@ const ActiveSurveys: React.FC<ActiveSurveysProps> = ({ surveys, onTakeSurvey })
|
|||
<FaClock className="w-3 h-3 text-purple-600 dark:text-purple-400" />
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-xs text-gray-500 dark:text-gray-400">Süre</p>
|
||||
<p className="text-xs text-gray-500 dark:text-gray-400">{translate('::App.Platform.Intranet.Widgets.ActiveSurveys.Duration')}</p>
|
||||
<p className="font-semibold text-gray-900 dark:text-white">~5dk</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -97,7 +99,7 @@ const ActiveSurveys: React.FC<ActiveSurveysProps> = ({ surveys, onTakeSurvey })
|
|||
{/* Progress Bar */}
|
||||
<div className="mb-4">
|
||||
<div className="flex justify-between text-xs mb-1">
|
||||
<span className="text-gray-600 dark:text-gray-400">Tamamlanma oranı</span>
|
||||
<span className="text-gray-600 dark:text-gray-400">{translate('::App.Platform.Intranet.Widgets.ActiveSurveys.CompletionRate')}</span>
|
||||
<span className="text-gray-800 dark:text-gray-200 font-medium">
|
||||
{Math.round((survey.responses / 100) * 100)}%
|
||||
</span>
|
||||
|
|
@ -118,7 +120,7 @@ const ActiveSurveys: React.FC<ActiveSurveysProps> = ({ surveys, onTakeSurvey })
|
|||
|
||||
{/* Action Button */}
|
||||
<button className="w-full flex items-center justify-center gap-2 px-4 py-3 bg-gradient-to-r from-purple-600 to-pink-600 hover:from-purple-700 hover:to-pink-700 text-white text-sm font-medium rounded-lg transition-all duration-300 transform group-hover:scale-[1.02] shadow-sm hover:shadow-md">
|
||||
Anketi Doldur
|
||||
{translate('::App.Platform.Intranet.Widgets.ActiveSurveys.FillSurvey')}
|
||||
<FaArrowRight className="w-3 h-3 transition-transform group-hover:translate-x-1" />
|
||||
</button>
|
||||
</div>
|
||||
|
|
@ -132,10 +134,10 @@ const ActiveSurveys: React.FC<ActiveSurveysProps> = ({ surveys, onTakeSurvey })
|
|||
<FaClipboardCheck className="w-8 h-8 text-gray-400" />
|
||||
</div>
|
||||
<h3 className="text-lg font-medium text-gray-900 dark:text-white mb-2">
|
||||
Aktif anket bulunmuyor
|
||||
{translate('::App.Platform.Intranet.Widgets.ActiveSurveys.NoActive')}
|
||||
</h3>
|
||||
<p className="text-sm text-gray-500 dark:text-gray-400">
|
||||
Yeni anketler eklendiğinde burada görünecektir.
|
||||
{translate('::App.Platform.Intranet.Widgets.ActiveSurveys.WillAppearHere')}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import React from 'react'
|
|||
import { FaBell, FaClipboardCheck, FaEye } from 'react-icons/fa'
|
||||
import dayjs from 'dayjs'
|
||||
import { AnnouncementDto } from '@/proxy/intranet/models'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
|
||||
interface AnnouncementsProps {
|
||||
announcements: AnnouncementDto[]
|
||||
|
|
@ -10,6 +11,7 @@ interface AnnouncementsProps {
|
|||
|
||||
const Announcements: React.FC<AnnouncementsProps> = ({ announcements, onAnnouncementClick }) => {
|
||||
const pinnedAnnouncements = announcements.filter((a) => a.isPinned).slice(0, 3)
|
||||
const { translate } = useLocalization();
|
||||
|
||||
const getCategoryColor = (category: string) => {
|
||||
const colors: Record<string, string> = {
|
||||
|
|
@ -28,7 +30,7 @@ const Announcements: React.FC<AnnouncementsProps> = ({ announcements, onAnnounce
|
|||
<div className="flex items-center justify-between">
|
||||
<h2 className="text-lg font-semibold text-gray-900 dark:text-white flex items-center gap-2">
|
||||
<FaBell className="w-5 h-5" />
|
||||
Önemli Duyurular
|
||||
{translate('::App.Platform.Intranet.Widgets.Announcements.Title')}
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -53,7 +55,7 @@ const Announcements: React.FC<AnnouncementsProps> = ({ announcements, onAnnounce
|
|||
<span
|
||||
className={`px-2 py-1 text-xs rounded-full ${getCategoryColor(announcement.category)}`}
|
||||
>
|
||||
{announcement.category}
|
||||
{translate(`::App.Platform.Intranet.Widgets.Announcements.Category.${announcement.category.charAt(0).toUpperCase() + announcement.category.slice(1)}`, announcement.category)}
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-sm text-gray-600 dark:text-gray-400 line-clamp-2">
|
||||
|
|
@ -80,10 +82,10 @@ const Announcements: React.FC<AnnouncementsProps> = ({ announcements, onAnnounce
|
|||
<FaClipboardCheck className="w-8 h-8 text-gray-400" />
|
||||
</div>
|
||||
<h3 className="text-lg font-medium text-gray-900 dark:text-white mb-2">
|
||||
Aktif duyuru bulunmuyor
|
||||
{translate('::App.Platform.Intranet.Widgets.Announcements.NoActive')}
|
||||
</h3>
|
||||
<p className="text-sm text-gray-500 dark:text-gray-400">
|
||||
Yeni duyurular eklendiğinde burada görünecektir.
|
||||
{translate('::App.Platform.Intranet.Widgets.Announcements.WillAppearHere')}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import React from 'react'
|
||||
import { FaDollarSign, FaPlus } from 'react-icons/fa'
|
||||
import { ExpensesDto } from '@/proxy/intranet/models'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
|
||||
interface ExpenseManagementProps {
|
||||
expenses: ExpensesDto
|
||||
|
|
@ -8,23 +9,24 @@ interface ExpenseManagementProps {
|
|||
}
|
||||
|
||||
const ExpenseManagement: React.FC<ExpenseManagementProps> = ({ expenses, onNewExpense }) => {
|
||||
const { translate } = useLocalization();
|
||||
return (
|
||||
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
|
||||
<div className="p-4 border-b border-gray-200 dark:border-gray-700">
|
||||
<h2 className="text-lg font-semibold text-gray-900 dark:text-white flex items-center gap-2">
|
||||
<FaDollarSign className="w-5 h-5" />
|
||||
Harcama Yönetimi
|
||||
{translate('::App.Platform.Intranet.Widgets.ExpenseManagement.Title')}
|
||||
</h2>
|
||||
</div>
|
||||
<div className="p-4 space-y-3">
|
||||
{/* Harcama özeti */}
|
||||
<div className="p-3 bg-emerald-50 dark:bg-emerald-900/20 rounded-lg border border-emerald-200 dark:border-emerald-800 mb-4">
|
||||
<p className="text-xs text-gray-600 dark:text-gray-400">Bu Ay Toplam</p>
|
||||
<p className="text-xs text-gray-600 dark:text-gray-400">{translate('::App.Platform.Intranet.Widgets.ExpenseManagement.ThisMonthTotal')}</p>
|
||||
<p className="text-2xl font-bold text-emerald-600 dark:text-emerald-400">
|
||||
{expenses.totalRequested.toLocaleString('tr-TR')}
|
||||
</p>
|
||||
<p className="text-xs text-gray-500 dark:text-gray-400 mt-1">
|
||||
{expenses.totalApproved.toLocaleString('tr-TR')} onaylandı
|
||||
{expenses.totalApproved.toLocaleString('tr-TR')} {translate('::App.Platform.Intranet.Widgets.ExpenseManagement.Approved')}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
|
@ -63,10 +65,10 @@ const ExpenseManagement: React.FC<ExpenseManagementProps> = ({ expenses, onNewEx
|
|||
}`}
|
||||
>
|
||||
{expense.status === 'approved'
|
||||
? 'Onaylandı'
|
||||
? translate('::App.Platform.Intranet.Widgets.ExpenseManagement.Status.Approved')
|
||||
: expense.status === 'pending'
|
||||
? 'Bekliyor'
|
||||
: 'Reddedildi'}
|
||||
? translate('::App.Platform.Intranet.Widgets.ExpenseManagement.Status.Pending')
|
||||
: translate('::App.Platform.Intranet.Widgets.ExpenseManagement.Status.Rejected')}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -78,7 +80,7 @@ const ExpenseManagement: React.FC<ExpenseManagementProps> = ({ expenses, onNewEx
|
|||
className="w-full mt-3 px-4 py-2 bg-emerald-600 hover:bg-emerald-700 text-white text-sm rounded-lg transition-colors flex items-center justify-center gap-2"
|
||||
>
|
||||
<FaPlus className="w-4 h-4" />
|
||||
Yeni Harcama Talebi
|
||||
{translate('::App.Platform.Intranet.Widgets.ExpenseManagement.NewExpense')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { LeaveDto } from '@/proxy/intranet/models'
|
|||
import useLocale from '@/utils/hooks/useLocale'
|
||||
import { currentLocalDate } from '@/utils/dateUtils'
|
||||
import { LeaveStatusEnum, LeaveTypeEnum } from '@/types/intranet'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
|
||||
interface LeaveManagementProps {
|
||||
leaves: LeaveDto[]
|
||||
|
|
@ -12,25 +13,26 @@ interface LeaveManagementProps {
|
|||
|
||||
const LeaveManagement: React.FC<LeaveManagementProps> = ({ leaves, onNewLeave }) => {
|
||||
const currentLocale = useLocale()
|
||||
const { translate } = useLocalization();
|
||||
|
||||
return (
|
||||
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
|
||||
<div className="p-4 border-b border-gray-200 dark:border-gray-700">
|
||||
<h2 className="text-lg font-semibold text-gray-900 dark:text-white flex items-center gap-2">
|
||||
<FaCalendarAlt className="w-5 h-5" />
|
||||
İzin Yönetimi
|
||||
{translate('::App.Platform.Intranet.Widgets.LeaveManagement.Title')}
|
||||
</h2>
|
||||
</div>
|
||||
<div className="p-4 space-y-3">
|
||||
{/* İzin bakiye özeti */}
|
||||
<div className="grid grid-cols-2 gap-2 mb-4">
|
||||
<div className="p-3 bg-blue-50 dark:bg-blue-900/20 rounded-lg border border-blue-200 dark:border-blue-800">
|
||||
<p className="text-xs text-gray-600 dark:text-gray-400">Yıllık İzin</p>
|
||||
<p className="text-lg font-bold text-blue-600 dark:text-blue-400">12 gün</p>
|
||||
<p className="text-xs text-gray-600 dark:text-gray-400">{translate('::App.Platform.Intranet.Widgets.LeaveManagement.AnnualLeave')}</p>
|
||||
<p className="text-lg font-bold text-blue-600 dark:text-blue-400">12 {translate('::App.Platform.Intranet.Widgets.LeaveManagement.Day')}</p>
|
||||
</div>
|
||||
<div className="p-3 bg-green-50 dark:bg-green-900/20 rounded-lg border border-green-200 dark:border-green-800">
|
||||
<p className="text-xs text-gray-600 dark:text-gray-400">Hastalık İzni</p>
|
||||
<p className="text-lg font-bold text-green-600 dark:text-green-400">8 gün</p>
|
||||
<p className="text-xs text-gray-600 dark:text-gray-400">{translate('::App.Platform.Intranet.Widgets.LeaveManagement.SickLeave')}</p>
|
||||
<p className="text-lg font-bold text-green-600 dark:text-green-400">8 {translate('::App.Platform.Intranet.Widgets.LeaveManagement.Day')}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -44,13 +46,13 @@ const LeaveManagement: React.FC<LeaveManagementProps> = ({ leaves, onNewLeave })
|
|||
<div className="flex items-start justify-between mb-1">
|
||||
<h4 className="text-sm font-medium text-gray-900 dark:text-white">
|
||||
{leave.leaveType === LeaveTypeEnum.Annual
|
||||
? '🏖️ Yıllık'
|
||||
? `🏖️ ${translate('::App.Platform.Intranet.Widgets.LeaveManagement.Annual')}`
|
||||
: leave.leaveType === LeaveTypeEnum.Sick
|
||||
? '🏥 Hastalık'
|
||||
? `🏥 ${translate('::App.Platform.Intranet.Widgets.LeaveManagement.Sick')}`
|
||||
: leave.leaveType === LeaveTypeEnum.Unpaid
|
||||
? '💼 Ücretsiz'
|
||||
: '📋 Diğer'}{' '}
|
||||
İzin
|
||||
? `💼 ${translate('::App.Platform.Intranet.Widgets.LeaveManagement.Unpaid')}`
|
||||
: `📋 ${translate('::App.Platform.Intranet.Widgets.LeaveManagement.Other')}`}{' '}
|
||||
{translate('::App.Platform.Intranet.Widgets.LeaveManagement.Leave')}
|
||||
</h4>
|
||||
<span
|
||||
className={`text-xs px-2 py-1 rounded-full ${
|
||||
|
|
@ -62,15 +64,15 @@ const LeaveManagement: React.FC<LeaveManagementProps> = ({ leaves, onNewLeave })
|
|||
}`}
|
||||
>
|
||||
{leave.status === LeaveStatusEnum.Approved
|
||||
? 'Onaylandı'
|
||||
? translate('::App.Platform.Intranet.Widgets.LeaveManagement.Status.Approved')
|
||||
: leave.status === LeaveStatusEnum.Pending
|
||||
? 'Bekliyor'
|
||||
: 'Reddedildi'}
|
||||
? translate('::App.Platform.Intranet.Widgets.LeaveManagement.Status.Pending')
|
||||
: translate('::App.Platform.Intranet.Widgets.LeaveManagement.Status.Rejected')}
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-xs text-gray-600 dark:text-gray-400">
|
||||
{currentLocalDate(leave.startDate, currentLocale || 'tr')} - {currentLocalDate(leave.endDate, currentLocale || 'tr')}{' '}
|
||||
({leave.totalDays} gün)
|
||||
({leave.totalDays} {translate('::App.Platform.Intranet.Widgets.LeaveManagement.Day')})
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
|
|
@ -81,7 +83,7 @@ const LeaveManagement: React.FC<LeaveManagementProps> = ({ leaves, onNewLeave })
|
|||
className="w-full mt-3 px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white text-sm rounded-lg transition-colors flex items-center justify-center gap-2"
|
||||
>
|
||||
<FaPlus className="w-4 h-4" />
|
||||
Yeni İzin Talebi
|
||||
{translate('::App.Platform.Intranet.Widgets.LeaveManagement.NewLeaveRequest')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -6,11 +6,13 @@ import { Badge } from '@/components/ui'
|
|||
import { MealDto } from '@/proxy/intranet/models'
|
||||
import useLocale from '@/utils/hooks/useLocale'
|
||||
import { currentLocalDate } from '@/utils/dateUtils'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
|
||||
dayjs.extend(isBetween)
|
||||
|
||||
const MealWeeklyMenu: React.FC<{ meals: MealDto[] }> = ({ meals }) => {
|
||||
const currentLocale = useLocale()
|
||||
const { translate } = useLocalization();
|
||||
|
||||
return (
|
||||
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
|
||||
|
|
@ -18,7 +20,7 @@ const MealWeeklyMenu: React.FC<{ meals: MealDto[] }> = ({ meals }) => {
|
|||
<div className="flex items-center justify-between">
|
||||
<h2 className="text-lg font-semibold text-gray-900 dark:text-white flex items-center gap-2">
|
||||
<FaUtensils className="w-5 h-5" />
|
||||
Haftalık Menü
|
||||
{translate('::App.Platform.Intranet.Widgets.MealWeeklyMenu.Title')}
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -40,7 +42,7 @@ const MealWeeklyMenu: React.FC<{ meals: MealDto[] }> = ({ meals }) => {
|
|||
</h3>
|
||||
{isToday && (
|
||||
<span className="text-xs bg-orange-500 text-white px-2 py-0.5 rounded-full">
|
||||
Bugün
|
||||
{translate('::App.Platform.Intranet.Widgets.MealWeeklyMenu.Today')}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
|
@ -67,7 +69,7 @@ const MealWeeklyMenu: React.FC<{ meals: MealDto[] }> = ({ meals }) => {
|
|||
</div>
|
||||
<div className="space-y-1">
|
||||
<p className="text-xs text-gray-500 dark:text-gray-400">
|
||||
Haftalık menü henüz hazırlanmamış. Lütfen daha sonra tekrar kontrol edin.
|
||||
{translate('::App.Platform.Intranet.Widgets.MealWeeklyMenu.NotReady')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { OvertimeDto } from '@/proxy/intranet/models'
|
|||
import useLocale from '@/utils/hooks/useLocale'
|
||||
import { currentLocalDate } from '@/utils/dateUtils'
|
||||
import { LeaveStatusEnum } from '@/types/intranet'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
|
||||
interface OvertimeManagementProps {
|
||||
overtimes: OvertimeDto[]
|
||||
|
|
@ -12,21 +13,22 @@ interface OvertimeManagementProps {
|
|||
|
||||
const OvertimeManagement: React.FC<OvertimeManagementProps> = ({ overtimes, onNewOvertime }) => {
|
||||
const currentLocale = useLocale()
|
||||
const { translate } = useLocalization();
|
||||
|
||||
return (
|
||||
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
|
||||
<div className="p-4 border-b border-gray-200 dark:border-gray-700">
|
||||
<h2 className="text-lg font-semibold text-gray-900 dark:text-white flex items-center gap-2">
|
||||
<FaClock className="w-5 h-5" />
|
||||
Mesai Yönetimi
|
||||
{translate('::App.Platform.Intranet.Widgets.OvertimeManagement.Title')}
|
||||
</h2>
|
||||
</div>
|
||||
<div className="p-4 space-y-3">
|
||||
{/* Mesai özeti */}
|
||||
<div className="p-3 bg-orange-50 dark:bg-orange-900/20 rounded-lg border border-orange-200 dark:border-orange-800 mb-4">
|
||||
<p className="text-xs text-gray-600 dark:text-gray-400">Bu Ay Toplam</p>
|
||||
<p className="text-2xl font-bold text-orange-600 dark:text-orange-400">24 saat</p>
|
||||
<p className="text-xs text-gray-500 dark:text-gray-400 mt-1">20 onaylandı, 4 bekliyor</p>
|
||||
<p className="text-xs text-gray-600 dark:text-gray-400">{translate('::App.Platform.Intranet.Widgets.OvertimeManagement.ThisMonthTotal')}</p>
|
||||
<p className="text-2xl font-bold text-orange-600 dark:text-orange-400">24 {translate('::App.Platform.Intranet.Widgets.OvertimeManagement.Hour')}</p>
|
||||
<p className="text-xs text-gray-500 dark:text-gray-400 mt-1">20 {translate('::App.Platform.Intranet.Widgets.OvertimeManagement.Status.Approved')}, 4 {translate('::App.Platform.Intranet.Widgets.OvertimeManagement.Status.Pending')}</p>
|
||||
</div>
|
||||
|
||||
{/* Son mesai talepleri */}
|
||||
|
|
@ -50,10 +52,10 @@ const OvertimeManagement: React.FC<OvertimeManagementProps> = ({ overtimes, onNe
|
|||
}`}
|
||||
>
|
||||
{overtime.status === LeaveStatusEnum.Approved
|
||||
? 'Onaylandı'
|
||||
? translate('::App.Platform.Intranet.Widgets.OvertimeManagement.Status.Approved')
|
||||
: overtime.status === LeaveStatusEnum.Pending
|
||||
? 'Bekliyor'
|
||||
: 'Reddedildi'}
|
||||
? translate('::App.Platform.Intranet.Widgets.OvertimeManagement.Status.Pending')
|
||||
: translate('::App.Platform.Intranet.Widgets.OvertimeManagement.Status.Rejected')}
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-xs text-gray-600 dark:text-gray-400">
|
||||
|
|
@ -68,7 +70,7 @@ const OvertimeManagement: React.FC<OvertimeManagementProps> = ({ overtimes, onNe
|
|||
className="w-full mt-3 px-4 py-2 bg-orange-600 hover:bg-orange-700 text-white text-sm rounded-lg transition-colors flex items-center justify-center gap-2"
|
||||
>
|
||||
<FaPlus className="w-4 h-4" />
|
||||
Yeni Mesai Talebi
|
||||
{translate('::App.Platform.Intranet.Widgets.OvertimeManagement.NewOvertimeRequest')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import React from 'react'
|
||||
import { FaChartBar, FaClock, FaUser } from 'react-icons/fa'
|
||||
import useLocale from '@/utils/hooks/useLocale'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
import { currentLocalDate } from '@/utils/dateUtils'
|
||||
import { PriorityEnum, TaskStatusEnum } from '@/types/intranet'
|
||||
import { ProjectTaskDto } from '@/proxy/intranet/models'
|
||||
|
|
@ -11,6 +12,7 @@ interface PriorityTasksProps {
|
|||
|
||||
const PriorityTasks: React.FC<PriorityTasksProps> = ({ tasks }) => {
|
||||
const currentLocale = useLocale()
|
||||
const { translate } = useLocalization();
|
||||
|
||||
const getPriorityColor = (priority: PriorityEnum) => {
|
||||
const colors: Record<PriorityEnum, string> = {
|
||||
|
|
@ -28,7 +30,7 @@ const PriorityTasks: React.FC<PriorityTasksProps> = ({ tasks }) => {
|
|||
<div className="p-4 border-b border-gray-200 dark:border-gray-700">
|
||||
<h2 className="text-lg font-semibold text-gray-900 dark:text-white flex items-center gap-2">
|
||||
<FaChartBar className="w-5 h-5" />
|
||||
Öncelikli Görevler
|
||||
{translate('::App.Platform.Intranet.Widgets.PriorityTasks.Title')}
|
||||
</h2>
|
||||
</div>
|
||||
<div className="divide-y divide-gray-200 dark:divide-gray-700">
|
||||
|
|
@ -47,10 +49,10 @@ const PriorityTasks: React.FC<PriorityTasksProps> = ({ tasks }) => {
|
|||
<span
|
||||
className={`px-2 py-0.5 text-xs rounded ${getPriorityColor(task.priority)}`}
|
||||
>
|
||||
{task.priority === PriorityEnum.Urgent && '🔥 Acil'}
|
||||
{task.priority === PriorityEnum.High && 'Yüksek'}
|
||||
{task.priority === PriorityEnum.Normal && 'Orta'}
|
||||
{task.priority === PriorityEnum.Low && 'Düşük'}
|
||||
{task.priority === PriorityEnum.Urgent && translate('::App.Platform.Intranet.Widgets.PriorityTasks.Urgent')}
|
||||
{task.priority === PriorityEnum.High && translate('::App.Platform.Intranet.Widgets.PriorityTasks.High')}
|
||||
{task.priority === PriorityEnum.Normal && translate('::App.Platform.Intranet.Widgets.PriorityTasks.Normal')}
|
||||
{task.priority === PriorityEnum.Low && translate('::App.Platform.Intranet.Widgets.PriorityTasks.Low')}
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-xs text-gray-600 dark:text-gray-400 mb-2">{task.description}</p>
|
||||
|
|
@ -61,7 +63,7 @@ const PriorityTasks: React.FC<PriorityTasksProps> = ({ tasks }) => {
|
|||
</span>
|
||||
<span className="flex items-center gap-1">
|
||||
<FaUser className="w-3 h-3" />
|
||||
{task.employee.name || 'Atanmadı'}
|
||||
{task.employee.name || translate('::App.Platform.Intranet.Widgets.PriorityTasks.Unassigned')}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { FaFileAlt, FaDownload } from 'react-icons/fa'
|
|||
import dayjs from 'dayjs'
|
||||
import { DocumentDto } from '@/proxy/intranet/models'
|
||||
import { getFileIcon, getFileType } from '@/proxy/intranet/utils'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
|
||||
const formatFileSize = (bytes: number): string => {
|
||||
if (bytes === 0) return '0 B'
|
||||
|
|
@ -13,13 +14,14 @@ const formatFileSize = (bytes: number): string => {
|
|||
}
|
||||
|
||||
const RecentDocuments: React.FC<{ documents: DocumentDto[] }> = ({ documents }) => {
|
||||
const { translate } = useLocalization();
|
||||
return (
|
||||
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
|
||||
<div className="p-4 border-b border-gray-200 dark:border-gray-700">
|
||||
<div className="flex items-center justify-between">
|
||||
<h2 className="text-lg font-semibold text-gray-900 dark:text-white flex items-center gap-2">
|
||||
<FaFileAlt className="w-5 h-5" />
|
||||
Son Dokümanlar
|
||||
{translate('::App.Platform.Intranet.Widgets.RecentDocuments.Title')}
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -48,7 +50,7 @@ const RecentDocuments: React.FC<{ documents: DocumentDto[] }> = ({ documents })
|
|||
{doc.isReadOnly && (
|
||||
<>
|
||||
<span>•</span>
|
||||
<span className="text-orange-500">🔒 Salt okunur</span>
|
||||
<span className="text-orange-500">🔒 {translate('::App.Platform.Intranet.Widgets.RecentDocuments.ReadOnly')}</span>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
|
@ -62,7 +64,7 @@ const RecentDocuments: React.FC<{ documents: DocumentDto[] }> = ({ documents })
|
|||
link.click()
|
||||
}}
|
||||
className="p-2 hover:bg-blue-100 dark:hover:bg-blue-900/30 rounded-lg transition-colors group"
|
||||
title="İndir"
|
||||
title={translate('::App.Platform.Intranet.Widgets.RecentDocuments.Download')}
|
||||
>
|
||||
<FaDownload className="w-5 h-5 text-gray-600 dark:text-gray-400 group-hover:text-blue-600 dark:group-hover:text-blue-400 transition-colors" />
|
||||
</button>
|
||||
|
|
@ -71,7 +73,7 @@ const RecentDocuments: React.FC<{ documents: DocumentDto[] }> = ({ documents })
|
|||
))
|
||||
) : (
|
||||
<div className="p-4 text-center text-sm text-gray-500 dark:text-gray-400">
|
||||
Gösterilecek doküman yok.
|
||||
{translate('::App.Platform.Intranet.Widgets.RecentDocuments.NoDocuments')}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,24 +1,26 @@
|
|||
import React from 'react'
|
||||
import { FaTruck } from 'react-icons/fa'
|
||||
import { ShuttleRouteDto } from '@/proxy/intranet/models'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
|
||||
const ShuttleRoute: React.FC<{ shuttleRoutes: ShuttleRouteDto[] }> = ({ shuttleRoutes }) => {
|
||||
const morningShuttles = shuttleRoutes.filter((s) => s.type === 'morning')
|
||||
const eveningShuttles = shuttleRoutes.filter((s) => s.type === 'evening')
|
||||
const { translate } = useLocalization();
|
||||
|
||||
return (
|
||||
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
|
||||
<div className="p-4 border-b border-gray-200 dark:border-gray-700">
|
||||
<h2 className="text-lg font-semibold text-gray-900 dark:text-white flex items-center gap-2">
|
||||
<FaTruck className="w-5 h-5" />
|
||||
Servis Saatleri
|
||||
{translate('::App.Platform.Intranet.Widgets.ShuttleRoute.Title')}
|
||||
</h2>
|
||||
</div>
|
||||
<div className="p-4 space-y-4">
|
||||
{/* Sabah Servisleri */}
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold text-gray-900 dark:text-white mb-3 flex items-center gap-2">
|
||||
🌅 Sabah Servisleri
|
||||
🌅 {translate('::App.Platform.Intranet.Widgets.ShuttleRoute.Morning')}
|
||||
</h3>
|
||||
<div className="space-y-2">
|
||||
{morningShuttles.slice(0, 2).map((shuttle) => (
|
||||
|
|
@ -52,7 +54,7 @@ const ShuttleRoute: React.FC<{ shuttleRoutes: ShuttleRouteDto[] }> = ({ shuttleR
|
|||
: 'bg-red-100 dark:bg-red-900/30 text-red-700 dark:text-red-300'
|
||||
}`}
|
||||
>
|
||||
{shuttle.available} yer
|
||||
{shuttle.available} {translate('::App.Platform.Intranet.Widgets.ShuttleRoute.Seat')}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -63,7 +65,7 @@ const ShuttleRoute: React.FC<{ shuttleRoutes: ShuttleRouteDto[] }> = ({ shuttleR
|
|||
{/* Akşam Servisleri */}
|
||||
<div>
|
||||
<h3 className="text-sm font-semibold text-gray-900 dark:text-white mb-3 flex items-center gap-2">
|
||||
🌆 Akşam Servisleri
|
||||
🌆 {translate('::App.Platform.Intranet.Widgets.ShuttleRoute.Evening')}
|
||||
</h3>
|
||||
<div className="space-y-2">
|
||||
{eveningShuttles.slice(0, 2).map((shuttle) => (
|
||||
|
|
@ -97,7 +99,7 @@ const ShuttleRoute: React.FC<{ shuttleRoutes: ShuttleRouteDto[] }> = ({ shuttleR
|
|||
: 'bg-red-100 dark:bg-red-900/30 text-red-700 dark:text-red-300'
|
||||
}`}
|
||||
>
|
||||
{shuttle.available} yer
|
||||
{shuttle.available} {translate('::App.Platform.Intranet.Widgets.ShuttleRoute.Seat')}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,15 +1,17 @@
|
|||
import React from 'react'
|
||||
import dayjs from 'dayjs'
|
||||
import { EmployeeDto } from '@/proxy/intranet/models'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
|
||||
const TodayBirthdays: React.FC<{ employees: EmployeeDto[] }> = ({ employees }) => {
|
||||
const today = dayjs()
|
||||
const { translate } = useLocalization();
|
||||
|
||||
return (
|
||||
<div className="bg-gradient-to-br from-pink-50 to-purple-50 dark:from-pink-900/20 dark:to-purple-900/20 rounded-lg shadow-sm border border-pink-200 dark:border-pink-800">
|
||||
<div className="p-4 border-b border-pink-200 dark:border-pink-700">
|
||||
<h2 className="text-lg font-semibold text-gray-900 dark:text-white flex items-center gap-2">
|
||||
🎂 Bugün Doğanlar
|
||||
🎂 {translate('::App.Platform.Intranet.Widgets.TodayBirthdays.Title')}
|
||||
</h2>
|
||||
</div>
|
||||
<div className="p-4 space-y-3">
|
||||
|
|
@ -30,10 +32,10 @@ const TodayBirthdays: React.FC<{ employees: EmployeeDto[] }> = ({ employees }) =
|
|||
{birthday.name}
|
||||
</p>
|
||||
<p className="text-xs text-gray-600 dark:text-gray-400">
|
||||
{today.diff(dayjs(birthday.birthDate), 'year')} yaşında 🎉
|
||||
{translate('::App.Platform.Intranet.Widgets.TodayBirthdays.Age', { age: today.diff(dayjs(birthday.birthDate), 'year') })} 🎉
|
||||
</p>
|
||||
<p className="text-xs text-gray-500 dark:text-gray-500 mt-1">
|
||||
{birthday.department?.name || 'Genel'}
|
||||
{birthday.department?.name || translate('::App.Platform.Intranet.Widgets.TodayBirthdays.General')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -41,7 +43,7 @@ const TodayBirthdays: React.FC<{ employees: EmployeeDto[] }> = ({ employees }) =
|
|||
</div>
|
||||
) : (
|
||||
<p className="text-sm text-gray-500 dark:text-gray-400 text-center py-4">
|
||||
Bugün doğan yok
|
||||
{translate('::App.Platform.Intranet.Widgets.TodayBirthdays.NoBirthday')}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -4,9 +4,11 @@ import dayjs from 'dayjs'
|
|||
import { EventDto } from '@/proxy/intranet/models'
|
||||
import useLocale from '@/utils/hooks/useLocale'
|
||||
import { currentLocalDate } from '@/utils/dateUtils'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
|
||||
const UpcomingEvents: React.FC<{ events: EventDto[] }> = ({ events }) => {
|
||||
const currentLocale = useLocale()
|
||||
const { translate } = useLocalization();
|
||||
|
||||
const upcomingEvents = events.filter(
|
||||
(event) =>
|
||||
|
|
@ -20,7 +22,7 @@ const UpcomingEvents: React.FC<{ events: EventDto[] }> = ({ events }) => {
|
|||
<div className="p-4 border-b border-gray-200 dark:border-gray-700">
|
||||
<h2 className="text-lg font-semibold text-gray-900 dark:text-white flex items-center gap-2">
|
||||
<FaCalendarAlt className="w-5 h-5" />
|
||||
Yaklaşan Etkinlikler
|
||||
{translate('::App.Platform.Intranet.Widgets.UpcomingEvents.Title')}
|
||||
</h2>
|
||||
</div>
|
||||
<div className="p-4 space-y-3">
|
||||
|
|
@ -38,7 +40,7 @@ const UpcomingEvents: React.FC<{ events: EventDto[] }> = ({ events }) => {
|
|||
))
|
||||
) : (
|
||||
<p className="text-sm text-gray-500 dark:text-gray-400 text-center py-4">
|
||||
Yaklaşan etkinlik yok
|
||||
{translate('::App.Platform.Intranet.Widgets.UpcomingEvents.NoEvent')}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -3,16 +3,18 @@ import { FaGraduationCap } from 'react-icons/fa'
|
|||
import { TrainingDto } from '@/proxy/intranet/models'
|
||||
import { currentLocalDate } from '@/utils/dateUtils'
|
||||
import useLocale from '@/utils/hooks/useLocale'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
|
||||
const UpcomingTrainings: React.FC<{ trainings: TrainingDto[] }> = ({ trainings }) => {
|
||||
const currentLocale = useLocale()
|
||||
const { translate } = useLocalization();
|
||||
|
||||
return (
|
||||
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
|
||||
<div className="p-4 border-b border-gray-200 dark:border-gray-700">
|
||||
<h2 className="text-lg font-semibold text-gray-900 dark:text-white flex items-center gap-2">
|
||||
<FaGraduationCap className="w-5 h-5" />
|
||||
Yaklaşan Eğitimler
|
||||
{translate('::App.Platform.Intranet.Widgets.UpcomingTrainings.Title')}
|
||||
</h2>
|
||||
</div>
|
||||
<div className="p-4 space-y-3">
|
||||
|
|
@ -43,7 +45,7 @@ const UpcomingTrainings: React.FC<{ trainings: TrainingDto[] }> = ({ trainings }
|
|||
))}
|
||||
{trainings.filter((t) => t.status === 'upcoming').length === 0 && (
|
||||
<p className="text-sm text-gray-500 dark:text-gray-400 text-center py-4">
|
||||
Yaklaşan eğitim yok
|
||||
{translate('::App.Platform.Intranet.Widgets.UpcomingTrainings.NoTraining')}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -2,15 +2,17 @@ import React from 'react'
|
|||
import { FaUser, FaUserCheck, FaUserClock } from 'react-icons/fa'
|
||||
import dayjs from 'dayjs'
|
||||
import { VisitorDto } from '@/proxy/intranet/models'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
|
||||
const Visitors: React.FC<{ visitors: VisitorDto[] }> = ({ visitors }) => {
|
||||
const { translate } = useLocalization();
|
||||
const getStatusIcon = (status: string) => {
|
||||
switch (status) {
|
||||
case 'Giriş':
|
||||
case translate('::App.Platform.Intranet.Widgets.Visitors.Status.Entry', 'Giriş'):
|
||||
return <FaUserCheck className="w-4 h-4 text-green-600" />
|
||||
case 'Çıkış':
|
||||
case translate('::App.Platform.Intranet.Widgets.Visitors.Status.Exit', 'Çıkış'):
|
||||
return <FaUser className="w-4 h-4 text-gray-600" />
|
||||
case 'Planlandı':
|
||||
case translate('::App.Platform.Intranet.Widgets.Visitors.Status.Planned', 'Planlandı'):
|
||||
return <FaUserClock className="w-4 h-4 text-blue-600" />
|
||||
default:
|
||||
return <FaUser className="w-4 h-4 text-gray-600" />
|
||||
|
|
@ -19,14 +21,14 @@ const Visitors: React.FC<{ visitors: VisitorDto[] }> = ({ visitors }) => {
|
|||
|
||||
const getStatusText = (status: string) => {
|
||||
switch (status) {
|
||||
case 'Giriş':
|
||||
return 'Giriş Yaptı'
|
||||
case 'Çıkış':
|
||||
return 'Çıkış Yaptı'
|
||||
case 'Planlandı':
|
||||
return 'Planlandı'
|
||||
case translate('::App.Platform.Intranet.Widgets.Visitors.Status.Entry', 'Giriş'):
|
||||
return translate('::App.Platform.Intranet.Widgets.Visitors.StatusText.Entry')
|
||||
case translate('::App.Platform.Intranet.Widgets.Visitors.Status.Exit', 'Çıkış'):
|
||||
return translate('::App.Platform.Intranet.Widgets.Visitors.StatusText.Exit')
|
||||
case translate('::App.Platform.Intranet.Widgets.Visitors.Status.Planned', 'Planlandı'):
|
||||
return translate('::App.Platform.Intranet.Widgets.Visitors.StatusText.Planned')
|
||||
default:
|
||||
return 'Bilinmiyor'
|
||||
return translate('::App.Platform.Intranet.Widgets.Visitors.StatusText.Unknown')
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -48,7 +50,7 @@ const Visitors: React.FC<{ visitors: VisitorDto[] }> = ({ visitors }) => {
|
|||
<div className="p-4 border-b border-gray-200 dark:border-gray-700">
|
||||
<h2 className="text-lg font-semibold text-gray-900 dark:text-white flex items-center gap-2">
|
||||
<FaUser className="w-5 h-5" />
|
||||
Bugünkü Ziyaretçiler
|
||||
{translate('::App.Platform.Intranet.Widgets.Visitors.Title')}
|
||||
</h2>
|
||||
</div>
|
||||
<div className="p-4 space-y-3">
|
||||
|
|
@ -90,7 +92,7 @@ const Visitors: React.FC<{ visitors: VisitorDto[] }> = ({ visitors }) => {
|
|||
</div>
|
||||
{visitor.employee && (
|
||||
<p className="text-xs text-gray-500 dark:text-gray-500 mt-1">
|
||||
Karşılayan: {visitor.employee.name}
|
||||
{translate('::App.Platform.Intranet.Widgets.Visitors.Host')}: {visitor.employee.name}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
|
@ -99,7 +101,7 @@ const Visitors: React.FC<{ visitors: VisitorDto[] }> = ({ visitors }) => {
|
|||
))
|
||||
) : (
|
||||
<p className="text-sm text-gray-500 dark:text-gray-400 text-center py-4">
|
||||
Bugün ziyaretçi yok
|
||||
{translate('::App.Platform.Intranet.Widgets.Visitors.NoVisitor')}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in a new issue