Use dedicated wizard hook

This commit is contained in:
dominik-zeglen 2020-03-31 19:56:53 +02:00
parent 5967c71d13
commit 50ff050155
8 changed files with 76 additions and 48 deletions

47
src/hooks/useWizard.ts Normal file
View file

@ -0,0 +1,47 @@
import { useState } from "react";
export interface UseWizardOpts<T> {
next: () => void;
prev: () => void;
set: (step: T) => void;
}
export type UseWizard<T> = [T, UseWizardOpts<T>];
function useWizard<T>(initial: T, steps: T[]): UseWizard<T> {
const [stepIndex, setStepIndex] = useState(steps.indexOf(initial));
function next() {
if (stepIndex === steps.length - 1) {
console.error("This is the last step");
} else {
setStepIndex(stepIndex + 1);
}
}
function prev() {
if (stepIndex === 0) {
console.error("This is the first step");
} else {
setStepIndex(stepIndex - 1);
}
}
function set(step: T) {
const newStepIndex = steps.findIndex(s => s === step);
if (newStepIndex === -1) {
console.error("Step does not exist");
} else {
setStepIndex(newStepIndex);
}
}
return [
steps[stepIndex],
{
next,
prev,
set
}
];
}
export default useWizard;

View file

@ -62,7 +62,7 @@ const ProductVariantCreateContent: React.FC<ProductVariantCreateContentProps> =
<div> <div>
<ProductVariantCreateTabs step={step} onStepClick={onStepClick} /> <ProductVariantCreateTabs step={step} onStepClick={onStepClick} />
<div className={classes.root}> <div className={classes.root}>
{step === "values" && ( {step === ProductVariantCreateStep.values && (
<ProductVariantCreateValues <ProductVariantCreateValues
attributes={selectedAttributes} attributes={selectedAttributes}
data={data} data={data}
@ -75,7 +75,7 @@ const ProductVariantCreateContent: React.FC<ProductVariantCreateContentProps> =
} }
/> />
)} )}
{step === "prices" && ( {step === ProductVariantCreateStep.prices && (
<ProductVariantCreatePrices <ProductVariantCreatePrices
attributes={selectedAttributes} attributes={selectedAttributes}
currencySymbol={currencySymbol} currencySymbol={currencySymbol}
@ -116,7 +116,7 @@ const ProductVariantCreateContent: React.FC<ProductVariantCreateContentProps> =
} }
/> />
)} )}
{step === "summary" && ( {step === ProductVariantCreateStep.summary && (
<ProductVariantCreateSummary <ProductVariantCreateSummary
attributes={selectedAttributes} attributes={selectedAttributes}
currencySymbol={currencySymbol} currencySymbol={currencySymbol}

View file

@ -9,6 +9,7 @@ import { FormattedMessage } from "react-intl";
import useModalDialogErrors from "@saleor/hooks/useModalDialogErrors"; import useModalDialogErrors from "@saleor/hooks/useModalDialogErrors";
import useModalDialogOpen from "@saleor/hooks/useModalDialogOpen"; import useModalDialogOpen from "@saleor/hooks/useModalDialogOpen";
import useWizard from "@saleor/hooks/useWizard";
import { ProductVariantBulkCreateInput } from "../../../types/globalTypes"; import { ProductVariantBulkCreateInput } from "../../../types/globalTypes";
import { createInitialForm, ProductVariantCreateFormData } from "./form"; import { createInitialForm, ProductVariantCreateFormData } from "./form";
import ProductVariantCreateContent, { import ProductVariantCreateContent, {
@ -39,9 +40,9 @@ function canHitNext(
data: ProductVariantCreateFormData data: ProductVariantCreateFormData
): boolean { ): boolean {
switch (step) { switch (step) {
case "values": case ProductVariantCreateStep.values:
return data.attributes.every(attribute => attribute.values.length > 0); return data.attributes.every(attribute => attribute.values.length > 0);
case "prices": case ProductVariantCreateStep.prices:
if (data.price.all) { if (data.price.all) {
if (data.price.value === "") { if (data.price.value === "") {
return false; return false;
@ -69,7 +70,7 @@ function canHitNext(
} }
return true; return true;
case "summary": case ProductVariantCreateStep.summary:
return data.variants.every(variant => variant.sku !== ""); return data.variants.every(variant => variant.sku !== "");
default: default:
@ -88,9 +89,7 @@ export interface ProductVariantCreateDialogProps
onSubmit: (data: ProductVariantBulkCreateInput[]) => void; onSubmit: (data: ProductVariantBulkCreateInput[]) => void;
} }
const ProductVariantCreateDialog: React.FC< const ProductVariantCreateDialog: React.FC<ProductVariantCreateDialogProps> = props => {
ProductVariantCreateDialogProps
> = props => {
const { const {
attributes, attributes,
defaultPrice, defaultPrice,
@ -101,29 +100,13 @@ const ProductVariantCreateDialog: React.FC<
...contentProps ...contentProps
} = props; } = props;
const classes = useStyles(props); const classes = useStyles(props);
const [step, setStep] = React.useState<ProductVariantCreateStep>("values"); const [step, { next, prev, set: setStep }] = useWizard<
ProductVariantCreateStep
function handleNextStep() { >(ProductVariantCreateStep.values, [
switch (step) { ProductVariantCreateStep.values,
case "values": ProductVariantCreateStep.prices,
setStep("prices"); ProductVariantCreateStep.summary
break; ]);
case "prices":
setStep("summary");
break;
}
}
function handlePrevStep() {
switch (step) {
case "prices":
setStep("values");
break;
case "summary":
setStep("prices");
break;
}
}
const [data, dispatchFormDataAction] = React.useReducer( const [data, dispatchFormDataAction] = React.useReducer(
reduceProductVariantCreateFormData, reduceProductVariantCreateFormData,
@ -141,7 +124,7 @@ const ProductVariantCreateDialog: React.FC<
useModalDialogOpen(open, { useModalDialogOpen(open, {
onClose: () => { onClose: () => {
reloadForm(); reloadForm();
setStep("values"); setStep(ProductVariantCreateStep.values);
} }
}); });
@ -171,25 +154,21 @@ const ProductVariantCreateDialog: React.FC<
<FormattedMessage defaultMessage="Cancel" description="button" /> <FormattedMessage defaultMessage="Cancel" description="button" />
</Button> </Button>
<div className={classes.spacer} /> <div className={classes.spacer} />
{step !== "values" && ( {step !== ProductVariantCreateStep.values && (
<Button <Button className={classes.button} color="primary" onClick={prev}>
className={classes.button}
color="primary"
onClick={handlePrevStep}
>
<FormattedMessage <FormattedMessage
defaultMessage="Previous" defaultMessage="Previous"
description="previous step, button" description="previous step, button"
/> />
</Button> </Button>
)} )}
{step !== "summary" ? ( {step !== ProductVariantCreateStep.summary ? (
<Button <Button
className={classes.button} className={classes.button}
color="primary" color="primary"
disabled={!canHitNext(step, data)} disabled={!canHitNext(step, data)}
variant="contained" variant="contained"
onClick={handleNextStep} onClick={next}
> >
<FormattedMessage defaultMessage="Next" description="button" /> <FormattedMessage defaultMessage="Next" description="button" />
</Button> </Button>

View file

@ -17,21 +17,21 @@ function getSteps(intl: IntlShape): Step[] {
defaultMessage: "Select Values", defaultMessage: "Select Values",
description: "attribute values, variant creation step" description: "attribute values, variant creation step"
}), }),
value: "values" value: ProductVariantCreateStep.values
}, },
{ {
label: intl.formatMessage({ label: intl.formatMessage({
defaultMessage: "Prices and SKU", defaultMessage: "Prices and SKU",
description: "variant creation step" description: "variant creation step"
}), }),
value: "prices" value: ProductVariantCreateStep.prices
}, },
{ {
label: intl.formatMessage({ label: intl.formatMessage({
defaultMessage: "Summary", defaultMessage: "Summary",
description: "variant creation step" description: "variant creation step"
}), }),
value: "summary" value: ProductVariantCreateStep.summary
} }
]; ];
} }
@ -71,9 +71,7 @@ export interface ProductVariantCreateTabsProps {
onStepClick: (step: ProductVariantCreateStep) => void; onStepClick: (step: ProductVariantCreateStep) => void;
} }
const ProductVariantCreateTabs: React.FC< const ProductVariantCreateTabs: React.FC<ProductVariantCreateTabsProps> = props => {
ProductVariantCreateTabsProps
> = props => {
const { step: currentStep, onStepClick } = props; const { step: currentStep, onStepClick } = props;
const classes = useStyles(props); const classes = useStyles(props);
const intl = useIntl(); const intl = useIntl();

View file

@ -1 +1,5 @@
export type ProductVariantCreateStep = "values" | "prices" | "summary"; export enum ProductVariantCreateStep {
values,
prices,
summary
}