From 555b9b27ae72f6b566c3049b2219e4460228c541 Mon Sep 17 00:00:00 2001 From: Dasha Date: Sun, 1 Mar 2026 18:20:26 +0100 Subject: [PATCH 1/7] fix: reset modal state when opening for different students --- .../RegularStudentScheduleModal.tsx | 42 ++++++++++++++----- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/client/src/components/regularStudentScheduleModal/RegularStudentScheduleModal.tsx b/client/src/components/regularStudentScheduleModal/RegularStudentScheduleModal.tsx index db5de20..5bde5f3 100644 --- a/client/src/components/regularStudentScheduleModal/RegularStudentScheduleModal.tsx +++ b/client/src/components/regularStudentScheduleModal/RegularStudentScheduleModal.tsx @@ -28,21 +28,18 @@ const HOURS = Array.from({ length: 17 }, (_, i) => ({ label: `${i + 7}:00`, })); -export const RegularStudentScheduleModal = ({ - isOpen, +const ModalContent = ({ onClose, onSave, studentName, initialSchedule = [], occupiedSlots = [], -}: RegularStudentScheduleModalProps) => { +}: Omit) => { const [savedSlots, setSavedSlots] = useState(initialSchedule); const [currentDay, setCurrentDay] = useState("Monday"); const [currentHour, setCurrentHour] = useState(7); - if (!isOpen) return null; - const isDuplicate = savedSlots.some( (slot) => slot.day === currentDay && slot.hour === currentHour, ); @@ -59,8 +56,20 @@ export const RegularStudentScheduleModal = ({ const newSlot = { day: currentDay, hour: currentHour }; const updatedSlots = [...savedSlots, newSlot]; setSavedSlots(updatedSlots); - setCurrentDay("Monday"); - setCurrentHour(7); + + const nextHour = currentHour + 1; + if (nextHour <= 23) { + setCurrentHour(nextHour); + } else { + const currentDayIndex = DAYS.findIndex((d) => d.value === currentDay); + if (currentDayIndex < DAYS.length - 1) { + setCurrentDay(DAYS[currentDayIndex + 1].value); + setCurrentHour(7); + } else { + setCurrentDay("Monday"); + setCurrentHour(7); + } + } }; const handleRemoveSlot = (index: number) => { @@ -73,9 +82,6 @@ export const RegularStudentScheduleModal = ({ }; const handleCancel = () => { - setSavedSlots(initialSchedule); - setCurrentDay("Monday"); - setCurrentHour(7); onClose(); }; @@ -204,3 +210,19 @@ export const RegularStudentScheduleModal = ({ ); }; + +export const RegularStudentScheduleModal = ({ + isOpen, + studentName, + ...props +}: RegularStudentScheduleModalProps) => { + if (!isOpen) return null; + + return ( + + ); +}; From 46ba3363b6abcdea4e9aa71577084949afc7d1a3 Mon Sep 17 00:00:00 2001 From: Dasha Date: Sun, 1 Mar 2026 18:23:21 +0100 Subject: [PATCH 2/7] fix: resolve ESLint errors in modals and sidebar --- client/src/components/sidebar/Sidebar.tsx | 76 +------------------ .../components/sidebar/sidebarMenuItems.ts | 11 --- .../teacherProfileSection/LessonSchedule.tsx | 53 ++++++++++--- 3 files changed, 44 insertions(+), 96 deletions(-) diff --git a/client/src/components/sidebar/Sidebar.tsx b/client/src/components/sidebar/Sidebar.tsx index 7f29085..67d41c4 100644 --- a/client/src/components/sidebar/Sidebar.tsx +++ b/client/src/components/sidebar/Sidebar.tsx @@ -1,80 +1,6 @@ -import React from "react"; import { Link, useLocation } from "react-router-dom"; -import AppointmentsIcon from "../icons/Appointments"; -import DashboardIcon from "../icons/Dashboard"; -import Chat from "../icons/Chat"; -import UsersIcon from "../icons/UsersIcon"; -import { - chatRoutes, - studentBase, - studentPrivatesRoutesVariables, - teacherBase, - teacherPrivatesRoutesVariables, -} from "../../router/routesVariables/pathVariables.ts"; -import { joinPath } from "../../util/joinPath.util.ts"; import { Logo } from "../logo/Logo.tsx"; - -export type MenuItem = { - name: string; - link: string; - icon: React.ElementType; -}; - -export const defaultStudentMenuItems: MenuItem[] = [ - { - name: "Dashboard", - link: joinPath(studentBase, studentPrivatesRoutesVariables.dashboard), - icon: DashboardIcon, - }, - { - name: "Appointments", - link: joinPath(studentBase, studentPrivatesRoutesVariables.appointments), - icon: AppointmentsIcon, - }, - // { - // name: "Video Call", - // link: joinPath(studentBase, studentPrivatesRoutesVariables.videoCall), - // icon: VideoCallIcon, - // }, - { - name: "My Profile", - link: joinPath(studentBase, studentPrivatesRoutesVariables.profile), - icon: UsersIcon, - }, - { - name: "Chat", - link: joinPath(studentBase, chatRoutes.root), - icon: Chat, - }, -]; - -export const defaultTeacherMenuItems: MenuItem[] = [ - { - name: "Dashboard", - link: joinPath(teacherBase, teacherPrivatesRoutesVariables.dashboard), - icon: DashboardIcon, - }, - { - name: "Appointments", - link: joinPath(teacherBase, teacherPrivatesRoutesVariables.appointments), - icon: AppointmentsIcon, - }, - // { - // name: "Video Call", - // link: joinPath(teacherBase, teacherPrivatesRoutesVariables.videoCall), - // icon: VideoCallIcon, - // }, - { - name: "My Profile", - link: joinPath(teacherBase, teacherPrivatesRoutesVariables.profile), - icon: UsersIcon, - }, - { - name: "Chat", - link: joinPath(teacherBase, chatRoutes.root), - icon: Chat, - }, -]; +import { type MenuItem, defaultStudentMenuItems } from "./sidebarMenuItems.ts"; type SidebarProps = { items?: MenuItem[]; diff --git a/client/src/components/sidebar/sidebarMenuItems.ts b/client/src/components/sidebar/sidebarMenuItems.ts index 4937441..007d5b4 100644 --- a/client/src/components/sidebar/sidebarMenuItems.ts +++ b/client/src/components/sidebar/sidebarMenuItems.ts @@ -3,7 +3,6 @@ import AppointmentsIcon from "../icons/Appointments"; import DashboardIcon from "../icons/Dashboard"; import Chat from "../icons/Chat"; import UsersIcon from "../icons/UsersIcon"; -// import VideoCallIcon from "../icons/VideoCallIcon"; import { chatRoutes, studentBase, @@ -30,11 +29,6 @@ export const defaultStudentMenuItems: MenuItem[] = [ link: joinPath(studentBase, studentPrivatesRoutesVariables.appointments), icon: AppointmentsIcon, }, - // { - // name: "Video Call", - // link: joinPath(studentBase, studentPrivatesRoutesVariables.videoCall), - // icon: VideoCallIcon, - // }, { name: "My Profile", link: joinPath(studentBase, studentPrivatesRoutesVariables.profile), @@ -58,11 +52,6 @@ export const defaultTeacherMenuItems: MenuItem[] = [ link: joinPath(teacherBase, teacherPrivatesRoutesVariables.appointments), icon: AppointmentsIcon, }, - // { - // name: "Video Call", - // link: joinPath(teacherBase, teacherPrivatesRoutesVariables.videoCall), - // icon: VideoCallIcon, - // }, { name: "My Profile", link: joinPath(teacherBase, teacherPrivatesRoutesVariables.profile), diff --git a/client/src/components/teacherProfileSection/LessonSchedule.tsx b/client/src/components/teacherProfileSection/LessonSchedule.tsx index 9a467bc..b20fbdb 100644 --- a/client/src/components/teacherProfileSection/LessonSchedule.tsx +++ b/client/src/components/teacherProfileSection/LessonSchedule.tsx @@ -12,6 +12,7 @@ interface LessonScheduleProps { onClose: () => void; onSave: (slots: TimeSlot[]) => Promise | void; initialSlots?: TimeSlot[]; + bookedSlots?: TimeSlot[]; } const DAYS = [ @@ -26,21 +27,26 @@ const DAYS = [ const HOURS = Array.from({ length: 17 }, (_, i) => i + 7); -export const LessonSchedule = ({ - isOpen, +const ModalContent = ({ onClose, onSave, initialSlots = [], -}: LessonScheduleProps) => { + bookedSlots = [], +}: Omit) => { const [selectedSlots, setSelectedSlots] = useState>( () => new Set(initialSlots.map((slot) => `${slot.day}-${slot.hour}`)), ); - - if (!isOpen) return null; + const [blockedSlots] = useState>( + () => new Set(bookedSlots.map((slot) => `${slot.day}-${slot.hour}`)), + ); const toggleSlot = (day: string, hour: number) => { const key = `${day}-${hour}`; + if (blockedSlots.has(key)) { + return; + } + setSelectedSlots((prev) => { const newSet = new Set(prev); if (newSet.has(key)) { @@ -107,15 +113,18 @@ export const LessonSchedule = ({ {HOURS.map((hour) => { const key = `${day}-${hour}`; const isSelected = selectedSlots.has(key); + const isBlocked = blockedSlots.has(key); return ( toggleSlot(day, hour)} + onClick={() => !isBlocked && toggleSlot(day, hour)} className={`border border-gray-600 p-1 transition-colors min-w-[60px] min-h-[50px] ${ - isSelected - ? "bg-purple-500 hover:bg-purple-600 cursor-pointer" - : "bg-gray-700 hover:bg-gray-600 cursor-pointer" + isBlocked + ? "bg-red-900 cursor-not-allowed" + : isSelected + ? "bg-purple-500 hover:bg-purple-600 cursor-pointer" + : "bg-gray-700 hover:bg-gray-600 cursor-pointer" }`} > ); @@ -130,8 +139,14 @@ export const LessonSchedule = ({
- free time lesson + Available time
+ {bookedSlots.length > 0 && ( +
+
+ Regular Students +
+ )}
@@ -143,3 +158,21 @@ export const LessonSchedule = ({
); }; + +export const LessonSchedule = ({ + isOpen, + initialSlots, + bookedSlots, + ...props +}: LessonScheduleProps) => { + if (!isOpen) return null; + + return ( + + ); +}; From 41f4698865319a98a66a37060342addec63d2324 Mon Sep 17 00:00:00 2001 From: Dasha Date: Sun, 1 Mar 2026 18:25:28 +0100 Subject: [PATCH 3/7] feat: add weekly schedule display on appointment cards --- .../appointmentCard/AppointmentCard.tsx | 15 +++- .../appointmentCard/AppointmentInfo.tsx | 35 +++++++- .../appointmentCard/AppointmentStatusBar.tsx | 45 +++++++++-- .../TeacherAppointmentInfo.tsx | 35 +++++++- .../teacherSchedule/TeacherSchedule.tsx | 37 +++++++-- .../query/useTeacherAppointmentsQuery.ts | 2 +- .../ClientsAppointments.tsx | 81 ++++++++++++++++--- 7 files changed, 222 insertions(+), 28 deletions(-) diff --git a/client/src/components/appointmentCard/AppointmentCard.tsx b/client/src/components/appointmentCard/AppointmentCard.tsx index f463b55..e377c3f 100644 --- a/client/src/components/appointmentCard/AppointmentCard.tsx +++ b/client/src/components/appointmentCard/AppointmentCard.tsx @@ -8,11 +8,13 @@ import { isInternalVideoCallLink, } from "./appointmentCard.utils"; -type AppointmentCardProps = { +export type AppointmentCardProps = { appointment: Appointment; teacherAvatar?: string | null; isPast?: boolean; onDelete?: () => void; + isRegularTeacher?: boolean; + onShowSchedule?: () => void; }; export const AppointmentCard = ({ @@ -20,6 +22,8 @@ export const AppointmentCard = ({ teacherAvatar, isPast = false, onDelete, + isRegularTeacher = false, + onShowSchedule, }: AppointmentCardProps) => { const statusStyles = getStatusStyles(appointment.status); const isInternalLink = isInternalVideoCallLink(appointment.videoCall); @@ -29,15 +33,18 @@ export const AppointmentCard = ({
@@ -50,6 +57,8 @@ export const AppointmentCard = ({ lesson={appointment.lesson} teacherName={appointment.teacherName} price={appointment.price} + weeklySchedule={appointment.weeklySchedule} + isRegularTeacher={isRegularTeacher} /> { + const scheduleByDay: Record = {}; + weeklySchedule.forEach((slot) => { + if (!scheduleByDay[slot.day]) { + scheduleByDay[slot.day] = []; + } + scheduleByDay[slot.day].push(slot.hour); + }); + + Object.keys(scheduleByDay).forEach((day) => { + scheduleByDay[day].sort((a, b) => a - b); + }); + + return Object.entries(scheduleByDay) + .map(([day, hours]) => { + const hoursStr = hours.map((h) => `${h}:00`).join(", "); + return `${day}: ${hoursStr}`; + }) + .join(" • "); }; export const AppointmentInfo = ({ lesson, teacherName, price, + weeklySchedule, + isRegularTeacher = false, }: AppointmentInfoProps) => { return (
@@ -26,6 +53,12 @@ export const AppointmentInfo = ({
{price} euro /hour
+ + {isRegularTeacher && weeklySchedule && weeklySchedule.length > 0 && ( +
+ {formatSchedule(weeklySchedule)} +
+ )}
); }; diff --git a/client/src/components/appointmentCard/AppointmentStatusBar.tsx b/client/src/components/appointmentCard/AppointmentStatusBar.tsx index f5edb9c..cf065f0 100644 --- a/client/src/components/appointmentCard/AppointmentStatusBar.tsx +++ b/client/src/components/appointmentCard/AppointmentStatusBar.tsx @@ -8,22 +8,57 @@ type AppointmentStatusBarProps = { date: string; time: string; statusStyles: StatusStyles; + isRegularStudent?: boolean; + isRegularTeacher?: boolean; + onShowSchedule?: () => void; }; export const AppointmentStatusBar = ({ date, time, statusStyles, + isRegularStudent = false, + isRegularTeacher = false, + onShowSchedule, }: AppointmentStatusBarProps) => { + if (isRegularTeacher) { + return ( +
+ + Regular Teacher + + {onShowSchedule && ( + + )} +
+ ); + } + return (
- - {statusStyles.label} - +
+ + {statusStyles.label} + + {isRegularStudent && ( + + Regular + + )} +
{ + const scheduleByDay: Record = {}; + weeklySchedule.forEach((slot) => { + if (!scheduleByDay[slot.day]) { + scheduleByDay[slot.day] = []; + } + scheduleByDay[slot.day].push(slot.hour); + }); + + Object.keys(scheduleByDay).forEach((day) => { + scheduleByDay[day].sort((a, b) => a - b); + }); + + return Object.entries(scheduleByDay) + .map(([day, hours]) => { + const hoursStr = hours.map((h) => `${h}:00`).join(", "); + return `${day}: ${hoursStr}`; + }) + .join(" • "); }; export const TeacherAppointmentInfo = ({ lesson, studentName, price, + weeklySchedule, + isRegularTab = false, }: TeacherAppointmentInfoProps) => { return (
@@ -26,6 +53,12 @@ export const TeacherAppointmentInfo = ({
{price} euro /hour
+ + {isRegularTab && weeklySchedule && weeklySchedule.length > 0 && ( +
+ {formatSchedule(weeklySchedule)} +
+ )}
); }; diff --git a/client/src/components/teacherSection/teacherSchedule/TeacherSchedule.tsx b/client/src/components/teacherSection/teacherSchedule/TeacherSchedule.tsx index 44fb186..34ced20 100644 --- a/client/src/components/teacherSection/teacherSchedule/TeacherSchedule.tsx +++ b/client/src/components/teacherSection/teacherSchedule/TeacherSchedule.tsx @@ -28,14 +28,18 @@ export default function TeacherSchedule({ teacher }: TeacherScheduleProps) { const isAuthenticated = !!user; const isTeacher = user?.role === "teacher"; - const { data } = useTeacherAppointmentsQuery( - isAuthenticated ? teacher?.id : undefined, - ); + const { data } = useTeacherAppointmentsQuery(teacher?.id); + const appointments = useMemo(() => { const allAppointments = data?.appointments || []; return allAppointments.filter((apt) => apt.date && apt.time); }, [data?.appointments]); + const regularStudents = useMemo(() => { + const allAppointments = data?.appointments || []; + return allAppointments.filter((apt) => apt.isRegularStudent === true); + }, [data?.appointments]); + const subjectOptions = useMemo(() => { if (!teacher?.subjects) return []; return teacher.subjects.map((subject) => ({ @@ -160,9 +164,13 @@ export default function TeacherSchedule({ teacher }: TeacherScheduleProps) { } const startHour = parseInt(startMatch[1], 10); - const endHour = parseInt(endMatch[1], 10); + let endHour = parseInt(endMatch[1], 10); - if (startHour < 0 || startHour > 23 || endHour < 0 || endHour > 23) { + if (slot.end === "23:59") { + endHour = 24; + } + + if (startHour < 0 || startHour > 23) { return; } @@ -184,6 +192,23 @@ export default function TeacherSchedule({ teacher }: TeacherScheduleProps) { approvedAppointments.map((apt) => apt.time.substring(0, 5)), ); + const regularStudentSlots = new Set(); + regularStudents.forEach( + (student: { weeklySchedule?: Array<{ day: string; hour: number }> }) => { + if (student.weeklySchedule && Array.isArray(student.weeklySchedule)) { + student.weeklySchedule.forEach( + (slot: { day: string; hour: number }) => { + const slotDayName = slot.day.toLowerCase(); + if (slotDayName === dayName) { + const slotTime = `${slot.hour.toString().padStart(2, "0")}:00`; + regularStudentSlots.add(slotTime); + } + }, + ); + } + }, + ); + const now = new Date(); const today = new Date(); today.setHours(0, 0, 0, 0); @@ -193,7 +218,7 @@ export default function TeacherSchedule({ teacher }: TeacherScheduleProps) { const isToday = selectedDateOnly.getTime() === today.getTime(); return slots.filter((slot) => { - if (bookedTimes.has(slot)) { + if (bookedTimes.has(slot) || regularStudentSlots.has(slot)) { return false; } diff --git a/client/src/features/appointments/query/useTeacherAppointmentsQuery.ts b/client/src/features/appointments/query/useTeacherAppointmentsQuery.ts index 724eea3..223081a 100644 --- a/client/src/features/appointments/query/useTeacherAppointmentsQuery.ts +++ b/client/src/features/appointments/query/useTeacherAppointmentsQuery.ts @@ -37,6 +37,6 @@ export const useTeacherAppointmentsQuery = ( return useQuery({ queryKey: queryKeys.teacherAppointments(resolvedTeacherId, page, limit), queryFn: () => fetchTeacherAppointments(resolvedTeacherId, page, limit), - enabled: !!resolvedTeacherId && !!user, + enabled: !!resolvedTeacherId, }); }; diff --git a/client/src/pages/privateStudentsPages/clientsAppointments/ClientsAppointments.tsx b/client/src/pages/privateStudentsPages/clientsAppointments/ClientsAppointments.tsx index e1c6bbe..aeb661b 100644 --- a/client/src/pages/privateStudentsPages/clientsAppointments/ClientsAppointments.tsx +++ b/client/src/pages/privateStudentsPages/clientsAppointments/ClientsAppointments.tsx @@ -9,16 +9,25 @@ import { getTeacherByIdApi } from "../../../api/teacher/teacher.api"; import { TeacherType } from "../../../api/teacher/teacher.type"; import { useAppointmentTime } from "../../../features/appointments/hooks/useAppointmentTime"; import { useModalStore } from "../../../store/modals.store"; +import { useRegularTeachersQuery } from "../../../features/appointments/query/useRegularTeachersQuery"; +import { ViewScheduleModal } from "../../../components/regularStudentScheduleModal/ViewScheduleModal"; +import { Appointment } from "../../../types/appointments.types"; export const ClientsAppointments = () => { const [activeTab, setActiveTab] = useState<"requests" | "regular">( "requests", ); const [page, setPage] = useState(1); + const [regularPage, setRegularPage] = useState(1); const [teachersData, setTeachersData] = useState>( {}, ); + const [isScheduleModalOpen, setIsScheduleModalOpen] = useState(false); + const [selectedTeacher, setSelectedTeacher] = useState( + null, + ); const limit = 5; + const regularLimit = 5; const user = useAuthSessionStore((state) => state.user); const { isPastAppointment } = useAppointmentTime(); const { open: openModal } = useModalStore(); @@ -29,10 +38,17 @@ export const ClientsAppointments = () => { error, } = useStudentAppointmentsQuery(user?.id || "", page, limit); + const { data: regularTeachersData } = useRegularTeachersQuery( + regularPage, + regularLimit, + ); + const deleteAppointmentMutation = useDeleteAppointmentMutation(); const appointments = studentData?.appointments || []; const totalPages = studentData?.totalPages || 1; + const regularTeachers = regularTeachersData?.appointments || []; + const regularTotalPages = regularTeachersData?.totalPages || 1; useEffect(() => { const fetchTeachersData = async () => { @@ -72,6 +88,11 @@ export const ClientsAppointments = () => { }); }; + const handleShowSchedule = (appointment: Appointment) => { + setSelectedTeacher(appointment); + setIsScheduleModalOpen(true); + }; + if (isLoading) { return (
@@ -123,7 +144,7 @@ export const ClientsAppointments = () => { : "text-gray-400 hover:text-gray-300" }`} > - Regular Students + Regular Teachers
@@ -169,19 +190,57 @@ export const ClientsAppointments = () => {
) : ( -
-
-

- Regular students feature coming soon -

-

- Here you'll be able to manage recurring lessons with your - regular teachers -

-
+
+ {regularTeachers.length === 0 ? ( +
+

No regular teachers yet

+

+ Your regular teachers will appear here +

+
+ ) : ( + <> +
+ {regularTeachers.map((appointment) => ( + handleShowSchedule(appointment)} + /> + ))} +
+ + {regularTotalPages > 1 && ( +
+ +
+ )} + + )}
)}
+ + { + setIsScheduleModalOpen(false); + setSelectedTeacher(null); + }} + teacherName={selectedTeacher?.teacherName || "Unknown Teacher"} + schedule={selectedTeacher?.weeklySchedule || []} + />
); }; From 7e3a080a7df2cbdad0a212116339c39e588504a2 Mon Sep 17 00:00:00 2001 From: Dasha Date: Sun, 1 Mar 2026 18:28:51 +0100 Subject: [PATCH 4/7] refactor: improve regular students mutations and query invalidation --- .../api/appointments/regularStudents.api.ts | 21 -- .../TeacherAppointmentActions.tsx | 34 ++- .../TeacherAppointmentCard.tsx | 2 + .../TeacherAppointmentsList.tsx | 20 +- .../useRemoveRegularStudentMutation.ts | 15 + .../mutations/useSetRegularStudentMutation.ts | 6 + .../useUpdateWeeklyScheduleMutation.ts | 3 + .../TeacherAppointments.tsx | 262 +++++++----------- .../teacherProfile/TeacherProfile.tsx | 33 +++ 9 files changed, 195 insertions(+), 201 deletions(-) diff --git a/client/src/api/appointments/regularStudents.api.ts b/client/src/api/appointments/regularStudents.api.ts index 34d69c8..dbadbea 100644 --- a/client/src/api/appointments/regularStudents.api.ts +++ b/client/src/api/appointments/regularStudents.api.ts @@ -70,24 +70,3 @@ export const getRegularTeachersApi = async ( ); return response.data; }; - -export const getAllRegularStudentsSlotsApi = async (): Promise< - WeeklyScheduleSlot[] -> => { - const response = await api.get( - `/api/appointments/regular/students?limit=1000`, - ); - const appointments: Appointment[] = response.data.appointments; - - const allSlots: WeeklyScheduleSlot[] = []; - appointments.forEach((appointment) => { - if ( - appointment.weeklySchedule && - Array.isArray(appointment.weeklySchedule) - ) { - allSlots.push(...appointment.weeklySchedule); - } - }); - - return allSlots; -}; diff --git a/client/src/components/teacherAppointmentCard/TeacherAppointmentActions.tsx b/client/src/components/teacherAppointmentCard/TeacherAppointmentActions.tsx index 175b4f6..1724f6a 100644 --- a/client/src/components/teacherAppointmentCard/TeacherAppointmentActions.tsx +++ b/client/src/components/teacherAppointmentCard/TeacherAppointmentActions.tsx @@ -23,31 +23,39 @@ export const TeacherAppointmentActions = ({ onRemoveFromRegular, isRegularTab = false, }: TeacherAppointmentActionsProps) => { + const isInRegular = !!onRemoveFromRegular; + return (
- {!isPast && onStatusChange && !isRegularTab && ( + {/* Status buttons - ЗАВЖДИ показуються в Requests табі для не-past appointments */} + {!isPast && !isRegularTab && onStatusChange && ( )} - {status === "approved" && !isPast && onAddToRegular && ( - - )} + {/* Add to Regular Students - показується тільки для approved appointments в Requests табі, якщо студент НЕ в regular */} + {!isPast && + !isRegularTab && + status === "approved" && + !isInRegular && + onAddToRegular && ( + + )} - {onRemoveFromRegular && ( + {!isPast && onRemoveFromRegular && ( )} diff --git a/client/src/components/teacherAppointmentCard/TeacherAppointmentCard.tsx b/client/src/components/teacherAppointmentCard/TeacherAppointmentCard.tsx index b07616d..db78e4c 100644 --- a/client/src/components/teacherAppointmentCard/TeacherAppointmentCard.tsx +++ b/client/src/components/teacherAppointmentCard/TeacherAppointmentCard.tsx @@ -59,6 +59,8 @@ export const TeacherAppointmentCard = ({ lesson={appointment.lesson} studentName={appointment.studentName} price={appointment.price} + weeklySchedule={appointment.weeklySchedule} + isRegularTab={isRegularTab} /> void; regularStudentIds?: string[]; isRegularTab?: boolean; - onScheduleClick?: () => void; + onScheduleClick?: (appointment: Appointment) => void; }; export const TeacherAppointmentsList = ({ @@ -45,7 +45,7 @@ export const TeacherAppointmentsList = ({ studentAvatar={appointment.studentProfileImageUrl} isPast={isPast} onStatusChange={ - !isPast && !isRegularTab + !isRegularTab && !isPast ? (newStatus: AppointmentStatus) => onStatusChange(appointment.id, newStatus) : undefined @@ -54,22 +54,30 @@ export const TeacherAppointmentsList = ({ onStartCall(appointment.studentId, appointment.id) } onDelete={ - isRegularTab || isPast + isPast || isRegularTab ? () => onDelete(appointment.id) : undefined } onAddToRegular={ - !isRegularTab && !isInRegular && onAddToRegular + !isRegularTab && + !isPast && + !isInRegular && + onAddToRegular && + appointment.status === "approved" ? () => onAddToRegular(appointment) : undefined } onRemoveFromRegular={ - isRegularTab && onRemoveFromRegular + !isPast && isInRegular && onRemoveFromRegular ? () => onRemoveFromRegular(appointment.id) : undefined } isRegularTab={isRegularTab} - onScheduleClick={onScheduleClick} + onScheduleClick={ + isRegularTab && onScheduleClick + ? () => onScheduleClick(appointment) + : undefined + } /> ); })} diff --git a/client/src/features/appointments/mutations/useRemoveRegularStudentMutation.ts b/client/src/features/appointments/mutations/useRemoveRegularStudentMutation.ts index 42dfecd..9718035 100644 --- a/client/src/features/appointments/mutations/useRemoveRegularStudentMutation.ts +++ b/client/src/features/appointments/mutations/useRemoveRegularStudentMutation.ts @@ -12,9 +12,24 @@ export const useRemoveRegularStudentMutation = () => { queryClient.invalidateQueries({ queryKey: queryKeys.regularStudents(), }); + queryClient.invalidateQueries({ + queryKey: queryKeys.regularTeachers(), + }); queryClient.invalidateQueries({ queryKey: queryKeys.appointments, }); + queryClient.invalidateQueries({ + queryKey: ["appointments", "teacher"], + }); + }, + onError: (error: Error) => { + console.error("Failed to remove regular student:", error); + if (error && typeof error === "object" && "response" in error) { + console.error( + "Error response:", + (error as { response?: { data?: unknown } }).response?.data, + ); + } }, }); }; diff --git a/client/src/features/appointments/mutations/useSetRegularStudentMutation.ts b/client/src/features/appointments/mutations/useSetRegularStudentMutation.ts index 3d7dacc..b27eb41 100644 --- a/client/src/features/appointments/mutations/useSetRegularStudentMutation.ts +++ b/client/src/features/appointments/mutations/useSetRegularStudentMutation.ts @@ -11,9 +11,15 @@ export const useSetRegularStudentMutation = () => { queryClient.invalidateQueries({ queryKey: queryKeys.regularStudents(), }); + queryClient.invalidateQueries({ + queryKey: queryKeys.regularTeachers(), + }); queryClient.invalidateQueries({ queryKey: queryKeys.appointments, }); + queryClient.invalidateQueries({ + queryKey: ["appointments", "teacher"], + }); }, }); }; diff --git a/client/src/features/appointments/mutations/useUpdateWeeklyScheduleMutation.ts b/client/src/features/appointments/mutations/useUpdateWeeklyScheduleMutation.ts index 20a0d1a..7bd3b23 100644 --- a/client/src/features/appointments/mutations/useUpdateWeeklyScheduleMutation.ts +++ b/client/src/features/appointments/mutations/useUpdateWeeklyScheduleMutation.ts @@ -24,6 +24,9 @@ export const useUpdateWeeklyScheduleMutation = () => { queryClient.invalidateQueries({ queryKey: queryKeys.appointments, }); + queryClient.invalidateQueries({ + queryKey: ["appointments", "teacher"], + }); }, }); }; diff --git a/client/src/pages/privetTeachersPages/teacherAppointments/TeacherAppointments.tsx b/client/src/pages/privetTeachersPages/teacherAppointments/TeacherAppointments.tsx index 3c0d0a2..88cb0eb 100644 --- a/client/src/pages/privetTeachersPages/teacherAppointments/TeacherAppointments.tsx +++ b/client/src/pages/privetTeachersPages/teacherAppointments/TeacherAppointments.tsx @@ -7,92 +7,43 @@ import { useDeleteAppointmentMutation } from "../../../features/appointments/mut import { Appointment, AppointmentStatus, + WeeklyScheduleSlot, } from "../../../types/appointments.types"; import { useModalStore } from "../../../store/modals.store"; import { useVideoCall } from "../../../features/appointments/hooks/useVideoCall"; import { useAppointmentTime } from "../../../features/appointments/hooks/useAppointmentTime"; import { TeacherAppointmentsList } from "../../../components/teacherAppointmentCard/TeacherAppointmentsList"; import { LessonSchedule } from "../../../components/teacherProfileSection/LessonSchedule"; -import { - getMyWeeklyScheduleApi, - updateMyWeeklyScheduleApi, -} from "../../../api/teacher/teacher.api"; -import { - mapUiSlotsToMergedWeekAvailability, - mapWeekAvailabilityToUiSlots, -} from "../teacherProfile/scheduleMappers"; -import { mapAppointmentsToBookedSlots } from "../../../util/appointmentSchedule.util"; +import { RegularStudentScheduleModal } from "../../../components/regularStudentScheduleModal/RegularStudentScheduleModal"; +import { useSetRegularStudentMutation } from "../../../features/appointments/mutations/useSetRegularStudentMutation"; +import { useUpdateWeeklyScheduleMutation } from "../../../features/appointments/mutations/useUpdateWeeklyScheduleMutation"; +import { useRemoveRegularStudentMutation } from "../../../features/appointments/mutations/useRemoveRegularStudentMutation"; +import { useRegularStudentsQuery } from "../../../features/appointments/query/useRegularStudentsQuery"; export interface TimeSlot { day: string; hour: number; } -const REGULAR_STUDENTS_KEY = "regularStudents"; - -const getInitialRegularStudents = (): Appointment[] => { - try { - const stored = localStorage.getItem(REGULAR_STUDENTS_KEY); - if (!stored) return []; - - const parsed = JSON.parse(stored); - if (!Array.isArray(parsed)) return []; - - let needsUpdate = false; - - const migratedStudents = parsed - .filter((item): item is Appointment => { - return ( - typeof item === "object" && - item !== null && - typeof item.id === "string" && - typeof item.date === "string" - ); - }) - .map((student) => { - if (!student.addedToRegularAt) { - const parsedDate = Date.parse(student.date); - if (!isNaN(parsedDate)) { - needsUpdate = true; - return { - ...student, - addedToRegularAt: new Date(parsedDate).toISOString(), - }; - } - } - return student; - }); - - if (needsUpdate) { - localStorage.setItem( - REGULAR_STUDENTS_KEY, - JSON.stringify(migratedStudents), - ); - } - - return migratedStudents; - } catch { - return []; - } -}; - export const TeacherAppointments = () => { const [activeTab, setActiveTab] = useState<"requests" | "regular">( "requests", ); const [page, setPage] = useState(1); - const [regularPage, setRegularPage] = useState(1); const limit = 5; - const regularLimit = 5; - const [regularStudents, setRegularStudents] = useState( - getInitialRegularStudents, + const [isRegularStudentModalOpen, setIsRegularStudentModalOpen] = + useState(false); + const [selectedStudent, setSelectedStudent] = useState( + null, ); - const [isScheduleOpen, setIsScheduleOpen] = useState(false); - const [schedule, setSchedule] = useState([]); const { open: openModal } = useModalStore(); const { confirmStartCall } = useVideoCall(); const { isPastAppointment } = useAppointmentTime(); + const setRegularStudentMutation = useSetRegularStudentMutation(); + const updateWeeklyScheduleMutation = useUpdateWeeklyScheduleMutation(); + const removeRegularStudentMutation = useRemoveRegularStudentMutation(); + const { data: regularStudentsData } = useRegularStudentsQuery(); const { data, isLoading, error } = useTeacherAppointmentsQuery( undefined, @@ -107,18 +58,7 @@ export const TeacherAppointments = () => { const deleteAppointmentMutation = useDeleteAppointmentMutation(); const handleAddToRegular = (appointment: Appointment) => { - const isAlreadyAdded = regularStudents.some( - (student) => student.id === appointment.id, - ); - if (!isAlreadyAdded) { - const appointmentWithTimestamp = { - ...appointment, - addedToRegularAt: new Date().toISOString(), - }; - const updated = [...regularStudents, appointmentWithTimestamp]; - setRegularStudents(updated); - localStorage.setItem(REGULAR_STUDENTS_KEY, JSON.stringify(updated)); - } + setRegularStudentMutation.mutate(appointment.id); }; const handleRemoveFromRegular = (appointmentId: string) => { @@ -126,49 +66,16 @@ export const TeacherAppointments = () => { title: "Remove from Regular Students", message: "Are you sure you want to remove this student from regular students?", - onConfirm: () => { - const updated = regularStudents.filter( - (student) => student.id !== appointmentId, - ); - setRegularStudents(updated); - localStorage.setItem(REGULAR_STUDENTS_KEY, JSON.stringify(updated)); + onConfirm: async () => { + try { + await removeRegularStudentMutation.mutateAsync(appointmentId); + } catch (error) { + console.error("Failed to remove from regular students", error); + } }, }); }; - const handleOpenSchedule = async () => { - try { - const availability = await getMyWeeklyScheduleApi(); - setSchedule(mapWeekAvailabilityToUiSlots(availability)); - } catch (error) { - console.error("Failed to load weekly availability", error); - } finally { - setIsScheduleOpen(true); - } - }; - - const handleScheduleSave = async (slots: TimeSlot[]) => { - try { - setSchedule(slots); - const availability = mapUiSlotsToMergedWeekAvailability(slots); - await updateMyWeeklyScheduleApi({ availability }); - openModal("alert", { - title: "Success", - message: "Schedule saved successfully", - }); - } catch (error) { - const axiosError = error as { - response?: { data?: { errorsMessages?: Array<{ message: string }> } }; - }; - openModal("alert", { - title: "Error", - message: - axiosError?.response?.data?.errorsMessages?.[0]?.message || - "Failed to save schedule. Please try again.", - }); - } - }; - const handleStatusChange = ( appointmentId: string, newStatus: AppointmentStatus, @@ -189,26 +96,55 @@ export const TeacherAppointments = () => { }); }; - const getSortedRegularStudents = () => { - return [...regularStudents].sort((a, b) => { - const dateA = new Date(a.addedToRegularAt || a.date).getTime(); - const dateB = new Date(b.addedToRegularAt || b.date).getTime(); - return dateB - dateA; - }); - }; + const handleUpdateStudentSchedule = async ( + schedule: WeeklyScheduleSlot[], + ) => { + if (!selectedStudent) return; - const getPaginatedRegularStudents = () => { - const sorted = getSortedRegularStudents(); - const startIndex = (regularPage - 1) * regularLimit; - const endIndex = startIndex + regularLimit; - return sorted.slice(startIndex, endIndex); - }; + try { + await updateWeeklyScheduleMutation.mutateAsync({ + appointmentId: selectedStudent.id, + weeklySchedule: schedule, + }); - const regularTotalPages = Math.ceil(regularStudents.length / regularLimit); + setIsRegularStudentModalOpen(false); + setSelectedStudent(null); + + openModal("alert", { + title: "Success", + message: "Schedule updated successfully", + }); + } catch (error) { + const axiosError = error as { + response?: { data?: { errorsMessages?: Array<{ message: string }> } }; + }; + openModal("alert", { + title: "Error", + message: + axiosError?.response?.data?.errorsMessages?.[0]?.message || + "Failed to update schedule", + }); + } + }; const getBookedSlots = () => { - const allAppointments = data?.appointments || []; - return mapAppointmentsToBookedSlots(allAppointments); + const regularSlots: TimeSlot[] = []; + regularStudentsData?.appointments?.forEach((student) => { + if (student.weeklySchedule && Array.isArray(student.weeklySchedule)) { + student.weeklySchedule.forEach((slot) => { + regularSlots.push({ + day: slot.day, + hour: slot.hour, + }); + }); + } + }); + return regularSlots; + }; + + const handleEditStudentSchedule = (appointment: Appointment) => { + setSelectedStudent(appointment); + setIsRegularStudentModalOpen(true); }; if (isLoading) { @@ -275,7 +211,10 @@ export const TeacherAppointments = () => { onStartCall={confirmStartCall} onDelete={handleDelete} onAddToRegular={handleAddToRegular} - regularStudentIds={regularStudents.map((student) => student.id)} + onRemoveFromRegular={handleRemoveFromRegular} + regularStudentIds={ + regularStudentsData?.appointments?.map((apt) => apt.id) || [] + } />
@@ -290,7 +229,7 @@ export const TeacherAppointments = () => {
) : (
- {regularStudents.length === 0 ? ( + {regularStudentsData?.appointments?.length === 0 ? (

No regular students yet

@@ -298,43 +237,44 @@ export const TeacherAppointments = () => {

) : ( - <> - - - {regularTotalPages > 1 && ( -
- -
- )} - + )}
)}
setIsScheduleOpen(false)} - onSave={handleScheduleSave} - initialSlots={schedule} + isOpen={false} + onClose={() => {}} + onSave={async () => {}} + initialSlots={[]} bookedSlots={getBookedSlots()} /> + + { + setIsRegularStudentModalOpen(false); + setSelectedStudent(null); + }} + onSave={handleUpdateStudentSchedule} + studentName={selectedStudent?.studentName || ""} + initialSchedule={selectedStudent?.weeklySchedule || []} + occupiedSlots={ + regularStudentsData?.appointments + ?.filter((apt) => apt.id !== selectedStudent?.id) + .flatMap((apt) => apt.weeklySchedule || []) || [] + } + />
); }; diff --git a/client/src/pages/privetTeachersPages/teacherProfile/TeacherProfile.tsx b/client/src/pages/privetTeachersPages/teacherProfile/TeacherProfile.tsx index 50d1cbf..de2febf 100644 --- a/client/src/pages/privetTeachersPages/teacherProfile/TeacherProfile.tsx +++ b/client/src/pages/privetTeachersPages/teacherProfile/TeacherProfile.tsx @@ -1,4 +1,5 @@ import { useState, useEffect } from "react"; +import { useQueryClient } from "@tanstack/react-query"; import type { LessonPrice } from "../../../components/teacherProfileSection/types"; import { ProfileAvatar } from "../../../components/teacherProfileSection/ProfileAvatar"; import { ProfileHeader } from "../../../components/teacherProfileSection/ProfileHeader"; @@ -18,7 +19,9 @@ import { } from "../../../api/teacher/teacher.api"; import { useMyProfileQuery } from "../../../features/teachers/query/useMyProfileQuery"; import { useUpdateMyProfileMutation } from "../../../features/teachers/mutations/useUpdateMyProfileMutation"; +import { useRegularStudentsQuery } from "../../../features/appointments/query/useRegularStudentsQuery"; import { useModalStore } from "../../../store/modals.store"; +import { queryKeys } from "../../../features/queryKeys"; export type { LessonPrice } from "../../../components/teacherProfileSection/types"; @@ -34,7 +37,9 @@ export interface TimeSlot { export const TeacherProfile = () => { const { data: profile, isLoading } = useMyProfileQuery(); const updateProfileMutation = useUpdateMyProfileMutation(); + const { data: regularStudentsData } = useRegularStudentsQuery(); const openModal = useModalStore((s) => s.open); + const queryClient = useQueryClient(); const [isEditing, setIsEditing] = useState(false); const [name, setName] = useState(""); @@ -270,6 +275,17 @@ export const TeacherProfile = () => { setSchedule(slots); const availability = mapUiSlotsToMergedWeekAvailability(slots); await updateMyWeeklyScheduleApi({ availability }); + + await queryClient.invalidateQueries({ + queryKey: queryKeys.teachers.myProfile(), + }); + + if (profile?.id) { + await queryClient.invalidateQueries({ + queryKey: queryKeys.teacher(profile.id), + }); + } + openModal("alert", { title: "Success", message: "Schedule saved successfully", @@ -298,6 +314,22 @@ export const TeacherProfile = () => { } }; + const getBookedSlots = (): TimeSlot[] => { + const regularStudents = regularStudentsData?.appointments || []; + const regularSlots: TimeSlot[] = []; + regularStudents.forEach((student) => { + if (student.weeklySchedule && Array.isArray(student.weeklySchedule)) { + student.weeklySchedule.forEach((slot) => { + regularSlots.push({ + day: slot.day, + hour: slot.hour, + }); + }); + } + }); + return regularSlots; + }; + const handleChangePassword = async ( oldPassword: string, newPassword: string, @@ -404,6 +436,7 @@ export const TeacherProfile = () => { onClose={() => setIsScheduleOpen(false)} onSave={handleScheduleSave} initialSlots={schedule} + bookedSlots={getBookedSlots()} /> Date: Sun, 1 Mar 2026 18:29:49 +0100 Subject: [PATCH 5/7] feat: teacher action --- .../teacherAppointmentCard/TeacherAppointmentActions.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/client/src/components/teacherAppointmentCard/TeacherAppointmentActions.tsx b/client/src/components/teacherAppointmentCard/TeacherAppointmentActions.tsx index 1724f6a..ebf03bd 100644 --- a/client/src/components/teacherAppointmentCard/TeacherAppointmentActions.tsx +++ b/client/src/components/teacherAppointmentCard/TeacherAppointmentActions.tsx @@ -27,12 +27,10 @@ export const TeacherAppointmentActions = ({ return (
- {/* Status buttons - ЗАВЖДИ показуються в Requests табі для не-past appointments */} {!isPast && !isRegularTab && onStatusChange && ( )} - {/* Add to Regular Students - показується тільки для approved appointments в Requests табі, якщо студент НЕ в regular */} {!isPast && !isRegularTab && status === "approved" && From 8e0fcda1b12c27f00e02c40612868183ce52bcac Mon Sep 17 00:00:00 2001 From: Dasha Date: Sun, 1 Mar 2026 18:49:32 +0100 Subject: [PATCH 6/7] fix: update import path for sidebar menu items in PrivateLayout --- client/src/layouts/PrivateLayout.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/layouts/PrivateLayout.tsx b/client/src/layouts/PrivateLayout.tsx index 92f74bf..9dae692 100644 --- a/client/src/layouts/PrivateLayout.tsx +++ b/client/src/layouts/PrivateLayout.tsx @@ -1,9 +1,9 @@ import { Outlet } from "react-router-dom"; +import { Sidebar } from "../components/sidebar/Sidebar.tsx"; import { defaultStudentMenuItems, defaultTeacherMenuItems, - Sidebar, -} from "../components/sidebar/Sidebar.tsx"; +} from "../components/sidebar/sidebarMenuItems.ts"; import { TopBar } from "../components/headerPrivate/TopBar.tsx"; import { useAuthSessionStore } from "../store/authSession.store.ts"; import { useEffect } from "react"; From 8a36b870d88989c42458b29852f736f746cb037f Mon Sep 17 00:00:00 2001 From: Dasha Date: Sun, 1 Mar 2026 19:00:19 +0100 Subject: [PATCH 7/7] fix:suggestions copilot --- .../RegularStudentScheduleModal.tsx | 14 +++------ .../teacherProfileSection/LessonSchedule.tsx | 28 +++++++----------- .../teacherSchedule/TeacherSchedule.tsx | 4 ++- .../TeacherAppointments.tsx | 29 ------------------- 4 files changed, 18 insertions(+), 57 deletions(-) diff --git a/client/src/components/regularStudentScheduleModal/RegularStudentScheduleModal.tsx b/client/src/components/regularStudentScheduleModal/RegularStudentScheduleModal.tsx index 5bde5f3..913e34d 100644 --- a/client/src/components/regularStudentScheduleModal/RegularStudentScheduleModal.tsx +++ b/client/src/components/regularStudentScheduleModal/RegularStudentScheduleModal.tsx @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { useState, useMemo } from "react"; import { Button } from "../ui/button/Button"; import Cross from "../icons/Cross"; import { SelectComponent } from "../ui/select/Select"; @@ -35,8 +35,9 @@ const ModalContent = ({ initialSchedule = [], occupiedSlots = [], }: Omit) => { + const initialSavedSlots = useMemo(() => initialSchedule, [initialSchedule]); const [savedSlots, setSavedSlots] = - useState(initialSchedule); + useState(initialSavedSlots); const [currentDay, setCurrentDay] = useState("Monday"); const [currentHour, setCurrentHour] = useState(7); @@ -213,16 +214,9 @@ const ModalContent = ({ export const RegularStudentScheduleModal = ({ isOpen, - studentName, ...props }: RegularStudentScheduleModalProps) => { if (!isOpen) return null; - return ( - - ); + return ; }; diff --git a/client/src/components/teacherProfileSection/LessonSchedule.tsx b/client/src/components/teacherProfileSection/LessonSchedule.tsx index b20fbdb..33c76e4 100644 --- a/client/src/components/teacherProfileSection/LessonSchedule.tsx +++ b/client/src/components/teacherProfileSection/LessonSchedule.tsx @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { useState, useMemo } from "react"; import { Button } from "../ui/button/Button.tsx"; import Cross from "../icons/Cross.tsx"; @@ -33,11 +33,17 @@ const ModalContent = ({ initialSlots = [], bookedSlots = [], }: Omit) => { - const [selectedSlots, setSelectedSlots] = useState>( + const initialSelectedSlots = useMemo( () => new Set(initialSlots.map((slot) => `${slot.day}-${slot.hour}`)), + [initialSlots], ); - const [blockedSlots] = useState>( + + const [selectedSlots, setSelectedSlots] = + useState>(initialSelectedSlots); + + const blockedSlots = useMemo( () => new Set(bookedSlots.map((slot) => `${slot.day}-${slot.hour}`)), + [bookedSlots], ); const toggleSlot = (day: string, hour: number) => { @@ -159,20 +165,8 @@ const ModalContent = ({ ); }; -export const LessonSchedule = ({ - isOpen, - initialSlots, - bookedSlots, - ...props -}: LessonScheduleProps) => { +export const LessonSchedule = ({ isOpen, ...props }: LessonScheduleProps) => { if (!isOpen) return null; - return ( - - ); + return ; }; diff --git a/client/src/components/teacherSection/teacherSchedule/TeacherSchedule.tsx b/client/src/components/teacherSection/teacherSchedule/TeacherSchedule.tsx index 34ced20..308c776 100644 --- a/client/src/components/teacherSection/teacherSchedule/TeacherSchedule.tsx +++ b/client/src/components/teacherSection/teacherSchedule/TeacherSchedule.tsx @@ -28,7 +28,9 @@ export default function TeacherSchedule({ teacher }: TeacherScheduleProps) { const isAuthenticated = !!user; const isTeacher = user?.role === "teacher"; - const { data } = useTeacherAppointmentsQuery(teacher?.id); + const { data } = useTeacherAppointmentsQuery( + isAuthenticated ? teacher?.id : undefined, + ); const appointments = useMemo(() => { const allAppointments = data?.appointments || []; diff --git a/client/src/pages/privetTeachersPages/teacherAppointments/TeacherAppointments.tsx b/client/src/pages/privetTeachersPages/teacherAppointments/TeacherAppointments.tsx index 88cb0eb..9b7cf75 100644 --- a/client/src/pages/privetTeachersPages/teacherAppointments/TeacherAppointments.tsx +++ b/client/src/pages/privetTeachersPages/teacherAppointments/TeacherAppointments.tsx @@ -13,18 +13,12 @@ import { useModalStore } from "../../../store/modals.store"; import { useVideoCall } from "../../../features/appointments/hooks/useVideoCall"; import { useAppointmentTime } from "../../../features/appointments/hooks/useAppointmentTime"; import { TeacherAppointmentsList } from "../../../components/teacherAppointmentCard/TeacherAppointmentsList"; -import { LessonSchedule } from "../../../components/teacherProfileSection/LessonSchedule"; import { RegularStudentScheduleModal } from "../../../components/regularStudentScheduleModal/RegularStudentScheduleModal"; import { useSetRegularStudentMutation } from "../../../features/appointments/mutations/useSetRegularStudentMutation"; import { useUpdateWeeklyScheduleMutation } from "../../../features/appointments/mutations/useUpdateWeeklyScheduleMutation"; import { useRemoveRegularStudentMutation } from "../../../features/appointments/mutations/useRemoveRegularStudentMutation"; import { useRegularStudentsQuery } from "../../../features/appointments/query/useRegularStudentsQuery"; -export interface TimeSlot { - day: string; - hour: number; -} - export const TeacherAppointments = () => { const [activeTab, setActiveTab] = useState<"requests" | "regular">( "requests", @@ -127,21 +121,6 @@ export const TeacherAppointments = () => { } }; - const getBookedSlots = () => { - const regularSlots: TimeSlot[] = []; - regularStudentsData?.appointments?.forEach((student) => { - if (student.weeklySchedule && Array.isArray(student.weeklySchedule)) { - student.weeklySchedule.forEach((slot) => { - regularSlots.push({ - day: slot.day, - hour: slot.hour, - }); - }); - } - }); - return regularSlots; - }; - const handleEditStudentSchedule = (appointment: Appointment) => { setSelectedStudent(appointment); setIsRegularStudentModalOpen(true); @@ -252,14 +231,6 @@ export const TeacherAppointments = () => { )}
- {}} - onSave={async () => {}} - initialSlots={[]} - bookedSlots={getBookedSlots()} - /> - {