Variant attribute values pagination (#1133)

* Implement attribute values pagination in variant pages

* Implement attribute values pagination in variant creator

* Update variant creator design bugs

* Fix deleting attribute value error

* Refactor attribute value handling in variant creator

* Update after review

* Create local pagination state for attribute values

* Fix autocomplete select field scrolling on fetch more

* Change onAttributeSelect to onAttributeFocus

* Update cypress test function with attribute values pagination
This commit is contained in:
Dawid Tarasiuk 2021-06-08 08:58:36 +02:00
parent 988b191690
commit d342bdb63b
54 changed files with 1922 additions and 1144 deletions

View file

@ -10,7 +10,13 @@ export function createAttribute(name, attributeValues = ["value"]) {
attribute{
id
name
values{name}
choices(first: 100){
edges{
node{
name
}
}
}
}
attributeErrors{
field

View file

@ -5643,6 +5643,10 @@
"context": "variant name",
"string": "Variant"
},
"src_dot_products_dot_components_dot_ProductVariantCreatorPage_dot_multipleValueLabel": {
"context": "attribute values",
"string": "Values"
},
"src_dot_products_dot_components_dot_ProductVariantDeleteDialog_dot_1583616500": {
"context": "button",
"string": "Delete variant"

View file

@ -60,8 +60,7 @@ export type AttributeUrlDialog =
| "remove"
| "remove-value"
| "remove-values";
export type AttributeUrlQueryParams = Pagination &
BulkAction &
export type AttributeUrlQueryParams = BulkAction &
Dialog<AttributeUrlDialog> &
SingleAction;
export const attributePath = (id: string) => urlJoin(attributeSection, id);

View file

@ -1,9 +1,9 @@
import useListSettings from "@saleor/hooks/useListSettings";
import useLocalPaginator, {
useLocalPaginationState
} from "@saleor/hooks/useLocalPaginator";
import useNavigator from "@saleor/hooks/useNavigator";
import useNotifier from "@saleor/hooks/useNotifier";
import usePaginator, {
createPaginationState
} from "@saleor/hooks/usePaginator";
import { commonMessages } from "@saleor/intl";
import { maybe } from "@saleor/misc";
import { ListViews, ReorderEvent } from "@saleor/types";
@ -47,7 +47,6 @@ interface AttributeDetailsProps {
const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => {
const navigate = useNavigator();
const paginate = usePaginator();
const notify = useNotifier();
const intl = useIntl();
const [updateMetadata] = useMetadataUpdate({});
@ -62,20 +61,26 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => {
ListViews.ATTRIBUTE_VALUE_LIST
);
const [
valuesPaginationState,
setValuesPaginationState
] = useLocalPaginationState(settings?.rowNumber);
const { data, loading } = useAttributeDetailsQuery({
variables: {
id,
firstValues: settings?.rowNumber,
afterValues: params.after
firstValues: valuesPaginationState.first,
lastValues: valuesPaginationState.last,
afterValues: valuesPaginationState.after,
beforeValues: valuesPaginationState.before
},
skip: !settings
});
const paginationState = createPaginationState(settings?.rowNumber, params);
const { loadNextPage, loadPreviousPage, pageInfo } = paginate(
const paginateValues = useLocalPaginator(setValuesPaginationState);
const { loadNextPage, loadPreviousPage, pageInfo } = paginateValues(
data?.attribute?.choices?.pageInfo,
paginationState,
params
valuesPaginationState
);
const [attributeDelete, attributeDeleteOpts] = useAttributeDeleteMutation({
@ -197,8 +202,10 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => {
id: data.attribute.choices.edges[oldIndex].node.id,
sortOrder: newIndex - oldIndex
},
firstValues: settings.rowNumber,
afterValues: params.after
firstValues: valuesPaginationState.first,
lastValues: valuesPaginationState.last,
afterValues: valuesPaginationState.after,
beforeValues: valuesPaginationState.before
}
});
@ -288,8 +295,10 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => {
attributeValueDelete({
variables: {
id: params.id,
firstValues: settings.rowNumber,
afterValues: params.after
firstValues: valuesPaginationState.first,
lastValues: valuesPaginationState.last,
afterValues: valuesPaginationState.after,
beforeValues: valuesPaginationState.before
}
})
}
@ -308,8 +317,10 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => {
variables: {
id,
input,
firstValues: settings.rowNumber,
afterValues: params.after
firstValues: valuesPaginationState.first,
lastValues: valuesPaginationState.last,
afterValues: valuesPaginationState.after,
beforeValues: valuesPaginationState.before
}
})
}
@ -335,8 +346,10 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => {
value => params.id === value.node.id
).node.id,
input,
firstValues: settings.rowNumber,
afterValues: params.after
firstValues: valuesPaginationState.first,
lastValues: valuesPaginationState.last,
afterValues: valuesPaginationState.after,
beforeValues: valuesPaginationState.before
}
})
}

View file

@ -57,7 +57,7 @@ export interface AttributeRowHandlers {
onReferencesReorder: FormsetChange<ReorderEvent>;
fetchAttributeValues: (query: string) => void;
fetchMoreAttributeValues: FetchMoreProps;
onAttributeSelect: (id: string) => void;
onAttributeFocus: (id: string) => void;
}
interface AttributeRowProps extends AttributeRowHandlers {
@ -82,7 +82,7 @@ const AttributeRow: React.FC<AttributeRowProps> = ({
onChange,
fetchAttributeValues,
fetchMoreAttributeValues,
onAttributeSelect
onAttributeFocus
}) => {
const intl = useIntl();
const classes = useStyles({});
@ -149,7 +149,7 @@ const AttributeRow: React.FC<AttributeRowProps> = ({
allowCustomValues={true}
fetchChoices={fetchAttributeValues}
{...fetchMoreAttributeValues}
onClick={() => onAttributeSelect(attribute.id)}
onFocus={() => onAttributeFocus(attribute.id)}
/>
</BasicAttributeRow>
);
@ -211,7 +211,7 @@ const AttributeRow: React.FC<AttributeRowProps> = ({
allowCustomValues={true}
fetchChoices={fetchAttributeValues}
{...fetchMoreAttributeValues}
onClick={() => onAttributeSelect(attribute.id)}
onFocus={() => onAttributeFocus(attribute.id)}
/>
</BasicAttributeRow>
);

View file

@ -18,7 +18,7 @@ const props: AttributesProps = {
onReferencesAddClick: () => undefined,
onReferencesRemove: () => undefined,
onReferencesReorder: () => undefined,
onAttributeSelect: () => undefined,
onAttributeFocus: () => undefined,
fetchAttributeValues: () => undefined,
fetchMoreAttributeValues: fetchMoreProps
};

View file

@ -44,7 +44,7 @@ export interface AttributesProps extends AttributeRowHandlers {
ProductErrorWithAttributesFragment | PageErrorWithAttributesFragment
>;
title?: React.ReactNode;
onAttributeSelect: (id: string) => void;
onAttributeFocus: (id: string) => void;
}
const useStyles = makeStyles(

View file

@ -85,7 +85,7 @@ export interface MultiAutocompleteSelectFieldProps
testId?: string;
fetchChoices?: (value: string) => void;
onChange: (event: React.ChangeEvent<any>) => void;
onClick?: () => void;
onFocus?: () => void;
}
const DebounceAutocomplete: React.ComponentType<DebounceProps<
@ -110,7 +110,7 @@ const MultiAutocompleteSelectFieldComponent: React.FC<MultiAutocompleteSelectFie
testId,
fetchChoices,
onChange,
onClick,
onFocus,
onFetchMore,
...rest
} = props;
@ -165,10 +165,10 @@ const MultiAutocompleteSelectFieldComponent: React.FC<MultiAutocompleteSelectFie
</div>
),
id: undefined,
onClick: (cb: () => void) => {
toggleMenu(cb);
if (onClick) {
onClick();
onClick: toggleMenu,
onFocus: () => {
if (onFocus) {
onFocus();
}
}
}}

View file

@ -46,7 +46,7 @@ export interface SingleAutocompleteSelectFieldProps
InputProps?: InputProps;
fetchChoices?: (value: string) => void;
onChange: (event: React.ChangeEvent<any>) => void;
onClick?: () => void;
onFocus?: () => void;
FormHelperTextProps?: ExtendedFormHelperTextProps;
nakedInput?: boolean;
}
@ -76,7 +76,7 @@ const SingleAutocompleteSelectFieldComponent: React.FC<SingleAutocompleteSelectF
fetchChoices,
onChange,
onFetchMore,
onClick,
onFocus,
FormHelperTextProps,
nakedInput = false,
...rest
@ -168,10 +168,10 @@ const SingleAutocompleteSelectFieldComponent: React.FC<SingleAutocompleteSelectF
error,
id: undefined,
onBlur: handleBlur,
onClick: (cb: () => void) => {
toggleMenu(cb);
if (onClick) {
onClick();
onClick: toggleMenu,
onFocus: () => {
if (onFocus) {
onFocus();
}
}
};

View file

@ -151,7 +151,8 @@ const SingleAutocompleteSelectFieldContent: React.FC<SingleAutocompleteSelectFie
const anchor = React.useRef<HTMLDivElement>();
const scrollPosition = useElementScroll(anchor);
const [calledForMore, setCalledForMore] = React.useState(false);
const [slice, setSlice] = React.useState(sliceSize);
const [slice, setSlice] = React.useState(onFetchMore ? 10000 : sliceSize);
const [initialized, setInitialized] = React.useState(false);
const scrolledToBottom = isScrolledToBottom(anchor, scrollPosition, offset);
@ -159,20 +160,27 @@ const SingleAutocompleteSelectFieldContent: React.FC<SingleAutocompleteSelectFie
if (!calledForMore && onFetchMore && scrolledToBottom) {
onFetchMore();
setCalledForMore(true);
} else if (scrolledToBottom) {
} else if (scrolledToBottom && !onFetchMore) {
setSlice(slice => slice + sliceSize);
}
}, [scrolledToBottom]);
React.useEffect(() => {
setSlice(sliceSize);
if (anchor.current?.scrollTo) {
if (!onFetchMore) {
setSlice(sliceSize);
}
if (anchor.current?.scrollTo && !initialized) {
anchor.current.scrollTo({
top: 0
});
setInitialized(true);
}
}, [choices?.length]);
React.useEffect(() => {
setInitialized(false);
}, [inputValue]);
React.useEffect(() => {
if (calledForMore && !loading) {
setCalledForMore(false);
@ -183,6 +191,8 @@ const SingleAutocompleteSelectFieldContent: React.FC<SingleAutocompleteSelectFie
item: ""
});
const choicesToDisplay = choices.slice(0, slice);
return (
<Paper className={classes.root}>
<div
@ -244,7 +254,7 @@ const SingleAutocompleteSelectFieldContent: React.FC<SingleAutocompleteSelectFie
{choices.length > 0 && (!!add || displayCustomValue) && (
<Hr className={classes.hr} />
)}
{choices.slice(0, slice).map((suggestion, index) => {
{choicesToDisplay.map((suggestion, index) => {
const choiceIndex = getChoiceIndex(
index,
emptyOption,

View file

@ -246,6 +246,7 @@ export const productFragmentDetails = gql`
`;
export const variantAttributeFragment = gql`
${attributeValueListFragment}
fragment VariantAttributeFragment on Attribute {
id
name
@ -254,14 +255,14 @@ export const variantAttributeFragment = gql`
entityType
valueRequired
unit
# values(
# first: $firstValues
# after: $afterValues
# last: $lastValues
# before: $beforeValues
# ) {
# ...AttributeValueListFragment
# }
choices(
first: $firstValues
after: $afterValues
last: $lastValues
before: $beforeValues
) {
...AttributeValueListFragment
}
}
`;

View file

@ -21,7 +21,7 @@ export interface ProductVariant_privateMetadata {
value: string;
}
export interface ProductVariant_selectionAttributes_attribute_values_pageInfo {
export interface ProductVariant_selectionAttributes_attribute_choices_pageInfo {
__typename: "PageInfo";
endCursor: string | null;
hasNextPage: boolean;
@ -29,32 +29,32 @@ export interface ProductVariant_selectionAttributes_attribute_values_pageInfo {
startCursor: string | null;
}
export interface ProductVariant_selectionAttributes_attribute_values_edges_node_file {
export interface ProductVariant_selectionAttributes_attribute_choices_edges_node_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductVariant_selectionAttributes_attribute_values_edges_node {
export interface ProductVariant_selectionAttributes_attribute_choices_edges_node {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: ProductVariant_selectionAttributes_attribute_values_edges_node_file | null;
file: ProductVariant_selectionAttributes_attribute_choices_edges_node_file | null;
reference: string | null;
richText: any | null;
}
export interface ProductVariant_selectionAttributes_attribute_values_edges {
export interface ProductVariant_selectionAttributes_attribute_choices_edges {
__typename: "AttributeValueCountableEdge";
cursor: string;
node: ProductVariant_selectionAttributes_attribute_values_edges_node;
node: ProductVariant_selectionAttributes_attribute_choices_edges_node;
}
export interface ProductVariant_selectionAttributes_attribute_values {
export interface ProductVariant_selectionAttributes_attribute_choices {
__typename: "AttributeValueCountableConnection";
pageInfo: ProductVariant_selectionAttributes_attribute_values_pageInfo;
edges: ProductVariant_selectionAttributes_attribute_values_edges[];
pageInfo: ProductVariant_selectionAttributes_attribute_choices_pageInfo;
edges: ProductVariant_selectionAttributes_attribute_choices_edges[];
}
export interface ProductVariant_selectionAttributes_attribute {
@ -66,7 +66,7 @@ export interface ProductVariant_selectionAttributes_attribute {
entityType: AttributeEntityTypeEnum | null;
valueRequired: boolean;
unit: MeasurementUnitsEnum | null;
values: ProductVariant_selectionAttributes_attribute_values | null;
choices: ProductVariant_selectionAttributes_attribute_choices | null;
}
export interface ProductVariant_selectionAttributes_values_file {
@ -91,7 +91,7 @@ export interface ProductVariant_selectionAttributes {
values: (ProductVariant_selectionAttributes_values | null)[];
}
export interface ProductVariant_nonSelectionAttributes_attribute_values_pageInfo {
export interface ProductVariant_nonSelectionAttributes_attribute_choices_pageInfo {
__typename: "PageInfo";
endCursor: string | null;
hasNextPage: boolean;
@ -99,32 +99,32 @@ export interface ProductVariant_nonSelectionAttributes_attribute_values_pageInfo
startCursor: string | null;
}
export interface ProductVariant_nonSelectionAttributes_attribute_values_edges_node_file {
export interface ProductVariant_nonSelectionAttributes_attribute_choices_edges_node_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductVariant_nonSelectionAttributes_attribute_values_edges_node {
export interface ProductVariant_nonSelectionAttributes_attribute_choices_edges_node {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: ProductVariant_nonSelectionAttributes_attribute_values_edges_node_file | null;
file: ProductVariant_nonSelectionAttributes_attribute_choices_edges_node_file | null;
reference: string | null;
richText: any | null;
}
export interface ProductVariant_nonSelectionAttributes_attribute_values_edges {
export interface ProductVariant_nonSelectionAttributes_attribute_choices_edges {
__typename: "AttributeValueCountableEdge";
cursor: string;
node: ProductVariant_nonSelectionAttributes_attribute_values_edges_node;
node: ProductVariant_nonSelectionAttributes_attribute_choices_edges_node;
}
export interface ProductVariant_nonSelectionAttributes_attribute_values {
export interface ProductVariant_nonSelectionAttributes_attribute_choices {
__typename: "AttributeValueCountableConnection";
pageInfo: ProductVariant_nonSelectionAttributes_attribute_values_pageInfo;
edges: ProductVariant_nonSelectionAttributes_attribute_values_edges[];
pageInfo: ProductVariant_nonSelectionAttributes_attribute_choices_pageInfo;
edges: ProductVariant_nonSelectionAttributes_attribute_choices_edges[];
}
export interface ProductVariant_nonSelectionAttributes_attribute {
@ -136,7 +136,7 @@ export interface ProductVariant_nonSelectionAttributes_attribute {
entityType: AttributeEntityTypeEnum | null;
valueRequired: boolean;
unit: MeasurementUnitsEnum | null;
values: ProductVariant_nonSelectionAttributes_attribute_values | null;
choices: ProductVariant_nonSelectionAttributes_attribute_choices | null;
}
export interface ProductVariant_nonSelectionAttributes_values_file {

View file

@ -9,7 +9,7 @@ import { AttributeInputTypeEnum, AttributeEntityTypeEnum, MeasurementUnitsEnum }
// GraphQL fragment: SelectedVariantAttributeFragment
// ====================================================
export interface SelectedVariantAttributeFragment_attribute_values_pageInfo {
export interface SelectedVariantAttributeFragment_attribute_choices_pageInfo {
__typename: "PageInfo";
endCursor: string | null;
hasNextPage: boolean;
@ -17,32 +17,32 @@ export interface SelectedVariantAttributeFragment_attribute_values_pageInfo {
startCursor: string | null;
}
export interface SelectedVariantAttributeFragment_attribute_values_edges_node_file {
export interface SelectedVariantAttributeFragment_attribute_choices_edges_node_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface SelectedVariantAttributeFragment_attribute_values_edges_node {
export interface SelectedVariantAttributeFragment_attribute_choices_edges_node {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: SelectedVariantAttributeFragment_attribute_values_edges_node_file | null;
file: SelectedVariantAttributeFragment_attribute_choices_edges_node_file | null;
reference: string | null;
richText: any | null;
}
export interface SelectedVariantAttributeFragment_attribute_values_edges {
export interface SelectedVariantAttributeFragment_attribute_choices_edges {
__typename: "AttributeValueCountableEdge";
cursor: string;
node: SelectedVariantAttributeFragment_attribute_values_edges_node;
node: SelectedVariantAttributeFragment_attribute_choices_edges_node;
}
export interface SelectedVariantAttributeFragment_attribute_values {
export interface SelectedVariantAttributeFragment_attribute_choices {
__typename: "AttributeValueCountableConnection";
pageInfo: SelectedVariantAttributeFragment_attribute_values_pageInfo;
edges: SelectedVariantAttributeFragment_attribute_values_edges[];
pageInfo: SelectedVariantAttributeFragment_attribute_choices_pageInfo;
edges: SelectedVariantAttributeFragment_attribute_choices_edges[];
}
export interface SelectedVariantAttributeFragment_attribute {
@ -54,7 +54,7 @@ export interface SelectedVariantAttributeFragment_attribute {
entityType: AttributeEntityTypeEnum | null;
valueRequired: boolean;
unit: MeasurementUnitsEnum | null;
values: SelectedVariantAttributeFragment_attribute_values | null;
choices: SelectedVariantAttributeFragment_attribute_choices | null;
}
export interface SelectedVariantAttributeFragment_values_file {

View file

@ -9,7 +9,7 @@ import { AttributeInputTypeEnum, AttributeEntityTypeEnum, MeasurementUnitsEnum }
// GraphQL fragment: VariantAttributeFragment
// ====================================================
export interface VariantAttributeFragment_values_pageInfo {
export interface VariantAttributeFragment_choices_pageInfo {
__typename: "PageInfo";
endCursor: string | null;
hasNextPage: boolean;
@ -17,32 +17,32 @@ export interface VariantAttributeFragment_values_pageInfo {
startCursor: string | null;
}
export interface VariantAttributeFragment_values_edges_node_file {
export interface VariantAttributeFragment_choices_edges_node_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface VariantAttributeFragment_values_edges_node {
export interface VariantAttributeFragment_choices_edges_node {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: VariantAttributeFragment_values_edges_node_file | null;
file: VariantAttributeFragment_choices_edges_node_file | null;
reference: string | null;
richText: any | null;
}
export interface VariantAttributeFragment_values_edges {
export interface VariantAttributeFragment_choices_edges {
__typename: "AttributeValueCountableEdge";
cursor: string;
node: VariantAttributeFragment_values_edges_node;
node: VariantAttributeFragment_choices_edges_node;
}
export interface VariantAttributeFragment_values {
export interface VariantAttributeFragment_choices {
__typename: "AttributeValueCountableConnection";
pageInfo: VariantAttributeFragment_values_pageInfo;
edges: VariantAttributeFragment_values_edges[];
pageInfo: VariantAttributeFragment_choices_pageInfo;
edges: VariantAttributeFragment_choices_edges[];
}
export interface VariantAttributeFragment {
@ -54,5 +54,5 @@ export interface VariantAttributeFragment {
entityType: AttributeEntityTypeEnum | null;
valueRequired: boolean;
unit: MeasurementUnitsEnum | null;
values: VariantAttributeFragment_values | null;
choices: VariantAttributeFragment_choices | null;
}

View file

@ -0,0 +1,79 @@
import { useState } from "react";
export interface PageInfo {
endCursor: string;
hasNextPage: boolean;
hasPreviousPage: boolean;
startCursor: string;
}
export interface PaginationState {
after?: string;
before?: string;
first?: number;
last?: number;
}
export function useLocalPaginationState(
paginateBy: number
): [PaginationState, (paginationState: PaginationState) => void] {
const [state, setState] = useState<PaginationState>({
first: paginateBy
});
const setPaginationState = (paginationState: PaginationState) => {
if (paginationState.after) {
setState({
after: paginationState.after,
first: paginateBy
});
} else if (paginationState.before) {
setState({
before: paginationState.before,
last: paginateBy
});
} else {
setState({
first: paginateBy
});
}
};
return [state, setPaginationState];
}
function useLocalPaginator(
setPaginationState: (paginationState: PaginationState) => void
) {
function paginate(pageInfo: PageInfo, paginationState: PaginationState) {
const loadNextPage = () =>
setPaginationState({
...paginationState,
after: pageInfo.endCursor,
before: undefined
});
const loadPreviousPage = () =>
setPaginationState({
...paginationState,
after: undefined,
before: pageInfo.startCursor
});
const newPageInfo = pageInfo
? {
...pageInfo,
hasNextPage: !!paginationState.before || pageInfo.hasNextPage,
hasPreviousPage: !!paginationState.after || pageInfo.hasPreviousPage
}
: undefined;
return {
loadNextPage,
loadPreviousPage,
pageInfo: newPageInfo
};
}
return paginate;
}
export default useLocalPaginator;

View file

@ -167,7 +167,7 @@ const PageDetailsPage: React.FC<PageDetailsPageProps> = ({
onReferencesReorder={handlers.reorderAttributeValue}
fetchAttributeValues={() => undefined}
fetchMoreAttributeValues={undefined}
onAttributeSelect={() => undefined}
onAttributeFocus={() => undefined}
/>
)}
<CardSpacer />

View file

@ -75,7 +75,7 @@ interface ProductCreatePageProps {
fetchCollections: (data: string) => void;
fetchProductTypes: (data: string) => void;
fetchAttributeValues: (query: string) => void;
onAttributeSelect: (id: string) => void;
onAttributeFocus: (id: string) => void;
onWarehouseConfigure: () => void;
openChannelsModal: () => void;
onChannelsChange: (data: ChannelData[]) => void;
@ -131,7 +131,7 @@ export const ProductCreatePage: React.FC<ProductCreatePageProps> = ({
fetchMoreAttributeValues,
onCloseDialog,
onSelectProductType,
onAttributeSelect
onAttributeFocus
}: ProductCreatePageProps) => {
const intl = useIntl();
@ -243,7 +243,7 @@ export const ProductCreatePage: React.FC<ProductCreatePageProps> = ({
onReferencesReorder={handlers.reorderAttributeValue}
fetchAttributeValues={fetchAttributeValues}
fetchMoreAttributeValues={fetchMoreAttributeValues}
onAttributeSelect={onAttributeSelect}
onAttributeFocus={onAttributeFocus}
/>
)}
<CardSpacer />

View file

@ -60,7 +60,7 @@ const props: ProductUpdatePageProps = {
onVariantsAdd: () => undefined,
onWarehouseConfigure: () => undefined,
openChannelsModal: () => undefined,
onAttributeSelect: () => undefined,
onAttributeFocus: () => undefined,
placeholderImage,
product,
referencePages: [],

View file

@ -102,7 +102,7 @@ export interface ProductUpdatePageProps extends ListActions, ChannelProps {
fetchReferencePages?: (data: string) => void;
fetchReferenceProducts?: (data: string) => void;
fetchAttributeValues: (query: string) => void;
onAttributeSelect: (id: string) => void;
onAttributeFocus: (id: string) => void;
onAssignReferencesClick: (attribute: AttributeInput) => void;
onCloseDialog: () => void;
onVariantsAdd: () => void;
@ -196,7 +196,7 @@ export const ProductUpdatePage: React.FC<ProductUpdatePageProps> = ({
onCloseDialog,
channelsWithVariantsData,
onChannelsChange,
onAttributeSelect
onAttributeFocus
}) => {
const intl = useIntl();
@ -319,7 +319,7 @@ export const ProductUpdatePage: React.FC<ProductUpdatePageProps> = ({
onReferencesReorder={handlers.reorderAttributeValue}
fetchAttributeValues={fetchAttributeValues}
fetchMoreAttributeValues={fetchMoreAttributeValues}
onAttributeSelect={onAttributeSelect}
onAttributeFocus={onAttributeFocus}
/>
)}
<CardSpacer />

View file

@ -8,8 +8,8 @@ import SingleAutocompleteSelectField, {
import Skeleton from "@saleor/components/Skeleton";
import { ProductErrorWithAttributesFragment } from "@saleor/fragments/types/ProductErrorWithAttributesFragment";
import {
ProductVariant_nonSelectionAttributes_attribute_values_edges,
ProductVariant_selectionAttributes_attribute_values_edges
ProductVariant_nonSelectionAttributes_attribute_choices_edges,
ProductVariant_selectionAttributes_attribute_choices_edges
} from "@saleor/fragments/types/ProductVariant";
import { FormsetAtomicData, FormsetChange } from "@saleor/hooks/useFormset";
import { commonMessages } from "@saleor/intl";
@ -19,8 +19,8 @@ import { useIntl } from "react-intl";
export interface VariantAttributeInputData {
values: Array<
| ProductVariant_selectionAttributes_attribute_values_edges
| ProductVariant_nonSelectionAttributes_attribute_values_edges
| ProductVariant_selectionAttributes_attribute_choices_edges
| ProductVariant_nonSelectionAttributes_attribute_choices_edges
>;
}
export type VariantAttributeInput = FormsetAtomicData<

View file

@ -17,6 +17,7 @@ import Metadata from "@saleor/components/Metadata";
import PageHeader from "@saleor/components/PageHeader";
import SaveButtonBar from "@saleor/components/SaveButtonBar";
import { ProductErrorWithAttributesFragment } from "@saleor/fragments/types/ProductErrorWithAttributesFragment";
import { SearchAttributeValues_attribute_choices_edges_node } from "@saleor/searches/types/SearchAttributeValues";
import { SearchPages_search_edges_node } from "@saleor/searches/types/SearchPages";
import { SearchProducts_search_edges_node } from "@saleor/searches/types/SearchProducts";
import { SearchWarehouses_search_edges_node } from "@saleor/searches/types/SearchWarehouses";
@ -69,6 +70,7 @@ interface ProductVariantCreatePageProps {
weightUnit: string;
referencePages?: SearchPages_search_edges_node[];
referenceProducts?: SearchProducts_search_edges_node[];
attributeValues: SearchAttributeValues_attribute_choices_edges_node[];
onBack: () => void;
onSubmit: (data: ProductVariantCreateData) => void;
onVariantClick: (variantId: string) => void;
@ -76,10 +78,13 @@ interface ProductVariantCreatePageProps {
onWarehouseConfigure: () => void;
assignReferencesAttributeId?: string;
onAssignReferencesClick: (attribute: AttributeInput) => void;
onAttributeFocus: (id: string) => void;
fetchReferencePages?: (data: string) => void;
fetchReferenceProducts?: (data: string) => void;
fetchAttributeValues: (query: string) => void;
fetchMoreReferencePages?: FetchMoreProps;
fetchMoreReferenceProducts?: FetchMoreProps;
fetchMoreAttributeValues?: FetchMoreProps;
onCloseDialog: () => void;
}
@ -94,17 +99,21 @@ const ProductVariantCreatePage: React.FC<ProductVariantCreatePageProps> = ({
weightUnit,
referencePages = [],
referenceProducts = [],
attributeValues,
onBack,
onSubmit,
onVariantClick,
onVariantReorder,
onWarehouseConfigure,
onAttributeFocus,
assignReferencesAttributeId,
onAssignReferencesClick,
fetchReferencePages,
fetchReferenceProducts,
fetchAttributeValues,
fetchMoreReferencePages,
fetchMoreReferenceProducts,
fetchMoreAttributeValues,
onCloseDialog
}) => {
const intl = useIntl();
@ -173,7 +182,7 @@ const ProductVariantCreatePage: React.FC<ProductVariantCreatePageProps> = ({
attribute.data.variantAttributeScope ===
VariantAttributeScope.NOT_VARIANT_SELECTION
)}
attributeValues={[]}
attributeValues={attributeValues}
loading={disabled}
disabled={disabled}
errors={errors}
@ -183,9 +192,9 @@ const ProductVariantCreatePage: React.FC<ProductVariantCreatePageProps> = ({
onReferencesRemove={handlers.selectAttributeReference}
onReferencesAddClick={onAssignReferencesClick}
onReferencesReorder={handlers.reorderAttributeValue}
fetchAttributeValues={() => undefined}
fetchMoreAttributeValues={undefined}
onAttributeSelect={() => undefined}
fetchAttributeValues={fetchAttributeValues}
fetchMoreAttributeValues={fetchMoreAttributeValues}
onAttributeFocus={onAttributeFocus}
/>
<CardSpacer />
<Attributes
@ -195,7 +204,7 @@ const ProductVariantCreatePage: React.FC<ProductVariantCreatePageProps> = ({
attribute.data.variantAttributeScope ===
VariantAttributeScope.VARIANT_SELECTION
)}
attributeValues={[]}
attributeValues={attributeValues}
loading={disabled}
disabled={disabled}
errors={errors}
@ -205,9 +214,9 @@ const ProductVariantCreatePage: React.FC<ProductVariantCreatePageProps> = ({
onReferencesRemove={handlers.selectAttributeReference}
onReferencesAddClick={onAssignReferencesClick}
onReferencesReorder={handlers.reorderAttributeValue}
fetchAttributeValues={() => undefined}
fetchMoreAttributeValues={undefined}
onAttributeSelect={() => undefined}
fetchAttributeValues={fetchAttributeValues}
fetchMoreAttributeValues={fetchMoreAttributeValues}
onAttributeFocus={onAttributeFocus}
/>
<CardSpacer />
<ProductShipping

View file

@ -1,7 +1,7 @@
import { attributes } from "@saleor/attributes/fixtures";
import { productChannels } from "@saleor/channels/fixtures";
import Container from "@saleor/components/Container";
import { limitsReached } from "@saleor/fixtures";
import { fetchMoreProps, limitsReached } from "@saleor/fixtures";
import { ProductVariantBulkCreate_productVariantBulkCreate_errors } from "@saleor/products/types/ProductVariantBulkCreate";
import { ProductErrorCode } from "@saleor/types/globalTypes";
import { warehouseList } from "@saleor/warehouses/fixtures";
@ -60,7 +60,10 @@ const stock: Stock = {
const dataAttributes = selectedAttributes.map(attribute => ({
id: attribute.id,
values: attribute.choices.edges
.map(value => value.node.slug)
.map(value => ({
slug: value.node.slug,
value: value.node
}))
.filter((_, valueIndex) => valueIndex % 2 !== 1)
}));
@ -89,6 +92,9 @@ const data: ProductVariantCreateFormData = {
};
const props: ProductVariantCreatorContentProps = {
attributes: [0, 1, 4, 6].map(index => attributes[index]),
attributeValues: [],
fetchAttributeValues: () => undefined,
fetchMoreAttributeValues: fetchMoreProps,
channelListings: productChannels.map(listing => ({
currency: listing.pricing?.priceRange?.start?.net.currency,
id: listing.channel.id,
@ -103,7 +109,8 @@ const props: ProductVariantCreatorContentProps = {
errors: [],
variantsLeft: 6,
step: ProductVariantCreatorStep.values,
warehouses: warehouseList
warehouses: warehouseList,
onAttributeFocus: () => undefined
};
storiesOf("Views / Products / Create multiple variants", module)

View file

@ -2,6 +2,8 @@ import { ChannelPriceData } from "@saleor/channels/utils";
import { WarehouseFragment } from "@saleor/fragments/types/WarehouseFragment";
import { ProductDetails_product_productType_variantAttributes } from "@saleor/products/types/ProductDetails";
import { ProductVariantBulkCreate_productVariantBulkCreate_errors } from "@saleor/products/types/ProductVariantBulkCreate";
import { SearchAttributeValues_attribute_choices_edges_node } from "@saleor/searches/types/SearchAttributeValues";
import { FetchMoreProps } from "@saleor/types";
import { isSelected } from "@saleor/utils/lists";
import React from "react";
@ -17,6 +19,7 @@ import { ProductVariantCreatorStep } from "./types";
export interface ProductVariantCreatorContentProps {
attributes: ProductDetails_product_productType_variantAttributes[];
attributeValues: SearchAttributeValues_attribute_choices_edges_node[];
channelListings: ChannelPriceData[];
data: ProductVariantCreateFormData;
dispatchFormDataAction: React.Dispatch<ProductVariantCreateReducerAction>;
@ -24,17 +27,24 @@ export interface ProductVariantCreatorContentProps {
step: ProductVariantCreatorStep;
variantsLeft: number | null;
warehouses: WarehouseFragment[];
fetchAttributeValues: (query: string) => void;
fetchMoreAttributeValues?: FetchMoreProps;
onAttributeFocus: (id: string) => void;
}
const ProductVariantCreatorContent: React.FC<ProductVariantCreatorContentProps> = ({
attributes,
attributeValues,
fetchAttributeValues,
fetchMoreAttributeValues,
channelListings,
data,
dispatchFormDataAction,
errors,
step,
variantsLeft,
warehouses
warehouses,
onAttributeFocus
}) => {
const selectedAttributes = attributes.filter(attribute =>
isSelected(
@ -49,17 +59,21 @@ const ProductVariantCreatorContent: React.FC<ProductVariantCreatorContentProps>
{step === ProductVariantCreatorStep.values && (
<ProductVariantCreateValues
attributes={selectedAttributes}
attributeValues={attributeValues}
fetchAttributeValues={fetchAttributeValues}
fetchMoreAttributeValues={fetchMoreAttributeValues}
data={data}
variantsLeft={variantsLeft}
onValueClick={(attributeId, valueId) =>
onValueClick={(attributeId, value) =>
dispatchFormDataAction({
selectValue: {
attributeId,
valueId
value
},
type: ProductVariantCreateReducerActionType.selectValue
})
}
onAttributeFocus={onAttributeFocus}
/>
)}
{step === ProductVariantCreatorStep.prices && (

View file

@ -1,4 +1,5 @@
import { Button, Typography } from "@material-ui/core";
import { drawerWidthExpanded } from "@saleor/components/AppLayout/consts";
import Container from "@saleor/components/Container";
import Hr from "@saleor/components/Hr";
import PageHeader from "@saleor/components/PageHeader";
@ -28,8 +29,13 @@ const useStyles = makeStyles(
},
content: {
overflowX: "visible",
overflowY: "hidden",
width: 800
[theme.breakpoints.up("md")]: {
position: "absolute",
width: `calc(100vw - ${drawerWidthExpanded}px + ${theme.spacing(6)}px)`,
maxWidth: `calc(${theme.breakpoints.width("lg")}px - ${theme.spacing(
6
)}px)`
}
},
description: {
marginTop: theme.spacing()
@ -185,7 +191,7 @@ const ProductVariantCreatePage: React.FC<ProductVariantCreatePageProps> = props
React.useEffect(reloadForm, [attributes.length, warehouses.length]);
const variantsLeft = limits.allowedUsage.productVariants
const variantsLeft = limits?.allowedUsage.productVariants
? limits.allowedUsage.productVariants - limits.currentUsage.productVariants
: null;
@ -237,17 +243,19 @@ const ProductVariantCreatePage: React.FC<ProductVariantCreatePageProps> = props
)}
</PageHeader>
<Hr className={classes.hr} />
<ProductVariantCreatorContent
{...contentProps}
attributes={attributes}
channelListings={channelListings}
data={wizardData}
dispatchFormDataAction={dispatchFormDataAction}
errors={errors}
variantsLeft={variantsLeft}
step={step}
warehouses={warehouses}
/>
<div className={classes.content}>
<ProductVariantCreatorContent
{...contentProps}
attributes={attributes}
channelListings={channelListings}
data={wizardData}
dispatchFormDataAction={dispatchFormDataAction}
errors={errors}
variantsLeft={variantsLeft}
step={step}
warehouses={warehouses}
/>
</div>
</Container>
);
};

View file

@ -20,7 +20,7 @@ import React from "react";
import { FormattedMessage, useIntl } from "react-intl";
import { ProductDetails_product_productType_variantAttributes } from "../../types/ProductDetails";
import { ChannelPrice, ProductVariantCreateFormData } from "./form";
import { Attribute, ChannelPrice, ProductVariantCreateFormData } from "./form";
export interface ProductVariantCreatorSummaryProps {
attributes: ProductDetails_product_productType_variantAttributes[];
@ -113,18 +113,18 @@ const useStyles = makeStyles<ProductVariantCreatorSummaryProps, ClassKey>(
function getVariantName(
variant: ProductVariantBulkCreateInput,
attributes: ProductDetails_product_productType_variantAttributes[]
attributes: Attribute[]
): string[] {
return attributes.reduce(
(acc, attribute) => [
...acc,
attribute.choices.edges.find(
attribute.values?.find(
value =>
value.node.slug ===
value?.slug ===
variant.attributes.find(
variantAttribute => variantAttribute.id === attribute.id
).values[0]
).node.name
)?.value?.name
],
[]
);
@ -132,7 +132,6 @@ function getVariantName(
const ProductVariantCreatorSummary: React.FC<ProductVariantCreatorSummaryProps> = props => {
const {
attributes,
channelListings,
data,
errors,
@ -220,7 +219,7 @@ const ProductVariantCreatorSummary: React.FC<ProductVariantCreatorSummaryProps>
.join(":")}
>
<div className={classNames(classes.col, classes.colName)}>
{getVariantName(variant, attributes).map(
{getVariantName(variant, data.attributes).map(
(value, valueIndex) => (
<span
className={classes.attributeValue}

View file

@ -1,17 +1,30 @@
import { Card, CardContent } from "@material-ui/core";
import Alert from "@saleor/components/Alert/Alert";
import { getMultiChoices } from "@saleor/components/Attributes/utils";
import CardSpacer from "@saleor/components/CardSpacer";
import CardTitle from "@saleor/components/CardTitle";
import ControlledCheckbox from "@saleor/components/ControlledCheckbox";
import Debounce from "@saleor/components/Debounce";
import MultiAutocompleteSelectField from "@saleor/components/MultiAutocompleteSelectField";
import Skeleton from "@saleor/components/Skeleton";
import { AttributeValueFragment } from "@saleor/fragments/types/AttributeValueFragment";
import { getById } from "@saleor/orders/components/OrderReturnPage/utils";
import { ProductDetails_product_productType_variantAttributes } from "@saleor/products/types/ProductDetails";
import { makeStyles } from "@saleor/theme";
import { isSelected } from "@saleor/utils/lists";
import { SearchAttributeValues_attribute_choices_edges_node } from "@saleor/searches/types/SearchAttributeValues";
import { FetchMoreProps } from "@saleor/types";
import React from "react";
import { FormattedMessage, useIntl } from "react-intl";
import { defineMessages, FormattedMessage, useIntl } from "react-intl";
import { ProductVariantCreateFormData } from "./form";
import {
Attribute,
AttributeValue,
ProductVariantCreateFormData
} from "./form";
const messages = defineMessages({
multipleValueLabel: {
defaultMessage: "Values",
description: "attribute values"
}
});
export function getVariantsNumber(data: ProductVariantCreateFormData): number {
return data.attributes.reduce(
@ -20,30 +33,64 @@ export function getVariantsNumber(data: ProductVariantCreateFormData): number {
);
}
export interface ProductVariantCreatorValuesProps {
attributes: ProductDetails_product_productType_variantAttributes[];
data: ProductVariantCreateFormData;
variantsLeft: number | null;
onValueClick: (attributeId: string, valueId: string) => void;
export function getMultiValues(
attributes: Attribute[],
attribute: ProductDetails_product_productType_variantAttributes
) {
return attributes
.find(getById(attribute.id))
?.values?.map(value => value.slug);
}
const useStyles = makeStyles(
theme => ({
valueContainer: {
display: "grid",
gridColumnGap: theme.spacing(3),
gridTemplateColumns: "repeat(5, 1fr)"
}
}),
{ name: "ProductVariantCreatorValues" }
);
export function getMultiDisplayValues(
attributes: Attribute[],
attribute: ProductDetails_product_productType_variantAttributes
) {
return attributes.find(getById(attribute.id))?.values.map(value => ({
label: value.value?.name,
value: value.slug
}));
}
export interface ProductVariantCreatorValuesProps {
attributes: ProductDetails_product_productType_variantAttributes[];
attributeValues: SearchAttributeValues_attribute_choices_edges_node[];
fetchAttributeValues: (query: string) => void;
fetchMoreAttributeValues?: FetchMoreProps;
data: ProductVariantCreateFormData;
variantsLeft: number | null;
onValueClick: (
attributeId: string,
value: AttributeValue<AttributeValueFragment>
) => void;
onAttributeFocus: (id: string) => void;
}
const ProductVariantCreatorValues: React.FC<ProductVariantCreatorValuesProps> = props => {
const { attributes, data, variantsLeft, onValueClick } = props;
const classes = useStyles(props);
const {
attributes,
attributeValues,
fetchAttributeValues,
fetchMoreAttributeValues,
data,
variantsLeft,
onValueClick,
onAttributeFocus
} = props;
const intl = useIntl();
const variantsNumber = getVariantsNumber(data);
const handleValueClick = (attributeId: string, valueSlug: string) => {
const dataAttribute = data.attributes.find(getById(attributeId));
onValueClick(attributeId, {
slug: valueSlug,
value:
dataAttribute?.values.find(value => value.slug === valueSlug)?.value ||
attributeValues.find(value => value.slug === valueSlug)
});
};
return (
<>
{variantsLeft !== null && (
@ -67,32 +114,24 @@ const ProductVariantCreatorValues: React.FC<ProductVariantCreatorValuesProps> =
<React.Fragment key={attribute.id}>
<Card>
<CardTitle title={attribute?.name || <Skeleton />} />
<CardContent
className={classes.valueContainer}
data-test-id="value-container"
>
{attribute.choices.edges.map(({ node: value }) => (
<Debounce
debounceFn={() => onValueClick(attribute.id, value.slug)}
time={100}
key={value.slug}
>
{change => (
<ControlledCheckbox
checked={isSelected(
value.slug,
data.attributes.find(
dataAttribute => attribute.id === dataAttribute.id
)?.values || [],
(a, b) => a === b
)}
name={`value:${value.slug}`}
label={value.name}
onChange={change}
/>
)}
</Debounce>
))}
<CardContent data-test-id="value-container">
<MultiAutocompleteSelectField
choices={getMultiChoices(attributeValues)}
displayValues={getMultiDisplayValues(
data.attributes,
attribute
)}
name={`attribute:${attribute.name}`}
label={intl.formatMessage(messages.multipleValueLabel)}
value={getMultiValues(data.attributes, attribute)}
onChange={event =>
handleValueClick(attribute.id, event.target.value)
}
allowCustomValues={true}
fetchChoices={fetchAttributeValues}
{...fetchMoreAttributeValues}
onFocus={() => onAttributeFocus(attribute.id)}
/>
</CardContent>
</Card>
<CardSpacer />

View file

@ -6,22 +6,88 @@ Object {
Object {
"id": "attr-1",
"values": Array [
"val-1-1",
"val-1-7",
Object {
"slug": "val-1-1",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-1-1",
"name": "val-1-1",
"reference": null,
"richText": null,
"slug": "val-1-1",
},
},
Object {
"slug": "val-1-7",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-1-7",
"name": "val-1-7",
"reference": null,
"richText": null,
"slug": "val-1-7",
},
},
],
},
Object {
"id": "attr-2",
"values": Array [
"val-2-2",
"val-2-4",
Object {
"slug": "val-2-2",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-2-2",
"name": "val-2-2",
"reference": null,
"richText": null,
"slug": "val-2-2",
},
},
Object {
"slug": "val-2-4",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-2-4",
"name": "val-2-4",
"reference": null,
"richText": null,
"slug": "val-2-4",
},
},
],
},
Object {
"id": "attr-4",
"values": Array [
"val-4-1",
"val-4-5",
Object {
"slug": "val-4-1",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-4-1",
"name": "val-4-1",
"reference": null,
"richText": null,
"slug": "val-4-1",
},
},
Object {
"slug": "val-4-5",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-4-5",
"name": "val-4-5",
"reference": null,
"richText": null,
"slug": "val-4-5",
},
},
],
},
],
@ -561,22 +627,88 @@ Object {
Object {
"id": "attr-1",
"values": Array [
"val-1-1",
"val-1-7",
Object {
"slug": "val-1-1",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-1-1",
"name": "val-1-1",
"reference": null,
"richText": null,
"slug": "val-1-1",
},
},
Object {
"slug": "val-1-7",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-1-7",
"name": "val-1-7",
"reference": null,
"richText": null,
"slug": "val-1-7",
},
},
],
},
Object {
"id": "attr-2",
"values": Array [
"val-2-2",
"val-2-4",
Object {
"slug": "val-2-2",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-2-2",
"name": "val-2-2",
"reference": null,
"richText": null,
"slug": "val-2-2",
},
},
Object {
"slug": "val-2-4",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-2-4",
"name": "val-2-4",
"reference": null,
"richText": null,
"slug": "val-2-4",
},
},
],
},
Object {
"id": "attr-4",
"values": Array [
"val-4-1",
"val-4-5",
Object {
"slug": "val-4-1",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-4-1",
"name": "val-4-1",
"reference": null,
"richText": null,
"slug": "val-4-1",
},
},
Object {
"slug": "val-4-5",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-4-5",
"name": "val-4-5",
"reference": null,
"richText": null,
"slug": "val-4-5",
},
},
],
},
],
@ -1116,22 +1248,88 @@ Object {
Object {
"id": "attr-1",
"values": Array [
"val-1-1",
"val-1-7",
Object {
"slug": "val-1-1",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-1-1",
"name": "val-1-1",
"reference": null,
"richText": null,
"slug": "val-1-1",
},
},
Object {
"slug": "val-1-7",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-1-7",
"name": "val-1-7",
"reference": null,
"richText": null,
"slug": "val-1-7",
},
},
],
},
Object {
"id": "attr-2",
"values": Array [
"val-2-2",
"val-2-4",
Object {
"slug": "val-2-2",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-2-2",
"name": "val-2-2",
"reference": null,
"richText": null,
"slug": "val-2-2",
},
},
Object {
"slug": "val-2-4",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-2-4",
"name": "val-2-4",
"reference": null,
"richText": null,
"slug": "val-2-4",
},
},
],
},
Object {
"id": "attr-4",
"values": Array [
"val-4-1",
"val-4-5",
Object {
"slug": "val-4-1",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-4-1",
"name": "val-4-1",
"reference": null,
"richText": null,
"slug": "val-4-1",
},
},
Object {
"slug": "val-4-5",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-4-5",
"name": "val-4-5",
"reference": null,
"richText": null,
"slug": "val-4-5",
},
},
],
},
],
@ -1171,22 +1369,88 @@ Object {
Object {
"id": "attr-1",
"values": Array [
"val-1-1",
"val-1-7",
Object {
"slug": "val-1-1",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-1-1",
"name": "val-1-1",
"reference": null,
"richText": null,
"slug": "val-1-1",
},
},
Object {
"slug": "val-1-7",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-1-7",
"name": "val-1-7",
"reference": null,
"richText": null,
"slug": "val-1-7",
},
},
],
},
Object {
"id": "attr-2",
"values": Array [
"val-2-2",
"val-2-4",
Object {
"slug": "val-2-2",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-2-2",
"name": "val-2-2",
"reference": null,
"richText": null,
"slug": "val-2-2",
},
},
Object {
"slug": "val-2-4",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-2-4",
"name": "val-2-4",
"reference": null,
"richText": null,
"slug": "val-2-4",
},
},
],
},
Object {
"id": "attr-4",
"values": Array [
"val-4-1",
"val-4-5",
Object {
"slug": "val-4-1",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-4-1",
"name": "val-4-1",
"reference": null,
"richText": null,
"slug": "val-4-1",
},
},
Object {
"slug": "val-4-5",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-4-5",
"name": "val-4-5",
"reference": null,
"richText": null,
"slug": "val-4-5",
},
},
],
},
],
@ -1677,22 +1941,88 @@ Object {
Object {
"id": "attr-1",
"values": Array [
"val-1-1",
"val-1-7",
Object {
"slug": "val-1-1",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-1-1",
"name": "val-1-1",
"reference": null,
"richText": null,
"slug": "val-1-1",
},
},
Object {
"slug": "val-1-7",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-1-7",
"name": "val-1-7",
"reference": null,
"richText": null,
"slug": "val-1-7",
},
},
],
},
Object {
"id": "attr-2",
"values": Array [
"val-2-2",
"val-2-4",
Object {
"slug": "val-2-2",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-2-2",
"name": "val-2-2",
"reference": null,
"richText": null,
"slug": "val-2-2",
},
},
Object {
"slug": "val-2-4",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-2-4",
"name": "val-2-4",
"reference": null,
"richText": null,
"slug": "val-2-4",
},
},
],
},
Object {
"id": "attr-4",
"values": Array [
"val-4-1",
"val-4-5",
Object {
"slug": "val-4-1",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-4-1",
"name": "val-4-1",
"reference": null,
"richText": null,
"slug": "val-4-1",
},
},
Object {
"slug": "val-4-5",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-4-5",
"name": "val-4-5",
"reference": null,
"richText": null,
"slug": "val-4-5",
},
},
],
},
],
@ -2138,22 +2468,88 @@ Object {
Object {
"id": "attr-1",
"values": Array [
"val-1-1",
"val-1-7",
Object {
"slug": "val-1-1",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-1-1",
"name": "val-1-1",
"reference": null,
"richText": null,
"slug": "val-1-1",
},
},
Object {
"slug": "val-1-7",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-1-7",
"name": "val-1-7",
"reference": null,
"richText": null,
"slug": "val-1-7",
},
},
],
},
Object {
"id": "attr-2",
"values": Array [
"val-2-2",
"val-2-4",
Object {
"slug": "val-2-2",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-2-2",
"name": "val-2-2",
"reference": null,
"richText": null,
"slug": "val-2-2",
},
},
Object {
"slug": "val-2-4",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-2-4",
"name": "val-2-4",
"reference": null,
"richText": null,
"slug": "val-2-4",
},
},
],
},
Object {
"id": "attr-4",
"values": Array [
"val-4-1",
"val-4-5",
Object {
"slug": "val-4-1",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-4-1",
"name": "val-4-1",
"reference": null,
"richText": null,
"slug": "val-4-1",
},
},
Object {
"slug": "val-4-5",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-4-5",
"name": "val-4-5",
"reference": null,
"richText": null,
"slug": "val-4-5",
},
},
],
},
],
@ -2644,22 +3040,88 @@ Object {
Object {
"id": "attr-1",
"values": Array [
"val-1-1",
"val-1-7",
Object {
"slug": "val-1-1",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-1-1",
"name": "val-1-1",
"reference": null,
"richText": null,
"slug": "val-1-1",
},
},
Object {
"slug": "val-1-7",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-1-7",
"name": "val-1-7",
"reference": null,
"richText": null,
"slug": "val-1-7",
},
},
],
},
Object {
"id": "attr-2",
"values": Array [
"val-2-2",
"val-2-4",
Object {
"slug": "val-2-2",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-2-2",
"name": "val-2-2",
"reference": null,
"richText": null,
"slug": "val-2-2",
},
},
Object {
"slug": "val-2-4",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-2-4",
"name": "val-2-4",
"reference": null,
"richText": null,
"slug": "val-2-4",
},
},
],
},
Object {
"id": "attr-4",
"values": Array [
"val-4-1",
"val-4-5",
Object {
"slug": "val-4-1",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-4-1",
"name": "val-4-1",
"reference": null,
"richText": null,
"slug": "val-4-1",
},
},
Object {
"slug": "val-4-5",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-4-5",
"name": "val-4-5",
"reference": null,
"richText": null,
"slug": "val-4-5",
},
},
],
},
],
@ -3067,22 +3529,88 @@ Object {
Object {
"id": "attr-1",
"values": Array [
"val-1-1",
"val-1-7",
Object {
"slug": "val-1-1",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-1-1",
"name": "val-1-1",
"reference": null,
"richText": null,
"slug": "val-1-1",
},
},
Object {
"slug": "val-1-7",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-1-7",
"name": "val-1-7",
"reference": null,
"richText": null,
"slug": "val-1-7",
},
},
],
},
Object {
"id": "attr-2",
"values": Array [
"val-2-2",
"val-2-4",
Object {
"slug": "val-2-2",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-2-2",
"name": "val-2-2",
"reference": null,
"richText": null,
"slug": "val-2-2",
},
},
Object {
"slug": "val-2-4",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-2-4",
"name": "val-2-4",
"reference": null,
"richText": null,
"slug": "val-2-4",
},
},
],
},
Object {
"id": "attr-4",
"values": Array [
"val-4-1",
"val-4-5",
Object {
"slug": "val-4-1",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-4-1",
"name": "val-4-1",
"reference": null,
"richText": null,
"slug": "val-4-1",
},
},
Object {
"slug": "val-4-5",
"value": Object {
"__typename": "AttributeValue",
"file": null,
"id": "val-4-5",
"name": "val-4-5",
"reference": null,
"richText": null,
"slug": "val-4-5",
},
},
],
},
],

View file

@ -63,7 +63,7 @@ describe("Creates variant matrix", () => {
attribute: attribute.id,
mode: "attribute",
values: attribute.values.map((attributeValue, index) => ({
slug: attributeValue,
slug: attributeValue.slug,
value: channels.map(channel => ({
channelId: channel.id,
price: (channel.price + index).toString()
@ -97,7 +97,7 @@ describe("Creates variant matrix", () => {
variant =>
variant.attributes.find(
variantAttribute => variantAttribute.id === attribute.id
).values[0] === attributeValue
).values[0] === attributeValue.slug
)
.forEach(variant => {
variant.channelListings.map((channel, index) => {
@ -128,7 +128,7 @@ describe("Creates variant matrix", () => {
attribute: attribute.id,
mode: "attribute",
values: attribute.values.map((attributeValue, attributeValueIndex) => ({
slug: attributeValue,
slug: attributeValue.slug,
value: stock.map(
(_, stockIndex) => stock[stockIndex] * (attributeValueIndex + 1)
)
@ -154,7 +154,7 @@ describe("Creates variant matrix", () => {
variant =>
variant.attributes.find(
variantAttribute => variantAttribute.id === attribute.id
).values[0] === attributeValue
).values[0] === attributeValue.slug
)
.forEach(variant => {
variant.stocks.forEach((_, stockIndex) => {
@ -179,7 +179,7 @@ describe("Creates variant matrix", () => {
attribute: attribute.id,
mode: "attribute",
values: attribute.values.map((attributeValue, index) => ({
slug: attributeValue,
slug: attributeValue.slug,
value: channels.map(channel => ({
channelId: channel.id,
price: (channel.price + index).toString()
@ -191,7 +191,7 @@ describe("Creates variant matrix", () => {
attribute: attribute.id,
mode: "attribute",
values: attribute.values.map((attributeValue, attributeValueIndex) => ({
slug: attributeValue,
slug: attributeValue.slug,
value: stock.map(
(_, stockIndex) => stock[stockIndex] * (attributeValueIndex + 1)
)
@ -213,7 +213,7 @@ describe("Creates variant matrix", () => {
variant =>
variant.attributes.find(
variantAttribute => variantAttribute.id === attribute.id
).values[0] === attributeValue
).values[0] === attributeValue.slug
)
.forEach(variant => {
variant.channelListings.map((channel, index) => {
@ -230,7 +230,7 @@ describe("Creates variant matrix", () => {
variant =>
variant.attributes.find(
variantAttribute => variantAttribute.id === attribute.id
).values[0] === attributeValue
).values[0] === attributeValue.slug
)
.forEach(variant => {
variant.stocks.forEach((_, stockIndex) => {

View file

@ -112,11 +112,11 @@ function addAttributeToVariant(
attribute: Attribute,
variant: CreateVariantInput
): CreateVariantInput[] {
return attribute.values.map(attributeValueSlug => [
return attribute.values.map(attributeValue => [
...variant,
{
attributeId: attribute.id,
attributeValueSlug
attributeValueSlug: attributeValue.slug
}
]);
}

View file

@ -20,25 +20,69 @@ export const attributes = [
id: "attr-1",
values: Array(9)
.fill(0)
.map((_, index) => `val-1-${index + 1}`)
.map((_, index) => ({
slug: `val-1-${index + 1}`,
value: {
__typename: "AttributeValue" as "AttributeValue",
id: `val-1-${index + 1}`,
name: `val-1-${index + 1}`,
slug: `val-1-${index + 1}`,
file: null,
reference: null,
richText: null
}
}))
},
{
id: "attr-2",
values: Array(6)
.fill(0)
.map((_, index) => `val-2-${index + 1}`)
.map((_, index) => ({
slug: `val-2-${index + 1}`,
value: {
__typename: "AttributeValue" as "AttributeValue",
id: `val-2-${index + 1}`,
name: `val-2-${index + 1}`,
slug: `val-2-${index + 1}`,
file: null,
reference: null,
richText: null
}
}))
},
{
id: "attr-3",
values: Array(4)
.fill(0)
.map((_, index) => `val-3-${index + 1}`)
.map((_, index) => ({
slug: `val-3-${index + 1}`,
value: {
__typename: "AttributeValue" as "AttributeValue",
id: `val-3-${index + 1}`,
name: `val-3-${index + 1}`,
slug: `val-3-${index + 1}`,
file: null,
reference: null,
richText: null
}
}))
},
{
id: "attr-4",
values: Array(11)
.fill(0)
.map((_, index) => `val-4-${index + 1}`)
.map((_, index) => ({
slug: `val-4-${index + 1}`,
value: {
__typename: "AttributeValue" as "AttributeValue",
id: `val-4-${index + 1}`,
name: `val-4-${index + 1}`,
slug: `val-4-${index + 1}`,
file: null,
reference: null,
richText: null
}
}))
}
];
@ -116,7 +160,7 @@ const price: Price = {
mode: "attribute",
values: [
{
slug: thirdStep.attributes[1].values[0],
slug: thirdStep.attributes[1].values[0].slug,
value: [
{ channelId: channels[0].id, price: "0" },
{ channelId: channels[1].id, price: "2" },
@ -124,7 +168,7 @@ const price: Price = {
]
},
{
slug: thirdStep.attributes[1].values[1],
slug: thirdStep.attributes[1].values[1].slug,
value: [
{ channelId: channels[0].id, price: "0" },
{ channelId: channels[1].id, price: "2" },
@ -139,11 +183,11 @@ const stock: Stock = {
value: [],
values: [
{
slug: thirdStep.attributes[2].values[0],
slug: thirdStep.attributes[2].values[0].slug,
value: [50, 20, 45, 75]
},
{
slug: thirdStep.attributes[2].values[1],
slug: thirdStep.attributes[2].values[1].slug,
value: [80, 50, 85, 105]
}
]

View file

@ -1,4 +1,5 @@
import { ChannelPriceData } from "@saleor/channels/utils";
import { AttributeValueFragment } from "@saleor/fragments/types/AttributeValueFragment";
import { WarehouseFragment } from "@saleor/fragments/types/WarehouseFragment";
import { ProductDetails_product_productType_variantAttributes } from "@saleor/products/types/ProductDetails";
@ -28,7 +29,7 @@ export interface Stock {
}
export interface Attribute {
id: string;
values: string[];
values: Array<AttributeValue<AttributeValueFragment>>;
}
export interface ProductVariantCreateFormData {
attributes: Attribute[];

View file

@ -23,14 +23,14 @@ describe("Reducer is able to", () => {
{
selectValue: {
attributeId: attributes[0].id,
valueId: attributes[0].values[0]
value: attributes[0].values[0]
},
type: ProductVariantCreateReducerActionType.selectValue
},
{
selectValue: {
attributeId: attributes[0].id,
valueId: attributes[0].values[6]
value: attributes[0].values[6]
},
type: ProductVariantCreateReducerActionType.selectValue
@ -38,28 +38,28 @@ describe("Reducer is able to", () => {
{
selectValue: {
attributeId: attributes[1].id,
valueId: attributes[1].values[1]
value: attributes[1].values[1]
},
type: ProductVariantCreateReducerActionType.selectValue
},
{
selectValue: {
attributeId: attributes[1].id,
valueId: attributes[1].values[3]
value: attributes[1].values[3]
},
type: ProductVariantCreateReducerActionType.selectValue
},
{
selectValue: {
attributeId: attributes[3].id,
valueId: attributes[3].values[0]
value: attributes[3].values[0]
},
type: ProductVariantCreateReducerActionType.selectValue
},
{
selectValue: {
attributeId: attributes[3].id,
valueId: attributes[3].values[4]
value: attributes[3].values[4]
},
type: ProductVariantCreateReducerActionType.selectValue
}
@ -164,7 +164,7 @@ describe("Reducer is able to", () => {
changeAttributeValuePrice: {
channelId: channels[0].id,
price: value.toString(),
valueId: attribute.values[0]
valueId: attribute.values[0].slug
},
type: ProductVariantCreateReducerActionType.changeAttributeValuePrice
},
@ -172,7 +172,7 @@ describe("Reducer is able to", () => {
changeAttributeValuePrice: {
channelId: channels[1].id,
price: (value + 6).toString(),
valueId: attribute.values[1]
valueId: attribute.values[1].slug
},
type: ProductVariantCreateReducerActionType.changeAttributeValuePrice
},
@ -209,7 +209,7 @@ describe("Reducer is able to", () => {
{
changeAttributeValueStock: {
quantity,
valueId: attribute.values[0],
valueId: attribute.values[0].slug,
warehouseIndex: 0
},
type: ProductVariantCreateReducerActionType.changeAttributeValueStock
@ -217,7 +217,7 @@ describe("Reducer is able to", () => {
{
changeAttributeValueStock: {
quantity: quantity + 6,
valueId: attribute.values[1],
valueId: attribute.values[1].slug,
warehouseIndex: 0
},
type: ProductVariantCreateReducerActionType.changeAttributeValueStock

View file

@ -1,3 +1,4 @@
import { AttributeValueFragment } from "@saleor/fragments/types/AttributeValueFragment";
import { StockInput } from "@saleor/types/globalTypes";
import {
add,
@ -10,6 +11,7 @@ import {
import { createVariants } from "./createVariants";
import {
AttributeValue,
ProductVariantCreateFormData,
VariantCreatorPricesAndSkuMode
} from "./form";
@ -72,19 +74,22 @@ export interface ProductVariantCreateReducerAction {
reload?: {
data?: ProductVariantCreateFormData;
};
selectValue?: Record<"attributeId" | "valueId", string>;
selectValue?: {
attributeId: string;
value: AttributeValue<AttributeValueFragment>;
};
type: ProductVariantCreateReducerActionType;
}
function selectValue(
prevState: ProductVariantCreateFormData,
attributeId: string,
valueSlug: string
value: AttributeValue<AttributeValueFragment>
): ProductVariantCreateFormData {
const attribute = prevState.attributes.find(
attribute => attribute.id === attributeId
);
const values = toggle(valueSlug, attribute.values, (a, b) => a === b);
const values = toggle(value, attribute.values, (a, b) => a.slug === b.slug);
const updatedAttributes = add(
{
id: attributeId,
@ -97,7 +102,7 @@ function selectValue(
prevState.price.attribute === attributeId
? toggle(
{
slug: valueSlug,
slug: value.slug,
value: []
},
prevState.price.values,
@ -109,7 +114,7 @@ function selectValue(
prevState.stock.attribute === attributeId
? toggle(
{
slug: valueSlug,
slug: value.slug,
value: []
},
prevState.stock.values,
@ -237,8 +242,8 @@ function changeApplyPriceToAttributeId(
const attribute = state.attributes.find(
attribute => attribute.id === attributeId
);
const values = attribute.values.map(slug => ({
slug,
const values = attribute.values.map(value => ({
slug: value.slug,
value: []
}));
@ -259,8 +264,8 @@ function changeApplyStockToAttributeId(
const attribute = state.attributes.find(
attribute => attribute.id === attributeId
);
const values = attribute.values.map(slug => ({
slug,
const values = attribute.values.map(value => ({
slug: value.slug,
value: []
}));
@ -435,7 +440,7 @@ function reduceProductVariantCreateFormData(
return selectValue(
prevState,
action.selectValue.attributeId,
action.selectValue.valueId
action.selectValue.value
);
case ProductVariantCreateReducerActionType.applyPriceToAll:
return applyPriceToAll(prevState, action.applyPriceOrStockToAll.mode);

View file

@ -17,7 +17,9 @@ export function getPriceAttributeValues(
.choices.edges.filter(value =>
data.attributes
.find(attribute => attribute.id === data.price.attribute)
.values.includes(value.node.slug)
.values.some(
attributeValue => attributeValue.slug === value.node.slug
)
)
.map(value => value.node)
: [];
@ -35,7 +37,9 @@ export function getStockAttributeValues(
.choices.edges.filter(value =>
data.attributes
.find(attribute => attribute.id === data.stock.attribute)
.values.includes(value.node.slug)
.values.some(
attributeValue => attributeValue.slug === value.node.slug
)
)
.map(value => value.node)
: [];

View file

@ -22,6 +22,7 @@ import { ProductErrorWithAttributesFragment } from "@saleor/fragments/types/Prod
import { ProductVariant } from "@saleor/fragments/types/ProductVariant";
import { WarehouseFragment } from "@saleor/fragments/types/WarehouseFragment";
import { VariantUpdate_productVariantUpdate_errors } from "@saleor/products/types/VariantUpdate";
import { SearchAttributeValues_attribute_choices_edges_node } from "@saleor/searches/types/SearchAttributeValues";
import { SearchPages_search_edges_node } from "@saleor/searches/types/SearchPages";
import { SearchProducts_search_edges_node } from "@saleor/searches/types/SearchProducts";
import { FetchMoreProps, ReorderAction } from "@saleor/types";
@ -87,11 +88,15 @@ interface ProductVariantPageProps {
warehouses: WarehouseFragment[];
referencePages?: SearchPages_search_edges_node[];
referenceProducts?: SearchProducts_search_edges_node[];
attributeValues: SearchAttributeValues_attribute_choices_edges_node[];
fetchMoreReferencePages?: FetchMoreProps;
fetchMoreReferenceProducts?: FetchMoreProps;
fetchMoreAttributeValues?: FetchMoreProps;
fetchReferencePages?: (data: string) => void;
fetchReferenceProducts?: (data: string) => void;
fetchAttributeValues: (query: string) => void;
onAssignReferencesClick: (attribute: AttributeInput) => void;
onAttributeFocus: (id: string) => void;
onCloseDialog: () => void;
onVariantReorder: ReorderAction;
onAdd();
@ -118,6 +123,7 @@ const ProductVariantPage: React.FC<ProductVariantPageProps> = ({
warehouses,
referencePages = [],
referenceProducts = [],
attributeValues,
onAdd,
onBack,
onDelete,
@ -127,12 +133,15 @@ const ProductVariantPage: React.FC<ProductVariantPageProps> = ({
onVariantReorder,
onSetDefaultVariant,
onWarehouseConfigure,
onAttributeFocus,
assignReferencesAttributeId,
onAssignReferencesClick,
fetchReferencePages,
fetchReferenceProducts,
fetchAttributeValues,
fetchMoreReferencePages,
fetchMoreReferenceProducts,
fetchMoreAttributeValues,
onCloseDialog
}) => {
const intl = useIntl();
@ -226,7 +235,7 @@ const ProductVariantPage: React.FC<ProductVariantPageProps> = ({
attribute.data.variantAttributeScope ===
VariantAttributeScope.NOT_VARIANT_SELECTION
)}
attributeValues={[]}
attributeValues={attributeValues}
loading={loading}
disabled={loading}
errors={errors}
@ -236,9 +245,9 @@ const ProductVariantPage: React.FC<ProductVariantPageProps> = ({
onReferencesRemove={handlers.selectAttributeReference}
onReferencesAddClick={onAssignReferencesClick}
onReferencesReorder={handlers.reorderAttributeValue}
fetchAttributeValues={() => undefined}
fetchMoreAttributeValues={undefined}
onAttributeSelect={() => undefined}
fetchAttributeValues={fetchAttributeValues}
fetchMoreAttributeValues={fetchMoreAttributeValues}
onAttributeFocus={onAttributeFocus}
/>
<CardSpacer />
<Attributes
@ -250,7 +259,7 @@ const ProductVariantPage: React.FC<ProductVariantPageProps> = ({
attribute.data.variantAttributeScope ===
VariantAttributeScope.VARIANT_SELECTION
)}
attributeValues={[]}
attributeValues={attributeValues}
loading={loading}
disabled={loading}
errors={errors}
@ -260,9 +269,9 @@ const ProductVariantPage: React.FC<ProductVariantPageProps> = ({
onReferencesRemove={handlers.selectAttributeReference}
onReferencesAddClick={onAssignReferencesClick}
onReferencesReorder={handlers.reorderAttributeValue}
fetchAttributeValues={() => undefined}
fetchMoreAttributeValues={undefined}
onAttributeSelect={() => undefined}
fetchAttributeValues={fetchAttributeValues}
fetchMoreAttributeValues={fetchMoreAttributeValues}
onAttributeFocus={onAttributeFocus}
/>
<CardSpacer />
<ProductVariantMedia

View file

@ -336,7 +336,7 @@ export const product: (
slug: "attachment",
valueRequired: true,
unit: null,
values: {
choices: {
__typename: "AttributeValueCountableConnection",
pageInfo: {
endCursor: "WyI4IiwgIjMiXQ==",
@ -377,7 +377,7 @@ export const product: (
slug: "color",
valueRequired: true,
unit: null,
values: {
choices: {
__typename: "AttributeValueCountableConnection",
pageInfo: {
endCursor: "WyI4IiwgIjMiXQ==",
@ -2885,7 +2885,7 @@ export const variant = (placeholderImage: string): ProductVariant => ({
slug: "attachment",
valueRequired: true,
unit: null,
values: {
choices: {
__typename: "AttributeValueCountableConnection",
pageInfo: {
endCursor: "WyI4IiwgIjMiXQ==",
@ -3168,7 +3168,7 @@ export const variant = (placeholderImage: string): ProductVariant => ({
slug: "Borders",
valueRequired: true,
unit: null,
values: {
choices: {
__typename: "AttributeValueCountableConnection",
pageInfo: {
endCursor: "WyI4IiwgIjMiXQ==",
@ -3230,7 +3230,7 @@ export const variant = (placeholderImage: string): ProductVariant => ({
slug: "Legacy",
valueRequired: true,
unit: null,
values: {
choices: {
__typename: "AttributeValueCountableConnection",
pageInfo: {
endCursor: "WyI4IiwgIjMiXQ==",

View file

@ -334,7 +334,11 @@ export const variantUpdateMutation = gql`
$sku: String
$trackInventory: Boolean!
$stocks: [StockInput!]!
$weight: WeightScalar # $firstValues: Int # $afterValues: String # $lastValues: Int # $beforeValues: String
$weight: WeightScalar
$firstValues: Int
$afterValues: String
$lastValues: Int
$beforeValues: String
) {
productVariantUpdate(
id: $id
@ -394,7 +398,11 @@ export const variantCreateMutation = gql`
${fragmentVariant}
${productErrorWithAttributesFragment}
mutation VariantCreate(
$input: ProductVariantCreateInput! # $firstValues: Int # $afterValues: String # $lastValues: Int # $beforeValues: String
$input: ProductVariantCreateInput!
$firstValues: Int
$afterValues: String
$lastValues: Int
$beforeValues: String
) {
productVariantCreate(input: $input) {
errors {

View file

@ -282,7 +282,11 @@ export const useProductTypeQuery = makeQuery<ProductType, ProductTypeVariables>(
const productVariantQuery = gql`
${fragmentVariant}
query ProductVariantDetails(
$id: ID! # $firstValues: Int # $afterValues: String # $lastValues: Int # $beforeValues: String
$id: ID!
$firstValues: Int
$afterValues: String
$lastValues: Int
$beforeValues: String
) {
productVariant(id: $id) {
...ProductVariant
@ -297,7 +301,11 @@ export const useProductVariantQuery = makeQuery<
const productVariantCreateQuery = gql`
${variantAttributeFragment}
query ProductVariantCreateData(
$id: ID! # $firstValues: Int # $afterValues: String # $lastValues: Int # $beforeValues: String
$id: ID!
$firstValues: Int
$afterValues: String
$lastValues: Int
$beforeValues: String
) {
product(id: $id) {
id

View file

@ -9,7 +9,7 @@ import { AttributeInputTypeEnum, AttributeEntityTypeEnum, MeasurementUnitsEnum }
// GraphQL query operation: CreateMultipleVariantsData
// ====================================================
export interface CreateMultipleVariantsData_product_attributes_attribute_values_pageInfo {
export interface CreateMultipleVariantsData_product_attributes_attribute_choices_pageInfo {
__typename: "PageInfo";
endCursor: string | null;
hasNextPage: boolean;
@ -17,32 +17,32 @@ export interface CreateMultipleVariantsData_product_attributes_attribute_values_
startCursor: string | null;
}
export interface CreateMultipleVariantsData_product_attributes_attribute_values_edges_node_file {
export interface CreateMultipleVariantsData_product_attributes_attribute_choices_edges_node_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface CreateMultipleVariantsData_product_attributes_attribute_values_edges_node {
export interface CreateMultipleVariantsData_product_attributes_attribute_choices_edges_node {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: CreateMultipleVariantsData_product_attributes_attribute_values_edges_node_file | null;
file: CreateMultipleVariantsData_product_attributes_attribute_choices_edges_node_file | null;
reference: string | null;
richText: any | null;
}
export interface CreateMultipleVariantsData_product_attributes_attribute_values_edges {
export interface CreateMultipleVariantsData_product_attributes_attribute_choices_edges {
__typename: "AttributeValueCountableEdge";
cursor: string;
node: CreateMultipleVariantsData_product_attributes_attribute_values_edges_node;
node: CreateMultipleVariantsData_product_attributes_attribute_choices_edges_node;
}
export interface CreateMultipleVariantsData_product_attributes_attribute_values {
export interface CreateMultipleVariantsData_product_attributes_attribute_choices {
__typename: "AttributeValueCountableConnection";
pageInfo: CreateMultipleVariantsData_product_attributes_attribute_values_pageInfo;
edges: CreateMultipleVariantsData_product_attributes_attribute_values_edges[];
pageInfo: CreateMultipleVariantsData_product_attributes_attribute_choices_pageInfo;
edges: CreateMultipleVariantsData_product_attributes_attribute_choices_edges[];
}
export interface CreateMultipleVariantsData_product_attributes_attribute {
@ -54,7 +54,7 @@ export interface CreateMultipleVariantsData_product_attributes_attribute {
entityType: AttributeEntityTypeEnum | null;
valueRequired: boolean;
unit: MeasurementUnitsEnum | null;
values: CreateMultipleVariantsData_product_attributes_attribute_values | null;
choices: CreateMultipleVariantsData_product_attributes_attribute_choices | null;
}
export interface CreateMultipleVariantsData_product_attributes_values_file {
@ -79,7 +79,7 @@ export interface CreateMultipleVariantsData_product_attributes {
values: (CreateMultipleVariantsData_product_attributes_values | null)[];
}
export interface CreateMultipleVariantsData_product_productType_variantAttributes_values_pageInfo {
export interface CreateMultipleVariantsData_product_productType_variantAttributes_choices_pageInfo {
__typename: "PageInfo";
endCursor: string | null;
hasNextPage: boolean;
@ -87,39 +87,39 @@ export interface CreateMultipleVariantsData_product_productType_variantAttribute
startCursor: string | null;
}
export interface CreateMultipleVariantsData_product_productType_variantAttributes_values_edges_node_file {
export interface CreateMultipleVariantsData_product_productType_variantAttributes_choices_edges_node_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface CreateMultipleVariantsData_product_productType_variantAttributes_values_edges_node {
export interface CreateMultipleVariantsData_product_productType_variantAttributes_choices_edges_node {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: CreateMultipleVariantsData_product_productType_variantAttributes_values_edges_node_file | null;
file: CreateMultipleVariantsData_product_productType_variantAttributes_choices_edges_node_file | null;
reference: string | null;
richText: any | null;
}
export interface CreateMultipleVariantsData_product_productType_variantAttributes_values_edges {
export interface CreateMultipleVariantsData_product_productType_variantAttributes_choices_edges {
__typename: "AttributeValueCountableEdge";
cursor: string;
node: CreateMultipleVariantsData_product_productType_variantAttributes_values_edges_node;
node: CreateMultipleVariantsData_product_productType_variantAttributes_choices_edges_node;
}
export interface CreateMultipleVariantsData_product_productType_variantAttributes_values {
export interface CreateMultipleVariantsData_product_productType_variantAttributes_choices {
__typename: "AttributeValueCountableConnection";
pageInfo: CreateMultipleVariantsData_product_productType_variantAttributes_values_pageInfo;
edges: CreateMultipleVariantsData_product_productType_variantAttributes_values_edges[];
pageInfo: CreateMultipleVariantsData_product_productType_variantAttributes_choices_pageInfo;
edges: CreateMultipleVariantsData_product_productType_variantAttributes_choices_edges[];
}
export interface CreateMultipleVariantsData_product_productType_variantAttributes {
__typename: "Attribute";
id: string;
name: string | null;
values: CreateMultipleVariantsData_product_productType_variantAttributes_values | null;
choices: CreateMultipleVariantsData_product_productType_variantAttributes_choices | null;
}
export interface CreateMultipleVariantsData_product_productType {

View file

@ -28,7 +28,7 @@ export interface ProductVariantCreateData_product_channelListings {
channel: ProductVariantCreateData_product_channelListings_channel;
}
export interface ProductVariantCreateData_product_productType_selectionVariantAttributes_values_pageInfo {
export interface ProductVariantCreateData_product_productType_selectionVariantAttributes_choices_pageInfo {
__typename: "PageInfo";
endCursor: string | null;
hasNextPage: boolean;
@ -36,32 +36,32 @@ export interface ProductVariantCreateData_product_productType_selectionVariantAt
startCursor: string | null;
}
export interface ProductVariantCreateData_product_productType_selectionVariantAttributes_values_edges_node_file {
export interface ProductVariantCreateData_product_productType_selectionVariantAttributes_choices_edges_node_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductVariantCreateData_product_productType_selectionVariantAttributes_values_edges_node {
export interface ProductVariantCreateData_product_productType_selectionVariantAttributes_choices_edges_node {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: ProductVariantCreateData_product_productType_selectionVariantAttributes_values_edges_node_file | null;
file: ProductVariantCreateData_product_productType_selectionVariantAttributes_choices_edges_node_file | null;
reference: string | null;
richText: any | null;
}
export interface ProductVariantCreateData_product_productType_selectionVariantAttributes_values_edges {
export interface ProductVariantCreateData_product_productType_selectionVariantAttributes_choices_edges {
__typename: "AttributeValueCountableEdge";
cursor: string;
node: ProductVariantCreateData_product_productType_selectionVariantAttributes_values_edges_node;
node: ProductVariantCreateData_product_productType_selectionVariantAttributes_choices_edges_node;
}
export interface ProductVariantCreateData_product_productType_selectionVariantAttributes_values {
export interface ProductVariantCreateData_product_productType_selectionVariantAttributes_choices {
__typename: "AttributeValueCountableConnection";
pageInfo: ProductVariantCreateData_product_productType_selectionVariantAttributes_values_pageInfo;
edges: ProductVariantCreateData_product_productType_selectionVariantAttributes_values_edges[];
pageInfo: ProductVariantCreateData_product_productType_selectionVariantAttributes_choices_pageInfo;
edges: ProductVariantCreateData_product_productType_selectionVariantAttributes_choices_edges[];
}
export interface ProductVariantCreateData_product_productType_selectionVariantAttributes {
@ -73,10 +73,10 @@ export interface ProductVariantCreateData_product_productType_selectionVariantAt
entityType: AttributeEntityTypeEnum | null;
valueRequired: boolean;
unit: MeasurementUnitsEnum | null;
values: ProductVariantCreateData_product_productType_selectionVariantAttributes_values | null;
choices: ProductVariantCreateData_product_productType_selectionVariantAttributes_choices | null;
}
export interface ProductVariantCreateData_product_productType_nonSelectionVariantAttributes_values_pageInfo {
export interface ProductVariantCreateData_product_productType_nonSelectionVariantAttributes_choices_pageInfo {
__typename: "PageInfo";
endCursor: string | null;
hasNextPage: boolean;
@ -84,32 +84,32 @@ export interface ProductVariantCreateData_product_productType_nonSelectionVarian
startCursor: string | null;
}
export interface ProductVariantCreateData_product_productType_nonSelectionVariantAttributes_values_edges_node_file {
export interface ProductVariantCreateData_product_productType_nonSelectionVariantAttributes_choices_edges_node_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductVariantCreateData_product_productType_nonSelectionVariantAttributes_values_edges_node {
export interface ProductVariantCreateData_product_productType_nonSelectionVariantAttributes_choices_edges_node {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: ProductVariantCreateData_product_productType_nonSelectionVariantAttributes_values_edges_node_file | null;
file: ProductVariantCreateData_product_productType_nonSelectionVariantAttributes_choices_edges_node_file | null;
reference: string | null;
richText: any | null;
}
export interface ProductVariantCreateData_product_productType_nonSelectionVariantAttributes_values_edges {
export interface ProductVariantCreateData_product_productType_nonSelectionVariantAttributes_choices_edges {
__typename: "AttributeValueCountableEdge";
cursor: string;
node: ProductVariantCreateData_product_productType_nonSelectionVariantAttributes_values_edges_node;
node: ProductVariantCreateData_product_productType_nonSelectionVariantAttributes_choices_edges_node;
}
export interface ProductVariantCreateData_product_productType_nonSelectionVariantAttributes_values {
export interface ProductVariantCreateData_product_productType_nonSelectionVariantAttributes_choices {
__typename: "AttributeValueCountableConnection";
pageInfo: ProductVariantCreateData_product_productType_nonSelectionVariantAttributes_values_pageInfo;
edges: ProductVariantCreateData_product_productType_nonSelectionVariantAttributes_values_edges[];
pageInfo: ProductVariantCreateData_product_productType_nonSelectionVariantAttributes_choices_pageInfo;
edges: ProductVariantCreateData_product_productType_nonSelectionVariantAttributes_choices_edges[];
}
export interface ProductVariantCreateData_product_productType_nonSelectionVariantAttributes {
@ -121,7 +121,7 @@ export interface ProductVariantCreateData_product_productType_nonSelectionVarian
entityType: AttributeEntityTypeEnum | null;
valueRequired: boolean;
unit: MeasurementUnitsEnum | null;
values: ProductVariantCreateData_product_productType_nonSelectionVariantAttributes_values | null;
choices: ProductVariantCreateData_product_productType_nonSelectionVariantAttributes_choices | null;
}
export interface ProductVariantCreateData_product_productType {

View file

@ -21,7 +21,7 @@ export interface ProductVariantDetails_productVariant_privateMetadata {
value: string;
}
export interface ProductVariantDetails_productVariant_selectionAttributes_attribute_values_pageInfo {
export interface ProductVariantDetails_productVariant_selectionAttributes_attribute_choices_pageInfo {
__typename: "PageInfo";
endCursor: string | null;
hasNextPage: boolean;
@ -29,32 +29,32 @@ export interface ProductVariantDetails_productVariant_selectionAttributes_attrib
startCursor: string | null;
}
export interface ProductVariantDetails_productVariant_selectionAttributes_attribute_values_edges_node_file {
export interface ProductVariantDetails_productVariant_selectionAttributes_attribute_choices_edges_node_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductVariantDetails_productVariant_selectionAttributes_attribute_values_edges_node {
export interface ProductVariantDetails_productVariant_selectionAttributes_attribute_choices_edges_node {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: ProductVariantDetails_productVariant_selectionAttributes_attribute_values_edges_node_file | null;
file: ProductVariantDetails_productVariant_selectionAttributes_attribute_choices_edges_node_file | null;
reference: string | null;
richText: any | null;
}
export interface ProductVariantDetails_productVariant_selectionAttributes_attribute_values_edges {
export interface ProductVariantDetails_productVariant_selectionAttributes_attribute_choices_edges {
__typename: "AttributeValueCountableEdge";
cursor: string;
node: ProductVariantDetails_productVariant_selectionAttributes_attribute_values_edges_node;
node: ProductVariantDetails_productVariant_selectionAttributes_attribute_choices_edges_node;
}
export interface ProductVariantDetails_productVariant_selectionAttributes_attribute_values {
export interface ProductVariantDetails_productVariant_selectionAttributes_attribute_choices {
__typename: "AttributeValueCountableConnection";
pageInfo: ProductVariantDetails_productVariant_selectionAttributes_attribute_values_pageInfo;
edges: ProductVariantDetails_productVariant_selectionAttributes_attribute_values_edges[];
pageInfo: ProductVariantDetails_productVariant_selectionAttributes_attribute_choices_pageInfo;
edges: ProductVariantDetails_productVariant_selectionAttributes_attribute_choices_edges[];
}
export interface ProductVariantDetails_productVariant_selectionAttributes_attribute {
@ -66,7 +66,7 @@ export interface ProductVariantDetails_productVariant_selectionAttributes_attrib
entityType: AttributeEntityTypeEnum | null;
valueRequired: boolean;
unit: MeasurementUnitsEnum | null;
values: ProductVariantDetails_productVariant_selectionAttributes_attribute_values | null;
choices: ProductVariantDetails_productVariant_selectionAttributes_attribute_choices | null;
}
export interface ProductVariantDetails_productVariant_selectionAttributes_values_file {
@ -91,7 +91,7 @@ export interface ProductVariantDetails_productVariant_selectionAttributes {
values: (ProductVariantDetails_productVariant_selectionAttributes_values | null)[];
}
export interface ProductVariantDetails_productVariant_nonSelectionAttributes_attribute_values_pageInfo {
export interface ProductVariantDetails_productVariant_nonSelectionAttributes_attribute_choices_pageInfo {
__typename: "PageInfo";
endCursor: string | null;
hasNextPage: boolean;
@ -99,32 +99,32 @@ export interface ProductVariantDetails_productVariant_nonSelectionAttributes_att
startCursor: string | null;
}
export interface ProductVariantDetails_productVariant_nonSelectionAttributes_attribute_values_edges_node_file {
export interface ProductVariantDetails_productVariant_nonSelectionAttributes_attribute_choices_edges_node_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductVariantDetails_productVariant_nonSelectionAttributes_attribute_values_edges_node {
export interface ProductVariantDetails_productVariant_nonSelectionAttributes_attribute_choices_edges_node {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: ProductVariantDetails_productVariant_nonSelectionAttributes_attribute_values_edges_node_file | null;
file: ProductVariantDetails_productVariant_nonSelectionAttributes_attribute_choices_edges_node_file | null;
reference: string | null;
richText: any | null;
}
export interface ProductVariantDetails_productVariant_nonSelectionAttributes_attribute_values_edges {
export interface ProductVariantDetails_productVariant_nonSelectionAttributes_attribute_choices_edges {
__typename: "AttributeValueCountableEdge";
cursor: string;
node: ProductVariantDetails_productVariant_nonSelectionAttributes_attribute_values_edges_node;
node: ProductVariantDetails_productVariant_nonSelectionAttributes_attribute_choices_edges_node;
}
export interface ProductVariantDetails_productVariant_nonSelectionAttributes_attribute_values {
export interface ProductVariantDetails_productVariant_nonSelectionAttributes_attribute_choices {
__typename: "AttributeValueCountableConnection";
pageInfo: ProductVariantDetails_productVariant_nonSelectionAttributes_attribute_values_pageInfo;
edges: ProductVariantDetails_productVariant_nonSelectionAttributes_attribute_values_edges[];
pageInfo: ProductVariantDetails_productVariant_nonSelectionAttributes_attribute_choices_pageInfo;
edges: ProductVariantDetails_productVariant_nonSelectionAttributes_attribute_choices_edges[];
}
export interface ProductVariantDetails_productVariant_nonSelectionAttributes_attribute {
@ -136,7 +136,7 @@ export interface ProductVariantDetails_productVariant_nonSelectionAttributes_att
entityType: AttributeEntityTypeEnum | null;
valueRequired: boolean;
unit: MeasurementUnitsEnum | null;
values: ProductVariantDetails_productVariant_nonSelectionAttributes_attribute_values | null;
choices: ProductVariantDetails_productVariant_nonSelectionAttributes_attribute_choices | null;
}
export interface ProductVariantDetails_productVariant_nonSelectionAttributes_values_file {

View file

@ -28,7 +28,7 @@ export interface VariantCreate_productVariantCreate_productVariant_privateMetada
value: string;
}
export interface VariantCreate_productVariantCreate_productVariant_selectionAttributes_attribute_values_pageInfo {
export interface VariantCreate_productVariantCreate_productVariant_selectionAttributes_attribute_choices_pageInfo {
__typename: "PageInfo";
endCursor: string | null;
hasNextPage: boolean;
@ -36,32 +36,32 @@ export interface VariantCreate_productVariantCreate_productVariant_selectionAttr
startCursor: string | null;
}
export interface VariantCreate_productVariantCreate_productVariant_selectionAttributes_attribute_values_edges_node_file {
export interface VariantCreate_productVariantCreate_productVariant_selectionAttributes_attribute_choices_edges_node_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface VariantCreate_productVariantCreate_productVariant_selectionAttributes_attribute_values_edges_node {
export interface VariantCreate_productVariantCreate_productVariant_selectionAttributes_attribute_choices_edges_node {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: VariantCreate_productVariantCreate_productVariant_selectionAttributes_attribute_values_edges_node_file | null;
file: VariantCreate_productVariantCreate_productVariant_selectionAttributes_attribute_choices_edges_node_file | null;
reference: string | null;
richText: any | null;
}
export interface VariantCreate_productVariantCreate_productVariant_selectionAttributes_attribute_values_edges {
export interface VariantCreate_productVariantCreate_productVariant_selectionAttributes_attribute_choices_edges {
__typename: "AttributeValueCountableEdge";
cursor: string;
node: VariantCreate_productVariantCreate_productVariant_selectionAttributes_attribute_values_edges_node;
node: VariantCreate_productVariantCreate_productVariant_selectionAttributes_attribute_choices_edges_node;
}
export interface VariantCreate_productVariantCreate_productVariant_selectionAttributes_attribute_values {
export interface VariantCreate_productVariantCreate_productVariant_selectionAttributes_attribute_choices {
__typename: "AttributeValueCountableConnection";
pageInfo: VariantCreate_productVariantCreate_productVariant_selectionAttributes_attribute_values_pageInfo;
edges: VariantCreate_productVariantCreate_productVariant_selectionAttributes_attribute_values_edges[];
pageInfo: VariantCreate_productVariantCreate_productVariant_selectionAttributes_attribute_choices_pageInfo;
edges: VariantCreate_productVariantCreate_productVariant_selectionAttributes_attribute_choices_edges[];
}
export interface VariantCreate_productVariantCreate_productVariant_selectionAttributes_attribute {
@ -73,7 +73,7 @@ export interface VariantCreate_productVariantCreate_productVariant_selectionAttr
entityType: AttributeEntityTypeEnum | null;
valueRequired: boolean;
unit: MeasurementUnitsEnum | null;
values: VariantCreate_productVariantCreate_productVariant_selectionAttributes_attribute_values | null;
choices: VariantCreate_productVariantCreate_productVariant_selectionAttributes_attribute_choices | null;
}
export interface VariantCreate_productVariantCreate_productVariant_selectionAttributes_values_file {
@ -98,7 +98,7 @@ export interface VariantCreate_productVariantCreate_productVariant_selectionAttr
values: (VariantCreate_productVariantCreate_productVariant_selectionAttributes_values | null)[];
}
export interface VariantCreate_productVariantCreate_productVariant_nonSelectionAttributes_attribute_values_pageInfo {
export interface VariantCreate_productVariantCreate_productVariant_nonSelectionAttributes_attribute_choices_pageInfo {
__typename: "PageInfo";
endCursor: string | null;
hasNextPage: boolean;
@ -106,32 +106,32 @@ export interface VariantCreate_productVariantCreate_productVariant_nonSelectionA
startCursor: string | null;
}
export interface VariantCreate_productVariantCreate_productVariant_nonSelectionAttributes_attribute_values_edges_node_file {
export interface VariantCreate_productVariantCreate_productVariant_nonSelectionAttributes_attribute_choices_edges_node_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface VariantCreate_productVariantCreate_productVariant_nonSelectionAttributes_attribute_values_edges_node {
export interface VariantCreate_productVariantCreate_productVariant_nonSelectionAttributes_attribute_choices_edges_node {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: VariantCreate_productVariantCreate_productVariant_nonSelectionAttributes_attribute_values_edges_node_file | null;
file: VariantCreate_productVariantCreate_productVariant_nonSelectionAttributes_attribute_choices_edges_node_file | null;
reference: string | null;
richText: any | null;
}
export interface VariantCreate_productVariantCreate_productVariant_nonSelectionAttributes_attribute_values_edges {
export interface VariantCreate_productVariantCreate_productVariant_nonSelectionAttributes_attribute_choices_edges {
__typename: "AttributeValueCountableEdge";
cursor: string;
node: VariantCreate_productVariantCreate_productVariant_nonSelectionAttributes_attribute_values_edges_node;
node: VariantCreate_productVariantCreate_productVariant_nonSelectionAttributes_attribute_choices_edges_node;
}
export interface VariantCreate_productVariantCreate_productVariant_nonSelectionAttributes_attribute_values {
export interface VariantCreate_productVariantCreate_productVariant_nonSelectionAttributes_attribute_choices {
__typename: "AttributeValueCountableConnection";
pageInfo: VariantCreate_productVariantCreate_productVariant_nonSelectionAttributes_attribute_values_pageInfo;
edges: VariantCreate_productVariantCreate_productVariant_nonSelectionAttributes_attribute_values_edges[];
pageInfo: VariantCreate_productVariantCreate_productVariant_nonSelectionAttributes_attribute_choices_pageInfo;
edges: VariantCreate_productVariantCreate_productVariant_nonSelectionAttributes_attribute_choices_edges[];
}
export interface VariantCreate_productVariantCreate_productVariant_nonSelectionAttributes_attribute {
@ -143,7 +143,7 @@ export interface VariantCreate_productVariantCreate_productVariant_nonSelectionA
entityType: AttributeEntityTypeEnum | null;
valueRequired: boolean;
unit: MeasurementUnitsEnum | null;
values: VariantCreate_productVariantCreate_productVariant_nonSelectionAttributes_attribute_values | null;
choices: VariantCreate_productVariantCreate_productVariant_nonSelectionAttributes_attribute_choices | null;
}
export interface VariantCreate_productVariantCreate_productVariant_nonSelectionAttributes_values_file {

View file

@ -28,7 +28,7 @@ export interface VariantUpdate_productVariantUpdate_productVariant_privateMetada
value: string;
}
export interface VariantUpdate_productVariantUpdate_productVariant_selectionAttributes_attribute_values_pageInfo {
export interface VariantUpdate_productVariantUpdate_productVariant_selectionAttributes_attribute_choices_pageInfo {
__typename: "PageInfo";
endCursor: string | null;
hasNextPage: boolean;
@ -36,32 +36,32 @@ export interface VariantUpdate_productVariantUpdate_productVariant_selectionAttr
startCursor: string | null;
}
export interface VariantUpdate_productVariantUpdate_productVariant_selectionAttributes_attribute_values_edges_node_file {
export interface VariantUpdate_productVariantUpdate_productVariant_selectionAttributes_attribute_choices_edges_node_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface VariantUpdate_productVariantUpdate_productVariant_selectionAttributes_attribute_values_edges_node {
export interface VariantUpdate_productVariantUpdate_productVariant_selectionAttributes_attribute_choices_edges_node {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: VariantUpdate_productVariantUpdate_productVariant_selectionAttributes_attribute_values_edges_node_file | null;
file: VariantUpdate_productVariantUpdate_productVariant_selectionAttributes_attribute_choices_edges_node_file | null;
reference: string | null;
richText: any | null;
}
export interface VariantUpdate_productVariantUpdate_productVariant_selectionAttributes_attribute_values_edges {
export interface VariantUpdate_productVariantUpdate_productVariant_selectionAttributes_attribute_choices_edges {
__typename: "AttributeValueCountableEdge";
cursor: string;
node: VariantUpdate_productVariantUpdate_productVariant_selectionAttributes_attribute_values_edges_node;
node: VariantUpdate_productVariantUpdate_productVariant_selectionAttributes_attribute_choices_edges_node;
}
export interface VariantUpdate_productVariantUpdate_productVariant_selectionAttributes_attribute_values {
export interface VariantUpdate_productVariantUpdate_productVariant_selectionAttributes_attribute_choices {
__typename: "AttributeValueCountableConnection";
pageInfo: VariantUpdate_productVariantUpdate_productVariant_selectionAttributes_attribute_values_pageInfo;
edges: VariantUpdate_productVariantUpdate_productVariant_selectionAttributes_attribute_values_edges[];
pageInfo: VariantUpdate_productVariantUpdate_productVariant_selectionAttributes_attribute_choices_pageInfo;
edges: VariantUpdate_productVariantUpdate_productVariant_selectionAttributes_attribute_choices_edges[];
}
export interface VariantUpdate_productVariantUpdate_productVariant_selectionAttributes_attribute {
@ -73,7 +73,7 @@ export interface VariantUpdate_productVariantUpdate_productVariant_selectionAttr
entityType: AttributeEntityTypeEnum | null;
valueRequired: boolean;
unit: MeasurementUnitsEnum | null;
values: VariantUpdate_productVariantUpdate_productVariant_selectionAttributes_attribute_values | null;
choices: VariantUpdate_productVariantUpdate_productVariant_selectionAttributes_attribute_choices | null;
}
export interface VariantUpdate_productVariantUpdate_productVariant_selectionAttributes_values_file {
@ -98,7 +98,7 @@ export interface VariantUpdate_productVariantUpdate_productVariant_selectionAttr
values: (VariantUpdate_productVariantUpdate_productVariant_selectionAttributes_values | null)[];
}
export interface VariantUpdate_productVariantUpdate_productVariant_nonSelectionAttributes_attribute_values_pageInfo {
export interface VariantUpdate_productVariantUpdate_productVariant_nonSelectionAttributes_attribute_choices_pageInfo {
__typename: "PageInfo";
endCursor: string | null;
hasNextPage: boolean;
@ -106,32 +106,32 @@ export interface VariantUpdate_productVariantUpdate_productVariant_nonSelectionA
startCursor: string | null;
}
export interface VariantUpdate_productVariantUpdate_productVariant_nonSelectionAttributes_attribute_values_edges_node_file {
export interface VariantUpdate_productVariantUpdate_productVariant_nonSelectionAttributes_attribute_choices_edges_node_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface VariantUpdate_productVariantUpdate_productVariant_nonSelectionAttributes_attribute_values_edges_node {
export interface VariantUpdate_productVariantUpdate_productVariant_nonSelectionAttributes_attribute_choices_edges_node {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: VariantUpdate_productVariantUpdate_productVariant_nonSelectionAttributes_attribute_values_edges_node_file | null;
file: VariantUpdate_productVariantUpdate_productVariant_nonSelectionAttributes_attribute_choices_edges_node_file | null;
reference: string | null;
richText: any | null;
}
export interface VariantUpdate_productVariantUpdate_productVariant_nonSelectionAttributes_attribute_values_edges {
export interface VariantUpdate_productVariantUpdate_productVariant_nonSelectionAttributes_attribute_choices_edges {
__typename: "AttributeValueCountableEdge";
cursor: string;
node: VariantUpdate_productVariantUpdate_productVariant_nonSelectionAttributes_attribute_values_edges_node;
node: VariantUpdate_productVariantUpdate_productVariant_nonSelectionAttributes_attribute_choices_edges_node;
}
export interface VariantUpdate_productVariantUpdate_productVariant_nonSelectionAttributes_attribute_values {
export interface VariantUpdate_productVariantUpdate_productVariant_nonSelectionAttributes_attribute_choices {
__typename: "AttributeValueCountableConnection";
pageInfo: VariantUpdate_productVariantUpdate_productVariant_nonSelectionAttributes_attribute_values_pageInfo;
edges: VariantUpdate_productVariantUpdate_productVariant_nonSelectionAttributes_attribute_values_edges[];
pageInfo: VariantUpdate_productVariantUpdate_productVariant_nonSelectionAttributes_attribute_choices_pageInfo;
edges: VariantUpdate_productVariantUpdate_productVariant_nonSelectionAttributes_attribute_choices_edges[];
}
export interface VariantUpdate_productVariantUpdate_productVariant_nonSelectionAttributes_attribute {
@ -143,7 +143,7 @@ export interface VariantUpdate_productVariantUpdate_productVariant_nonSelectionA
entityType: AttributeEntityTypeEnum | null;
valueRequired: boolean;
unit: MeasurementUnitsEnum | null;
values: VariantUpdate_productVariantUpdate_productVariant_nonSelectionAttributes_attribute_values | null;
choices: VariantUpdate_productVariantUpdate_productVariant_nonSelectionAttributes_attribute_choices | null;
}
export interface VariantUpdate_productVariantUpdate_productVariant_nonSelectionAttributes_values_file {
@ -359,7 +359,7 @@ export interface VariantUpdate_productVariantStocksUpdate_productVariant_private
value: string;
}
export interface VariantUpdate_productVariantStocksUpdate_productVariant_selectionAttributes_attribute_values_pageInfo {
export interface VariantUpdate_productVariantStocksUpdate_productVariant_selectionAttributes_attribute_choices_pageInfo {
__typename: "PageInfo";
endCursor: string | null;
hasNextPage: boolean;
@ -367,32 +367,32 @@ export interface VariantUpdate_productVariantStocksUpdate_productVariant_selecti
startCursor: string | null;
}
export interface VariantUpdate_productVariantStocksUpdate_productVariant_selectionAttributes_attribute_values_edges_node_file {
export interface VariantUpdate_productVariantStocksUpdate_productVariant_selectionAttributes_attribute_choices_edges_node_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface VariantUpdate_productVariantStocksUpdate_productVariant_selectionAttributes_attribute_values_edges_node {
export interface VariantUpdate_productVariantStocksUpdate_productVariant_selectionAttributes_attribute_choices_edges_node {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: VariantUpdate_productVariantStocksUpdate_productVariant_selectionAttributes_attribute_values_edges_node_file | null;
file: VariantUpdate_productVariantStocksUpdate_productVariant_selectionAttributes_attribute_choices_edges_node_file | null;
reference: string | null;
richText: any | null;
}
export interface VariantUpdate_productVariantStocksUpdate_productVariant_selectionAttributes_attribute_values_edges {
export interface VariantUpdate_productVariantStocksUpdate_productVariant_selectionAttributes_attribute_choices_edges {
__typename: "AttributeValueCountableEdge";
cursor: string;
node: VariantUpdate_productVariantStocksUpdate_productVariant_selectionAttributes_attribute_values_edges_node;
node: VariantUpdate_productVariantStocksUpdate_productVariant_selectionAttributes_attribute_choices_edges_node;
}
export interface VariantUpdate_productVariantStocksUpdate_productVariant_selectionAttributes_attribute_values {
export interface VariantUpdate_productVariantStocksUpdate_productVariant_selectionAttributes_attribute_choices {
__typename: "AttributeValueCountableConnection";
pageInfo: VariantUpdate_productVariantStocksUpdate_productVariant_selectionAttributes_attribute_values_pageInfo;
edges: VariantUpdate_productVariantStocksUpdate_productVariant_selectionAttributes_attribute_values_edges[];
pageInfo: VariantUpdate_productVariantStocksUpdate_productVariant_selectionAttributes_attribute_choices_pageInfo;
edges: VariantUpdate_productVariantStocksUpdate_productVariant_selectionAttributes_attribute_choices_edges[];
}
export interface VariantUpdate_productVariantStocksUpdate_productVariant_selectionAttributes_attribute {
@ -404,7 +404,7 @@ export interface VariantUpdate_productVariantStocksUpdate_productVariant_selecti
entityType: AttributeEntityTypeEnum | null;
valueRequired: boolean;
unit: MeasurementUnitsEnum | null;
values: VariantUpdate_productVariantStocksUpdate_productVariant_selectionAttributes_attribute_values | null;
choices: VariantUpdate_productVariantStocksUpdate_productVariant_selectionAttributes_attribute_choices | null;
}
export interface VariantUpdate_productVariantStocksUpdate_productVariant_selectionAttributes_values_file {
@ -429,7 +429,7 @@ export interface VariantUpdate_productVariantStocksUpdate_productVariant_selecti
values: (VariantUpdate_productVariantStocksUpdate_productVariant_selectionAttributes_values | null)[];
}
export interface VariantUpdate_productVariantStocksUpdate_productVariant_nonSelectionAttributes_attribute_values_pageInfo {
export interface VariantUpdate_productVariantStocksUpdate_productVariant_nonSelectionAttributes_attribute_choices_pageInfo {
__typename: "PageInfo";
endCursor: string | null;
hasNextPage: boolean;
@ -437,32 +437,32 @@ export interface VariantUpdate_productVariantStocksUpdate_productVariant_nonSele
startCursor: string | null;
}
export interface VariantUpdate_productVariantStocksUpdate_productVariant_nonSelectionAttributes_attribute_values_edges_node_file {
export interface VariantUpdate_productVariantStocksUpdate_productVariant_nonSelectionAttributes_attribute_choices_edges_node_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface VariantUpdate_productVariantStocksUpdate_productVariant_nonSelectionAttributes_attribute_values_edges_node {
export interface VariantUpdate_productVariantStocksUpdate_productVariant_nonSelectionAttributes_attribute_choices_edges_node {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: VariantUpdate_productVariantStocksUpdate_productVariant_nonSelectionAttributes_attribute_values_edges_node_file | null;
file: VariantUpdate_productVariantStocksUpdate_productVariant_nonSelectionAttributes_attribute_choices_edges_node_file | null;
reference: string | null;
richText: any | null;
}
export interface VariantUpdate_productVariantStocksUpdate_productVariant_nonSelectionAttributes_attribute_values_edges {
export interface VariantUpdate_productVariantStocksUpdate_productVariant_nonSelectionAttributes_attribute_choices_edges {
__typename: "AttributeValueCountableEdge";
cursor: string;
node: VariantUpdate_productVariantStocksUpdate_productVariant_nonSelectionAttributes_attribute_values_edges_node;
node: VariantUpdate_productVariantStocksUpdate_productVariant_nonSelectionAttributes_attribute_choices_edges_node;
}
export interface VariantUpdate_productVariantStocksUpdate_productVariant_nonSelectionAttributes_attribute_values {
export interface VariantUpdate_productVariantStocksUpdate_productVariant_nonSelectionAttributes_attribute_choices {
__typename: "AttributeValueCountableConnection";
pageInfo: VariantUpdate_productVariantStocksUpdate_productVariant_nonSelectionAttributes_attribute_values_pageInfo;
edges: VariantUpdate_productVariantStocksUpdate_productVariant_nonSelectionAttributes_attribute_values_edges[];
pageInfo: VariantUpdate_productVariantStocksUpdate_productVariant_nonSelectionAttributes_attribute_choices_pageInfo;
edges: VariantUpdate_productVariantStocksUpdate_productVariant_nonSelectionAttributes_attribute_choices_edges[];
}
export interface VariantUpdate_productVariantStocksUpdate_productVariant_nonSelectionAttributes_attribute {
@ -474,7 +474,7 @@ export interface VariantUpdate_productVariantStocksUpdate_productVariant_nonSele
entityType: AttributeEntityTypeEnum | null;
valueRequired: boolean;
unit: MeasurementUnitsEnum | null;
values: VariantUpdate_productVariantStocksUpdate_productVariant_nonSelectionAttributes_attribute_values | null;
choices: VariantUpdate_productVariantStocksUpdate_productVariant_nonSelectionAttributes_attribute_choices | null;
}
export interface VariantUpdate_productVariantStocksUpdate_productVariant_nonSelectionAttributes_values_file {

View file

@ -89,7 +89,7 @@ export function getAttributeInputFromAttributes(
entityType: attribute.entityType,
inputType: attribute.inputType,
isRequired: attribute.valueRequired,
values: mapEdgesToItems(attribute.values),
values: mapEdgesToItems(attribute.choices),
unit: attribute.unit,
variantAttributeScope
},
@ -109,7 +109,7 @@ export function getAttributeInputFromSelectedAttributes(
inputType: attribute.attribute.inputType,
isRequired: attribute.attribute.valueRequired,
selectedValues: attribute.values,
values: mapEdgesToItems(attribute.attribute.values),
values: mapEdgesToItems(attribute.attribute.choices),
unit: attribute.attribute.unit,
variantAttributeScope
},

View file

@ -103,17 +103,17 @@ export const ProductCreateView: React.FC<ProductCreateProps> = ({ params }) => {
} = useProductSearch({
variables: DEFAULT_INITIAL_SEARCH_DATA
});
const [selectedAttribute, setSelectedAttribute] = useState<string>();
const [focusedAttribute, setFocusedAttribute] = useState<string>();
const {
loadMore: loadMoreAttributeValues,
search: searchAttributeValues,
result: searchAttributeValuesOpts
} = useAttributeValueSearch({
variables: {
id: selectedAttribute,
id: focusedAttribute,
...DEFAULT_INITIAL_SEARCH_DATA
},
skip: !selectedAttribute
skip: !focusedAttribute
});
const warehouses = useWarehouseList({
displayLoader: true,
@ -348,7 +348,7 @@ export const ProductCreateView: React.FC<ProductCreateProps> = ({ params }) => {
onCloseDialog={() => navigate(productAddUrl())}
selectedProductType={selectedProductType?.productType}
onSelectProductType={id => setSelectedProductTypeId(id)}
onAttributeSelect={setSelectedAttribute}
onAttributeFocus={setFocusedAttribute}
/>
</>
);

View file

@ -141,17 +141,17 @@ export const ProductUpdate: React.FC<ProductUpdateProps> = ({ id, params }) => {
} = useProductSearch({
variables: DEFAULT_INITIAL_SEARCH_DATA
});
const [selectedAttribute, setSelectedAttribute] = useState<string>();
const [focusedAttribute, setFocusedAttribute] = useState<string>();
const {
loadMore: loadMoreAttributeValues,
search: searchAttributeValues,
result: searchAttributeValuesOpts
} = useAttributeValueSearch({
variables: {
id: selectedAttribute,
id: focusedAttribute,
...DEFAULT_INITIAL_SEARCH_DATA
},
skip: !selectedAttribute
skip: !focusedAttribute
});
const warehouses = useWarehouseList({
displayLoader: true,
@ -605,7 +605,7 @@ export const ProductUpdate: React.FC<ProductUpdateProps> = ({ id, params }) => {
fetchMoreReferenceProducts={fetchMoreReferenceProducts}
fetchMoreAttributeValues={fetchMoreAttributeValues}
onCloseDialog={() => navigate(productUrl(id))}
onAttributeSelect={setSelectedAttribute}
onAttributeFocus={setFocusedAttribute}
/>
<ActionDialog
open={params.action === "remove"}

View file

@ -23,6 +23,7 @@ import useShop from "@saleor/hooks/useShop";
import { commonMessages } from "@saleor/intl";
import { useProductVariantChannelListingUpdate } from "@saleor/products/mutations";
import { ProductVariantDetails_productVariant } from "@saleor/products/types/ProductVariantDetails";
import useAttributeValueSearch from "@saleor/searches/useAttributeValueSearch";
import usePageSearch from "@saleor/searches/usePageSearch";
import useProductSearch from "@saleor/searches/useProductSearch";
import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers";
@ -92,7 +93,8 @@ export const ProductVariant: React.FC<ProductUpdateProps> = ({
const { data, loading } = useProductVariantQuery({
displayLoader: true,
variables: {
id: variantId
id: variantId,
firstValues: 10
}
});
const [updateMetadata] = useMetadataUpdate({});
@ -254,7 +256,8 @@ export const ProductVariant: React.FC<ProductUpdateProps> = ({
sku: data.sku,
stocks: data.updateStocks.map(mapFormsetStockToStockInput),
trackInventory: data.trackInventory,
weight: weight(data.weight)
weight: weight(data.weight),
firstValues: 10
}
});
await handleSubmitChannels(data, variant);
@ -297,6 +300,18 @@ export const ProductVariant: React.FC<ProductUpdateProps> = ({
} = useProductSearch({
variables: DEFAULT_INITIAL_SEARCH_DATA
});
const [focusedAttribute, setFocusedAttribute] = useState<string>();
const {
loadMore: loadMoreAttributeValues,
search: searchAttributeValues,
result: searchAttributeValuesOpts
} = useAttributeValueSearch({
variables: {
id: focusedAttribute,
...DEFAULT_INITIAL_SEARCH_DATA
},
skip: !focusedAttribute
});
const fetchMoreReferencePages = {
hasMore: searchPagesOpts.data?.search?.pageInfo?.hasNextPage,
@ -308,6 +323,16 @@ export const ProductVariant: React.FC<ProductUpdateProps> = ({
loading: searchProductsOpts.loading,
onFetchMore: loadMoreProducts
};
const fetchMoreAttributeValues = {
hasMore: !!searchAttributeValuesOpts.data?.attribute?.choices?.pageInfo
?.hasNextPage,
loading: !!searchAttributeValuesOpts.loading,
onFetchMore: loadMoreAttributeValues
};
const attributeValues = mapEdgesToItems(
searchAttributeValuesOpts?.data?.attribute.choices
);
return (
<>
@ -316,6 +341,7 @@ export const ProductVariant: React.FC<ProductUpdateProps> = ({
defaultWeightUnit={shop?.defaultWeightUnit}
defaultVariantId={data?.productVariant.product.defaultVariant?.id}
errors={errors}
attributeValues={attributeValues}
channels={channels}
channelErrors={
updateChannelsOpts?.data?.productVariantChannelListingUpdate
@ -351,9 +377,12 @@ export const ProductVariant: React.FC<ProductUpdateProps> = ({
fetchMoreReferencePages={fetchMoreReferencePages}
fetchReferenceProducts={searchProducts}
fetchMoreReferenceProducts={fetchMoreReferenceProducts}
fetchAttributeValues={searchAttributeValues}
fetchMoreAttributeValues={fetchMoreAttributeValues}
onCloseDialog={() =>
navigate(productVariantEditUrl(productId, variantId))
}
onAttributeFocus={setFocusedAttribute}
/>
<ProductVariantDeleteDialog
confirmButtonState={deleteVariantOpts.status}

View file

@ -11,6 +11,7 @@ import { DEFAULT_INITIAL_SEARCH_DATA } from "@saleor/config";
import { useFileUploadMutation } from "@saleor/files/mutations";
import useNavigator from "@saleor/hooks/useNavigator";
import useShop from "@saleor/hooks/useShop";
import useAttributeValueSearch from "@saleor/searches/useAttributeValueSearch";
import usePageSearch from "@saleor/searches/usePageSearch";
import useProductSearch from "@saleor/searches/useProductSearch";
import createMetadataCreateHandler from "@saleor/utils/handlers/metadataCreateHandler";
@ -21,7 +22,7 @@ import {
} from "@saleor/utils/metadata/updateMetadata";
import { useWarehouseList } from "@saleor/warehouses/queries";
import { warehouseAddPath } from "@saleor/warehouses/urls";
import React from "react";
import React, { useState } from "react";
import { useIntl } from "react-intl";
import { weight } from "../../misc";
@ -62,7 +63,10 @@ export const ProductVariant: React.FC<ProductVariantCreateProps> = ({
const { data, loading: productLoading } = useProductVariantCreateQuery({
displayLoader: true,
variables: { id: productId }
variables: {
id: productId,
firstValues: 10
}
});
const [uploadFile, uploadFileOpts] = useFileUploadMutation({});
@ -126,7 +130,8 @@ export const ProductVariant: React.FC<ProductVariantCreateProps> = ({
})),
trackInventory: true,
weight: weight(formData.weight)
}
},
firstValues: 10
}
});
const id = result.data?.productVariantCreate?.productVariant?.id;
@ -163,6 +168,18 @@ export const ProductVariant: React.FC<ProductVariantCreateProps> = ({
} = useProductSearch({
variables: DEFAULT_INITIAL_SEARCH_DATA
});
const [focusedAttribute, setFocusedAttribute] = useState<string>();
const {
loadMore: loadMoreAttributeValues,
search: searchAttributeValues,
result: searchAttributeValuesOpts
} = useAttributeValueSearch({
variables: {
id: focusedAttribute,
...DEFAULT_INITIAL_SEARCH_DATA
},
skip: !focusedAttribute
});
const fetchMoreReferencePages = {
hasMore: searchPagesOpts.data?.search?.pageInfo?.hasNextPage,
@ -174,6 +191,16 @@ export const ProductVariant: React.FC<ProductVariantCreateProps> = ({
loading: searchProductsOpts.loading,
onFetchMore: loadMoreProducts
};
const fetchMoreAttributeValues = {
hasMore: !!searchAttributeValuesOpts.data?.attribute?.choices?.pageInfo
?.hasNextPage,
loading: !!searchAttributeValuesOpts.loading,
onFetchMore: loadMoreAttributeValues
};
const attributeValues = mapEdgesToItems(
searchAttributeValuesOpts?.data?.attribute.choices
);
const disableForm =
productLoading ||
@ -198,6 +225,7 @@ export const ProductVariant: React.FC<ProductVariantCreateProps> = ({
description: "header"
})}
product={data?.product}
attributeValues={attributeValues}
onBack={handleBack}
onSubmit={handleSubmit}
onVariantClick={handleVariantClick}
@ -216,7 +244,10 @@ export const ProductVariant: React.FC<ProductVariantCreateProps> = ({
fetchMoreReferencePages={fetchMoreReferencePages}
fetchReferenceProducts={searchProducts}
fetchMoreReferenceProducts={fetchMoreReferenceProducts}
fetchAttributeValues={searchAttributeValues}
fetchMoreAttributeValues={fetchMoreAttributeValues}
onCloseDialog={() => navigate(productVariantAddUrl(productId))}
onAttributeFocus={setFocusedAttribute}
/>
</>
);

View file

@ -1,12 +1,14 @@
import { useShopLimitsQuery } from "@saleor/components/Shop/query";
import { WindowTitle } from "@saleor/components/WindowTitle";
import { DEFAULT_INITIAL_SEARCH_DATA } from "@saleor/config";
import useNavigator from "@saleor/hooks/useNavigator";
import useNotifier from "@saleor/hooks/useNotifier";
import { useProductVariantBulkCreateMutation } from "@saleor/products/mutations";
import { useCreateMultipleVariantsData } from "@saleor/products/queries";
import { productUrl } from "@saleor/products/urls";
import useAttributeValueSearch from "@saleor/searches/useAttributeValueSearch";
import { mapEdgesToItems } from "@saleor/utils/maps";
import React from "react";
import React, { useState } from "react";
import { useIntl } from "react-intl";
import ProductVariantCreatorPage from "../../components/ProductVariantCreatorPage";
@ -23,7 +25,10 @@ const ProductVariantCreator: React.FC<ProductVariantCreatorProps> = ({
const intl = useIntl();
const { data } = useCreateMultipleVariantsData({
displayLoader: true,
variables: { id }
variables: {
id,
firstValues: 10
}
});
const [
bulkProductVariantCreate,
@ -48,6 +53,30 @@ const ProductVariantCreator: React.FC<ProductVariantCreatorProps> = ({
}
});
const [focusedAttribute, setFocusedAttribute] = useState<string>();
const {
loadMore: loadMoreAttributeValues,
search: searchAttributeValues,
result: searchAttributeValuesOpts
} = useAttributeValueSearch({
variables: {
id: focusedAttribute,
...DEFAULT_INITIAL_SEARCH_DATA
},
skip: !focusedAttribute
});
const fetchMoreAttributeValues = {
hasMore: !!searchAttributeValuesOpts.data?.attribute?.choices?.pageInfo
?.hasNextPage,
loading: !!searchAttributeValuesOpts.loading,
onFetchMore: loadMoreAttributeValues
};
const attributeValues = mapEdgesToItems(
searchAttributeValuesOpts?.data?.attribute.choices
);
return (
<>
<WindowTitle
@ -67,12 +96,10 @@ const ProductVariantCreator: React.FC<ProductVariantCreatorProps> = ({
name: listing.channel.name,
price: ""
}))}
attributes={
data?.product?.productType?.variantAttributes?.map(attr => ({
...attr,
choices: attr.values
})) || []
}
attributes={data?.product?.productType?.variantAttributes || []}
attributeValues={attributeValues}
fetchAttributeValues={searchAttributeValues}
fetchMoreAttributeValues={fetchMoreAttributeValues}
limits={limitOpts.data?.shop?.limits}
onSubmit={inputs =>
bulkProductVariantCreate({
@ -80,6 +107,7 @@ const ProductVariantCreator: React.FC<ProductVariantCreatorProps> = ({
})
}
warehouses={mapEdgesToItems(data?.warehouses)}
onAttributeFocus={setFocusedAttribute}
/>
</>
);

File diff suppressed because it is too large Load diff

View file

@ -56,7 +56,7 @@ storiesOf("Views / Products / Create product", module)
onAssignReferencesClick={() => undefined}
onCloseDialog={() => undefined}
onSelectProductType={() => undefined}
onAttributeSelect={() => undefined}
onAttributeFocus={() => undefined}
/>
))
.add("When loading", () => (
@ -93,7 +93,7 @@ storiesOf("Views / Products / Create product", module)
onAssignReferencesClick={() => undefined}
onCloseDialog={() => undefined}
onSelectProductType={() => undefined}
onAttributeSelect={() => undefined}
onAttributeFocus={() => undefined}
/>
))
.add("form errors", () => (
@ -145,6 +145,6 @@ storiesOf("Views / Products / Create product", module)
onAssignReferencesClick={() => undefined}
onCloseDialog={() => undefined}
onSelectProductType={() => undefined}
onAttributeSelect={() => undefined}
onAttributeFocus={() => undefined}
/>
));

View file

@ -70,7 +70,7 @@ const props: ProductUpdatePageProps = {
onVariantsAdd: () => undefined,
onWarehouseConfigure: () => undefined,
openChannelsModal: () => undefined,
onAttributeSelect: () => undefined,
onAttributeFocus: () => undefined,
placeholderImage,
product,
referencePages: [],

View file

@ -36,8 +36,11 @@ storiesOf("Views / Products / Create product variant", module)
onWarehouseConfigure={() => undefined}
referencePages={[]}
referenceProducts={[]}
attributeValues={[]}
fetchAttributeValues={() => undefined}
onAssignReferencesClick={() => undefined}
onCloseDialog={() => undefined}
onAttributeFocus={() => undefined}
/>
))
.add("with errors", () => (
@ -76,8 +79,11 @@ storiesOf("Views / Products / Create product variant", module)
onWarehouseConfigure={() => undefined}
referencePages={[]}
referenceProducts={[]}
attributeValues={[]}
fetchAttributeValues={() => undefined}
onAssignReferencesClick={() => undefined}
onCloseDialog={() => undefined}
onAttributeFocus={() => undefined}
/>
))
.add("when loading data", () => (
@ -97,8 +103,11 @@ storiesOf("Views / Products / Create product variant", module)
onWarehouseConfigure={() => undefined}
referencePages={[]}
referenceProducts={[]}
attributeValues={[]}
fetchAttributeValues={() => undefined}
onAssignReferencesClick={() => undefined}
onCloseDialog={() => undefined}
onAttributeFocus={() => undefined}
/>
))
.add("add first variant", () => (
@ -121,8 +130,11 @@ storiesOf("Views / Products / Create product variant", module)
onWarehouseConfigure={() => undefined}
referencePages={[]}
referenceProducts={[]}
attributeValues={[]}
fetchAttributeValues={() => undefined}
onAssignReferencesClick={() => undefined}
onCloseDialog={() => undefined}
onAttributeFocus={() => undefined}
/>
))
.add("no warehouses", () => (
@ -142,7 +154,10 @@ storiesOf("Views / Products / Create product variant", module)
onWarehouseConfigure={() => undefined}
referencePages={[]}
referenceProducts={[]}
attributeValues={[]}
fetchAttributeValues={() => undefined}
onAssignReferencesClick={() => undefined}
onCloseDialog={() => undefined}
onAttributeFocus={() => undefined}
/>
));

View file

@ -35,8 +35,11 @@ storiesOf("Views / Products / Product variant details", module)
onWarehouseConfigure={() => undefined}
referencePages={[]}
referenceProducts={[]}
attributeValues={[]}
fetchAttributeValues={() => undefined}
onAssignReferencesClick={() => undefined}
onCloseDialog={() => undefined}
onAttributeFocus={() => undefined}
/>
))
.add("when loading data", () => (
@ -61,8 +64,11 @@ storiesOf("Views / Products / Product variant details", module)
onWarehouseConfigure={() => undefined}
referencePages={[]}
referenceProducts={[]}
attributeValues={[]}
fetchAttributeValues={() => undefined}
onAssignReferencesClick={() => undefined}
onCloseDialog={() => undefined}
onAttributeFocus={() => undefined}
/>
))
.add("no warehouses", () => (
@ -86,8 +92,11 @@ storiesOf("Views / Products / Product variant details", module)
onWarehouseConfigure={() => undefined}
referencePages={[]}
referenceProducts={[]}
attributeValues={[]}
fetchAttributeValues={() => undefined}
onAssignReferencesClick={() => undefined}
onCloseDialog={() => undefined}
onAttributeFocus={() => undefined}
/>
))
.add("attribute errors", () => (
@ -139,7 +148,10 @@ storiesOf("Views / Products / Product variant details", module)
onWarehouseConfigure={() => undefined}
referencePages={[]}
referenceProducts={[]}
attributeValues={[]}
fetchAttributeValues={() => undefined}
onAssignReferencesClick={() => undefined}
onCloseDialog={() => undefined}
onAttributeFocus={() => undefined}
/>
));