Classroom
This commit is contained in:
parent
7e402d352c
commit
76615b074b
15 changed files with 133 additions and 143 deletions
|
|
@ -13,8 +13,8 @@ public interface IClassroomAppService : IApplicationService
|
|||
Task<ClassroomDto> GetAsync(Guid id);
|
||||
Task<ClassroomDto> UpdateAsync(Guid id, ClassroomDto input);
|
||||
Task DeleteAsync(Guid id);
|
||||
Task<ClassroomDto> StartClassAsync(Guid id);
|
||||
Task EndClassAsync(Guid id);
|
||||
// Task<ClassroomDto> StartClassAsync(Guid id);
|
||||
// Task EndClassAsync(Guid id);
|
||||
Task<ClassroomDto> JoinClassAsync(Guid id);
|
||||
Task LeaveClassAsync(Guid id);
|
||||
Task<List<ClassAttendanceDto>> GetAttendanceAsync(Guid sessionId);
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ using System.Text.Json;
|
|||
using System.Threading.Tasks;
|
||||
using Kurs.Platform.Entities;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Volo.Abp.Application.Dtos;
|
||||
using Volo.Abp.Domain.Repositories;
|
||||
|
||||
|
|
@ -88,9 +89,15 @@ public class ClassroomAppService : PlatformAppService, IClassroomAppService
|
|||
classSession.Name = input.Name;
|
||||
classSession.Description = input.Description;
|
||||
classSession.Subject = input.Subject;
|
||||
classSession.TeacherId = input.TeacherId;
|
||||
classSession.TeacherName = input.TeacherName;
|
||||
classSession.ScheduledStartTime = input.ScheduledStartTime;
|
||||
classSession.ActualStartTime = input.ActualStartTime;
|
||||
classSession.Duration = input.Duration;
|
||||
classSession.MaxParticipants = input.MaxParticipants;
|
||||
classSession.IsActive = input.IsActive;
|
||||
classSession.IsScheduled = input.IsScheduled;
|
||||
classSession.SettingsJson = JsonSerializer.Serialize(input.SettingsDto);
|
||||
|
||||
await _classSessionRepository.UpdateAsync(classSession);
|
||||
return ObjectMapper.Map<Classroom, ClassroomDto>(classSession);
|
||||
|
|
@ -113,7 +120,8 @@ public class ClassroomAppService : PlatformAppService, IClassroomAppService
|
|||
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);
|
||||
|
||||
|
|
@ -127,13 +135,19 @@ public class ClassroomAppService : PlatformAppService, IClassroomAppService
|
|||
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);
|
||||
|
||||
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);
|
||||
|
||||
|
|
@ -142,7 +156,12 @@ public class ClassroomAppService : PlatformAppService, IClassroomAppService
|
|||
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);
|
||||
|
||||
// Update attendance records
|
||||
|
|
|
|||
|
|
@ -64,27 +64,9 @@ public class Classroom : FullAuditedEntity<Guid>
|
|||
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()
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
var now = DateTime.Now;
|
||||
var tenMinutesBefore = ScheduledStartTime.AddMinutes(-10);
|
||||
var twoHoursAfter = ScheduledStartTime.AddHours(2);
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ export interface ClassroomDto {
|
|||
isScheduled: boolean
|
||||
participantCount: number
|
||||
canJoin: boolean
|
||||
settings?: ClassroomSettingsDto
|
||||
settingsDto?: ClassroomSettingsDto
|
||||
}
|
||||
|
||||
export interface ClassroomSettingsDto {
|
||||
|
|
|
|||
|
|
@ -35,3 +35,15 @@ export const deleteClassroom = (id: string) =>
|
|||
method: 'DELETE',
|
||||
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`,
|
||||
})
|
||||
|
|
|
|||
7
ui/src/utils/dateUtils.ts
Normal file
7
ui/src/utils/dateUtils.ts
Normal 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)
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
import React, { useEffect, useState } from 'react'
|
||||
import { showDbDateAsIs } from '@/utils/dateUtils'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { motion } from 'framer-motion'
|
||||
import {
|
||||
|
|
@ -20,6 +21,7 @@ import {
|
|||
createClassroom,
|
||||
deleteClassroom,
|
||||
getClassrooms,
|
||||
startClassroom,
|
||||
updateClassroom,
|
||||
} from '@/services/classroom.service'
|
||||
|
||||
|
|
@ -41,7 +43,7 @@ const ClassList: React.FC = () => {
|
|||
isScheduled: true,
|
||||
participantCount: 0,
|
||||
canJoin: false,
|
||||
settings: {
|
||||
settingsDto: {
|
||||
allowHandRaise: true,
|
||||
allowStudentChat: true,
|
||||
allowPrivateMessages: true,
|
||||
|
|
@ -67,7 +69,15 @@ const ClassList: React.FC = () => {
|
|||
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) {
|
||||
console.error('Error fetching classrooms:', error)
|
||||
}
|
||||
|
|
@ -138,17 +148,12 @@ const ClassList: React.FC = () => {
|
|||
setClassroom(newClassEntity)
|
||||
}
|
||||
|
||||
const handleStartClass = (classSession: ClassroomDto) => {
|
||||
const updatedClass = {
|
||||
...classSession,
|
||||
isActive: true,
|
||||
actualStartTime: new Date().toISOString(),
|
||||
}
|
||||
|
||||
const handleStartClass = async (classSession: ClassroomDto) => {
|
||||
await startClassroom(classSession.id!)
|
||||
getClassroomList()
|
||||
|
||||
if (updatedClass.id) {
|
||||
navigate(ROUTES_ENUM.protected.admin.classroom.classroom.replace(':id', updatedClass.id))
|
||||
if (classSession.id) {
|
||||
navigate(ROUTES_ENUM.protected.admin.classroom.classroom.replace(':id', classSession.id))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -186,16 +191,6 @@ const ClassList: React.FC = () => {
|
|||
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 (
|
||||
<Container>
|
||||
{/* 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">
|
||||
<FaCalendarAlt size={14} className="text-gray-500" />
|
||||
<span className="truncate">
|
||||
{formatDateTime(classSession.scheduledStartTime)}
|
||||
{showDbDateAsIs(classSession.scheduledStartTime)}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
|
@ -536,12 +531,12 @@ const ClassList: React.FC = () => {
|
|||
<label className="flex items-center space-x-3">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={classroom.settings?.allowHandRaise}
|
||||
checked={classroom.settingsDto?.allowHandRaise}
|
||||
onChange={(e) =>
|
||||
setClassroom({
|
||||
...classroom,
|
||||
settings: {
|
||||
...classroom.settings!,
|
||||
settingsDto: {
|
||||
...classroom.settingsDto!,
|
||||
allowHandRaise: e.target.checked,
|
||||
},
|
||||
})
|
||||
|
|
@ -553,12 +548,12 @@ const ClassList: React.FC = () => {
|
|||
<label className="flex items-center space-x-3">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={classroom.settings?.allowStudentChat}
|
||||
checked={classroom.settingsDto?.allowStudentChat}
|
||||
onChange={(e) =>
|
||||
setClassroom({
|
||||
...classroom,
|
||||
settings: {
|
||||
...classroom.settings!,
|
||||
settingsDto: {
|
||||
...classroom.settingsDto!,
|
||||
allowStudentChat: e.target.checked,
|
||||
},
|
||||
})
|
||||
|
|
@ -570,12 +565,12 @@ const ClassList: React.FC = () => {
|
|||
<label className="flex items-center space-x-3">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={classroom.settings?.allowPrivateMessages}
|
||||
checked={classroom.settingsDto?.allowPrivateMessages}
|
||||
onChange={(e) =>
|
||||
setClassroom({
|
||||
...classroom,
|
||||
settings: {
|
||||
...classroom.settings!,
|
||||
settingsDto: {
|
||||
...classroom.settingsDto!,
|
||||
allowPrivateMessages: e.target.checked,
|
||||
},
|
||||
})
|
||||
|
|
@ -587,12 +582,12 @@ const ClassList: React.FC = () => {
|
|||
<label className="flex items-center space-x-3">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={classroom.settings?.allowStudentScreenShare}
|
||||
checked={classroom.settingsDto?.allowStudentScreenShare}
|
||||
onChange={(e) =>
|
||||
setClassroom({
|
||||
...classroom,
|
||||
settings: {
|
||||
...classroom.settings!,
|
||||
settingsDto: {
|
||||
...classroom.settingsDto!,
|
||||
allowStudentScreenShare: e.target.checked,
|
||||
},
|
||||
})
|
||||
|
|
@ -611,12 +606,12 @@ const ClassList: React.FC = () => {
|
|||
Varsayılan mikrofon durumu
|
||||
</label>
|
||||
<select
|
||||
value={classroom.settings?.defaultMicrophoneState}
|
||||
value={classroom.settingsDto?.defaultMicrophoneState}
|
||||
onChange={(e) =>
|
||||
setClassroom({
|
||||
...classroom,
|
||||
settings: {
|
||||
...classroom.settings!,
|
||||
settingsDto: {
|
||||
...classroom.settingsDto!,
|
||||
defaultMicrophoneState: e.target.value as 'muted' | 'unmuted',
|
||||
},
|
||||
})
|
||||
|
|
@ -633,12 +628,12 @@ const ClassList: React.FC = () => {
|
|||
Varsayılan kamera durumu
|
||||
</label>
|
||||
<select
|
||||
value={classroom.settings?.defaultCameraState}
|
||||
value={classroom.settingsDto?.defaultCameraState}
|
||||
onChange={(e) =>
|
||||
setClassroom({
|
||||
...classroom,
|
||||
settings: {
|
||||
...classroom.settings!,
|
||||
settingsDto: {
|
||||
...classroom.settingsDto!,
|
||||
defaultCameraState: e.target.value as 'on' | 'off',
|
||||
},
|
||||
})
|
||||
|
|
@ -655,12 +650,12 @@ const ClassList: React.FC = () => {
|
|||
Varsayılan layout
|
||||
</label>
|
||||
<select
|
||||
value={classroom.settings?.defaultLayout}
|
||||
value={classroom.settingsDto?.defaultLayout}
|
||||
onChange={(e) =>
|
||||
setClassroom({
|
||||
...classroom,
|
||||
settings: {
|
||||
...classroom.settings!,
|
||||
settingsDto: {
|
||||
...classroom.settingsDto!,
|
||||
defaultLayout: e.target.value,
|
||||
},
|
||||
})
|
||||
|
|
@ -677,12 +672,12 @@ const ClassList: React.FC = () => {
|
|||
<label className="flex items-center space-x-3">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={classroom.settings?.autoMuteNewParticipants}
|
||||
checked={classroom.settingsDto?.autoMuteNewParticipants}
|
||||
onChange={(e) =>
|
||||
setClassroom({
|
||||
...classroom,
|
||||
settings: {
|
||||
...classroom.settings!,
|
||||
settingsDto: {
|
||||
...classroom.settingsDto!,
|
||||
autoMuteNewParticipants: e.target.checked,
|
||||
},
|
||||
})
|
||||
|
|
@ -699,7 +694,10 @@ const ClassList: React.FC = () => {
|
|||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
if (showCreateModal) setShowCreateModal(false)
|
||||
if (showCreateModal) {
|
||||
setShowCreateModal(false)
|
||||
}
|
||||
|
||||
if (showEditModal) {
|
||||
setShowEditModal(false)
|
||||
setClassroom(newClassEntity)
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ import { ScreenSharePanel } from '@/components/classroom/Panels/ScreenSharePanel
|
|||
import { KickParticipantModal } from '@/components/classroom/KickParticipantModal'
|
||||
import { useParams } from 'react-router-dom'
|
||||
import { getClassroomById } from '@/services/classroom.service'
|
||||
import { showDbDateAsIs } from '@/utils/dateUtils'
|
||||
|
||||
type SidePanelType =
|
||||
| 'chat'
|
||||
|
|
@ -129,7 +130,7 @@ const RoomDetail: React.FC = () => {
|
|||
allowStudentScreenShare: false,
|
||||
allowStudentChat: true,
|
||||
allowPrivateMessages: true,
|
||||
autoMuteNewParticipants: true
|
||||
autoMuteNewParticipants: true,
|
||||
})
|
||||
|
||||
const signalRServiceRef = useRef<SignalRService>()
|
||||
|
|
@ -192,6 +193,7 @@ const RoomDetail: React.FC = () => {
|
|||
//ClassEntity
|
||||
const classEntity = await getClassroomById(params?.id ?? '')
|
||||
if (classEntity) {
|
||||
classEntity.data.scheduledStartTime = showDbDateAsIs(classEntity.data.scheduledStartTime)
|
||||
setClassSession(classEntity.data)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import Card from '@/components/ui/Card'
|
||||
import GrowShrinkTag from '@/components/shared/GrowShrinkTag'
|
||||
import dayjs from 'dayjs'
|
||||
import { showDbDateAsIs } from '@/utils/dateUtils'
|
||||
|
||||
const Widget = ({
|
||||
label,
|
||||
|
|
@ -11,25 +11,25 @@ const Widget = ({
|
|||
}: {
|
||||
label: string
|
||||
datavalue: number
|
||||
datagrowShrink: number,
|
||||
datagrowShrink: number
|
||||
valuePrefix: string
|
||||
date: Date
|
||||
date: string
|
||||
}) => {
|
||||
return (
|
||||
<Card>
|
||||
<h6 className="font-semibold mb-4 text-sm">{label}</h6>
|
||||
<div className="flex justify-between items-center">
|
||||
<div>
|
||||
<h3 className="font-bold">{datavalue} {valuePrefix}</h3>
|
||||
<p>
|
||||
<span className="font-semibold">
|
||||
{dayjs(date).format('DD MMM')}
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
<GrowShrinkTag value={datagrowShrink} suffix="%" />
|
||||
</div>
|
||||
</Card>
|
||||
<Card>
|
||||
<h6 className="font-semibold mb-4 text-sm">{label}</h6>
|
||||
<div className="flex justify-between items-center">
|
||||
<div>
|
||||
<h3 className="font-bold">
|
||||
{datavalue} {valuePrefix}
|
||||
</h3>
|
||||
<p>
|
||||
<span className="font-semibold">{showDbDateAsIs(date)}</span>
|
||||
</p>
|
||||
</div>
|
||||
<GrowShrinkTag value={datagrowShrink} suffix="%" />
|
||||
</div>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,13 @@
|
|||
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 { HtmlEditor, ImageUpload, Item, MediaResizing, Toolbar } from 'devextreme-react/html-editor'
|
||||
import { useStoreState } from '@/store/store'
|
||||
|
|
@ -8,6 +16,7 @@ import { Formik, Form, Field, FieldProps } from 'formik'
|
|||
import * as Yup from 'yup'
|
||||
import { FormContainer, FormItem, Button } from '@/components/ui'
|
||||
import { ConfirmDialog } from '@/components/shared'
|
||||
import { showDbDateAsIs } from '@/utils/dateUtils'
|
||||
import {
|
||||
fontFamilyOptions,
|
||||
fontSizeOptions,
|
||||
|
|
@ -136,16 +145,7 @@ export function PostManagement({
|
|||
}
|
||||
|
||||
const formatDate = (value: string | Date) => {
|
||||
const date = value instanceof Date ? value : new Date(value)
|
||||
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 showDbDateAsIs(typeof value === 'string' ? value : value.toISOString())
|
||||
}
|
||||
|
||||
const postValidationSchema = Yup.object().shape({
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import { Formik, Form, Field } from 'formik'
|
|||
import * as Yup from 'yup'
|
||||
import { FormContainer, FormItem, Button } from '@/components/ui'
|
||||
import { ConfirmDialog } from '@/components/shared'
|
||||
import { showDbDateAsIs } from '@/utils/dateUtils'
|
||||
|
||||
interface TopicManagementProps {
|
||||
topics: ForumTopic[]
|
||||
|
|
@ -180,16 +181,7 @@ export function TopicManagement({
|
|||
}
|
||||
|
||||
const formatDate = (value: string | Date) => {
|
||||
const date = value instanceof Date ? value : new Date(value)
|
||||
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 showDbDateAsIs(typeof value === 'string' ? value : value.toISOString())
|
||||
}
|
||||
|
||||
const topicInitialValues = {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
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 { AVATAR_URL } from '@/constants/app.constant'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
import { showDbDateAsIs } from '@/utils/dateUtils'
|
||||
|
||||
interface PostCardProps {
|
||||
post: ForumPost
|
||||
|
|
@ -21,16 +22,7 @@ export function ForumPostCard({
|
|||
}: PostCardProps) {
|
||||
const { translate } = useLocalization()
|
||||
const formatDate = (value: string | Date) => {
|
||||
const date = value instanceof Date ? value : new Date(value)
|
||||
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 showDbDateAsIs(typeof value === 'string' ? value : value.toISOString())
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import React, { useState, useEffect } from 'react'
|
||||
import { FaTimes, FaSearch, FaFolder, FaRegComment, FaFileAlt } from 'react-icons/fa'
|
||||
import { ForumCategory, ForumPost, ForumTopic } from '@/proxy/forum/forum'
|
||||
import { showDbDateAsIs } from '@/utils/dateUtils'
|
||||
import { useForumSearch } from '@/utils/hooks/useForumSearch'
|
||||
|
||||
interface SearchModalProps {
|
||||
|
|
@ -84,16 +85,7 @@ export function SearchModal({
|
|||
}
|
||||
|
||||
const formatDate = (value: string | Date) => {
|
||||
const date = value instanceof Date ? value : new Date(value)
|
||||
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 showDbDateAsIs(typeof value === 'string' ? value : value.toISOString())
|
||||
}
|
||||
|
||||
const getTopicTitle = (topicId: string) => {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
import React, { useEffect, useState } from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { FaCalendarAlt, FaUser, FaTag, FaSearch } from 'react-icons/fa'
|
||||
import dayjs from 'dayjs'
|
||||
import 'dayjs/locale/tr'
|
||||
import { showDbDateAsIs } from '@/utils/dateUtils'
|
||||
import { BlogCategory, BlogPost } from '@/proxy/blog/blog'
|
||||
import { blogService } from '@/services/blog.service'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
|
|
@ -19,8 +18,6 @@ const Blog = () => {
|
|||
const [currentPage, setCurrentPage] = useState(1)
|
||||
const [totalPages, setTotalPages] = useState(1)
|
||||
|
||||
dayjs.locale('tr')
|
||||
|
||||
useEffect(() => {
|
||||
loadBlogData()
|
||||
}, [currentPage, selectedCategory])
|
||||
|
|
@ -200,7 +197,7 @@ const Blog = () => {
|
|||
</div>
|
||||
<div className="flex items-center">
|
||||
<FaCalendarAlt size={16} className="mr-1" />
|
||||
{dayjs(post.publishedAt || post.creationTime).format('DD MMM YYYY')}
|
||||
{showDbDateAsIs(post.publishedAt || post.creationTime)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import React, { useState, useEffect } from 'react'
|
||||
import { Link, useParams } from 'react-router-dom'
|
||||
import dayjs from 'dayjs'
|
||||
import 'dayjs/locale/tr'
|
||||
import { showDbDateAsIs } from '@/utils/dateUtils'
|
||||
import { BlogPost } from '@/proxy/blog/blog'
|
||||
import { blogService } from '@/services/blog.service'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
|
|
@ -28,8 +27,6 @@ const BlogDetail: React.FC = () => {
|
|||
const [loading, setLoading] = useState(true)
|
||||
const [error, setError] = useState<string | null>(null)
|
||||
|
||||
dayjs.locale('tr')
|
||||
|
||||
useEffect(() => {
|
||||
const fetchBlogPost = async () => {
|
||||
setLoading(true)
|
||||
|
|
@ -111,7 +108,7 @@ const BlogDetail: React.FC = () => {
|
|||
<span>{postData.author?.name}</span>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
{blogPost.publishedAt && dayjs(blogPost.publishedAt).format('DD MMM YYYY')}
|
||||
{blogPost.publishedAt && showDbDateAsIs(blogPost.publishedAt)}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
|
|
|
|||
Loading…
Reference in a new issue