Extract useDashboardNotification (#362)

* Extract useDashboardNotification

Play with config to make app-sdk working in monorepo

bump pnpm

remove local locks

unify deps

Changesets

Replace appBridge.dispatch(Notification()) with shared useDashboardNotification package

Fix build

Update klaviyo packages

update deps

update deps - root next version

* update and ix

* Restore logic in cms
This commit is contained in:
Lukasz Ostrowski 2023-04-14 17:40:49 +02:00 committed by GitHub
parent 74174c4763
commit 2e518906d1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
46 changed files with 233 additions and 80745 deletions

View file

@ -0,0 +1,17 @@
---
"eslint-config-saleor": patch
"saleor-app-emails-and-messages": patch
"saleor-app-data-importer": patch
"saleor-app-products-feed": patch
"saleor-app-monitoring": patch
"@saleor/apps-shared": patch
"saleor-app-invoices": patch
"saleor-app-klaviyo": patch
"saleor-app-search": patch
"saleor-app-slack": patch
"saleor-app-taxes": patch
"saleor-app-cms": patch
"saleor-app-crm": patch
---
Update next.js to 13.3.0

View file

@ -0,0 +1,17 @@
---
"eslint-config-saleor": patch
"saleor-app-emails-and-messages": patch
"saleor-app-data-importer": patch
"saleor-app-products-feed": patch
"saleor-app-monitoring": patch
"@saleor/apps-shared": patch
"saleor-app-invoices": patch
"saleor-app-klaviyo": patch
"saleor-app-search": patch
"saleor-app-slack": patch
"saleor-app-taxes": patch
"saleor-app-cms": patch
"saleor-app-crm": patch
---
Update @saleor/app-sdk to 0.37.2

View file

@ -0,0 +1,5 @@
---
"@saleor/apps-shared": minor
---
Added useDashboardNotification hook, that allows quick access to AppBridge.dispatch(Notification())

View file

@ -0,0 +1,15 @@
---
"saleor-app-emails-and-messages": patch
"saleor-app-data-importer": patch
"saleor-app-products-feed": patch
"saleor-app-monitoring": patch
"saleor-app-invoices": patch
"saleor-app-klaviyo": patch
"saleor-app-search": patch
"saleor-app-slack": patch
"saleor-app-taxes": patch
"saleor-app-cms": patch
"saleor-app-crm": patch
---
Use useDashboardNotification hook from shared package, instead of direct AppBridge usage

View file

@ -2,7 +2,7 @@ import { useChannelsFetch } from "./useChannelsFetch";
import { MergedChannelSchema, SingleChannelSchema } from "../../../../lib/cms/config";
import { useChannelsQuery } from "../../../../../generated/graphql";
import { useIsMounted } from "usehooks-ts";
import { actions, useAppBridge } from "@saleor/app-sdk/app-bridge";
import { useDashboardNotification } from "@saleor/apps-shared";
export interface ChannelsDataLoading {
fetching: boolean;
@ -15,7 +15,6 @@ export interface ChannelsDataErrors {
}
export const useChannels = () => {
const { appBridge } = useAppBridge();
const isMounted = useIsMounted();
const [channelsQueryData, channelsQueryOpts] = useChannelsQuery({
pause: !isMounted,
@ -27,6 +26,7 @@ export const useChannels = () => {
error: fetchingError,
isFetching,
} = useChannelsFetch();
const { notifySuccess, notifyError } = useDashboardNotification();
const saveChannel = async (channelToSave: SingleChannelSchema) => {
console.log("saveChannel", channelToSave);
@ -55,21 +55,9 @@ export const useChannels = () => {
});
if (fetchResult.success) {
appBridge?.dispatch(
actions.Notification({
title: "Success",
status: "success",
text: "Configuration saved",
})
);
notifySuccess("Success", "Configuration saved");
} else {
appBridge?.dispatch(
actions.Notification({
title: "Error",
status: "error",
text: "Error while saving configuration",
})
);
notifyError("Error", "Error while saving configuration");
}
};

View file

@ -7,6 +7,7 @@ import { actions, useAppBridge } from "@saleor/app-sdk/app-bridge";
import { Button, makeStyles } from "@saleor/macaw-ui";
import { ProviderInstancesSelect } from "./provider-instances-list";
import { Add } from "@material-ui/icons";
import { useDashboardNotification } from "@saleor/apps-shared";
const useStyles = makeStyles({
wrapper: {
@ -18,13 +19,14 @@ const useStyles = makeStyles({
export const ProviderInstances = () => {
const styles = useStyles();
const { appBridge } = useAppBridge();
const { providerInstances, saveProviderInstance, deleteProviderInstance, loading, errors } =
useProviderInstances();
const [activeProviderInstanceId, setActiveProviderInstanceId] = useState<string | null>(null);
const [newProviderInstance, setNewProviderInstance] = useState<SingleProviderSchema | null>(null);
const { notifySuccess } = useDashboardNotification();
useEffect(() => {
if (providerInstances.length && !activeProviderInstanceId) {
setActiveProviderInstanceId(providerInstances[0].id);
@ -48,13 +50,7 @@ export const ProviderInstances = () => {
const handleSaveProviderInstance = async (providerInstance: SingleProviderSchema) => {
const savedProviderInstance = await saveProviderInstance(providerInstance);
appBridge?.dispatch(
actions.Notification({
title: "Success",
status: "success",
text: "Configuration saved",
})
);
notifySuccess("Success", "Configuration saved");
if (newProviderInstance) {
setNewProviderInstance(null);

File diff suppressed because it is too large Load diff

View file

@ -1,21 +0,0 @@
import { useCallback } from "react";
import { actions, useAppBridge } from "@saleor/app-sdk/app-bridge";
export const useDashboardNotification = () => {
const { appBridge } = useAppBridge();
return {
notifySuccess: useCallback(
(title: string, text: string) => {
appBridge?.dispatch(
actions.Notification({
status: "success",
title,
text,
})
);
},
[appBridge]
),
};
};

View file

@ -2,7 +2,7 @@ import { Box, Button, Checkbox, Text } from "@saleor/macaw-ui/next";
import { trpcClient } from "../../../trpc/trpc-client";
import { ComponentProps, useEffect, useState } from "react";
import { Section } from "../../../ui/section/section";
import { useDashboardNotification } from "../../../../lib/use-dashboard-notification";
import { useDashboardNotification } from "@saleor/apps-shared";
import { MailchimpListPicker } from "../../mailchimp-list-picker/mailchimp-list-picker";
type EnabledState = {

View file

@ -1,7 +1,7 @@
import { ComponentProps, useEffect, useState } from "react";
import { Box, Button, Text, useTheme, WarningIcon } from "@saleor/macaw-ui/next";
import { trpcClient } from "../trpc/trpc-client";
import { useDashboardNotification } from "../../lib/use-dashboard-notification";
import { useDashboardNotification } from "@saleor/apps-shared";
import { useFetchAllCustomers } from "./use-fetch-all-customers";
import { Section } from "../ui/section/section";
import { MailchimpListPicker } from "../mailchimp/mailchimp-list-picker/mailchimp-list-picker";

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,5 @@
/** @type {import('next').NextConfig} */
module.exports = {
reactStrictMode: true,
transpilePackages: ["@saleor/apps-shared"],
};

File diff suppressed because it is too large Load diff

View file

@ -7,6 +7,7 @@ import { trpcClient } from "../../trpc/trpc-client";
import { SideMenu } from "./side-menu";
import { LoadingIndicator } from "../../ui/loading-indicator";
import { Instructions } from "./instructions";
import { useDashboardNotification } from "@saleor/apps-shared";
const useStyles = makeStyles((theme) => {
return {
@ -26,6 +27,7 @@ export const ChannelsConfigurationTab = () => {
const styles = useStyles();
const { appBridge } = useAppBridge();
const [activeChannelSlug, setActiveChannelSlug] = useState<string | null>(null);
const { notifySuccess } = useDashboardNotification();
const { data: channelsData, isLoading: isChannelsDataLoading } =
trpcClient.channels.fetch.useQuery(undefined, {
@ -75,13 +77,8 @@ export const ChannelsConfigurationTab = () => {
trpcClient.appConfiguration.setChannelConfiguration.useMutation({
onSuccess() {
refetchConfig();
appBridge?.dispatch(
actions.Notification({
title: "Success",
text: "Saved app configuration",
status: "success",
})
);
notifySuccess("Success", "Saved app configuration");
},
});

View file

@ -6,6 +6,7 @@ import { MjmlConfiguration, smtpEncryptionTypes } from "../mjml-config";
import { trpcClient } from "../../../trpc/trpc-client";
import { useAppBridge, actions } from "@saleor/app-sdk/app-bridge";
import { useQueryClient } from "@tanstack/react-query";
import { useDashboardNotification } from "@saleor/apps-shared";
const useStyles = makeStyles((theme) => ({
field: {
@ -30,7 +31,7 @@ type Props = {
export const MjmlConfigurationForm = (props: Props) => {
const styles = useStyles();
const { appBridge } = useAppBridge();
const { notifySuccess, notifyError } = useDashboardNotification();
const { handleSubmit, control, reset, setError } = useForm<MjmlConfiguration>({
defaultValues: props.initialData,
@ -64,12 +65,7 @@ export const MjmlConfigurationForm = (props: Props) => {
// Trigger refetch to make sure we have a fresh data
props.onConfigurationSaved();
appBridge?.dispatch(
actions.Notification({
title: "Configuration saved",
status: "success",
})
);
notifySuccess("Configuration saved");
},
onError(error) {
let isFieldErrorSet = false;
@ -85,13 +81,10 @@ export const MjmlConfigurationForm = (props: Props) => {
}
const formErrors = error.data?.zodError?.formErrors || [];
const formErrorMessage = formErrors.length ? formErrors.join("\n") : undefined;
appBridge?.dispatch(
actions.Notification({
title: "Could not save the configuration",
text: isFieldErrorSet ? "Submitted form contain errors" : "Error saving configuration",
apiMessage: formErrorMessage,
status: "error",
})
notifyError(
"Could not save the configuration",
isFieldErrorSet ? "Submitted form contain errors" : "Error saving configuration",
formErrorMessage
);
},
});

View file

@ -1,6 +1,5 @@
import React from "react";
import { IconButton, makeStyles } from "@saleor/macaw-ui";
import { actions, useAppBridge } from "@saleor/app-sdk/app-bridge";
import { AppColumnsLayout } from "../../../ui/app-columns-layout";
import { trpcClient } from "../../../trpc/trpc-client";
import { MjmlConfigurationForm } from "./mjml-configuration-form";
@ -14,6 +13,7 @@ import { LoadingIndicator } from "../../../ui/loading-indicator";
import { Add } from "@material-ui/icons";
import { useQueryClient } from "@tanstack/react-query";
import { MjmlInstructions } from "./mjml-instructions";
import { useDashboardNotification } from "@saleor/apps-shared";
const useStyles = makeStyles((theme) => {
return {
@ -50,7 +50,7 @@ const navigateToFirstConfiguration = (router: NextRouter, configurations?: MjmlC
export const MjmlConfigurationTab = ({ configurationId }: MjmlConfigurationTabProps) => {
const styles = useStyles();
const { appBridge } = useAppBridge();
const { notifyError, notifySuccess } = useDashboardNotification();
const router = useRouter();
const queryClient = useQueryClient();
@ -72,13 +72,7 @@ export const MjmlConfigurationTab = ({ configurationId }: MjmlConfigurationTabPr
const { mutate: deleteConfiguration } =
trpcClient.mjmlConfiguration.deleteConfiguration.useMutation({
onError: (error) => {
appBridge?.dispatch(
actions.Notification({
title: "Could not remove the configuration",
text: error.message,
status: "error",
})
);
notifyError("Could not remove the configuration", error.message);
},
onSuccess: async (_data, variables) => {
await queryClient.cancelQueries({ queryKey: ["mjmlConfiguration", "getConfigurations"] });
@ -103,13 +97,7 @@ export const MjmlConfigurationTab = ({ configurationId }: MjmlConfigurationTabPr
}
refetchConfigurations();
appBridge?.dispatch(
actions.Notification({
title: "Success",
text: "Removed successfully",
status: "success",
})
);
notifySuccess("Success", "Removed successfully");
},
});

View file

@ -22,6 +22,7 @@ import { useRouter } from "next/router";
import { mjmlUrls } from "../../urls";
import { useAppBridge, actions } from "@saleor/app-sdk/app-bridge";
import { examplePayloads } from "../../../event-handlers/default-payloads";
import { useDashboardNotification } from "@saleor/apps-shared";
const PREVIEW_DEBOUNCE_DELAY = 500;
@ -71,6 +72,7 @@ export const EventConfigurationForm = ({
configurationId,
eventType,
}: EventConfigurationFormProps) => {
const { notifySuccess, notifyError } = useDashboardNotification();
const router = useRouter();
const { appBridge } = useAppBridge();
const { handleSubmit, control, getValues, setError } = useForm<MjmlEventConfiguration>({
@ -113,12 +115,7 @@ export const EventConfigurationForm = ({
const { mutate: updateEventConfiguration } =
trpcClient.mjmlConfiguration.updateEventConfiguration.useMutation({
onSuccess: (data) => {
appBridge?.dispatch(
actions.Notification({
title: "Configuration saved",
status: "success",
})
);
notifySuccess("Success", "Configuration saved");
},
onError: (error) => {
let isFieldErrorSet = false;
@ -134,13 +131,11 @@ export const EventConfigurationForm = ({
}
const formErrors = error.data?.zodError?.formErrors || [];
const formErrorMessage = formErrors.length ? formErrors.join("\n") : undefined;
appBridge?.dispatch(
actions.Notification({
title: "Could not save the configuration",
text: isFieldErrorSet ? "Submitted form contain errors" : "Error saving configuration",
apiMessage: formErrorMessage,
status: "error",
})
notifyError(
"Could not save the configuration",
isFieldErrorSet ? "Submitted form contain errors" : "Error saving configuration",
formErrorMessage
);
},
});

View file

@ -16,7 +16,7 @@ import { mjmlUrls } from "../../urls";
import { messageEventTypesLabels } from "../../../event-handlers/message-event-types";
import { MjmlConfiguration } from "../mjml-config";
import { trpcClient } from "../../../trpc/trpc-client";
import { useAppBridge, actions } from "@saleor/app-sdk/app-bridge";
import { useDashboardNotification } from "@saleor/apps-shared";
const useStyles = makeStyles((theme) => {
return {
@ -52,18 +52,14 @@ export const MjmlTemplatesCard = ({
}: MjmlTemplatesCardProps) => {
const classes = useStyles();
const router = useRouter();
const { appBridge } = useAppBridge();
const { notifySuccess } = useDashboardNotification();
const { mutate: updateEventConfiguration } =
trpcClient.mjmlConfiguration.updateEventConfiguration.useMutation({
onSuccess(data, variables) {
onEventChanged();
appBridge?.dispatch(
actions.Notification({
title: variables.active ? "Event enabled" : "Event disabled",
status: "success",
})
);
notifySuccess(variables.active ? "Event enabled" : "Event disabled");
},
});

View file

@ -16,6 +16,7 @@ import { trpcClient } from "../../../trpc/trpc-client";
import { useAppBridge, actions } from "@saleor/app-sdk/app-bridge";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { fetchSenders } from "../../sendgrid-api";
import { useDashboardNotification } from "@saleor/apps-shared";
const useStyles = makeStyles((theme) => ({
field: {
@ -41,6 +42,7 @@ type Props = {
export const SendgridConfigurationForm = (props: Props) => {
const styles = useStyles();
const { appBridge } = useAppBridge();
const { notifySuccess, notifyError } = useDashboardNotification();
const [senderId, setSenderId] = useState<string | undefined>(undefined);
const { handleSubmit, control, reset, setError, setValue } = useForm<SendgridConfiguration>({
@ -93,12 +95,7 @@ export const SendgridConfigurationForm = (props: Props) => {
// Trigger refetch to make sure we have a fresh data
props.onConfigurationSaved();
appBridge?.dispatch(
actions.Notification({
title: "Configuration saved",
status: "success",
})
);
notifySuccess("Configuration saved");
},
onError(error) {
let isFieldErrorSet = false;
@ -114,13 +111,11 @@ export const SendgridConfigurationForm = (props: Props) => {
}
const formErrors = error.data?.zodError?.formErrors || [];
const formErrorMessage = formErrors.length ? formErrors.join("\n") : undefined;
appBridge?.dispatch(
actions.Notification({
title: "Could not save the configuration",
text: isFieldErrorSet ? "Submitted form contain errors" : "Error saving configuration",
apiMessage: formErrorMessage,
status: "error",
})
notifyError(
"Could not save the configuration",
isFieldErrorSet ? "Submitted form contain errors" : "Error saving configuration",
formErrorMessage
);
},
});

View file

@ -1,6 +1,5 @@
import React from "react";
import { IconButton, makeStyles } from "@saleor/macaw-ui";
import { actions, useAppBridge } from "@saleor/app-sdk/app-bridge";
import { AppColumnsLayout } from "../../../ui/app-columns-layout";
import { trpcClient } from "../../../trpc/trpc-client";
import { SendgridConfigurationForm } from "./sendgrid-configuration-form";
@ -14,6 +13,7 @@ import { useQueryClient } from "@tanstack/react-query";
import { sendgridUrls } from "../../urls";
import { SendgridTemplatesCard } from "./sendgrid-templates-card";
import { SendgridInstructions } from "./sendgrid-instructions";
import { useDashboardNotification } from "@saleor/apps-shared";
const useStyles = makeStyles((theme) => {
return {
@ -53,9 +53,9 @@ const navigateToFirstConfiguration = (
export const SendgridConfigurationTab = ({ configurationId }: SendgridConfigurationTabProps) => {
const styles = useStyles();
const { appBridge } = useAppBridge();
const router = useRouter();
const queryClient = useQueryClient();
const { notifySuccess, notifyError } = useDashboardNotification();
const {
data: configurations,
@ -75,13 +75,7 @@ export const SendgridConfigurationTab = ({ configurationId }: SendgridConfigurat
const { mutate: deleteConfiguration } =
trpcClient.sendgridConfiguration.deleteConfiguration.useMutation({
onError: (error) => {
appBridge?.dispatch(
actions.Notification({
title: "Could not remove the configuration",
text: error.message,
status: "error",
})
);
notifyError("Could not remove the configuration", error.message);
},
onSuccess: async (_data, variables) => {
await queryClient.cancelQueries({
@ -108,13 +102,8 @@ export const SendgridConfigurationTab = ({ configurationId }: SendgridConfigurat
}
refetchConfigurations();
appBridge?.dispatch(
actions.Notification({
title: "Success",
text: "Removed successfully",
status: "success",
})
);
notifySuccess("Success", "Removed successfully");
},
});

View file

@ -5,7 +5,6 @@ import {
InputLabel,
MenuItem,
Select,
TextField,
TextFieldProps,
Typography,
} from "@material-ui/core";
@ -26,9 +25,9 @@ import {
import { trpcClient } from "../../../trpc/trpc-client";
import { useRouter } from "next/router";
import { sendgridUrls } from "../../urls";
import { useAppBridge, actions } from "@saleor/app-sdk/app-bridge";
import { useQuery } from "@tanstack/react-query";
import { fetchTemplates } from "../../sendgrid-api";
import { useDashboardNotification } from "@saleor/apps-shared";
const useStyles = makeStyles((theme) => ({
viewContainer: {
@ -79,7 +78,8 @@ export const EventConfigurationForm = ({
configuration,
}: EventConfigurationFormProps) => {
const router = useRouter();
const { appBridge } = useAppBridge();
const { notifySuccess, notifyError } = useDashboardNotification();
const { handleSubmit, control, getValues, setError } = useForm<SendgridEventConfiguration>({
defaultValues: initialData,
});
@ -100,12 +100,7 @@ export const EventConfigurationForm = ({
const { mutate: updateEventConfiguration } =
trpcClient.sendgridConfiguration.updateEventConfiguration.useMutation({
onSuccess: (data) => {
appBridge?.dispatch(
actions.Notification({
title: "Configuration saved",
status: "success",
})
);
notifySuccess("Configuration saved");
},
onError: (error) => {
let isFieldErrorSet = false;
@ -121,13 +116,10 @@ export const EventConfigurationForm = ({
}
const formErrors = error.data?.zodError?.formErrors || [];
const formErrorMessage = formErrors.length ? formErrors.join("\n") : undefined;
appBridge?.dispatch(
actions.Notification({
title: "Could not save the configuration",
text: isFieldErrorSet ? "Submitted form contain errors" : "Error saving configuration",
apiMessage: formErrorMessage,
status: "error",
})
notifyError(
"Could not save the configuration",
isFieldErrorSet ? "Submitted form contain errors" : "Error saving configuration",
formErrorMessage
);
},
});

View file

@ -17,6 +17,7 @@ import { trpcClient } from "../../../trpc/trpc-client";
import { useAppBridge, actions } from "@saleor/app-sdk/app-bridge";
import { SendgridConfiguration } from "../sendgrid-config";
import { sendgridUrls } from "../../urls";
import { useDashboardNotification } from "@saleor/apps-shared";
const useStyles = makeStyles((theme) => {
return {
@ -52,18 +53,13 @@ export const SendgridTemplatesCard = ({
}: SendgridTemplatesCardProps) => {
const classes = useStyles();
const router = useRouter();
const { appBridge } = useAppBridge();
const { notifySuccess } = useDashboardNotification();
const { mutate: updateEventConfiguration } =
trpcClient.sendgridConfiguration.updateEventConfiguration.useMutation({
onSuccess(_data, variables) {
onEventChanged();
appBridge?.dispatch(
actions.Notification({
title: variables.active ? "Event enabled" : "Event disabled",
status: "success",
})
);
notifySuccess(variables.active ? "Event enabled" : "Event disabled");
},
});

File diff suppressed because it is too large Load diff

View file

@ -7,6 +7,7 @@ import { AddressForm } from "./address-form";
import { ChannelsList } from "./channels-list";
import { actions, useAppBridge } from "@saleor/app-sdk/app-bridge";
import { AppColumnsLayout } from "../../ui/app-columns-layout";
import { useDashboardNotification } from "@saleor/apps-shared";
const useStyles = makeStyles((theme) => {
return {
@ -23,6 +24,7 @@ const useStyles = makeStyles((theme) => {
export const ChannelsConfiguration = () => {
const styles = useStyles();
const { appBridge } = useAppBridge();
const { notifySuccess } = useDashboardNotification();
const { data: configurationData, refetch: refetchConfig } =
trpcClient.appConfiguration.fetch.useQuery();
@ -34,13 +36,7 @@ export const ChannelsConfiguration = () => {
const { mutate, error: saveError } = trpcClient.appConfiguration.setAndReplace.useMutation({
onSuccess() {
refetchConfig();
appBridge?.dispatch(
actions.Notification({
title: "Success",
text: "Saved app configuration",
status: "success",
})
);
notifySuccess("Success", "Saved app configuration");
},
});

View file

@ -15,7 +15,7 @@ const nextConfig = {
disableServerWebpackPlugin: !isSentryPropertiesInEnvironment,
disableClientWebpackPlugin: !isSentryPropertiesInEnvironment,
},
transpilePackages: ["nuvo-react", "@saleor/apps-shared"],
transpilePackages: ["@saleor/apps-shared"],
redirects() {
return [
{

File diff suppressed because it is too large Load diff

View file

@ -9,8 +9,7 @@ import { ChangeEvent, SyntheticEvent, useEffect, useState } from "react";
import { AccessWarning } from "../components/AccessWarning/AccessWarning";
import { useAppApi } from "../hooks/useAppApi";
import { AppColumnsLayout } from "../lib/ui/app-columns-layout";
import { useDashboardNotifier } from "../utils/useDashboardNotifier";
import { useDashboardNotification } from "@saleor/apps-shared";
interface ConfigurationField {
key: string;
@ -124,7 +123,7 @@ function Instructions() {
function Configuration() {
const { appBridgeState } = useAppBridge();
const classes = useStyles();
const [notify] = useDashboardNotifier();
const { notifySuccess, notifyError } = useDashboardNotification();
const [configuration, setConfiguration] = useState<ConfigurationField[]>();
const [transitionState, setTransitionState] = useState<ConfirmButtonTransitionState>("default");
@ -160,19 +159,13 @@ function Configuration() {
}
setTransitionState("success");
await notify({
status: "success",
title: "Success",
text: "Configuration updated successfully",
});
notifySuccess("Success", "Configuration updated successfully");
})
.catch(async () => {
setTransitionState("error");
await notify({
status: "error",
title:
"Configuration update failed. Ensure fields are filled correctly and you have MANAGE_APPS permission",
});
await notifyError(
"Configuration update failed. Ensure fields are filled correctly and you have MANAGE_APPS permission"
);
});
};

View file

@ -1,10 +0,0 @@
import { actions, NotificationPayload, useAppBridge } from "@saleor/app-sdk/app-bridge";
export const useDashboardNotifier = () => {
const { appBridgeState, appBridge } = useAppBridge();
const notify = (payload: NotificationPayload) =>
appBridgeState?.ready && appBridge?.dispatch(actions.Notification(payload));
return [notify];
};

View file

@ -1,5 +1,6 @@
/** @type {import('next').NextConfig} */
module.exports = {
transpilePackages: ["@saleor/apps-shared"],
reactStrictMode: true,
rewrites() {
/**

File diff suppressed because it is too large Load diff

View file

@ -1,30 +0,0 @@
import { actions, useAppBridge } from "@saleor/app-sdk/app-bridge";
export const useDashboardNotifications = () => {
const { appBridge } = useAppBridge();
const showSuccessNotification = (title: string, text: string) => {
appBridge?.dispatch(
actions.Notification({
title: title,
text: text,
status: "success",
})
);
};
const showErrorNotification = (title: string, text: string) => {
appBridge?.dispatch(
actions.Notification({
title: title,
text: text,
status: "error",
})
);
};
return {
showSuccessNotification,
showErrorNotification,
};
};

View file

@ -28,8 +28,9 @@ import { gql, useMutation } from "urql";
import { actions, useAppBridge } from "@saleor/app-sdk/app-bridge";
import { ArrowBack } from "@material-ui/icons";
import { useRouter } from "next/router";
import { useDashboardNotifications } from "../../lib/use-dashboard-notifications";
import { API_KEYS_LINKS } from "../../datadog-urls";
import { useDashboardNotification } from "@saleor/apps-shared";
const useStyles = makeStyles({
form: {
@ -133,7 +134,7 @@ export const DatadogConfig = () => {
const [, mutateCredentials] = useUpdateCredentialsMutation();
const [, deleteCredentials] = useDeleteDatadogCredentialsMutation();
const router = useRouter();
const { showSuccessNotification, showErrorNotification } = useDashboardNotifications();
const { notifyError, notifySuccess } = useDashboardNotification();
const { register, handleSubmit, setValue, control, reset, watch } = useForm<
DataDogCredentialsInput & {
@ -213,14 +214,11 @@ export const DatadogConfig = () => {
setValue("apiKey", buildMaskedKey(updatedConfig.credentials.apiKeyLast4));
setValue("site", updatedConfig.credentials.site);
showSuccessNotification(
"Configuration updated",
"Successfully updated Datadog settings"
);
notifySuccess("Configuration updated", "Successfully updated Datadog settings");
}
if (errors?.length) {
showErrorNotification("Error configuring Datadog", errors[0].message);
notifyError("Error configuring Datadog", errors[0].message);
}
});
})}
@ -278,10 +276,7 @@ export const DatadogConfig = () => {
deleteCredentials({}).then(() => {
fetchConfig();
reset();
showSuccessNotification(
"Configuration updated",
"Successfully deleted Datadog settings"
);
notifySuccess("Configuration updated", "Successfully deleted Datadog settings");
});
}}
>

View file

@ -1,4 +1,5 @@
/** @type {import('next').NextConfig} */
module.exports = {
reactStrictMode: true,
transpilePackages: ["@saleor/apps-shared"],
};

File diff suppressed because it is too large Load diff

View file

@ -9,6 +9,7 @@ import { AppColumnsLayout } from "../../ui/app-columns-layout";
import { FeedPreviewCard } from "./feed-preview-card";
import { Instructions } from "./instructions";
import { SideMenu } from "./side-menu";
import { useDashboardNotification } from "@saleor/apps-shared";
const useStyles = makeStyles((theme) => {
return {
@ -33,6 +34,7 @@ export const ChannelsConfiguration = () => {
const styles = useStyles();
const { appBridge } = useAppBridge();
const { notifySuccess } = useDashboardNotification();
const { data: configurationData, refetch: refetchConfig } =
trpcClient.appConfiguration.fetch.useQuery();
@ -44,13 +46,7 @@ export const ChannelsConfiguration = () => {
const { mutate, error: saveError } = trpcClient.appConfiguration.setAndReplace.useMutation({
onSuccess() {
refetchConfig();
appBridge?.dispatch(
actions.Notification({
title: "Success",
text: "Saved app configuration",
status: "success",
})
);
notifySuccess("Success", "Saved app configuration");
},
});

View file

@ -1,16 +1,7 @@
import { Controller, useForm } from "react-hook-form";
import {
FormControl,
Grid,
InputLabel,
MenuItem,
Select,
TextFieldProps,
Typography,
} from "@material-ui/core";
import { FormControl, Grid, InputLabel, MenuItem, Select, Typography } from "@material-ui/core";
import { Button, makeStyles } from "@saleor/macaw-ui";
import React from "react";
import { actions, useAppBridge } from "@saleor/app-sdk/app-bridge";
import { zodResolver } from "@hookform/resolvers/zod";
import {
SetCategoryMappingInputSchema,
@ -19,6 +10,7 @@ import {
import { CategoryWithMappingFragmentFragment } from "../../../../generated/graphql";
import { GoogleProductCategories } from "../google-product-categories";
import { trpcClient } from "../../trpc/trpc-client";
import { useDashboardNotification } from "@saleor/apps-shared";
const useStyles = makeStyles({
field: {
@ -39,7 +31,7 @@ type CategoryMappingFormProps = {
export const CategoryMappingForm = ({ category }: CategoryMappingFormProps) => {
const styles = useStyles();
const { appBridge } = useAppBridge();
const { notifySuccess, notifyError } = useDashboardNotification();
const { control, handleSubmit, formState } = useForm<SetCategoryMappingInputType>({
defaultValues: {
@ -50,20 +42,10 @@ export const CategoryMappingForm = ({ category }: CategoryMappingFormProps) => {
});
const { mutate, isLoading } = trpcClient.categoryMapping.setCategoryMapping.useMutation({
onError() {
appBridge?.dispatch(
actions.Notification({
title: "Could not save the category mapping",
status: "error",
})
);
notifyError("Could not save the category mapping");
},
onSuccess() {
appBridge?.dispatch(
actions.Notification({
title: "Success",
status: "success",
})
);
notifySuccess("Success");
},
});

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -17,8 +17,8 @@ import { ChangeEvent, ReactElement, SyntheticEvent, useEffect, useState } from "
import { AccessWarning } from "../components/AccessWarning/AccessWarning";
import { ConfigurationError } from "../components/ConfigurationError/ConfigurationError";
import { useAppApi } from "../hooks/useAppApi";
import { useDashboardNotifier } from "../utils/useDashboardNotifier";
import { AppColumnsLayout } from "../components/AppColumnsLayout/AppColumnsLayout";
import { useDashboardNotification } from "@saleor/apps-shared";
interface ConfigurationField {
key: string;
@ -40,7 +40,7 @@ const useStyles = makeStyles((theme) => ({
function Configuration() {
const classes = useStyles();
const { appBridgeState } = useAppBridge();
const [notify] = useDashboardNotifier();
const { notifyError, notifySuccess } = useDashboardNotification();
const [configuration, setConfiguration] = useState<ConfigurationField[]>();
const [transitionState, setTransitionState] = useState<ConfirmButtonTransitionState>("default");
@ -69,18 +69,11 @@ function Configuration() {
})
.then(async (response) => {
setTransitionState(response.status === 200 ? "success" : "error");
await notify({
status: "success",
title: "Success",
text: "Configuration updated successfully",
});
notifySuccess("Success", "Configuration updated successfully");
})
.catch(async () => {
setTransitionState("error");
await notify({
status: "error",
title: "Configuration update failed",
});
await notifyError("Configuration update failed");
});
};

View file

@ -1,10 +0,0 @@
import { actions, NotificationPayload, useAppBridge } from "@saleor/app-sdk/app-bridge";
export const useDashboardNotifier = () => {
const { appBridge, appBridgeState } = useAppBridge();
const notify = (payload: NotificationPayload) =>
appBridgeState?.ready && appBridge?.dispatch(actions.Notification(payload));
return [notify];
};

File diff suppressed because it is too large Load diff

View file

@ -8,7 +8,6 @@ import {
TextFieldProps,
} from "@material-ui/core";
import { Delete, Save } from "@material-ui/icons";
import { actions, useAppBridge } from "@saleor/app-sdk/app-bridge";
import { Button, makeStyles } from "@saleor/macaw-ui";
import React from "react";
import { Controller, useForm } from "react-hook-form";
@ -17,6 +16,7 @@ import { useInstanceId } from "../../taxes/tax-context";
import { trpcClient } from "../../trpc/trpc-client";
import { AppLink } from "../../ui/app-link";
import { avataxConfigSchema } from "../avatax-config";
import { useDashboardNotification } from "@saleor/apps-shared";
const useStyles = makeStyles((theme) => ({
reverseRow: {
@ -39,9 +39,9 @@ const defaultValues: FormValues = {
};
export const AvataxConfigurationForm = () => {
const { notifySuccess, notifyError } = useDashboardNotification();
const [isWarningDialogOpen, setIsWarningDialogOpen] = React.useState(false);
const styles = useStyles();
const { appBridge } = useAppBridge();
const { handleSubmit, reset, control, formState } = useForm<FormValues>({
resolver: zodResolver(schema),
defaultValues,
@ -50,13 +50,7 @@ export const AvataxConfigurationForm = () => {
const { refetch: refetchChannelConfigurationData } =
trpcClient.channelsConfiguration.fetch.useQuery(undefined, {
onError(error) {
appBridge?.dispatch(
actions.Notification({
title: "Error",
text: error.message,
status: "error",
})
);
notifyError("Error", error.message);
},
});
const { refetch: refetchProvidersConfigurationData } =
@ -66,13 +60,7 @@ export const AvataxConfigurationForm = () => {
{
enabled: !!instanceId,
onError(error) {
appBridge?.dispatch(
actions.Notification({
title: "Error",
text: error.message,
status: "error",
})
);
notifyError("Error", error.message);
},
}
);
@ -95,22 +83,10 @@ export const AvataxConfigurationForm = () => {
onSuccess({ id }) {
setInstanceId(id);
refetchProvidersConfigurationData();
appBridge?.dispatch(
actions.Notification({
title: "Success",
text: "Saved app configuration",
status: "success",
})
);
notifySuccess("Success", "Saved app configuration");
},
onError(error) {
appBridge?.dispatch(
actions.Notification({
title: "Error",
text: error.message,
status: "error",
})
);
notifyError("Error", error.message);
},
});
@ -118,22 +94,10 @@ export const AvataxConfigurationForm = () => {
trpcClient.avataxConfiguration.patch.useMutation({
onSuccess() {
refetchProvidersConfigurationData();
appBridge?.dispatch(
actions.Notification({
title: "Success",
text: "Updated Avalara configuration",
status: "success",
})
);
notifySuccess("Success", "Updated Avalara configuration");
},
onError(error) {
appBridge?.dispatch(
actions.Notification({
title: "Error",
text: error.message,
status: "error",
})
);
notifyError("Error", error.message);
},
});
@ -142,22 +106,10 @@ export const AvataxConfigurationForm = () => {
resetInstanceId();
refetchProvidersConfigurationData();
refetchChannelConfigurationData();
appBridge?.dispatch(
actions.Notification({
title: "Success",
text: "Removed Avatax instance",
status: "success",
})
);
notifySuccess("Success", "Removed Avatax instance");
},
onError(error) {
appBridge?.dispatch(
actions.Notification({
title: "Error",
text: error.message,
status: "error",
})
);
notifyError("Error", error.message);
},
});

View file

@ -11,7 +11,6 @@ import {
Typography,
} from "@material-ui/core";
import { Save } from "@material-ui/icons";
import { actions, useAppBridge } from "@saleor/app-sdk/app-bridge";
import { Button, makeStyles } from "@saleor/macaw-ui";
import React from "react";
@ -25,6 +24,7 @@ import { ProvidersConfig } from "../../providers-configuration/providers-config"
import { ProviderIcon } from "../../providers-configuration/ui/provider-icon";
import { useChannelSlug } from "../../taxes/tax-context";
import { trpcClient } from "../../trpc/trpc-client";
import { useDashboardNotification } from "@saleor/apps-shared";
type ChannelTaxProviderFormValues = ChannelConfig;
@ -70,23 +70,17 @@ const getDefaultFormValues = (
// todo: rename because address is here
export const ChannelTaxProviderForm = () => {
const styles = useStyles();
const { appBridge } = useAppBridge();
const { control, reset, handleSubmit } = useForm<ChannelTaxProviderFormValues>({
resolver: zodResolver(channelSchema),
});
const { notifyError, notifySuccess } = useDashboardNotification();
const { channelSlug } = useChannelSlug();
const { data: channelConfigurationData, refetch: refetchChannelConfigurationData } =
trpcClient.channelsConfiguration.fetch.useQuery(undefined, {
onError(error) {
appBridge?.dispatch(
actions.Notification({
title: "Error",
text: error.message,
status: "error",
})
);
notifyError("Error", error.message);
},
});
@ -94,13 +88,7 @@ export const ChannelTaxProviderForm = () => {
undefined,
{
onError(error) {
appBridge?.dispatch(
actions.Notification({
title: "Error",
text: error.message,
status: "error",
})
);
notifyError("Error", error.message);
},
}
);
@ -109,22 +97,10 @@ export const ChannelTaxProviderForm = () => {
const { mutate, isLoading } = trpcClient.channelsConfiguration.upsert.useMutation({
onSuccess() {
refetchChannelConfigurationData();
appBridge?.dispatch(
actions.Notification({
title: "Success",
text: `Saved configuration of channel: ${channelSlug}`,
status: "success",
})
);
notifySuccess("Success", `Saved configuration of channel: ${channelSlug}`);
},
onError(error) {
appBridge?.dispatch(
actions.Notification({
title: "Error",
text: error.message,
status: "error",
})
);
notifyError("Error", error.message);
},
});

View file

@ -8,7 +8,6 @@ import {
TextFieldProps,
} from "@material-ui/core";
import { Delete, Save } from "@material-ui/icons";
import { actions, useAppBridge } from "@saleor/app-sdk/app-bridge";
import { Button, makeStyles } from "@saleor/macaw-ui";
import React from "react";
import { Controller, useForm } from "react-hook-form";
@ -16,6 +15,7 @@ import { z } from "zod";
import { useInstanceId } from "../../taxes/tax-context";
import { trpcClient } from "../../trpc/trpc-client";
import { taxJarConfigSchema } from "../taxjar-config";
import { useDashboardNotification } from "@saleor/apps-shared";
const useStyles = makeStyles((theme) => ({
reverseRow: {
@ -38,11 +38,11 @@ export const TaxJarConfigurationForm = () => {
const [isWarningDialogOpen, setIsWarningDialogOpen] = React.useState(false);
const styles = useStyles();
const { instanceId, setInstanceId } = useInstanceId();
const { appBridge } = useAppBridge();
const { handleSubmit, reset, control, formState } = useForm<FormValues>({
resolver: zodResolver(schema),
defaultValues,
});
const { notifySuccess, notifyError } = useDashboardNotification();
const resetInstanceId = () => {
setInstanceId(null);
@ -51,13 +51,7 @@ export const TaxJarConfigurationForm = () => {
const { refetch: refetchChannelConfigurationData } =
trpcClient.channelsConfiguration.fetch.useQuery(undefined, {
onError(error) {
appBridge?.dispatch(
actions.Notification({
title: "Error",
text: error.message,
status: "error",
})
);
notifyError("Error", error.message);
},
});
@ -68,13 +62,7 @@ export const TaxJarConfigurationForm = () => {
{
enabled: !!instanceId,
onError(error) {
appBridge?.dispatch(
actions.Notification({
title: "Error",
text: error.message,
status: "error",
})
);
notifyError("Error", error.message);
},
}
);
@ -85,22 +73,11 @@ export const TaxJarConfigurationForm = () => {
setInstanceId(id);
refetchProvidersConfigurationData();
refetchChannelConfigurationData();
appBridge?.dispatch(
actions.Notification({
title: "Success",
text: "Saved TaxJar configuration",
status: "success",
})
);
notifySuccess("Success", "Saved TaxJar configuration");
},
onError(error) {
appBridge?.dispatch(
actions.Notification({
title: "Error",
text: error.message,
status: "error",
})
);
notifyError("Error", error.message);
},
});
@ -109,22 +86,10 @@ export const TaxJarConfigurationForm = () => {
onSuccess() {
refetchProvidersConfigurationData();
refetchChannelConfigurationData();
appBridge?.dispatch(
actions.Notification({
title: "Success",
text: "Updated TaxJar configuration",
status: "success",
})
);
notifySuccess("Success", "Updated TaxJar configuration");
},
onError(error) {
appBridge?.dispatch(
actions.Notification({
title: "Error",
text: error.message,
status: "error",
})
);
notifyError("Error", error.message);
},
});
@ -134,22 +99,11 @@ export const TaxJarConfigurationForm = () => {
resetInstanceId();
refetchProvidersConfigurationData();
refetchChannelConfigurationData();
appBridge?.dispatch(
actions.Notification({
title: "Success",
text: "Removed TaxJar instance",
status: "success",
})
);
notifySuccess("Success", "Removed TaxJar instance");
},
onError(error) {
appBridge?.dispatch(
actions.Notification({
title: "Error",
text: error.message,
status: "error",
})
);
notifyError("Error", error.message);
},
});

View file

@ -1,3 +1,4 @@
export * from "./src/is-in-iframe";
export * from "./src/macaw-theme-provider/macaw-theme-provider";
export * from "./src/no-ssr-wrapper";
export * from "./src/use-dashboard-notification";

View file

@ -0,0 +1,58 @@
import { useCallback } from "react";
import { actions, useAppBridge } from "@saleor/app-sdk/app-bridge";
export const useDashboardNotification = () => {
const { appBridge } = useAppBridge();
return {
notifySuccess: useCallback(
(title: string, text?: string) => {
appBridge?.dispatch(
actions.Notification({
status: "success",
title,
text,
})
);
},
[appBridge]
),
notifyError: useCallback(
(title: string, text?: string, apiMessage?: string) => {
appBridge?.dispatch(
actions.Notification({
status: "error",
title,
text,
apiMessage: apiMessage,
})
);
},
[appBridge]
),
notifyWarning: useCallback(
(title: string, text?: string) => {
appBridge?.dispatch(
actions.Notification({
status: "warning",
title,
text,
})
);
},
[appBridge]
),
notifyInfo: useCallback(
(title: string, text?: string) => {
appBridge?.dispatch(
actions.Notification({
status: "info",
title,
text,
})
);
},
[appBridge]
),
};
};