@apollo/client#Reference TypeScript Examples

The following examples show how to use @apollo/client#Reference. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: useDeleteBtnCallback.ts    From jmix-frontend with Apache License 2.0 6 votes vote down vote up
function defaultOnConfirm<
  TEntity,
  TData,
  TVariables extends HasId = HasId
  >(
  entityInstance: EntityInstance<TEntity, HasId>,
  executeDeleteMutation: GraphQLMutationFn<TData, TVariables>,
  queryName: string
) {
  return () => {
    if (entityInstance.id != null) {
      // noinspection JSIgnoredPromiseFromCall
      executeDeleteMutation({
        variables: { id: entityInstance.id } as TVariables,
        update(cache: ApolloCache<TData>) {
          // Remove deleted item from cache
          cache.modify({
            fields: {
              [queryName](existingRefs, { readField }) {
                return existingRefs.filter(
                  (ref: Reference) => entityInstance.id !== readField("id", ref)
                );
              }
            }
          });
        }
      });
    }
  };
}
Example #2
Source File: handleDuplicate.ts    From lexicon with MIT License 6 votes vote down vote up
export function handleDuplicateRef<T extends Reference>(
  firstArray: Array<T> | null,
  secondArray: Array<T> | null,
): Array<T> {
  if (!secondArray || !firstArray) {
    return secondArray || firstArray || [];
  }

  const firstArrayIds = firstArray.map(({ __ref }) => __ref);

  const filteredSecondArray = secondArray.filter(
    (item) => !firstArrayIds.includes(item.__ref),
  );

  return [...firstArray, ...filteredSecondArray];
}
Example #3
Source File: DeleteEntityField.tsx    From amplication with Apache License 2.0 4 votes vote down vote up
DeleteEntityField = ({
  entityField,
  entityId,
  showLabel = false,
  onDelete,
  onError,
}: Props) => {
  const [confirmDelete, setConfirmDelete] = useState<boolean>(false);
  const pendingChangesContext = useContext(PendingChangesContext);

  const [deleteEntityField, { loading: deleteLoading }] = useMutation<DType>(
    DELETE_ENTITY_FIELD,
    {
      update(cache, { data }) {
        if (!data) return;
        const deletedFieldId = data.deleteEntityField.id;

        if (entityField.dataType === models.EnumDataType.Lookup) {
          const relatedEntityId = entityField.properties.relatedEntityId;
          cache.evict({
            id: cache.identify({ id: relatedEntityId, __typename: "Entity" }),
          });
        }

        cache.modify({
          id: cache.identify({ id: entityId, __typename: "Entity" }),
          fields: {
            fields(existingFieldsRefs, { readField }) {
              return existingFieldsRefs.filter(
                (fieldRef: Reference) =>
                  deletedFieldId !== readField("id", fieldRef)
              );
            },
          },
        });
      },
      onCompleted: (data) => {
        pendingChangesContext.addEntity(entityId);
        onDelete && onDelete();
      },
    }
  );

  const handleDelete = useCallback(
    (event) => {
      event.stopPropagation();
      setConfirmDelete(true);
    },
    [setConfirmDelete]
  );

  const handleDismissDelete = useCallback(() => {
    setConfirmDelete(false);
  }, [setConfirmDelete]);

  const handleConfirmDelete = useCallback(() => {
    setConfirmDelete(false);
    deleteEntityField({
      variables: {
        entityFieldId: entityField.id,
      },
    }).catch(onError);
  }, [entityField, deleteEntityField, onError]);

  return (
    <>
      <ConfirmationDialog
        isOpen={confirmDelete}
        title={`Delete ${entityField.displayName}`}
        confirmButton={CONFIRM_BUTTON}
        dismissButton={DISMISS_BUTTON}
        message="Are you sure you want to delete this entity field?"
        onConfirm={handleConfirmDelete}
        onDismiss={handleDismissDelete}
      />

      <div className={CLASS_NAME}>
        {!deleteLoading && !SYSTEM_DATA_TYPES.has(entityField.dataType) && (
          <Button
            buttonStyle={
              showLabel ? EnumButtonStyle.Secondary : EnumButtonStyle.Clear
            }
            icon="trash_2"
            onClick={handleDelete}
          >
            {showLabel && "Delete"}
          </Button>
        )}
      </div>
    </>
  );
}
Example #4
Source File: EntityListItem.tsx    From amplication with Apache License 2.0 4 votes vote down vote up
EntityListItem = ({
  entity,
  applicationId,
  onDelete,
  onError,
}: Props) => {
  const pendingChangesContext = useContext(PendingChangesContext);
  const history = useHistory();

  const [confirmDelete, setConfirmDelete] = useState<boolean>(false);

  const [deleteEntity, { loading: deleteLoading }] = useMutation<DType>(
    DELETE_ENTITY,
    {
      update(cache, { data }) {
        if (!data) return;
        const deletedEntityId = data.deleteEntity.id;

        cache.modify({
          fields: {
            entities(existingEntityRefs, { readField }) {
              return existingEntityRefs.filter(
                (entityRef: Reference) =>
                  deletedEntityId !== readField("id", entityRef)
              );
            },
          },
        });
      },
      onCompleted: (data) => {
        pendingChangesContext.addEntity(data.deleteEntity.id);
        onDelete && onDelete();
      },
    }
  );

  const handleDelete = useCallback(
    (event) => {
      event.stopPropagation();
      setConfirmDelete(true);
    },
    [setConfirmDelete]
  );

  const handleDismissDelete = useCallback(() => {
    setConfirmDelete(false);
  }, [setConfirmDelete]);

  const handleConfirmDelete = useCallback(() => {
    setConfirmDelete(false);
    deleteEntity({
      variables: {
        entityId: entity.id,
      },
    }).catch(onError);
  }, [entity, deleteEntity, onError]);

  const handleRowClick = useCallback(() => {
    history.push(`/${applicationId}/entities/${entity.id}`);
  }, [history, applicationId, entity]);

  const [latestVersion] = entity.versions;

  return (
    <>
      <ConfirmationDialog
        isOpen={confirmDelete}
        title={`Delete ${entity.displayName}`}
        confirmButton={CONFIRM_BUTTON}
        dismissButton={DISMISS_BUTTON}
        message="Are you sure you want to delete this entity?"
        onConfirm={handleConfirmDelete}
        onDismiss={handleDismissDelete}
      />
      <Panel
        className={CLASS_NAME}
        clickable
        onClick={handleRowClick}
        panelStyle={EnumPanelStyle.Bordered}
      >
        <div className={`${CLASS_NAME}__row`}>
          <Link
            className={`${CLASS_NAME}__title`}
            title={entity.displayName}
            to={`/${applicationId}/entities/${entity.id}`}
          >
            {entity.displayName}
          </Link>
          {Boolean(entity.lockedByUser) && (
            <LockStatusIcon lockedByUser={entity.lockedByUser} />
          )}

          <span className="spacer" />
          {!deleteLoading && entity.name !== USER_ENTITY && (
            <Button
              buttonStyle={EnumButtonStyle.Clear}
              icon="trash_2"
              onClick={handleDelete}
            />
          )}
        </div>
        <div className={`${CLASS_NAME}__row`}>
          <span className={`${CLASS_NAME}__description`}>
            {entity.description}
          </span>
        </div>
        <div className={`${CLASS_NAME}__divider`} />

        <div className={`${CLASS_NAME}__row`}>
          <span className={`${CLASS_NAME}__label`}>Last commit:</span>

          {latestVersion.commit && (
            <UserAndTime
              account={latestVersion.commit.user?.account}
              time={latestVersion.commit.createdAt}
            />
          )}
          <span className={`${CLASS_NAME}__description`}>
            {latestVersion.commit ? latestVersion.commit?.message : "Never"}
          </span>
          <span className="spacer" />
          {entity.lockedByUser && (
            <>
              <span className={`${CLASS_NAME}__label`}>Locked by:</span>
              <UserAndTime
                account={entity.lockedByUser.account || {}}
                time={entity.lockedAt}
              />
            </>
          )}
        </div>
      </Panel>
    </>
  );
}
Example #5
Source File: NewEntity.tsx    From amplication with Apache License 2.0 4 votes vote down vote up
NewEntity = ({ applicationId }: Props) => {
  const { trackEvent } = useTracking();
  const pendingChangesContext = useContext(PendingChangesContext);

  const [createEntity, { error, data, loading }] = useMutation<DType>(
    CREATE_ENTITY,
    {
      onCompleted: (data) => {
        pendingChangesContext.addEntity(data.createOneEntity.id);
        trackEvent({
          eventName: "createEntity",
          entityName: data.createOneEntity.displayName,
        });
      },
      update(cache, { data }) {
        if (!data) return;

        const newEntity = data.createOneEntity;

        cache.modify({
          fields: {
            entities(existingEntityRefs = [], { readField }) {
              const newEntityRef = cache.writeFragment({
                data: newEntity,
                fragment: NEW_ENTITY_FRAGMENT,
              });

              if (
                existingEntityRefs.some(
                  (EntityRef: Reference) =>
                    readField("id", EntityRef) === newEntity.id
                )
              ) {
                return existingEntityRefs;
              }

              return [...existingEntityRefs, newEntityRef];
            },
          },
        });
      },
    }
  );
  const history = useHistory();

  const handleSubmit = useCallback(
    (data: CreateEntityType) => {
      const displayName = data.displayName.trim();
      const pluralDisplayName = generatePluralDisplayName(displayName);
      const singularDisplayName = generateSingularDisplayName(displayName);
      const name = pascalCase(singularDisplayName);

      createEntity({
        variables: {
          data: {
            ...data,
            displayName,
            name,
            pluralDisplayName,
            app: { connect: { id: applicationId } },
          },
        },
      }).catch(console.error);
    },
    [createEntity, applicationId]
  );

  useEffect(() => {
    if (data) {
      history.push(`/${applicationId}/entities/${data.createOneEntity.id}`);
    }
  }, [history, data, applicationId]);

  const errorMessage = formatError(error);

  return (
    <div className={CLASS_NAME}>
      <SvgThemeImage image={EnumImages.Entities} />
      <div className={`${CLASS_NAME}__instructions`}>
        Give your new entity a descriptive name. <br />
        For example: Customer, Support Ticket, Purchase Order...
      </div>
      <Formik
        initialValues={INITIAL_VALUES}
        validate={(values: CreateEntityType) => validate(values, FORM_SCHEMA)}
        onSubmit={handleSubmit}
        validateOnMount
      >
        {(formik) => {
          const handlers = {
            SUBMIT: formik.submitForm,
          };
          return (
            <Form>
              <GlobalHotKeys keyMap={keyMap} handlers={handlers} />
              <TextField
                name="displayName"
                label="New Entity Name"
                disabled={loading}
                autoFocus
                hideLabel
                placeholder="Type New Entity Name"
                autoComplete="off"
              />
              <Button
                type="submit"
                buttonStyle={EnumButtonStyle.Primary}
                disabled={!formik.isValid || loading}
              >
                Create Entity
              </Button>
            </Form>
          );
        }}
      </Formik>
      <Snackbar open={Boolean(error)} message={errorMessage} />
    </div>
  );
}
Example #6
Source File: NewEntityField.tsx    From amplication with Apache License 2.0 4 votes vote down vote up
NewEntityField = ({ entity, onFieldAdd }: Props) => {
  const { trackEvent } = useTracking();
  const pendingChangesContext = useContext(PendingChangesContext);

  const inputRef = useRef<HTMLInputElement | null>(null);

  const [autoFocus, setAutoFocus] = useState<boolean>(false);

  const [createEntityField, { error, loading }] = useMutation<TData>(
    CREATE_ENTITY_FIELD,
    {
      update(cache, { data }) {
        if (!data) return;

        const newEntityField = data.createEntityFieldByDisplayName;

        if (newEntityField.dataType === models.EnumDataType.Lookup) {
          const relatedEntityId = newEntityField.properties.relatedEntityId;
          //remove the related entity from cache so it will be updated with the new relation field
          cache.evict({
            id: cache.identify({ id: relatedEntityId, __typename: "Entity" }),
          });
        }

        cache.modify({
          id: cache.identify(entity),
          fields: {
            fields(existingEntityFieldRefs = [], { readField }) {
              const newEntityFieldRef = cache.writeFragment({
                data: newEntityField,
                fragment: NEW_ENTITY_FIELD_FRAGMENT,
              });

              if (
                existingEntityFieldRefs.some(
                  (ref: Reference) => readField("id", ref) === newEntityField.id
                )
              ) {
                return existingEntityFieldRefs;
              }

              return [...existingEntityFieldRefs, newEntityFieldRef];
            },
          },
        });
      },
      onCompleted: (data) => {
        pendingChangesContext.addEntity(entity.id);
        trackEvent({
          eventName: "createEntityField",
          entityFieldName: data.createEntityFieldByDisplayName.displayName,
          dataType: data.createEntityFieldByDisplayName.dataType,
        });
      },
      errorPolicy: "none",
    }
  );

  const handleSubmit = useCallback(
    (data, actions) => {
      setAutoFocus(true);
      createEntityField({
        variables: {
          data: {
            displayName: data.displayName,
            entity: { connect: { id: entity.id } },
          },
        },
      })
        .then((result) => {
          if (onFieldAdd && result.data) {
            onFieldAdd(result.data.createEntityFieldByDisplayName);
          }
          actions.resetForm();
          inputRef.current?.focus();
        })
        .catch(console.error);
    },
    [createEntityField, entity.id, inputRef, onFieldAdd]
  );

  const errorMessage = formatError(error);

  return (
    <div className={CLASS_NAME}>
      <Formik
        initialValues={INITIAL_VALUES}
        validateOnBlur={false}
        onSubmit={handleSubmit}
      >
        {(formik) => (
          <Form className={`${CLASS_NAME}__add-field`}>
            <TextField
              required
              name="displayName"
              label="New Field Name"
              disabled={loading}
              inputRef={inputRef}
              placeholder="Add field"
              autoComplete="off"
              autoFocus={autoFocus}
              hideLabel
              className={`${CLASS_NAME}__add-field__text`}
            />
            <Button
              buttonStyle={EnumButtonStyle.Clear}
              icon="plus"
              className={classNames(`${CLASS_NAME}__add-field__button`, {
                [`${CLASS_NAME}__add-field__button--show`]:
                  formik.values.displayName.length > 0,
              })}
            />
          </Form>
        )}
      </Formik>
      <Snackbar open={Boolean(error)} message={errorMessage} />
    </div>
  );
}
Example #7
Source File: NewRole.tsx    From amplication with Apache License 2.0 4 votes vote down vote up
NewRole = ({ onRoleAdd, applicationId }: Props) => {
  const [createRole, { error, loading }] = useMutation(CREATE_ROLE, {
    update(cache, { data }) {
      if (!data) return;

      const newAppRole = data.createAppRole;

      cache.modify({
        fields: {
          appRoles(existingAppRoleRefs = [], { readField }) {
            const newAppRoleRef = cache.writeFragment({
              data: newAppRole,
              fragment: NEW_ROLE_FRAGMENT,
            });

            if (
              existingAppRoleRefs.some(
                (appRoleRef: Reference) =>
                  readField("id", appRoleRef) === newAppRole.id
              )
            ) {
              return existingAppRoleRefs;
            }

            return [...existingAppRoleRefs, newAppRoleRef];
          },
        },
      });
    },
  });
  const inputRef = useRef<HTMLInputElement | null>(null);
  const [autoFocus, setAutoFocus] = useState<boolean>(false);

  const handleSubmit = useCallback(
    (data, actions) => {
      setAutoFocus(true);
      createRole({
        variables: {
          data: {
            ...data,
            name: camelCase(data.displayName),

            app: { connect: { id: applicationId } },
          },
        },
      })
        .then((result) => {
          if (onRoleAdd) {
            onRoleAdd(result.data.createAppRole);
          }
          actions.resetForm();
          inputRef.current?.focus();
        })
        .catch(console.error);
    },
    [createRole, applicationId, inputRef, onRoleAdd]
  );

  const errorMessage = formatError(error);

  return (
    <div className={CLASS_NAME}>
      <Formik
        initialValues={INITIAL_VALUES}
        validate={(values: Partial<models.AppRole>) =>
          validate(values, FORM_SCHEMA)
        }
        validateOnBlur={false}
        onSubmit={handleSubmit}
      >
        {(formik) => (
          <Form className={`${CLASS_NAME}__add-field`}>
            <TextField
              required
              name="displayName"
              label="New Role Name"
              disabled={loading}
              inputRef={inputRef}
              placeholder="Add role"
              autoComplete="off"
              autoFocus={autoFocus}
              hideLabel
              className={`${CLASS_NAME}__add-field__text`}
            />
            <Button
              buttonStyle={EnumButtonStyle.Clear}
              icon="plus"
              className={classNames(`${CLASS_NAME}__add-field__button`, {
                [`${CLASS_NAME}__add-field__button--show`]: !isEmpty(
                  formik.values.displayName
                ),
              })}
            />
          </Form>
        )}
      </Formik>
      <Snackbar open={Boolean(error)} message={errorMessage} />
    </div>
  );
}
Example #8
Source File: NewApiToken.tsx    From amplication with Apache License 2.0 4 votes vote down vote up
NewApiToken = ({ onCompleted }: Props) => {
  const { trackEvent } = useTracking();

  const [createApiToken, { error, loading }] = useMutation<DType>(
    CREATE_API_TOKEN,
    {
      onCompleted: (data) => {
        trackEvent({
          eventName: "createApiToken",
          tokenName: data.createApiToken.name,
        });
        onCompleted(data.createApiToken);
      },
      update(cache, { data }) {
        if (!data) return;

        const newToken = data.createApiToken;

        cache.modify({
          fields: {
            userApiTokens(existingTokenRefs = [], { readField }) {
              const newTokenRef = cache.writeFragment({
                data: newToken,
                fragment: NEW_API_TOKEN_FRAGMENT,
              });

              if (
                existingTokenRefs.some(
                  (TokenRef: Reference) =>
                    readField("id", TokenRef) === newToken.id
                )
              ) {
                return existingTokenRefs;
              }

              return [newTokenRef, ...existingTokenRefs];
            },
          },
        });
      },
    }
  );

  const handleSubmit = useCallback(
    (data: models.ApiTokenCreateInput) => {
      createApiToken({
        variables: {
          data,
        },
      }).catch(console.error);
    },
    [createApiToken]
  );

  const errorMessage = formatError(error);

  return (
    <div className={CLASS_NAME}>
      <div className={`${CLASS_NAME}__instructions`}>
        Give the new token a descriptive name.
      </div>
      <Formik
        initialValues={INITIAL_VALUES}
        validate={(values: models.ApiTokenCreateInput) =>
          validate(values, FORM_SCHEMA)
        }
        onSubmit={handleSubmit}
        validateOnMount
      >
        {(formik) => {
          const handlers = {
            SUBMIT: formik.submitForm,
          };
          return (
            <Form>
              <GlobalHotKeys keyMap={keyMap} handlers={handlers} />
              <TextField
                name="name"
                label="Token Name"
                disabled={loading}
                autoFocus
                hideLabel
                placeholder="Token Name"
                autoComplete="off"
              />
              <Button
                type="submit"
                buttonStyle={EnumButtonStyle.Primary}
                disabled={!formik.isValid || loading}
              >
                Create Token
              </Button>
            </Form>
          );
        }}
      </Formik>
      <Snackbar open={Boolean(error)} message={errorMessage} />
    </div>
  );
}
Example #9
Source File: ApplicationList.tsx    From amplication with Apache License 2.0 4 votes vote down vote up
function ApplicationList() {
  const { trackEvent } = useTracking();
  const [searchPhrase, setSearchPhrase] = useState<string>("");
  const [error, setError] = useState<Error | null>(null);

  const clearError = useCallback(() => {
    setError(null);
  }, [setError]);

  const [deleteApp] = useMutation<TDeleteData>(DELETE_APP, {
    update(cache, { data }) {
      if (!data) return;
      const deletedAppId = data.deleteApp.id;

      cache.modify({
        fields: {
          apps(existingAppRefs, { readField }) {
            return existingAppRefs.filter(
              (appRef: Reference) => deletedAppId !== readField("id", appRef)
            );
          },
        },
      });
    },
  });

  const handleDelete = useCallback(
    (app) => {
      trackEvent({
        eventName: "deleteApp",
      });
      deleteApp({
        variables: {
          appId: app.id,
        },
      }).catch(setError);
    },
    [deleteApp, setError, trackEvent]
  );

  const handleSearchChange = useCallback(
    (value) => {
      setSearchPhrase(value);
    },
    [setSearchPhrase]
  );

  const { data, error: errorLoading, loading } = useQuery<TData>(
    GET_APPLICATIONS,
    {
      variables: {
        whereName:
          searchPhrase !== ""
            ? { contains: searchPhrase, mode: models.QueryMode.Insensitive }
            : undefined,
      },
    }
  );
  const errorMessage =
    formatError(errorLoading) || (error && formatError(error));

  const handleNewAppClick = useCallback(() => {
    trackEvent({
      eventName: "createNewAppCardClick",
    });
  }, [trackEvent]);

  return (
    <div className={CLASS_NAME}>
      <div className={`${CLASS_NAME}__header`}>
        <SearchField
          label="search"
          placeholder="search"
          onChange={handleSearchChange}
        />

        <Link onClick={handleNewAppClick} to="/create-app">
          <Button
            className={`${CLASS_NAME}__add-button`}
            buttonStyle={EnumButtonStyle.Primary}
            icon="plus"
          >
            New app
          </Button>
        </Link>
      </div>
      <div className={`${CLASS_NAME}__title`}>{data?.apps.length} Apps</div>
      {loading && <CircularProgress />}

      {isEmpty(data?.apps) && !loading ? (
        <div className={`${CLASS_NAME}__empty-state`}>
          <SvgThemeImage image={EnumImages.AddApp} />
          <div className={`${CLASS_NAME}__empty-state__title`}>
            There are no apps to show
          </div>
        </div>
      ) : (
        data?.apps.map((app) => {
          return (
            <ApplicationListItem
              key={app.id}
              app={app}
              onDelete={handleDelete}
            />
          );
        })
      )}

      <Snackbar
        open={Boolean(error || errorLoading)}
        message={errorMessage}
        onClose={clearError}
      />
    </div>
  );
}
Example #10
Source File: NewWorkspace.tsx    From amplication with Apache License 2.0 4 votes vote down vote up
NewWorkspace = ({ onWorkspaceCreated }: Props) => {
  const { trackEvent } = useTracking();

  const [createWorkspace, { error, loading }] = useMutation<DType>(
    CREATE_WORKSPACE,
    {
      onCompleted: (data) => {
        trackEvent({
          eventName: "createWorkspace",
          workspaceName: data.createWorkspace.name,
        });
        onWorkspaceCreated && onWorkspaceCreated(data.createWorkspace);
      },
      update(cache, { data }) {
        if (!data) return;

        const newWorkspace = data.createWorkspace;

        cache.modify({
          fields: {
            workspaces(existingWorkspaceRefs = [], { readField }) {
              const newWorkspaceRef = cache.writeFragment({
                data: newWorkspace,
                fragment: NEW_WORKSPACE_FRAGMENT,
              });

              if (
                existingWorkspaceRefs.some(
                  (WorkspaceRef: Reference) =>
                    readField("id", WorkspaceRef) === newWorkspace.id
                )
              ) {
                return existingWorkspaceRefs;
              }

              return [...existingWorkspaceRefs, newWorkspaceRef];
            },
          },
        });
      },
    }
  );

  const handleSubmit = useCallback(
    (data: CreateWorkspaceType) => {
      createWorkspace({
        variables: {
          data,
        },
      }).catch(console.error);
    },
    [createWorkspace]
  );

  const errorMessage = formatError(error);

  return (
    <div className={CLASS_NAME}>
      <SvgThemeImage image={EnumImages.Entities} />
      <div className={`${CLASS_NAME}__instructions`}>
        Give your new workspace a descriptive name.
      </div>
      <Formik
        initialValues={INITIAL_VALUES}
        validate={(values: CreateWorkspaceType) =>
          validate(values, FORM_SCHEMA)
        }
        onSubmit={handleSubmit}
        validateOnMount
      >
        {(formik) => {
          const handlers = {
            SUBMIT: formik.submitForm,
          };
          return (
            <Form>
              <GlobalHotKeys keyMap={keyMap} handlers={handlers} />
              <TextField
                name="name"
                label="New Workspace Name"
                disabled={loading}
                autoFocus
                hideLabel
                placeholder="Type New Workspace Name"
                autoComplete="off"
              />
              <Button
                type="submit"
                buttonStyle={EnumButtonStyle.Primary}
                disabled={!formik.isValid || loading}
              >
                Create Workspace
              </Button>
            </Form>
          );
        }}
      </Formik>
      <Snackbar open={Boolean(error)} message={errorMessage} />
    </div>
  );
}