88 lines
2.2 KiB
TypeScript
88 lines
2.2 KiB
TypeScript
|
|
/**
|
||
|
|
* Custom hook for managing school comparison state
|
||
|
|
*/
|
||
|
|
|
||
|
|
'use client';
|
||
|
|
|
||
|
|
import { useState, useEffect, useCallback } from 'react';
|
||
|
|
import useSWR from 'swr';
|
||
|
|
import { fetcher } from '@/lib/api';
|
||
|
|
import { getFromLocalStorage, setToLocalStorage } from '@/lib/utils';
|
||
|
|
import type { School, ComparisonResponse } from '@/lib/types';
|
||
|
|
|
||
|
|
const STORAGE_KEY = 'selectedSchools';
|
||
|
|
const MAX_SCHOOLS = 5;
|
||
|
|
|
||
|
|
export function useComparison() {
|
||
|
|
const [selectedSchools, setSelectedSchools] = useState<School[]>([]);
|
||
|
|
const [isInitialized, setIsInitialized] = useState(false);
|
||
|
|
|
||
|
|
// Load from localStorage on mount
|
||
|
|
useEffect(() => {
|
||
|
|
const stored = getFromLocalStorage<School[]>(STORAGE_KEY, []);
|
||
|
|
setSelectedSchools(stored);
|
||
|
|
setIsInitialized(true);
|
||
|
|
}, []);
|
||
|
|
|
||
|
|
// Save to localStorage when schools change
|
||
|
|
useEffect(() => {
|
||
|
|
if (isInitialized) {
|
||
|
|
setToLocalStorage(STORAGE_KEY, selectedSchools);
|
||
|
|
}
|
||
|
|
}, [selectedSchools, isInitialized]);
|
||
|
|
|
||
|
|
// Fetch comparison data for selected schools
|
||
|
|
const urns = selectedSchools.map((s) => s.urn).join(',');
|
||
|
|
const { data, error, isLoading, mutate } = useSWR<ComparisonResponse>(
|
||
|
|
selectedSchools.length > 0 ? `/compare?urns=${urns}` : null,
|
||
|
|
fetcher,
|
||
|
|
{
|
||
|
|
revalidateOnFocus: false,
|
||
|
|
dedupingInterval: 10000, // 10 seconds
|
||
|
|
}
|
||
|
|
);
|
||
|
|
|
||
|
|
const addSchool = useCallback((school: School) => {
|
||
|
|
setSelectedSchools((prev) => {
|
||
|
|
// Check if already selected
|
||
|
|
if (prev.some((s) => s.urn === school.urn)) {
|
||
|
|
return prev;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Check max limit
|
||
|
|
if (prev.length >= MAX_SCHOOLS) {
|
||
|
|
alert(`Maximum ${MAX_SCHOOLS} schools can be compared`);
|
||
|
|
return prev;
|
||
|
|
}
|
||
|
|
|
||
|
|
return [...prev, school];
|
||
|
|
});
|
||
|
|
}, []);
|
||
|
|
|
||
|
|
const removeSchool = useCallback((urn: number) => {
|
||
|
|
setSelectedSchools((prev) => prev.filter((s) => s.urn !== urn));
|
||
|
|
}, []);
|
||
|
|
|
||
|
|
const clearAll = useCallback(() => {
|
||
|
|
setSelectedSchools([]);
|
||
|
|
}, []);
|
||
|
|
|
||
|
|
const isSelected = useCallback(
|
||
|
|
(urn: number) => selectedSchools.some((s) => s.urn === urn),
|
||
|
|
[selectedSchools]
|
||
|
|
);
|
||
|
|
|
||
|
|
return {
|
||
|
|
selectedSchools,
|
||
|
|
comparisonData: data?.comparison,
|
||
|
|
isLoading,
|
||
|
|
error,
|
||
|
|
addSchool,
|
||
|
|
removeSchool,
|
||
|
|
clearAll,
|
||
|
|
isSelected,
|
||
|
|
canAddMore: selectedSchools.length < MAX_SCHOOLS,
|
||
|
|
mutate,
|
||
|
|
};
|
||
|
|
}
|