Shopify / ui-extensions

MIT License
268 stars 36 forks source link

DateField popover showing up behind the comments and other order blocks in admin block UI extension #1733

Open rbarreca opened 9 months ago

rbarreca commented 9 months ago

Please list the package(s) involved in the issue, and include the version you are using

"@shopify/ui-extensions-react": "2024.01.x"

Describe the bug

When using a DateField in an order admin UI block extension, the popover shows up offset to the bottom-right and behind the other blocks.

Steps to reproduce the behavior:

  1. Run the code
  2. Click on the DateField

Expected behavior

Popover shows up below the DateField and on top of everything else.

Screenshots

Screenshot 2024-02-12 at 12 34 18 AM

Sample code

import { useEffect, useState } from 'react';
import {
  reactExtension,
  useApi,
  AdminBlock,
  BlockStack,
  Text,
  InlineStack,
  DateField,
  Form,
} from '@shopify/ui-extensions-react/admin';

const TARGET = 'admin.order-details.block.render';

export default reactExtension(TARGET, () => <App />);

function App() {
  const {
    extension: { target },
    i18n,
    data,
  } = useApi(TARGET);

  const [deliveryWindow, setDeliveryWindow] = useState<string>();

  useEffect(() => {
    getInitialValues();
  }, []);

  async function getOrderAttributes() {
    const getDeliveryWindowQuery = {
      query: `query Order($id: ID!) {
        order(id: $id) {
          customAttributes {
            key
            value 
          }
        }
      }`,
      variables: { id: data.selected[0].id },
    };

    const res = await fetch("shopify:admin/api/graphql.json", {
      method: "POST",
      body: JSON.stringify(getDeliveryWindowQuery),
    });

    if (!res.ok) {
      console.error("Network error");
    }

    const orderData = await res.json();
    console.log(orderData)
    return orderData.data.order?.customAttributes ?? [];
  }

  async function onSubmit() {
    const date = convertDateToDeliveryWindowKey(deliveryWindow);
    const orderAttributes = await getOrderAttributes();
    let found = false;
    const updatedOrderAttributes = orderAttributes.map((attr) => {
      if (attr.key === "farmlink_delivery_datetime") {
        found = true;
        return { ...attr, value: date };
      }
      return attr;
    });
    if (!found) {
      updatedOrderAttributes.push({ key: "farmlink_delivery_datetime", value: date });
    }
    console.log(data.selected[0].id)
    console.log('updatedOrderAttributes', updatedOrderAttributes)
    const orderUpdateQuery = {
      query: `mutation orderUpdate($input: OrderInput!) {
        orderUpdate(input: $input) {
          order {
            customAttributes {
              key
              value 
            }
          }
          userErrors {
            field
            message
          }
        }
      }`,
      variables: {
        input: {
          customAttributes: updatedOrderAttributes,
          id: data.selected[0].id
        }
      },
    };
    const res = await fetch("shopify:admin/api/graphql.json", {
      method: "POST",
      body: JSON.stringify(orderUpdateQuery),
    });

    if (!res.ok) {
      console.error("Network error");
    }

    const orderData = await res.json();
    if (orderData.data.orderUpdate.userErrors.length > 0) {
      console.error('update error', orderData.data.orderUpdate.userErrors);
      return;
    }

    setDeliveryWindow(parseDeliveryWindow(orderData.data.orderUpdate.order?.customAttributes));
  }

  function parseDeliveryWindow(orderAttributes) {
    let nextDeliveryWindow = orderAttributes?.find((attr) => attr.key === "farmlink_delivery_datetime")?.value;
    if (nextDeliveryWindow === undefined) return "";

    const date = new Date(nextDeliveryWindow);
    nextDeliveryWindow = date.toLocaleDateString('en-US', { timeZone: 'Pacific/Honolulu', year: 'numeric' })
      + '-' + date.toLocaleDateString('en-US', { timeZone: 'Pacific/Honolulu', month: '2-digit' })
      + '-' + date.toLocaleDateString('en-US', { timeZone: 'Pacific/Honolulu', day: '2-digit' })
    return nextDeliveryWindow;
  }

  function convertDateToDeliveryWindowKey(date) {
    if (!date) return "";
    date = new Date(date);
    const year = date.getUTCFullYear();
    const month = String(date.getUTCMonth() + 1).padStart(2, '0');
    const day = String(date.getUTCDate()).padStart(2, '0');
    const hours = '19';
    const minutes = '00';
    const seconds = '00';
    const formattedDate = `${year}-${month}-${day}T${hours}:${minutes}:${seconds}Z`;
    return formattedDate;
  }

  const getInitialValues = async () => {
    const orderAttributes = await getOrderAttributes();
    setDeliveryWindow(parseDeliveryWindow(orderAttributes));
  };

  const onReset = () => {
    getInitialValues();
  };

  return (
    // The AdminBlock component provides an API for setting the title of the Block extension wrapper.
    <AdminBlock title="Farm Link">
      <BlockStack>
        <Form id={`delivery-window-form`} onSubmit={onSubmit} onReset={onReset}>
          <DateField label="Delivery window" value={deliveryWindow} onChange={setDeliveryWindow} />
        </Form>
      </BlockStack>
    </AdminBlock>
  );
}
zachsitka commented 5 months ago

Can we expect this to be fixed in a future version (hopefully Summer '24)? This bug makes this component unusable for my users. As you can see in the screenshot on this bug report, the date picker that opens up does not show all of the pickable dates because other UI is overlayed on top of them. My users are having to resize their screen until the date they need to pick is exposed.

cambalzer commented 4 months ago

This bug is also preventing us from using a date field in our admin blocks app

advplyr commented 3 weeks ago

This is still an issue in 2024-10 for the Block Extension, however it appears to be resolved in the Action Extension modal.

The DateField is still unusable in the Action Extension modal though due to https://github.com/Shopify/ui-extensions/issues/1421

The popover only opens below the input so gets cutoff if it extends beyond the page.

advplyr commented 3 weeks ago

Not completely resolved in the Action Extension modal. On mobile the popover still displays behind the buttons in addition to being cutoff at the bottom of the page.

Image