Spaces:
Sleeping
Sleeping
| import React, { createContext, useContext, useEffect, useState, useCallback } from 'react'; | |
| import { useAuth } from './authContext'; | |
| import { getApiBaseUrl } from './api/config'; | |
| const BASE_URL = getApiBaseUrl(); | |
| const TOKEN_KEY = 'authToken'; | |
| // โโโ Types โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| export interface SheikhDto { | |
| id: number; | |
| name: string; | |
| country: string; | |
| rating: number; | |
| pricePerHour: number; | |
| experienceYears: number; | |
| description: string; | |
| specializations: string; | |
| } | |
| export interface SheikhProfileDto extends SheikhDto { | |
| bio?: string; | |
| certificateUrl?: string; | |
| profilePhotoUrl?: string; | |
| } | |
| interface FilterRequest { | |
| name: string | null; | |
| country: string | null; | |
| ratingAsc: boolean | null; | |
| priceAsc: boolean | null; | |
| } | |
| // โโโ API helpers โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| function getHeaders(): HeadersInit { | |
| const token = localStorage.getItem(TOKEN_KEY) ?? ''; | |
| return { | |
| 'Content-Type': 'application/json', | |
| ...(token ? { Authorization: `Bearer ${token}` } : {}), | |
| }; | |
| } | |
| export async function apiFetchAllSheikhs(): Promise<SheikhDto[]> { | |
| const res = await fetch(`${BASE_URL}/api/sheikhs/allSheikhsToStudents`, { | |
| headers: getHeaders(), | |
| }); | |
| if (!res.ok) throw new Error(`Failed to fetch sheikhs: ${res.status}`); | |
| const data = await res.json(); | |
| if (!Array.isArray(data)) return []; | |
| // Debug: log first sheikh to see the structure | |
| if (data.length > 0) { | |
| console.log('[StudentContext] Sheikh data structure:', Object.keys(data[0])); | |
| console.log('[StudentContext] First sheikh:', data[0]); | |
| } | |
| return data; | |
| } | |
| export async function apiFilterSheikhs(filter: FilterRequest): Promise<SheikhDto[]> { | |
| const res = await fetch(`${BASE_URL}/api/sheikhs/filter`, { | |
| method: 'POST', | |
| headers: getHeaders(), | |
| body: JSON.stringify(filter), | |
| }); | |
| if (!res.ok) throw new Error(`Failed to filter sheikhs: ${res.status}`); | |
| const data = await res.json(); | |
| return Array.isArray(data) ? data : []; | |
| } | |
| export async function apiFetchSheikhById(id: string): Promise<SheikhProfileDto> { | |
| if (!id || id === 'undefined') { | |
| throw new Error('Invalid sheikh ID'); | |
| } | |
| // โ ุงุณุชุฎุฏู /profile ูู ุง ูู ู ุฐููุฑ ูู ุงูุชูุซูู | |
| const res = await fetch(`${BASE_URL}/api/sheikhs/${id}/profile`, { | |
| headers: getHeaders(), | |
| }); | |
| if (res.status === 401 || res.status === 403) { | |
| throw new Error('Please login again - session expired'); | |
| } | |
| if (!res.ok) throw new Error(`Sheikh not found: ${res.status}`); | |
| const data = await res.json(); | |
| // โ ุงูู API ุจูุฑุฌุน { profile, numberOfSessions } | |
| if (!data.profile) { | |
| throw new Error('Invalid profile data'); | |
| } | |
| // โ ุฃุฑุฌุน ุงูู profile ููุท (ุฃู ุงุฑุฌุน data ูุงู ูุฉ ูู ู ุญุชุงุฌ numberOfSessions) | |
| return data.profile as SheikhProfileDto; | |
| } | |
| // โโโ Context โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
| interface StudentContextType { | |
| sheikhs: SheikhDto[]; | |
| loading: boolean; | |
| error: string | null; | |
| fetchSheikhs: () => Promise<void>; | |
| filterSheikhs: (filter: FilterRequest) => Promise<void>; | |
| fetchSheikhById: (id: string) => Promise<SheikhProfileDto | null>; | |
| } | |
| const StudentContext = createContext<StudentContextType | undefined>(undefined); | |
| export function StudentProvider({ children }: { children: React.ReactNode }) { | |
| const { user } = useAuth(); | |
| const [sheikhs, setSheikhs] = useState<SheikhDto[]>([]); | |
| const [loading, setLoading] = useState(false); | |
| const [error, setError] = useState<string | null>(null); | |
| const fetchSheikhs = async () => { | |
| if (!user || user.role !== 'student') return; | |
| setLoading(true); | |
| setError(null); | |
| try { | |
| const data = await apiFetchAllSheikhs(); | |
| setSheikhs(data); | |
| } catch (err) { | |
| setError(err instanceof Error ? err.message : 'Failed to load sheikhs'); | |
| } finally { | |
| setLoading(false); | |
| } | |
| }; | |
| const filterSheikhs = async (filter: FilterRequest) => { | |
| setLoading(true); | |
| setError(null); | |
| try { | |
| const data = await apiFilterSheikhs(filter); | |
| setSheikhs(data); | |
| } catch (err) { | |
| setError(err instanceof Error ? err.message : 'Failed to filter sheikhs'); | |
| } finally { | |
| setLoading(false); | |
| } | |
| }; | |
| const fetchSheikhById = useCallback(async (id: string): Promise<SheikhProfileDto | null> => { | |
| try { | |
| return await apiFetchSheikhById(id); | |
| } catch (err) { | |
| console.error('Failed to fetch sheikh:', err); | |
| setError(err instanceof Error ? err.message : 'Failed to load sheikh profile'); | |
| return null; | |
| } | |
| }, []); // stable reference โ apiFetchSheikhById is a module-level function | |
| useEffect(() => { | |
| if (user?.role === 'student') { | |
| fetchSheikhs(); | |
| } | |
| }, [user]); | |
| return ( | |
| <StudentContext.Provider value={{ | |
| sheikhs, | |
| loading, | |
| error, | |
| fetchSheikhs, | |
| filterSheikhs, | |
| fetchSheikhById | |
| }}> | |
| {children} | |
| </StudentContext.Provider> | |
| ); | |
| } | |
| export function useStudent() { | |
| const context = useContext(StudentContext); | |
| if (!context) throw new Error('useStudent must be used within StudentProvider'); | |
| return context; | |
| } |