From 1610cc4022f36446707b6581a67c54bc1815e131 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mikko=20Pyykk=C3=B6?= Date: Fri, 18 Aug 2023 12:47:51 +0300 Subject: [PATCH] fix user state not updating on login/logout (#1225) --- frontend/components/Dashboard/CourseCard.tsx | 3 +++ .../Editor/Course/form-validation.tsx | 9 +++++--- .../Dashboard/Editor/Course/serialization.ts | 5 ++--- .../Dashboard/Editor/Course/types.ts | 4 ++-- .../Dashboard/Users/Search/SearchForm.tsx | 22 ++++++++++++++++--- .../Users/Summary/Course/CourseEntry.tsx | 7 ++---- .../Users/Summary/UserPointsSummary.tsx | 13 +---------- frontend/components/Link.tsx | 2 +- frontend/components/SignInForm.tsx | 12 +++++----- frontend/lib/authentication.ts | 5 ++--- frontend/lib/with-apollo-client/get-apollo.ts | 2 +- frontend/lib/with-apollo-client/index.tsx | 6 ++--- frontend/pages/_app.tsx | 9 ++++---- frontend/pages/_document.tsx | 8 ++++++- 14 files changed, 59 insertions(+), 48 deletions(-) diff --git a/frontend/components/Dashboard/CourseCard.tsx b/frontend/components/Dashboard/CourseCard.tsx index 7a5a11ffd..f36c9cea4 100644 --- a/frontend/components/Dashboard/CourseCard.tsx +++ b/frontend/components/Dashboard/CourseCard.tsx @@ -239,6 +239,7 @@ const CourseCard = ({ course, loading, isNew }: CourseCardProps) => { <> } @@ -247,6 +248,7 @@ const CourseCard = ({ course, loading, isNew }: CourseCardProps) => { { )} {isNew && ( { .required(t("courseTeacherEmailRequired")), support_email: Yup.string().email(t("courseEmailInvalid")), start_date: Yup.mixed() + .nullable() .typeError(t("courseStartDateRequired")) .required(t("courseStartDateRequired")) .transform((datetime?: string | DateTime) => { @@ -124,6 +125,7 @@ const courseEditSchema = ({ client, initialSlug, t }: CourseEditSchemaArgs) => { }, ), end_date: Yup.mixed() + .nullable() .test( "end_invalid", t("invalidDate"), @@ -234,9 +236,10 @@ const courseEditSchema = ({ client, initialSlug, t }: CourseEditSchemaArgs) => { }) } -export type CourseEditSchemaType = Yup.InferType< - ReturnType -> +export type CourseEditSchemaType = Omit< + Yup.InferType>, + "start_date" +> & { start_date: DateTime | null } // help typescript a bit, even if we don't really allow null interface ValidateSlugArgs { client: ApolloClient diff --git a/frontend/components/Dashboard/Editor/Course/serialization.ts b/frontend/components/Dashboard/Editor/Course/serialization.ts index a94b1dc17..c7050b14b 100644 --- a/frontend/components/Dashboard/Editor/Course/serialization.ts +++ b/frontend/components/Dashboard/Editor/Course/serialization.ts @@ -45,9 +45,8 @@ export const toCourseForm = ({ ]), language: course.language ?? "", support_email: course.support_email ?? "", - // @ts-expect-error: expected to be invalid initially - start_date: course.start_date ? DateTime.fromISO(course.start_date) : "", - end_date: course.end_date ? DateTime.fromISO(course.end_date) : undefined, + start_date: course.start_date ? DateTime.fromISO(course.start_date) : null, + end_date: course.end_date ? DateTime.fromISO(course.end_date) : null, start_point: course.start_point ?? false, promote: course.promote ?? false, hidden: course.hidden ?? false, diff --git a/frontend/components/Dashboard/Editor/Course/types.ts b/frontend/components/Dashboard/Editor/Course/types.ts index 1c3950217..4346ef280 100644 --- a/frontend/components/Dashboard/Editor/Course/types.ts +++ b/frontend/components/Dashboard/Editor/Course/types.ts @@ -18,8 +18,8 @@ export interface CourseFormValues extends FormValues { teacher_in_charge_name: string teacher_in_charge_email: string support_email?: string - start_date: DateTime - end_date?: DateTime + start_date: DateTime | null + end_date: DateTime | null ects?: string photo?: string | ImageCoreFieldsFragment | null language?: string diff --git a/frontend/components/Dashboard/Users/Search/SearchForm.tsx b/frontend/components/Dashboard/Users/Search/SearchForm.tsx index ff9c6c995..02246cac6 100644 --- a/frontend/components/Dashboard/Users/Search/SearchForm.tsx +++ b/frontend/components/Dashboard/Users/Search/SearchForm.tsx @@ -6,6 +6,8 @@ import { useState, } from "react" +import dynamic from "next/dynamic" + import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown" import KeyboardArrowUpIcon from "@mui/icons-material/KeyboardArrowUp" import { @@ -20,10 +22,7 @@ import { styled } from "@mui/material/styles" import { useEventCallback } from "@mui/material/utils" import { Column, Row } from "./Common" -import MobileGrid from "./MobileGrid" import { SearchFieldOptions } from "./SearchFieldOptions" -import { MetaResult, NarrowMetaResult } from "./SearchMetaResult" -import WideGrid from "./WideGrid" import { ButtonWithPaddingAndMargin } from "/components/Buttons/ButtonWithPaddingAndMargin" import { H1NoBackground } from "/components/Text/headers" import UserSearchContext from "/contexts/UserSearchContext" @@ -31,6 +30,23 @@ import { useTranslator } from "/hooks/useTranslator" import UsersTranslations from "/translations/users" import { isDefinedAndNotEmpty } from "/util/guards" +const MobileGrid = dynamic(() => import("./MobileGrid"), { + ssr: false, + loading: () => null, +}) +const WideGrid = dynamic(() => import("./WideGrid"), { + ssr: false, + loading: () => null, +}) +const MetaResult = dynamic( + () => import("./SearchMetaResult").then((c) => c.MetaResult), + { ssr: false, loading: () => null }, +) +const NarrowMetaResult = dynamic( + () => import("./SearchMetaResult").then((c) => c.NarrowMetaResult), + { ssr: false, loading: () => null }, +) + const StyledForm = styled("form")` display: flex; flex-direction: column; diff --git a/frontend/components/Dashboard/Users/Summary/Course/CourseEntry.tsx b/frontend/components/Dashboard/Users/Summary/Course/CourseEntry.tsx index 060f2ee6c..3f51e2855 100644 --- a/frontend/components/Dashboard/Users/Summary/Course/CourseEntry.tsx +++ b/frontend/components/Dashboard/Users/Summary/Course/CourseEntry.tsx @@ -82,11 +82,8 @@ export function CourseEntry({ children }: PropsWithChildren) { key={`${selectedData.course.id}-progress`} data={selectedData} /> - - + + )} diff --git a/frontend/components/Dashboard/Users/Summary/UserPointsSummary.tsx b/frontend/components/Dashboard/Users/Summary/UserPointsSummary.tsx index 53b779a8d..debd59d71 100644 --- a/frontend/components/Dashboard/Users/Summary/UserPointsSummary.tsx +++ b/frontend/components/Dashboard/Users/Summary/UserPointsSummary.tsx @@ -26,18 +26,7 @@ function UserPointsSummary() { return ( {!isNarrow && } - {loading || state.loading ? ( - - ) : ( - /*data?.length === 0 ? ( - - {t("noResults")} - - ) : */ - )} - {/*filteredData.map((entry, index) => ( - - ))*/} + {loading || state.loading ? : } ) } diff --git a/frontend/components/Link.tsx b/frontend/components/Link.tsx index 6934b43a4..e44c8764c 100644 --- a/frontend/components/Link.tsx +++ b/frontend/components/Link.tsx @@ -7,5 +7,5 @@ export const LinkBehavior = React.forwardRef< React.AnchorHTMLAttributes & NextLinkProps >((props, ref) => { const { href, ...other } = props - return + return }) diff --git a/frontend/components/SignInForm.tsx b/frontend/components/SignInForm.tsx index d98aa8093..3b38d92ec 100644 --- a/frontend/components/SignInForm.tsx +++ b/frontend/components/SignInForm.tsx @@ -96,12 +96,12 @@ function SignIn() { // TODO: typing e.preventDefault() try { - await signIn( - { email, password, shallow: false }, - apollo, - logInOrOut, - ) - + await signIn({ email, password, shallow: false }, apollo) + try { + await logInOrOut() + } catch (e) { + console.error("Login in or out failed") + } if (errorTimeout) { clearTimeout(errorTimeout) } diff --git a/frontend/lib/authentication.ts b/frontend/lib/authentication.ts index 6ccb9ccf7..0b6a30668 100644 --- a/frontend/lib/authentication.ts +++ b/frontend/lib/authentication.ts @@ -38,12 +38,12 @@ export const signIn = async ( const res = await tmcClient.authenticate({ username: email, password }) const details = await userDetails(res.accessToken) - await apollo?.resetStore() - document.cookie = `access_token=${res.accessToken};path=/` document.cookie = `admin=${details.administrator};path=/` + await apollo?.resetStore() + cb?.() const rawRedirectLocation = nookies.get()["redirect-back"] @@ -85,7 +85,6 @@ export const signOut = async ( setTimeout(() => { cb() setTimeout(() => { - apollo.stop() apollo.resetStore() }, 100) }, 100) diff --git a/frontend/lib/with-apollo-client/get-apollo.ts b/frontend/lib/with-apollo-client/get-apollo.ts index 5fe0c8e27..c9c27e73b 100644 --- a/frontend/lib/with-apollo-client/get-apollo.ts +++ b/frontend/lib/with-apollo-client/get-apollo.ts @@ -261,7 +261,7 @@ export default function getApollo( previousAccessToken = accessToken previousLocale = locale - if (initialState) { + if (initialState && isBrowser) { const existingCache = _apolloClient.extract() const data = deepmerge(existingCache, initialState, { arrayMerge: (destination: any, source: any) => [ diff --git a/frontend/lib/with-apollo-client/index.tsx b/frontend/lib/with-apollo-client/index.tsx index fc44168a3..3d8141dd9 100644 --- a/frontend/lib/with-apollo-client/index.tsx +++ b/frontend/lib/with-apollo-client/index.tsx @@ -32,7 +32,7 @@ const withApolloClient = (App: any) => { // eslint-disable-next-line react-hooks/rules-of-hooks const router = useRouter() const locale = router.locale ?? pageProps?.router?.locale - const apolloClient = apollo ?? getApollo(apolloState, accessToken, locale) + const apolloClient = getApollo(apolloState, accessToken, locale) return ( @@ -76,6 +76,7 @@ const withApolloClient = (App: any) => { } pageProps.pageProps.currentUser = currentUser + if (typeof window === "undefined") { if (ctx?.res?.headersSent || ctx?.res?.finished) { return pageProps ?? {} @@ -93,9 +94,6 @@ const withApolloClient = (App: any) => { renderFunction: renderToString, tree: , }) - /*const rendered = await renderToStringWithData( - - )*/ // Run all GraphQL queries } catch (error) { // Prevent Apollo Client GraphQL errors from crashing SSR. diff --git a/frontend/pages/_app.tsx b/frontend/pages/_app.tsx index 116a3a4c4..8afd16c52 100644 --- a/frontend/pages/_app.tsx +++ b/frontend/pages/_app.tsx @@ -126,16 +126,17 @@ MyApp.getInitialProps = async (props: AppContext) => { const admin = signedIn && isAdmin(ctx) const accessToken = getAccessToken(ctx) - Object.assign(originalProps.pageProps, { signedIn, admin, accessToken }) - return originalProps - /*return { + /*Object.assign(originalProps.pageProps, { signedIn, admin, accessToken }) + return originalProps*/ + return { ...originalProps, pageProps: { ...originalProps.pageProps, signedIn, admin, + accessToken, }, - }*/ + } } // @ts-ignore: silence for now diff --git a/frontend/pages/_document.tsx b/frontend/pages/_document.tsx index 6defa7597..6d1cbe0c8 100644 --- a/frontend/pages/_document.tsx +++ b/frontend/pages/_document.tsx @@ -10,8 +10,14 @@ import originalTheme, { fontVariableClass as originalFontVariableClass, } from "/src/theme" -function CustomDocument(props: DocumentProps) { +interface CustomDocumentProps extends DocumentProps { + apolloState: any +} + +function CustomDocument(props: CustomDocumentProps) { + props.__NEXT_DATA__.props.apolloState = props.apolloState const isNew = props.__NEXT_DATA__.page.includes("_new") + const theme = isNew ? newTheme : originalTheme const fontVariableClass = isNew ? newFontVariableClass