sozsoft-platform/ui/src/views/intranet/widgets/Surveys.tsx
2026-05-19 23:22:25 +03:00

177 lines
9.7 KiB
TypeScript

import React from 'react'
import { FaClipboardCheck, FaQuestionCircle, FaUsers, FaClock, FaArrowRight } from 'react-icons/fa'
import dayjs from 'dayjs'
import { SurveyDto } from '@/proxy/intranet/models'
import useLocale from '@/utils/hooks/useLocale'
import { currentLocalDate } from '@/utils/dateUtils'
import { useLocalization } from '@/utils/hooks/useLocalization'
interface SurveysProps {
surveys?: SurveyDto[]
onTakeSurvey: (survey: SurveyDto) => void
}
const Surveys: React.FC<SurveysProps> = ({ surveys, onTakeSurvey }) => {
const currentLocale = useLocale()
const { translate } = useLocalization()
return (
<div className="bg-gradient-to-br from-white to-gray-50 dark:from-gray-800 dark:to-gray-900 rounded-xl shadow-lg border border-gray-200/50 dark:border-gray-700/50 overflow-hidden">
{/* Header with gradient */}
<div className="p-4 border-b border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800">
<h2 className="text-base font-semibold text-gray-900 dark:text-white flex items-center gap-2">
<FaClipboardCheck className="w-5 h-5" />
{translate('::App.Platform.Intranet.Widgets.ActiveSurveys.Title')}
</h2>
</div>
<div className="p-3 space-y-4 bg-white dark:bg-gray-800">
{surveys?.map((survey, index) => {
const daysLeft = dayjs(survey.deadline).diff(dayjs(), 'day')
const urgency = daysLeft <= 3 ? 'urgent' : daysLeft <= 7 ? 'warning' : 'normal'
const isCompleted = !!survey.myResponse
return (
<div
key={survey.id}
onClick={() => onTakeSurvey(survey)}
className={`group relative p-5 rounded-xl border cursor-pointer transition-all duration-300 hover:shadow-lg hover:-translate-y-1 ${
isCompleted
? 'bg-green-50 dark:bg-green-900/30 border-green-300 dark:border-green-700 hover:border-green-400 dark:hover:border-green-500'
: 'bg-white dark:bg-gray-800 border-gray-200 dark:border-gray-700 hover:border-purple-300 dark:hover:border-purple-500'
}`}
>
{/* Background gradient on hover */}
<div className={`absolute inset-0 rounded-xl opacity-0 group-hover:opacity-100 transition-opacity duration-300 pointer-events-none ${
isCompleted
? 'bg-gradient-to-r from-green-50 to-emerald-50 dark:from-green-900/20 dark:to-emerald-900/20'
: 'bg-gradient-to-r from-purple-50 to-pink-50 dark:from-purple-900/20 dark:to-pink-900/20'
}`}></div>
<div className="relative">
{/* Survey Title */}
<div className="flex items-start justify-between mb-3">
<div className="flex items-center gap-2 flex-1 min-w-0">
{isCompleted && (
<span className="flex-shrink-0 inline-flex items-center justify-center w-5 h-5 bg-green-500 rounded-full">
<svg className="w-3 h-3 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={3}>
<path strokeLinecap="round" strokeLinejoin="round" d="M5 13l4 4L19 7" />
</svg>
</span>
)}
<h4 className={`text-base font-semibold transition-colors ${
isCompleted
? 'text-green-800 dark:text-green-300 group-hover:text-green-700 dark:group-hover:text-green-200'
: 'text-gray-900 dark:text-white group-hover:text-purple-700 dark:group-hover:text-purple-300'
}`}>
{survey.title}
</h4>
</div>
<div
className={`px-2 py-1 text-center rounded-full text-xs font-medium ${
urgency === 'urgent'
? 'bg-red-100 text-red-700 dark:bg-red-900/40 dark:text-red-300'
: urgency === 'warning'
? 'bg-amber-100 text-amber-700 dark:bg-amber-900/40 dark:text-amber-300'
: 'bg-green-100 text-green-700 dark:bg-green-900/40 dark:text-green-300'
}`}
>
{daysLeft > 0 ? translate('::App.Platform.Intranet.Widgets.ActiveSurveys.DaysLeft', { count: daysLeft }) : translate('::App.Platform.Intranet.Widgets.ActiveSurveys.LastDay')}
</div>
</div>
{/* Survey Stats */}
<div className="grid grid-cols-3 gap-4 mb-4">
<div className="flex items-center gap-2 text-sm">
<div className="p-1.5 bg-blue-100 dark:bg-blue-900/40 rounded-lg">
<FaQuestionCircle className="w-3 h-3 text-blue-600 dark:text-blue-300" />
</div>
<div>
<p className="text-xs text-gray-500 dark:text-gray-400">{translate('::App.Platform.Intranet.Widgets.ActiveSurveys.Questions')}</p>
<p className="font-semibold text-gray-900 dark:text-white">
{survey.questions.length}
</p>
</div>
</div>
<div className="flex items-center gap-2 text-sm">
<div className="p-1.5 bg-green-100 dark:bg-green-900/40 rounded-lg">
<FaUsers className="w-3 h-3 text-green-600 dark:text-green-300" />
</div>
<div>
<p className="text-xs text-gray-500 dark:text-gray-400">{translate('::App.Platform.Intranet.Widgets.ActiveSurveys.Responses')}</p>
<p className="font-semibold text-gray-900 dark:text-white">
{survey.responses}
</p>
</div>
</div>
<div className="flex items-center gap-2 text-sm">
<div className="p-1.5 bg-purple-100 dark:bg-purple-900/40 rounded-lg">
<FaClock className="w-3 h-3 text-purple-600 dark:text-purple-300" />
</div>
<div>
<p className="text-xs text-gray-500 dark:text-gray-400">{translate('::App.Platform.Intranet.Widgets.ActiveSurveys.Duration')}</p>
<p className="font-semibold text-gray-900 dark:text-white">~5dk</p>
</div>
</div>
</div>
{/* Progress Bar */}
<div className="mb-4">
<div className="flex justify-between text-xs mb-1">
<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-100 font-medium">
{Math.round((survey.responses / 100) * 100)}%
</span>
</div>
<div className="w-full bg-gray-200 dark:bg-gray-700 rounded-full h-2">
<div
className="bg-gradient-to-r from-purple-500 to-pink-500 dark:from-purple-700 dark:to-pink-700 h-2 rounded-full transition-all duration-500"
style={{ width: `${Math.min((survey.responses / 100) * 100, 100)}%` }}
></div>
</div>
</div>
{/* Deadline */}
<p className="text-sm text-gray-600 dark:text-gray-400 mb-4">
<FaClock className="inline w-3 h-3 mr-1 text-purple-500 dark:text-purple-300" />
{currentLocalDate(survey.deadline, currentLocale || 'tr')}
</p>
{/* Action Button */}
<button className={`w-full flex items-center justify-center gap-2 px-4 py-3 text-white text-sm font-medium rounded-lg transition-all duration-300 transform group-hover:scale-[1.02] shadow-sm hover:shadow-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-purple-500 dark:focus:ring-purple-400 ${
isCompleted
? 'bg-gradient-to-r from-green-500 to-emerald-500 hover:from-green-600 hover:to-emerald-600 dark:from-green-600 dark:to-emerald-600 dark:hover:from-green-700 dark:hover:to-emerald-700'
: 'bg-gradient-to-r from-purple-600 to-pink-600 hover:from-purple-700 hover:to-pink-700 dark:from-purple-700 dark:to-pink-700 dark:hover:from-purple-800 dark:hover:to-pink-800'
}`}>
{isCompleted
? translate('::App.Platform.Intranet.Widgets.ActiveSurveys.ViewResponses')
: translate('::App.Platform.Intranet.Widgets.ActiveSurveys.FillSurvey')}
<FaArrowRight className="w-3 h-3 transition-transform group-hover:translate-x-1" />
</button>
</div>
</div>
)
})}
{surveys?.length === 0 && (
<div className="text-center py-12 bg-white dark:bg-gray-800 rounded-xl">
<div className="inline-flex items-center justify-center w-16 h-16 bg-gray-100 dark:bg-gray-700 rounded-full mb-4">
<FaClipboardCheck className="w-8 h-8 text-gray-400 dark:text-gray-500" />
</div>
<h3 className="text-lg font-medium text-gray-900 dark:text-white mb-2">
{translate('::App.Platform.Intranet.Widgets.ActiveSurveys.NoActive')}
</h3>
<p className="text-sm text-gray-500 dark:text-gray-400">
{translate('::App.Platform.Intranet.Widgets.ActiveSurveys.WillAppearHere')}
</p>
</div>
)}
</div>
</div>
)
}
export default Surveys