From df24bac9135aeaa01040bf977aa75e3f83bd1367 Mon Sep 17 00:00:00 2001 From: Ali BARIN Date: Mon, 28 Aug 2023 20:44:55 +0000 Subject: [PATCH] refactor: fetch notifications over graphql query --- .devcontainer/boot.sh | 1 - .vscode/settings.json | 5 ++- .../src/graphql/queries/get-notifications.ts | 15 ++++++++ .../backend/src/graphql/query-resolvers.ts | 4 ++- packages/backend/src/graphql/schema.graphql | 8 +++++ .../backend/src/helpers/authentication.ts | 11 +++--- packages/types/index.d.ts | 7 ++++ packages/web/.env-example | 1 - packages/web/src/config/app.ts | 2 -- .../src/graphql/queries/get-notifications.ts | 12 +++++++ packages/web/src/hooks/useNotifications.ts | 34 ++++++++----------- packages/web/src/hooks/useVersion.ts | 2 +- .../web/src/pages/Notifications/index.tsx | 2 +- 13 files changed, 71 insertions(+), 33 deletions(-) create mode 100644 packages/backend/src/graphql/queries/get-notifications.ts create mode 100644 packages/web/src/graphql/queries/get-notifications.ts diff --git a/.devcontainer/boot.sh b/.devcontainer/boot.sh index 1c1af9e6..b37db9ae 100644 --- a/.devcontainer/boot.sh +++ b/.devcontainer/boot.sh @@ -29,7 +29,6 @@ rm -rf .env echo " PORT=$WEB_PORT REACT_APP_GRAPHQL_URL=http://localhost:$BACKEND_PORT/graphql -REACT_APP_NOTIFICATIONS_URL=https://notifications.automatisch.io " >> .env cd $CURRENT_DIR diff --git a/.vscode/settings.json b/.vscode/settings.json index 1b6457c5..f62af994 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,7 @@ { "editor.formatOnSave": true, - "editor.defaultFormatter": "esbenp.prettier-vscode" + "editor.defaultFormatter": "esbenp.prettier-vscode", + "[javascript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + } } diff --git a/packages/backend/src/graphql/queries/get-notifications.ts b/packages/backend/src/graphql/queries/get-notifications.ts new file mode 100644 index 00000000..39da69b1 --- /dev/null +++ b/packages/backend/src/graphql/queries/get-notifications.ts @@ -0,0 +1,15 @@ +import axios from '../../helpers/axios-with-proxy'; + +const NOTIFICATIONS_URL = 'https://notifications.automatisch.io/notifications.json'; + +const getNotifications = async () => { + try { + const { data: notifications = [] } = await axios.get(NOTIFICATIONS_URL); + + return notifications; + } catch (err) { + return []; + } +}; + +export default getNotifications; diff --git a/packages/backend/src/graphql/query-resolvers.ts b/packages/backend/src/graphql/query-resolvers.ts index 1d484230..20bb6bcb 100644 --- a/packages/backend/src/graphql/query-resolvers.ts +++ b/packages/backend/src/graphql/query-resolvers.ts @@ -16,13 +16,14 @@ import getExecutions from './queries/get-executions'; import getFlow from './queries/get-flow'; import getFlows from './queries/get-flows'; import getInvoices from './queries/get-invoices.ee'; +import getNotifications from './queries/get-notifications'; import getPaddleInfo from './queries/get-paddle-info.ee'; import getPaymentPlans from './queries/get-payment-plans.ee'; import getPermissionCatalog from './queries/get-permission-catalog.ee'; import getRole from './queries/get-role.ee'; import getRoles from './queries/get-roles.ee'; -import getSamlAuthProvider from './queries/get-saml-auth-provider.ee'; import getSamlAuthProviderRoleMappings from './queries/get-saml-auth-provider-role-mappings.ee'; +import getSamlAuthProvider from './queries/get-saml-auth-provider.ee'; import getStepWithTestExecutions from './queries/get-step-with-test-executions'; import getSubscriptionStatus from './queries/get-subscription-status.ee'; import getTrialStatus from './queries/get-trial-status.ee'; @@ -51,6 +52,7 @@ const queryResolvers = { getFlow, getFlows, getInvoices, + getNotifications, getPaddleInfo, getPaymentPlans, getPermissionCatalog, diff --git a/packages/backend/src/graphql/schema.graphql b/packages/backend/src/graphql/schema.graphql index 4237bc84..1c98a8b3 100644 --- a/packages/backend/src/graphql/schema.graphql +++ b/packages/backend/src/graphql/schema.graphql @@ -46,6 +46,7 @@ type Query { getPermissionCatalog: PermissionCatalog getRole(id: String!): Role getRoles: [Role] + getNotifications: [Notification] getSamlAuthProvider: SamlAuthProvider getSamlAuthProviderRoleMappings(id: String!): [SamlAuthProvidersRoleMapping] getSubscriptionStatus: GetSubscriptionStatus @@ -787,6 +788,13 @@ input UpdateAppAuthClientInput { active: Boolean } +type Notification { + name: String + createdAt: String + documentationUrl: String + description: String +} + schema { query: Query mutation: Mutation diff --git a/packages/backend/src/helpers/authentication.ts b/packages/backend/src/helpers/authentication.ts index d57e80c4..83a5d060 100644 --- a/packages/backend/src/helpers/authentication.ts +++ b/packages/backend/src/helpers/authentication.ts @@ -1,7 +1,7 @@ -import { rule, shield, allow } from 'graphql-shield'; +import { allow, rule, shield } from 'graphql-shield'; import jwt from 'jsonwebtoken'; -import User from '../models/user'; import appConfig from '../config/app'; +import User from '../models/user'; const isAuthenticated = rule()(async (_parent, _args, req) => { const token = req.headers['authorization']; @@ -34,15 +34,16 @@ const authentication = shield( Query: { '*': isAuthenticated, getAutomatischInfo: allow, - listSamlAuthProviders: allow, - healthcheck: allow, getConfig: allow, + getNotifications: allow, + healthcheck: allow, + listSamlAuthProviders: allow, }, Mutation: { '*': isAuthenticated, - registerUser: allow, forgotPassword: allow, login: allow, + registerUser: allow, resetPassword: allow, }, }, diff --git a/packages/types/index.d.ts b/packages/types/index.d.ts index 76b7aa6e..c45d85fa 100644 --- a/packages/types/index.d.ts +++ b/packages/types/index.d.ts @@ -448,6 +448,13 @@ type AppAuthClient = { formattedAuthDefaults: IJSONObject; }; +type Notification = { + name: string; + createdAt: string; + documentationUrl: string; + description: string; +} + declare module 'axios' { interface AxiosResponse { httpError?: IJSONObject; diff --git a/packages/web/.env-example b/packages/web/.env-example index 003236c0..a7428e7b 100644 --- a/packages/web/.env-example +++ b/packages/web/.env-example @@ -2,4 +2,3 @@ PORT=3001 REACT_APP_GRAPHQL_URL=http://localhost:3000/graphql # HTTPS=true REACT_APP_BASE_URL=http://localhost:3001 -REACT_APP_NOTIFICATIONS_URL=https://notifications.automatisch.io diff --git a/packages/web/src/config/app.ts b/packages/web/src/config/app.ts index 8e38746e..ed6e016c 100644 --- a/packages/web/src/config/app.ts +++ b/packages/web/src/config/app.ts @@ -2,7 +2,6 @@ type Config = { [key: string]: string; baseUrl: string; graphqlUrl: string; - notificationsUrl: string; chatwootBaseUrl: string; supportEmailAddress: string; }; @@ -10,7 +9,6 @@ type Config = { const config: Config = { baseUrl: process.env.REACT_APP_BASE_URL as string, graphqlUrl: process.env.REACT_APP_GRAPHQL_URL as string, - notificationsUrl: process.env.REACT_APP_NOTIFICATIONS_URL as string, chatwootBaseUrl: 'https://app.chatwoot.com', supportEmailAddress: 'support@automatisch.io', }; diff --git a/packages/web/src/graphql/queries/get-notifications.ts b/packages/web/src/graphql/queries/get-notifications.ts new file mode 100644 index 00000000..7057c3db --- /dev/null +++ b/packages/web/src/graphql/queries/get-notifications.ts @@ -0,0 +1,12 @@ +import { gql } from '@apollo/client'; + +export const GET_NOTIFICATIONS = gql` + query GetNotifications { + getNotifications { + name + createdAt + documentationUrl + description + } + } +`; diff --git a/packages/web/src/hooks/useNotifications.ts b/packages/web/src/hooks/useNotifications.ts index 7f0a396b..9b5215a6 100644 --- a/packages/web/src/hooks/useNotifications.ts +++ b/packages/web/src/hooks/useNotifications.ts @@ -1,26 +1,20 @@ -import * as React from 'react'; -import appConfig from 'config/app'; +import { useQuery } from '@apollo/client'; +import type { Notification } from '@automatisch/types'; -interface INotification { - name: string; - createdAt: string; - documentationUrl: string; - description: string; +import { GET_NOTIFICATIONS } from 'graphql/queries/get-notifications'; + +type UseNotificationsReturn = { + notifications: Notification[]; + loading: boolean; } -export default function useNotifications(): INotification[] { - const [notifications, setNotifications] = React.useState([]); +export default function useNotifications(): UseNotificationsReturn { + const { data, loading } = useQuery(GET_NOTIFICATIONS); - React.useEffect(() => { - fetch(`${appConfig.notificationsUrl}/notifications.json`) - .then((response) => response.json()) - .then((notifications) => { - if (Array.isArray(notifications) && notifications.length) { - setNotifications(notifications); - } - }) - .catch(console.error); - }, []); + const notifications = data?.getNotifications || []; - return notifications; + return { + loading, + notifications, + }; } diff --git a/packages/web/src/hooks/useVersion.ts b/packages/web/src/hooks/useVersion.ts index ec670d48..67fbae9e 100644 --- a/packages/web/src/hooks/useVersion.ts +++ b/packages/web/src/hooks/useVersion.ts @@ -10,7 +10,7 @@ type TVersionInfo = { }; export default function useVersion(): TVersionInfo { - const notifications = useNotifications(); + const { notifications } = useNotifications(); const { data } = useQuery(HEALTHCHECK, { fetchPolicy: 'cache-and-network' }); const version = data?.healthcheck.version; diff --git a/packages/web/src/pages/Notifications/index.tsx b/packages/web/src/pages/Notifications/index.tsx index 716b0f50..43953984 100644 --- a/packages/web/src/pages/Notifications/index.tsx +++ b/packages/web/src/pages/Notifications/index.tsx @@ -17,7 +17,7 @@ interface INotification { export default function Updates(): React.ReactElement { const formatMessage = useFormatMessage(); - const notifications = useNotifications(); + const { notifications } = useNotifications(); return (