diff --git a/src/components/BreakpointManager.ts b/src/components/BreakpointManager.ts index e23038ba3fc119626da099a49083871b7bc6a40c..746c510e5b809b7e09245489670dd721a32c3ab9 100644 --- a/src/components/BreakpointManager.ts +++ b/src/components/BreakpointManager.ts @@ -1,6 +1,7 @@ import { useContext, useEffect } from "react"; -import { getBreakpointForWidth } from "src/helper"; + import { AppStoreContext } from "./AppStoreContext"; +import { getBreakpointForWidth } from "src/helper"; export const BreakpointManager = () => { const appStore = useContext(AppStoreContext); diff --git a/src/helper.ts b/src/helper.ts index 0378e0da38ba3a37100ef693e526de4e5ed33da6..e1d6b762cff088d7b5a02199e9cdd528562a43bf 100644 --- a/src/helper.ts +++ b/src/helper.ts @@ -4,7 +4,7 @@ export const getBreakpointForWidth = (width: number): number => { const breakpoints = Object.keys(Breakpoint); let result = breakpoints[0]; - for (let i = 0; i < breakpoints.length && width > Breakpoint[breakpoints[i]]; i++) result = breakpoints[i]; + for (let i = 0; i < breakpoints.length && width >= Breakpoint[breakpoints[i]]; i++) result = breakpoints[i]; return Breakpoint[result]; }; diff --git a/src/screens/course/Course.tsx b/src/screens/course/Course.tsx index b0722ed6cc657a9fc969aa77b765ede6a41d5d4e..87157bd52a9074b3b6500bcb61f5672dec7b21e6 100644 --- a/src/screens/course/Course.tsx +++ b/src/screens/course/Course.tsx @@ -1,24 +1,87 @@ import { CourseContext, CourseProvider } from "./useCourse"; +import React, { useContext, useEffect, useMemo } from "react"; import { observer, useComputed } from "mobx-react-lite"; -import { useContext, useEffect, useMemo } from "react"; import { AppStoreContext } from "src/components/AppStoreContext"; import { Breakpoint } from "src/style"; import { LayoutContext } from "../../layout/Layout"; import { Loading } from "src/components/loading/Loading"; import { NavigationComponentProps } from "../../navigation/Navigator"; -import React from "react"; +import { courseFromJSON } from "openfing-core/lib/factories"; +import gql from "graphql-tag"; import queryString from "query-string"; import { styles } from "./Course.styles"; -import { toJS } from "mobx"; import { useDocumentTitle } from "../../components/useDocumentTitle"; -import { useFetchCourseByCode } from "openfing-core/lib/hooks/useFetchCourse"; import { useHistory } from "src/hooks/useHistory"; +import { useQuery } from "react-apollo-hooks"; +import { useRootStore } from "openfing-core/lib/hooks/useRootStore"; + +type CourseData = { + courseByCode: { + id: number; + code: string; + name?: string; + eva?: string; + iconURL?: string; + }; +}; + +const COURSE_QUERY = gql` + query courseByCode($code: String!) { + courseByCode(code: $code) { + id + code + name + eva + semester + year + iconURL + + classLists { + id + name + + classes { + id + title + number + + videos { + id + name + position + + qualities { + id + height + width + + formats { + id + name + url + } + } + } + } + } + } + } +`; // TODO: custom useQuery with parseData callback? +const useForceUpdate = () => { + const [, setB] = React.useState(false); + + return React.useCallback(() => { + setB(b => !b); + }, []); +}; + export const Course: React.FunctionComponent<NavigationComponentProps<{ courseCode: string }>> = observer(props => { const { courseCode } = props.match.params; + const forceUpdate = useForceUpdate(); const { history } = useHistory(); const queryParams = useMemo<{ t?: string; cci?: string; ccn?: string; ccl?: string }>( @@ -26,9 +89,20 @@ export const Course: React.FunctionComponent<NavigationComponentProps<{ courseCo [history.location.search] ); const appStore = useContext(AppStoreContext); - const [fetchCourseByCodeState] = useFetchCourseByCode({ courseCode, autoFetch: true, forceFetch: false }); + const { courseStore } = useRootStore(); + const course = courseStore.coursesByCode.get(courseCode) || undefined; + + const { loading, data, ...rest } = useQuery<CourseData>(COURSE_QUERY, { + skip: !!course && !!course.classLists, + variables: { code: courseCode }, + }); + React.useEffect(() => { + if (!data || !data.courseByCode) return; + + courseStore.saveCourse(courseFromJSON(data.courseByCode)); + forceUpdate(); + }, [data]); - const course = fetchCourseByCodeState.success ? fetchCourseByCodeState.course : undefined; const courseName = course ? course.name : undefined; const setLayoutOptions = useContext(LayoutContext); const contextRef = React.useRef<CourseContext>(); @@ -65,11 +139,15 @@ export const Course: React.FunctionComponent<NavigationComponentProps<{ courseCo if (!current) return; - current.fetchCourseByCodeState = fetchCourseByCodeState; + current.fetchCourseByCodeState = loading + ? { isLoading: loading } + : course + ? { isLoading: false, success: true, course } + : { isLoading: false, success: undefined }; current.course = course; current.courseClassList = courseClassList; current.courseClass = courseClass; - }, [fetchCourseByCodeState, course, courseClassList, courseClass]); + }, [loading, course, courseClassList, courseClass]); useEffect(() => { if (!contextRef.current) return; @@ -99,8 +177,6 @@ export const Course: React.FunctionComponent<NavigationComponentProps<{ courseCo ); return ( - <CourseProvider contextRef={contextRef}> - {fetchCourseByCodeState.isLoading ? <Loading /> : fetchCourseByCodeState.success ? content : null} - </CourseProvider> + <CourseProvider contextRef={contextRef}>{loading ? <Loading /> : course ? content : <div />}</CourseProvider> ); }); diff --git a/src/style/Mixins.ts b/src/style/Mixins.ts index 869636b2f7d00262f51bba261ba1f03fe93bbdd8..0bbafebaabf17f7d15bb5bd00145877b59b867d1 100644 --- a/src/style/Mixins.ts +++ b/src/style/Mixins.ts @@ -1,6 +1,7 @@ -import darken from "polished/lib/color/darken"; import { FlattenSimpleInterpolation, css } from "styled-components"; + import { Breakpoint } from "./Breakpoint"; +import darken from "polished/lib/color/darken"; export const EllipsisText = (maxHeight?: string) => css` overflow: hidden;