Fix strict null check in attributes (#3005)
This commit is contained in:
parent
01172aed95
commit
993595caac
17 changed files with 207 additions and 178 deletions
|
@ -197,7 +197,7 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = props => {
|
|||
label={intl.formatMessage(messages.entityType)}
|
||||
name="entityType"
|
||||
onChange={onChange}
|
||||
value={data.entityType}
|
||||
value={data.entityType ?? undefined}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
@ -40,7 +40,7 @@ const useStyles = makeStyles(
|
|||
);
|
||||
|
||||
interface UnitData {
|
||||
unit?: MeasurementUnitsEnum;
|
||||
unit: MeasurementUnitsEnum | null | undefined;
|
||||
system?: UnitSystem;
|
||||
type?: UnitType;
|
||||
}
|
||||
|
@ -145,7 +145,10 @@ export const NumericUnits: React.FC<NumericUnitsProps> = ({
|
|||
label={formatMessage(M.messages.unitSystem)}
|
||||
choices={systemChoices}
|
||||
onChange={({ target }: React.ChangeEvent<HTMLSelectElement>) =>
|
||||
setUnitData({ system: target.value as UnitSystem })
|
||||
setUnitData(data => ({
|
||||
...data,
|
||||
system: target.value as UnitSystem,
|
||||
}))
|
||||
}
|
||||
value={system}
|
||||
disabled={disabled}
|
||||
|
@ -156,8 +159,8 @@ export const NumericUnits: React.FC<NumericUnitsProps> = ({
|
|||
label={formatMessage(M.messages.unitOf)}
|
||||
choices={typeChoices}
|
||||
onChange={({ target }: React.ChangeEvent<HTMLSelectElement>) =>
|
||||
setUnitData(({ system }) => ({
|
||||
system,
|
||||
setUnitData(data => ({
|
||||
...data,
|
||||
type: target.value as UnitType,
|
||||
}))
|
||||
}
|
||||
|
@ -168,7 +171,7 @@ export const NumericUnits: React.FC<NumericUnitsProps> = ({
|
|||
{...(type && !unit && errorProps)}
|
||||
testId="unit"
|
||||
label={formatMessage(M.messages.unit)}
|
||||
choices={type ? unitChoices[system][type] : []}
|
||||
choices={type && system ? unitChoices[system][type] : []}
|
||||
onChange={({ target }: React.ChangeEvent<HTMLSelectElement>) =>
|
||||
setUnitData(data => ({
|
||||
...data,
|
||||
|
@ -177,7 +180,7 @@ export const NumericUnits: React.FC<NumericUnitsProps> = ({
|
|||
}
|
||||
disabled={!type || disabled}
|
||||
value={
|
||||
type && unitMapping[system][type].includes(unit)
|
||||
type && system && unit && unitMapping[system][type].includes(unit)
|
||||
? unit
|
||||
: undefined
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ import { TablePaginationWithContext } from "@dashboard/components/TablePaginatio
|
|||
import TableRowLink from "@dashboard/components/TableRowLink";
|
||||
import { AttributeFragment } from "@dashboard/graphql";
|
||||
import { translateBoolean } from "@dashboard/intl";
|
||||
import { maybe, renderCollection } from "@dashboard/misc";
|
||||
import { renderCollection } from "@dashboard/misc";
|
||||
import { ListActions, ListProps, SortPage } from "@dashboard/types";
|
||||
import { getArrowDirection } from "@dashboard/utils/sort";
|
||||
import { TableBody, TableCell, TableFooter } from "@material-ui/core";
|
||||
|
@ -95,7 +95,7 @@ const AttributeList: React.FC<AttributeListProps> = ({
|
|||
className={classes.colSlug}
|
||||
direction={
|
||||
sort.sort === AttributeListUrlSortField.slug
|
||||
? getArrowDirection(sort.asc)
|
||||
? getArrowDirection(!!sort.asc)
|
||||
: undefined
|
||||
}
|
||||
arrowPosition="right"
|
||||
|
@ -107,7 +107,7 @@ const AttributeList: React.FC<AttributeListProps> = ({
|
|||
className={classes.colName}
|
||||
direction={
|
||||
sort.sort === AttributeListUrlSortField.name
|
||||
? getArrowDirection(sort.asc)
|
||||
? getArrowDirection(!!sort.asc)
|
||||
: undefined
|
||||
}
|
||||
onClick={() => onSort(AttributeListUrlSortField.name)}
|
||||
|
@ -122,7 +122,7 @@ const AttributeList: React.FC<AttributeListProps> = ({
|
|||
className={classes.colVisible}
|
||||
direction={
|
||||
sort.sort === AttributeListUrlSortField.visible
|
||||
? getArrowDirection(sort.asc)
|
||||
? getArrowDirection(!!sort.asc)
|
||||
: undefined
|
||||
}
|
||||
textAlign="center"
|
||||
|
@ -138,7 +138,7 @@ const AttributeList: React.FC<AttributeListProps> = ({
|
|||
className={classes.colSearchable}
|
||||
direction={
|
||||
sort.sort === AttributeListUrlSortField.searchable
|
||||
? getArrowDirection(sort.asc)
|
||||
? getArrowDirection(!!sort.asc)
|
||||
: undefined
|
||||
}
|
||||
textAlign="center"
|
||||
|
@ -154,7 +154,7 @@ const AttributeList: React.FC<AttributeListProps> = ({
|
|||
className={classes.colFaceted}
|
||||
direction={
|
||||
sort.sort === AttributeListUrlSortField.useInFacetedSearch
|
||||
? getArrowDirection(sort.asc)
|
||||
? getArrowDirection(!!sort.asc)
|
||||
: undefined
|
||||
}
|
||||
textAlign="center"
|
||||
|
@ -185,14 +185,14 @@ const AttributeList: React.FC<AttributeListProps> = ({
|
|||
key={attribute ? attribute.id : "skeleton"}
|
||||
href={attribute && attributeUrl(attribute.id)}
|
||||
className={classes.link}
|
||||
data-test-id={"id-" + maybe(() => attribute.id)}
|
||||
data-test-id={`id-${attribute?.id}`}
|
||||
>
|
||||
<TableCell padding="checkbox">
|
||||
<Checkbox
|
||||
checked={isSelected}
|
||||
disabled={disabled}
|
||||
disableClickPropagation
|
||||
onChange={() => toggle(attribute.id)}
|
||||
onChange={() => toggle(attribute?.id ?? "")}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell className={classes.colSlug} data-test-id="slug">
|
||||
|
@ -204,7 +204,7 @@ const AttributeList: React.FC<AttributeListProps> = ({
|
|||
<TableCell
|
||||
className={classes.colVisible}
|
||||
data-test-id="visible"
|
||||
data-test-visible={maybe(() => attribute.visibleInStorefront)}
|
||||
data-test-visible={attribute?.visibleInStorefront}
|
||||
>
|
||||
{attribute ? (
|
||||
translateBoolean(attribute.visibleInStorefront, intl)
|
||||
|
@ -215,9 +215,7 @@ const AttributeList: React.FC<AttributeListProps> = ({
|
|||
<TableCell
|
||||
className={classes.colSearchable}
|
||||
data-test-id="searchable"
|
||||
data-test-searchable={maybe(
|
||||
() => attribute.filterableInDashboard,
|
||||
)}
|
||||
data-test-searchable={attribute?.filterableInDashboard}
|
||||
>
|
||||
{attribute ? (
|
||||
translateBoolean(attribute.filterableInDashboard, intl)
|
||||
|
@ -228,9 +226,9 @@ const AttributeList: React.FC<AttributeListProps> = ({
|
|||
<TableCell
|
||||
className={classes.colFaceted}
|
||||
data-test-id="use-in-faceted-search"
|
||||
data-test-use-in-faceted-search={maybe(
|
||||
() => attribute.filterableInStorefront,
|
||||
)}
|
||||
data-test-use-in-faceted-search={
|
||||
attribute?.filterableInStorefront
|
||||
}
|
||||
>
|
||||
{attribute ? (
|
||||
translateBoolean(attribute.filterableInStorefront, intl)
|
||||
|
|
|
@ -22,7 +22,6 @@ import {
|
|||
import { SubmitPromise } from "@dashboard/hooks/useForm";
|
||||
import useNavigator from "@dashboard/hooks/useNavigator";
|
||||
import { sectionNames } from "@dashboard/intl";
|
||||
import { maybe } from "@dashboard/misc";
|
||||
import { ListSettings, ReorderAction } from "@dashboard/types";
|
||||
import { mapEdgesToItems, mapMetadataItemToInput } from "@dashboard/utils/maps";
|
||||
import useMetadataChangeTrigger from "@dashboard/utils/metadata/useMetadataChangeTrigger";
|
||||
|
@ -37,11 +36,13 @@ import AttributeProperties from "../AttributeProperties";
|
|||
import AttributeValues from "../AttributeValues";
|
||||
|
||||
export interface AttributePageProps {
|
||||
attribute: AttributeDetailsFragment | null;
|
||||
attribute?: AttributeDetailsFragment | null | undefined;
|
||||
disabled: boolean;
|
||||
errors: AttributeErrorFragment[];
|
||||
saveButtonBarState: ConfirmButtonTransitionState;
|
||||
values: AttributeDetailsQuery["attribute"]["choices"];
|
||||
values?:
|
||||
| NonNullable<AttributeDetailsQuery["attribute"]>["choices"]
|
||||
| undefined;
|
||||
onDelete: () => void;
|
||||
onSubmit: (data: AttributePageFormData) => SubmitPromise;
|
||||
onValueAdd: () => void;
|
||||
|
@ -64,7 +65,7 @@ export interface AttributePageFormData extends MetadataFormData {
|
|||
availableInGrid: boolean;
|
||||
filterableInDashboard: boolean;
|
||||
inputType: AttributeInputTypeEnum;
|
||||
entityType: AttributeEntityTypeEnum;
|
||||
entityType: AttributeEntityTypeEnum | null;
|
||||
filterableInStorefront: boolean;
|
||||
name: string;
|
||||
slug: string;
|
||||
|
@ -102,59 +103,51 @@ const AttributePage: React.FC<AttributePageProps> = ({
|
|||
makeChangeHandler: makeMetadataChangeHandler,
|
||||
} = useMetadataChangeTrigger();
|
||||
|
||||
const initialForm: AttributePageFormData =
|
||||
attribute === null
|
||||
? {
|
||||
availableInGrid: true,
|
||||
entityType: null,
|
||||
filterableInDashboard: true,
|
||||
filterableInStorefront: true,
|
||||
inputType: AttributeInputTypeEnum.DROPDOWN,
|
||||
metadata: [],
|
||||
name: "",
|
||||
privateMetadata: [],
|
||||
slug: "",
|
||||
storefrontSearchPosition: "",
|
||||
type: AttributeTypeEnum.PRODUCT_TYPE,
|
||||
valueRequired: true,
|
||||
visibleInStorefront: true,
|
||||
unit: undefined,
|
||||
}
|
||||
: {
|
||||
availableInGrid: attribute?.availableInGrid ?? true,
|
||||
entityType: attribute?.entityType ?? null,
|
||||
filterableInDashboard: attribute?.filterableInDashboard ?? true,
|
||||
filterableInStorefront: attribute?.filterableInStorefront ?? true,
|
||||
inputType: attribute?.inputType ?? AttributeInputTypeEnum.DROPDOWN,
|
||||
metadata: attribute?.metadata?.map(mapMetadataItemToInput),
|
||||
name: attribute?.name ?? "",
|
||||
privateMetadata: attribute?.privateMetadata?.map(
|
||||
mapMetadataItemToInput,
|
||||
),
|
||||
slug: attribute?.slug ?? "",
|
||||
storefrontSearchPosition:
|
||||
attribute?.storefrontSearchPosition.toString() ?? "",
|
||||
type: attribute?.type || AttributeTypeEnum.PRODUCT_TYPE,
|
||||
valueRequired: !!attribute?.valueRequired ?? true,
|
||||
visibleInStorefront: attribute?.visibleInStorefront ?? true,
|
||||
unit: attribute?.unit || null,
|
||||
};
|
||||
const initialForm: AttributePageFormData = !attribute
|
||||
? {
|
||||
availableInGrid: true,
|
||||
entityType: null,
|
||||
filterableInDashboard: true,
|
||||
filterableInStorefront: true,
|
||||
inputType: AttributeInputTypeEnum.DROPDOWN,
|
||||
metadata: [],
|
||||
name: "",
|
||||
privateMetadata: [],
|
||||
slug: "",
|
||||
storefrontSearchPosition: "",
|
||||
type: AttributeTypeEnum.PRODUCT_TYPE,
|
||||
valueRequired: true,
|
||||
visibleInStorefront: true,
|
||||
unit: undefined,
|
||||
}
|
||||
: {
|
||||
availableInGrid: attribute.availableInGrid,
|
||||
entityType: attribute.entityType,
|
||||
filterableInDashboard: attribute.filterableInDashboard,
|
||||
filterableInStorefront: attribute.filterableInStorefront,
|
||||
inputType: attribute?.inputType ?? AttributeInputTypeEnum.DROPDOWN,
|
||||
metadata: attribute.metadata.map(mapMetadataItemToInput),
|
||||
name: attribute?.name ?? "",
|
||||
privateMetadata: attribute.privateMetadata.map(mapMetadataItemToInput),
|
||||
slug: attribute?.slug ?? "",
|
||||
storefrontSearchPosition: attribute.storefrontSearchPosition.toString(),
|
||||
type: attribute?.type ?? AttributeTypeEnum.PRODUCT_TYPE,
|
||||
valueRequired: !!attribute.valueRequired,
|
||||
visibleInStorefront: attribute.visibleInStorefront,
|
||||
unit: attribute?.unit ?? null,
|
||||
};
|
||||
|
||||
const handleSubmit = (data: AttributePageFormData) => {
|
||||
const metadata =
|
||||
!attribute || isMetadataModified ? data.metadata : undefined;
|
||||
const metadata = !attribute || isMetadataModified ? data.metadata : [];
|
||||
const privateMetadata =
|
||||
!attribute || isPrivateMetadataModified
|
||||
? data.privateMetadata
|
||||
: undefined;
|
||||
const type = attribute === null ? data.type : undefined;
|
||||
!attribute || isPrivateMetadataModified ? data.privateMetadata : [];
|
||||
|
||||
return onSubmit({
|
||||
...data,
|
||||
metadata,
|
||||
privateMetadata,
|
||||
slug: data.slug || slugify(data.name).toLowerCase(),
|
||||
type,
|
||||
type: data.type,
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -185,13 +178,13 @@ const AttributePage: React.FC<AttributePageProps> = ({
|
|||
</Backlink>
|
||||
<PageHeader
|
||||
title={
|
||||
attribute === null
|
||||
!attribute
|
||||
? intl.formatMessage({
|
||||
id: "8cUEPV",
|
||||
defaultMessage: "Create New Attribute",
|
||||
description: "page title",
|
||||
})
|
||||
: maybe(() => attribute.name)
|
||||
: attribute.name
|
||||
}
|
||||
/>
|
||||
<Grid>
|
||||
|
@ -215,7 +208,7 @@ const AttributePage: React.FC<AttributePageProps> = ({
|
|||
<AttributeValues
|
||||
inputType={data.inputType}
|
||||
disabled={disabled}
|
||||
values={mapEdgesToItems(values)}
|
||||
values={mapEdgesToItems(values) ?? []}
|
||||
onValueAdd={onValueAdd}
|
||||
onValueDelete={onValueDelete}
|
||||
onValueReorder={onValueReorder}
|
||||
|
@ -248,7 +241,7 @@ const AttributePage: React.FC<AttributePageProps> = ({
|
|||
</div>
|
||||
</Grid>
|
||||
<Savebar
|
||||
disabled={isSaveDisabled}
|
||||
disabled={!!isSaveDisabled}
|
||||
state={saveButtonBarState}
|
||||
onCancel={() => navigate(attributeListUrl())}
|
||||
onSubmit={submit}
|
||||
|
|
|
@ -41,11 +41,9 @@ const AttributeSwatchField: React.FC<AttributeSwatchFieldProps<
|
|||
const handleFileUpload = async (file: File) => {
|
||||
setProcessing(true);
|
||||
|
||||
const {
|
||||
data: { fileUpload },
|
||||
} = await uploadFile({ variables: { file } });
|
||||
const { data } = await uploadFile({ variables: { file } });
|
||||
|
||||
if (fileUpload.errors?.length) {
|
||||
if (data?.fileUpload?.errors?.length) {
|
||||
notify({
|
||||
status: "error",
|
||||
title: intl.formatMessage(errorMessages.imgageUploadErrorTitle),
|
||||
|
@ -53,8 +51,8 @@ const AttributeSwatchField: React.FC<AttributeSwatchFieldProps<
|
|||
});
|
||||
} else {
|
||||
set({
|
||||
fileUrl: fileUpload.uploadedFile.url,
|
||||
contentType: fileUpload.uploadedFile.contentType,
|
||||
fileUrl: data?.fileUpload?.uploadedFile?.url,
|
||||
contentType: data?.fileUpload?.uploadedFile?.contentType ?? "",
|
||||
value: undefined,
|
||||
});
|
||||
}
|
||||
|
@ -95,7 +93,7 @@ const AttributeSwatchField: React.FC<AttributeSwatchFieldProps<
|
|||
<FileUploadField
|
||||
disabled={processing}
|
||||
loading={processing}
|
||||
file={{ label: null, value: null, file: null }}
|
||||
file={{ label: "", value: "", file: undefined }}
|
||||
onFileUpload={handleFileUpload}
|
||||
onFileDelete={handleFileDelete}
|
||||
inputProps={{
|
||||
|
|
|
@ -71,13 +71,13 @@ const useStyles = makeStyles(
|
|||
{ name: "AttributeValues" },
|
||||
);
|
||||
|
||||
const getSwatchCellStyle = (value: AttributeValueFragment) => {
|
||||
const getSwatchCellStyle = (value?: AttributeValueFragment | undefined) => {
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
return value.file
|
||||
? { backgroundImage: `url(${value.file.url})` }
|
||||
: { backgroundColor: value.value };
|
||||
: { backgroundColor: value.value ?? undefined };
|
||||
};
|
||||
|
||||
const AttributeValues: React.FC<AttributeValuesProps> = ({
|
||||
|
@ -198,7 +198,9 @@ const AttributeValues: React.FC<AttributeValuesProps> = ({
|
|||
<IconButton
|
||||
variant="secondary"
|
||||
disabled={disabled}
|
||||
onClick={stopPropagation(() => onValueDelete(value.id))}
|
||||
onClick={stopPropagation(() =>
|
||||
onValueDelete(value?.id ?? ""),
|
||||
)}
|
||||
>
|
||||
<DeleteIcon />
|
||||
</IconButton>
|
||||
|
|
|
@ -14,9 +14,9 @@ const messages = defineMessages({
|
|||
});
|
||||
|
||||
export function getAttributeSlugErrorMessage(
|
||||
err: AttributeErrorFragment,
|
||||
err: AttributeErrorFragment | undefined,
|
||||
intl: IntlShape,
|
||||
): string {
|
||||
): string | undefined {
|
||||
switch (err?.code) {
|
||||
case AttributeErrorCode.UNIQUE:
|
||||
return intl.formatMessage(messages.attributeSlugUnique);
|
||||
|
@ -26,9 +26,9 @@ export function getAttributeSlugErrorMessage(
|
|||
}
|
||||
|
||||
export function getAttributeValueErrorMessage(
|
||||
err: AttributeErrorFragment,
|
||||
err: AttributeErrorFragment | undefined,
|
||||
intl: IntlShape,
|
||||
): string {
|
||||
): string | undefined {
|
||||
switch (err?.code) {
|
||||
case AttributeErrorCode.ALREADY_EXISTS:
|
||||
return intl.formatMessage(messages.attributeValueAlreadyExists);
|
||||
|
|
|
@ -80,8 +80,10 @@ export const attribute: AttributeDetailsQuery["attribute"] = {
|
|||
visibleInStorefront: true,
|
||||
};
|
||||
|
||||
export const attributes: Array<AttributeListQuery["attributes"]["edges"][0]["node"] &
|
||||
ProductDetailsQuery["product"]["attributes"][0]["attribute"]> = [
|
||||
export const attributes: Array<NonNullable<
|
||||
AttributeListQuery["attributes"]
|
||||
>["edges"][0]["node"] &
|
||||
NonNullable<ProductDetailsQuery["product"]>["attributes"][0]["attribute"]> = [
|
||||
{
|
||||
__typename: "Attribute" as "Attribute",
|
||||
entityType: AttributeEntityTypeEnum.PRODUCT,
|
||||
|
|
|
@ -66,7 +66,7 @@ export function filterable(
|
|||
attribute: Pick<AttributeFragment, "inputType">,
|
||||
): boolean {
|
||||
return ATTRIBUTE_TYPES_WITH_CONFIGURABLE_FACED_NAVIGATION.includes(
|
||||
attribute.inputType,
|
||||
attribute.inputType!,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -86,9 +86,9 @@ export function attributeValueFragmentToFormData(
|
|||
data: AttributeValueFragment | null,
|
||||
): AttributeValueEditDialogFormData {
|
||||
return {
|
||||
name: data?.name,
|
||||
value: data?.value,
|
||||
contentType: data?.file?.contentType,
|
||||
name: data?.name ?? "",
|
||||
value: data?.value ?? "",
|
||||
contentType: data?.file?.contentType ?? "",
|
||||
fileUrl: data?.file?.url,
|
||||
};
|
||||
}
|
||||
|
@ -265,7 +265,7 @@ export const mergeAttributeValues = (
|
|||
) => {
|
||||
const attribute = attributes.find(attribute => attribute.id === attributeId);
|
||||
|
||||
return attribute.value
|
||||
return attribute?.value
|
||||
? [...attribute.value, ...attributeValues]
|
||||
: attributeValues;
|
||||
};
|
||||
|
@ -332,8 +332,8 @@ export const getAttributesOfUploadedFiles = (
|
|||
const attribute = fileValuesToUpload[index];
|
||||
|
||||
return {
|
||||
file: uploadFileResult.data.fileUpload.uploadedFile.url,
|
||||
contentType: uploadFileResult.data.fileUpload.uploadedFile.contentType,
|
||||
file: uploadFileResult.data?.fileUpload?.uploadedFile?.url,
|
||||
contentType: uploadFileResult.data?.fileUpload?.uploadedFile?.contentType,
|
||||
id: attribute.id,
|
||||
values: [],
|
||||
};
|
||||
|
@ -380,7 +380,7 @@ export const getFileAttributeDisplayData = (
|
|||
|
||||
export const getPageReferenceAttributeDisplayData = (
|
||||
attribute: AttributeInput,
|
||||
referencePages: RelayToFlat<SearchPagesQuery["search"]>,
|
||||
referencePages: RelayToFlat<NonNullable<SearchPagesQuery["search"]>>,
|
||||
) => ({
|
||||
...attribute,
|
||||
data: {
|
||||
|
@ -388,12 +388,18 @@ export const getPageReferenceAttributeDisplayData = (
|
|||
references:
|
||||
referencePages?.length > 0 && attribute.value?.length > 0
|
||||
? mapPagesToChoices(
|
||||
attribute.value.map(value => {
|
||||
attribute.value.reduce<
|
||||
RelayToFlat<NonNullable<SearchPagesQuery["search"]>>
|
||||
>((acc, value) => {
|
||||
const reference = referencePages.find(
|
||||
reference => reference.id === value,
|
||||
);
|
||||
return { ...reference };
|
||||
}),
|
||||
|
||||
if (reference) {
|
||||
acc.push(reference);
|
||||
}
|
||||
return acc;
|
||||
}, []),
|
||||
)
|
||||
: [],
|
||||
},
|
||||
|
@ -401,7 +407,7 @@ export const getPageReferenceAttributeDisplayData = (
|
|||
|
||||
export const getProductReferenceAttributeDisplayData = (
|
||||
attribute: AttributeInput,
|
||||
referenceProducts: RelayToFlat<SearchProductsQuery["search"]>,
|
||||
referenceProducts: RelayToFlat<NonNullable<SearchProductsQuery["search"]>>,
|
||||
) => ({
|
||||
...attribute,
|
||||
data: {
|
||||
|
@ -409,12 +415,18 @@ export const getProductReferenceAttributeDisplayData = (
|
|||
references:
|
||||
referenceProducts?.length > 0 && attribute.value?.length > 0
|
||||
? mapNodeToChoice(
|
||||
attribute.value.map(value => {
|
||||
attribute.value.reduce<
|
||||
RelayToFlat<NonNullable<SearchProductsQuery["search"]>>
|
||||
>((acc, value) => {
|
||||
const reference = referenceProducts.find(
|
||||
reference => reference.id === value,
|
||||
);
|
||||
return { ...reference };
|
||||
}),
|
||||
|
||||
if (reference) {
|
||||
acc.push(reference);
|
||||
}
|
||||
return acc;
|
||||
}, []),
|
||||
)
|
||||
: [],
|
||||
},
|
||||
|
@ -422,7 +434,7 @@ export const getProductReferenceAttributeDisplayData = (
|
|||
|
||||
export const getProductVariantReferenceAttributeDisplayData = (
|
||||
attribute: AttributeInput,
|
||||
referenceProducts: RelayToFlat<SearchProductsQuery["search"]>,
|
||||
referenceProducts: RelayToFlat<NonNullable<SearchProductsQuery["search"]>>,
|
||||
) => ({
|
||||
...attribute,
|
||||
data: {
|
||||
|
@ -430,12 +442,19 @@ export const getProductVariantReferenceAttributeDisplayData = (
|
|||
references:
|
||||
referenceProducts?.length > 0 && attribute.value?.length > 0
|
||||
? mapNodeToChoice(
|
||||
attribute.value.map(value => {
|
||||
const reference = mapReferenceProductsToVariants(
|
||||
referenceProducts,
|
||||
).find(reference => reference.id === value);
|
||||
return { ...reference };
|
||||
}),
|
||||
attribute.value.reduce<Array<Node & Record<"name", string>>>(
|
||||
(acc, value) => {
|
||||
const reference = mapReferenceProductsToVariants(
|
||||
referenceProducts,
|
||||
).find(reference => reference.id === value);
|
||||
|
||||
if (reference) {
|
||||
acc.push(reference);
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
[],
|
||||
),
|
||||
)
|
||||
: [],
|
||||
},
|
||||
|
@ -443,8 +462,8 @@ export const getProductVariantReferenceAttributeDisplayData = (
|
|||
|
||||
export const getReferenceAttributeDisplayData = (
|
||||
attribute: AttributeInput,
|
||||
referencePages: RelayToFlat<SearchPagesQuery["search"]>,
|
||||
referenceProducts: RelayToFlat<SearchProductsQuery["search"]>,
|
||||
referencePages: RelayToFlat<NonNullable<SearchPagesQuery["search"]>>,
|
||||
referenceProducts: RelayToFlat<NonNullable<SearchProductsQuery["search"]>>,
|
||||
) => {
|
||||
if (attribute.data.entityType === AttributeEntityTypeEnum.PAGE) {
|
||||
return getPageReferenceAttributeDisplayData(attribute, referencePages);
|
||||
|
@ -466,8 +485,8 @@ export const getReferenceAttributeDisplayData = (
|
|||
export const getAttributesDisplayData = (
|
||||
attributes: AttributeInput[],
|
||||
attributesWithNewFileValue: FormsetData<null, File>,
|
||||
referencePages: RelayToFlat<SearchPagesQuery["search"]>,
|
||||
referenceProducts: RelayToFlat<SearchProductsQuery["search"]>,
|
||||
referencePages: RelayToFlat<NonNullable<SearchPagesQuery["search"]>>,
|
||||
referenceProducts: RelayToFlat<NonNullable<SearchProductsQuery["search"]>>,
|
||||
) =>
|
||||
attributes.map(attribute => {
|
||||
if (attribute.data.inputType === AttributeInputTypeEnum.REFERENCE) {
|
||||
|
@ -499,11 +518,11 @@ export const getReferenceAttributeEntityTypeFromAttribute = (
|
|||
attributes?.find(attribute => attribute.id === attributeId)?.data?.entityType;
|
||||
|
||||
export const mapReferenceProductsToVariants = (
|
||||
referenceProducts: RelayToFlat<SearchProductsQuery["search"]>,
|
||||
referenceProducts: RelayToFlat<NonNullable<SearchProductsQuery["search"]>>,
|
||||
) =>
|
||||
referenceProducts.flatMap(product =>
|
||||
product.variants.map(variant => ({
|
||||
(product.variants || []).map(variant => ({
|
||||
...variant,
|
||||
name: product.name + " " + variant.name,
|
||||
name: `${product.name} ${variant.name}`,
|
||||
})),
|
||||
);
|
||||
|
|
|
@ -136,7 +136,7 @@ const createAttribute = ({
|
|||
value,
|
||||
}: CreateAttribute): AttributeInput => ({
|
||||
data: {
|
||||
entityType: null,
|
||||
entityType: undefined,
|
||||
inputType,
|
||||
isRequired: false,
|
||||
// those values don't matter
|
||||
|
@ -146,7 +146,7 @@ const createAttribute = ({
|
|||
},
|
||||
id: ATTR_ID,
|
||||
label: "MyAttribute",
|
||||
value: value !== null ? [value] : [],
|
||||
value: value !== null && value !== undefined ? [value] : [],
|
||||
});
|
||||
|
||||
const createSelectAttribute = (value: string) =>
|
||||
|
@ -478,7 +478,7 @@ describe("Sending only changed attributes", () => {
|
|||
});
|
||||
describe("works with file attributes", () => {
|
||||
it("removes existing image (img -> null)", () => {
|
||||
const attribute = createFileAttribute(null);
|
||||
const attribute = createFileAttribute("");
|
||||
const prevAttribute = createNumericAttribute("bob.jpg");
|
||||
|
||||
const result = prepareAttributesInput({
|
||||
|
@ -494,7 +494,7 @@ describe("Sending only changed attributes", () => {
|
|||
});
|
||||
it("adds new image (null -> img)", () => {
|
||||
const attribute = createFileAttribute("bob.jpg");
|
||||
const prevAttribute = createNumericAttribute(null);
|
||||
const prevAttribute = createNumericAttribute("");
|
||||
|
||||
const uploadUrl = "http://some-url.com/media/file_upload/bob.jpg";
|
||||
const result = prepareAttributesInput({
|
||||
|
|
|
@ -48,7 +48,7 @@ export function createAttributeMultiChangeHandler(
|
|||
|
||||
const newAttributeValues = toggle(
|
||||
value,
|
||||
attribute.value,
|
||||
attribute?.value ?? [],
|
||||
(a, b) => a === b,
|
||||
);
|
||||
|
||||
|
@ -88,6 +88,7 @@ export function createFetchReferencesHandler(
|
|||
) {
|
||||
fetchReferencePages(value);
|
||||
} else if (
|
||||
attribute.data?.entityType &&
|
||||
[
|
||||
AttributeEntityTypeEnum.PRODUCT,
|
||||
AttributeEntityTypeEnum.PRODUCT_VARIANT,
|
||||
|
@ -116,6 +117,7 @@ export function createFetchMoreReferencesHandler(
|
|||
if (attribute.data.entityType === AttributeEntityTypeEnum.PAGE) {
|
||||
return fetchMoreReferencePages;
|
||||
} else if (
|
||||
attribute.data?.entityType &&
|
||||
[
|
||||
AttributeEntityTypeEnum.PRODUCT,
|
||||
AttributeEntityTypeEnum.PRODUCT_VARIANT,
|
||||
|
@ -145,7 +147,7 @@ export function createAttributeFileChangeHandler(
|
|||
addAttributeNewFileValue({
|
||||
data: null,
|
||||
id: attributeId,
|
||||
label: null,
|
||||
label: "",
|
||||
value,
|
||||
});
|
||||
}
|
||||
|
@ -167,8 +169,8 @@ export function createAttributeValueReorderHandler(
|
|||
);
|
||||
|
||||
const reorderedValues = move(
|
||||
attribute.value[reorder.oldIndex],
|
||||
attribute.value,
|
||||
attribute?.value?.[reorder.oldIndex] ?? "",
|
||||
attribute?.value ?? [],
|
||||
(a, b) => a === b,
|
||||
reorder.newIndex,
|
||||
);
|
||||
|
@ -194,7 +196,7 @@ function getFileInput(
|
|||
}
|
||||
return {
|
||||
file: attribute.data.selectedValues?.[0]?.file?.url,
|
||||
contentType: attribute.data.selectedValues?.[0]?.file.contentType,
|
||||
contentType: attribute.data.selectedValues?.[0]?.file?.contentType,
|
||||
id: attribute.id,
|
||||
};
|
||||
}
|
||||
|
@ -318,7 +320,9 @@ export const handleDeleteMultipleAttributeValues = async (
|
|||
attributes: Array<
|
||||
| PageSelectedAttributeFragment
|
||||
| ProductFragment["attributes"][0]
|
||||
| ProductVariantDetailsQuery["productVariant"]["nonSelectionAttributes"][0]
|
||||
| NonNullable<
|
||||
ProductVariantDetailsQuery["productVariant"]
|
||||
>["nonSelectionAttributes"][0]
|
||||
>,
|
||||
deleteAttributeValue: (
|
||||
variables: AttributeValueDeleteMutationVariables,
|
||||
|
|
|
@ -86,7 +86,7 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ params }) => {
|
|||
|
||||
const [attributeCreate, attributeCreateOpts] = useAttributeCreateMutation({
|
||||
onCompleted: data => {
|
||||
if (data.attributeCreate.errors.length === 0) {
|
||||
if (data?.attributeCreate?.errors.length === 0) {
|
||||
notify({
|
||||
status: "success",
|
||||
text: intl.formatMessage({
|
||||
|
@ -94,7 +94,7 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ params }) => {
|
|||
defaultMessage: "Successfully created attribute",
|
||||
}),
|
||||
});
|
||||
navigate(attributeUrl(data.attributeCreate.attribute.id));
|
||||
navigate(attributeUrl(data?.attributeCreate?.attribute?.id ?? ""));
|
||||
}
|
||||
},
|
||||
});
|
||||
|
@ -113,8 +113,10 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ params }) => {
|
|||
React.useEffect(() => setValueErrors([]), [params.action]);
|
||||
|
||||
const handleValueDelete = () => {
|
||||
const newValues = remove(values[id], values, areValuesEqual);
|
||||
setValues(newValues);
|
||||
if (id) {
|
||||
const newValues = remove(values[id], values, areValuesEqual);
|
||||
setValues(newValues);
|
||||
}
|
||||
closeModal();
|
||||
};
|
||||
|
||||
|
@ -122,7 +124,9 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ params }) => {
|
|||
if (isSelected(input, values, areValuesEqual)) {
|
||||
setValueErrors([attributeValueAlreadyExistsError]);
|
||||
} else {
|
||||
setValues(updateAtIndex(input, values, id));
|
||||
if (id) {
|
||||
setValues(updateAtIndex(input, values, id));
|
||||
}
|
||||
closeModal();
|
||||
}
|
||||
};
|
||||
|
@ -164,7 +168,7 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ params }) => {
|
|||
});
|
||||
|
||||
return {
|
||||
id: result.data.attributeCreate?.attribute?.id || null,
|
||||
id: result.data?.attributeCreate?.attribute?.id ?? undefined,
|
||||
errors: getMutationErrors(result),
|
||||
};
|
||||
};
|
||||
|
@ -179,8 +183,8 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ params }) => {
|
|||
<AttributePage
|
||||
attribute={null}
|
||||
disabled={attributeCreateOpts.loading}
|
||||
errors={attributeCreateOpts.data?.attributeCreate.errors || []}
|
||||
onDelete={undefined}
|
||||
errors={attributeCreateOpts?.data?.attributeCreate?.errors || []}
|
||||
onDelete={() => undefined}
|
||||
onSubmit={handleSubmit}
|
||||
onValueAdd={() => openModal("add-value")}
|
||||
onValueDelete={id =>
|
||||
|
@ -212,7 +216,7 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ params }) => {
|
|||
file: value?.fileUrl
|
||||
? {
|
||||
url: value.fileUrl,
|
||||
contentType: value.contentType,
|
||||
contentType: value.contentType ?? "",
|
||||
__typename: "File",
|
||||
}
|
||||
: null,
|
||||
|
@ -251,16 +255,16 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ params }) => {
|
|||
{values.length > 0 && (
|
||||
<>
|
||||
<AttributeValueDeleteDialog
|
||||
attributeName={undefined}
|
||||
attributeName=""
|
||||
open={params.action === "remove-value"}
|
||||
name={getStringOrPlaceholder(values[id]?.name)}
|
||||
name={getStringOrPlaceholder(id ? values[id]?.name : "")}
|
||||
confirmButtonState="default"
|
||||
onClose={closeModal}
|
||||
onConfirm={handleValueDelete}
|
||||
/>
|
||||
<AttributeValueEditDialog
|
||||
inputType={data.inputType}
|
||||
attributeValue={values[id]}
|
||||
attributeValue={id ? values[id] : null}
|
||||
confirmButtonState="default"
|
||||
disabled={false}
|
||||
errors={valueErrors}
|
||||
|
|
|
@ -91,7 +91,7 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => {
|
|||
|
||||
const [attributeDelete, attributeDeleteOpts] = useAttributeDeleteMutation({
|
||||
onCompleted: data => {
|
||||
if (data?.attributeDelete.errors.length === 0) {
|
||||
if (data?.attributeDelete?.errors.length === 0) {
|
||||
notify({
|
||||
status: "success",
|
||||
text: intl.formatMessage({
|
||||
|
@ -109,7 +109,7 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => {
|
|||
attributeValueDeleteOpts,
|
||||
] = useAttributeValueDeleteMutation({
|
||||
onCompleted: data => {
|
||||
if (data?.attributeValueDelete.errors.length === 0) {
|
||||
if (data?.attributeValueDelete?.errors.length === 0) {
|
||||
notify({
|
||||
status: "success",
|
||||
text: intl.formatMessage({
|
||||
|
@ -128,7 +128,7 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => {
|
|||
attributeValueUpdateOpts,
|
||||
] = useAttributeValueUpdateMutation({
|
||||
onCompleted: data => {
|
||||
if (data?.attributeValueUpdate.errors.length === 0) {
|
||||
if (data?.attributeValueUpdate?.errors.length === 0) {
|
||||
notifySaved();
|
||||
closeModal();
|
||||
}
|
||||
|
@ -137,7 +137,7 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => {
|
|||
|
||||
const [attributeUpdate, attributeUpdateOpts] = useAttributeUpdateMutation({
|
||||
onCompleted: data => {
|
||||
if (data?.attributeUpdate.errors.length === 0) {
|
||||
if (data?.attributeUpdate?.errors.length === 0) {
|
||||
notifySaved();
|
||||
}
|
||||
},
|
||||
|
@ -148,7 +148,7 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => {
|
|||
attributeValueCreateOpts,
|
||||
] = useAttributeValueCreateMutation({
|
||||
onCompleted: data => {
|
||||
if (data?.attributeValueCreate.errors.length === 0) {
|
||||
if (data?.attributeValueCreate?.errors.length === 0) {
|
||||
notify({
|
||||
status: "success",
|
||||
text: intl.formatMessage({
|
||||
|
@ -164,11 +164,11 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => {
|
|||
|
||||
const [attributeValueReorder] = useAttributeValueReorderMutation({
|
||||
onCompleted: data => {
|
||||
if (data?.attributeReorderValues.errors.length !== 0) {
|
||||
if (data?.attributeReorderValues?.errors.length !== 0) {
|
||||
notify({
|
||||
status: "error",
|
||||
text: getAttributeErrorMessage(
|
||||
data?.attributeReorderValues.errors[0],
|
||||
data?.attributeReorderValues?.errors[0],
|
||||
intl,
|
||||
),
|
||||
});
|
||||
|
@ -185,16 +185,16 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => {
|
|||
attributeReorderValues: {
|
||||
__typename: "AttributeReorderValues",
|
||||
attribute: {
|
||||
...data?.attribute,
|
||||
...data?.attribute!,
|
||||
choices: {
|
||||
__typename: "AttributeValueCountableConnection",
|
||||
pageInfo: {
|
||||
...data?.attribute.choices.pageInfo,
|
||||
...data?.attribute?.choices?.pageInfo!,
|
||||
},
|
||||
edges: move(
|
||||
data?.attribute.choices.edges[oldIndex],
|
||||
data?.attribute.choices.edges,
|
||||
(a, b) => a.node.id === b.node.id,
|
||||
data?.attribute?.choices?.edges[oldIndex]!,
|
||||
data?.attribute?.choices?.edges ?? [],
|
||||
(a, b) => a?.node.id === b?.node.id,
|
||||
newIndex,
|
||||
),
|
||||
},
|
||||
|
@ -205,7 +205,7 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => {
|
|||
variables: {
|
||||
id,
|
||||
move: {
|
||||
id: data?.attribute.choices.edges[oldIndex].node.id,
|
||||
id: data?.attribute?.choices?.edges[oldIndex].node.id ?? "",
|
||||
sortOrder: newIndex - oldIndex,
|
||||
},
|
||||
firstValues: valuesPaginationState.first,
|
||||
|
@ -237,7 +237,7 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => {
|
|||
);
|
||||
|
||||
const handleSubmit = createMetadataUpdateHandler(
|
||||
data?.attribute,
|
||||
data?.attribute!,
|
||||
handleUpdate,
|
||||
variables => updateMetadata({ variables }),
|
||||
variables => updatePrivateMetadata({ variables }),
|
||||
|
@ -247,7 +247,7 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => {
|
|||
<AttributePage
|
||||
attribute={data?.attribute}
|
||||
disabled={loading}
|
||||
errors={attributeUpdateOpts.data?.attributeUpdate.errors || []}
|
||||
errors={attributeUpdateOpts.data?.attributeUpdate?.errors || []}
|
||||
onDelete={() => openModal("remove")}
|
||||
onSubmit={handleSubmit}
|
||||
onValueAdd={() => openModal("add-value")}
|
||||
|
@ -266,7 +266,7 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => {
|
|||
values={data?.attribute?.choices}
|
||||
settings={settings}
|
||||
onUpdateListSettings={updateListSettings}
|
||||
pageInfo={pageInfo}
|
||||
pageInfo={pageInfo ?? { hasNextPage: false, hasPreviousPage: false }}
|
||||
onNextPage={loadNextPage}
|
||||
onPreviousPage={loadPreviousPage}
|
||||
>
|
||||
|
@ -291,7 +291,7 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => {
|
|||
name={getStringOrPlaceholder(
|
||||
data?.attribute?.choices?.edges?.find(
|
||||
value => params.id === value.node.id,
|
||||
)?.node.name,
|
||||
)?.node?.name ?? "",
|
||||
)}
|
||||
useName={true}
|
||||
confirmButtonState={attributeValueDeleteOpts.status}
|
||||
|
@ -299,7 +299,7 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => {
|
|||
onConfirm={() =>
|
||||
attributeValueDelete({
|
||||
variables: {
|
||||
id: params.id,
|
||||
id: params?.id ?? "",
|
||||
firstValues: valuesPaginationState.first,
|
||||
lastValues: valuesPaginationState.last,
|
||||
afterValues: valuesPaginationState.after,
|
||||
|
@ -314,7 +314,7 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => {
|
|||
confirmButtonState={attributeValueCreateOpts.status}
|
||||
disabled={loading}
|
||||
errors={
|
||||
attributeValueCreateOpts.data?.attributeValueCreate.errors || []
|
||||
attributeValueCreateOpts.data?.attributeValueCreate?.errors || []
|
||||
}
|
||||
open={params.action === "add-value"}
|
||||
onClose={closeModal}
|
||||
|
@ -336,21 +336,22 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => {
|
|||
attributeValue={attributeValueFragmentToFormData(
|
||||
data?.attribute?.choices?.edges?.find(
|
||||
value => params.id === value.node.id,
|
||||
)?.node,
|
||||
)?.node ?? null,
|
||||
)}
|
||||
confirmButtonState={attributeValueUpdateOpts.status}
|
||||
disabled={loading}
|
||||
errors={
|
||||
attributeValueUpdateOpts.data?.attributeValueUpdate.errors || []
|
||||
attributeValueUpdateOpts.data?.attributeValueUpdate?.errors || []
|
||||
}
|
||||
open={params.action === "edit-value"}
|
||||
onClose={closeModal}
|
||||
onSubmit={input =>
|
||||
attributeValueUpdate({
|
||||
variables: {
|
||||
id: data?.attribute.choices.edges.find(
|
||||
value => params.id === value.node.id,
|
||||
).node.id,
|
||||
id:
|
||||
data?.attribute?.choices?.edges?.find(
|
||||
value => params.id === value.node.id,
|
||||
)?.node?.id || "",
|
||||
input,
|
||||
firstValues: valuesPaginationState.first,
|
||||
lastValues: valuesPaginationState.last,
|
||||
|
|
|
@ -73,7 +73,7 @@ const AttributeList: React.FC<AttributeListProps> = ({ params }) => {
|
|||
attributeBulkDeleteOpts,
|
||||
] = useAttributeBulkDeleteMutation({
|
||||
onCompleted: data => {
|
||||
if (data.attributeBulkDelete.errors.length === 0) {
|
||||
if (data.attributeBulkDelete?.errors.length === 0) {
|
||||
closeModal();
|
||||
notify({
|
||||
status: "success",
|
||||
|
@ -132,7 +132,7 @@ const AttributeList: React.FC<AttributeListProps> = ({ params }) => {
|
|||
};
|
||||
|
||||
const paginationValues = usePaginator({
|
||||
pageInfo: maybe(() => data.attributes.pageInfo),
|
||||
pageInfo: data?.attributes?.pageInfo,
|
||||
paginationState,
|
||||
queryString: params,
|
||||
});
|
||||
|
@ -142,7 +142,7 @@ const AttributeList: React.FC<AttributeListProps> = ({ params }) => {
|
|||
return (
|
||||
<PaginatorContext.Provider value={paginationValues}>
|
||||
<AttributeListPage
|
||||
attributes={mapEdgesToItems(data?.attributes)}
|
||||
attributes={mapEdgesToItems(data?.attributes) ?? []}
|
||||
currentTab={currentTab}
|
||||
disabled={loading || attributeBulkDeleteOpts.loading}
|
||||
filterOpts={getFilterOpts(params)}
|
||||
|
@ -176,12 +176,14 @@ const AttributeList: React.FC<AttributeListProps> = ({ params }) => {
|
|||
/>
|
||||
<AttributeBulkDeleteDialog
|
||||
confirmButtonState={attributeBulkDeleteOpts.status}
|
||||
open={params.action === "remove" && maybe(() => params.ids.length > 0)}
|
||||
open={
|
||||
params.action === "remove" && !!params.ids && params.ids.length > 0
|
||||
}
|
||||
onConfirm={() =>
|
||||
attributeBulkDelete({ variables: { ids: params.ids } })
|
||||
attributeBulkDelete({ variables: { ids: params?.ids ?? [] } })
|
||||
}
|
||||
onClose={closeModal}
|
||||
quantity={maybe(() => params.ids.length)}
|
||||
quantity={params.ids?.length ?? 0}
|
||||
/>
|
||||
<SaveFilterTabDialog
|
||||
open={params.action === "save-search"}
|
||||
|
|
|
@ -4,7 +4,7 @@ import {
|
|||
} from "@dashboard/attributes/components/AttributeListPage";
|
||||
import { FilterElement } from "@dashboard/components/Filter";
|
||||
import { AttributeFilterInput } from "@dashboard/graphql";
|
||||
import { maybe, parseBoolean } from "@dashboard/misc";
|
||||
import { parseBoolean } from "@dashboard/misc";
|
||||
|
||||
import {
|
||||
createFilterTabUtils,
|
||||
|
@ -25,19 +25,19 @@ export function getFilterOpts(
|
|||
return {
|
||||
filterableInStorefront: {
|
||||
active: params.filterableInStorefront !== undefined,
|
||||
value: maybe(() => parseBoolean(params.filterableInStorefront, true)),
|
||||
value: parseBoolean(params.filterableInStorefront, true),
|
||||
},
|
||||
isVariantOnly: {
|
||||
active: params.isVariantOnly !== undefined,
|
||||
value: maybe(() => parseBoolean(params.isVariantOnly, true)),
|
||||
value: parseBoolean(params.isVariantOnly, true),
|
||||
},
|
||||
valueRequired: {
|
||||
active: params.valueRequired !== undefined,
|
||||
value: maybe(() => parseBoolean(params.valueRequired, true)),
|
||||
value: parseBoolean(params.valueRequired, true),
|
||||
},
|
||||
visibleInStorefront: {
|
||||
active: params.visibleInStorefront !== undefined,
|
||||
value: maybe(() => parseBoolean(params.visibleInStorefront, true)),
|
||||
value: parseBoolean(params.visibleInStorefront, true),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ export function getSortQueryField(
|
|||
case AttributeListUrlSortField.visible:
|
||||
return AttributeSortField.VISIBLE_IN_STOREFRONT;
|
||||
default:
|
||||
return undefined;
|
||||
return AttributeSortField.NAME;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -431,7 +431,10 @@ export function findValueInEnum<TEnum extends {}>(
|
|||
return needle as unknown as TEnum[keyof TEnum];
|
||||
}
|
||||
|
||||
export function parseBoolean(a: string, defaultValue: boolean): boolean {
|
||||
export function parseBoolean(
|
||||
a: string | undefined,
|
||||
defaultValue: boolean,
|
||||
): boolean {
|
||||
if (a === undefined) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue