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

View file

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

View file

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

View file

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