Skip to content

Instantly share code, notes, and snippets.

@andyxmas
Created July 24, 2023 08:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save andyxmas/a048ac8afe6f7c62020894c2c9ab351e to your computer and use it in GitHub Desktop.
Save andyxmas/a048ac8afe6f7c62020894c2c9ab351e to your computer and use it in GitHub Desktop.
availability select
import React, { useState, useEffect } from "react";
import {
Select,
useAppMetafields,
BlockStack,
useApplyAttributeChange,
useTranslate,
TextField,
useExtensionCapability,
useBuyerJourneyIntercept,
} from "@shopify/checkout-ui-extensions-react";
const AvailabilitySelect = () => {
/**
* Variables
*/
const INPUT_COMPARATOR = "enter-manually";
const translate = useTranslate();
const applyAttributesChange = useApplyAttributeChange();
// Fetch the metafield at the shop level
const availabilityOptionsArray = useAppMetafields({
namespace: "checkout",
key: "recipient-availability-options",
});
let availabilityOptions = [];
if (
availabilityOptionsArray.length &&
availabilityOptionsArray[0].metafield?.value
) {
availabilityOptions = JSON.parse(
availabilityOptionsArray[0].metafield.value
);
}
/**
* State
*/
const [selection, setSelection] = useState("");
const [showTextField, setShowTextField] = useState(false);
const [textFieldInput, setTextFieldInput] = useState("");
const [textFieldPositionInput, setTextFieldPositionInput] = useState("");
const [validationError, setValidationError] = useState(false);
const [selectValidationError, setSelectValidationError] = useState(false);
const canBlockProgress = useExtensionCapability("block_progress");
// If textFieldInput is not valid, show validation errors
useEffect(() => {
if (canBlockProgress && !isTextFieldSet()) {
showValidationErrors();
return;
}
clearValidationErrors();
}, [textFieldInput]);
// Block progress if no selection is made
useEffect(() => {
if (canBlockProgress && !isSelectionSet()) {
showValidationErrors();
return;
}
clearValidationErrors();
}, [selection]);
/**
* Block progress
*/
useBuyerJourneyIntercept(() => {
let response = {
behavior: "allow",
perform: (result) => {
// Ensure any errors are hidden
clearValidationErrors();
},
};
if (showTextField && textFieldInput.trim().length === 0) {
response = {
behavior: "block",
reason: translate("availability.error.reason"),
perform: (result) => {
// If we were able to block progress, set a validation error
if (result.behavior === "block")
setValidationError(translate("availability.error.label"));
},
};
}
if (selection.trim().length === 0) {
response = {
behavior: "block",
reason: translate("availability.error.reason"),
perform: (result) => {
// If we were able to block progress, set a validation error
if (result.behavior === "block")
setSelectValidationError(
translate("availability.duration.error.reason")
);
},
};
}
return response;
}, [textFieldInput, showTextField, selection]);
/**
* Methods
*/
const isTextFieldSet = () => {
return textFieldInput !== "";
};
const isSelectionSet = () => {
return selection !== "";
};
const showValidationErrors = () => {
setValidationError(true);
};
const clearValidationErrors = () => {
setValidationError(false);
setSelectValidationError(false);
};
/**
* Setter to determine if the text field should be rendered
* @param {*} value input select value
* @returns {void}
*/
const canRenderTextField = (value) => {
if (!value) {
setShowTextField(false);
return;
}
if (value.toLowerCase().replace(/ /g, "-") !== INPUT_COMPARATOR) {
setShowTextField(false);
return;
}
setShowTextField(true);
};
return (
<BlockStack>
<TextField
label={translate("recipient.label")}
type="text"
value={textFieldPositionInput}
onChange={(value) => {
setTextFieldPositionInput(value);
applyAttributesChange({
type: "updateAttribute",
key: "Recipient Position",
value: `${value}`,
});
}}
/>
<Select
label={translate("availability.label")}
value={selection}
error={selectValidationError}
onChange={(value) => {
setSelection(value);
applyAttributesChange({
type: "updateAttribute",
key: "Availability",
value: `${value}`,
});
canRenderTextField(value);
}}
options={[
{
label: translate("availability.option.label"),
value: "select option",
disabled: true,
},
].concat(
availabilityOptions.map((option) => {
return {
value: option,
label: option,
};
})
)}
/>
{showTextField && (
<TextField
label={translate("availability.duration.label")}
type="text"
value={textFieldInput}
error={validationError}
required={canBlockProgress}
onChange={(value) => {
setTextFieldInput(value);
applyAttributesChange({
type: "updateAttribute",
key: "Vessel Duration",
value: `${value}`,
});
}}
/>
)}
</BlockStack>
);
};
export { AvailabilitySelect };
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment