Enable save button on channel pages (#2328)

* Enable save button on channel pages

* Update changelog with enable save button

* Remove disabling save while updating channel

* Trigger CI

Co-authored-by: Patryk Andrzejewski <vox3r69@gmail.com>
This commit is contained in:
Dawid 2022-10-13 10:34:21 +02:00 committed by GitHub
parent 42d999a222
commit 943b96436c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 67 additions and 23 deletions

View file

@ -10,12 +10,14 @@ All notable, unreleased changes to this project will be documented in this file.
- Fix invalid values in channel picker - #2313 by @orzechdev - Fix invalid values in channel picker - #2313 by @orzechdev
- Fix missing metadata and payment balance on unconfirmed orders - #2314 by @orzechdev - Fix missing metadata and payment balance on unconfirmed orders - #2314 by @orzechdev
- Fix exit form dialog false positive - #2311 by @orzechdev - Fix exit form dialog false positive - #2311 by @orzechdev
- Enable save button on channel pages - #2328 by @orzechdev
- Handle form errors before product creation - #2299 by @orzechdev - Handle form errors before product creation - #2299 by @orzechdev
- Fix no product error on unconfirmed order lines - #2324 by @orzechdev - Fix no product error on unconfirmed order lines - #2324 by @orzechdev
- Enable save button on discount pages - #2319 by @orzechdev - Enable save button on discount pages - #2319 by @orzechdev
- Enable save button on page pages - #2325 by @orzechdev - Enable save button on page pages - #2325 by @orzechdev
- Fix pagination errors on voucher and sale pages - #2317 by @orzechdev - Fix pagination errors on voucher and sale pages - #2317 by @orzechdev
## 3.4 ## 3.4
- Added links instead of imperative navigation with onClick - #1969 by @taniotanio7 - Added links instead of imperative navigation with onClick - #1969 by @taniotanio7

View file

@ -72,10 +72,11 @@ export const ChannelForm: React.FC<ChannelFormProps> = ({
const intl = useIntl(); const intl = useIntl();
const [copied, copy] = useClipboard(); const [copied, copy] = useClipboard();
const formErrors = getFormErrors<keyof FormData, ChannelErrorFragment>( const formErrors = getFormErrors<keyof FormData, ChannelErrorFragment>(
["name", "slug", "currencyCode"], ["name", "slug", "currencyCode", "defaultCountry"],
errors, errors,
); );
const classes = useStyles({}); const classes = useStyles();
return ( return (
<> <>
<Card> <Card>

View file

@ -2,6 +2,7 @@ import ChannelAllocationStrategy from "@saleor/channels/components/ChannelAlloca
import ShippingZones from "@saleor/channels/components/ShippingZones"; import ShippingZones from "@saleor/channels/components/ShippingZones";
import Warehouses from "@saleor/channels/components/Warehouses"; import Warehouses from "@saleor/channels/components/Warehouses";
import { channelsListUrl } from "@saleor/channels/urls"; import { channelsListUrl } from "@saleor/channels/urls";
import { validateChannelFormData } from "@saleor/channels/validation";
import CardSpacer from "@saleor/components/CardSpacer"; import CardSpacer from "@saleor/components/CardSpacer";
import Form from "@saleor/components/Form"; import Form from "@saleor/components/Form";
import Grid from "@saleor/components/Grid"; import Grid from "@saleor/components/Grid";
@ -41,7 +42,9 @@ import {
} from "./handlers"; } from "./handlers";
import { ChannelShippingZones, ChannelWarehouses } from "./types"; import { ChannelShippingZones, ChannelWarehouses } from "./types";
export interface ChannelDetailsPageProps<TErrors> { export interface ChannelDetailsPageProps<
TErrors extends ChannelErrorFragment[]
> {
channel?: ChannelDetailsFragment; channel?: ChannelDetailsFragment;
currencyCodes?: SingleAutocompleteChoiceType[]; currencyCodes?: SingleAutocompleteChoiceType[];
disabled: boolean; disabled: boolean;
@ -58,13 +61,13 @@ export interface ChannelDetailsPageProps<TErrors> {
allWarehousesCount: number; allWarehousesCount: number;
countries: CountryFragment[]; countries: CountryFragment[];
onDelete?: () => void; onDelete?: () => void;
onSubmit: (data: FormData) => SubmitPromise<TErrors[]>; onSubmit: (data: FormData) => SubmitPromise<TErrors>;
updateChannelStatus?: () => void; updateChannelStatus?: () => void;
searchShippingZones: (query: string) => void; searchShippingZones: (query: string) => void;
searchWarehouses: (query: string) => void; searchWarehouses: (query: string) => void;
} }
const ChannelDetailsPage = function<TErrors>({ const ChannelDetailsPage = function<TErrors extends ChannelErrorFragment[]>({
channel, channel,
currencyCodes, currencyCodes,
disabled, disabled,
@ -88,6 +91,10 @@ const ChannelDetailsPage = function<TErrors>({
}: ChannelDetailsPageProps<TErrors>) { }: ChannelDetailsPageProps<TErrors>) {
const navigate = useNavigator(); const navigate = useNavigator();
const [validationErrors, setValidationErrors] = useState<
ChannelErrorFragment[]
>([]);
const [selectedCurrencyCode, setSelectedCurrencyCode] = useState(""); const [selectedCurrencyCode, setSelectedCurrencyCode] = useState("");
const [ const [
selectedCountryDisplayName, selectedCountryDisplayName,
@ -133,25 +140,21 @@ const ChannelDetailsPage = function<TErrors>({
!warehousesToDisplay.some(({ id }) => id === searchedWarehouseId), !warehousesToDisplay.some(({ id }) => id === searchedWarehouseId),
); );
const checkIfSaveIsDisabled = (data: FormData) => { const handleSubmit = async (data: FormData) => {
const isValid = const errors = validateChannelFormData(data);
!!data.name &&
!!data.slug &&
!!data.currencyCode &&
!!data.defaultCountry &&
data.name.trim().length > 0;
return disabled || !isValid; setValidationErrors(errors);
if (errors.length) {
return errors;
}
return onSubmit(data);
}; };
return ( return (
<Form <Form confirmLeave onSubmit={handleSubmit} initial={initialData}>
confirmLeave {({ change, data, submit, set, triggerChange }) => {
onSubmit={onSubmit}
initial={initialData}
checkIfSaveIsDisabled={checkIfSaveIsDisabled}
>
{({ change, data, submit, set, isSaveDisabled, triggerChange }) => {
const handleCurrencyCodeSelect = createSingleAutocompleteSelectHandler( const handleCurrencyCodeSelect = createSingleAutocompleteSelectHandler(
change, change,
setSelectedCurrencyCode, setSelectedCurrencyCode,
@ -188,6 +191,8 @@ const ChannelDetailsPage = function<TErrors>({
); );
const reorderWarehouse = createWarehouseReorderHandler(data, set); const reorderWarehouse = createWarehouseReorderHandler(data, set);
const allErrors = [...errors, ...validationErrors];
return ( return (
<> <>
<Grid> <Grid>
@ -202,7 +207,7 @@ const ChannelDetailsPage = function<TErrors>({
onChange={change} onChange={change}
onCurrencyCodeChange={handleCurrencyCodeSelect} onCurrencyCodeChange={handleCurrencyCodeSelect}
onDefaultCountryChange={handleDefaultCountrySelect} onDefaultCountryChange={handleDefaultCountrySelect}
errors={errors} errors={allErrors}
/> />
</div> </div>
<div> <div>
@ -267,7 +272,7 @@ const ChannelDetailsPage = function<TErrors>({
onSubmit={submit} onSubmit={submit}
onDelete={onDelete} onDelete={onDelete}
state={saveButtonBarState} state={saveButtonBarState}
disabled={isSaveDisabled} disabled={disabled}
/> />
</> </>
); );

View file

@ -0,0 +1,32 @@
import { ChannelErrorCode, ChannelErrorFragment } from "@saleor/graphql";
import { FormData } from "./components/ChannelForm";
const createEmptyRequiredError = (field: string): ChannelErrorFragment => ({
__typename: "ChannelError",
code: ChannelErrorCode.REQUIRED,
field,
message: null,
});
export const validateChannelFormData = (data: FormData) => {
let errors: ChannelErrorFragment[] = [];
if (!data.name) {
errors = [...errors, createEmptyRequiredError("name")];
}
if (!data.slug) {
errors = [...errors, createEmptyRequiredError("slug")];
}
if (!data.currencyCode) {
errors = [...errors, createEmptyRequiredError("currencyCode")];
}
if (!data.defaultCountry) {
errors = [...errors, createEmptyRequiredError("defaultCountry")];
}
return errors;
};

View file

@ -46,7 +46,10 @@ export const ChannelCreateView = ({}) => {
}, },
}); });
const [reorderChannelWarehouses] = useChannelReorderWarehousesMutation({ const [
reorderChannelWarehouses,
reorderChannelWarehousesOpts,
] = useChannelReorderWarehousesMutation({
onCompleted: data => { onCompleted: data => {
const errors = data.channelReorderWarehouses.errors; const errors = data.channelReorderWarehouses.errors;
if (errors.length) { if (errors.length) {
@ -173,6 +176,7 @@ export const ChannelCreateView = ({}) => {
)} )}
disabled={ disabled={
createChannelOpts.loading || createChannelOpts.loading ||
reorderChannelWarehousesOpts.loading ||
shippingZonesCountLoading || shippingZonesCountLoading ||
warehousesCountLoading warehousesCountLoading
} }