Add prettier command and run it inside src folder (#3892)

This commit is contained in:
Krzysztof Żuraw 2023-07-11 08:34:08 +02:00 committed by GitHub
parent de098fd520
commit 03d9e92c97
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
68 changed files with 342 additions and 350 deletions

View file

@ -0,0 +1,5 @@
---
"saleor-dashboard": patch
---
Run prettier against source folder

View file

@ -330,7 +330,8 @@
"dep-status": "depcruise --config .dependency-cruiser.js src", "dep-status": "depcruise --config .dependency-cruiser.js src",
"chromatic": "chromatic --exit-zero-on-changes", "chromatic": "chromatic --exit-zero-on-changes",
"change:add": "changeset add", "change:add": "changeset add",
"release:prepare-main": "./scripts/prepare-main-after-release.sh" "release:prepare-main": "./scripts/prepare-main-after-release.sh",
"format:code": "prettier --ignore-unknown --write src/*"
}, },
"description": "![Saleor Dashboard](https://user-images.githubusercontent.com/44495184/185379472-2a204c0b-9b7a-4a3e-93c0-2cb85205ed5e.png)" "description": "![Saleor Dashboard](https://user-images.githubusercontent.com/44495184/185379472-2a204c0b-9b7a-4a3e-93c0-2cb85205ed5e.png)"
} }

View file

@ -13,7 +13,9 @@ export interface ResetPasswordSuccessPageProps {
onBack: () => void; onBack: () => void;
} }
const ResetPasswordSuccessPage: React.FC<ResetPasswordSuccessPageProps> = props => { const ResetPasswordSuccessPage: React.FC<
ResetPasswordSuccessPageProps
> = props => {
const { onBack } = props; const { onBack } = props;
const classes = useStyles(props); const classes = useStyles(props);

View file

@ -26,7 +26,8 @@ export const UserContextError = {
unknownLoginError: "unknownLoginError", unknownLoginError: "unknownLoginError",
} as const; } as const;
export type UserContextError = typeof UserContextError[keyof typeof UserContextError]; export type UserContextError =
(typeof UserContextError)[keyof typeof UserContextError];
export interface UserContext { export interface UserContext {
login: (username: string, password: string) => Promise<LoginData>; login: (username: string, password: string) => Promise<LoginData>;

View file

@ -307,7 +307,7 @@ export const createChannelsDataFromProduct = (productData?: ProductFragment) =>
listing => listing.channel.id === channel.id, listing => listing.channel.id === channel.id,
); );
// Comparing explicitly to false because `hasVariants` can be undefined // Comparing explicitly to false because `hasVariants` can be undefined
const isSimpleProduct = !(productData.productType?.hasVariants); const isSimpleProduct = !productData.productType?.hasVariants;
const haveVariantsChannelListings = productData.variants.some(variant => const haveVariantsChannelListings = productData.variants.some(variant =>
variant.channelListings.some( variant.channelListings.some(
listing => listing.channel.id === channel.id, listing => listing.channel.id === channel.id,

View file

@ -2,10 +2,12 @@ import { AddressTypeInput } from "@dashboard/customers/types";
import { FormChange } from "@dashboard/hooks/useForm"; import { FormChange } from "@dashboard/hooks/useForm";
import { ChangeEvent } from "react"; import { ChangeEvent } from "react";
export const createCountryHandler = ( export const createCountryHandler =
currentHandler: FormChange, (
set: (dataSet: Partial<AddressTypeInput>) => void, currentHandler: FormChange,
) => (event: ChangeEvent<any>) => { set: (dataSet: Partial<AddressTypeInput>) => void,
currentHandler(event); ) =>
set({ countryArea: "" }); (event: ChangeEvent<any>) => {
}; currentHandler(event);
set({ countryArea: "" });
};

View file

@ -13,7 +13,7 @@ export const Backlink = ({
return ( return (
<MacawBacklink<LinkType> <MacawBacklink<LinkType>
{...props} {...props}
component={(Link as unknown) as LinkType} component={Link as unknown as LinkType}
to={href} to={href}
/> />
); );

View file

@ -19,7 +19,9 @@ export interface ChannelsAvailabilityContentProps {
toggleAll?: (items: Channel[], selected: number) => void; toggleAll?: (items: Channel[], selected: number) => void;
} }
export const ChannelsAvailabilityContent: React.FC<ChannelsAvailabilityContentProps> = ({ export const ChannelsAvailabilityContent: React.FC<
ChannelsAvailabilityContentProps
> = ({
isSelected, isSelected,
channels, channels,
contentType = "", contentType = "",

View file

@ -1,7 +1,7 @@
import { filter } from "fuzzaldrin"; import { filter } from "fuzzaldrin";
import React from "react"; import React from "react";
export const useChannelsSearch = function<T extends { name: string }>( export const useChannelsSearch = function <T extends { name: string }>(
channels: T[], channels: T[],
) { ) {
const [query, onQueryChange] = React.useState(""); const [query, onQueryChange] = React.useState("");

View file

@ -28,11 +28,9 @@ export interface ChannelsAvailabilityContentProps {
onChange: (option: Channel) => void; onChange: (option: Channel) => void;
} }
const ChannelsAvailabilityContent: React.FC<ChannelsAvailabilityContentProps> = ({ const ChannelsAvailabilityContent: React.FC<
isChannelSelected, ChannelsAvailabilityContentProps
channels, > = ({ isChannelSelected, channels, onChange }) => {
onChange,
}) => {
const classes = useStyles({}); const classes = useStyles({});
return ( return (

View file

@ -86,7 +86,9 @@ export interface ChannelsAvailabilityContentProps {
hasAllSelected: boolean; hasAllSelected: boolean;
} }
export const ChannelsAvailabilityContentWrapper: React.FC<ChannelsAvailabilityContentProps> = ({ export const ChannelsAvailabilityContentWrapper: React.FC<
ChannelsAvailabilityContentProps
> = ({
contentType = "", contentType = "",
toggleAll, toggleAll,
toggleAllLabel, toggleAllLabel,

View file

@ -5,7 +5,9 @@
<img width="977" alt="image" src="https://user-images.githubusercontent.com/41952692/233042483-d2cb30f3-26b7-40b5-9d08-2ea42f7f0242.png"> <img width="977" alt="image" src="https://user-images.githubusercontent.com/41952692/233042483-d2cb30f3-26b7-40b5-9d08-2ea42f7f0242.png">
### Column types ### Column types
In datagrid views various types of columns are available. We can split them into two groups: In datagrid views various types of columns are available. We can split them into two groups:
- static columns - e. g. `id`, `name`, `created_at`. These columns are simple to set up as a static object. - static columns - e. g. `id`, `name`, `created_at`. These columns are simple to set up as a static object.
- dynamic columns - e.g. stocks, attributes, channels. These column values are not known in advance and must be fetched from the API. - dynamic columns - e.g. stocks, attributes, channels. These column values are not known in advance and must be fetched from the API.
@ -16,13 +18,17 @@ For dynamic columns, the naming convetion is as follows:
``` ```
column_name:column_id column_name:column_id
``` ```
For example: For example:
``` ```
attribute:QXR0cmlidXRlOjIx attribute:QXR0cmlidXRlOjIx
``` ```
### useColumns hook ### useColumns hook
`useColumns` is a custom hook that is used as single source of truth for both Datagrid and Column Picker. It returns an object with the following properties: `useColumns` is a custom hook that is used as single source of truth for both Datagrid and Column Picker. It returns an object with the following properties:
- visible columns - array of visible columns for the datagrid - visible columns - array of visible columns for the datagrid
- static columns - array of static columns for the column picker - static columns - array of static columns for the column picker
- dynamic columns - array of dynamic columns for the column picker - dynamic columns - array of dynamic columns for the column picker
@ -37,6 +43,7 @@ attribute:QXR0cmlidXRlOjIx
- dynamic column selection handler (for column picker) - dynamic column selection handler (for column picker)
In order to use this hook, you need to provide four things: In order to use this hook, you need to provide four things:
- `staticColumns` - array of static columns in datagrid-ready format (`AvailableColumns[]`) - `staticColumns` - array of static columns in datagrid-ready format (`AvailableColumns[]`)
- `columnCategories` - array of column categories - `columnCategories` - array of column categories
- state & setter of column settings which we get from `useListSettings` - state & setter of column settings which we get from `useListSettings`
@ -45,31 +52,32 @@ In order to use this hook, you need to provide four things:
## Adapting new views ## Adapting new views
### Column picker settings ### Column picker settings
Firstly, in the view file, we need to provide two settings object, one for the selected columns and one for the dynamic column settings. We should use `useColumnPickerSettings` and `useListSettings` hook for that. The first settings object manages columns selected for the datagrid (visible columns). The second manages state of seleceted dynamic columns (if we pick a value from left side of column picked, it is then displayed on the right side of the picker as dynamic column with togglable visibility). Toggling the visiblity saves the column in the first settings object. Firstly, in the view file, we need to provide two settings object, one for the selected columns and one for the dynamic column settings. We should use `useColumnPickerSettings` and `useListSettings` hook for that. The first settings object manages columns selected for the datagrid (visible columns). The second manages state of seleceted dynamic columns (if we pick a value from left side of column picked, it is then displayed on the right side of the picker as dynamic column with togglable visibility). Toggling the visiblity saves the column in the first settings object.
The reason why column picker settings object needs to be in the view file and cannot be integrated into internal logic of useColumns is because we use column picker settings in the query. We need to know which columns are selected in order to fetch the correct data from the API. The reason why column picker settings object needs to be in the view file and cannot be integrated into internal logic of useColumns is because we use column picker settings in the query. We need to know which columns are selected in order to fetch the correct data from the API.
```tsx ```tsx
const { columnPickerSettings, setDynamicColumnsSettings } = const { columnPickerSettings, setDynamicColumnsSettings } =
useColumnPickerSettings("PRODUCT_LIST"); useColumnPickerSettings("PRODUCT_LIST");
// Translates columnIDs to api IDs // Translates columnIDs to api IDs
const filteredColumnIds = columnPickerSettings const filteredColumnIds = columnPickerSettings
.filter(isAttributeColumnValue) .filter(isAttributeColumnValue)
.map(getAttributeIdFromColumnValue); .map(getAttributeIdFromColumnValue);
const gridAttributes = useGridAttributesQuery({ const gridAttributes = useGridAttributesQuery({
variables: { ids: filteredColumnIds }, variables: { ids: filteredColumnIds },
skip: filteredColumnIds.length === 0, skip: filteredColumnIds.length === 0,
}); });
``` ```
### Static columns adapter ### Static columns adapter
Writing an adapter for static columns is an easy task. We need to provide an array of static columns in datagrid-ready format (`AvailableColumns[]`). Writing an adapter for static columns is an easy task. We need to provide an array of static columns in datagrid-ready format (`AvailableColumns[]`).
For example: For example:
```tsx ```tsx
export const parseStaticColumnsForProductListView = (intl, emptyColumn, sort) => export const parseStaticColumnsForProductListView = (intl, emptyColumn, sort) =>
[ [
@ -94,17 +102,19 @@ export const parseStaticColumnsForProductListView = (intl, emptyColumn, sort) =>
Empty column is a special column that is used to add padding in the datagrid. It is filtered out by the column picker. Empty column is a special column that is used to add padding in the datagrid. It is filtered out by the column picker.
### Dynamic column adapter ### Dynamic column adapter
This function creates ColumnCategory[] object from available data.
This function creates ColumnCategory[] object from available data.
Creating a column category requires two queries per category. Let's say we want to have custom attributes as columns. We need Creating a column category requires two queries per category. Let's say we want to have custom attributes as columns. We need
- query which fetches all attributes - query which fetches all attributes
- query which fetches selected attributes - query which fetches selected attributes
We cannot rely on single query, because searching through attributes would influence already selected columns which are visible in the datagrid. We cannot rely on single query, because searching through attributes would influence already selected columns which are visible in the datagrid.
Example: Example:
```tsx ```tsx
export const parseDynamicColumnsForProductListView = ({ export const parseDynamicColumnsForProductListView = ({
attributesData, attributesData,
@ -138,9 +148,11 @@ export const parseDynamicColumnsForProductListView = ({
}, },
]; ];
``` ```
Here we only have 1 column category, attributes. `attributesData` is the result of the first query, `gridAttributesData` is the result of the second query. We also provide pagination props, which are used in the column picker. Here we only have 1 column category, attributes. `attributesData` is the result of the first query, `gridAttributesData` is the result of the second query. We also provide pagination props, which are used in the column picker.
Queries which are used in this case are for categories. Let's look at the first query: Queries which are used in this case are for categories. Let's look at the first query:
```tsx ```tsx
export const availableColumnAttribues = gql` export const availableColumnAttribues = gql`
query AvailableColumnAttributes( query AvailableColumnAttributes(
@ -170,9 +182,11 @@ export const availableColumnAttribues = gql`
} }
`; `;
``` ```
This query is used to fetch all **available** attributes. It is paginated and has a search filter and results are displayed in the left part of the column picker. This query is used to fetch all **available** attributes. It is paginated and has a search filter and results are displayed in the left part of the column picker.
The second query is similar, but it has a filter of IDs, which come from local storage settings (useColumnPickerSettngs): The second query is similar, but it has a filter of IDs, which come from local storage settings (useColumnPickerSettngs):
```tsx ```tsx
export const gridAttributes = gql` export const gridAttributes = gql`
query GridAttributes($ids: [ID!]!) { query GridAttributes($ids: [ID!]!) {
@ -187,10 +201,11 @@ export const gridAttributes = gql`
} }
`; `;
``` ```
Data of this query is displayed in the right part of the column picker, below the static columns. Data of this query is displayed in the right part of the column picker, below the static columns.
Here is the adapter for the dynamic columns inside the category: Here is the adapter for the dynamic columns inside the category:
```tsx ```tsx
export const parseAttributesColumns = ( export const parseAttributesColumns = (
attributes: RelayToFlat< attributes: RelayToFlat<
@ -210,4 +225,4 @@ export const parseAttributesColumns = (
})); }));
``` ```
With the dynamic column adapter written, we can now use the `useColumns` hook. With the dynamic column adapter written, we can now use the `useColumns` hook.

View file

@ -1,2 +1,2 @@
export { Condition } from "./Condition" export { Condition } from "./Condition";
export { type FilterContainer,FilterElement } from "./FilterElement" export { type FilterContainer, FilterElement } from "./FilterElement";

View file

@ -1,8 +1,8 @@
import { FilterContainer } from "./FilterElement"; import { FilterContainer } from "./FilterElement";
type QueryVars = type QueryVars =
| { OR: QueryVars, current?: FilterContainer[number] } | { OR: QueryVars; current?: FilterContainer[number] }
| { AND: QueryVars, current?: FilterContainer[number] } | { AND: QueryVars; current?: FilterContainer[number] };
export interface FilterValueProvider { export interface FilterValueProvider {
value: FilterContainer; value: FilterContainer;
@ -11,21 +11,24 @@ export interface FilterValueProvider {
persist: (newValue: FilterContainer) => void; persist: (newValue: FilterContainer) => void;
} }
const toNested = (p: QueryVars, current: FilterContainer[number]): QueryVars => { const toNested = (
p: QueryVars,
current: FilterContainer[number],
): QueryVars => {
if (typeof current !== "string") { if (typeof current !== "string") {
return { ...p, current } return { ...p, current };
} }
if (current === "AND") { if (current === "AND") {
return { AND: p } return { AND: p };
} }
if (current === "OR") { if (current === "OR") {
return { OR: p } return { OR: p };
} }
return p return p;
} };
export const createVariables = (filter: FilterContainer) => export const createVariables = (filter: FilterContainer) =>
filter.reduceRight(toNested, {} as QueryVars) filter.reduceRight(toNested, {} as QueryVars);

View file

@ -8,7 +8,7 @@ export interface FetchingParams {
attribute: Record<string, string[]>; attribute: Record<string, string[]>;
} }
type FetchingParamsKeys = keyof Omit<FetchingParams, "attribute"> type FetchingParamsKeys = keyof Omit<FetchingParams, "attribute">;
export const emptyFetchingParams: FetchingParams = { export const emptyFetchingParams: FetchingParams = {
category: [], category: [],
@ -21,10 +21,10 @@ export const emptyFetchingParams: FetchingParams = {
const unique = <T>(array: Iterable<T>) => Array.from(new Set(array)); const unique = <T>(array: Iterable<T>) => Array.from(new Set(array));
export const toFetchingParams = (p: FetchingParams, c: UrlToken) => { export const toFetchingParams = (p: FetchingParams, c: UrlToken) => {
const key = c.name as FetchingParamsKeys const key = c.name as FetchingParamsKeys;
if (!c.isAttribute() && !p[key]) { if (!c.isAttribute() && !p[key]) {
p[key] = [] p[key] = [];
} }
if (c.isAttribute() && !p.attribute[c.name]) { if (c.isAttribute() && !p.attribute[c.name]) {

View file

@ -35,9 +35,7 @@ const mapToTokens = (urlEntries: Array<ParsedQs | string>): TokenArray =>
return mapToTokens(entry); return mapToTokens(entry);
} }
return UrlToken.fromUrlEntry( return UrlToken.fromUrlEntry(UrlEntry.fromQs(entry));
UrlEntry.fromQs(entry)
);
}) as TokenArray; }) as TokenArray;
const tokenizeUrl = (urlParams: string) => { const tokenizeUrl = (urlParams: string) => {

View file

@ -9,11 +9,10 @@ const STATIC_TO_LOAD = ["category", "collection", "channel", "producttype"];
export const TokenType = { export const TokenType = {
ATTRIBUTE: "a", ATTRIBUTE: "a",
STATIC: "s" STATIC: "s",
} as const } as const;
export type TokenTypeValue = (typeof TokenType)[keyof typeof TokenType]
export type TokenTypeValue = (typeof TokenType)[keyof typeof TokenType];
export class UrlEntry { export class UrlEntry {
constructor(key: string, value: string | string[]) { constructor(key: string, value: string | string[]) {
@ -21,49 +20,54 @@ export class UrlEntry {
} }
public static fromQs(entry: ParsedQs) { public static fromQs(entry: ParsedQs) {
const key = Object.keys(entry)[0] const key = Object.keys(entry)[0];
const value = entry[key] as string | string[] const value = entry[key] as string | string[];
return new UrlEntry(key, value) return new UrlEntry(key, value);
} }
public static forAttribute (condition: ConditionSelected, paramName: string) { public static forAttribute(condition: ConditionSelected, paramName: string) {
return UrlEntry.fromConditionSelected(condition, paramName, TokenType.ATTRIBUTE) return UrlEntry.fromConditionSelected(
condition,
paramName,
TokenType.ATTRIBUTE,
);
} }
public static forStatic (condition: ConditionSelected, paramName: string) { public static forStatic(condition: ConditionSelected, paramName: string) {
return UrlEntry.fromConditionSelected(condition, paramName, TokenType.STATIC) return UrlEntry.fromConditionSelected(
condition,
paramName,
TokenType.STATIC,
);
} }
public getInfo () { public getInfo() {
const [key, value] = Object.entries(this)[0] as [ const [key, value] = Object.entries(this)[0] as [string, string | string[]];
string,
string | string[],
];
const [identifier, entryName] = key.split("."); const [identifier, entryName] = key.split(".");
const [type, control] = identifier.split("") as [TokenTypeValue, number]; const [type, control] = identifier.split("") as [TokenTypeValue, number];
const conditionKid = CONDITIONS[control] const conditionKid = CONDITIONS[control];
return { key, value, entryName, type, conditionKid } return { key, value, entryName, type, conditionKid };
} }
private static fromConditionSelected ( private static fromConditionSelected(
condition: ConditionSelected, condition: ConditionSelected,
paramName: string, paramName: string,
tokenSlug: TokenTypeValue tokenSlug: TokenTypeValue,
) { ) {
const { conditionValue } = condition; const { conditionValue } = condition;
const slug = slugFromConditionValue(condition.value) const slug = slugFromConditionValue(condition.value);
if (!conditionValue) { if (!conditionValue) {
return new UrlEntry(tokenSlug, slug) return new UrlEntry(tokenSlug, slug);
} }
const conditionIndex = CONDITIONS.findIndex( const conditionIndex = CONDITIONS.findIndex(
el => el === conditionValue.label, el => el === conditionValue.label,
); );
return new UrlEntry(`${tokenSlug}${conditionIndex}.${paramName}`, slug) return new UrlEntry(`${tokenSlug}${conditionIndex}.${paramName}`, slug);
} }
} }
@ -76,12 +80,7 @@ export class UrlToken {
) {} ) {}
public static fromUrlEntry(entry: UrlEntry) { public static fromUrlEntry(entry: UrlEntry) {
const { const { entryName, value, type, conditionKid } = entry.getInfo();
entryName,
value,
type,
conditionKid
} = entry.getInfo()
return new UrlToken(entryName, value, type, conditionKid); return new UrlToken(entryName, value, type, conditionKid);
} }

View file

@ -3,11 +3,11 @@ import useRouter from "use-react-router";
import { useInitialAPIState } from "../API/initialState/useInitalAPIState"; import { useInitialAPIState } from "../API/initialState/useInitalAPIState";
import { FilterContainer } from "../FilterElement"; import { FilterContainer } from "../FilterElement";
import { createVariables,FilterValueProvider } from "../FilterValueProvider"; import { createVariables, FilterValueProvider } from "../FilterValueProvider";
import { useTokenArray } from "./TokenArray"; import { useTokenArray } from "./TokenArray";
import { UrlEntry } from "./UrlToken"; import { UrlEntry } from "./UrlToken";
type Structure = Array<string | UrlEntry | Structure> type Structure = Array<string | UrlEntry | Structure>;
const prepareStructure = (filterValue: FilterContainer): Structure => const prepareStructure = (filterValue: FilterContainer): Structure =>
filterValue.map(f => { filterValue.map(f => {

View file

@ -1,29 +1,34 @@
import { useState } from "react"; import { useState } from "react";
import { FilterContainer,FilterElement } from "./FilterElement"; import { FilterContainer, FilterElement } from "./FilterElement";
type StateCallback = (el: FilterElement) => void type StateCallback = (el: FilterElement) => void;
type Element = FilterContainer[number] type Element = FilterContainer[number];
export const useContainerState = (initialValue: FilterContainer) => { export const useContainerState = (initialValue: FilterContainer) => {
const [value, setValue] = useState(initialValue); const [value, setValue] = useState(initialValue);
const isFilterElement = (elIndex: number, index: number, el: Element): el is FilterElement => { const isFilterElement = (
return elIndex === index && typeof el !== "string" && !Array.isArray(el) elIndex: number,
} index: number,
el: Element,
): el is FilterElement => {
return elIndex === index && typeof el !== "string" && !Array.isArray(el);
};
const updateFilterElement = (index: number, cb: StateCallback) => (el: Element, elIndex: number) => { const updateFilterElement =
if (isFilterElement(elIndex, index, el)) { (index: number, cb: StateCallback) => (el: Element, elIndex: number) => {
cb(el); if (isFilterElement(elIndex, index, el)) {
} cb(el);
}
return el; return el;
} };
const updateAt = (position: string, cb: StateCallback) => { const updateAt = (position: string, cb: StateCallback) => {
const index = parseInt(position, 10); const index = parseInt(position, 10);
setValue(v => v.map(updateFilterElement(index, cb))); setValue(v => v.map(updateFilterElement(index, cb)));
} };
const removeAt = (position: string) => { const removeAt = (position: string) => {
const index = parseInt(position, 10); const index = parseInt(position, 10);
@ -50,11 +55,10 @@ export const useContainerState = (initialValue: FilterContainer) => {
setValue(v => v.concat(newValue)); setValue(v => v.concat(newValue));
}; };
return { return {
createEmpty, createEmpty,
updateAt, updateAt,
removeAt, removeAt,
value, value,
} };
} };

View file

@ -19,15 +19,8 @@ interface ExternalLinkProps extends React.HTMLProps<HTMLAnchorElement> {
} }
const ExternalLink: React.FC<ExternalLinkProps> = props => { const ExternalLink: React.FC<ExternalLinkProps> = props => {
const { const { className, children, href, typographyProps, target, rel, ...rest } =
className, props;
children,
href,
typographyProps,
target,
rel,
...rest
} = props;
const classes = useStyles(props); const classes = useStyles(props);

View file

@ -16,9 +16,8 @@ const useStyles = makeStyles(
{ name: "FilterGroupLabel" }, { name: "FilterGroupLabel" },
); );
export type FilterGroupLabelProps< export type FilterGroupLabelProps<K extends string = string> =
K extends string = string, FilterFieldBaseProps<K>;
> = FilterFieldBaseProps<K>;
const FilterGroupLabel: React.FC<FilterGroupLabelProps> = ({ const FilterGroupLabel: React.FC<FilterGroupLabelProps> = ({
filter, filter,

View file

@ -45,11 +45,10 @@ export type FilterElementValueData =
export type IFilterElementMutableData = FilterElementCommonData & export type IFilterElementMutableData = FilterElementCommonData &
FilterElementValueData; FilterElementValueData;
export type IFilterElementMutableDataGeneric< export type IFilterElementMutableDataGeneric<T extends FieldType> =
T extends FieldType, T extends FieldType.keyValue
> = T extends FieldType.keyValue ? KeyValueFilterElementData & FilterElementCommonData
? KeyValueFilterElementData & FilterElementCommonData : RegularFilterElementData & FilterElementCommonData;
: RegularFilterElementData & FilterElementCommonData;
type FilterElementCommon<K extends string = string> = { type FilterElementCommon<K extends string = string> = {
autocomplete?: boolean; autocomplete?: boolean;
@ -68,13 +67,11 @@ type FilterElementCommon<K extends string = string> = {
export type FilterElement<K extends string = string> = FilterElementCommon<K> & export type FilterElement<K extends string = string> = FilterElementCommon<K> &
Partial<UnknownFilterElementData>; Partial<UnknownFilterElementData>;
export type FilterElementRegular< export type FilterElementRegular<K extends string = string> =
K extends string = string, FilterElementCommon<K> & RegularFilterElementData;
> = FilterElementCommon<K> & RegularFilterElementData;
export type FilterElementKeyValue< export type FilterElementKeyValue<K extends string = string> =
K extends string = string, FilterElementCommon<K> & KeyValueFilterElementData;
> = FilterElementCommon<K> & KeyValueFilterElementData;
export type FilterElementGeneric< export type FilterElementGeneric<
K extends string, K extends string,

View file

@ -20,7 +20,10 @@ export interface MetadataFormData {
privateMetadata: MetadataInput[]; privateMetadata: MetadataInput[];
} }
export type MetadataIdSchema = Record<string, { export type MetadataIdSchema = Record<
string,
{
metadata: MetadataInput[]; metadata: MetadataInput[];
privateMetadata: MetadataInput[]; privateMetadata: MetadataInput[];
}>; }
>;

View file

@ -92,10 +92,9 @@ const Navigator: React.FC<NavigatorProps> = ({ visible, setVisibility }) => {
description: "navigator notification", description: "navigator notification",
}, },
{ {
keyboardShortcut: keyboardShortcut: navigator.platform.toLowerCase().includes("mac")
navigator.platform.toLowerCase().includes("mac") ? "⌘+K"
? "⌘+K" : "Ctrl+K",
: "Ctrl+K",
}, },
), ),
title: intl.formatMessage({ title: intl.formatMessage({

View file

@ -8,9 +8,10 @@ import { findPriceSeparator, getCurrencyDecimalPoints } from "./utils";
export function usePriceField(currency: string, onChange: FormChange) { export function usePriceField(currency: string, onChange: FormChange) {
const minValue = 0; const minValue = 0;
const maxDecimalLength = useMemo(() => getCurrencyDecimalPoints(currency), [ const maxDecimalLength = useMemo(
currency, () => getCurrencyDecimalPoints(currency),
]); [currency],
);
const handleChange: FormChange = e => { const handleChange: FormChange = e => {
let value = e.target.value; let value = e.target.value;

View file

@ -48,14 +48,8 @@ export interface SortableChipsFieldProps extends SortableContainerProps {
} }
const SortableChipsField: React.FC<SortableChipsFieldProps> = props => { const SortableChipsField: React.FC<SortableChipsFieldProps> = props => {
const { const { loading, values, error, helperText, onValueDelete, onValueReorder } =
loading, props;
values,
error,
helperText,
onValueDelete,
onValueReorder,
} = props;
const classes = useStyles(props); const classes = useStyles(props);
const handleSortStart = () => { const handleSortStart = () => {

View file

@ -12,12 +12,9 @@ interface DeleteWarningDialogConsentContentProps {
onConsentChange: (value: boolean) => void; onConsentChange: (value: boolean) => void;
} }
const DeleteWarningDialogConsentContent: React.FC<DeleteWarningDialogConsentContentProps> = ({ const DeleteWarningDialogConsentContent: React.FC<
description, DeleteWarningDialogConsentContentProps
consentLabel, > = ({ description, consentLabel, isConsentChecked, onConsentChange }) => {
isConsentChecked,
onConsentChange,
}) => {
const classes = useStyles(); const classes = useStyles();
const handleConsentChange = ({ target }: ChangeEvent<any>) => const handleConsentChange = ({ target }: ChangeEvent<any>) =>

View file

@ -51,10 +51,8 @@ export const customerAddUrl = customerAddPath;
export const customerAddressesPath = (id: string) => export const customerAddressesPath = (id: string) =>
urlJoin(customerPath(id), "addresses"); urlJoin(customerPath(id), "addresses");
export type CustomerAddressesUrlDialog = "add" | "edit" | "remove"; export type CustomerAddressesUrlDialog = "add" | "edit" | "remove";
export type CustomerAddressesUrlQueryParams = Dialog< export type CustomerAddressesUrlQueryParams =
CustomerAddressesUrlDialog Dialog<CustomerAddressesUrlDialog> & SingleAction;
> &
SingleAction;
export const customerAddressesUrl = ( export const customerAddressesUrl = (
id: string, id: string,
params?: CustomerAddressesUrlQueryParams, params?: CustomerAddressesUrlQueryParams,

View file

@ -23,13 +23,12 @@ const getChannelMinAmountSpent = (
return channel.minSpent; return channel.minSpent;
}; };
const mapChannelToChannelInput = (formData: VoucherDetailsPageFormData) => ( const mapChannelToChannelInput =
channel: ChannelVoucherData, (formData: VoucherDetailsPageFormData) => (channel: ChannelVoucherData) => ({
) => ({ channelId: channel.id,
channelId: channel.id, discountValue: getChannelDiscountValue(channel, formData),
discountValue: getChannelDiscountValue(channel, formData), minAmountSpent: getChannelMinAmountSpent(channel, formData),
minAmountSpent: getChannelMinAmountSpent(channel, formData), });
});
const filterNotDiscountedChannel = ( const filterNotDiscountedChannel = (
channelInput: VoucherChannelListingAddInput, channelInput: VoucherChannelListingAddInput,

View file

@ -12,10 +12,9 @@ type GiftCardCreateRequiresActivationSectionProps = Pick<
"checked" | "onChange" "checked" | "onChange"
>; >;
const GiftCardCreateRequiresActivationSection: React.FC<GiftCardCreateRequiresActivationSectionProps> = ({ const GiftCardCreateRequiresActivationSection: React.FC<
checked, GiftCardCreateRequiresActivationSectionProps
onChange, > = ({ checked, onChange }) => (
}) => (
<ControlledCheckbox <ControlledCheckbox
name="requiresActivation" name="requiresActivation"
label={ label={

View file

@ -48,32 +48,30 @@ const useGiftCardActivateToggle = ({
refetchQueries: [GIFT_CARD_DETAILS_QUERY], refetchQueries: [GIFT_CARD_DETAILS_QUERY],
}); });
const [ const [giftCardDeactivate, giftCardDeactivateOpts] =
giftCardDeactivate, useGiftCardDeactivateMutation({
giftCardDeactivateOpts, onCompleted: data => {
] = useGiftCardDeactivateMutation({ const errors = data?.giftCardDeactivate?.errors;
onCompleted: data => {
const errors = data?.giftCardDeactivate?.errors; if (!!errors?.length) {
notify({
status: "error",
text: intl.formatMessage(commonErrorMessages.unknownError),
});
return;
}
if (!!errors?.length) {
notify({ notify({
status: "error", status: "success",
text: intl.formatMessage(commonErrorMessages.unknownError), text: intl.formatMessage(messages.successfullyDisabledTitle),
}); });
return;
}
notify({ if (!!onDeactivateActionComplete) {
status: "success", onDeactivateActionComplete();
text: intl.formatMessage(messages.successfullyDisabledTitle), }
}); },
refetchQueries: [GIFT_CARD_DETAILS_QUERY],
if (!!onDeactivateActionComplete) { });
onDeactivateActionComplete();
}
},
refetchQueries: [GIFT_CARD_DETAILS_QUERY],
});
const currentOpts = isActive ? giftCardDeactivateOpts : giftCardActivateOpts; const currentOpts = isActive ? giftCardDeactivateOpts : giftCardActivateOpts;

View file

@ -6,8 +6,7 @@ export enum GiftCardUpdatePageActionParamsEnum {
RESEND_CODE = "resend-code", RESEND_CODE = "resend-code",
} }
export type GiftCardUpdatePageUrlQueryParams = Dialog< export type GiftCardUpdatePageUrlQueryParams =
GiftCardUpdatePageActionParamsEnum Dialog<GiftCardUpdatePageActionParamsEnum>;
>;
export const PLACEHOLDER = "-"; export const PLACEHOLDER = "-";

View file

@ -13,10 +13,9 @@ interface GiftCardsListHeaderAlertContentProps {
giftCardProductsExist: boolean; giftCardProductsExist: boolean;
} }
const GiftCardsListHeaderAlertContent: React.FC<GiftCardsListHeaderAlertContentProps> = ({ const GiftCardsListHeaderAlertContent: React.FC<
giftCardProductTypesExist, GiftCardsListHeaderAlertContentProps
giftCardProductsExist, > = ({ giftCardProductTypesExist, giftCardProductsExist }) => {
}) => {
const classes = useStyles({}); const classes = useStyles({});
const giftCardProductTypeUrl = productTypeAddUrl({ const giftCardProductTypeUrl = productTypeAddUrl({

View file

@ -18,9 +18,9 @@ interface CustomerGiftCardsCardListItemProps {
giftCard: ExtendedGiftCard<CustomerGiftCardFragment>; giftCard: ExtendedGiftCard<CustomerGiftCardFragment>;
} }
const CustomerGiftCardsCardListItem: React.FC<CustomerGiftCardsCardListItemProps> = ({ const CustomerGiftCardsCardListItem: React.FC<
giftCard, CustomerGiftCardsCardListItemProps
}) => { > = ({ giftCard }) => {
const intl = useIntl(); const intl = useIntl();
const classes = useListWrapperStyles(); const classes = useListWrapperStyles();
const [openDeleteGiftCard, setOpenDeleteGiftCard] = useState(false); const [openDeleteGiftCard, setOpenDeleteGiftCard] = useState(false);

View file

@ -33,13 +33,11 @@ const GiftCardDeleteDialog: React.FC<GiftCardDeleteDialogProps> = ({
refetchQueries: [GIFT_CARD_LIST_QUERY, ...refetchQueries], refetchQueries: [GIFT_CARD_LIST_QUERY, ...refetchQueries],
}); });
const { const { onBulkDeleteGiftCards, bulkDeleteGiftCardOpts } =
onBulkDeleteGiftCards, useGiftCardBulkDelete({
bulkDeleteGiftCardOpts, onClose,
} = useGiftCardBulkDelete({ refetchQueries: [GIFT_CARD_LIST_QUERY, ...refetchQueries],
onClose, });
refetchQueries: [GIFT_CARD_LIST_QUERY, ...refetchQueries],
});
const dialogProps: Pick< const dialogProps: Pick<
ActionDialogProps, ActionDialogProps,

View file

@ -1,6 +1,6 @@
import { PermissionEnum } from "./types.generated"; import { PermissionEnum } from "./types.generated";
export interface Node { export interface Node {
id: string id: string;
} }
export type PrefixedPermissions = `PERMISSION_${PermissionEnum}`; export type PrefixedPermissions = `PERMISSION_${PermissionEnum}`;

View file

@ -3,7 +3,7 @@ import { FetchMoreProps, Search, SearchProps } from "@dashboard/types";
import { filter } from "fuzzaldrin"; import { filter } from "fuzzaldrin";
import React from "react"; import React from "react";
export const useChannelsSearch = function<T extends { name: string }>( export const useChannelsSearch = function <T extends { name: string }>(
channels: T[], channels: T[],
) { ) {
const [query, onQueryChange] = React.useState(""); const [query, onQueryChange] = React.useState("");

View file

@ -6,11 +6,11 @@ export const useServiceWorker = (timeout: number) => {
const registrationRef = useRef<ServiceWorkerRegistration>(); const registrationRef = useRef<ServiceWorkerRegistration>();
useEffect(() => { useEffect(() => {
const interval = (setInterval(() => { const interval = setInterval(() => {
if (registrationRef.current) { if (registrationRef.current) {
registrationRef.current.update(); registrationRef.current.update();
} }
}, timeout) as unknown) as number; }, timeout) as unknown as number;
return () => clearInterval(interval); return () => clearInterval(interval);
}, [timeout]); }, [timeout]);

View file

@ -9,9 +9,12 @@
<meta name="robots" content="noindex" /> <meta name="robots" content="noindex" />
<title>Sign in to the Saleor Dashboard</title> <title>Sign in to the Saleor Dashboard</title>
<meta name="description" content="Sign in to the Saleor Dashboard to manage your orders, payments, products and more."> <meta
name="description"
content="Sign in to the Saleor Dashboard to manage your orders, payments, products and more."
/>
<%- injectOgTags %> <%- injectOgTags %>
<script> <script>
window.__SALEOR_CONFIG__ = { window.__SALEOR_CONFIG__ = {

View file

@ -213,4 +213,4 @@ export const OrderChangeWarehouseDialog: React.FC<
); );
}; };
OrderChangeWarehouseDialog.displayName = "OrderChangeWarehouseDialog"; OrderChangeWarehouseDialog.displayName = "OrderChangeWarehouseDialog";
export default OrderChangeWarehouseDialog; export default OrderChangeWarehouseDialog;

View file

@ -11,9 +11,9 @@ export interface OrderChannelSectionCardProps {
channel?: Pick<ChannelFragment, "id" | "name">; channel?: Pick<ChannelFragment, "id" | "name">;
} }
export const OrderChannelSectionCard: React.FC<OrderChannelSectionCardProps> = ({ export const OrderChannelSectionCard: React.FC<
channel, OrderChannelSectionCardProps
}) => { > = ({ channel }) => {
const intl = useIntl(); const intl = useIntl();
return ( return (

View file

@ -11,9 +11,8 @@ export interface OrderCustomerChangeData {
changeActionOption: CustomerChangeActionEnum; changeActionOption: CustomerChangeActionEnum;
} }
type UseOrderCustomerChangeFormResult = CommonUseFormResult< type UseOrderCustomerChangeFormResult =
OrderCustomerChangeData CommonUseFormResult<OrderCustomerChangeData>;
>;
export interface OrderCustomerChangeFormProps { export interface OrderCustomerChangeFormProps {
children: (props: UseOrderCustomerChangeFormResult) => React.ReactNode; children: (props: UseOrderCustomerChangeFormResult) => React.ReactNode;

View file

@ -82,7 +82,10 @@ export interface OrderDetailsPageProps {
onInvoiceClick: (invoiceId: string) => any; onInvoiceClick: (invoiceId: string) => any;
onInvoiceGenerate: () => any; onInvoiceGenerate: () => any;
onInvoiceSend: (invoiceId: string) => any; onInvoiceSend: (invoiceId: string) => any;
onTransactionAction: (transactionId: string, actionType: TransactionActionEnum) => any; onTransactionAction: (
transactionId: string,
actionType: TransactionActionEnum,
) => any;
onAddManualTransaction: () => any; onAddManualTransaction: () => any;
onSubmit: (data: MetadataIdSchema) => SubmitPromise; onSubmit: (data: MetadataIdSchema) => SubmitPromise;
} }

View file

@ -137,7 +137,7 @@ export const OrderDraftDetailsDatagrid = ({
rowMarkers="none" rowMarkers="none"
columnSelect="none" columnSelect="none"
freezeColumns={2} freezeColumns={2}
verticalBorder={col => (col > 1)} verticalBorder={col => col > 1}
availableColumns={columns} availableColumns={columns}
emptyText={intl.formatMessage(messages.emptyText)} emptyText={intl.formatMessage(messages.emptyText)}
getCellContent={getCellContent} getCellContent={getCellContent}

View file

@ -14,7 +14,10 @@ import { OrderTransactionsWrapper } from "./OrderTransactionsWrapper";
export interface OrderPaymentOrTransactionProps { export interface OrderPaymentOrTransactionProps {
order: OrderDetailsFragment; order: OrderDetailsFragment;
shop: OrderDetailsQuery["shop"]; shop: OrderDetailsQuery["shop"];
onTransactionAction: (transactionId: string, actionType: TransactionActionEnum) => any; onTransactionAction: (
transactionId: string,
actionType: TransactionActionEnum,
) => any;
onPaymentCapture: () => any; onPaymentCapture: () => any;
onPaymentVoid: () => any; onPaymentVoid: () => any;
onPaymentRefund: () => any; onPaymentRefund: () => any;

View file

@ -20,7 +20,10 @@ import { getFilteredPayments } from "./utils";
interface OrderTransactionsWrapper { interface OrderTransactionsWrapper {
order: OrderDetailsFragment; order: OrderDetailsFragment;
shop: OrderDetailsQuery["shop"]; shop: OrderDetailsQuery["shop"];
onTransactionAction: (transactionId: string, actionType: TransactionActionEnum) => any; onTransactionAction: (
transactionId: string,
actionType: TransactionActionEnum,
) => any;
onPaymentCapture: () => any; onPaymentCapture: () => any;
onMarkAsPaid: () => any; onMarkAsPaid: () => any;
onPaymentVoid: () => any; onPaymentVoid: () => any;

View file

@ -16,9 +16,8 @@ export interface OrderSettingsFormData {
automaticallyFulfillNonShippableGiftCard: boolean; automaticallyFulfillNonShippableGiftCard: boolean;
} }
export type UseOrderSettingsFormResult = CommonUseFormResult< export type UseOrderSettingsFormResult =
OrderSettingsFormData CommonUseFormResult<OrderSettingsFormData>;
>;
export interface OrderSettingsFormProps { export interface OrderSettingsFormProps {
children: (props: UseOrderSettingsFormResult) => React.ReactNode; children: (props: UseOrderSettingsFormResult) => React.ReactNode;
orderSettings: OrderSettingsFragment; orderSettings: OrderSettingsFragment;

View file

@ -20,16 +20,10 @@ export function getFilterVariables(
}; };
} }
export const { export const { deleteFilterTab, getFilterTabs, saveFilterTab } =
deleteFilterTab, createFilterTabUtils<PageTypeListUrlFilters>(PAGE_TYPE_FILTERS_KEY);
getFilterTabs,
saveFilterTab,
} = createFilterTabUtils<PageTypeListUrlFilters>(PAGE_TYPE_FILTERS_KEY);
export const { export const { areFiltersApplied, getActiveFilters, getFiltersCurrentTab } =
areFiltersApplied, createFilterUtils<PageTypeListUrlQueryParams, PageTypeListUrlFilters>(
getActiveFilters, PageTypeListUrlFiltersEnum,
getFiltersCurrentTab, );
} = createFilterUtils<PageTypeListUrlQueryParams, PageTypeListUrlFilters>(
PageTypeListUrlFiltersEnum,
);

View file

@ -18,12 +18,11 @@ export enum PermissionGroupListUrlSortField {
name = "name", name = "name",
} }
export type PermissionGroupListUrlSort = Sort<PermissionGroupListUrlSortField>; export type PermissionGroupListUrlSort = Sort<PermissionGroupListUrlSortField>;
export type PermissionGroupListUrlQueryParams = Dialog< export type PermissionGroupListUrlQueryParams =
PermissionGroupListUrlDialog Dialog<PermissionGroupListUrlDialog> &
> & Pagination &
Pagination & PermissionGroupListUrlSort &
PermissionGroupListUrlSort & SingleAction;
SingleAction;
export const permissionGroupListUrl = ( export const permissionGroupListUrl = (
params?: PermissionGroupListUrlQueryParams, params?: PermissionGroupListUrlQueryParams,
) => permissionGroupListPath + "?" + stringifyQs(params); ) => permissionGroupListPath + "?" + stringifyQs(params);

View file

@ -8,7 +8,9 @@ import PluginDetailsChannelsCardContent, {
PluginDetailsChannelsCardProps, PluginDetailsChannelsCardProps,
} from "./PluginDetailsChannelsCardContent"; } from "./PluginDetailsChannelsCardContent";
const PluginDetailsChannelsCard: React.FC<PluginDetailsChannelsCardProps> = props => { const PluginDetailsChannelsCard: React.FC<
PluginDetailsChannelsCardProps
> = props => {
const intl = useIntl(); const intl = useIntl();
return ( return (

View file

@ -10,9 +10,9 @@ interface PluginChannelAvailabilityCellProps {
plugin: PluginBaseFragment; plugin: PluginBaseFragment;
} }
const PluginChannelAvailabilityCell: React.FC<PluginChannelAvailabilityCellProps> = ({ const PluginChannelAvailabilityCell: React.FC<
plugin, PluginChannelAvailabilityCellProps
}) => { > = ({ plugin }) => {
const [isPopupOpen, setIsPopupOpen] = useState(false); const [isPopupOpen, setIsPopupOpen] = useState(false);
const popupAnchor = useRef<HTMLTableCellElement>(null); const popupAnchor = useRef<HTMLTableCellElement>(null);

View file

@ -34,14 +34,8 @@ export interface PluginListProps
const totalColSpan = 10; const totalColSpan = 10;
const PluginList: React.FC<PluginListProps> = props => { const PluginList: React.FC<PluginListProps> = props => {
const { const { settings, plugins, disabled, sort, onSort, onUpdateListSettings } =
settings, props;
plugins,
disabled,
sort,
onSort,
onUpdateListSettings,
} = props;
const classes = useStyles(props); const classes = useStyles(props);
const navigate = useNavigator(); const navigate = useNavigator();
const intl = useIntl(); const intl = useIntl();

View file

@ -4,8 +4,7 @@ export const isPluginGlobal = (
globalConfiguration: PluginConfigurationBaseFragment, globalConfiguration: PluginConfigurationBaseFragment,
) => !!globalConfiguration; ) => !!globalConfiguration;
export const getConfigByChannelId = (channelIdToCompare: string) => ({ export const getConfigByChannelId =
channel, (channelIdToCompare: string) =>
}: { ({ channel }: { channel: { id: string } }) =>
channel: { id: string }; channel.id === channelIdToCompare;
}) => channel.id === channelIdToCompare;

View file

@ -1,14 +1,13 @@
import { ProductTypeKindEnum, TaxClassBaseFragment } from "@dashboard/graphql"; import { ProductTypeKindEnum, TaxClassBaseFragment } from "@dashboard/graphql";
import { ChangeEvent, FormChange } from "@dashboard/hooks/useForm"; import { ChangeEvent, FormChange } from "@dashboard/hooks/useForm";
export const makeProductTypeKindChangeHandler = ( export const makeProductTypeKindChangeHandler =
onChange: FormChange, (onChange: FormChange, onKindChange: (kind: ProductTypeKindEnum) => void) =>
onKindChange: (kind: ProductTypeKindEnum) => void, (event: React.ChangeEvent<any>) => {
) => (event: React.ChangeEvent<any>) => { const kind = event.target.value as ProductTypeKindEnum;
const kind = event.target.value as ProductTypeKindEnum; onKindChange(kind);
onKindChange(kind); onChange(event);
onChange(event); };
};
export function handleTaxClassChange( export function handleTaxClassChange(
event: ChangeEvent, event: ChangeEvent,

View file

@ -225,7 +225,7 @@ export const ProductCreatePage: React.FC<ProductCreatePageProps> = ({
attributeRichTextGetters, attributeRichTextGetters,
}) => { }) => {
// Comparing explicitly to false because `hasVariants` can be undefined // Comparing explicitly to false because `hasVariants` can be undefined
const isSimpleProduct = !(data.productType?.hasVariants); const isSimpleProduct = !data.productType?.hasVariants;
const errors = [...apiErrors, ...validationErrors]; const errors = [...apiErrors, ...validationErrors];

View file

@ -62,26 +62,25 @@ const ExportDialogSettings: React.FC<ExportDialogSettingsProps> = ({
const formErrors = getFormErrors(formFields, errors); const formErrors = getFormErrors(formFields, errors);
const productExportTypeChoices: Array<RadioGroupFieldChoice< const productExportTypeChoices: Array<RadioGroupFieldChoice<FileTypesEnum>> =
FileTypesEnum [
>> = [ {
{ label: intl.formatMessage({
label: intl.formatMessage({ id: "9Tl/bT",
id: "9Tl/bT", defaultMessage: "Spreadsheet for Excel, Numbers etc.",
defaultMessage: "Spreadsheet for Excel, Numbers etc.", description: "export items as spreadsheet",
description: "export items as spreadsheet", }),
}), value: FileTypesEnum.XLSX,
value: FileTypesEnum.XLSX, },
}, {
{ label: intl.formatMessage({
label: intl.formatMessage({ id: "li1BBk",
id: "li1BBk", defaultMessage: "Plain CSV file",
defaultMessage: "Plain CSV file", description: "export items as csv file",
description: "export items as csv file", }),
}), value: FileTypesEnum.CSV,
value: FileTypesEnum.CSV, },
}, ];
];
const exportScopeChoices = [ const exportScopeChoices = [
{ {

View file

@ -11,10 +11,9 @@ interface VariantDetailsChannelsAvailabilityCardContainerProps {
cardTitle?: React.ReactNode; cardTitle?: React.ReactNode;
} }
const VariantDetailsChannelsAvailabilityCardContainer: React.FC<VariantDetailsChannelsAvailabilityCardContainerProps> = ({ const VariantDetailsChannelsAvailabilityCardContainer: React.FC<
children, VariantDetailsChannelsAvailabilityCardContainerProps
cardTitle, > = ({ children, cardTitle }) => (
}) => (
<> <>
<Card> <Card>
{cardTitle || ( {cardTitle || (

View file

@ -19,7 +19,9 @@ interface ProductVariantCheckoutSettingsProps {
onChange: FormChange; onChange: FormChange;
} }
const ProductVariantCheckoutSettings: React.FC<ProductVariantCheckoutSettingsProps> = props => { const ProductVariantCheckoutSettings: React.FC<
ProductVariantCheckoutSettingsProps
> = props => {
const { data, disabled, errors, onChange } = props; const { data, disabled, errors, onChange } = props;
const intl = useIntl(); const intl = useIntl();

View file

@ -82,8 +82,9 @@ const ProductVariantMediaSelectDialog: React.FC<
className={clsx([ className={clsx([
classes.imageContainer, classes.imageContainer,
{ {
[classes.selectedImageContainer]: [classes.selectedImageContainer]: selectedMedia.includes(
selectedMedia.includes(mediaObj.id), mediaObj.id,
),
}, },
])} ])}
onClick={() => handleMediaSelect(mediaObj.id)} onClick={() => handleMediaSelect(mediaObj.id)}

View file

@ -33,7 +33,9 @@ export interface ShippingZoneSettingsCardProps {
loading: boolean; loading: boolean;
} }
export const ShippingZoneSettingsCard: React.FC<ShippingZoneSettingsCardProps> = ({ export const ShippingZoneSettingsCard: React.FC<
ShippingZoneSettingsCardProps
> = ({
formData, formData,
warehousesDisplayValues, warehousesDisplayValues,
hasMoreWarehouses, hasMoreWarehouses,

View file

@ -31,9 +31,9 @@ const ShippingZonesList: React.FC<RouteComponentProps<{}>> = ({ location }) => {
interface ShippingZoneDetailsRouteProps { interface ShippingZoneDetailsRouteProps {
id: string; id: string;
} }
const ShippingZoneDetails: React.FC<RouteComponentProps< const ShippingZoneDetails: React.FC<
ShippingZoneDetailsRouteProps RouteComponentProps<ShippingZoneDetailsRouteProps>
>> = ({ location, match }) => { > = ({ location, match }) => {
const qs = parseQs(location.search.substr(1)); const qs = parseQs(location.search.substr(1));
const params: ShippingZoneUrlQueryParams = qs; const params: ShippingZoneUrlQueryParams = qs;
return ( return (
@ -58,10 +58,12 @@ const RateCreate: React.FC<RouteComponentProps<{ id: string }>> = ({
); );
}; };
const RateUpdate: React.FC<RouteComponentProps<{ const RateUpdate: React.FC<
id: string; RouteComponentProps<{
rateId: string; id: string;
}>> = ({ match }) => { rateId: string;
}>
> = ({ match }) => {
const qs = parseQs(location.search.substr(1)); const qs = parseQs(location.search.substr(1));
const params: ShippingRateUrlQueryParams = qs; const params: ShippingRateUrlQueryParams = qs;

View file

@ -51,13 +51,12 @@ export type ShippingRateUrlQueryParams = Dialog<ShippingRateUrlDialog> &
SingleAction & SingleAction &
BulkAction; BulkAction;
export type ShippingRateCreateUrlDialog = ZipCodeRangeActions | ChannelsAction; export type ShippingRateCreateUrlDialog = ZipCodeRangeActions | ChannelsAction;
export type ShippingRateCreateUrlQueryParams = Dialog< export type ShippingRateCreateUrlQueryParams =
ShippingRateCreateUrlDialog Dialog<ShippingRateCreateUrlDialog> &
> & SingleAction &
SingleAction & Partial<{
Partial<{ type: ShippingMethodTypeEnum;
type: ShippingMethodTypeEnum; }>;
}>;
export const shippingRateCreatePath = (id: string) => export const shippingRateCreatePath = (id: string) =>
urlJoin(shippingZonePath(id), "add"); urlJoin(shippingZonePath(id), "add");

View file

@ -39,9 +39,8 @@ export type StaffMemberDetailsUrlDialog =
| "change-password" | "change-password"
| "remove" | "remove"
| "remove-avatar"; | "remove-avatar";
export type StaffMemberDetailsUrlQueryParams = Dialog< export type StaffMemberDetailsUrlQueryParams =
StaffMemberDetailsUrlDialog Dialog<StaffMemberDetailsUrlDialog>;
>;
export const staffMemberDetailsUrl = ( export const staffMemberDetailsUrl = (
id: string, id: string,

View file

@ -231,12 +231,12 @@ const TranslationFields: React.FC<TranslationFieldsProps> = props => {
onDiscard={onDiscard} onDiscard={onDiscard}
onSubmit={data => onSubmit(field, data)} onSubmit={data => onSubmit(field, data)}
/> />
) // FIXME ) : // FIXME
// For now this is the only way to fix the issue // For now this is the only way to fix the issue
// of initializing the editor with fetched data. // of initializing the editor with fetched data.
// Without this the editor doesn't get the saved data // Without this the editor doesn't get the saved data
// and is empty // and is empty
: disabled ? ( disabled ? (
<Skeleton /> <Skeleton />
) : ( ) : (
<TranslationFieldsRich <TranslationFieldsRich

View file

@ -10,16 +10,11 @@ export function useRichTextSubmit(
) { ) {
const { setIsDirty, setExitDialogSubmitRef } = useExitFormDialog(); const { setIsDirty, setExitDialogSubmitRef } = useExitFormDialog();
const { const { defaultValue, editorRef, isReadyForMount, handleChange, getValue } =
defaultValue, useRichText({
editorRef, initial,
isReadyForMount, triggerChange: () => setIsDirty(true),
handleChange, });
getValue,
} = useRichText({
initial,
triggerChange: () => setIsDirty(true),
});
const handleSubmit = React.useCallback(async () => { const handleSubmit = React.useCallback(async () => {
const result = onSubmit(await getValue()); const result = onSubmit(await getValue());
@ -34,10 +29,10 @@ export function useRichTextSubmit(
return errors; return errors;
}, [getValue, onSubmit, setIsDirty]); }, [getValue, onSubmit, setIsDirty]);
React.useEffect(() => setExitDialogSubmitRef(handleSubmit), [ React.useEffect(
handleSubmit, () => setExitDialogSubmitRef(handleSubmit),
setExitDialogSubmitRef, [handleSubmit, setExitDialogSubmitRef],
]); );
return { return {
defaultValue, defaultValue,

View file

@ -25,7 +25,7 @@ describe("Multiple file upload handler", () => {
return promise; return promise;
}, cbs); }, cbs);
handle((testFiles as unknown) as FileList).then(() => { handle(testFiles as unknown as FileList).then(() => {
expect(cbs.onAfterUpload).toBeCalledTimes(testFiles.length); expect(cbs.onAfterUpload).toBeCalledTimes(testFiles.length);
expect(cbs.onBeforeUpload).toBeCalledTimes(testFiles.length); expect(cbs.onBeforeUpload).toBeCalledTimes(testFiles.length);
expect(cbs.onCompleted).toBeCalledTimes(1); expect(cbs.onCompleted).toBeCalledTimes(1);
@ -56,7 +56,7 @@ describe("Multiple file upload handler", () => {
return promise; return promise;
}, cbs); }, cbs);
handle((testFiles as unknown) as FileList).then(() => { handle(testFiles as unknown as FileList).then(() => {
expect(cbs.onAfterUpload).toBeCalledTimes(testFiles.length - 1); expect(cbs.onAfterUpload).toBeCalledTimes(testFiles.length - 1);
expect(cbs.onBeforeUpload).toBeCalledTimes(testFiles.length); expect(cbs.onBeforeUpload).toBeCalledTimes(testFiles.length);
expect(cbs.onCompleted).toBeCalledTimes(1); expect(cbs.onCompleted).toBeCalledTimes(1);

View file

@ -3,20 +3,18 @@ import { useState } from "react";
function useMetadataChangeTrigger() { function useMetadataChangeTrigger() {
const [isMetadataModified, setMetadataModified] = useState(false); const [isMetadataModified, setMetadataModified] = useState(false);
const [isPrivateMetadataModified, setPrivateMetadataModified] = useState( const [isPrivateMetadataModified, setPrivateMetadataModified] =
false, useState(false);
);
const makeChangeHandler: ( const makeChangeHandler: (onChange: FormChange) => FormChange =
onChange: FormChange, onChange => event => {
) => FormChange = onChange => event => { if (event.target.name === "metadata") {
if (event.target.name === "metadata") { setMetadataModified(true);
setMetadataModified(true); } else {
} else { setPrivateMetadataModified(true);
setPrivateMetadataModified(true); }
} onChange(event);
onChange(event); };
};
const resetMetadataChanged = () => { const resetMetadataChanged = () => {
setMetadataModified(false); setMetadataModified(false);

View file

@ -20,16 +20,10 @@ export function getFilterVariables(
}; };
} }
export const { export const { deleteFilterTab, getFilterTabs, saveFilterTab } =
deleteFilterTab, createFilterTabUtils<WarehouseListUrlFilters>(WAREHOUSE_FILTERS_KEY);
getFilterTabs,
saveFilterTab,
} = createFilterTabUtils<WarehouseListUrlFilters>(WAREHOUSE_FILTERS_KEY);
export const { export const { areFiltersApplied, getActiveFilters, getFiltersCurrentTab } =
areFiltersApplied, createFilterUtils<WarehouseListUrlQueryParams, WarehouseListUrlFilters>(
getActiveFilters, WarehouseListUrlFiltersEnum,
getFiltersCurrentTab, );
} = createFilterUtils<WarehouseListUrlQueryParams, WarehouseListUrlFilters>(
WarehouseListUrlFiltersEnum,
);