vendredi 30 juillet 2021

ReactJs: How to check my props and other values correctly in an if statement?

I am trying to follow and create the right order in my if statement for my error, isloading and template values.

I recieve errors through: const [error, doRetry] = useTemplates();

isLoading through: const isLoading = !templates;

and my templates through a prop "templates" which are mapped here:

{templates.map((item) => (
                    <TemplateCard
                        id={item._id}
                        title={item.text}
                        description={item.description}
                        img={item.imgURL}
                        classNameToAdd={styles.cardContainer}
                        key={item.order}
                        onSelectCard={onSelected}
                        onDeselectCard={onDeselected}
                    />
                ))}

I return my values here:

return (
        <div style={sideScrollContainer}>
        <SideScrollContainer>{test}</SideScrollContainer>
        </div>

What would be the correct way of organizing my if statement in order to:

  1. If I recieve an error show the error
  2. If no templates are shown yet show the loader.
  3. If there are no errors and templates are not loading show the templates.

I did it this way but it is not working, can someone enlighten me please?

let test;
    if (error) {
        actionButtonClassName = `${styles.actionActive}`;
        test = (
            <div style={loader}>
                <span style={pStyle}>
                    <Trans>errorProduced</Trans>
                </span>
                <MenuButton
                    style={actionButton}
                    className={`${styles.actionActive}`}
                    onClick={doRetry}
                    classNameOnPressed={styles.onPressed}
                >
                    <Trans>Retry</Trans>
                </MenuButton>
            </div>
        );
    } else if (isLoading) {
        test = (
            <div style={loader}>
                <i className="fa fa-circle-o-notch fa-spin fa-2x fa-fw"></i>
            </div>
        );
    } else if (templates) {
        test = (
            <div style={templateCards}>
                {templates.map((item) => (
                    <TemplateCard
                        id={item._id}
                        title={item.text}
                        description={item.description}
                        img={item.imgURL}
                        classNameToAdd={styles.cardContainer}
                        key={item.order}
                        onSelectCard={onSelected}
                        onDeselectCard={onDeselected}
                    />
                ))}
            </div>
        );
    }

This is my useTemplates file.

const useTemplates = () => {
    const [result, setResult] = useState<[TemplateWithId[]?, Error?, Function?]>([]);
    // used to retringer the useEffect
    const [forceRerenderFlag, getForceRerenderFlag] = useState(true);

    const doRetry = () => {
        // changes the value so that useEffect retriggers
        getForceRerenderFlag(!forceRerenderFlag);
    };

    useEffect(() => {
        Meteor.call(
            GET_PUBLIC_TEMPLATES,
            i18n.locale,
            (error?: Error, result?: TemplateWithId[]) => {
                // returns the results sorted by template.order field
                if (result)
                    result.sort((templateA, templateB) => templateA.order - templateB.order);

                setResult([result, error, doRetry]);
            },
        );
    }, [forceRerenderFlag]);

    return result;
};

export default useTemplates;

Whole template file.

import React, { useState } from "react";
import TemplateCard from "/imports/cuadds/client/components/modals/templates/TemplateCard";
import MenuButton from "/imports/cuadds/client/components/common/menubutton/MenuButton";
import useWindowResponsiveValues from "/imports/cuadds/client/components/common/hooks/useWindowResponsiveValues";
import {
    DESKTOP_NARROW,
    TABLET,
    PHONE_WIDE,
    PHONE,
} from "/imports/cuadds/client/components/pages/onboarding/AspectRatios";
import SideScrollContainer from "/imports/cuadds/client/components/common/scrollContainer/SideScrollContainer";
import { t, Trans } from "@lingui/macro";
import useTemplates from "./useTemplates";
import { ROOT_ITEM_ACCESSED } from "/imports/cuadds/constants/onboardingLevels";
import styles from "./styles/templatepage.m.css";

type Props = {
    trainingLevel: number | undefined;
    templates?: TemplateWithId[];
    onOnboardingComplete: Function;
};

const MIN_NUM_OF_OPTIONS = 3;

const TemplateList = ({ trainingLevel, templates, onOnboardingComplete }: Props) => {
    const { aspectRatio, vmin } = useWindowResponsiveValues();
    const [error, doRetry] = useTemplates();

    let [selectedTemplatesIds, setSelectedTemplatesIds] = useState<string[]>([]);
    const isLoading = !templates;

    const onSelected = (id: string) => {
        const index = selectedTemplatesIds.indexOf(id);

        if (index === -1) {
            selectedTemplatesIds = [...selectedTemplatesIds, id];
            setSelectedTemplatesIds(selectedTemplatesIds);
        }
    };

    const onDeselected = (id: string) => {
        const index = selectedTemplatesIds.indexOf(id);

        if (index !== -1) {
            selectedTemplatesIds = selectedTemplatesIds.slice();
            selectedTemplatesIds.splice(index, 1);
            setSelectedTemplatesIds(selectedTemplatesIds);
        }
    };

    const actionButton = {
        fontSize: 2.8 * vmin,
        height: 6 * vmin,
        paddingBottom: 0.4 * vmin,
        width: 45 * vmin,
        borderRadius: 1 * vmin,
        fontWeight: 600,
    };

    const pStyle = {
        fontSize: 2.8 * vmin,
        color: "#3b3b3b",
    };

    const sideScrollContainer = {
        width: "100vw",
        marginTop: 2 * vmin,
        marginBottom: 3.2 * vmin,
    };

    const templateCards: React.CSSProperties = {
        whiteSpace: "nowrap",
        paddingTop: 0.5 * vmin,
        paddingBottom: 4 * vmin,
        marginTop: 2 * vmin,
        marginBottom: -1 * vmin,
        display: "inline-flex",
    };

    const loader: React.CSSProperties = {
        color: "#C5C5C5",
        fontSize: 22,
        height: 28.5 * vmin,
        padding: 1.5 * vmin,
        margin: "11px 0",
    };

    if (aspectRatio < DESKTOP_NARROW && aspectRatio >= TABLET) {
        actionButton.fontSize = 2.9 * vmin;
        actionButton.paddingBottom = 0.3 * vmin;
        loader.height = 31 * vmin;
    } else if (aspectRatio < TABLET && aspectRatio >= PHONE_WIDE) {
        actionButton.fontSize = 3.7 * vmin;
        actionButton.width = 60 * vmin;
        actionButton.height = 7.5 * vmin;
        actionButton.paddingBottom = 0.3 * vmin;
        loader.height = 40 * vmin;
    } else if (aspectRatio < PHONE_WIDE && aspectRatio >= PHONE) {
        actionButton.fontSize = 4.1 * vmin;
        actionButton.width = 68 * vmin;
        actionButton.height = 9 * vmin;
        actionButton.paddingBottom = 0.4 * vmin;

        templateCards.marginBottom = 1 * vmin;

        loader.height = 46 * vmin;
        loader.padding = 1.6 * vmin;
    } else if (aspectRatio < PHONE) {
        actionButton.fontSize = 4.8 * vmin;
        actionButton.width = 78 * vmin;
        actionButton.height = 11 * vmin;
        actionButton.paddingBottom = 0.5 * vmin;

        templateCards.marginBottom = 1.7 * vmin;

        loader.height = 59.2 * vmin;
        loader.padding = 2.2 * vmin;
    }

    const numOfTemplates = templates ? templates.length : 0;
    // makes sure we have enough templates to be over the minimum, otherise the user get's stuck
    const minNumOfOptions =
        numOfTemplates < MIN_NUM_OF_OPTIONS ? numOfTemplates : MIN_NUM_OF_OPTIONS;

    const firstTimeOnOnboarding =
        trainingLevel !== undefined ? trainingLevel < ROOT_ITEM_ACCESSED : true;

    let buttonText;
    if (firstTimeOnOnboarding) {
        if (selectedTemplatesIds.length < minNumOfOptions) {
            buttonText =
                t`SelectMore` + " (" + (minNumOfOptions - selectedTemplatesIds.length) + ")";
        } else {
            buttonText =
                t`SelectDone` +
                " " +
                // don't show the number if there's only one, otherwise it says "...your 1 cuadds!"
                (selectedTemplatesIds.length > 1 ? selectedTemplatesIds.length + " " : "") +
                "cuadds!";
        }
    } else {
        // if the user is re-watching the onboarding, don't force them to select templates
        buttonText = t`AlreadyDone`;
    }

    let actionButtonClassName;
    /**
     * if it's loading or on their first time onboarding the user didn't select enough templates.
     * If it's not the first time onboarding, the user is re-watching it, so we don't want to force
     * them to select templates, they should be able to continue directly.
     */
    if (isLoading || (firstTimeOnOnboarding && selectedTemplatesIds.length < minNumOfOptions)) {
        // shows the button in gray and inactive
        actionButtonClassName = `${styles.actionInactive}`;
    } else {
        // shows the button in blue and active
        actionButtonClassName = `${styles.actionActive}`;
    }

    let test;
    if (!error) {
        console.log("error");
        actionButtonClassName = `${styles.actionActive}`;
        test = (
            <div style={loader}>
                <span style={pStyle}>
                    <Trans>errorProduced</Trans>
                </span>
                <MenuButton
                    style={actionButton}
                    className={`${styles.actionActive}`}
                    onClick={doRetry}
                    classNameOnPressed={styles.onPressed}
                >
                    <Trans>Retry</Trans>
                </MenuButton>
            </div>
        );
    } else if (isLoading) {
        console.log("loading");
        test = (
            <div style={loader}>
                <i className="fa fa-circle-o-notch fa-spin fa-2x fa-fw"></i>
            </div>
        );
    } else {
        test = (
            <div style={templateCards}>
                {templates.map((item) => (
                    <TemplateCard
                        id={item._id}
                        title={item.text}
                        description={item.description}
                        img={item.imgURL}
                        classNameToAdd={styles.cardContainer}
                        key={item.order}
                        onSelectCard={onSelected}
                        onDeselectCard={onDeselected}
                    />
                ))}
            </div>
        );
    }

    const onActionButtonClick = () => {
        onOnboardingComplete(selectedTemplatesIds);
    };

    return (
        <>
            <div style={sideScrollContainer}>
                <SideScrollContainer>{test}</SideScrollContainer>
            </div>
            <MenuButton
                onClick={onActionButtonClick}
                style={actionButton}
                className={actionButtonClassName}
                classNameOnPressed={styles.onPressed}
            >
                {buttonText}
            </MenuButton>
        </>
    );
};

export default TemplateList;

Aucun commentaire:

Enregistrer un commentaire