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 () => {
|
setTimeout(async () => {
|
||||||
getConfig(true)
|
getConfig(true)
|
||||||
}, 6000)
|
}, 3000)
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPermissionsWithGroupName(groups: PermissionGroupDto[]): PermissionWithGroupName[] {
|
function getPermissionsWithGroupName(groups: PermissionGroupDto[]): PermissionWithGroupName[] {
|
||||||
|
|
|
||||||
|
|
@ -104,7 +104,7 @@ function UsersPermission({
|
||||||
|
|
||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
getConfig(true)
|
getConfig(true)
|
||||||
}, 6000)
|
}, 3000)
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPermissionsWithGroupName(groups: PermissionGroupDto[]): PermissionWithGroupName[] {
|
function getPermissionsWithGroupName(groups: PermissionGroupDto[]): PermissionWithGroupName[] {
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,9 @@ interface CreatePostProps {
|
||||||
}) => void
|
}) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
const CreatePost: React.FC<CreatePostProps> = ({ onCreatePost }) => {
|
const CreatePost: React.FC<CreatePostProps> = ({ onCreatePost }) => {
|
||||||
|
const { translate } = useLocalization();
|
||||||
const [content, setContent] = useState('')
|
const [content, setContent] = useState('')
|
||||||
const [mediaType, setMediaType] = useState<'media' | 'poll' | null>(null)
|
const [mediaType, setMediaType] = useState<'media' | 'poll' | null>(null)
|
||||||
const [mediaItems, setMediaItems] = useState<SocialMediaDto[]>([])
|
const [mediaItems, setMediaItems] = useState<SocialMediaDto[]>([])
|
||||||
|
|
@ -164,7 +166,7 @@ const CreatePost: React.FC<CreatePostProps> = ({ onCreatePost }) => {
|
||||||
value={content}
|
value={content}
|
||||||
onChange={(e) => setContent(e.target.value)}
|
onChange={(e) => setContent(e.target.value)}
|
||||||
onFocus={() => setIsExpanded(true)}
|
onFocus={() => setIsExpanded(true)}
|
||||||
placeholder="Ne düşünüyorsunuz?"
|
placeholder={translate('::App.Platform.Intranet.SocialWall.CreatePost.Placeholder')}
|
||||||
className={classNames(
|
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',
|
'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]'
|
isExpanded ? 'min-h-[120px]' : 'min-h-[48px]'
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
import { FaExternalLinkAlt, FaMapMarkerAlt } from 'react-icons/fa'
|
import { FaExternalLinkAlt, FaMapMarkerAlt } from 'react-icons/fa'
|
||||||
|
|
||||||
interface LocationData {
|
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}`
|
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 (
|
return (
|
||||||
<div className={`relative rounded-lg overflow-hidden bg-gray-200 dark:bg-gray-700 ${className}`}>
|
<div className={`relative rounded-lg overflow-hidden bg-gray-200 dark:bg-gray-700 ${className}`}>
|
||||||
{/* Map Container */}
|
{/* Map Container */}
|
||||||
|
|
@ -76,9 +78,9 @@ const LocationMap: React.FC<LocationMapProps> = ({
|
||||||
<button
|
<button
|
||||||
onClick={handleOpenGoogleMaps}
|
onClick={handleOpenGoogleMaps}
|
||||||
className="absolute inset-0 w-full h-full cursor-pointer group"
|
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>
|
</button>
|
||||||
|
|
||||||
{/* Hover Effect */}
|
{/* 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"
|
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" />
|
<FaExternalLinkAlt className="w-5 h-5" />
|
||||||
<span>Google Maps'te Aç</span>
|
<span>{translate('::App.Platform.Intranet.SocialWall.LocationMap.OpenInGoogleMaps')}</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">
|
||||||
Yol tarifi almak için tıklayın
|
{translate('::App.Platform.Intranet.SocialWall.LocationMap.ClickForDirections')}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import React, { useState, useEffect, useRef } from 'react'
|
import React, { useState, useEffect, useRef } from 'react'
|
||||||
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
import { motion } from 'framer-motion'
|
import { motion } from 'framer-motion'
|
||||||
import { FaTimes, FaSearch, FaMapMarkerAlt } from 'react-icons/fa'
|
import { FaTimes, FaSearch, FaMapMarkerAlt } from 'react-icons/fa'
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
|
|
@ -28,6 +29,7 @@ declare global {
|
||||||
}
|
}
|
||||||
|
|
||||||
const LocationPicker: React.FC<LocationPickerProps> = ({ onSelect, onClose }) => {
|
const LocationPicker: React.FC<LocationPickerProps> = ({ onSelect, onClose }) => {
|
||||||
|
const { translate } = useLocalization();
|
||||||
const [searchQuery, setSearchQuery] = useState('')
|
const [searchQuery, setSearchQuery] = useState('')
|
||||||
const [locations, setLocations] = useState<LocationData[]>([])
|
const [locations, setLocations] = useState<LocationData[]>([])
|
||||||
const [selectedLocation, setSelectedLocation] = useState<LocationData | null>(null)
|
const [selectedLocation, setSelectedLocation] = useState<LocationData | null>(null)
|
||||||
|
|
@ -55,7 +57,7 @@ const LocationPicker: React.FC<LocationPickerProps> = ({ onSelect, onClose }) =>
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!GOOGLE_API_KEY) {
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -92,7 +94,7 @@ const LocationPicker: React.FC<LocationPickerProps> = ({ onSelect, onClose }) =>
|
||||||
}
|
}
|
||||||
|
|
||||||
script.onerror = () => {
|
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)
|
document.head.appendChild(script)
|
||||||
|
|
@ -142,7 +144,7 @@ const LocationPicker: React.FC<LocationPickerProps> = ({ onSelect, onClose }) =>
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status !== window.google.maps.places.PlacesServiceStatus.OK) {
|
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)
|
setIsLoading(false)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -189,7 +191,7 @@ const LocationPicker: React.FC<LocationPickerProps> = ({ onSelect, onClose }) =>
|
||||||
)
|
)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Location search error:', 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)
|
setIsLoading(false)
|
||||||
}
|
}
|
||||||
}, 500) // 500ms debounce
|
}, 500) // 500ms debounce
|
||||||
|
|
@ -222,7 +224,7 @@ const LocationPicker: React.FC<LocationPickerProps> = ({ onSelect, onClose }) =>
|
||||||
>
|
>
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="flex items-center justify-between p-4 border-b border-gray-200 dark:border-gray-700">
|
<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
|
<button
|
||||||
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"
|
||||||
|
|
@ -240,14 +242,14 @@ const LocationPicker: React.FC<LocationPickerProps> = ({ onSelect, onClose }) =>
|
||||||
type="text"
|
type="text"
|
||||||
value={searchQuery}
|
value={searchQuery}
|
||||||
onChange={(e) => setSearchQuery(e.target.value)}
|
onChange={(e) => setSearchQuery(e.target.value)}
|
||||||
placeholder="Konum ara..."
|
placeholder={translate('::App.Platform.Intranet.SocialWall.LocationPicker.SearchPlaceholder')}
|
||||||
disabled={!isGoogleLoaded}
|
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"
|
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>
|
</div>
|
||||||
{!isGoogleLoaded && (
|
{!isGoogleLoaded && (
|
||||||
<p className="text-xs text-gray-500 dark:text-gray-400 mt-2">
|
<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>
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -257,12 +259,12 @@ const LocationPicker: React.FC<LocationPickerProps> = ({ onSelect, onClose }) =>
|
||||||
{!isGoogleLoaded ? (
|
{!isGoogleLoaded ? (
|
||||||
<div className="text-center py-12">
|
<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>
|
<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>
|
</div>
|
||||||
) : isLoading ? (
|
) : isLoading ? (
|
||||||
<div className="text-center py-12">
|
<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>
|
<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>
|
</div>
|
||||||
) : error ? (
|
) : error ? (
|
||||||
<div className="text-center py-12">
|
<div className="text-center py-12">
|
||||||
|
|
@ -273,17 +275,17 @@ const LocationPicker: React.FC<LocationPickerProps> = ({ onSelect, onClose }) =>
|
||||||
<div className="text-center py-12">
|
<div className="text-center py-12">
|
||||||
<FaSearch 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
|
{translate('::App.Platform.Intranet.SocialWall.LocationPicker.TypeToSearch')}
|
||||||
</p>
|
</p>
|
||||||
<p className="text-sm text-gray-400 dark:text-gray-500 mt-2">
|
<p className="text-sm text-gray-400 dark:text-gray-500 mt-2">
|
||||||
Örn: Taksim, İstanbul
|
{translate('::App.Platform.Intranet.SocialWall.LocationPicker.Example')}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
) : locations.length === 0 ? (
|
) : locations.length === 0 ? (
|
||||||
<div className="text-center py-12">
|
<div className="text-center py-12">
|
||||||
<FaMapMarkerAlt 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.
|
{translate('::App.Platform.Intranet.SocialWall.LocationPicker.NotFound')}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
|
|
@ -359,7 +361,7 @@ const LocationPicker: React.FC<LocationPickerProps> = ({ onSelect, onClose }) =>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
) : (
|
) : (
|
||||||
<span>Bir konum seçin</span>
|
<span>{translate('::App.Platform.Intranet.SocialWall.LocationPicker.SelectLocation')}</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
|
|
@ -367,14 +369,14 @@ const LocationPicker: React.FC<LocationPickerProps> = ({ onSelect, onClose }) =>
|
||||||
onClick={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"
|
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>
|
||||||
<button
|
<button
|
||||||
onClick={handleConfirm}
|
onClick={handleConfirm}
|
||||||
disabled={!selectedLocation}
|
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"
|
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>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import React, { useState } from 'react'
|
import React, { useState } from 'react'
|
||||||
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
import { motion } from 'framer-motion'
|
import { motion } from 'framer-motion'
|
||||||
import { FaTimes, FaLink, FaUpload } from 'react-icons/fa'
|
import { FaTimes, FaLink, FaUpload } from 'react-icons/fa'
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
|
|
@ -11,6 +12,7 @@ interface MediaManagerProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
const MediaManager: React.FC<MediaManagerProps> = ({ media, onChange, onClose }) => {
|
const MediaManager: React.FC<MediaManagerProps> = ({ media, onChange, onClose }) => {
|
||||||
|
const { translate } = useLocalization();
|
||||||
const [activeTab, setActiveTab] = useState<'upload' | 'url'>('upload')
|
const [activeTab, setActiveTab] = useState<'upload' | 'url'>('upload')
|
||||||
const [urlInput, setUrlInput] = useState('')
|
const [urlInput, setUrlInput] = useState('')
|
||||||
const [mediaType, setMediaType] = useState<'image' | 'video'>('image')
|
const [mediaType, setMediaType] = useState<'image' | 'video'>('image')
|
||||||
|
|
@ -58,7 +60,7 @@ const MediaManager: React.FC<MediaManagerProps> = ({ media, onChange, onClose })
|
||||||
>
|
>
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="flex items-center justify-between p-4 border-b border-gray-200 dark:border-gray-700">
|
<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
|
<button
|
||||||
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"
|
||||||
|
|
@ -80,7 +82,7 @@ const MediaManager: React.FC<MediaManagerProps> = ({ media, onChange, onClose })
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<FaUpload className="w-5 h-5" />
|
<FaUpload className="w-5 h-5" />
|
||||||
<span>Bilgisayarımdan Seç</span>
|
<span>{translate('::App.Platform.Intranet.SocialWall.MediaManager.SelectFromComputer')}</span>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
|
|
@ -94,7 +96,7 @@ const MediaManager: React.FC<MediaManagerProps> = ({ media, onChange, onClose })
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<FaLink className="w-5 h-5" />
|
<FaLink className="w-5 h-5" />
|
||||||
<span>URL ile Ekle</span>
|
<span>{translate('::App.Platform.Intranet.SocialWall.MediaManager.AddByUrl')}</span>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</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">
|
<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" />
|
<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
|
{translate('::App.Platform.Intranet.SocialWall.MediaManager.ClickToSelectFile')}
|
||||||
</p>
|
</p>
|
||||||
<p className="text-sm text-gray-500 dark:text-gray-400">
|
<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>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<input
|
<input
|
||||||
|
|
@ -126,7 +128,7 @@ const MediaManager: React.FC<MediaManagerProps> = ({ media, onChange, onClose })
|
||||||
<div>
|
<div>
|
||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
<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>
|
</label>
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<button
|
<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'
|
: '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>
|
||||||
<button
|
<button
|
||||||
onClick={() => setMediaType('video')}
|
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'
|
: '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>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -159,7 +161,7 @@ const MediaManager: React.FC<MediaManagerProps> = ({ media, onChange, onClose })
|
||||||
value={urlInput}
|
value={urlInput}
|
||||||
onChange={(e) => setUrlInput(e.target.value)}
|
onChange={(e) => setUrlInput(e.target.value)}
|
||||||
onKeyPress={(e) => e.key === 'Enter' && handleUrlAdd()}
|
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"
|
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
|
<button
|
||||||
|
|
@ -167,7 +169,7 @@ const MediaManager: React.FC<MediaManagerProps> = ({ media, onChange, onClose })
|
||||||
disabled={!urlInput.trim()}
|
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"
|
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>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -177,7 +179,7 @@ const MediaManager: React.FC<MediaManagerProps> = ({ media, onChange, onClose })
|
||||||
{media.length > 0 && (
|
{media.length > 0 && (
|
||||||
<div className="mt-6">
|
<div className="mt-6">
|
||||||
<h3 className="text-sm font-medium text-gray-700 dark:text-gray-300 mb-3">
|
<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>
|
</h3>
|
||||||
<div className="grid grid-cols-4 gap-3">
|
<div className="grid grid-cols-4 gap-3">
|
||||||
{media.map((item) => (
|
{media.map((item) => (
|
||||||
|
|
@ -205,7 +207,7 @@ const MediaManager: React.FC<MediaManagerProps> = ({ media, onChange, onClose })
|
||||||
<FaTimes 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' ? translate('::App.Platform.Intranet.SocialWall.MediaManager.ImageIcon') : translate('::App.Platform.Intranet.SocialWall.MediaManager.VideoIcon')}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|
@ -220,14 +222,14 @@ const MediaManager: React.FC<MediaManagerProps> = ({ media, onChange, onClose })
|
||||||
onClick={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"
|
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>
|
||||||
<button
|
<button
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
disabled={media.length === 0}
|
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"
|
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>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import React, { useState, useRef, useEffect } from 'react'
|
import React, { useState, useRef, useEffect } from 'react'
|
||||||
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
import { motion, AnimatePresence } from 'framer-motion'
|
import { motion, AnimatePresence } from 'framer-motion'
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
|
|
@ -28,6 +29,7 @@ interface PostItemProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
const PostItem: React.FC<PostItemProps> = ({ post, onLike, onComment, onDelete, onVote }) => {
|
const PostItem: React.FC<PostItemProps> = ({ post, onLike, onComment, onDelete, onVote }) => {
|
||||||
|
const { translate } = useLocalization();
|
||||||
const [showComments, setShowComments] = useState(false)
|
const [showComments, setShowComments] = useState(false)
|
||||||
const [commentText, setCommentText] = useState('')
|
const [commentText, setCommentText] = useState('')
|
||||||
const [showAllImages, setShowAllImages] = useState(false)
|
const [showAllImages, setShowAllImages] = useState(false)
|
||||||
|
|
@ -269,7 +271,7 @@ const PostItem: React.FC<PostItemProps> = ({ post, onLike, onComment, onDelete,
|
||||||
id: post.employee.id,
|
id: post.employee.id,
|
||||||
name: post.employee.name,
|
name: post.employee.name,
|
||||||
avatar: post.employee.avatar || 'https://i.pravatar.cc/150?img=1',
|
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,
|
email: post.employee.email,
|
||||||
phoneNumber: post.employee.phoneNumber,
|
phoneNumber: post.employee.phoneNumber,
|
||||||
department: post.employee.department?.name,
|
department: post.employee.department?.name,
|
||||||
|
|
@ -285,7 +287,7 @@ const PostItem: React.FC<PostItemProps> = ({ post, onLike, onComment, onDelete,
|
||||||
{post.employee.name}
|
{post.employee.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.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>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -293,7 +295,7 @@ const PostItem: React.FC<PostItemProps> = ({ post, onLike, onComment, onDelete,
|
||||||
<button
|
<button
|
||||||
onClick={() => onDelete(post.id)}
|
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"
|
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" />
|
<FaTrash className="w-5 h-5" />
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -357,7 +359,7 @@ const PostItem: React.FC<PostItemProps> = ({ post, onLike, onComment, onDelete,
|
||||||
type="text"
|
type="text"
|
||||||
value={commentText}
|
value={commentText}
|
||||||
onChange={(e) => setCommentText(e.target.value)}
|
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"
|
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
|
<button
|
||||||
|
|
@ -391,7 +393,7 @@ const PostItem: React.FC<PostItemProps> = ({ post, onLike, onComment, onDelete,
|
||||||
id: comment.creator.id,
|
id: comment.creator.id,
|
||||||
name: comment.creator.name,
|
name: comment.creator.name,
|
||||||
avatar: comment.creator.avatar || 'https://i.pravatar.cc/150?img=1',
|
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"
|
position="bottom"
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
import { motion } from 'framer-motion'
|
import { motion } from 'framer-motion'
|
||||||
import { FaTimes, FaEye, FaClipboard } from 'react-icons/fa'
|
import { FaTimes, FaEye, FaClipboard } from 'react-icons/fa'
|
||||||
import dayjs from 'dayjs'
|
|
||||||
import { AnnouncementDto } from '@/proxy/intranet/models'
|
import { AnnouncementDto } from '@/proxy/intranet/models'
|
||||||
import useLocale from '@/utils/hooks/useLocale'
|
import useLocale from '@/utils/hooks/useLocale'
|
||||||
import { currentLocalDate } from '@/utils/dateUtils'
|
import { currentLocalDate } from '@/utils/dateUtils'
|
||||||
|
|
@ -12,6 +12,7 @@ interface AnnouncementDetailModalProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
const AnnouncementDetailModal: React.FC<AnnouncementDetailModalProps> = ({ announcement, onClose }) => {
|
const AnnouncementDetailModal: React.FC<AnnouncementDetailModalProps> = ({ announcement, onClose }) => {
|
||||||
|
const { translate } = useLocalization();
|
||||||
const currentLocale = useLocale()
|
const currentLocale = useLocale()
|
||||||
const getCategoryColor = (category: string) => {
|
const getCategoryColor = (category: string) => {
|
||||||
const colors: Record<string, string> = {
|
const colors: Record<string, string> = {
|
||||||
|
|
@ -49,14 +50,14 @@ const AnnouncementDetailModal: React.FC<AnnouncementDetailModalProps> = ({ annou
|
||||||
<span
|
<span
|
||||||
className={`px-3 py-1 text-xs font-medium rounded-full ${getCategoryColor(announcement.category)}`}
|
className={`px-3 py-1 text-xs font-medium rounded-full ${getCategoryColor(announcement.category)}`}
|
||||||
>
|
>
|
||||||
{announcement.category === 'general' && '📢 Genel'}
|
{announcement.category === 'general' && `📢 ${translate('::App.Platform.Intranet.AnnouncementDetailModal.Category.General')}`}
|
||||||
{announcement.category === 'hr' && '👥 İnsan Kaynakları'}
|
{announcement.category === 'hr' && `👥 ${translate('::App.Platform.Intranet.AnnouncementDetailModal.Category.HR')}`}
|
||||||
{announcement.category === 'it' && '💻 Bilgi Teknolojileri'}
|
{announcement.category === 'it' && `💻 ${translate('::App.Platform.Intranet.AnnouncementDetailModal.Category.IT')}`}
|
||||||
{announcement.category === 'event' && '🎉 Etkinlik'}
|
{announcement.category === 'event' && `🎉 ${translate('::App.Platform.Intranet.AnnouncementDetailModal.Category.Event')}`}
|
||||||
{announcement.category === 'urgent' && '🚨 Acil'}
|
{announcement.category === 'urgent' && `🚨 ${translate('::App.Platform.Intranet.AnnouncementDetailModal.Category.Urgent')}`}
|
||||||
</span>
|
</span>
|
||||||
{announcement.isPinned && (
|
{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>
|
</div>
|
||||||
<h2 className="text-2xl font-bold text-gray-900 dark:text-white">
|
<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>•</span>
|
||||||
<span className="flex items-center gap-1">
|
<span className="flex items-center gap-1">
|
||||||
<FaEye className="w-4 h-4" />
|
<FaEye className="w-4 h-4" />
|
||||||
{announcement.viewCount} görüntülenme
|
{announcement.viewCount} {translate('::App.Platform.Intranet.AnnouncementDetailModal.Views')}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</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">
|
<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">
|
<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" />
|
<FaClipboard className="w-5 h-5" />
|
||||||
Ekler ({announcement.attachments.length})
|
{translate('::App.Platform.Intranet.AnnouncementDetailModal.Attachments')} ({announcement.attachments.length})
|
||||||
</h3>
|
</h3>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
{announcement.attachments.map((attachment, idx) => (
|
{announcement.attachments.map((attachment, idx) => (
|
||||||
|
|
@ -141,7 +142,7 @@ const AnnouncementDetailModal: React.FC<AnnouncementDetailModalProps> = ({ annou
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<span className="text-sm text-blue-600 dark:text-blue-400">
|
<span className="text-sm text-blue-600 dark:text-blue-400">
|
||||||
İndir
|
{translate('::App.Platform.Intranet.AnnouncementDetailModal.Download')}
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
))}
|
))}
|
||||||
|
|
@ -154,7 +155,7 @@ const AnnouncementDetailModal: React.FC<AnnouncementDetailModalProps> = ({ annou
|
||||||
announcement.departments.length > 0 && (
|
announcement.departments.length > 0 && (
|
||||||
<div className="mt-6 pt-6 border-t border-gray-200 dark:border-gray-700">
|
<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">
|
<h3 className="text-sm font-semibold text-gray-900 dark:text-white mb-3">
|
||||||
Hedef Departmanlar
|
{translate('::App.Platform.Intranet.AnnouncementDetailModal.TargetDepartments')}
|
||||||
</h3>
|
</h3>
|
||||||
<div className="flex flex-wrap gap-2">
|
<div className="flex flex-wrap gap-2">
|
||||||
{announcement.departments?.map((dept, idx) => (
|
{announcement.departments?.map((dept, idx) => (
|
||||||
|
|
@ -173,7 +174,7 @@ const AnnouncementDetailModal: React.FC<AnnouncementDetailModalProps> = ({ annou
|
||||||
{announcement.expiryDate && (
|
{announcement.expiryDate && (
|
||||||
<div className="mt-6 pt-6 border-t border-gray-200 dark:border-gray-700">
|
<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">
|
<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')}
|
{currentLocalDate(announcement.expiryDate, currentLocale || 'tr')}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -186,7 +187,7 @@ const AnnouncementDetailModal: React.FC<AnnouncementDetailModalProps> = ({ annou
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
className="w-full px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg transition-colors"
|
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>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
import { motion } from 'framer-motion'
|
import { motion } from 'framer-motion'
|
||||||
import { FaTimes } from 'react-icons/fa'
|
import { FaTimes } from 'react-icons/fa'
|
||||||
|
|
||||||
|
|
@ -8,6 +9,7 @@ interface ExpenseRequestModalProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
const ExpenseRequestModal: React.FC<ExpenseRequestModalProps> = ({ onClose, onSubmit }) => {
|
const ExpenseRequestModal: React.FC<ExpenseRequestModalProps> = ({ onClose, onSubmit }) => {
|
||||||
|
const { translate } = useLocalization();
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<motion.div
|
<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">
|
<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">
|
<h2 className="text-xl font-semibold text-gray-900 dark:text-white">
|
||||||
Yeni Harcama Talebi
|
{translate('::App.Platform.Intranet.ExpenseRequestModal.Title')}
|
||||||
</h2>
|
</h2>
|
||||||
<button
|
<button
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
|
|
@ -46,29 +48,29 @@ 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">
|
<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>
|
</label>
|
||||||
<select
|
<select
|
||||||
required
|
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"
|
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="">{translate('::App.Platform.Intranet.ExpenseRequestModal.Select')}</option>
|
||||||
<option value="travel">✈️ Seyahat</option>
|
<option value="travel">✈️ {translate('::App.Platform.Intranet.ExpenseRequestModal.Travel')}</option>
|
||||||
<option value="meal">🍽️ Yemek</option>
|
<option value="meal">🍽️ {translate('::App.Platform.Intranet.ExpenseRequestModal.Meal')}</option>
|
||||||
<option value="accommodation">🏨 Konaklama</option>
|
<option value="accommodation">🏨 {translate('::App.Platform.Intranet.ExpenseRequestModal.Accommodation')}</option>
|
||||||
<option value="transport">🚗 Ulaşım</option>
|
<option value="transport">🚗 {translate('::App.Platform.Intranet.ExpenseRequestModal.Transport')}</option>
|
||||||
<option value="other">📋 Diğer</option>
|
<option value="other">📋 {translate('::App.Platform.Intranet.ExpenseRequestModal.Other')}</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
<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>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
required
|
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"
|
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>
|
||||||
|
|
@ -76,7 +78,7 @@ const ExpenseRequestModal: React.FC<ExpenseRequestModalProps> = ({ onClose, onSu
|
||||||
<div className="grid grid-cols-2 gap-4">
|
<div className="grid grid-cols-2 gap-4">
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||||
Tutar (₺) *
|
{translate('::App.Platform.Intranet.ExpenseRequestModal.Amount')}
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
|
|
@ -89,7 +91,7 @@ const ExpenseRequestModal: React.FC<ExpenseRequestModalProps> = ({ onClose, onSu
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||||
Tarih *
|
{translate('::App.Platform.Intranet.ExpenseRequestModal.Date')}
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="date"
|
type="date"
|
||||||
|
|
@ -101,11 +103,11 @@ 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">
|
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||||
Not
|
{translate('::App.Platform.Intranet.ExpenseRequestModal.Note')}
|
||||||
</label>
|
</label>
|
||||||
<textarea
|
<textarea
|
||||||
rows={3}
|
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"
|
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>
|
||||||
|
|
@ -116,13 +118,13 @@ const ExpenseRequestModal: React.FC<ExpenseRequestModalProps> = ({ onClose, onSu
|
||||||
onClick={onClose}
|
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"
|
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>
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
className="flex-1 px-4 py-2 bg-emerald-600 hover:bg-emerald-700 text-white rounded-lg transition-colors"
|
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>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
import { motion } from 'framer-motion'
|
import { motion } from 'framer-motion'
|
||||||
import { FaTimes } from 'react-icons/fa'
|
import { FaTimes } from 'react-icons/fa'
|
||||||
|
|
||||||
|
|
@ -8,6 +9,7 @@ interface LeaveRequestModalProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
const LeaveRequestModal: React.FC<LeaveRequestModalProps> = ({ onClose, onSubmit }) => {
|
const LeaveRequestModal: React.FC<LeaveRequestModalProps> = ({ onClose, onSubmit }) => {
|
||||||
|
const { translate } = useLocalization();
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<motion.div
|
<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">
|
<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">
|
<h2 className="text-xl font-semibold text-gray-900 dark:text-white">
|
||||||
Yeni İzin Talebi
|
{translate('::App.Platform.Intranet.LeaveRequestModal.Title')}
|
||||||
</h2>
|
</h2>
|
||||||
<button
|
<button
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
|
|
@ -46,24 +48,24 @@ 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">
|
<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>
|
</label>
|
||||||
<select
|
<select
|
||||||
required
|
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"
|
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="">{translate('::App.Platform.Intranet.LeaveRequestModal.Select')}</option>
|
||||||
<option value="annual">🏖️ Yıllık İzin</option>
|
<option value="annual">🏖️ {translate('::App.Platform.Intranet.LeaveRequestModal.AnnualLeave')}</option>
|
||||||
<option value="sick">🏥 Hastalık İzni</option>
|
<option value="sick">🏥 {translate('::App.Platform.Intranet.LeaveRequestModal.SickLeave')}</option>
|
||||||
<option value="unpaid">💼 Ücretsiz İzin</option>
|
<option value="unpaid">💼 {translate('::App.Platform.Intranet.LeaveRequestModal.UnpaidLeave')}</option>
|
||||||
<option value="other">📋 Diğer</option>
|
<option value="other">📋 {translate('::App.Platform.Intranet.LeaveRequestModal.Other')}</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid grid-cols-2 gap-4">
|
<div className="grid grid-cols-2 gap-4">
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
<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>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="date"
|
type="date"
|
||||||
|
|
@ -73,7 +75,7 @@ const LeaveRequestModal: React.FC<LeaveRequestModalProps> = ({ onClose, onSubmit
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
<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>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="date"
|
type="date"
|
||||||
|
|
@ -85,12 +87,12 @@ 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">
|
<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>
|
</label>
|
||||||
<textarea
|
<textarea
|
||||||
required
|
required
|
||||||
rows={3}
|
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"
|
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>
|
||||||
|
|
@ -101,13 +103,13 @@ const LeaveRequestModal: React.FC<LeaveRequestModalProps> = ({ onClose, onSubmit
|
||||||
onClick={onClose}
|
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"
|
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>
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
className="flex-1 px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg transition-colors"
|
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>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
import { motion } from 'framer-motion'
|
import { motion } from 'framer-motion'
|
||||||
import { FaTimes } from 'react-icons/fa'
|
import { FaTimes } from 'react-icons/fa'
|
||||||
|
|
||||||
|
|
@ -8,6 +9,7 @@ interface OvertimeRequestModalProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
const OvertimeRequestModal: React.FC<OvertimeRequestModalProps> = ({ onClose, onSubmit }) => {
|
const OvertimeRequestModal: React.FC<OvertimeRequestModalProps> = ({ onClose, onSubmit }) => {
|
||||||
|
const { translate } = useLocalization();
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<motion.div
|
<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">
|
<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">
|
<h2 className="text-xl font-semibold text-gray-900 dark:text-white">
|
||||||
Yeni Mesai Talebi
|
{translate('::App.Platform.Intranet.OvertimeRequestModal.Title')}
|
||||||
</h2>
|
</h2>
|
||||||
<button
|
<button
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
|
|
@ -46,7 +48,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">
|
<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>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="date"
|
type="date"
|
||||||
|
|
@ -58,7 +60,7 @@ const OvertimeRequestModal: React.FC<OvertimeRequestModalProps> = ({ onClose, on
|
||||||
<div className="grid grid-cols-2 gap-4">
|
<div className="grid grid-cols-2 gap-4">
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
<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>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="time"
|
type="time"
|
||||||
|
|
@ -68,7 +70,7 @@ const OvertimeRequestModal: React.FC<OvertimeRequestModalProps> = ({ onClose, on
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
<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>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="time"
|
type="time"
|
||||||
|
|
@ -80,12 +82,12 @@ 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">
|
<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>
|
</label>
|
||||||
<textarea
|
<textarea
|
||||||
required
|
required
|
||||||
rows={3}
|
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"
|
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>
|
||||||
|
|
@ -96,13 +98,13 @@ const OvertimeRequestModal: React.FC<OvertimeRequestModalProps> = ({ onClose, on
|
||||||
onClick={onClose}
|
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"
|
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>
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
className="flex-1 px-4 py-2 bg-orange-600 hover:bg-orange-700 text-white rounded-lg transition-colors"
|
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>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
import { motion } from 'framer-motion'
|
import { motion } from 'framer-motion'
|
||||||
import { FaTimes } from 'react-icons/fa'
|
import { FaTimes } from 'react-icons/fa'
|
||||||
|
|
||||||
|
|
@ -8,6 +9,7 @@ interface ReservationRequestModalProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
const ReservationRequestModal: React.FC<ReservationRequestModalProps> = ({ onClose, onSubmit }) => {
|
const ReservationRequestModal: React.FC<ReservationRequestModalProps> = ({ onClose, onSubmit }) => {
|
||||||
|
const { translate } = useLocalization();
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<motion.div
|
<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">
|
<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">
|
<h2 className="text-xl font-semibold text-gray-900 dark:text-white">
|
||||||
Yeni Rezervasyon Talebi
|
{translate('::App.Platform.Intranet.ReservationRequestModal.Title')}
|
||||||
</h2>
|
</h2>
|
||||||
<button
|
<button
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
|
|
@ -46,27 +48,27 @@ const ReservationRequestModal: React.FC<ReservationRequestModalProps> = ({ onClo
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
<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>
|
</label>
|
||||||
<select
|
<select
|
||||||
required
|
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"
|
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="">{translate('::App.Platform.Intranet.ReservationRequestModal.Select')}</option>
|
||||||
<option value="room">🏢 Toplantı Odası</option>
|
<option value="room">🏢 {translate('::App.Platform.Intranet.ReservationRequestModal.Room')}</option>
|
||||||
<option value="vehicle">🚗 Şirket Aracı</option>
|
<option value="vehicle">🚗 {translate('::App.Platform.Intranet.ReservationRequestModal.Vehicle')}</option>
|
||||||
<option value="equipment">⚙️ Ekipman</option>
|
<option value="equipment">⚙️ {translate('::App.Platform.Intranet.ReservationRequestModal.Equipment')}</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
<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>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
required
|
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"
|
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>
|
||||||
|
|
@ -74,7 +76,7 @@ const ReservationRequestModal: React.FC<ReservationRequestModalProps> = ({ onClo
|
||||||
<div className="grid grid-cols-2 gap-4">
|
<div className="grid grid-cols-2 gap-4">
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
<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>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="datetime-local"
|
type="datetime-local"
|
||||||
|
|
@ -84,7 +86,7 @@ const ReservationRequestModal: React.FC<ReservationRequestModalProps> = ({ onClo
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
<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>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="datetime-local"
|
type="datetime-local"
|
||||||
|
|
@ -96,42 +98,42 @@ const ReservationRequestModal: React.FC<ReservationRequestModalProps> = ({ onClo
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||||
Amaç *
|
{translate('::App.Platform.Intranet.ReservationRequestModal.Purpose')}
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
required
|
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"
|
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>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
<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>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
min="1"
|
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"
|
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>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||||
Notlar
|
{translate('::App.Platform.Intranet.ReservationRequestModal.Notes')}
|
||||||
</label>
|
</label>
|
||||||
<textarea
|
<textarea
|
||||||
rows={3}
|
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"
|
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>
|
||||||
|
|
||||||
<div className="bg-blue-50 dark:bg-blue-900/20 rounded-lg p-3">
|
<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">
|
<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>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -141,13 +143,13 @@ const ReservationRequestModal: React.FC<ReservationRequestModalProps> = ({ onClo
|
||||||
onClick={onClose}
|
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"
|
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>
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
className="flex-1 px-4 py-2 bg-green-600 hover:bg-green-700 text-white rounded-lg transition-colors"
|
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>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,9 @@ interface SurveyModalProps {
|
||||||
onSubmit: (answers: SurveyAnswerDto[]) => void
|
onSubmit: (answers: SurveyAnswerDto[]) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
const SurveyModal: React.FC<SurveyModalProps> = ({ survey, onClose, onSubmit }) => {
|
const SurveyModal: React.FC<SurveyModalProps> = ({ survey, onClose, onSubmit }) => {
|
||||||
|
const { translate } = useLocalization();
|
||||||
const [answers, setAnswers] = useState<{ [questionId: string]: any }>({})
|
const [answers, setAnswers] = useState<{ [questionId: string]: any }>({})
|
||||||
const [errors, setErrors] = useState<{ [questionId: string]: string }>({})
|
const [errors, setErrors] = useState<{ [questionId: string]: string }>({})
|
||||||
|
|
||||||
|
|
@ -33,7 +35,7 @@ const SurveyModal: React.FC<SurveyModalProps> = ({ survey, onClose, onSubmit })
|
||||||
|
|
||||||
survey.questions.forEach((question) => {
|
survey.questions.forEach((question) => {
|
||||||
if (question.isRequired && (!answers[question.id] || answers[question.id] === '')) {
|
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 ${
|
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'
|
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 && (
|
{hasError && (
|
||||||
<p className="text-sm text-red-600 dark:text-red-400">{errors[question.id]}</p>
|
<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 ${
|
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'
|
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 && (
|
{hasError && (
|
||||||
<p className="text-sm text-red-600 dark:text-red-400">{errors[question.id]}</p>
|
<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}
|
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"
|
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>
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
className="flex-1 px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg transition-colors"
|
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>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import { FaKey, FaPlus } from 'react-icons/fa'
|
||||||
import { ReservationDto } from '@/proxy/intranet/models'
|
import { ReservationDto } from '@/proxy/intranet/models'
|
||||||
import useLocale from '@/utils/hooks/useLocale'
|
import useLocale from '@/utils/hooks/useLocale'
|
||||||
import { currentLocalDate } from '@/utils/dateUtils'
|
import { currentLocalDate } from '@/utils/dateUtils'
|
||||||
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
|
|
||||||
interface ActiveReservationsProps {
|
interface ActiveReservationsProps {
|
||||||
reservations: ReservationDto[]
|
reservations: ReservationDto[]
|
||||||
|
|
@ -14,13 +15,14 @@ const ActiveReservations: React.FC<ActiveReservationsProps> = ({
|
||||||
onNewReservation,
|
onNewReservation,
|
||||||
}) => {
|
}) => {
|
||||||
const currentLocale = useLocale()
|
const currentLocale = useLocale()
|
||||||
|
const { translate } = useLocalization()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
|
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
|
||||||
<div className="p-4 border-b border-gray-200 dark:border-gray-700">
|
<div className="p-4 border-b border-gray-200 dark:border-gray-700">
|
||||||
<h2 className="text-lg font-semibold text-gray-900 dark:text-white flex items-center gap-2">
|
<h2 className="text-lg font-semibold text-gray-900 dark:text-white flex items-center gap-2">
|
||||||
<FaKey className="w-5 h-5" />
|
<FaKey className="w-5 h-5" />
|
||||||
Aktif Rezervasyonlar
|
{translate('::App.Platform.Intranet.Widgets.ActiveReservations.Title')}
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-4 space-y-3">
|
<div className="p-4 space-y-3">
|
||||||
|
|
@ -52,7 +54,7 @@ const ActiveReservations: React.FC<ActiveReservationsProps> = ({
|
||||||
))}
|
))}
|
||||||
{reservations.filter((r) => r.status === 'approved').length === 0 && (
|
{reservations.filter((r) => r.status === 'approved').length === 0 && (
|
||||||
<p className="text-sm text-gray-500 dark:text-gray-400 text-center py-4">
|
<p className="text-sm text-gray-500 dark:text-gray-400 text-center py-4">
|
||||||
Aktif rezervasyon yok
|
{translate('::App.Platform.Intranet.Widgets.ActiveReservations.NoActive')}
|
||||||
</p>
|
</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"
|
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" />
|
<FaPlus className="w-4 h-4" />
|
||||||
Yeni Rezervasyon
|
{translate('::App.Platform.Intranet.Widgets.ActiveReservations.NewReservation')}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import dayjs from 'dayjs'
|
||||||
import { SurveyDto } from '@/proxy/intranet/models'
|
import { SurveyDto } from '@/proxy/intranet/models'
|
||||||
import useLocale from '@/utils/hooks/useLocale'
|
import useLocale from '@/utils/hooks/useLocale'
|
||||||
import { currentLocalDate } from '@/utils/dateUtils'
|
import { currentLocalDate } from '@/utils/dateUtils'
|
||||||
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
|
|
||||||
interface ActiveSurveysProps {
|
interface ActiveSurveysProps {
|
||||||
surveys?: SurveyDto[]
|
surveys?: SurveyDto[]
|
||||||
|
|
@ -12,6 +13,7 @@ interface ActiveSurveysProps {
|
||||||
|
|
||||||
const ActiveSurveys: React.FC<ActiveSurveysProps> = ({ surveys, onTakeSurvey }) => {
|
const ActiveSurveys: React.FC<ActiveSurveysProps> = ({ surveys, onTakeSurvey }) => {
|
||||||
const currentLocale = useLocale()
|
const currentLocale = useLocale()
|
||||||
|
const { translate } = useLocalization()
|
||||||
|
|
||||||
return (
|
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">
|
<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">
|
<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">
|
<h2 className="text-lg font-semibold text-gray-900 dark:text-white flex items-center gap-2">
|
||||||
<FaClipboardCheck className="w-5 h-5" />
|
<FaClipboardCheck className="w-5 h-5" />
|
||||||
Aktif Anketler
|
{translate('::App.Platform.Intranet.Widgets.ActiveSurveys.Title')}
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</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'
|
: '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>
|
||||||
</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" />
|
<FaQuestionCircle className="w-3 h-3 text-blue-600 dark:text-blue-400" />
|
||||||
</div>
|
</div>
|
||||||
<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">
|
<p className="font-semibold text-gray-900 dark:text-white">
|
||||||
{survey.questions.length}
|
{survey.questions.length}
|
||||||
</p>
|
</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" />
|
<FaUsers className="w-3 h-3 text-green-600 dark:text-green-400" />
|
||||||
</div>
|
</div>
|
||||||
<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">
|
<p className="font-semibold text-gray-900 dark:text-white">
|
||||||
{survey.responses}
|
{survey.responses}
|
||||||
</p>
|
</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" />
|
<FaClock className="w-3 h-3 text-purple-600 dark:text-purple-400" />
|
||||||
</div>
|
</div>
|
||||||
<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>
|
<p className="font-semibold text-gray-900 dark:text-white">~5dk</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -97,7 +99,7 @@ const ActiveSurveys: React.FC<ActiveSurveysProps> = ({ surveys, onTakeSurvey })
|
||||||
{/* Progress Bar */}
|
{/* Progress Bar */}
|
||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
<div className="flex justify-between text-xs mb-1">
|
<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">
|
<span className="text-gray-800 dark:text-gray-200 font-medium">
|
||||||
{Math.round((survey.responses / 100) * 100)}%
|
{Math.round((survey.responses / 100) * 100)}%
|
||||||
</span>
|
</span>
|
||||||
|
|
@ -118,7 +120,7 @@ const ActiveSurveys: React.FC<ActiveSurveysProps> = ({ surveys, onTakeSurvey })
|
||||||
|
|
||||||
{/* Action Button */}
|
{/* 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">
|
<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" />
|
<FaArrowRight className="w-3 h-3 transition-transform group-hover:translate-x-1" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -132,10 +134,10 @@ const ActiveSurveys: React.FC<ActiveSurveysProps> = ({ surveys, onTakeSurvey })
|
||||||
<FaClipboardCheck className="w-8 h-8 text-gray-400" />
|
<FaClipboardCheck className="w-8 h-8 text-gray-400" />
|
||||||
</div>
|
</div>
|
||||||
<h3 className="text-lg font-medium text-gray-900 dark:text-white mb-2">
|
<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>
|
</h3>
|
||||||
<p className="text-sm text-gray-500 dark:text-gray-400">
|
<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>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import React from 'react'
|
||||||
import { FaBell, FaClipboardCheck, FaEye } from 'react-icons/fa'
|
import { FaBell, FaClipboardCheck, FaEye } from 'react-icons/fa'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import { AnnouncementDto } from '@/proxy/intranet/models'
|
import { AnnouncementDto } from '@/proxy/intranet/models'
|
||||||
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
|
|
||||||
interface AnnouncementsProps {
|
interface AnnouncementsProps {
|
||||||
announcements: AnnouncementDto[]
|
announcements: AnnouncementDto[]
|
||||||
|
|
@ -10,6 +11,7 @@ interface AnnouncementsProps {
|
||||||
|
|
||||||
const Announcements: React.FC<AnnouncementsProps> = ({ announcements, onAnnouncementClick }) => {
|
const Announcements: React.FC<AnnouncementsProps> = ({ announcements, onAnnouncementClick }) => {
|
||||||
const pinnedAnnouncements = announcements.filter((a) => a.isPinned).slice(0, 3)
|
const pinnedAnnouncements = announcements.filter((a) => a.isPinned).slice(0, 3)
|
||||||
|
const { translate } = useLocalization();
|
||||||
|
|
||||||
const getCategoryColor = (category: string) => {
|
const getCategoryColor = (category: string) => {
|
||||||
const colors: Record<string, string> = {
|
const colors: Record<string, string> = {
|
||||||
|
|
@ -28,7 +30,7 @@ const Announcements: React.FC<AnnouncementsProps> = ({ announcements, onAnnounce
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<h2 className="text-lg font-semibold text-gray-900 dark:text-white flex items-center gap-2">
|
<h2 className="text-lg font-semibold text-gray-900 dark:text-white flex items-center gap-2">
|
||||||
<FaBell className="w-5 h-5" />
|
<FaBell className="w-5 h-5" />
|
||||||
Önemli Duyurular
|
{translate('::App.Platform.Intranet.Widgets.Announcements.Title')}
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -53,7 +55,7 @@ const Announcements: React.FC<AnnouncementsProps> = ({ announcements, onAnnounce
|
||||||
<span
|
<span
|
||||||
className={`px-2 py-1 text-xs rounded-full ${getCategoryColor(announcement.category)}`}
|
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>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-sm text-gray-600 dark:text-gray-400 line-clamp-2">
|
<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" />
|
<FaClipboardCheck className="w-8 h-8 text-gray-400" />
|
||||||
</div>
|
</div>
|
||||||
<h3 className="text-lg font-medium text-gray-900 dark:text-white mb-2">
|
<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>
|
</h3>
|
||||||
<p className="text-sm text-gray-500 dark:text-gray-400">
|
<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>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { FaDollarSign, FaPlus } from 'react-icons/fa'
|
import { FaDollarSign, FaPlus } from 'react-icons/fa'
|
||||||
import { ExpensesDto } from '@/proxy/intranet/models'
|
import { ExpensesDto } from '@/proxy/intranet/models'
|
||||||
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
|
|
||||||
interface ExpenseManagementProps {
|
interface ExpenseManagementProps {
|
||||||
expenses: ExpensesDto
|
expenses: ExpensesDto
|
||||||
|
|
@ -8,23 +9,24 @@ interface ExpenseManagementProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
const ExpenseManagement: React.FC<ExpenseManagementProps> = ({ expenses, onNewExpense }) => {
|
const ExpenseManagement: React.FC<ExpenseManagementProps> = ({ expenses, onNewExpense }) => {
|
||||||
|
const { translate } = useLocalization();
|
||||||
return (
|
return (
|
||||||
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
|
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
|
||||||
<div className="p-4 border-b border-gray-200 dark:border-gray-700">
|
<div className="p-4 border-b border-gray-200 dark:border-gray-700">
|
||||||
<h2 className="text-lg font-semibold text-gray-900 dark:text-white flex items-center gap-2">
|
<h2 className="text-lg font-semibold text-gray-900 dark:text-white flex items-center gap-2">
|
||||||
<FaDollarSign className="w-5 h-5" />
|
<FaDollarSign className="w-5 h-5" />
|
||||||
Harcama Yönetimi
|
{translate('::App.Platform.Intranet.Widgets.ExpenseManagement.Title')}
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-4 space-y-3">
|
<div className="p-4 space-y-3">
|
||||||
{/* Harcama özeti */}
|
{/* Harcama özeti */}
|
||||||
<div className="p-3 bg-emerald-50 dark:bg-emerald-900/20 rounded-lg border border-emerald-200 dark:border-emerald-800 mb-4">
|
<div className="p-3 bg-emerald-50 dark:bg-emerald-900/20 rounded-lg border border-emerald-200 dark:border-emerald-800 mb-4">
|
||||||
<p className="text-xs text-gray-600 dark:text-gray-400">Bu Ay Toplam</p>
|
<p className="text-xs text-gray-600 dark:text-gray-400">{translate('::App.Platform.Intranet.Widgets.ExpenseManagement.ThisMonthTotal')}</p>
|
||||||
<p className="text-2xl font-bold text-emerald-600 dark:text-emerald-400">
|
<p className="text-2xl font-bold text-emerald-600 dark:text-emerald-400">
|
||||||
{expenses.totalRequested.toLocaleString('tr-TR')}
|
{expenses.totalRequested.toLocaleString('tr-TR')}
|
||||||
</p>
|
</p>
|
||||||
<p className="text-xs text-gray-500 dark:text-gray-400 mt-1">
|
<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>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -63,10 +65,10 @@ const ExpenseManagement: React.FC<ExpenseManagementProps> = ({ expenses, onNewEx
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{expense.status === 'approved'
|
{expense.status === 'approved'
|
||||||
? 'Onaylandı'
|
? translate('::App.Platform.Intranet.Widgets.ExpenseManagement.Status.Approved')
|
||||||
: expense.status === 'pending'
|
: expense.status === 'pending'
|
||||||
? 'Bekliyor'
|
? translate('::App.Platform.Intranet.Widgets.ExpenseManagement.Status.Pending')
|
||||||
: 'Reddedildi'}
|
: translate('::App.Platform.Intranet.Widgets.ExpenseManagement.Status.Rejected')}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</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"
|
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" />
|
<FaPlus className="w-4 h-4" />
|
||||||
Yeni Harcama Talebi
|
{translate('::App.Platform.Intranet.Widgets.ExpenseManagement.NewExpense')}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import { LeaveDto } from '@/proxy/intranet/models'
|
||||||
import useLocale from '@/utils/hooks/useLocale'
|
import useLocale from '@/utils/hooks/useLocale'
|
||||||
import { currentLocalDate } from '@/utils/dateUtils'
|
import { currentLocalDate } from '@/utils/dateUtils'
|
||||||
import { LeaveStatusEnum, LeaveTypeEnum } from '@/types/intranet'
|
import { LeaveStatusEnum, LeaveTypeEnum } from '@/types/intranet'
|
||||||
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
|
|
||||||
interface LeaveManagementProps {
|
interface LeaveManagementProps {
|
||||||
leaves: LeaveDto[]
|
leaves: LeaveDto[]
|
||||||
|
|
@ -12,25 +13,26 @@ interface LeaveManagementProps {
|
||||||
|
|
||||||
const LeaveManagement: React.FC<LeaveManagementProps> = ({ leaves, onNewLeave }) => {
|
const LeaveManagement: React.FC<LeaveManagementProps> = ({ leaves, onNewLeave }) => {
|
||||||
const currentLocale = useLocale()
|
const currentLocale = useLocale()
|
||||||
|
const { translate } = useLocalization();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
|
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
|
||||||
<div className="p-4 border-b border-gray-200 dark:border-gray-700">
|
<div className="p-4 border-b border-gray-200 dark:border-gray-700">
|
||||||
<h2 className="text-lg font-semibold text-gray-900 dark:text-white flex items-center gap-2">
|
<h2 className="text-lg font-semibold text-gray-900 dark:text-white flex items-center gap-2">
|
||||||
<FaCalendarAlt className="w-5 h-5" />
|
<FaCalendarAlt className="w-5 h-5" />
|
||||||
İzin Yönetimi
|
{translate('::App.Platform.Intranet.Widgets.LeaveManagement.Title')}
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-4 space-y-3">
|
<div className="p-4 space-y-3">
|
||||||
{/* İzin bakiye özeti */}
|
{/* İzin bakiye özeti */}
|
||||||
<div className="grid grid-cols-2 gap-2 mb-4">
|
<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">
|
<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-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 gün</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>
|
||||||
<div className="p-3 bg-green-50 dark:bg-green-900/20 rounded-lg border border-green-200 dark:border-green-800">
|
<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-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 gün</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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -44,13 +46,13 @@ const LeaveManagement: React.FC<LeaveManagementProps> = ({ leaves, onNewLeave })
|
||||||
<div className="flex items-start justify-between mb-1">
|
<div className="flex items-start justify-between mb-1">
|
||||||
<h4 className="text-sm font-medium text-gray-900 dark:text-white">
|
<h4 className="text-sm font-medium text-gray-900 dark:text-white">
|
||||||
{leave.leaveType === LeaveTypeEnum.Annual
|
{leave.leaveType === LeaveTypeEnum.Annual
|
||||||
? '🏖️ Yıllık'
|
? `🏖️ ${translate('::App.Platform.Intranet.Widgets.LeaveManagement.Annual')}`
|
||||||
: leave.leaveType === LeaveTypeEnum.Sick
|
: leave.leaveType === LeaveTypeEnum.Sick
|
||||||
? '🏥 Hastalık'
|
? `🏥 ${translate('::App.Platform.Intranet.Widgets.LeaveManagement.Sick')}`
|
||||||
: leave.leaveType === LeaveTypeEnum.Unpaid
|
: leave.leaveType === LeaveTypeEnum.Unpaid
|
||||||
? '💼 Ücretsiz'
|
? `💼 ${translate('::App.Platform.Intranet.Widgets.LeaveManagement.Unpaid')}`
|
||||||
: '📋 Diğer'}{' '}
|
: `📋 ${translate('::App.Platform.Intranet.Widgets.LeaveManagement.Other')}`}{' '}
|
||||||
İzin
|
{translate('::App.Platform.Intranet.Widgets.LeaveManagement.Leave')}
|
||||||
</h4>
|
</h4>
|
||||||
<span
|
<span
|
||||||
className={`text-xs px-2 py-1 rounded-full ${
|
className={`text-xs px-2 py-1 rounded-full ${
|
||||||
|
|
@ -62,15 +64,15 @@ const LeaveManagement: React.FC<LeaveManagementProps> = ({ leaves, onNewLeave })
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{leave.status === LeaveStatusEnum.Approved
|
{leave.status === LeaveStatusEnum.Approved
|
||||||
? 'Onaylandı'
|
? translate('::App.Platform.Intranet.Widgets.LeaveManagement.Status.Approved')
|
||||||
: leave.status === LeaveStatusEnum.Pending
|
: leave.status === LeaveStatusEnum.Pending
|
||||||
? 'Bekliyor'
|
? translate('::App.Platform.Intranet.Widgets.LeaveManagement.Status.Pending')
|
||||||
: 'Reddedildi'}
|
: translate('::App.Platform.Intranet.Widgets.LeaveManagement.Status.Rejected')}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-xs text-gray-600 dark:text-gray-400">
|
<p className="text-xs text-gray-600 dark:text-gray-400">
|
||||||
{currentLocalDate(leave.startDate, currentLocale || 'tr')} - {currentLocalDate(leave.endDate, currentLocale || 'tr')}{' '}
|
{currentLocalDate(leave.startDate, currentLocale || 'tr')} - {currentLocalDate(leave.endDate, currentLocale || 'tr')}{' '}
|
||||||
({leave.totalDays} gün)
|
({leave.totalDays} {translate('::App.Platform.Intranet.Widgets.LeaveManagement.Day')})
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</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"
|
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" />
|
<FaPlus className="w-4 h-4" />
|
||||||
Yeni İzin Talebi
|
{translate('::App.Platform.Intranet.Widgets.LeaveManagement.NewLeaveRequest')}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -6,11 +6,13 @@ import { Badge } from '@/components/ui'
|
||||||
import { MealDto } from '@/proxy/intranet/models'
|
import { MealDto } from '@/proxy/intranet/models'
|
||||||
import useLocale from '@/utils/hooks/useLocale'
|
import useLocale from '@/utils/hooks/useLocale'
|
||||||
import { currentLocalDate } from '@/utils/dateUtils'
|
import { currentLocalDate } from '@/utils/dateUtils'
|
||||||
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
|
|
||||||
dayjs.extend(isBetween)
|
dayjs.extend(isBetween)
|
||||||
|
|
||||||
const MealWeeklyMenu: React.FC<{ meals: MealDto[] }> = ({ meals }) => {
|
const MealWeeklyMenu: React.FC<{ meals: MealDto[] }> = ({ meals }) => {
|
||||||
const currentLocale = useLocale()
|
const currentLocale = useLocale()
|
||||||
|
const { translate } = useLocalization();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
|
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
|
||||||
|
|
@ -18,7 +20,7 @@ const MealWeeklyMenu: React.FC<{ meals: MealDto[] }> = ({ meals }) => {
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<h2 className="text-lg font-semibold text-gray-900 dark:text-white flex items-center gap-2">
|
<h2 className="text-lg font-semibold text-gray-900 dark:text-white flex items-center gap-2">
|
||||||
<FaUtensils className="w-5 h-5" />
|
<FaUtensils className="w-5 h-5" />
|
||||||
Haftalık Menü
|
{translate('::App.Platform.Intranet.Widgets.MealWeeklyMenu.Title')}
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -40,7 +42,7 @@ const MealWeeklyMenu: React.FC<{ meals: MealDto[] }> = ({ meals }) => {
|
||||||
</h3>
|
</h3>
|
||||||
{isToday && (
|
{isToday && (
|
||||||
<span className="text-xs bg-orange-500 text-white px-2 py-0.5 rounded-full">
|
<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>
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -67,7 +69,7 @@ const MealWeeklyMenu: React.FC<{ meals: MealDto[] }> = ({ meals }) => {
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
<p className="text-xs text-gray-500 dark:text-gray-400">
|
<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>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import { OvertimeDto } from '@/proxy/intranet/models'
|
||||||
import useLocale from '@/utils/hooks/useLocale'
|
import useLocale from '@/utils/hooks/useLocale'
|
||||||
import { currentLocalDate } from '@/utils/dateUtils'
|
import { currentLocalDate } from '@/utils/dateUtils'
|
||||||
import { LeaveStatusEnum } from '@/types/intranet'
|
import { LeaveStatusEnum } from '@/types/intranet'
|
||||||
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
|
|
||||||
interface OvertimeManagementProps {
|
interface OvertimeManagementProps {
|
||||||
overtimes: OvertimeDto[]
|
overtimes: OvertimeDto[]
|
||||||
|
|
@ -12,21 +13,22 @@ interface OvertimeManagementProps {
|
||||||
|
|
||||||
const OvertimeManagement: React.FC<OvertimeManagementProps> = ({ overtimes, onNewOvertime }) => {
|
const OvertimeManagement: React.FC<OvertimeManagementProps> = ({ overtimes, onNewOvertime }) => {
|
||||||
const currentLocale = useLocale()
|
const currentLocale = useLocale()
|
||||||
|
const { translate } = useLocalization();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
|
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
|
||||||
<div className="p-4 border-b border-gray-200 dark:border-gray-700">
|
<div className="p-4 border-b border-gray-200 dark:border-gray-700">
|
||||||
<h2 className="text-lg font-semibold text-gray-900 dark:text-white flex items-center gap-2">
|
<h2 className="text-lg font-semibold text-gray-900 dark:text-white flex items-center gap-2">
|
||||||
<FaClock className="w-5 h-5" />
|
<FaClock className="w-5 h-5" />
|
||||||
Mesai Yönetimi
|
{translate('::App.Platform.Intranet.Widgets.OvertimeManagement.Title')}
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-4 space-y-3">
|
<div className="p-4 space-y-3">
|
||||||
{/* Mesai özeti */}
|
{/* 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">
|
<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-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 saat</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 onaylandı, 4 bekliyor</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>
|
</div>
|
||||||
|
|
||||||
{/* Son mesai talepleri */}
|
{/* Son mesai talepleri */}
|
||||||
|
|
@ -50,10 +52,10 @@ const OvertimeManagement: React.FC<OvertimeManagementProps> = ({ overtimes, onNe
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{overtime.status === LeaveStatusEnum.Approved
|
{overtime.status === LeaveStatusEnum.Approved
|
||||||
? 'Onaylandı'
|
? translate('::App.Platform.Intranet.Widgets.OvertimeManagement.Status.Approved')
|
||||||
: overtime.status === LeaveStatusEnum.Pending
|
: overtime.status === LeaveStatusEnum.Pending
|
||||||
? 'Bekliyor'
|
? translate('::App.Platform.Intranet.Widgets.OvertimeManagement.Status.Pending')
|
||||||
: 'Reddedildi'}
|
: translate('::App.Platform.Intranet.Widgets.OvertimeManagement.Status.Rejected')}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-xs text-gray-600 dark:text-gray-400">
|
<p className="text-xs text-gray-600 dark:text-gray-400">
|
||||||
|
|
@ -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"
|
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" />
|
<FaPlus className="w-4 h-4" />
|
||||||
Yeni Mesai Talebi
|
{translate('::App.Platform.Intranet.Widgets.OvertimeManagement.NewOvertimeRequest')}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { FaChartBar, FaClock, FaUser } from 'react-icons/fa'
|
import { FaChartBar, FaClock, FaUser } from 'react-icons/fa'
|
||||||
import useLocale from '@/utils/hooks/useLocale'
|
import useLocale from '@/utils/hooks/useLocale'
|
||||||
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
import { currentLocalDate } from '@/utils/dateUtils'
|
import { currentLocalDate } from '@/utils/dateUtils'
|
||||||
import { PriorityEnum, TaskStatusEnum } from '@/types/intranet'
|
import { PriorityEnum, TaskStatusEnum } from '@/types/intranet'
|
||||||
import { ProjectTaskDto } from '@/proxy/intranet/models'
|
import { ProjectTaskDto } from '@/proxy/intranet/models'
|
||||||
|
|
@ -11,6 +12,7 @@ interface PriorityTasksProps {
|
||||||
|
|
||||||
const PriorityTasks: React.FC<PriorityTasksProps> = ({ tasks }) => {
|
const PriorityTasks: React.FC<PriorityTasksProps> = ({ tasks }) => {
|
||||||
const currentLocale = useLocale()
|
const currentLocale = useLocale()
|
||||||
|
const { translate } = useLocalization();
|
||||||
|
|
||||||
const getPriorityColor = (priority: PriorityEnum) => {
|
const getPriorityColor = (priority: PriorityEnum) => {
|
||||||
const colors: Record<PriorityEnum, string> = {
|
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">
|
<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">
|
<h2 className="text-lg font-semibold text-gray-900 dark:text-white flex items-center gap-2">
|
||||||
<FaChartBar className="w-5 h-5" />
|
<FaChartBar className="w-5 h-5" />
|
||||||
Öncelikli Görevler
|
{translate('::App.Platform.Intranet.Widgets.PriorityTasks.Title')}
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className="divide-y divide-gray-200 dark:divide-gray-700">
|
<div className="divide-y divide-gray-200 dark:divide-gray-700">
|
||||||
|
|
@ -47,10 +49,10 @@ const PriorityTasks: React.FC<PriorityTasksProps> = ({ tasks }) => {
|
||||||
<span
|
<span
|
||||||
className={`px-2 py-0.5 text-xs rounded ${getPriorityColor(task.priority)}`}
|
className={`px-2 py-0.5 text-xs rounded ${getPriorityColor(task.priority)}`}
|
||||||
>
|
>
|
||||||
{task.priority === PriorityEnum.Urgent && '🔥 Acil'}
|
{task.priority === PriorityEnum.Urgent && translate('::App.Platform.Intranet.Widgets.PriorityTasks.Urgent')}
|
||||||
{task.priority === PriorityEnum.High && 'Yüksek'}
|
{task.priority === PriorityEnum.High && translate('::App.Platform.Intranet.Widgets.PriorityTasks.High')}
|
||||||
{task.priority === PriorityEnum.Normal && 'Orta'}
|
{task.priority === PriorityEnum.Normal && translate('::App.Platform.Intranet.Widgets.PriorityTasks.Normal')}
|
||||||
{task.priority === PriorityEnum.Low && 'Düşük'}
|
{task.priority === PriorityEnum.Low && translate('::App.Platform.Intranet.Widgets.PriorityTasks.Low')}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-xs text-gray-600 dark:text-gray-400 mb-2">{task.description}</p>
|
<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>
|
||||||
<span className="flex items-center gap-1">
|
<span className="flex items-center gap-1">
|
||||||
<FaUser className="w-3 h-3" />
|
<FaUser className="w-3 h-3" />
|
||||||
{task.employee.name || 'Atanmadı'}
|
{task.employee.name || translate('::App.Platform.Intranet.Widgets.PriorityTasks.Unassigned')}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import { FaFileAlt, FaDownload } from 'react-icons/fa'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import { DocumentDto } from '@/proxy/intranet/models'
|
import { DocumentDto } from '@/proxy/intranet/models'
|
||||||
import { getFileIcon, getFileType } from '@/proxy/intranet/utils'
|
import { getFileIcon, getFileType } from '@/proxy/intranet/utils'
|
||||||
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
|
|
||||||
const formatFileSize = (bytes: number): string => {
|
const formatFileSize = (bytes: number): string => {
|
||||||
if (bytes === 0) return '0 B'
|
if (bytes === 0) return '0 B'
|
||||||
|
|
@ -13,13 +14,14 @@ const formatFileSize = (bytes: number): string => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const RecentDocuments: React.FC<{ documents: DocumentDto[] }> = ({ documents }) => {
|
const RecentDocuments: React.FC<{ documents: DocumentDto[] }> = ({ documents }) => {
|
||||||
|
const { translate } = useLocalization();
|
||||||
return (
|
return (
|
||||||
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
|
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
|
||||||
<div className="p-4 border-b border-gray-200 dark:border-gray-700">
|
<div className="p-4 border-b border-gray-200 dark:border-gray-700">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<h2 className="text-lg font-semibold text-gray-900 dark:text-white flex items-center gap-2">
|
<h2 className="text-lg font-semibold text-gray-900 dark:text-white flex items-center gap-2">
|
||||||
<FaFileAlt className="w-5 h-5" />
|
<FaFileAlt className="w-5 h-5" />
|
||||||
Son Dokümanlar
|
{translate('::App.Platform.Intranet.Widgets.RecentDocuments.Title')}
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -48,7 +50,7 @@ const RecentDocuments: React.FC<{ documents: DocumentDto[] }> = ({ documents })
|
||||||
{doc.isReadOnly && (
|
{doc.isReadOnly && (
|
||||||
<>
|
<>
|
||||||
<span>•</span>
|
<span>•</span>
|
||||||
<span className="text-orange-500">🔒 Salt okunur</span>
|
<span className="text-orange-500">🔒 {translate('::App.Platform.Intranet.Widgets.RecentDocuments.ReadOnly')}</span>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -62,7 +64,7 @@ const RecentDocuments: React.FC<{ documents: DocumentDto[] }> = ({ documents })
|
||||||
link.click()
|
link.click()
|
||||||
}}
|
}}
|
||||||
className="p-2 hover:bg-blue-100 dark:hover:bg-blue-900/30 rounded-lg transition-colors group"
|
className="p-2 hover:bg-blue-100 dark:hover:bg-blue-900/30 rounded-lg transition-colors group"
|
||||||
title="İndir"
|
title={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" />
|
<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>
|
</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">
|
<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>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,26 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { FaTruck } from 'react-icons/fa'
|
import { FaTruck } from 'react-icons/fa'
|
||||||
import { ShuttleRouteDto } from '@/proxy/intranet/models'
|
import { ShuttleRouteDto } from '@/proxy/intranet/models'
|
||||||
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
|
|
||||||
const ShuttleRoute: React.FC<{ shuttleRoutes: ShuttleRouteDto[] }> = ({ shuttleRoutes }) => {
|
const ShuttleRoute: React.FC<{ shuttleRoutes: ShuttleRouteDto[] }> = ({ shuttleRoutes }) => {
|
||||||
const morningShuttles = shuttleRoutes.filter((s) => s.type === 'morning')
|
const morningShuttles = shuttleRoutes.filter((s) => s.type === 'morning')
|
||||||
const eveningShuttles = shuttleRoutes.filter((s) => s.type === 'evening')
|
const eveningShuttles = shuttleRoutes.filter((s) => s.type === 'evening')
|
||||||
|
const { translate } = useLocalization();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
|
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
|
||||||
<div className="p-4 border-b border-gray-200 dark:border-gray-700">
|
<div className="p-4 border-b border-gray-200 dark:border-gray-700">
|
||||||
<h2 className="text-lg font-semibold text-gray-900 dark:text-white flex items-center gap-2">
|
<h2 className="text-lg font-semibold text-gray-900 dark:text-white flex items-center gap-2">
|
||||||
<FaTruck className="w-5 h-5" />
|
<FaTruck className="w-5 h-5" />
|
||||||
Servis Saatleri
|
{translate('::App.Platform.Intranet.Widgets.ShuttleRoute.Title')}
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-4 space-y-4">
|
<div className="p-4 space-y-4">
|
||||||
{/* Sabah Servisleri */}
|
{/* Sabah Servisleri */}
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-sm font-semibold text-gray-900 dark:text-white mb-3 flex items-center gap-2">
|
<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>
|
</h3>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
{morningShuttles.slice(0, 2).map((shuttle) => (
|
{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'
|
: '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>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -63,7 +65,7 @@ const ShuttleRoute: React.FC<{ shuttleRoutes: ShuttleRouteDto[] }> = ({ shuttleR
|
||||||
{/* Akşam Servisleri */}
|
{/* Akşam Servisleri */}
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-sm font-semibold text-gray-900 dark:text-white mb-3 flex items-center gap-2">
|
<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>
|
</h3>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
{eveningShuttles.slice(0, 2).map((shuttle) => (
|
{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'
|
: '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>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,17 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import { EmployeeDto } from '@/proxy/intranet/models'
|
import { EmployeeDto } from '@/proxy/intranet/models'
|
||||||
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
|
|
||||||
const TodayBirthdays: React.FC<{ employees: EmployeeDto[] }> = ({ employees }) => {
|
const TodayBirthdays: React.FC<{ employees: EmployeeDto[] }> = ({ employees }) => {
|
||||||
const today = dayjs()
|
const today = dayjs()
|
||||||
|
const { translate } = useLocalization();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-gradient-to-br from-pink-50 to-purple-50 dark:from-pink-900/20 dark:to-purple-900/20 rounded-lg shadow-sm border border-pink-200 dark:border-pink-800">
|
<div className="bg-gradient-to-br from-pink-50 to-purple-50 dark:from-pink-900/20 dark:to-purple-900/20 rounded-lg shadow-sm border border-pink-200 dark:border-pink-800">
|
||||||
<div className="p-4 border-b border-pink-200 dark:border-pink-700">
|
<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">
|
<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>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-4 space-y-3">
|
<div className="p-4 space-y-3">
|
||||||
|
|
@ -30,10 +32,10 @@ const TodayBirthdays: React.FC<{ employees: EmployeeDto[] }> = ({ employees }) =
|
||||||
{birthday.name}
|
{birthday.name}
|
||||||
</p>
|
</p>
|
||||||
<p className="text-xs text-gray-600 dark:text-gray-400">
|
<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>
|
||||||
<p className="text-xs text-gray-500 dark:text-gray-500 mt-1">
|
<p className="text-xs text-gray-500 dark:text-gray-500 mt-1">
|
||||||
{birthday.department?.name || 'Genel'}
|
{birthday.department?.name || translate('::App.Platform.Intranet.Widgets.TodayBirthdays.General')}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -41,7 +43,7 @@ const TodayBirthdays: React.FC<{ employees: EmployeeDto[] }> = ({ employees }) =
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<p className="text-sm text-gray-500 dark:text-gray-400 text-center py-4">
|
<p className="text-sm text-gray-500 dark:text-gray-400 text-center py-4">
|
||||||
Bugün doğan yok
|
{translate('::App.Platform.Intranet.Widgets.TodayBirthdays.NoBirthday')}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,11 @@ import dayjs from 'dayjs'
|
||||||
import { EventDto } from '@/proxy/intranet/models'
|
import { EventDto } from '@/proxy/intranet/models'
|
||||||
import useLocale from '@/utils/hooks/useLocale'
|
import useLocale from '@/utils/hooks/useLocale'
|
||||||
import { currentLocalDate } from '@/utils/dateUtils'
|
import { currentLocalDate } from '@/utils/dateUtils'
|
||||||
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
|
|
||||||
const UpcomingEvents: React.FC<{ events: EventDto[] }> = ({ events }) => {
|
const UpcomingEvents: React.FC<{ events: EventDto[] }> = ({ events }) => {
|
||||||
const currentLocale = useLocale()
|
const currentLocale = useLocale()
|
||||||
|
const { translate } = useLocalization();
|
||||||
|
|
||||||
const upcomingEvents = events.filter(
|
const upcomingEvents = events.filter(
|
||||||
(event) =>
|
(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">
|
<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">
|
<h2 className="text-lg font-semibold text-gray-900 dark:text-white flex items-center gap-2">
|
||||||
<FaCalendarAlt className="w-5 h-5" />
|
<FaCalendarAlt className="w-5 h-5" />
|
||||||
Yaklaşan Etkinlikler
|
{translate('::App.Platform.Intranet.Widgets.UpcomingEvents.Title')}
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-4 space-y-3">
|
<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">
|
<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>
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -3,16 +3,18 @@ import { FaGraduationCap } from 'react-icons/fa'
|
||||||
import { TrainingDto } from '@/proxy/intranet/models'
|
import { TrainingDto } from '@/proxy/intranet/models'
|
||||||
import { currentLocalDate } from '@/utils/dateUtils'
|
import { currentLocalDate } from '@/utils/dateUtils'
|
||||||
import useLocale from '@/utils/hooks/useLocale'
|
import useLocale from '@/utils/hooks/useLocale'
|
||||||
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
|
|
||||||
const UpcomingTrainings: React.FC<{ trainings: TrainingDto[] }> = ({ trainings }) => {
|
const UpcomingTrainings: React.FC<{ trainings: TrainingDto[] }> = ({ trainings }) => {
|
||||||
const currentLocale = useLocale()
|
const currentLocale = useLocale()
|
||||||
|
const { translate } = useLocalization();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
|
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
|
||||||
<div className="p-4 border-b border-gray-200 dark:border-gray-700">
|
<div className="p-4 border-b border-gray-200 dark:border-gray-700">
|
||||||
<h2 className="text-lg font-semibold text-gray-900 dark:text-white flex items-center gap-2">
|
<h2 className="text-lg font-semibold text-gray-900 dark:text-white flex items-center gap-2">
|
||||||
<FaGraduationCap className="w-5 h-5" />
|
<FaGraduationCap className="w-5 h-5" />
|
||||||
Yaklaşan Eğitimler
|
{translate('::App.Platform.Intranet.Widgets.UpcomingTrainings.Title')}
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-4 space-y-3">
|
<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 && (
|
{trainings.filter((t) => t.status === 'upcoming').length === 0 && (
|
||||||
<p className="text-sm text-gray-500 dark:text-gray-400 text-center py-4">
|
<p className="text-sm text-gray-500 dark:text-gray-400 text-center py-4">
|
||||||
Yaklaşan eğitim yok
|
{translate('::App.Platform.Intranet.Widgets.UpcomingTrainings.NoTraining')}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -2,15 +2,17 @@ import React from 'react'
|
||||||
import { FaUser, FaUserCheck, FaUserClock } from 'react-icons/fa'
|
import { FaUser, FaUserCheck, FaUserClock } from 'react-icons/fa'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import { VisitorDto } from '@/proxy/intranet/models'
|
import { VisitorDto } from '@/proxy/intranet/models'
|
||||||
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
|
|
||||||
const Visitors: React.FC<{ visitors: VisitorDto[] }> = ({ visitors }) => {
|
const Visitors: React.FC<{ visitors: VisitorDto[] }> = ({ visitors }) => {
|
||||||
|
const { translate } = useLocalization();
|
||||||
const getStatusIcon = (status: string) => {
|
const getStatusIcon = (status: string) => {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case 'Giriş':
|
case translate('::App.Platform.Intranet.Widgets.Visitors.Status.Entry', 'Giriş'):
|
||||||
return <FaUserCheck className="w-4 h-4 text-green-600" />
|
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" />
|
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" />
|
return <FaUserClock className="w-4 h-4 text-blue-600" />
|
||||||
default:
|
default:
|
||||||
return <FaUser className="w-4 h-4 text-gray-600" />
|
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) => {
|
const getStatusText = (status: string) => {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case 'Giriş':
|
case translate('::App.Platform.Intranet.Widgets.Visitors.Status.Entry', 'Giriş'):
|
||||||
return 'Giriş Yaptı'
|
return translate('::App.Platform.Intranet.Widgets.Visitors.StatusText.Entry')
|
||||||
case 'Çıkış':
|
case translate('::App.Platform.Intranet.Widgets.Visitors.Status.Exit', 'Çıkış'):
|
||||||
return 'Çıkış Yaptı'
|
return translate('::App.Platform.Intranet.Widgets.Visitors.StatusText.Exit')
|
||||||
case 'Planlandı':
|
case translate('::App.Platform.Intranet.Widgets.Visitors.Status.Planned', 'Planlandı'):
|
||||||
return 'Planlandı'
|
return translate('::App.Platform.Intranet.Widgets.Visitors.StatusText.Planned')
|
||||||
default:
|
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">
|
<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">
|
<h2 className="text-lg font-semibold text-gray-900 dark:text-white flex items-center gap-2">
|
||||||
<FaUser className="w-5 h-5" />
|
<FaUser className="w-5 h-5" />
|
||||||
Bugünkü Ziyaretçiler
|
{translate('::App.Platform.Intranet.Widgets.Visitors.Title')}
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-4 space-y-3">
|
<div className="p-4 space-y-3">
|
||||||
|
|
@ -90,7 +92,7 @@ const Visitors: React.FC<{ visitors: VisitorDto[] }> = ({ visitors }) => {
|
||||||
</div>
|
</div>
|
||||||
{visitor.employee && (
|
{visitor.employee && (
|
||||||
<p className="text-xs text-gray-500 dark:text-gray-500 mt-1">
|
<p className="text-xs text-gray-500 dark:text-gray-500 mt-1">
|
||||||
Karşılayan: {visitor.employee.name}
|
{translate('::App.Platform.Intranet.Widgets.Visitors.Host')}: {visitor.employee.name}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</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">
|
<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>
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue