polaris
polaris copied to clipboard
Page Action onAction prop does nothing when passed a callback function
Summary
I've been trying to set up some UI to edit some values in Shopify Functions. The tutorial provides some code like this for submitting the form to update the values of metafields to use in my discount logic:
import { useEffect, useMemo } from "react";
import { json } from "@remix-run/node";
import { useForm, useField } from "@shopify/react-form";
import { CurrencyCode } from "@shopify/react-i18n";
import {
Form,
useActionData,
useNavigation,
useSubmit,
} from "@remix-run/react";
import {
ActiveDatesCard,
CombinationCard,
DiscountClass,
DiscountMethod,
MethodCard,
DiscountStatus,
RequirementType,
SummaryCard,
UsageLimitsCard,
} from "@shopify/discount-app-components";
import {
Banner,
Card,
Text,
Layout,
Page,
PageActions,
TextField,
BlockStack,
Box,
} from "@shopify/polaris";
import shopify from "../shopify.server";
export default function VolumeNew() {
const submitForm = useSubmit();
const actionData = useActionData();
const navigation = useNavigation();
const todaysDate = useMemo(() => new Date(), []);
const isLoading = navigation.state === "submitting";
const currencyCode = CurrencyCode.Cad;
const submitErrors = actionData?.errors || [];
const returnToDiscounts = () => open("shopify://admin/discounts", "_top");
useEffect(() => {
if (actionData?.errors.length === 0 && actionData?.discount) {
returnToDiscounts();
}
}, [actionData]);
const {
fields: {
discountTitle,
discountCode,
discountMethod,
combinesWith,
requirementType,
requirementSubtotal,
requirementQuantity,
usageLimit,
appliesOncePerCustomer,
startDate,
endDate,
configuration,
},
submit,
} = useForm({
fields: {
discountTitle: useField(""),
discountMethod: useField(DiscountMethod.Code),
discountCode: useField(""),
combinesWith: useField({
orderDiscounts: false,
productDiscounts: false,
shippingDiscounts: false,
}),
requirementType: useField(RequirementType.None),
requirementSubtotal: useField("0"),
requirementQuantity: useField("0"),
usageLimit: useField(null),
appliesOncePerCustomer: useField(false),
startDate: useField(todaysDate),
endDate: useField(null),
configuration: {
quantity: useField("1"),
percentage: useField("0"),
},
},
onSubmit: async (form) => {
const discount = {
title: form.discountTitle,
method: form.discountMethod,
code: form.discountCode,
combinesWith: form.combinesWith,
usageLimit: form.usageLimit == null ? null : parseInt(form.usageLimit),
appliesOncePerCustomer: form.appliesOncePerCustomer,
startsAt: form.startDate,
endsAt: form.endDate,
configuration: {
quantity: parseInt(form.configuration.quantity),
percentage: parseFloat(form.configuration.percentage),
},
};
submitForm({ discount: JSON.stringify(discount) }, { method: "post" });
return { status: "success" };
},
});
const errorBanner =
submitErrors.length > 0 ? (
<Layout.Section>
<Banner tone="critical">
<p>There were some issues with your form submission:</p>
<ul>
{submitErrors.map(({ message, field }, index) => {
return (
<li key={`${message}${index}`}>
{field.join(".")} {message}
</li>
);
})}
</ul>
</Banner>
</Layout.Section>
) : null;
return (
<Page>
<ui-title-bar title="Create volume discount">
<button variant="breadcrumb" onClick={returnToDiscounts}>
Discounts
</button>
<button variant="primary" onClick={submit}>
Save discount
</button>
</ui-title-bar>
<Layout>
{errorBanner}
<Layout.Section>
<Form method="post">
<BlockStack align="space-around" gap="200">
<MethodCard
title="Volume"
discountTitle={discountTitle}
discountClass={DiscountClass.Product}
discountCode={discountCode}
discountMethod={discountMethod}
/>
<Box paddingBlockEnd="300">
<Card>
<BlockStack>
<Text variant="headingMd" as="h2">
Volume
</Text>
<TextField
label="Minimum quantity"
autoComplete="on"
{...configuration.quantity}
/>
<TextField
label="Discount percentage"
autoComplete="on"
{...configuration.percentage}
suffix="%"
/>
</BlockStack>
</Card>
</Box>
{discountMethod.value === DiscountMethod.Code && (
<UsageLimitsCard
totalUsageLimit={usageLimit}
oncePerCustomer={appliesOncePerCustomer}
/>
)}
<CombinationCard
combinableDiscountTypes={combinesWith}
discountClass={DiscountClass.Product}
discountDescriptor={"Discount"}
/>
<ActiveDatesCard
startDate={startDate}
endDate={endDate}
timezoneAbbreviation="EST"
/>
</BlockStack>
</Form>
</Layout.Section>
<Layout.Section variant="oneThird">
<SummaryCard
header={{
discountMethod: discountMethod.value,
discountDescriptor:
discountMethod.value === DiscountMethod.Automatic
? discountTitle.value
: discountCode.value,
appDiscountType: "Volume",
isEditing: false,
}}
performance={{
status: DiscountStatus.Scheduled,
usageCount: 0,
isEditing: false,
}}
minimumRequirements={{
requirementType: requirementType.value,
subtotal: requirementSubtotal.value,
quantity: requirementQuantity.value,
currencyCode: currencyCode,
}}
usageLimits={{
oncePerCustomer: appliesOncePerCustomer.value,
totalUsageLimit: usageLimit.value,
}}
activeDates={{
startDate: startDate.value,
endDate: endDate.value,
}}
/>
</Layout.Section>
<Layout.Section>
<PageActions
primaryAction={{
content: "Save discount",
onAction: submit,
loading: isLoading,
}}
secondaryActions={[
{
content: "Discard",
onAction: returnToDiscounts,
},
]}
/>
</Layout.Section>
</Layout>
</Page>
);
}
I'm trying to setup the simplest form possible to submit metafields relevant to my discount logic. I was trying to get a simple POC like this to work:
import React, { useEffect } from 'react';
import {
Form,
useSubmit,
useNavigation,
useActionData,
} from "@remix-run/react";
import { useForm, useField } from "@shopify/react-form";
import { Page, TextField, Layout, PageActions } from "@shopify/polaris";
import shopify from "../shopify.server";
export default function GiftThresholdNew() {
const {
fields: {
configuration
},
submit
} = useForm({
fields: {
configuration: {
threshold: useField("5900"),
},
},
onSubmit: async (form) => {
console.log(form);
console.log('i am sumbitting the form');
}
});
return (
<Page>
<Layout>
<Layout.Section>
<Form method="post">
<TextField
label="Free Gift Threshold"
{...configuration.threshold}
/>
<button>Click Me</button>
</Form>
</Layout.Section>
<Layout.Section>
<PageActions
primaryAction={{
content: "Save discount",
onAction: submit,
loading: isLoading,
}}
/>
</Layout.Section>
</Layout>
</Page>
);
}
However, nothing happens at all in the PageActions component when I click "Save Discount". It seems like onAction
prop does not do anything and the documentation for Polaris does not even acknowlege onAction
as an available prop despite it being used in the Shopify Functions discount tutorial. I'm expecting it to run the code of the onSubmit property returned from the useForm
hook, however it does not log anything in the browser or terminal. What am I missing? Thank you.
Expected behavior
Clicking the "Save Discount" button that the <PageActions>
component renders should log the form data and "'i am sumbitting the form"
Actual behavior
Nothing happens at all. No log in browser or terminal. It seem the onAction
prop does not do anything. Even passing a callback function directly to the prop does nothing.
Steps to reproduce
- Add a
PageActions
component to a Layout in Polaris. - Pass any value to
onAction
prop, even something as simple as this:
<PageActions
primaryAction={{
content: "Save discount",
onAction: () => console.log('Hello world`),
}}
/>
- Notice that nothing happens.
Are you using React components?
Yes
Polaris version number
13.9.0
Browser
Chrome
Device
Macbook Pro Sanoma 14.4