2021-01-12 11:13:02 +00:00
|
|
|
import {
|
|
|
|
AttributeInput,
|
|
|
|
AttributeInputData
|
|
|
|
} from "@saleor/components/Attributes";
|
2020-12-16 10:53:28 +00:00
|
|
|
import { FileUpload } from "@saleor/files/types/FileUpload";
|
|
|
|
import { AttributeErrorFragment } from "@saleor/fragments/types/AttributeErrorFragment";
|
|
|
|
import { SelectedVariantAttributeFragment } from "@saleor/fragments/types/SelectedVariantAttributeFragment";
|
|
|
|
import { UploadErrorFragment } from "@saleor/fragments/types/UploadErrorFragment";
|
|
|
|
import { FormsetData } from "@saleor/hooks/useFormset";
|
|
|
|
import { PageDetails_page_attributes } from "@saleor/pages/types/PageDetails";
|
2021-01-13 12:11:01 +00:00
|
|
|
import { ProductDetails_product_attributes } from "@saleor/products/types/ProductDetails";
|
2021-01-12 11:13:02 +00:00
|
|
|
import { SearchPages_search_edges_node } from "@saleor/searches/types/SearchPages";
|
2021-01-20 16:37:36 +00:00
|
|
|
import { SearchProducts_search_edges_node } from "@saleor/searches/types/SearchProducts";
|
2020-12-16 10:53:28 +00:00
|
|
|
import {
|
2021-01-20 16:37:36 +00:00
|
|
|
AttributeEntityTypeEnum,
|
2020-12-16 10:53:28 +00:00
|
|
|
AttributeInputTypeEnum,
|
|
|
|
AttributeValueInput
|
|
|
|
} from "@saleor/types/globalTypes";
|
2021-01-20 16:37:36 +00:00
|
|
|
import { mapNodeToChoice, mapPagesToChoices } from "@saleor/utils/maps";
|
2020-12-16 10:53:28 +00:00
|
|
|
import { MutationFetchResult } from "react-apollo";
|
|
|
|
|
2021-01-12 11:11:15 +00:00
|
|
|
import { AttributePageFormData } from "../components/AttributePage";
|
|
|
|
import { AttributeValueEditDialogFormData } from "../components/AttributeValueEditDialog";
|
2020-12-16 10:53:28 +00:00
|
|
|
import { AttributeValueDelete } from "../types/AttributeValueDelete";
|
|
|
|
|
2021-01-12 11:11:15 +00:00
|
|
|
export const ATTRIBUTE_TYPES_WITH_DEDICATED_VALUES = [
|
|
|
|
AttributeInputTypeEnum.DROPDOWN,
|
|
|
|
AttributeInputTypeEnum.MULTISELECT
|
|
|
|
];
|
|
|
|
|
2021-01-20 16:37:36 +00:00
|
|
|
export interface AttributeReference {
|
|
|
|
label: string;
|
|
|
|
value: string;
|
|
|
|
}
|
|
|
|
|
2021-01-12 11:11:15 +00:00
|
|
|
function getSimpleAttributeData(
|
|
|
|
data: AttributePageFormData,
|
|
|
|
values: AttributeValueEditDialogFormData[]
|
|
|
|
) {
|
|
|
|
return {
|
|
|
|
...data,
|
|
|
|
metadata: undefined,
|
|
|
|
privateMetadata: undefined,
|
|
|
|
storefrontSearchPosition: parseInt(data.storefrontSearchPosition, 10),
|
|
|
|
values: values.map(value => ({
|
|
|
|
name: value.name
|
|
|
|
}))
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
function getFileOrReferenceAttributeData(
|
|
|
|
data: AttributePageFormData,
|
|
|
|
values: AttributeValueEditDialogFormData[]
|
|
|
|
) {
|
|
|
|
return {
|
|
|
|
...getSimpleAttributeData(data, values),
|
|
|
|
availableInGrid: undefined,
|
|
|
|
filterableInDashboard: undefined,
|
|
|
|
filterableInStorefront: undefined
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
export function getAttributeData(
|
|
|
|
data: AttributePageFormData,
|
|
|
|
values: AttributeValueEditDialogFormData[]
|
|
|
|
) {
|
|
|
|
if (ATTRIBUTE_TYPES_WITH_DEDICATED_VALUES.includes(data.inputType)) {
|
|
|
|
return getSimpleAttributeData(data, values);
|
|
|
|
} else {
|
|
|
|
return getFileOrReferenceAttributeData(data, values);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-13 12:11:01 +00:00
|
|
|
export function getSelectedAttributeValues(
|
|
|
|
attribute:
|
|
|
|
| PageDetails_page_attributes
|
|
|
|
| ProductDetails_product_attributes
|
|
|
|
| SelectedVariantAttributeFragment
|
|
|
|
) {
|
|
|
|
if (attribute.attribute.inputType === AttributeInputTypeEnum.REFERENCE) {
|
|
|
|
return attribute.values.map(value => value.reference);
|
|
|
|
}
|
2021-04-23 12:27:31 +00:00
|
|
|
if (attribute.attribute.inputType === AttributeInputTypeEnum.RICH_TEXT) {
|
|
|
|
return [attribute.values[0]?.richText];
|
|
|
|
}
|
2021-01-13 12:11:01 +00:00
|
|
|
return attribute.values.map(value => value.slug);
|
|
|
|
}
|
|
|
|
|
2020-12-16 10:53:28 +00:00
|
|
|
export const isFileValueUnused = (
|
|
|
|
attributesWithNewFileValue: FormsetData<null, File>,
|
|
|
|
existingAttribute:
|
|
|
|
| PageDetails_page_attributes
|
|
|
|
| SelectedVariantAttributeFragment
|
|
|
|
) => {
|
|
|
|
if (existingAttribute.attribute.inputType !== AttributeInputTypeEnum.FILE) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (existingAttribute.values.length === 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
const modifiedAttribute = attributesWithNewFileValue.find(
|
|
|
|
dataAttribute => dataAttribute.id === existingAttribute.attribute.id
|
|
|
|
);
|
|
|
|
|
|
|
|
return !!modifiedAttribute;
|
|
|
|
};
|
|
|
|
|
|
|
|
export const mergeFileUploadErrors = (
|
|
|
|
uploadFilesResult: Array<MutationFetchResult<FileUpload>>
|
|
|
|
): UploadErrorFragment[] =>
|
|
|
|
uploadFilesResult.reduce((errors, uploadFileResult) => {
|
2021-04-26 07:49:55 +00:00
|
|
|
const uploadErrors = uploadFileResult?.data?.fileUpload?.errors;
|
2020-12-16 10:53:28 +00:00
|
|
|
if (uploadErrors) {
|
|
|
|
return [...errors, ...uploadErrors];
|
|
|
|
}
|
|
|
|
return errors;
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
export const mergeAttributeValueDeleteErrors = (
|
|
|
|
deleteAttributeValuesResult: Array<MutationFetchResult<AttributeValueDelete>>
|
|
|
|
): AttributeErrorFragment[] =>
|
|
|
|
deleteAttributeValuesResult.reduce((errors, deleteValueResult) => {
|
|
|
|
const deleteErrors = deleteValueResult?.data?.attributeValueDelete?.errors;
|
|
|
|
if (deleteErrors) {
|
|
|
|
return [...errors, ...deleteErrors];
|
|
|
|
}
|
|
|
|
return errors;
|
|
|
|
}, []);
|
|
|
|
|
2021-01-12 11:13:02 +00:00
|
|
|
export const mergeAttributeValues = (
|
|
|
|
attributeId: string,
|
|
|
|
attributeValues: string[],
|
|
|
|
attributes: FormsetData<AttributeInputData, string[]>
|
|
|
|
) => {
|
|
|
|
const attribute = attributes.find(attribute => attribute.id === attributeId);
|
|
|
|
|
|
|
|
return attribute.value
|
|
|
|
? [...attribute.value, ...attributeValues]
|
|
|
|
: attributeValues;
|
|
|
|
};
|
|
|
|
|
2020-12-16 10:53:28 +00:00
|
|
|
export const getFileValuesToUploadFromAttributes = (
|
|
|
|
attributesWithNewFileValue: FormsetData<null, File>
|
|
|
|
) => attributesWithNewFileValue.filter(fileAttribute => !!fileAttribute.value);
|
|
|
|
|
|
|
|
export const getFileValuesRemovedFromAttributes = (
|
|
|
|
attributesWithNewFileValue: FormsetData<null, File>
|
|
|
|
) => attributesWithNewFileValue.filter(attribute => !attribute.value);
|
|
|
|
|
|
|
|
export const getAttributesOfRemovedFiles = (
|
|
|
|
fileAttributesRemoved: FormsetData<null, File>
|
|
|
|
) =>
|
|
|
|
fileAttributesRemoved.map(attribute => ({
|
|
|
|
file: undefined,
|
|
|
|
id: attribute.id,
|
|
|
|
values: []
|
|
|
|
}));
|
|
|
|
|
|
|
|
export const getAttributesOfUploadedFiles = (
|
|
|
|
fileValuesToUpload: FormsetData<null, File>,
|
|
|
|
uploadFilesResult: Array<MutationFetchResult<FileUpload>>
|
|
|
|
) =>
|
|
|
|
uploadFilesResult.map((uploadFileResult, index) => {
|
|
|
|
const attribute = fileValuesToUpload[index];
|
|
|
|
|
|
|
|
return {
|
|
|
|
file: uploadFileResult.data.fileUpload.uploadedFile.url,
|
|
|
|
id: attribute.id,
|
|
|
|
values: []
|
|
|
|
};
|
|
|
|
});
|
|
|
|
|
|
|
|
export const getAttributesAfterFileAttributesUpdate = (
|
|
|
|
attributesWithNewFileValue: FormsetData<null, File>,
|
|
|
|
uploadFilesResult: Array<MutationFetchResult<FileUpload>>
|
|
|
|
): AttributeValueInput[] => {
|
|
|
|
const removedFileValues = getFileValuesRemovedFromAttributes(
|
|
|
|
attributesWithNewFileValue
|
|
|
|
);
|
|
|
|
const fileValuesToUpload = getFileValuesToUploadFromAttributes(
|
|
|
|
attributesWithNewFileValue
|
|
|
|
);
|
|
|
|
|
|
|
|
const removedFileAttributes = getAttributesOfRemovedFiles(removedFileValues);
|
|
|
|
const uploadedFileAttributes = getAttributesOfUploadedFiles(
|
|
|
|
fileValuesToUpload,
|
|
|
|
uploadFilesResult
|
|
|
|
);
|
|
|
|
|
|
|
|
return uploadedFileAttributes.concat(removedFileAttributes);
|
|
|
|
};
|
2021-01-12 11:13:02 +00:00
|
|
|
|
|
|
|
export const getFileAttributeDisplayData = (
|
|
|
|
attribute: AttributeInput,
|
|
|
|
attributesWithNewFileValue: FormsetData<null, File>
|
|
|
|
) => {
|
|
|
|
const attributeWithNewFileValue = attributesWithNewFileValue.find(
|
|
|
|
attributeWithNewFile => attribute.id === attributeWithNewFile.id
|
|
|
|
);
|
|
|
|
|
|
|
|
if (attributeWithNewFileValue) {
|
|
|
|
return {
|
|
|
|
...attribute,
|
|
|
|
value: attributeWithNewFileValue?.value?.name
|
|
|
|
? [attributeWithNewFileValue.value.name]
|
|
|
|
: []
|
|
|
|
};
|
|
|
|
}
|
|
|
|
return attribute;
|
|
|
|
};
|
|
|
|
|
2021-01-20 16:37:36 +00:00
|
|
|
export const getPageReferenceAttributeDisplayData = (
|
2021-01-12 11:13:02 +00:00
|
|
|
attribute: AttributeInput,
|
|
|
|
referencePages: SearchPages_search_edges_node[]
|
|
|
|
) => ({
|
|
|
|
...attribute,
|
|
|
|
data: {
|
|
|
|
...attribute.data,
|
|
|
|
references:
|
2021-01-13 12:11:01 +00:00
|
|
|
referencePages?.length > 0 && attribute.value?.length > 0
|
2021-01-20 16:37:36 +00:00
|
|
|
? mapPagesToChoices(
|
|
|
|
attribute.value.map(value => {
|
|
|
|
const reference = referencePages.find(
|
|
|
|
reference => reference.id === value
|
|
|
|
);
|
|
|
|
return { ...reference };
|
|
|
|
})
|
2021-01-13 12:11:01 +00:00
|
|
|
)
|
|
|
|
: []
|
2021-01-12 11:13:02 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2021-01-20 16:37:36 +00:00
|
|
|
export const getProductReferenceAttributeDisplayData = (
|
|
|
|
attribute: AttributeInput,
|
|
|
|
referenceProducts: SearchProducts_search_edges_node[]
|
|
|
|
) => ({
|
|
|
|
...attribute,
|
|
|
|
data: {
|
|
|
|
...attribute.data,
|
|
|
|
references:
|
|
|
|
referenceProducts?.length > 0 && attribute.value?.length > 0
|
|
|
|
? mapNodeToChoice(
|
|
|
|
attribute.value.map(value => {
|
|
|
|
const reference = referenceProducts.find(
|
|
|
|
reference => reference.id === value
|
|
|
|
);
|
|
|
|
return { ...reference };
|
|
|
|
})
|
|
|
|
)
|
|
|
|
: []
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
export const getReferenceAttributeDisplayData = (
|
|
|
|
attribute: AttributeInput,
|
|
|
|
referencePages: SearchPages_search_edges_node[],
|
|
|
|
referenceProducts: SearchProducts_search_edges_node[]
|
|
|
|
) => {
|
|
|
|
if (attribute.data.entityType === AttributeEntityTypeEnum.PAGE) {
|
|
|
|
return getPageReferenceAttributeDisplayData(attribute, referencePages);
|
|
|
|
} else if (attribute.data.entityType === AttributeEntityTypeEnum.PRODUCT) {
|
|
|
|
return getProductReferenceAttributeDisplayData(
|
|
|
|
attribute,
|
|
|
|
referenceProducts
|
|
|
|
);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-01-12 11:13:02 +00:00
|
|
|
export const getAttributesDisplayData = (
|
|
|
|
attributes: AttributeInput[],
|
|
|
|
attributesWithNewFileValue: FormsetData<null, File>,
|
2021-01-20 16:37:36 +00:00
|
|
|
referencePages: SearchPages_search_edges_node[],
|
|
|
|
referenceProducts: SearchProducts_search_edges_node[]
|
2021-01-12 11:13:02 +00:00
|
|
|
) =>
|
|
|
|
attributes.map(attribute => {
|
|
|
|
if (attribute.data.inputType === AttributeInputTypeEnum.REFERENCE) {
|
2021-01-20 16:37:36 +00:00
|
|
|
return getReferenceAttributeDisplayData(
|
|
|
|
attribute,
|
|
|
|
referencePages,
|
|
|
|
referenceProducts
|
|
|
|
);
|
2021-01-12 11:13:02 +00:00
|
|
|
}
|
|
|
|
if (attribute.data.inputType === AttributeInputTypeEnum.FILE) {
|
|
|
|
return getFileAttributeDisplayData(attribute, attributesWithNewFileValue);
|
|
|
|
}
|
|
|
|
return attribute;
|
|
|
|
});
|
2021-01-20 16:37:36 +00:00
|
|
|
|
|
|
|
export const getSelectedReferencesFromAttribute = <
|
|
|
|
Node extends SearchPages_search_edges_node | SearchProducts_search_edges_node
|
|
|
|
>(
|
|
|
|
attribute?: AttributeInput,
|
|
|
|
references?: Node[]
|
|
|
|
) =>
|
|
|
|
references?.filter(
|
|
|
|
value =>
|
|
|
|
!attribute?.value?.some(selectedValue => selectedValue === value.id)
|
|
|
|
) || [];
|
|
|
|
|
|
|
|
export const getAttributeValuesFromReferences = (
|
|
|
|
attributeId: string,
|
|
|
|
attributes?: AttributeInput[],
|
|
|
|
referencePages?: SearchPages_search_edges_node[],
|
|
|
|
referenceProducts?: SearchProducts_search_edges_node[]
|
|
|
|
) => {
|
|
|
|
const attribute = attributes?.find(attribute => attribute.id === attributeId);
|
|
|
|
|
|
|
|
if (attribute?.data?.entityType === AttributeEntityTypeEnum.PAGE) {
|
|
|
|
return mapPagesToChoices(
|
|
|
|
getSelectedReferencesFromAttribute(attribute, referencePages)
|
|
|
|
);
|
|
|
|
} else if (attribute?.data?.entityType === AttributeEntityTypeEnum.PRODUCT) {
|
|
|
|
return mapNodeToChoice(
|
|
|
|
getSelectedReferencesFromAttribute(attribute, referenceProducts)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
return [];
|
|
|
|
};
|