saleor-dashboard/src/attributes/utils/handlers.ts
2022-04-15 16:33:01 +02:00

306 lines
8.1 KiB
TypeScript

import { FetchResult } from "@apollo/client";
import {
AttributeInput,
AttributeInputData
} from "@saleor/components/Attributes";
import {
AttributeEntityTypeEnum,
AttributeInputTypeEnum,
AttributeValueDeleteMutation,
AttributeValueDeleteMutationVariables,
AttributeValueInput,
FileUploadMutation,
FileUploadMutationVariables,
PageSelectedAttributeFragment,
ProductFragment,
ProductVariantDetailsQuery
} from "@saleor/graphql";
import {
FormsetAtomicData,
FormsetChange,
FormsetData
} from "@saleor/hooks/useFormset";
import { FetchMoreProps, ReorderEvent } from "@saleor/types";
import { move, toggle } from "@saleor/utils/lists";
import { getFileValuesToUploadFromAttributes, isFileValueUnused } from "./data";
export function createAttributeChangeHandler(
changeAttributeData: FormsetChange<string[]>,
triggerChange: () => void
): FormsetChange<string> {
return (attributeId: string, value: string) => {
triggerChange();
changeAttributeData(attributeId, value === "" ? [] : [value]);
};
}
export function createAttributeMultiChangeHandler(
changeAttributeData: FormsetChange<string[]>,
attributes: FormsetData<AttributeInputData, string[]>,
triggerChange: () => void
): FormsetChange<string> {
return (attributeId: string, value: string) => {
const attribute = attributes.find(
attribute => attribute.id === attributeId
);
const newAttributeValues = toggle(
value,
attribute.value,
(a, b) => a === b
);
triggerChange();
changeAttributeData(attributeId, newAttributeValues);
};
}
export function createAttributeReferenceChangeHandler(
changeAttributeData: FormsetChange<string[]>,
triggerChange: () => void
): FormsetChange<string[]> {
return (attributeId: string, values: string[]) => {
changeAttributeData(attributeId, values);
triggerChange();
};
}
export function createFetchReferencesHandler(
attributes: FormsetData<AttributeInputData, string[]>,
assignReferencesAttributeId: string,
fetchReferencePages?: (data: string) => void,
fetchReferenceProducts?: (data: string) => void
) {
return (value: string) => {
const attribute = attributes?.find(
attribute => attribute.id === assignReferencesAttributeId
);
if (!attribute) {
return;
}
if (
attribute.data.entityType === AttributeEntityTypeEnum.PAGE &&
fetchReferencePages
) {
fetchReferencePages(value);
} else if (
attribute.data.entityType === AttributeEntityTypeEnum.PRODUCT &&
fetchReferenceProducts
) {
fetchReferenceProducts(value);
}
};
}
export function createFetchMoreReferencesHandler(
attributes: FormsetData<AttributeInputData, string[]>,
assignReferencesAttributeId: string,
fetchMoreReferencePages?: FetchMoreProps,
fetchMoreReferenceProducts?: FetchMoreProps
) {
const attribute = attributes?.find(
attribute => attribute.id === assignReferencesAttributeId
);
if (!attribute) {
return;
}
if (attribute.data.entityType === AttributeEntityTypeEnum.PAGE) {
return fetchMoreReferencePages;
} else if (attribute.data.entityType === AttributeEntityTypeEnum.PRODUCT) {
return fetchMoreReferenceProducts;
}
}
export function createAttributeFileChangeHandler(
changeAttributeData: FormsetChange<string[]>,
attributesWithNewFileValue: FormsetData<FormsetData<null, File>>,
addAttributeNewFileValue: (data: FormsetAtomicData<null, File>) => void,
changeAttributeNewFileValue: FormsetChange<File>,
triggerChange: () => void
): FormsetChange<File> {
return (attributeId: string, value: File) => {
triggerChange();
const newFileValueAssigned = attributesWithNewFileValue.find(
attribute => attribute.id === attributeId
);
if (newFileValueAssigned) {
changeAttributeNewFileValue(attributeId, value);
} else {
addAttributeNewFileValue({
data: null,
id: attributeId,
label: null,
value
});
}
changeAttributeData(attributeId, value ? [value.name] : []);
};
}
export function createAttributeValueReorderHandler(
changeAttributeData: FormsetChange<string[]>,
attributes: FormsetData<AttributeInputData, string[]>,
triggerChange: () => void
): FormsetChange<ReorderEvent> {
return (attributeId: string, reorder: ReorderEvent) => {
triggerChange();
const attribute = attributes.find(
attribute => attribute.id === attributeId
);
const reorderedValues = move(
attribute.value[reorder.oldIndex],
attribute.value,
(a, b) => a === b,
reorder.newIndex
);
changeAttributeData(attributeId, reorderedValues);
};
}
interface AttributesArgs {
attributes: AttributeInput[];
updatedFileAttributes: AttributeValueInput[];
}
function getFileInput(
attribute: AttributeInput,
updatedFileAttributes: AttributeValueInput[]
) {
const updatedFileAttribute = updatedFileAttributes.find(
attributeWithNewFile => attribute.id === attributeWithNewFile.id
);
if (updatedFileAttribute) {
return {
file: updatedFileAttribute.file,
id: updatedFileAttribute.id,
contentType: updatedFileAttribute.contentType
};
}
return {
file: attribute.data.selectedValues?.[0]?.file?.url,
contentType: attribute.data.selectedValues?.[0]?.file.contentType,
id: attribute.id
};
}
function getBooleanInput(attribute: AttributeInput) {
return {
id: attribute.id,
boolean: JSON.parse(attribute.value[0] ?? "false")
};
}
export const prepareAttributesInput = ({
attributes,
updatedFileAttributes
}: AttributesArgs): AttributeValueInput[] =>
attributes.reduce((attrInput, attr) => {
const inputType = attr.data.inputType;
if (inputType === AttributeInputTypeEnum.FILE) {
const fileInput = getFileInput(attr, updatedFileAttributes);
if (fileInput.file) {
attrInput.push(fileInput);
}
return attrInput;
}
if (inputType === AttributeInputTypeEnum.BOOLEAN) {
const booleanInput = getBooleanInput(attr);
attrInput.push(booleanInput);
return attrInput;
}
if (inputType === AttributeInputTypeEnum.RICH_TEXT) {
attrInput.push({
id: attr.id,
richText: attr.value[0]
});
return attrInput;
}
// for cases other than rich text, boolean and file
// we can skip attribute
if (!attr.value[0]) {
return attrInput;
}
if (inputType === AttributeInputTypeEnum.REFERENCE) {
attrInput.push({
id: attr.id,
references: attr.value
});
return attrInput;
}
if (inputType === AttributeInputTypeEnum.DATE) {
attrInput.push({
id: attr.id,
date: attr.value[0]
});
return attrInput;
}
if (inputType === AttributeInputTypeEnum.DATE_TIME) {
attrInput.push({
id: attr.id,
dateTime: attr.value[0]
});
return attrInput;
}
attrInput.push({
id: attr.id,
values: attr.value
});
return attrInput;
}, []);
export const handleUploadMultipleFiles = async (
attributesWithNewFileValue: FormsetData<null, File>,
uploadFile: (
variables: FileUploadMutationVariables
) => Promise<FetchResult<FileUploadMutation>>
) =>
Promise.all(
getFileValuesToUploadFromAttributes(attributesWithNewFileValue).map(
fileAttribute =>
uploadFile({
file: fileAttribute.value
})
)
);
export const handleDeleteMultipleAttributeValues = async (
attributesWithNewFileValue: FormsetData<null, File>,
attributes: Array<
| PageSelectedAttributeFragment
| ProductFragment["attributes"][0]
| ProductVariantDetailsQuery["productVariant"]["nonSelectionAttributes"][0]
>,
deleteAttributeValue: (
variables: AttributeValueDeleteMutationVariables
) => Promise<FetchResult<AttributeValueDeleteMutation>>
) =>
Promise.all(
attributes.map(existingAttribute => {
const fileValueUnused = isFileValueUnused(
attributesWithNewFileValue,
existingAttribute
);
if (fileValueUnused) {
return deleteAttributeValue({
id: existingAttribute.values[0].id,
firstValues: 20
});
}
})
);