Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Page Action onAction prop does nothing when passed a callback function #12621

Open
brianecook opened this issue Sep 10, 2024 · 3 comments
Open
Labels
Bug Something is broken and not working as intended in the system. untriaged

Comments

@brianecook
Copy link

brianecook commented Sep 10, 2024

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

  1. Add a PageActions component to a Layout in Polaris.
  2. Pass any value to onAction prop, even something as simple as this:
<PageActions
  primaryAction={{
    content: "Save discount",
    onAction: () => console.log('Hello world`),
  }}
/>
  1. Notice that nothing happens.

Are you using React components?

Yes

Polaris version number

13.9.0

Browser

Chrome

Device

Macbook Pro Sanoma 14.4

@brianecook brianecook added Bug Something is broken and not working as intended in the system. untriaged labels Sep 10, 2024
@brianecook
Copy link
Author

Can anyone give any indication if this has been read or when I might expect to get some help?

@aveline
Copy link
Contributor

aveline commented Oct 1, 2024

Hi @brianecook, onAction is working as expected, here is a sandbox https://codesandbox.io/p/sandbox/blissful-resonance-84p9fx

@brianecook
Copy link
Author

@aveline dropping this exact code in my project does not trigger the event as it does it your sandbox environment. I'm working on my app while running shopify app dev from my terminal, which displays the interface in the "Apps" section of the admin. Are there special considerations that need to be made when developing this way?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Something is broken and not working as intended in the system. untriaged
Projects
None yet
Development

No branches or pull requests

2 participants