Hr Survey güncellemesi
This commit is contained in:
parent
68482e0a8d
commit
f02136d358
5 changed files with 523 additions and 108 deletions
|
|
@ -11,6 +11,10 @@ import {
|
|||
MealMenu,
|
||||
ShuttleRoute,
|
||||
Survey,
|
||||
SurveyQuestion,
|
||||
SurveyQuestionOption,
|
||||
SurveyResponse,
|
||||
SurveyAnswer,
|
||||
SocialPost,
|
||||
} from '@/types/intranet'
|
||||
|
||||
|
|
@ -70,7 +74,58 @@ export const mockSurveys: Survey[] = [
|
|||
creatorId: mockEmployees[0],
|
||||
creationTime: new Date('2024-10-01'),
|
||||
deadline: new Date('2024-10-31'),
|
||||
totalQuestions: 25,
|
||||
questions: [
|
||||
{
|
||||
id: 'q1',
|
||||
surveyId: 'survey1',
|
||||
questionText: 'Genel memnuniyet düzeyiniz nedir?',
|
||||
type: 'rating',
|
||||
order: 1,
|
||||
isRequired: true,
|
||||
ratingConfig: {
|
||||
min: 1,
|
||||
max: 5,
|
||||
labels: {
|
||||
1: 'Çok Kötü',
|
||||
2: 'Kötü',
|
||||
3: 'Orta',
|
||||
4: 'İyi',
|
||||
5: 'Çok İyi'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'q2',
|
||||
surveyId: 'survey1',
|
||||
questionText: 'Hangi departmanda çalışıyorsunuz?',
|
||||
type: 'multiple-choice',
|
||||
order: 2,
|
||||
isRequired: true,
|
||||
options: [
|
||||
{ id: 'opt1', text: 'Bilgi Teknolojileri', order: 1 },
|
||||
{ id: 'opt2', text: 'İnsan Kaynakları', order: 2 },
|
||||
{ id: 'opt3', text: 'Finans', order: 3 },
|
||||
{ id: 'opt4', text: 'Satış', order: 4 },
|
||||
{ id: 'opt5', text: 'Pazarlama', order: 5 }
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'q3',
|
||||
surveyId: 'survey1',
|
||||
questionText: 'Görüş ve önerileriniz',
|
||||
type: 'textarea',
|
||||
order: 3,
|
||||
isRequired: false
|
||||
},
|
||||
{
|
||||
id: 'q4',
|
||||
surveyId: 'survey1',
|
||||
questionText: 'Çalışma ortamından memnun musunuz?',
|
||||
type: 'yes-no',
|
||||
order: 4,
|
||||
isRequired: true
|
||||
}
|
||||
],
|
||||
responses: 45,
|
||||
targetAudience: ['Tüm Çalışanlar'],
|
||||
status: 'active',
|
||||
|
|
@ -83,7 +138,53 @@ export const mockSurveys: Survey[] = [
|
|||
creatorId: mockEmployees[2],
|
||||
creationTime: new Date('2024-10-10'),
|
||||
deadline: new Date('2024-11-15'),
|
||||
totalQuestions: 15,
|
||||
questions: [
|
||||
{
|
||||
id: 'q5',
|
||||
surveyId: 'survey2',
|
||||
questionText: 'Hangi teknoloji konularında eğitim almak istiyorsunuz?',
|
||||
type: 'multiple-choice',
|
||||
order: 1,
|
||||
isRequired: true,
|
||||
options: [
|
||||
{ id: 'opt6', text: 'React / Frontend', order: 1 },
|
||||
{ id: 'opt7', text: 'Node.js / Backend', order: 2 },
|
||||
{ id: 'opt8', text: 'Database / SQL', order: 3 },
|
||||
{ id: 'opt9', text: 'DevOps / Cloud', order: 4 },
|
||||
{ id: 'opt10', text: 'Mobile Development', order: 5 }
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'q6',
|
||||
surveyId: 'survey2',
|
||||
questionText: 'Eğitim formatı tercihiniz nedir?',
|
||||
type: 'multiple-choice',
|
||||
order: 2,
|
||||
isRequired: true,
|
||||
options: [
|
||||
{ id: 'opt11', text: 'Online Eğitim', order: 1 },
|
||||
{ id: 'opt12', text: 'Yüz Yüze Eğitim', order: 2 },
|
||||
{ id: 'opt13', text: 'Hibrit (Karma)', order: 3 }
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'q7',
|
||||
surveyId: 'survey2',
|
||||
questionText: 'Eğitim için haftalık ne kadar zaman ayırabilirsiniz?',
|
||||
type: 'rating',
|
||||
order: 3,
|
||||
isRequired: true,
|
||||
ratingConfig: {
|
||||
min: 1,
|
||||
max: 10,
|
||||
labels: {
|
||||
1: '1 saat',
|
||||
5: '5 saat',
|
||||
10: '10+ saat'
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
responses: 28,
|
||||
targetAudience: ['Yazılım Geliştirme', 'Ürün Yönetimi'],
|
||||
status: 'active',
|
||||
|
|
@ -96,7 +197,43 @@ export const mockSurveys: Survey[] = [
|
|||
creatorId: mockEmployees[4],
|
||||
creationTime: new Date('2024-09-15'),
|
||||
deadline: new Date('2024-09-30'),
|
||||
totalQuestions: 10,
|
||||
questions: [
|
||||
{
|
||||
id: 'q8',
|
||||
surveyId: 'survey3',
|
||||
questionText: 'Yemek kalitesini nasıl değerlendiriyorsunuz?',
|
||||
type: 'rating',
|
||||
order: 1,
|
||||
isRequired: true,
|
||||
ratingConfig: {
|
||||
min: 1,
|
||||
max: 5,
|
||||
labels: {
|
||||
1: 'Çok Kötü',
|
||||
2: 'Kötü',
|
||||
3: 'Orta',
|
||||
4: 'İyi',
|
||||
5: 'Mükemmel'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'q9',
|
||||
surveyId: 'survey3',
|
||||
questionText: 'Hangi yemekleri daha sık görmek istiyorsunuz?',
|
||||
type: 'textarea',
|
||||
order: 2,
|
||||
isRequired: false
|
||||
},
|
||||
{
|
||||
id: 'q10',
|
||||
surveyId: 'survey3',
|
||||
questionText: 'Servis hızından memnun musunuz?',
|
||||
type: 'yes-no',
|
||||
order: 3,
|
||||
isRequired: true
|
||||
}
|
||||
],
|
||||
responses: 62,
|
||||
targetAudience: ['Tüm Çalışanlar'],
|
||||
status: 'closed',
|
||||
|
|
|
|||
|
|
@ -161,6 +161,29 @@ export interface ShuttleRoute {
|
|||
type: 'morning' | 'evening'
|
||||
}
|
||||
|
||||
// Anket Sorusu
|
||||
export interface SurveyQuestion {
|
||||
id: string
|
||||
surveyId: string
|
||||
questionText: string
|
||||
type: 'rating' | 'multiple-choice' | 'text' | 'textarea' | 'yes-no'
|
||||
order: number
|
||||
isRequired: boolean
|
||||
options?: SurveyQuestionOption[]
|
||||
ratingConfig?: {
|
||||
min: number
|
||||
max: number
|
||||
labels?: { [key: number]: string }
|
||||
}
|
||||
}
|
||||
|
||||
// Anket Sorusu Seçeneği
|
||||
export interface SurveyQuestionOption {
|
||||
id: string
|
||||
text: string
|
||||
order: number
|
||||
}
|
||||
|
||||
// Anket
|
||||
export interface Survey {
|
||||
id: string
|
||||
|
|
@ -169,13 +192,29 @@ export interface Survey {
|
|||
creatorId: HrEmployee
|
||||
creationTime: Date
|
||||
deadline: Date
|
||||
totalQuestions: number
|
||||
questions: SurveyQuestion[]
|
||||
responses: number
|
||||
targetAudience: string[]
|
||||
status: 'draft' | 'active' | 'closed'
|
||||
isAnonymous: boolean
|
||||
}
|
||||
|
||||
// Anket Cevabı
|
||||
export interface SurveyResponse {
|
||||
id: string
|
||||
surveyId: string
|
||||
respondentId?: string // Anonymous ise null
|
||||
submissionTime: Date
|
||||
answers: SurveyAnswer[]
|
||||
}
|
||||
|
||||
// Anket Cevap
|
||||
export interface SurveyAnswer {
|
||||
questionId: string
|
||||
questionType: 'rating' | 'multiple-choice' | 'text' | 'textarea' | 'yes-no'
|
||||
value: string | number | string[]
|
||||
}
|
||||
|
||||
// Ziyaretçi
|
||||
export interface Visitor {
|
||||
id: string
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ import AnnouncementDetailModal from './modals/AnnouncementDetailModal'
|
|||
|
||||
// Social Wall
|
||||
import SocialWall from './SocialWall'
|
||||
import { Announcement, Survey } from '@/types/intranet'
|
||||
import { Announcement, Survey, SurveyAnswer } from '@/types/intranet'
|
||||
import { Container } from '@/components/shared'
|
||||
|
||||
dayjs.locale('tr')
|
||||
|
|
@ -52,7 +52,9 @@ const IntranetDashboard: React.FC = () => {
|
|||
setShowSurveyModal(true)
|
||||
}
|
||||
|
||||
const handleSubmitSurvey = () => {
|
||||
const handleSubmitSurvey = (answers: SurveyAnswer[]) => {
|
||||
console.log('Survey submitted with answers:', answers)
|
||||
// Burada survey cevapları API'ye gönderilecek
|
||||
setShowSurveyModal(false)
|
||||
setSelectedSurvey(null)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,214 @@
|
|||
import React from 'react'
|
||||
import React, { useState } from 'react'
|
||||
import { motion } from 'framer-motion'
|
||||
import { FaTimes } from 'react-icons/fa'
|
||||
import { Survey } from '@/types/intranet'
|
||||
import { Survey, SurveyQuestion, SurveyAnswer } from '@/types/intranet'
|
||||
|
||||
interface SurveyModalProps {
|
||||
survey: Survey
|
||||
onClose: () => void
|
||||
onSubmit: () => void
|
||||
onSubmit: (answers: SurveyAnswer[]) => void
|
||||
}
|
||||
|
||||
const SurveyModal: React.FC<SurveyModalProps> = ({ survey, onClose, onSubmit }) => {
|
||||
const [answers, setAnswers] = useState<{ [questionId: string]: any }>({})
|
||||
const [errors, setErrors] = useState<{ [questionId: string]: string }>({})
|
||||
|
||||
const handleAnswerChange = (questionId: string, value: any) => {
|
||||
setAnswers(prev => ({
|
||||
...prev,
|
||||
[questionId]: value
|
||||
}))
|
||||
|
||||
// Clear error when user provides an answer
|
||||
if (errors[questionId]) {
|
||||
setErrors(prev => ({
|
||||
...prev,
|
||||
[questionId]: ''
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
const validateAnswers = (): boolean => {
|
||||
const newErrors: { [questionId: string]: string } = {}
|
||||
|
||||
survey.questions.forEach(question => {
|
||||
if (question.isRequired && (!answers[question.id] || answers[question.id] === '')) {
|
||||
newErrors[question.id] = 'Bu alan zorunludur'
|
||||
}
|
||||
})
|
||||
|
||||
setErrors(newErrors)
|
||||
return Object.keys(newErrors).length === 0
|
||||
}
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault()
|
||||
|
||||
if (!validateAnswers()) {
|
||||
return
|
||||
}
|
||||
|
||||
const surveyAnswers: SurveyAnswer[] = survey.questions.map(question => ({
|
||||
questionId: question.id,
|
||||
questionType: question.type,
|
||||
value: answers[question.id] || (question.type === 'multiple-choice' ? '' :
|
||||
question.type === 'rating' ? 0 : '')
|
||||
}))
|
||||
|
||||
onSubmit(surveyAnswers)
|
||||
}
|
||||
|
||||
const renderQuestion = (question: SurveyQuestion, index: number) => {
|
||||
const questionNumber = index + 1
|
||||
const hasError = !!errors[question.id]
|
||||
|
||||
switch (question.type) {
|
||||
case 'rating':
|
||||
return (
|
||||
<div key={question.id} className="space-y-2">
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
{questionNumber}. {question.questionText} {question.isRequired && '*'}
|
||||
</label>
|
||||
<div className="flex gap-2 flex-wrap">
|
||||
{Array.from({ length: question.ratingConfig!.max - question.ratingConfig!.min + 1 }, (_, i) => {
|
||||
const value = question.ratingConfig!.min + i
|
||||
const label = question.ratingConfig!.labels?.[value] || value.toString()
|
||||
return (
|
||||
<label
|
||||
key={value}
|
||||
className={`flex flex-col items-center gap-1 px-3 py-2 border rounded-lg cursor-pointer transition-colors ${
|
||||
answers[question.id] === value
|
||||
? 'bg-blue-100 border-blue-500 dark:bg-blue-900/30 dark:border-blue-400'
|
||||
: 'border-gray-300 dark:border-gray-600 hover:bg-gray-50 dark:hover:bg-gray-700'
|
||||
}`}
|
||||
>
|
||||
<input
|
||||
type="radio"
|
||||
name={`question-${question.id}`}
|
||||
value={value}
|
||||
checked={answers[question.id] === value}
|
||||
onChange={(e) => handleAnswerChange(question.id, parseInt(e.target.value))}
|
||||
className="sr-only"
|
||||
/>
|
||||
<span className="font-medium text-gray-900 dark:text-white">{value}</span>
|
||||
<span className="text-xs text-gray-500 dark:text-gray-400 text-center">{label}</span>
|
||||
</label>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
{hasError && <p className="text-sm text-red-600 dark:text-red-400">{errors[question.id]}</p>}
|
||||
</div>
|
||||
)
|
||||
|
||||
case 'multiple-choice':
|
||||
return (
|
||||
<div key={question.id} className="space-y-2">
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
{questionNumber}. {question.questionText} {question.isRequired && '*'}
|
||||
</label>
|
||||
<div className="space-y-2">
|
||||
{question.options?.map(option => (
|
||||
<label
|
||||
key={option.id}
|
||||
className={`flex items-center gap-3 p-3 border rounded-lg cursor-pointer transition-colors ${
|
||||
answers[question.id] === option.id
|
||||
? 'bg-blue-50 border-blue-500 dark:bg-blue-900/20 dark:border-blue-400'
|
||||
: 'border-gray-300 dark:border-gray-600 hover:bg-gray-50 dark:hover:bg-gray-700'
|
||||
}`}
|
||||
>
|
||||
<input
|
||||
type="radio"
|
||||
name={`question-${question.id}`}
|
||||
value={option.id}
|
||||
checked={answers[question.id] === option.id}
|
||||
onChange={(e) => handleAnswerChange(question.id, e.target.value)}
|
||||
className="w-4 h-4 text-blue-600"
|
||||
/>
|
||||
<span className="text-sm text-gray-900 dark:text-white">{option.text}</span>
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
{hasError && <p className="text-sm text-red-600 dark:text-red-400">{errors[question.id]}</p>}
|
||||
</div>
|
||||
)
|
||||
|
||||
case 'yes-no':
|
||||
return (
|
||||
<div key={question.id} className="space-y-2">
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
{questionNumber}. {question.questionText} {question.isRequired && '*'}
|
||||
</label>
|
||||
<div className="flex gap-4">
|
||||
{['yes', 'no'].map(value => (
|
||||
<label
|
||||
key={value}
|
||||
className={`flex items-center gap-2 px-4 py-2 border rounded-lg cursor-pointer transition-colors ${
|
||||
answers[question.id] === value
|
||||
? 'bg-blue-50 border-blue-500 dark:bg-blue-900/20 dark:border-blue-400'
|
||||
: 'border-gray-300 dark:border-gray-600 hover:bg-gray-50 dark:hover:bg-gray-700'
|
||||
}`}
|
||||
>
|
||||
<input
|
||||
type="radio"
|
||||
name={`question-${question.id}`}
|
||||
value={value}
|
||||
checked={answers[question.id] === value}
|
||||
onChange={(e) => handleAnswerChange(question.id, e.target.value)}
|
||||
className="w-4 h-4 text-blue-600"
|
||||
/>
|
||||
<span className="text-sm text-gray-900 dark:text-white">
|
||||
{value === 'yes' ? 'Evet' : 'Hayır'}
|
||||
</span>
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
{hasError && <p className="text-sm text-red-600 dark:text-red-400">{errors[question.id]}</p>}
|
||||
</div>
|
||||
)
|
||||
|
||||
case 'text':
|
||||
return (
|
||||
<div key={question.id} className="space-y-2">
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
{questionNumber}. {question.questionText} {question.isRequired && '*'}
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={answers[question.id] || ''}
|
||||
onChange={(e) => handleAnswerChange(question.id, e.target.value)}
|
||||
className={`w-full px-4 py-2 border rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-blue-500 ${
|
||||
hasError ? 'border-red-500' : 'border-gray-300 dark:border-gray-600'
|
||||
}`}
|
||||
placeholder="Cevabınızı yazın..."
|
||||
/>
|
||||
{hasError && <p className="text-sm text-red-600 dark:text-red-400">{errors[question.id]}</p>}
|
||||
</div>
|
||||
)
|
||||
|
||||
case 'textarea':
|
||||
return (
|
||||
<div key={question.id} className="space-y-2">
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
{questionNumber}. {question.questionText} {question.isRequired && '*'}
|
||||
</label>
|
||||
<textarea
|
||||
rows={4}
|
||||
value={answers[question.id] || ''}
|
||||
onChange={(e) => handleAnswerChange(question.id, e.target.value)}
|
||||
className={`w-full px-4 py-2 border rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-blue-500 ${
|
||||
hasError ? 'border-red-500' : 'border-gray-300 dark:border-gray-600'
|
||||
}`}
|
||||
placeholder="Yorumlarınızı buraya yazabilirsiniz..."
|
||||
/>
|
||||
{hasError && <p className="text-sm text-red-600 dark:text-red-400">{errors[question.id]}</p>}
|
||||
</div>
|
||||
)
|
||||
|
||||
default:
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<motion.div
|
||||
|
|
@ -44,78 +243,30 @@ const SurveyModal: React.FC<SurveyModalProps> = ({ survey, onClose, onSubmit })
|
|||
</button>
|
||||
</div>
|
||||
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault()
|
||||
onSubmit()
|
||||
}}
|
||||
className="p-6 space-y-6"
|
||||
>
|
||||
{/* Örnek Anket Soruları */}
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||
1. Genel memnuniyet düzeyiniz nedir? *
|
||||
</label>
|
||||
<div className="flex gap-2">
|
||||
{[1, 2, 3, 4, 5].map((rating) => (
|
||||
<label
|
||||
key={rating}
|
||||
className="flex items-center gap-2 px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-700"
|
||||
>
|
||||
<input type="radio" name="rating" value={rating} required />
|
||||
<span className="text-sm text-gray-900 dark:text-white">{rating}</span>
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||
2. Hangi departmanda çalışıyorsunuz? *
|
||||
</label>
|
||||
<select
|
||||
required
|
||||
className="w-full px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-blue-500"
|
||||
>
|
||||
<option value="">Seçiniz</option>
|
||||
<option value="it">Bilgi Teknolojileri</option>
|
||||
<option value="hr">İnsan Kaynakları</option>
|
||||
<option value="finance">Finans</option>
|
||||
<option value="sales">Satış</option>
|
||||
<option value="marketing">Pazarlama</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||
3. Görüş ve önerileriniz
|
||||
</label>
|
||||
<textarea
|
||||
rows={4}
|
||||
placeholder="Yorumlarınızı buraya yazabilirsiniz..."
|
||||
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>
|
||||
|
||||
{!survey.isAnonymous && (
|
||||
<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">
|
||||
ℹ️ Bu anket isim belirtilerek doldurulmaktadır. Yanıtlarınız
|
||||
kaydedilecektir.
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{survey.isAnonymous && (
|
||||
<div className="bg-green-50 dark:bg-green-900/20 rounded-lg p-3">
|
||||
<p className="text-sm text-green-700 dark:text-green-300">
|
||||
✅ Bu anket anonimdir. Kimlik bilgileriniz kaydedilmeyecektir.
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
<form onSubmit={handleSubmit} className="p-6 space-y-6">
|
||||
<div className="space-y-6">
|
||||
{survey.questions
|
||||
.sort((a, b) => a.order - b.order)
|
||||
.map((question, index) => renderQuestion(question, index))}
|
||||
</div>
|
||||
|
||||
{!survey.isAnonymous && (
|
||||
<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">
|
||||
ℹ️ Bu anket isim belirtilerek doldurulmaktadır. Yanıtlarınız
|
||||
kaydedilecektir.
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{survey.isAnonymous && (
|
||||
<div className="bg-green-50 dark:bg-green-900/20 rounded-lg p-3">
|
||||
<p className="text-sm text-green-700 dark:text-green-300">
|
||||
✅ Bu anket anonimdir. Kimlik bilgileriniz kaydedilmeyecektir.
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="flex gap-3 pt-4 border-t border-gray-200 dark:border-gray-700">
|
||||
<button
|
||||
type="button"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import React from 'react'
|
||||
import { FaClipboardCheck } from 'react-icons/fa'
|
||||
import { FaClipboardCheck, FaQuestionCircle, FaUsers, FaClock, FaArrowRight } from 'react-icons/fa'
|
||||
import dayjs from 'dayjs'
|
||||
import { mockSurveys } from '../../../mocks/mockIntranet'
|
||||
import { Survey } from '@/types/intranet'
|
||||
|
|
@ -9,47 +9,133 @@ interface ActiveSurveysProps {
|
|||
}
|
||||
|
||||
const ActiveSurveys: React.FC<ActiveSurveysProps> = ({ onTakeSurvey }) => {
|
||||
const activeSurveys = mockSurveys.filter((s) => s.status === 'active').slice(0, 3)
|
||||
|
||||
return (
|
||||
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
|
||||
<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">
|
||||
{/* Header with gradient */}
|
||||
|
||||
<div className="p-6 border-b border-gray-200 dark:border-gray-700">
|
||||
<h2 className="text-lg font-semibold text-gray-900 dark:text-white flex items-center gap-2">
|
||||
<FaClipboardCheck className="w-5 h-5" />
|
||||
Aktif Anketler
|
||||
</h2>
|
||||
</div>
|
||||
<div className="p-4 space-y-3">
|
||||
{mockSurveys
|
||||
.filter((s) => s.status === 'active')
|
||||
.slice(0, 3)
|
||||
.map((survey) => (
|
||||
|
||||
<div className="p-6 space-y-4">
|
||||
{activeSurveys.map((survey, index) => {
|
||||
const daysLeft = dayjs(survey.deadline).diff(dayjs(), 'day')
|
||||
const urgency = daysLeft <= 3 ? 'urgent' : daysLeft <= 7 ? 'warning' : 'normal'
|
||||
|
||||
return (
|
||||
<div
|
||||
key={survey.id}
|
||||
onClick={() => onTakeSurvey(survey)}
|
||||
className="p-3 rounded-lg bg-purple-50 dark:bg-purple-900/20 border border-purple-200 dark:border-purple-800 hover:bg-purple-100 dark:hover:bg-purple-900/30 cursor-pointer transition-colors"
|
||||
className="group relative p-5 rounded-xl bg-white dark:bg-gray-750 border border-gray-200 dark:border-gray-600 hover:border-purple-300 dark:hover:border-purple-500 cursor-pointer transition-all duration-300 hover:shadow-lg hover:-translate-y-1"
|
||||
>
|
||||
<h4 className="text-sm font-medium text-gray-900 dark:text-white mb-1">
|
||||
{survey.title}
|
||||
</h4>
|
||||
<div className="flex items-center justify-between text-xs">
|
||||
<span className="text-gray-600 dark:text-gray-400">
|
||||
{survey.totalQuestions} soru
|
||||
</span>
|
||||
<span className="text-purple-600 dark:text-purple-400 font-medium">
|
||||
{survey.responses} yanıt
|
||||
</span>
|
||||
{/* Background gradient on hover */}
|
||||
<div className="absolute inset-0 bg-gradient-to-r from-purple-50 to-pink-50 dark:from-purple-900/10 dark:to-pink-900/10 rounded-xl opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
|
||||
|
||||
<div className="relative">
|
||||
{/* Survey Title */}
|
||||
<div className="flex items-start justify-between mb-3">
|
||||
<h4 className="text-base font-semibold text-gray-900 dark:text-white group-hover:text-purple-700 dark:group-hover:text-purple-300 transition-colors">
|
||||
{survey.title}
|
||||
</h4>
|
||||
<div
|
||||
className={`px-2 py-1 rounded-full text-xs font-medium ${
|
||||
urgency === 'urgent'
|
||||
? 'bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-300'
|
||||
: urgency === 'warning'
|
||||
? 'bg-amber-100 text-amber-700 dark:bg-amber-900/30 dark:text-amber-300'
|
||||
: 'bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-300'
|
||||
}`}
|
||||
>
|
||||
{daysLeft > 0 ? `${daysLeft} gün` : 'Son gün'}
|
||||
</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/30 rounded-lg">
|
||||
<FaQuestionCircle className="w-3 h-3 text-blue-600 dark:text-blue-400" />
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-xs text-gray-500 dark:text-gray-400">Sorular</p>
|
||||
<p className="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/30 rounded-lg">
|
||||
<FaUsers className="w-3 h-3 text-green-600 dark:text-green-400" />
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-xs text-gray-500 dark:text-gray-400">Yanıtlar</p>
|
||||
<p className="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/30 rounded-lg">
|
||||
<FaClock className="w-3 h-3 text-purple-600 dark:text-purple-400" />
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-xs text-gray-500 dark:text-gray-400">Süre</p>
|
||||
<p className="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">Tamamlanma oranı</span>
|
||||
<span className="text-gray-800 dark:text-gray-200 font-medium">
|
||||
{Math.round((survey.responses / 100) * 100)}%
|
||||
</span>
|
||||
</div>
|
||||
<div className="w-full bg-gray-200 dark:bg-gray-600 rounded-full h-2">
|
||||
<div
|
||||
className="bg-gradient-to-r from-purple-500 to-pink-500 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" />
|
||||
Son tarih: {dayjs(survey.deadline).format('DD MMMM YYYY')}
|
||||
</p>
|
||||
|
||||
{/* Action Button */}
|
||||
<button className="w-full flex items-center justify-center gap-2 px-4 py-3 bg-gradient-to-r from-purple-600 to-pink-600 hover:from-purple-700 hover:to-pink-700 text-white text-sm font-medium rounded-lg transition-all duration-300 transform group-hover:scale-[1.02] shadow-sm hover:shadow-md">
|
||||
Anketi Doldur
|
||||
<FaArrowRight className="w-3 h-3 transition-transform group-hover:translate-x-1" />
|
||||
</button>
|
||||
</div>
|
||||
<p className="text-xs text-gray-500 dark:text-gray-400 mt-1">
|
||||
Son tarih: {dayjs(survey.deadline).format('DD MMM')}
|
||||
</p>
|
||||
<button className="mt-2 w-full px-3 py-1.5 bg-purple-600 hover:bg-purple-700 text-white text-xs rounded-md transition-colors">
|
||||
Anketi Doldur
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
{mockSurveys.filter((s) => s.status === 'active').length === 0 && (
|
||||
<p className="text-sm text-gray-500 dark:text-gray-400 text-center py-4">
|
||||
Aktif anket yok
|
||||
</p>
|
||||
)
|
||||
})}
|
||||
|
||||
{activeSurveys.length === 0 && (
|
||||
<div className="text-center py-12">
|
||||
<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" />
|
||||
</div>
|
||||
<h3 className="text-lg font-medium text-gray-900 dark:text-white mb-2">
|
||||
Aktif anket bulunmuyor
|
||||
</h3>
|
||||
<p className="text-sm text-gray-500 dark:text-gray-400">
|
||||
Yeni anketler eklendiğinde burada görünecektir.
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in a new issue