Classroom Search
This commit is contained in:
parent
0b60f006d0
commit
51f2c976bf
6 changed files with 102 additions and 14 deletions
|
|
@ -0,0 +1,7 @@
|
||||||
|
using Volo.Abp.Application.Dtos;
|
||||||
|
|
||||||
|
public class ClassroomFilterInputDto : PagedAndSortedResultRequestDto
|
||||||
|
{
|
||||||
|
public string Search { get; set; }
|
||||||
|
public string Status { get; set; }
|
||||||
|
}
|
||||||
|
|
@ -9,7 +9,7 @@ namespace Kurs.Platform.Classrooms;
|
||||||
public interface IClassroomAppService : IApplicationService
|
public interface IClassroomAppService : IApplicationService
|
||||||
{
|
{
|
||||||
Task<ClassroomDto> GetAsync(Guid id);
|
Task<ClassroomDto> GetAsync(Guid id);
|
||||||
Task<PagedResultDto<ClassroomDto>> GetListAsync(PagedAndSortedResultRequestDto input);
|
Task<PagedResultDto<ClassroomDto>> GetListAsync(ClassroomFilterInputDto input);
|
||||||
Task<ClassroomDto> CreateAsync(ClassroomDto input);
|
Task<ClassroomDto> CreateAsync(ClassroomDto input);
|
||||||
Task<ClassroomDto> UpdateAsync(Guid id, ClassroomDto input);
|
Task<ClassroomDto> UpdateAsync(Guid id, ClassroomDto input);
|
||||||
Task DeleteAsync(Guid id);
|
Task DeleteAsync(Guid id);
|
||||||
|
|
|
||||||
|
|
@ -34,9 +34,39 @@ public class ClassroomAppService : PlatformAppService, IClassroomAppService
|
||||||
return ObjectMapper.Map<Classroom, ClassroomDto>(classSession);
|
return ObjectMapper.Map<Classroom, ClassroomDto>(classSession);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<PagedResultDto<ClassroomDto>> GetListAsync(PagedAndSortedResultRequestDto input)
|
public async Task<PagedResultDto<ClassroomDto>> GetListAsync(ClassroomFilterInputDto input)
|
||||||
{
|
{
|
||||||
var query = await _classSessionRepository.GetQueryableAsync();
|
var query = await _classSessionRepository.GetQueryableAsync();
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(input.Search))
|
||||||
|
{
|
||||||
|
query = query.Where(x =>
|
||||||
|
x.Name.Contains(input.Search) ||
|
||||||
|
x.Description.Contains(input.Search) ||
|
||||||
|
x.Subject.Contains(input.Search) ||
|
||||||
|
x.TeacherName.Contains(input.Search)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(input.Status))
|
||||||
|
{
|
||||||
|
switch (input.Status)
|
||||||
|
{
|
||||||
|
case "Active":
|
||||||
|
query = query.Where(x => x.ActualStartTime == null && x.ActualEndTime == null);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "Open":
|
||||||
|
query = query.Where(x => x.ActualStartTime != null && x.ActualEndTime == null);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "Passive":
|
||||||
|
query = query.Where(x => x.ActualEndTime != null);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
var totalCount = query.Count();
|
var totalCount = query.Count();
|
||||||
var items = query
|
var items = query
|
||||||
.OrderBy(x => x.ScheduledStartTime)
|
.OrderBy(x => x.ScheduledStartTime)
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { PagedAndSortedResultRequestDto } from '../abp'
|
||||||
|
|
||||||
export type RoleState = 'role-selection' | 'dashboard' | 'classroom'
|
export type RoleState = 'role-selection' | 'dashboard' | 'classroom'
|
||||||
|
|
||||||
export type Role = 'teacher' | 'student' | 'observer'
|
export type Role = 'teacher' | 'student' | 'observer'
|
||||||
|
|
@ -131,3 +133,8 @@ export interface ScreenShareRequestDto {
|
||||||
userName: string
|
userName: string
|
||||||
isActive: boolean
|
isActive: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ClassroomFilterInputDto extends PagedAndSortedResultRequestDto {
|
||||||
|
search: string
|
||||||
|
status: string
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { ClassroomDto } from '@/proxy/classroom/models'
|
import { ClassroomDto, ClassroomFilterInputDto } from '@/proxy/classroom/models'
|
||||||
import apiService from './api.service'
|
import apiService from './api.service'
|
||||||
import { PagedAndSortedResultRequestDto, PagedResultDto } from '@/proxy'
|
import { PagedAndSortedResultRequestDto, PagedResultDto } from '@/proxy'
|
||||||
|
|
||||||
|
|
@ -8,7 +8,7 @@ export const getClassroomById = (id: string) =>
|
||||||
url: `/api/app/classroom/${id}`,
|
url: `/api/app/classroom/${id}`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const getClassrooms = (input: PagedAndSortedResultRequestDto) =>
|
export const getClassrooms = (input: ClassroomFilterInputDto) =>
|
||||||
apiService.fetchData<PagedResultDto<ClassroomDto>>({
|
apiService.fetchData<PagedResultDto<ClassroomDto>>({
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
url: `/api/app/classroom`,
|
url: `/api/app/classroom`,
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,8 @@ import {
|
||||||
FaEye,
|
FaEye,
|
||||||
FaHourglassEnd,
|
FaHourglassEnd,
|
||||||
FaDoorOpen,
|
FaDoorOpen,
|
||||||
|
FaSearch,
|
||||||
|
FaFilter,
|
||||||
} from 'react-icons/fa'
|
} from 'react-icons/fa'
|
||||||
|
|
||||||
import { ClassroomDto } from '@/proxy/classroom/models'
|
import { ClassroomDto } from '@/proxy/classroom/models'
|
||||||
|
|
@ -70,12 +72,24 @@ const ClassList: React.FC = () => {
|
||||||
const [showEditModal, setShowEditModal] = useState(false)
|
const [showEditModal, setShowEditModal] = useState(false)
|
||||||
const [showDeleteModal, setShowDeleteModal] = useState(false)
|
const [showDeleteModal, setShowDeleteModal] = useState(false)
|
||||||
|
|
||||||
const getClassroomList = async (skipCount = 0, maxResultCount = 1000, sorting = '') => {
|
// Filter/search state
|
||||||
|
const [searchTerm, setSearchTerm] = useState('')
|
||||||
|
const [statusFilter, setStatusFilter] = useState('')
|
||||||
|
|
||||||
|
const getClassroomList = async (
|
||||||
|
skipCount = 0,
|
||||||
|
maxResultCount = 1000,
|
||||||
|
sorting = '',
|
||||||
|
search = '',
|
||||||
|
status = '',
|
||||||
|
) => {
|
||||||
try {
|
try {
|
||||||
const result = await getClassrooms({
|
const result = await getClassrooms({
|
||||||
sorting,
|
sorting,
|
||||||
skipCount,
|
skipCount,
|
||||||
maxResultCount,
|
maxResultCount,
|
||||||
|
search,
|
||||||
|
status,
|
||||||
})
|
})
|
||||||
|
|
||||||
const items = (result.data.items || []).map((item) => ({
|
const items = (result.data.items || []).map((item) => ({
|
||||||
|
|
@ -93,8 +107,8 @@ const ClassList: React.FC = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getClassroomList()
|
getClassroomList(0, 1000, '', searchTerm, statusFilter)
|
||||||
}, [])
|
}, [searchTerm, statusFilter])
|
||||||
|
|
||||||
const handleCreateClass = async (e: React.FormEvent) => {
|
const handleCreateClass = async (e: React.FormEvent) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|
@ -166,13 +180,13 @@ const ClassList: React.FC = () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const canJoinClass = (actualStartTime: string) => {
|
// const canJoinClass = (actualStartTime: string) => {
|
||||||
const actualed = new Date(actualStartTime)
|
// const actualed = new Date(actualStartTime)
|
||||||
const now = new Date()
|
// const now = new Date()
|
||||||
const tenMinutesBefore = new Date(actualed.getTime() - 10 * 60 * 1000) //10 dakika öncesine kadar
|
// const tenMinutesBefore = new Date(actualed.getTime() - 10 * 60 * 1000) //10 dakika öncesine kadar
|
||||||
const twoHoursAfter = new Date(actualed.getTime() + 2 * 60 * 60 * 1000) // 2 saat sonrasına kadar
|
// const twoHoursAfter = new Date(actualed.getTime() + 2 * 60 * 60 * 1000) // 2 saat sonrasına kadar
|
||||||
return now >= tenMinutesBefore && now <= twoHoursAfter
|
// return now >= tenMinutesBefore && now <= twoHoursAfter
|
||||||
}
|
// }
|
||||||
|
|
||||||
const widgets = () => {
|
const widgets = () => {
|
||||||
return {
|
return {
|
||||||
|
|
@ -342,6 +356,36 @@ const ClassList: React.FC = () => {
|
||||||
</motion.div>
|
</motion.div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Filter Bar */}
|
||||||
|
<div className="bg-white rounded-lg border border-slate-200 p-6 mb-6 shadow-sm">
|
||||||
|
<div className="flex flex-col lg:flex-row gap-4">
|
||||||
|
<div className="flex-1 relative">
|
||||||
|
<FaSearch className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-slate-400" />
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
className="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
||||||
|
placeholder="Search class"
|
||||||
|
value={searchTerm}
|
||||||
|
onChange={(e) => setSearchTerm(e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-4">
|
||||||
|
<FaFilter className="w-5 h-5 text-slate-500" />
|
||||||
|
<select
|
||||||
|
className="ml-2 px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
||||||
|
value={statusFilter}
|
||||||
|
onChange={(e) => setStatusFilter(e.target.value)}
|
||||||
|
style={{ minWidth: 120 }}
|
||||||
|
>
|
||||||
|
<option value="">All Status</option>
|
||||||
|
<option value="Active">Aktif</option>
|
||||||
|
<option value="Open">Katılıma Açık</option>
|
||||||
|
<option value="Passive">Pasif</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Scheduled Classes */}
|
{/* Scheduled Classes */}
|
||||||
<div className="bg-white rounded-lg shadow-md">
|
<div className="bg-white rounded-lg shadow-md">
|
||||||
<div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4 p-4 sm:px-6 border-b border-gray-200">
|
<div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4 p-4 sm:px-6 border-b border-gray-200">
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue