user()->id) ->with('category_to_tutorCategory') // Eager load the related category ->get(); // Filter out duplicates by category_id $page_data['categories'] = $categories->unique('category_id'); return view('instructor.tutor_booking.my_subjects', $page_data); } public function my_subject_add() {} public function my_subject_store(Request $request) { $validated = $request->validate([ 'category_id' => 'required', 'subject_id' => 'required', 'description' => 'required', 'price' => 'required' ]); $data['category_id'] = $request->category_id; $data['subject_id'] = $request->subject_id; $data['instructor_id'] = auth()->user()->id; $data['description'] = $request->description; $data['price'] = $request->price; $data['created_at'] = date('Y-m-d H:i:s'); $data['updated_at'] = date('Y-m-d H:i:s'); if ($request->thumbnail) { $data['thumbnail'] = "uploads/tutor-booking/subject-thumbnail/" . nice_file_name(random(9), $request->thumbnail->extension()); FileUploader::upload($request->thumbnail, $data['thumbnail'], 400, null, 200, 200); } TutorCanTeach::insert($data); return redirect(route('instructor.my_subjects'))->with('success', get_phrase('Subject added successfully')); } public function my_subject_edit() {} public function my_subject_update(Request $request, $id) { $validated = $request->validate([ 'category_id' => 'required', 'subject_id' => 'required', 'description' => 'required', 'price' => 'required' ]); // Fetch the existing record $subject = TutorCanTeach::findOrFail($id); // Prepare the data for update $data['category_id'] = $request->category_id; $data['subject_id'] = $request->subject_id; $data['instructor_id'] = auth()->user()->id; $data['description'] = $request->description; $data['price'] = $request->price; $data['updated_at'] = date('Y-m-d H:i:s'); // Handle thumbnail upload if ($request->thumbnail) { // Unlink the previous thumbnail if it exists if ($subject->thumbnail && file_exists(public_path($subject->thumbnail))) { unlink(public_path($subject->thumbnail)); } // Generate a new thumbnail path and upload the new file $data['thumbnail'] = "uploads/tutor-booking/subject-thumbnail/" . nice_file_name(random(9), $request->thumbnail->extension()); FileUploader::upload($request->thumbnail, $data['thumbnail'], 400, null, 200, 200); } // Update the record TutorCanTeach::where('id', $id)->update($data); // Redirect back with success message return redirect(route('instructor.my_subjects'))->with('success', get_phrase('Subject updated successfully')); } public function my_subject_delete($id) { $query = TutorCanTeach::where('id', $id); $query->delete(); return redirect(route('instructor.my_subjects'))->with('success', get_phrase('Subject deleted successfully')); } public function my_subject_category_delete($id) { $subjects = TutorCanTeach::where('category_id', $id)->get(); if ($subjects->isEmpty()) { return redirect()->back()->with('error', get_phrase('No subjects found for this category')); } // Delete all records associated with the category_id TutorCanTeach::where('category_id', $id)->delete(); // Redirect with a success message return redirect(route('instructor.my_subjects'))->with('success', get_phrase('Subjects for the selected category deleted successfully')); } public function manage_schedules() { // Retrieve the schedules for the authenticated tutor $schedule_list = TutorSchedule::where('tutor_id', auth()->user()->id)->get(); $schedulesByDate = []; foreach ($schedule_list as $schedule) { // Get the formatted date (Y-m-d) from the start time $date = date('Y-m-d', $schedule->start_time); // Group schedules by date if (!isset($schedulesByDate[$date])) { $schedulesByDate[$date] = 0; } // Increment count for the specific date $schedulesByDate[$date]++; } $schedules = []; foreach ($schedulesByDate as $date => $count) { // Create an info array for each unique date with schedule count $info = [ 'title' => $count . ' schedules', // Display the count of schedules 'start' => $date, // Use the date as start ]; $schedules[] = $info; } // Convert the schedules array to JSON $schedules = json_encode($schedules); // Pass the schedules to the view return view('instructor.tutor_booking.manage_schedules', ['schedules' => $schedules]); } public function manage_schedules_by_date($date) { // Parse the provided date to match the expected format (e.g., '12-Feb-24') $parsedDate = \DateTime::createFromFormat('d-M-y', $date); if (!$parsedDate) { Session::flash('error', get_phrase('Invalid date format')); return redirect()->back(); } $formattedDate = $parsedDate->format('Y-m-d'); // Get the start and end timestamps for the selected day $dayStart = $parsedDate->setTime(0, 0)->getTimestamp(); $dayEnd = $parsedDate->setTime(23, 59, 59)->getTimestamp(); // Retrieve schedules for the authenticated tutor within the specified day's timestamp range $schedules = TutorSchedule::where('tutor_id', auth()->user()->id) ->where('start_time', '>=', $dayStart) ->where('start_time', '<=', $dayEnd) ->paginate(10); return view('instructor.tutor_booking.schedules_by_day', ['schedules' => $schedules, 'selected_date' => $date]); } public function schedule_edit($id = "") { $page_data['schedule_details'] = TutorSchedule::find($id); // Fetch all records for the instructor $categories = TutorCanTeach::where('instructor_id', auth()->user()->id) ->with('category_to_tutorCategory') // Eager load the related category ->get(); // Filter out duplicates by category_id $page_data['categories'] = $categories->unique('category_id'); return view('instructor.tutor_booking.edit_schedule', $page_data); } public function schedule_update(Request $request, $id) { // Validate the form input $validated = $request->validate([ 'category_id' => 'required|integer', 'subject_id' => 'required|integer', 'start_time' => 'required|date', 'duration' => 'required|integer', 'description' => 'nullable|string', ]); // Cast duration to an integer just in case $duration = (int) $validated['duration']; // Start time for the session $startDate = Carbon::parse($validated['start_time']); // Save single session to TutorSchedule TutorSchedule::where('id', $id)->update([ 'category_id' => $validated['category_id'], 'subject_id' => $validated['subject_id'], 'start_time' => $startDate->timestamp, // Store as timestamp 'end_time' => $startDate->copy()->addMinutes($duration)->timestamp, 'duration' => $duration, 'description' => $validated['description'], ]); // Extract the date in the desired format (e.g., 12-Feb-24) $date = $startDate->format('d-M-y'); return redirect()->route('instructor.manage_schedules_by_date', ['date' => $date])->with('success', get_phrase('Schedule updated successfully.')); } public function schedule_delete($id) { // Retrieve the schedule record $schedule = TutorSchedule::find($id); if (!$schedule) { return redirect()->back()->with('error', get_phrase('No schedule found for this id')); } // Delete the schedule $schedule->delete(); // Redirect to the route with the formatted date return redirect()->back()->with('success', get_phrase('Schedule deleted successfully.')); } public function add_schedule() { // Fetch all records for the instructor $categories = TutorCanTeach::where('instructor_id', auth()->user()->id) ->with('category_to_tutorCategory') // Eager load the related category ->get(); // Filter out duplicates by category_id $page_data['categories'] = $categories->unique('category_id'); return view('instructor.tutor_booking.add_schedule', $page_data); } public function schedule_store(Request $request) { // Validate the form input $validated = $request->validate([ 'category_id' => 'required|integer', 'subject_id' => 'required|integer', 'tution_type' => 'required|integer', // 1 for single, 0 for repeated 'start_time' => 'required|date', 'end_time' => 'nullable|date', // Only needed for repeated sessions 'duration' => 'required|integer', 'description' => 'nullable|string', '1_day' => 'nullable|array', // Only for repeated schedule (array of selected days) ]); // Cast duration to an integer just in case $duration = (int) $validated['duration']; // Start time for the session $startDate = Carbon::parse($validated['start_time']); if ($validated['tution_type'] == 0) { // Repeated session (tution_type == 0) if (!empty($validated['end_time'])) { $endDate = Carbon::parse($validated['end_time']); // Create a period between start and end dates $period = CarbonPeriod::create($startDate, $endDate); // Check if specific days are selected for the repeated schedule if (!empty($validated['1_day'])) { foreach ($period as $date) { $dayOfWeek = strtolower($date->format('l')); if (in_array($dayOfWeek, $validated['1_day'])) { // Save each repeated session to TutorSchedule TutorSchedule::create([ 'tutor_id' => auth()->user()->id, 'category_id' => $validated['category_id'], 'subject_id' => $validated['subject_id'], 'start_time' => $date->timestamp, // Store as timestamp 'end_time' => $date->copy()->addMinutes($duration)->timestamp, 'duration' => $duration, 'description' => $validated['description'], 'tution_type' => $validated['tution_type'], ]); } } } } } else { // Single session (tution_type == 1) // Save single session to TutorSchedule TutorSchedule::create([ 'tutor_id' => auth()->user()->id, 'category_id' => $validated['category_id'], 'subject_id' => $validated['subject_id'], 'start_time' => $startDate->timestamp, // Store as timestamp 'end_time' => $startDate->copy()->addMinutes($duration)->timestamp, 'duration' => $duration, 'description' => $validated['description'], 'tution_type' => $validated['tution_type'], ]); } return redirect(route('instructor.manage_schedules'))->with('success', get_phrase('Schedule successfully created.')); } public function subject_by_category_id(Request $request) { if (isset($request->category_id)) { $teaches = TutorCanTeach::where('category_id', $request->category_id)->get(); return view('instructor.tutor_booking.load_subjects', compact('teaches')); } } public function tutor_booking_list() { // Get the current timestamp for today at midnight $todayStart = strtotime('today'); // Initialize query for current bookings (today onwards) $currentQuery = TutorBooking::where('tutor_bookings.start_time', '>=', $todayStart) ->join('tutor_schedules', 'tutor_bookings.schedule_id', '=', 'tutor_schedules.id') ->join('tutor_subjects', 'tutor_schedules.subject_id', '=', 'tutor_subjects.id') ->join('users', 'tutor_bookings.student_id', '=', 'users.id') ->select('tutor_bookings.*', 'tutor_subjects.name', 'users.name as student_name') ->orderBy('tutor_bookings.id', 'desc'); // Initialize query for archived bookings (before today) $archiveQuery = TutorBooking::where('tutor_bookings.start_time', '<', $todayStart) ->join('tutor_schedules', 'tutor_bookings.schedule_id', '=', 'tutor_schedules.id') ->join('tutor_subjects', 'tutor_schedules.subject_id', '=', 'tutor_subjects.id') ->join('users', 'tutor_bookings.student_id', '=', 'users.id') ->select('tutor_bookings.*', 'tutor_subjects.name', 'users.name as student_name') ->orderBy('tutor_bookings.id', 'desc'); // Add search condition for both queries if (request()->has('search')) { $search = request()->query('search'); $currentQuery = $currentQuery->where(function ($q) use ($search) { $q->where('users.name', 'LIKE', "%{$search}%") ->orWhere('tutor_subjects.name', 'LIKE', "%{$search}%"); }); $archiveQuery = $archiveQuery->where(function ($q) use ($search) { $q->where('users.name', 'LIKE', "%{$search}%") ->orWhere('tutor_subjects.name', 'LIKE', "%{$search}%"); }); } // Paginate results $page_data['booking_list'] = $currentQuery->paginate(20)->appends(request()->query()); $page_data['archive_list'] = $archiveQuery->paginate(20, ['*'], 'archive_page')->appends(request()->query()); // Return the view with the data return view('instructor.tutor_booking.tutor_booking_list', $page_data); } public function join_class($booking_id = "") { $booking_details = TutorBooking::find($booking_id); if(empty($booking_details->joining_data)) { $joining_info = $this->create_zoom_meeting($booking_details->booking_to_schedule->schedule_to_tutorSubjects->name, $booking_details->start_time); $meeting_info = json_decode($joining_info, true); if (array_key_exists('code', $meeting_info) && $meeting_info) { return redirect()->back()->with('error', get_phrase($meeting_info['message'])); } $data['joining_data'] = $joining_info; TutorBooking::where('id', $booking_id)->update($data); } else { $meeting_info = json_decode($booking_details->joining_data, true); } $current_time = time(); $extended_time = $current_time + (60 * 15); $booking = TutorBooking::where('id', $booking_id) ->where('start_time', '<', $extended_time) ->where('end_time', '>', $current_time) ->where('tutor_id', auth()->user()->id) ->first(); if (! $booking) { Session::flash('error', get_phrase('Session not found.')); return redirect()->back(); } if (get_settings('zoom_web_sdk') == 'active') { $page_data['booking'] = $booking; $page_data['user'] = get_user_info($booking->tutor_id); $page_data['is_host'] = 1; return view('instructor.tutor_booking.join_tution', $page_data); } else { return redirect($meeting_info['start_url']); } } public function create_zoom_meeting($topic, $date_and_time) { $zoom_account_email = get_settings('zoom_account_email'); $token = $this->create_zoom_token(); // API Endpoint for creating a meeting $zoomEndpoint = 'https://api.zoom.us/v2/users/me/meetings'; // Meeting data $meetingData = [ 'topic' => $topic, 'schedule_for' => $zoom_account_email, 'type' => 2, // Scheduled meeting 'start_time' => date('Y-m-d\TH:i:s', strtotime($date_and_time)), // Start time (in UTC) 'duration' => 60, // Duration in minutes 'timezone' => get_settings('timezone'), // Timezone 'settings' => [ 'approval_type' => 2, 'join_before_host' => true, 'jbh_time' => 0, ], ]; // Prepare headers $headers = [ 'Authorization: Bearer ' . $token, 'Content-Type: application/json', ]; // Make POST request to create meeting $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $zoomEndpoint); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($meetingData)); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); $response = curl_exec($ch); curl_close($ch); // JSON response return $response; } public function create_zoom_token() { // Access the environment variables $clientId = get_settings('zoom_client_id'); $clientSecret = get_settings('zoom_client_secret'); $accountId = get_settings('zoom_account_id'); $oauthUrl = 'https://zoom.us/oauth/token?grant_type=account_credentials&account_id=' . $accountId; // Replace with your OAuth endpoint URL $authHeader = 'Basic ' . base64_encode($clientId . ':' . $clientSecret); $curl = curl_init(); curl_setopt_array($curl, array( CURLOPT_URL => 'https://zoom.us/oauth/token?grant_type=account_credentials&account_id=' . $accountId, CURLOPT_RETURNTRANSFER => true, CURLOPT_ENCODING => '', CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 0, CURLOPT_FOLLOWLOCATION => true, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, CURLOPT_CUSTOMREQUEST => 'POST', CURLOPT_HTTPHEADER => array( 'Content-Type: application/x-www-form-urlencoded', 'Authorization: ' . $authHeader, 'Cookie: __cf_bm=kn5ec2sntPlDgQWVWtSYdPeISb6bp6F7NHwuAFJQaGk-1736318967-1.0.1.1-SeM4z5pIb.nrMno35jg3y5BdXib.GPP13s2_yNnqz6LxbU9zsFTfZQc3a_Di94qx3DoyQjBT2Osz7idFMWWOrw; _zm_chtaid=816; _zm_ctaid=nbT15WlMTsCEAgCyUg3rYw.1736318967206.63747957ef3128f771210fb69e8d6831; _zm_mtk_guid=fa77ae1ac8e349bea690b72d942d6de6; _zm_page_auth=us04_c_uqPDVOshQQK6FRkhQPiPRA; _zm_ssid=us04_c_atJ4QboaQZG4Lw4U-Wpx6A; cred=A404810ADF33AFC21FF517216A4CB862' ), )); $response = curl_exec($curl); curl_close($curl); $oauthResponse = json_decode($response, true) ?? ['access_token' => '']; $accessToken = $oauthResponse['access_token']; return $accessToken; } }