From 631e974769b2fe8b2680cebace3af50c70f64025 Mon Sep 17 00:00:00 2001 From: Hariom Balhara Date: Wed, 21 Sep 2022 21:31:47 +0530 Subject: [PATCH] Fix flash of untranslated content by adding inline Skeleton Loaders on EventType (#4519) * Add support for easy use of inline skeleton * Fix user being taken to /v2 path * Fixes * Fix TS Co-authored-by: Peer Richelsen --- .../v2/eventtype/EventAdvancedTab.tsx | 42 ++++++++++----- .../components/v2/eventtype/EventSetupTab.tsx | 6 ++- .../v2/eventtype/EventTypeSingleLayout.tsx | 8 ++- packages/ui/v2/core/form/fields.tsx | 23 ++++---- .../core/navigation/tabs/VerticalTabItem.tsx | 10 +++- packages/ui/v2/core/skeleton/index.tsx | 53 ++++++++++++++++++- 6 files changed, 112 insertions(+), 30 deletions(-) diff --git a/apps/web/components/v2/eventtype/EventAdvancedTab.tsx b/apps/web/components/v2/eventtype/EventAdvancedTab.tsx index 17f1403c0c..f0d3a8c004 100644 --- a/apps/web/components/v2/eventtype/EventAdvancedTab.tsx +++ b/apps/web/components/v2/eventtype/EventAdvancedTab.tsx @@ -19,6 +19,7 @@ import { DialogContent, Label, showToast, + Skeleton, Switch, TextField, Tooltip, @@ -37,7 +38,6 @@ export const EventAdvancedTab = ({ eventType, team }: Pick(); const { t } = useLocale(); - const utils = trpc.useContext(); const [showEventNameTip, setShowEventNameTip] = useState(false); const [hashedLinkVisible, setHashedLinkVisible] = useState(!!eventType.hashedLink); const [hashedUrl, setHashedUrl] = useState(eventType.hashedLink?.link); @@ -138,8 +138,12 @@ export const EventAdvancedTab = ({ eventType, team }: Pick
- -

{t("additional_input_description")}

+ + {t("additional_inputs")} + + + {t("additional_input_description")} +
    @@ -184,12 +188,12 @@ export const EventAdvancedTab = ({ eventType, team }: Pick
    - -

    + + {t("requires_confirmation_description")} -

    +
    )} @@ -209,8 +213,12 @@ export const EventAdvancedTab = ({ eventType, team }: Pick
    - -

    {t("disable_guests_description")}

    + + {t("disable_guests")} + + + {t("disable_guests_description")} +
    )} @@ -230,8 +238,12 @@ export const EventAdvancedTab = ({ eventType, team }: Pick onChange(e)} />
    - -

    {t("disable_notes_description")}

    + + {t("disable_notes")} + + + {t("disable_notes_description")} +
    )} @@ -255,8 +267,12 @@ export const EventAdvancedTab = ({ eventType, team }: Pick
    - -

    {t("private_link_description")}

    + + {t("private_link")} + + + {t("private_link_description")} +
    diff --git a/apps/web/components/v2/eventtype/EventSetupTab.tsx b/apps/web/components/v2/eventtype/EventSetupTab.tsx index 96c797a3d2..cdc93d15d9 100644 --- a/apps/web/components/v2/eventtype/EventSetupTab.tsx +++ b/apps/web/components/v2/eventtype/EventSetupTab.tsx @@ -10,7 +10,7 @@ import { getEventLocationType, EventLocationType } from "@calcom/app-store/locat import { CAL_URL } from "@calcom/lib/constants"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { Icon } from "@calcom/ui/Icon"; -import { Select, Label, TextField, Button } from "@calcom/ui/v2"; +import { Select, Label, TextField, Button, Skeleton } from "@calcom/ui/v2"; import { slugify } from "@lib/slugify"; @@ -222,7 +222,9 @@ export const EventSetupTab = ( }} />
    - + + {t("location")} +
    - + + className={classNames("mb-2 block text-sm font-medium leading-none text-gray-700", props.className)}> {props.children} ); @@ -166,15 +166,14 @@ type InputFieldProps = { const InputField = forwardRef(function InputField(props, ref) { const id = useId(); - const { t: _t } = useLocale(); + const { t: _t, isLocaleReady } = useLocale(); const t = props.t || _t; const name = props.name || ""; const { label = t(name), labelProps, labelClassName, - /** Prevents displaying untranslated placeholder keys */ - placeholder = t(name + "_placeholder") !== name + "_placeholder" ? t(name + "_placeholder") : "", + placeholder = isLocaleReady ? t(name + "_placeholder") : "", className, addOnLeading, addOnSuffix, @@ -188,15 +187,19 @@ const InputField = forwardRef(function InputF ...passThrough } = props; + const translatedPlaceholder = isLocaleReady ? placeholder : ""; + return (
    {!!name && ( - + )} {addOnLeading || addOnSuffix ? (
    (function InputF
    (function InputF />
    ) : ( - + )} {hint &&
    {hint}
    } diff --git a/packages/ui/v2/core/navigation/tabs/VerticalTabItem.tsx b/packages/ui/v2/core/navigation/tabs/VerticalTabItem.tsx index cf6c7708fe..9ddccb538f 100644 --- a/packages/ui/v2/core/navigation/tabs/VerticalTabItem.tsx +++ b/packages/ui/v2/core/navigation/tabs/VerticalTabItem.tsx @@ -7,6 +7,8 @@ import { useLocale } from "@calcom/lib/hooks/useLocale"; import { SVGComponent } from "@calcom/types/SVGComponent"; import { Icon } from "@calcom/ui/Icon"; +import { Skeleton } from "../../skeleton"; + export type VerticalTabItemProps = { name: string; info?: string; @@ -55,8 +57,12 @@ const VerticalTabItem = function ({ )}
    -

    {t(name)}

    - {info &&

    {t(info)}

    } + {t(name)} + {info && ( + + {t(info)} + + )}
    {!disableChevron && isCurrent && (
    diff --git a/packages/ui/v2/core/skeleton/index.tsx b/packages/ui/v2/core/skeleton/index.tsx index 5655443c88..fd599ffd65 100644 --- a/packages/ui/v2/core/skeleton/index.tsx +++ b/packages/ui/v2/core/skeleton/index.tsx @@ -1,4 +1,7 @@ +import React from "react"; + import classNames from "@calcom/lib/classNames"; +import { useLocale } from "@calcom/lib/hooks/useLocale"; type SkeletonBaseProps = { className?: string; @@ -14,6 +17,54 @@ const SkeletonAvatar: React.FC = ({ className }) => { return
    ; }; +type SkeletonProps = { + as: keyof JSX.IntrinsicElements | React.FC; + className?: string; + children: React.ReactNode; + loading?: boolean; + waitForTranslation?: boolean; + loadingClassName?: string; +} & (T extends React.FC + ? P + : T extends keyof JSX.IntrinsicElements + ? JSX.IntrinsicElements[T] + : never); + +const Skeleton = ({ + as, + className = "", + children, + loading = false, + /** + * Assumes that the text needs translation by default and wait for it. + */ + waitForTranslation = true, + /** + * Classes that you need only in loading state + */ + loadingClassName = "", + ...rest +}: SkeletonProps) => { + const { isLocaleReady } = useLocale(); + loading = (waitForTranslation ? !isLocaleReady : false) || loading; + const Component = as; + return ( + + {children} + + ); +}; + const SkeletonText: React.FC = ({ className = "", invisible = false, @@ -42,4 +93,4 @@ const SkeletonContainer: React.FC = ({ children, as, classNam return {children}; }; -export { SkeletonAvatar, SkeletonText, SkeletonButton, SkeletonContainer }; +export { Skeleton, SkeletonAvatar, SkeletonText, SkeletonButton, SkeletonContainer };