mirror of
https://github.com/xlorepdarkhelm/numinar-coding-project.git
synced 2026-09-09 17:45:35 -04:00
101 lines
2.7 KiB
TypeScript
101 lines
2.7 KiB
TypeScript
/**
|
|
* UserContext
|
|
* Provides user data and loading/error state for users.
|
|
* @context
|
|
*/
|
|
// External imports
|
|
import React, {
|
|
createContext,
|
|
useContext,
|
|
useEffect,
|
|
useState,
|
|
ReactNode,
|
|
} from "react";
|
|
|
|
// API imports
|
|
import { getUsers } from "../apis/users";
|
|
|
|
// Type-only imports
|
|
import type { User } from "../interfaces";
|
|
|
|
// Context imports
|
|
import { useBookings } from "./BookingContext";
|
|
|
|
/**
|
|
* useAvailableUsers
|
|
* Hook to get available users for a time slot using context.
|
|
* @param {Object} params - Parameters for filtering users
|
|
* @param {string} params.start_time - Start time
|
|
* @param {string} params.end_time - End time
|
|
* @param {string|number} [params.exclude_booking_id] - Booking ID to exclude
|
|
* @returns {User[]} Array of available users
|
|
*/
|
|
export function useAvailableUsers(params: {
|
|
start_time: string;
|
|
end_time: string;
|
|
exclude_booking_id?: string | number;
|
|
}): User[] {
|
|
const { users } = useUsers();
|
|
const { bookings } = useBookings();
|
|
const start = new Date(params.start_time).getTime();
|
|
const end = new Date(params.end_time).getTime();
|
|
const overlappingBookings = bookings.filter((b) => {
|
|
if (params.exclude_booking_id && b.id === params.exclude_booking_id)
|
|
return false;
|
|
const bStart = new Date(b.start_time).getTime();
|
|
const bEnd = new Date(b.end_time).getTime();
|
|
return bStart < end && bEnd > start;
|
|
});
|
|
const busyInvitees = new Set<string>();
|
|
overlappingBookings.forEach((b) => {
|
|
(b.invitees || []).forEach((email) => busyInvitees.add(email));
|
|
});
|
|
return users.filter((u) => u.email && !busyInvitees.has(u.email));
|
|
}
|
|
|
|
interface UserContextType {
|
|
users: User[];
|
|
loading: boolean;
|
|
error: Error | null;
|
|
}
|
|
|
|
const UserContext = createContext<UserContextType | undefined>(undefined);
|
|
|
|
/**
|
|
* UserProvider
|
|
* Provides user context to child components.
|
|
* @param {ReactNode} children - Child components
|
|
* @returns {JSX.Element} User context provider
|
|
*/
|
|
export const UserProvider: React.FC<{ children: ReactNode }> = ({
|
|
children,
|
|
}) => {
|
|
const [users, setUsers] = useState<User[]>([]);
|
|
const [loading, setLoading] = useState(true);
|
|
const [error, setError] = useState<Error | null>(null);
|
|
|
|
useEffect(() => {
|
|
getUsers()
|
|
.then((data) => {
|
|
setUsers(data || []);
|
|
setLoading(false);
|
|
})
|
|
.catch((err) => {
|
|
setError(err);
|
|
setLoading(false);
|
|
});
|
|
}, []);
|
|
|
|
return (
|
|
<UserContext.Provider value={{ users, loading, error }}>
|
|
{children}
|
|
</UserContext.Provider>
|
|
);
|
|
};
|
|
|
|
export const useUsers = () => {
|
|
const context = useContext(UserContext);
|
|
if (!context) throw new Error("useUsers must be used within a UserProvider");
|
|
return context;
|
|
};
|