Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add push notifications #2369

Merged
merged 70 commits into from
Sep 25, 2023
Merged
Show file tree
Hide file tree
Changes from 50 commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
92106a8
feat: implement Firebase Cloud Messaging
iamacook Aug 8, 2023
2654d76
fix: move to custom `next-pwa` worker
iamacook Aug 8, 2023
d3b8624
Revert "fix: move to custom `next-pwa` worker"
iamacook Aug 9, 2023
6fded4a
fix: remove `next-pwa`
iamacook Aug 9, 2023
ae952c5
fix: convert SW to TS + add notification text
iamacook Aug 9, 2023
2168cdf
fix: improve notifications
iamacook Aug 9, 2023
70ee4ca
refactor: separate types + add test
iamacook Aug 9, 2023
771ba43
fix: improve UI + add partial tests
iamacook Aug 10, 2023
bba709a
fix: add more test coverage
iamacook Aug 10, 2023
94918a1
fix: list Safes
iamacook Aug 11, 2023
d363062
Merge branch 'dev' into firebase
iamacook Aug 17, 2023
77f90df
Merge branch 'dev' into firebase
iamacook Aug 22, 2023
1a48177
fix: migrate to SDK
iamacook Aug 22, 2023
819e652
feat: basic notification preferences
iamacook Aug 22, 2023
7a4e788
fix: tests
iamacook Aug 22, 2023
ef23f7c
fix: implement designs
iamacook Aug 22, 2023
1ded885
feat: per-Safe preferences
iamacook Aug 23, 2023
ea9a72a
refactor: move registrations to IndexedDB
iamacook Aug 23, 2023
b71acd5
fix: adjust style, add banner + registration list
iamacook Aug 23, 2023
12d9c1d
fix: split databases + finish design
iamacook Aug 24, 2023
c770a39
fix: database reactivity with `ExternalStore`
iamacook Aug 24, 2023
4e65035
fix: update tests
iamacook Aug 25, 2023
797fb38
Merge branch 'dev' into firebase
iamacook Aug 25, 2023
d7eb862
fix: preferences, env vars, not in UI + tweaks
iamacook Aug 25, 2023
0e8facd
feat: add deep link to notification
iamacook Aug 25, 2023
72a6353
fix: add tracking + rename to push notifications
iamacook Aug 25, 2023
82ceaf8
fix: test
iamacook Aug 25, 2023
e638ed4
fix: condense preferences
iamacook Aug 25, 2023
95d06d0
Merge branch 'dev' into firebase
iamacook Aug 28, 2023
f369958
Merge branch 'dev' into firebase
iamacook Aug 30, 2023
6f10676
fix: address review comments + adjust design
iamacook Aug 30, 2023
e861ced
fix: test
iamacook Aug 30, 2023
d246610
refactor: clean up code
iamacook Aug 31, 2023
c2e366a
refactor: make `_parseWebhookNotification` a map
iamacook Aug 31, 2023
6508339
fix: register for confirmation requests by default
iamacook Aug 31, 2023
b87a259
fix: adjust text + fix tests
iamacook Aug 31, 2023
9e91423
fix: reduce service worker bundle size
iamacook Aug 31, 2023
ffcfd00
fix: don't re-export
iamacook Aug 31, 2023
7a1ed3d
wip: reimplement next-pwa
iamacook Sep 6, 2023
8d33c98
fix: `next-pwa` with custom worker
iamacook Sep 6, 2023
e227b5f
chore: convert env var to JSON
iamacook Sep 6, 2023
75b5a63
refactor: abstract code from component + fix test
iamacook Sep 6, 2023
ac3d9e2
fix: env issue
iamacook Sep 6, 2023
f7047d8
refactor: leverage SDK
iamacook Sep 6, 2023
ceaacff
feat: add cached tracking
iamacook Sep 7, 2023
2350d58
fix: test
iamacook Sep 7, 2023
e10df30
fix: mock response on Safe Apps share page
iamacook Sep 7, 2023
168886e
revert: cached tracking
iamacook Sep 7, 2023
bbe73f4
refactor: restructure/rename + add error codes
iamacook Sep 7, 2023
a115c14
fix: address review comments
iamacook Sep 8, 2023
12116b7
fix: address comments
iamacook Sep 14, 2023
93b614e
fix: regenerate lockfile
iamacook Sep 14, 2023
cc5fa66
fix: address comments
iamacook Sep 14, 2023
a8ed67a
feat: add push notification tracking (#2500)
iamacook Sep 18, 2023
f7836a2
feat: add close button to banner
iamacook Sep 18, 2023
28517d7
fix: remove unnecessary types + qa findings
iamacook Sep 18, 2023
8cea4ed
fix: texts, confirmation registration + enable all
iamacook Sep 19, 2023
944bad8
fix: mock
iamacook Sep 19, 2023
124827d
fix: spacing
iamacook Sep 19, 2023
e0bd7b8
fix: spacing
iamacook Sep 19, 2023
482a015
Merge branch 'firebase' of github.com:safe-global/web-core into firebase
iamacook Sep 19, 2023
e9e94c0
fix: use EIP-191
iamacook Sep 22, 2023
19f4219
Merge remote-tracking branch 'origin/dev' into firebase
iamacook Sep 25, 2023
75b6177
fix: test
iamacook Sep 25, 2023
21bdb3d
feat: add feature flag
iamacook Sep 25, 2023
8c2ae58
fix: test
iamacook Sep 25, 2023
8c381b2
Merge branch 'dev' into firebase
iamacook Sep 25, 2023
e18c16b
fix: add space + only show banner on added Safes
iamacook Sep 25, 2023
1cb4116
fix: remove space
iamacook Sep 25, 2023
7b85e74
fix: e2e
iamacook Sep 25, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,12 @@ NEXT_PUBLIC_CYPRESS_MNEMONIC=
NEXT_PUBLIC_SAFE_GELATO_RELAY_SERVICE_URL_PRODUCTION=
NEXT_PUBLIC_SAFE_GELATO_RELAY_SERVICE_URL_STAGING=

# Firebase Cloud Messaging
NEXT_PUBLIC_FIREBASE_OPTIONS_PRODUCTION=
NEXT_PUBLIC_FIREBASE_VAPID_KEY_PRODUCTION=

NEXT_PUBLIC_FIREBASE_OPTIONS_STAGING=
NEXT_PUBLIC_FIREBASE_VAPID_KEY_STAGING=

# Redefine
NEXT_PUBLIC_REDEFINE_API=
4 changes: 4 additions & 0 deletions .github/workflows/build/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,7 @@ runs:
NEXT_PUBLIC_SAFE_RELAY_SERVICE_URL_STAGING: ${{ fromJSON(inputs.secrets).NEXT_PUBLIC_SAFE_GELATO_RELAY_SERVICE_URL_STAGING }}
NEXT_PUBLIC_IS_OFFICIAL_HOST: ${{ fromJSON(inputs.secrets).NEXT_PUBLIC_IS_OFFICIAL_HOST }}
NEXT_PUBLIC_REDEFINE_API: ${{ fromJSON(inputs.secrets).NEXT_PUBLIC_REDEFINE_API }}
NEXT_PUBLIC_FIREBASE_OPTIONS_PRODUCTION: ${{ fromJSON(inputs.secrets).NEXT_PUBLIC_FIREBASE_OPTIONS_PRODUCTION }}
NEXT_PUBLIC_FIREBASE_OPTIONS_STAGING: ${{ fromJSON(inputs.secrets).NEXT_PUBLIC_FIREBASE_OPTIONS_STAGING }}
NEXT_PUBLIC_FIREBASE_VAPID_KEY_PRODUCTION: ${{ fromJSON(inputs.secrets).NEXT_PUBLIC_FIREBASE_VAPID_KEY_PRODUCTION }}
NEXT_PUBLIC_FIREBASE_VAPID_KEY_STAGING: ${{ fromJSON(inputs.secrets).NEXT_PUBLIC_FIREBASE_VAPID_KEY_STAGING }}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ yalc.lock

/public/sw.js
/public/sw.js.map
/public/worker-*.js
/public/workbox-*.js
/public/workbox-*.js.map
/public/fallback*
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ Here's the list of all the required and optional variables:
| `NEXT_PUBLIC_SAFE_GELATO_RELAY_SERVICE_URL_STAGING` | optional | Relay URL on staging
| `NEXT_PUBLIC_IS_OFFICIAL_HOST` | optional | Whether it's the official distribution of the app, or a fork; has legal implications. Set to true only if you also update the legal pages like Imprint and Terms of use
| `NEXT_PUBLIC_REDEFINE_API` | optional | Redefine API base URL
| `NEXT_PUBLIC_FIREBASE_OPTIONS_PRODUCTION` | optional | Firebase Cloud Messaging (FCM) `initializeApp` options on production
| `NEXT_PUBLIC_FIREBASE_VAPID_KEY_PRODUCTION` | optional | FCM vapid key on production
| `NEXT_PUBLIC_FIREBASE_OPTIONS_STAGING` | optional | FCM `initializeApp` options on staging
| `NEXT_PUBLIC_FIREBASE_VAPID_KEY_STAGING` | optional | FCM vapid key on staging

If you don't provide some of the optional vars, the corresponding features will be disabled in the UI.

Expand Down
13 changes: 10 additions & 3 deletions next.config.mjs
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
import path from 'path'
import withBundleAnalyzer from '@next/bundle-analyzer'
import NextPwa from 'next-pwa'
import withPWAInit from '@ducanh2912/next-pwa'

const withPWA = NextPwa({
disable: process.env.NODE_ENV === 'development',
const SERVICE_WORKERS_PATH = './src/service-workers'

const withPWA = withPWAInit({
dest: 'public',
workboxOptions: {
mode: 'production',
},
reloadOnOnline: false,
/* Do not precache anything */
publicExcludes: ['**/*'],
buildExcludes: [/./],
customWorkerSrc: SERVICE_WORKERS_PATH,
// Prefer InjectManifest for Web Push
swSrc: `${SERVICE_WORKERS_PATH}/index.ts`,
})

/** @type {import('next').NextConfig} */
Expand Down
13 changes: 9 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"routes": "node scripts/generate-routes.js > src/config/routes.ts && prettier -w src/config/routes.ts && cat src/config/routes.ts",
"css-vars": "ts-node-esm ./scripts/css-vars.ts > ./src/styles/vars.css && prettier -w src/styles/vars.css",
"generate-types": "typechain --target ethers-v5 --out-dir src/types/contracts ./node_modules/@safe-global/safe-deployments/dist/assets/**/*.json ./node_modules/@safe-global/safe-modules-deployments/dist/assets/**/*.json ./node_modules/@openzeppelin/contracts/build/contracts/ERC20.json ./node_modules/@openzeppelin/contracts/build/contracts/ERC721.json",
"postinstall": "yarn generate-types && yarn css-vars",
"postinstall": "yarn patch-package && yarn generate-types && yarn css-vars",
"analyze": "cross-env ANALYZE=true yarn build",
"cypress:open": "cross-env TZ=UTC cypress open --e2e",
"cypress:canary": "cross-env TZ=UTC cypress open --e2e -b chrome:canary",
Expand All @@ -39,6 +39,7 @@
},
"dependencies": {
"@date-io/date-fns": "^2.15.0",
"@ducanh2912/next-pwa": "^9.5.0",
"@emotion/cache": "^11.10.1",
"@emotion/react": "^11.10.0",
"@emotion/server": "^11.10.0",
Expand All @@ -52,7 +53,7 @@
"@safe-global/safe-core-sdk-utils": "^1.7.4",
"@safe-global/safe-deployments": "1.25.0",
"@safe-global/safe-ethers-lib": "^1.9.4",
"@safe-global/safe-gateway-typescript-sdk": "^3.9.0",
"@safe-global/safe-gateway-typescript-sdk": "^3.11.0",
"@safe-global/safe-modules-deployments": "^1.0.0",
"@safe-global/safe-react-components": "^2.0.6",
"@sentry/react": "^7.28.1",
Expand All @@ -70,12 +71,13 @@
"ethereum-blockies-base64": "^1.0.2",
"ethers": "5.7.2",
"exponential-backoff": "^3.1.0",
"firebase": "^10.3.1",
"framer-motion": "^10.13.1",
"fuse.js": "^6.6.2",
"idb-keyval": "^6.2.1",
"js-cookie": "^3.0.1",
"lodash": "^4.17.21",
"next": "^13.2.0",
"next-pwa": "^5.6.0",
"papaparse": "^5.3.2",
"qrcode.react": "^3.1.0",
"react": "18.2.0",
Expand Down Expand Up @@ -118,14 +120,17 @@
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-unused-imports": "^2.0.0",
"fake-indexeddb": "^4.0.2",
"jest": "^29.6.2",
"jest-environment-jsdom": "^29.6.2",
"patch-package": "^8.0.0",
"pre-commit": "^1.2.2",
"prettier": "^2.7.0",
"ts-node": "^10.8.2",
"ts-prune": "^0.10.3",
"typechain": "^8.0.0",
"typescript": "4.9.4",
"typescript-plugin-css-modules": "^4.2.2"
"typescript-plugin-css-modules": "^4.2.2",
"webpack": "^5.88.2"
usame-algan marked this conversation as resolved.
Show resolved Hide resolved
}
}
24 changes: 24 additions & 0 deletions patches/@ducanh2912+next-pwa+9.5.0.patch

Large diffs are not rendered by default.

11 changes: 11 additions & 0 deletions public/images/notifications/push-notification.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
28 changes: 4 additions & 24 deletions src/components/batch/BatchIndicator/BatchTooltip.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,9 @@
import { type ReactElement, useEffect, useState } from 'react'
import { Box, SvgIcon } from '@mui/material'
import Tooltip, { type TooltipProps, tooltipClasses } from '@mui/material/Tooltip'
import { styled } from '@mui/material/styles'

import SuccessIcon from '@/public/images/common/success.svg'
import { TxEvent, txSubscribe } from '@/services/tx/txEvents'

const StyledTooltip = styled(({ className, ...props }: TooltipProps) => (
<Tooltip {...props} classes={{ popper: className }} />
))(({ theme }) => ({
[`& .${tooltipClasses.tooltip}`]: {
backgroundColor: theme.palette.background.paper,
color: theme.palette.text.primary,
fontSize: theme.typography.pxToRem(16),
fontWeight: 700,
border: `1px solid ${theme.palette.border.light}`,
marginTop: theme.spacing(2) + ' !important',
},
[`& .${tooltipClasses.arrow}`]: {
color: theme.palette.background.paper,
},
[`& .${tooltipClasses.arrow}:before`]: {
border: `1px solid ${theme.palette.border.light}`,
},
}))
import { CustomTooltip } from '@/components/common/CustomTooltip'

const BatchTooltip = ({ children }: { children: ReactElement }) => {
const [showTooltip, setShowTooltip] = useState<boolean>(false)
Expand All @@ -40,10 +21,9 @@ const BatchTooltip = ({ children }: { children: ReactElement }) => {
}, [])

return (
<StyledTooltip
<CustomTooltip
open={showTooltip}
onClose={() => setShowTooltip(false)}
arrow
title={
<Box display="flex" flexDirection="column" alignItems="center" p={2} gap={2}>
<Box fontSize="53px">
Expand All @@ -54,7 +34,7 @@ const BatchTooltip = ({ children }: { children: ReactElement }) => {
}
>
<div>{children}</div>
</StyledTooltip>
</CustomTooltip>
)
}

Expand Down
22 changes: 22 additions & 0 deletions src/components/common/CustomTooltip/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { styled } from '@mui/material/styles'
import Tooltip, { tooltipClasses } from '@mui/material/Tooltip'
import { type TooltipProps } from '@mui/material/Tooltip'

export const CustomTooltip = styled(({ className, ...props }: TooltipProps) => (
<Tooltip {...props} classes={{ popper: className }} arrow />
))(({ theme }) => ({
[`& .${tooltipClasses.tooltip}`]: {
backgroundColor: theme.palette.background.paper,
color: theme.palette.text.primary,
fontSize: theme.typography.pxToRem(16),
fontWeight: 700,
border: `1px solid ${theme.palette.border.light}`,
marginTop: theme.spacing(2) + ' !important',
},
[`& .${tooltipClasses.arrow}`]: {
color: theme.palette.background.paper,
},
[`& .${tooltipClasses.arrow}:before`]: {
border: `1px solid ${theme.palette.border.light}`,
},
}))
5 changes: 4 additions & 1 deletion src/components/common/Header/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import SafeLogo from '@/public/images/logo.svg'
import Link from 'next/link'
import useSafeAddress from '@/hooks/useSafeAddress'
import BatchIndicator from '@/components/batch/BatchIndicator'
import { PushNotificationsBanner } from '@/components/settings/PushNotifications/PushNotificationsBanner'

type HeaderProps = {
onMenuToggle?: Dispatch<SetStateAction<boolean>>
Expand Down Expand Up @@ -71,7 +72,9 @@ const Header = ({ onMenuToggle, onBatchToggle }: HeaderProps): ReactElement => {
)}

<div className={css.element}>
<NotificationCenter />
<PushNotificationsBanner>
<NotificationCenter />
</PushNotificationsBanner>
</div>

<div className={classnames(css.element, css.connectWallet)}>
Expand Down
Loading
Loading