mirror of
https://github.com/soconnor0919/hristudio.git
synced 2026-03-24 03:37:51 -04:00
chore: clean diagnostics and prepare for designer structural refactor (stub legacy useActiveStudy)
This commit is contained in:
123
src/hooks/useSelectedStudyDetails.ts
Normal file
123
src/hooks/useSelectedStudyDetails.ts
Normal file
@@ -0,0 +1,123 @@
|
||||
import { useCallback, useMemo } from "react";
|
||||
import { api } from "~/trpc/react";
|
||||
import { useStudyContext } from "~/lib/study-context";
|
||||
|
||||
/**
|
||||
* useSelectedStudyDetails
|
||||
*
|
||||
* Strongly typed unified source of truth for the currently selected study.
|
||||
*
|
||||
* Provides a single hook to retrieve:
|
||||
* - selected study id
|
||||
* - lightweight summary counts
|
||||
* - role + createdAt
|
||||
* - loading / fetching flags
|
||||
* - mutation helpers
|
||||
*/
|
||||
|
||||
interface StudyRelatedEntity {
|
||||
id: string;
|
||||
}
|
||||
|
||||
interface StudyMember {
|
||||
id: string;
|
||||
userId?: string;
|
||||
role?: string;
|
||||
}
|
||||
|
||||
interface StudyDetails {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string | null;
|
||||
status: string;
|
||||
experiments?: StudyRelatedEntity[];
|
||||
participants?: StudyRelatedEntity[];
|
||||
members?: StudyMember[];
|
||||
userRole?: string;
|
||||
createdAt?: Date;
|
||||
}
|
||||
|
||||
export interface StudySummary {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
status: string;
|
||||
experimentCount: number;
|
||||
participantCount: number;
|
||||
memberCount: number;
|
||||
userRole?: string;
|
||||
createdAt?: Date;
|
||||
}
|
||||
|
||||
export interface UseSelectedStudyDetailsReturn {
|
||||
studyId: string | null;
|
||||
study: StudySummary | null;
|
||||
isLoading: boolean;
|
||||
isFetching: boolean;
|
||||
refetch: () => Promise<unknown>;
|
||||
setStudyId: (id: string | null) => void;
|
||||
clearStudy: () => void;
|
||||
hasStudy: boolean;
|
||||
}
|
||||
|
||||
export function useSelectedStudyDetails(): UseSelectedStudyDetailsReturn {
|
||||
const { selectedStudyId, setSelectedStudyId } = useStudyContext();
|
||||
|
||||
const { data, isLoading, isFetching, refetch } = api.studies.get.useQuery(
|
||||
{ id: selectedStudyId ?? "" },
|
||||
{
|
||||
enabled: !!selectedStudyId,
|
||||
refetchOnWindowFocus: false,
|
||||
staleTime: 5 * 60 * 1000,
|
||||
},
|
||||
);
|
||||
|
||||
const study: StudySummary | null = useMemo(() => {
|
||||
if (!data || !selectedStudyId) return null;
|
||||
|
||||
// data is inferred from tRPC; we defensively narrow array fields
|
||||
const typed = data as StudyDetails;
|
||||
|
||||
const experiments = Array.isArray(typed.experiments)
|
||||
? typed.experiments
|
||||
: [];
|
||||
const participants = Array.isArray(typed.participants)
|
||||
? typed.participants
|
||||
: [];
|
||||
const members = Array.isArray(typed.members) ? typed.members : [];
|
||||
|
||||
return {
|
||||
id: typed.id,
|
||||
name: typed.name ?? "Unnamed Study",
|
||||
description: typed.description ?? "",
|
||||
status: typed.status ?? "active",
|
||||
experimentCount: experiments.length,
|
||||
participantCount: participants.length,
|
||||
memberCount: members.length,
|
||||
userRole: typed.userRole,
|
||||
createdAt: typed.createdAt,
|
||||
};
|
||||
}, [data, selectedStudyId]);
|
||||
|
||||
const setStudyId = useCallback(
|
||||
(id: string | null) => {
|
||||
void setSelectedStudyId(id);
|
||||
},
|
||||
[setSelectedStudyId],
|
||||
);
|
||||
|
||||
const clearStudy = useCallback(() => {
|
||||
void setSelectedStudyId(null);
|
||||
}, [setSelectedStudyId]);
|
||||
|
||||
return {
|
||||
studyId: selectedStudyId,
|
||||
study,
|
||||
isLoading,
|
||||
isFetching,
|
||||
refetch,
|
||||
setStudyId,
|
||||
clearStudy,
|
||||
hasStudy: !!study,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user