Classroom

This commit is contained in:
Sedat ÖZTÜRK 2025-08-27 18:00:22 +03:00
parent 7e402d352c
commit 76615b074b
15 changed files with 133 additions and 143 deletions

View file

@ -13,8 +13,8 @@ public interface IClassroomAppService : IApplicationService
Task<ClassroomDto> GetAsync(Guid id); Task<ClassroomDto> GetAsync(Guid id);
Task<ClassroomDto> UpdateAsync(Guid id, ClassroomDto input); Task<ClassroomDto> UpdateAsync(Guid id, ClassroomDto input);
Task DeleteAsync(Guid id); Task DeleteAsync(Guid id);
Task<ClassroomDto> StartClassAsync(Guid id); // Task<ClassroomDto> StartClassAsync(Guid id);
Task EndClassAsync(Guid id); // Task EndClassAsync(Guid id);
Task<ClassroomDto> JoinClassAsync(Guid id); Task<ClassroomDto> JoinClassAsync(Guid id);
Task LeaveClassAsync(Guid id); Task LeaveClassAsync(Guid id);
Task<List<ClassAttendanceDto>> GetAttendanceAsync(Guid sessionId); Task<List<ClassAttendanceDto>> GetAttendanceAsync(Guid sessionId);

View file

@ -5,6 +5,7 @@ using System.Text.Json;
using System.Threading.Tasks; using System.Threading.Tasks;
using Kurs.Platform.Entities; using Kurs.Platform.Entities;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Dtos;
using Volo.Abp.Domain.Repositories; using Volo.Abp.Domain.Repositories;
@ -88,9 +89,15 @@ public class ClassroomAppService : PlatformAppService, IClassroomAppService
classSession.Name = input.Name; classSession.Name = input.Name;
classSession.Description = input.Description; classSession.Description = input.Description;
classSession.Subject = input.Subject; classSession.Subject = input.Subject;
classSession.TeacherId = input.TeacherId;
classSession.TeacherName = input.TeacherName;
classSession.ScheduledStartTime = input.ScheduledStartTime; classSession.ScheduledStartTime = input.ScheduledStartTime;
classSession.ActualStartTime = input.ActualStartTime;
classSession.Duration = input.Duration; classSession.Duration = input.Duration;
classSession.MaxParticipants = input.MaxParticipants; classSession.MaxParticipants = input.MaxParticipants;
classSession.IsActive = input.IsActive;
classSession.IsScheduled = input.IsScheduled;
classSession.SettingsJson = JsonSerializer.Serialize(input.SettingsDto);
await _classSessionRepository.UpdateAsync(classSession); await _classSessionRepository.UpdateAsync(classSession);
return ObjectMapper.Map<Classroom, ClassroomDto>(classSession); return ObjectMapper.Map<Classroom, ClassroomDto>(classSession);
@ -113,7 +120,8 @@ public class ClassroomAppService : PlatformAppService, IClassroomAppService
await _classSessionRepository.DeleteAsync(id); await _classSessionRepository.DeleteAsync(id);
} }
public async Task<ClassroomDto> StartClassAsync(Guid id) [HttpPut]
public async Task<ClassroomDto> StartClassroomAsync(Guid id)
{ {
var classSession = await _classSessionRepository.GetAsync(id); var classSession = await _classSessionRepository.GetAsync(id);
@ -127,13 +135,19 @@ public class ClassroomAppService : PlatformAppService, IClassroomAppService
throw new InvalidOperationException("Class cannot be started at this time"); throw new InvalidOperationException("Class cannot be started at this time");
} }
classSession.StartClass(); if (classSession.IsActive)
throw new InvalidOperationException("Class is already active");
classSession.IsActive = true;
classSession.ActualStartTime = DateTime.Now;
await _classSessionRepository.UpdateAsync(classSession); await _classSessionRepository.UpdateAsync(classSession);
return ObjectMapper.Map<Classroom, ClassroomDto>(classSession); return ObjectMapper.Map<Classroom, ClassroomDto>(classSession);
} }
public async Task EndClassAsync(Guid id) [HttpPut]
public async Task EndClassroomAsync(Guid id)
{ {
var classSession = await _classSessionRepository.GetAsync(id); var classSession = await _classSessionRepository.GetAsync(id);
@ -142,7 +156,12 @@ public class ClassroomAppService : PlatformAppService, IClassroomAppService
throw new UnauthorizedAccessException("Only the teacher can end this class"); throw new UnauthorizedAccessException("Only the teacher can end this class");
} }
classSession.EndClass(); if (!classSession.IsActive)
throw new InvalidOperationException("Class is not active");
classSession.IsActive = false;
classSession.EndTime = DateTime.Now;
await _classSessionRepository.UpdateAsync(classSession); await _classSessionRepository.UpdateAsync(classSession);
// Update attendance records // Update attendance records

View file

@ -64,27 +64,9 @@ public class Classroom : FullAuditedEntity<Guid>
ChatMessages = new HashSet<ClassChat>(); ChatMessages = new HashSet<ClassChat>();
} }
public void StartClass()
{
if (IsActive)
throw new InvalidOperationException("Class is already active");
IsActive = true;
ActualStartTime = DateTime.UtcNow;
}
public void EndClass()
{
if (!IsActive)
throw new InvalidOperationException("Class is not active");
IsActive = false;
EndTime = DateTime.UtcNow;
}
public bool CanJoin() public bool CanJoin()
{ {
var now = DateTime.UtcNow; var now = DateTime.Now;
var tenMinutesBefore = ScheduledStartTime.AddMinutes(-10); var tenMinutesBefore = ScheduledStartTime.AddMinutes(-10);
var twoHoursAfter = ScheduledStartTime.AddHours(2); var twoHoursAfter = ScheduledStartTime.AddHours(2);

View file

@ -25,7 +25,7 @@ export interface ClassroomDto {
isScheduled: boolean isScheduled: boolean
participantCount: number participantCount: number
canJoin: boolean canJoin: boolean
settings?: ClassroomSettingsDto settingsDto?: ClassroomSettingsDto
} }
export interface ClassroomSettingsDto { export interface ClassroomSettingsDto {

View file

@ -35,3 +35,15 @@ export const deleteClassroom = (id: string) =>
method: 'DELETE', method: 'DELETE',
url: `/api/app/classroom/${id}`, url: `/api/app/classroom/${id}`,
}) })
export const startClassroom = (id: string) =>
apiService.fetchData({
method: 'PUT',
url: `/api/app/${id}/start-classroom`,
})
export const endClassroom = (id: string) =>
apiService.fetchData({
method: 'PUT',
url: `/api/app/${id}/end-classroom`,
})

View file

@ -0,0 +1,7 @@
// Veritabanındaki tarihi olduğu gibi göstermek için yardımcı fonksiyon
export function showDbDateAsIs(dateStr: string) {
if (!dateStr) return ''
// ISO formatı veya '2025-08-27 14:15:00.0000000' gibi formatlar için
// Sadece ilk 19 karakteri (YYYY-MM-DD HH:mm:ss) al
return dateStr.replace('T', ' ').substring(0, 19)
}

View file

@ -1,4 +1,5 @@
import React, { useEffect, useState } from 'react' import React, { useEffect, useState } from 'react'
import { showDbDateAsIs } from '@/utils/dateUtils'
import { useNavigate } from 'react-router-dom' import { useNavigate } from 'react-router-dom'
import { motion } from 'framer-motion' import { motion } from 'framer-motion'
import { import {
@ -20,6 +21,7 @@ import {
createClassroom, createClassroom,
deleteClassroom, deleteClassroom,
getClassrooms, getClassrooms,
startClassroom,
updateClassroom, updateClassroom,
} from '@/services/classroom.service' } from '@/services/classroom.service'
@ -41,7 +43,7 @@ const ClassList: React.FC = () => {
isScheduled: true, isScheduled: true,
participantCount: 0, participantCount: 0,
canJoin: false, canJoin: false,
settings: { settingsDto: {
allowHandRaise: true, allowHandRaise: true,
allowStudentChat: true, allowStudentChat: true,
allowPrivateMessages: true, allowPrivateMessages: true,
@ -67,7 +69,15 @@ const ClassList: React.FC = () => {
maxResultCount, maxResultCount,
}) })
setClassList(result.data.items || []) const items = (result.data.items || []).map((item) => ({
...item,
scheduledStartTime: item.scheduledStartTime
? showDbDateAsIs(item.scheduledStartTime)
: null,
actualStartTime: item.actualStartTime ? showDbDateAsIs(item.actualStartTime) : null,
})) as ClassroomDto[]
setClassList(items)
} catch (error) { } catch (error) {
console.error('Error fetching classrooms:', error) console.error('Error fetching classrooms:', error)
} }
@ -138,17 +148,12 @@ const ClassList: React.FC = () => {
setClassroom(newClassEntity) setClassroom(newClassEntity)
} }
const handleStartClass = (classSession: ClassroomDto) => { const handleStartClass = async (classSession: ClassroomDto) => {
const updatedClass = { await startClassroom(classSession.id!)
...classSession,
isActive: true,
actualStartTime: new Date().toISOString(),
}
getClassroomList() getClassroomList()
if (updatedClass.id) { if (classSession.id) {
navigate(ROUTES_ENUM.protected.admin.classroom.classroom.replace(':id', updatedClass.id)) navigate(ROUTES_ENUM.protected.admin.classroom.classroom.replace(':id', classSession.id))
} }
} }
@ -186,16 +191,6 @@ const ClassList: React.FC = () => {
return `${minutes}d kaldı` return `${minutes}d kaldı`
} }
const formatDateTime = (dateString: string) => {
return new Date(dateString).toLocaleString('tr-TR', {
day: '2-digit',
month: '2-digit',
year: 'numeric',
hour: '2-digit',
minute: '2-digit',
})
}
return ( return (
<Container> <Container>
{/* Main Content */} {/* Main Content */}
@ -377,7 +372,7 @@ const ClassList: React.FC = () => {
<div className="col-span-1 flex items-center gap-2 px-3 py-2 rounded-lg"> <div className="col-span-1 flex items-center gap-2 px-3 py-2 rounded-lg">
<FaCalendarAlt size={14} className="text-gray-500" /> <FaCalendarAlt size={14} className="text-gray-500" />
<span className="truncate"> <span className="truncate">
{formatDateTime(classSession.scheduledStartTime)} {showDbDateAsIs(classSession.scheduledStartTime)}
</span> </span>
</div> </div>
@ -536,12 +531,12 @@ const ClassList: React.FC = () => {
<label className="flex items-center space-x-3"> <label className="flex items-center space-x-3">
<input <input
type="checkbox" type="checkbox"
checked={classroom.settings?.allowHandRaise} checked={classroom.settingsDto?.allowHandRaise}
onChange={(e) => onChange={(e) =>
setClassroom({ setClassroom({
...classroom, ...classroom,
settings: { settingsDto: {
...classroom.settings!, ...classroom.settingsDto!,
allowHandRaise: e.target.checked, allowHandRaise: e.target.checked,
}, },
}) })
@ -553,12 +548,12 @@ const ClassList: React.FC = () => {
<label className="flex items-center space-x-3"> <label className="flex items-center space-x-3">
<input <input
type="checkbox" type="checkbox"
checked={classroom.settings?.allowStudentChat} checked={classroom.settingsDto?.allowStudentChat}
onChange={(e) => onChange={(e) =>
setClassroom({ setClassroom({
...classroom, ...classroom,
settings: { settingsDto: {
...classroom.settings!, ...classroom.settingsDto!,
allowStudentChat: e.target.checked, allowStudentChat: e.target.checked,
}, },
}) })
@ -570,12 +565,12 @@ const ClassList: React.FC = () => {
<label className="flex items-center space-x-3"> <label className="flex items-center space-x-3">
<input <input
type="checkbox" type="checkbox"
checked={classroom.settings?.allowPrivateMessages} checked={classroom.settingsDto?.allowPrivateMessages}
onChange={(e) => onChange={(e) =>
setClassroom({ setClassroom({
...classroom, ...classroom,
settings: { settingsDto: {
...classroom.settings!, ...classroom.settingsDto!,
allowPrivateMessages: e.target.checked, allowPrivateMessages: e.target.checked,
}, },
}) })
@ -587,12 +582,12 @@ const ClassList: React.FC = () => {
<label className="flex items-center space-x-3"> <label className="flex items-center space-x-3">
<input <input
type="checkbox" type="checkbox"
checked={classroom.settings?.allowStudentScreenShare} checked={classroom.settingsDto?.allowStudentScreenShare}
onChange={(e) => onChange={(e) =>
setClassroom({ setClassroom({
...classroom, ...classroom,
settings: { settingsDto: {
...classroom.settings!, ...classroom.settingsDto!,
allowStudentScreenShare: e.target.checked, allowStudentScreenShare: e.target.checked,
}, },
}) })
@ -611,12 +606,12 @@ const ClassList: React.FC = () => {
Varsayılan mikrofon durumu Varsayılan mikrofon durumu
</label> </label>
<select <select
value={classroom.settings?.defaultMicrophoneState} value={classroom.settingsDto?.defaultMicrophoneState}
onChange={(e) => onChange={(e) =>
setClassroom({ setClassroom({
...classroom, ...classroom,
settings: { settingsDto: {
...classroom.settings!, ...classroom.settingsDto!,
defaultMicrophoneState: e.target.value as 'muted' | 'unmuted', defaultMicrophoneState: e.target.value as 'muted' | 'unmuted',
}, },
}) })
@ -633,12 +628,12 @@ const ClassList: React.FC = () => {
Varsayılan kamera durumu Varsayılan kamera durumu
</label> </label>
<select <select
value={classroom.settings?.defaultCameraState} value={classroom.settingsDto?.defaultCameraState}
onChange={(e) => onChange={(e) =>
setClassroom({ setClassroom({
...classroom, ...classroom,
settings: { settingsDto: {
...classroom.settings!, ...classroom.settingsDto!,
defaultCameraState: e.target.value as 'on' | 'off', defaultCameraState: e.target.value as 'on' | 'off',
}, },
}) })
@ -655,12 +650,12 @@ const ClassList: React.FC = () => {
Varsayılan layout Varsayılan layout
</label> </label>
<select <select
value={classroom.settings?.defaultLayout} value={classroom.settingsDto?.defaultLayout}
onChange={(e) => onChange={(e) =>
setClassroom({ setClassroom({
...classroom, ...classroom,
settings: { settingsDto: {
...classroom.settings!, ...classroom.settingsDto!,
defaultLayout: e.target.value, defaultLayout: e.target.value,
}, },
}) })
@ -677,12 +672,12 @@ const ClassList: React.FC = () => {
<label className="flex items-center space-x-3"> <label className="flex items-center space-x-3">
<input <input
type="checkbox" type="checkbox"
checked={classroom.settings?.autoMuteNewParticipants} checked={classroom.settingsDto?.autoMuteNewParticipants}
onChange={(e) => onChange={(e) =>
setClassroom({ setClassroom({
...classroom, ...classroom,
settings: { settingsDto: {
...classroom.settings!, ...classroom.settingsDto!,
autoMuteNewParticipants: e.target.checked, autoMuteNewParticipants: e.target.checked,
}, },
}) })
@ -699,7 +694,10 @@ const ClassList: React.FC = () => {
<button <button
type="button" type="button"
onClick={() => { onClick={() => {
if (showCreateModal) setShowCreateModal(false) if (showCreateModal) {
setShowCreateModal(false)
}
if (showEditModal) { if (showEditModal) {
setShowEditModal(false) setShowEditModal(false)
setClassroom(newClassEntity) setClassroom(newClassEntity)

View file

@ -54,6 +54,7 @@ import { ScreenSharePanel } from '@/components/classroom/Panels/ScreenSharePanel
import { KickParticipantModal } from '@/components/classroom/KickParticipantModal' import { KickParticipantModal } from '@/components/classroom/KickParticipantModal'
import { useParams } from 'react-router-dom' import { useParams } from 'react-router-dom'
import { getClassroomById } from '@/services/classroom.service' import { getClassroomById } from '@/services/classroom.service'
import { showDbDateAsIs } from '@/utils/dateUtils'
type SidePanelType = type SidePanelType =
| 'chat' | 'chat'
@ -129,7 +130,7 @@ const RoomDetail: React.FC = () => {
allowStudentScreenShare: false, allowStudentScreenShare: false,
allowStudentChat: true, allowStudentChat: true,
allowPrivateMessages: true, allowPrivateMessages: true,
autoMuteNewParticipants: true autoMuteNewParticipants: true,
}) })
const signalRServiceRef = useRef<SignalRService>() const signalRServiceRef = useRef<SignalRService>()
@ -192,6 +193,7 @@ const RoomDetail: React.FC = () => {
//ClassEntity //ClassEntity
const classEntity = await getClassroomById(params?.id ?? '') const classEntity = await getClassroomById(params?.id ?? '')
if (classEntity) { if (classEntity) {
classEntity.data.scheduledStartTime = showDbDateAsIs(classEntity.data.scheduledStartTime)
setClassSession(classEntity.data) setClassSession(classEntity.data)
} }

View file

@ -1,6 +1,6 @@
import Card from '@/components/ui/Card' import Card from '@/components/ui/Card'
import GrowShrinkTag from '@/components/shared/GrowShrinkTag' import GrowShrinkTag from '@/components/shared/GrowShrinkTag'
import dayjs from 'dayjs' import { showDbDateAsIs } from '@/utils/dateUtils'
const Widget = ({ const Widget = ({
label, label,
@ -11,25 +11,25 @@ const Widget = ({
}: { }: {
label: string label: string
datavalue: number datavalue: number
datagrowShrink: number, datagrowShrink: number
valuePrefix: string valuePrefix: string
date: Date date: string
}) => { }) => {
return ( return (
<Card> <Card>
<h6 className="font-semibold mb-4 text-sm">{label}</h6> <h6 className="font-semibold mb-4 text-sm">{label}</h6>
<div className="flex justify-between items-center"> <div className="flex justify-between items-center">
<div> <div>
<h3 className="font-bold">{datavalue} {valuePrefix}</h3> <h3 className="font-bold">
<p> {datavalue} {valuePrefix}
<span className="font-semibold"> </h3>
{dayjs(date).format('DD MMM')} <p>
</span> <span className="font-semibold">{showDbDateAsIs(date)}</span>
</p> </p>
</div> </div>
<GrowShrinkTag value={datagrowShrink} suffix="%" /> <GrowShrinkTag value={datagrowShrink} suffix="%" />
</div> </div>
</Card> </Card>
) )
} }

View file

@ -1,5 +1,13 @@
import React, { useState } from 'react' import React, { useState } from 'react'
import { FaPlus, FaEdit, FaTrashAlt, FaCheckCircle, FaCircle, FaHeart, FaSpinner } from 'react-icons/fa'; import {
FaPlus,
FaEdit,
FaTrashAlt,
FaCheckCircle,
FaCircle,
FaHeart,
FaSpinner,
} from 'react-icons/fa'
import { ForumPost, ForumTopic } from '@/proxy/forum/forum' import { ForumPost, ForumTopic } from '@/proxy/forum/forum'
import { HtmlEditor, ImageUpload, Item, MediaResizing, Toolbar } from 'devextreme-react/html-editor' import { HtmlEditor, ImageUpload, Item, MediaResizing, Toolbar } from 'devextreme-react/html-editor'
import { useStoreState } from '@/store/store' import { useStoreState } from '@/store/store'
@ -8,6 +16,7 @@ import { Formik, Form, Field, FieldProps } from 'formik'
import * as Yup from 'yup' import * as Yup from 'yup'
import { FormContainer, FormItem, Button } from '@/components/ui' import { FormContainer, FormItem, Button } from '@/components/ui'
import { ConfirmDialog } from '@/components/shared' import { ConfirmDialog } from '@/components/shared'
import { showDbDateAsIs } from '@/utils/dateUtils'
import { import {
fontFamilyOptions, fontFamilyOptions,
fontSizeOptions, fontSizeOptions,
@ -136,16 +145,7 @@ export function PostManagement({
} }
const formatDate = (value: string | Date) => { const formatDate = (value: string | Date) => {
const date = value instanceof Date ? value : new Date(value) return showDbDateAsIs(typeof value === 'string' ? value : value.toISOString())
if (isNaN(date.getTime())) return 'Invalid Date'
return new Intl.DateTimeFormat('en', {
year: 'numeric',
month: 'short',
day: 'numeric',
hour: '2-digit',
minute: '2-digit',
}).format(date)
} }
const postValidationSchema = Yup.object().shape({ const postValidationSchema = Yup.object().shape({

View file

@ -19,6 +19,7 @@ import { Formik, Form, Field } from 'formik'
import * as Yup from 'yup' import * as Yup from 'yup'
import { FormContainer, FormItem, Button } from '@/components/ui' import { FormContainer, FormItem, Button } from '@/components/ui'
import { ConfirmDialog } from '@/components/shared' import { ConfirmDialog } from '@/components/shared'
import { showDbDateAsIs } from '@/utils/dateUtils'
interface TopicManagementProps { interface TopicManagementProps {
topics: ForumTopic[] topics: ForumTopic[]
@ -180,16 +181,7 @@ export function TopicManagement({
} }
const formatDate = (value: string | Date) => { const formatDate = (value: string | Date) => {
const date = value instanceof Date ? value : new Date(value) return showDbDateAsIs(typeof value === 'string' ? value : value.toISOString())
if (isNaN(date.getTime())) return 'Invalid Date'
return new Intl.DateTimeFormat('en', {
year: 'numeric',
month: 'short',
day: 'numeric',
hour: '2-digit',
minute: '2-digit',
}).format(date)
} }
const topicInitialValues = { const topicInitialValues = {

View file

@ -1,8 +1,9 @@
import React from 'react' import React from 'react'
import { FaHeart, FaCheckCircle, FaReply } from 'react-icons/fa'; import { FaHeart, FaCheckCircle, FaReply } from 'react-icons/fa'
import { ForumPost } from '@/proxy/forum/forum' import { ForumPost } from '@/proxy/forum/forum'
import { AVATAR_URL } from '@/constants/app.constant' import { AVATAR_URL } from '@/constants/app.constant'
import { useLocalization } from '@/utils/hooks/useLocalization' import { useLocalization } from '@/utils/hooks/useLocalization'
import { showDbDateAsIs } from '@/utils/dateUtils'
interface PostCardProps { interface PostCardProps {
post: ForumPost post: ForumPost
@ -21,16 +22,7 @@ export function ForumPostCard({
}: PostCardProps) { }: PostCardProps) {
const { translate } = useLocalization() const { translate } = useLocalization()
const formatDate = (value: string | Date) => { const formatDate = (value: string | Date) => {
const date = value instanceof Date ? value : new Date(value) return showDbDateAsIs(typeof value === 'string' ? value : value.toISOString())
if (isNaN(date.getTime())) return 'Invalid Date'
return new Intl.DateTimeFormat('en', {
year: 'numeric',
month: 'short',
day: 'numeric',
hour: '2-digit',
minute: '2-digit',
}).format(date)
} }
return ( return (

View file

@ -1,6 +1,7 @@
import React, { useState, useEffect } from 'react' import React, { useState, useEffect } from 'react'
import { FaTimes, FaSearch, FaFolder, FaRegComment, FaFileAlt } from 'react-icons/fa' import { FaTimes, FaSearch, FaFolder, FaRegComment, FaFileAlt } from 'react-icons/fa'
import { ForumCategory, ForumPost, ForumTopic } from '@/proxy/forum/forum' import { ForumCategory, ForumPost, ForumTopic } from '@/proxy/forum/forum'
import { showDbDateAsIs } from '@/utils/dateUtils'
import { useForumSearch } from '@/utils/hooks/useForumSearch' import { useForumSearch } from '@/utils/hooks/useForumSearch'
interface SearchModalProps { interface SearchModalProps {
@ -84,16 +85,7 @@ export function SearchModal({
} }
const formatDate = (value: string | Date) => { const formatDate = (value: string | Date) => {
const date = value instanceof Date ? value : new Date(value) return showDbDateAsIs(typeof value === 'string' ? value : value.toISOString())
if (isNaN(date.getTime())) return 'Invalid Date'
return new Intl.DateTimeFormat('en', {
year: 'numeric',
month: 'short',
day: 'numeric',
hour: '2-digit',
minute: '2-digit',
}).format(date)
} }
const getTopicTitle = (topicId: string) => { const getTopicTitle = (topicId: string) => {

View file

@ -1,8 +1,7 @@
import React, { useEffect, useState } from 'react' import React, { useEffect, useState } from 'react'
import { Link } from 'react-router-dom' import { Link } from 'react-router-dom'
import { FaCalendarAlt, FaUser, FaTag, FaSearch } from 'react-icons/fa' import { FaCalendarAlt, FaUser, FaTag, FaSearch } from 'react-icons/fa'
import dayjs from 'dayjs' import { showDbDateAsIs } from '@/utils/dateUtils'
import 'dayjs/locale/tr'
import { BlogCategory, BlogPost } from '@/proxy/blog/blog' import { BlogCategory, BlogPost } from '@/proxy/blog/blog'
import { blogService } from '@/services/blog.service' import { blogService } from '@/services/blog.service'
import { useLocalization } from '@/utils/hooks/useLocalization' import { useLocalization } from '@/utils/hooks/useLocalization'
@ -19,8 +18,6 @@ const Blog = () => {
const [currentPage, setCurrentPage] = useState(1) const [currentPage, setCurrentPage] = useState(1)
const [totalPages, setTotalPages] = useState(1) const [totalPages, setTotalPages] = useState(1)
dayjs.locale('tr')
useEffect(() => { useEffect(() => {
loadBlogData() loadBlogData()
}, [currentPage, selectedCategory]) }, [currentPage, selectedCategory])
@ -200,7 +197,7 @@ const Blog = () => {
</div> </div>
<div className="flex items-center"> <div className="flex items-center">
<FaCalendarAlt size={16} className="mr-1" /> <FaCalendarAlt size={16} className="mr-1" />
{dayjs(post.publishedAt || post.creationTime).format('DD MMM YYYY')} {showDbDateAsIs(post.publishedAt || post.creationTime)}
</div> </div>
</div> </div>
</div> </div>

View file

@ -1,7 +1,6 @@
import React, { useState, useEffect } from 'react' import React, { useState, useEffect } from 'react'
import { Link, useParams } from 'react-router-dom' import { Link, useParams } from 'react-router-dom'
import dayjs from 'dayjs' import { showDbDateAsIs } from '@/utils/dateUtils'
import 'dayjs/locale/tr'
import { BlogPost } from '@/proxy/blog/blog' import { BlogPost } from '@/proxy/blog/blog'
import { blogService } from '@/services/blog.service' import { blogService } from '@/services/blog.service'
import { useLocalization } from '@/utils/hooks/useLocalization' import { useLocalization } from '@/utils/hooks/useLocalization'
@ -28,8 +27,6 @@ const BlogDetail: React.FC = () => {
const [loading, setLoading] = useState(true) const [loading, setLoading] = useState(true)
const [error, setError] = useState<string | null>(null) const [error, setError] = useState<string | null>(null)
dayjs.locale('tr')
useEffect(() => { useEffect(() => {
const fetchBlogPost = async () => { const fetchBlogPost = async () => {
setLoading(true) setLoading(true)
@ -111,7 +108,7 @@ const BlogDetail: React.FC = () => {
<span>{postData.author?.name}</span> <span>{postData.author?.name}</span>
</div> </div>
<div className="flex items-center"> <div className="flex items-center">
{blogPost.publishedAt && dayjs(blogPost.publishedAt).format('DD MMM YYYY')} {blogPost.publishedAt && showDbDateAsIs(blogPost.publishedAt)}
</div> </div>
</div> </div>
<div <div