Shopify / shopify-app-bridge

https://shopify.dev/docs/api/app-bridge
82 stars 9 forks source link

Contextual save bar not showing up #223

Closed BaggioGiacomo closed 10 months ago

BaggioGiacomo commented 11 months ago

Describe the bug

I want to remove the @shopify/app-bridge-react package since it will be removed soon. While refactoring, I got blocked on the contextual save bar.

Contextual information

This is my code:

<>
      <ContextualSaveBar
        saveAction={saveAction}
        discardAction={discardAction}
        fullWidth
        leaveConfirmationDisable
        visible={
          !isEqual(
            draftEditableMetafieldDefinitionIds,
            editableMetafieldDefinitionIds
          )
        }
      />
      <Card padding="0">
        <CardTitle title="Account section" padding="5" />

        <p className="px-5 pb-2">
          Select the metafields that customers can update. You can drag and drop
          each row to select the order of the inputs on the app extension.
          Please note that some options are currently disabled, as they are not
          yet supported. Stay tuned – additional support is coming soon!
        </p>

        <Divider borderColor="border-input" />
        <div className="w-full">
          <ListHeading />
          {draftEditableMetafieldDefinitions.length !== 0 && (
            <EditableMetafieldDefinitionsList
              editableMetafieldDefinitions={draftEditableMetafieldDefinitions}
              onDragEnd={handleDragEnd}
              onToggleEditable={removeMetafieldDefinitionFromEditables}
              numberOfDefinitions={customerMetafieldDefinitions.length}
            />
          )}

          {availableMetafieldDefinitions.length !== 0 && (
            <AvailableMetafieldDefinitionsList
              availableMetafieldDefinitions={availableMetafieldDefinitions}
              onToggleEditable={addMetafieldDefinitionToEditables}
            />
          )}

          <Divider borderColor="border-input" />
          <div className="p-5">
            <HorizontalStack>
              <div className="flex-1">
                <Text as="p" variant="bodyMd" color="subdued">
                  If you want to create new metafield definitions you can enter
                  them{" "}
                  <Button
                    plain
                    monochrome
                    onClick={() =>
                      navigate(
                        `https://${shop.shopify_domain}/admin/metafields/customer`
                      )
                    }
                  >
                    here
                  </Button>
                  .
                </Text>
              </div>
              <div>
                <Button
                  primary
                  onClick={() => {
                    updateEditableMetafields();
                  }}
                  loading={editableCustomerMetafieldsMutation.isLoading}
                  disabled={isEqual(
                    draftEditableMetafieldDefinitionIds,
                    editableMetafieldDefinitionIds
                  )}
                >
                  Save
                </Button>
              </div>
            </HorizontalStack>
          </div>
          <Divider />
          {editableCustomerMetafieldsMutation.isSuccess && (
            <Toast
              content="Selection saved correctly!"
              onDismiss={editableCustomerMetafieldsMutation.reset}
            />
          )}
          {editableCustomerMetafieldsMutation.isError && (
            <Toast
              content="Error! Try again later or contact support using the chat."
              onDismiss={editableCustomerMetafieldsMutation.reset}
              error
            />
          )}
        </div>
      </Card>
    </>

This is how I refactored:

<>
      <Card padding="0">
        <CardTitle title="Account section" padding="5" />

        <p className="px-5 pb-2">
          Select the metafields that customers can update. You can drag and drop
          each row to select the order of the inputs on the app extension.
          Please note that some options are currently disabled, as they are not
          yet supported. Stay tuned – additional support is coming soon!
        </p>
        <Divider borderColor="border-input" />
        <div className="w-full">
          <ListHeading />
          <form data-save-bar>
            {draftEditableMetafieldDefinitions.length !== 0 && (
              <EditableMetafieldDefinitionsList
                editableMetafieldDefinitions={draftEditableMetafieldDefinitions}
                onDragEnd={handleDragEnd}
                onToggleEditable={removeMetafieldDefinitionFromEditables}
                numberOfDefinitions={customerMetafieldDefinitions.length}
              />
            )}
            {availableMetafieldDefinitions.length !== 0 && (
              <AvailableMetafieldDefinitionsList
                availableMetafieldDefinitions={availableMetafieldDefinitions}
                onToggleEditable={addMetafieldDefinitionToEditables}
              />
            )}
          </form>
          <Divider borderColor="border-input" />
          <div className="p-5">
            <HorizontalStack>
              <div className="flex-1">
                <Text as="p" variant="bodyMd" color="subdued">
                  If you want to create new metafield definitions you can enter
                  them{" "}
                  <Button
                    plain
                    monochrome
                    onClick={() =>
                      open(
                        "shopify:admin/settings/custom_data/customer/metafields",
                        "_self"
                      )
                    }
                  >
                    here
                  </Button>
                  .
                </Text>
              </div>
              <div>
                <Button
                  primary
                  onClick={() => {
                    updateEditableMetafields();
                  }}
                  loading={editableCustomerMetafieldsMutation.isLoading}
                  disabled={isEqual(
                    draftEditableMetafieldDefinitionIds,
                    editableMetafieldDefinitionIds
                  )}
                >
                  Save
                </Button>
              </div>
            </HorizontalStack>
          </div>
          <Divider />
        </div>
      </Card>
    </>

EditableMetafieldDefinitionsList and AvailableMetafieldDefinitionsList are drag and drop lists made using react-beautiful-dnd package. This is their code (I put just one code snippet since they are very similar):

<>
      <div className="bg-gray-100 py-2 px-5 border-y border-x-0 border-solid border-gray-400">
        <Text as="p" variant="bodyMd" fontWeight="semibold" color="subdued">
          EDITABLE ({editableMetafieldDefinitions.length} OF{" "}
          {numberOfDefinitions})
        </Text>
      </div>

      <DragDropContext onDragEnd={onDragEnd}>
        <Droppable droppableId="root">
          {(provided) => {
            return (
              <div ref={provided.innerRef} {...provided.droppableProps}>
                {editableMetafieldDefinitions.map(
                  (editableMetafieldDefinition, index) => {
                    return (
                      <Draggable
                        draggableId={index.toString()}
                        index={index}
                        key={index}
                      >
                        {(provided, snapshot) => {
                          const transform =
                            provided.draggableProps.style?.transform;
                          const translateValue = transform
                            ? transform.split(",")[1]
                            : "0px";
                          return (
                            <div
                              ref={provided.innerRef}
                              {...provided.draggableProps}
                              style={{
                                ...provided.draggableProps.style,
                                transform: `translate(0px,${translateValue}`,
                                background: snapshot.isDragging
                                  ? "white"
                                  : "none",
                              }}
                            >
                              <div
                                id={index.toString()}
                                className="my-2 w-full"
                              >
                                <div className="flex flex-row w-full">
                                  <ListItem
                                    editable
                                    metafieldDefinition={
                                      editableMetafieldDefinition
                                    }
                                    dragHandleProps={provided.dragHandleProps}
                                    onToggleEditable={() =>
                                      onToggleEditable(index)
                                    }
                                    disabled={
                                      !editableMetafieldDefinition.type
                                        .is_supported
                                    }
                                  />
                                </div>
                              </div>
                              {index !==
                                editableMetafieldDefinitions.length - 1 && (
                                <hr className="border border-gray-50 border-opacity-50" />
                              )}
                            </div>
                          );
                        }}
                      </Draggable>
                    );
                  }
                )}
                {provided.placeholder}
              </div>
            );
          }}
        </Droppable>
      </DragDropContext>
    </>

ListItem is just a component with some divs and styling

I've tried to make a simple test to check if the problem was the library. The contextual bar appears if I create a simple form (so I'm sure that it has to work):

<form data-save-bar>
  <Checkbox <some props> />
</form>

Packages and versions

List the relevant packages you’re using, and their versions. For example:

Platform

Additional context

I'm using the Rails shopify app template

gitlexa commented 11 months ago

Did you manage to solve the problem?

BaggioGiacomo commented 11 months ago

I dispatch a change event on the Form onChange:

onChange={(event) => {
  const checkbox = event.target as HTMLInputElement;
  const checkboxId = checkbox.id;
  checkbox.dispatchEvent(new Event("change", { bubbles: true }));
}}
gitlexa commented 11 months ago

I dispatch a change event on the Form onChange:

onChange={(event) => {
  const checkbox = event.target as HTMLInputElement;
  const checkboxId = checkbox.id;
  checkbox.dispatchEvent(new Event("change", { bubbles: true }));
}}

Thank you for your response I've also resolved the issue in the same manner =)