├── .dockerignore ├── .env.example ├── .gitattributes ├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── next.config.js ├── package-lock.json ├── package.json ├── postcss.config.mjs ├── public ├── android │ ├── android-launchericon-144-144.png │ ├── android-launchericon-192-192.png │ ├── android-launchericon-48-48.png │ ├── android-launchericon-512-512.png │ ├── android-launchericon-72-72.png │ └── android-launchericon-96-96.png ├── ios-pwa │ └── pwa_ios.jpg ├── ios │ ├── 100.png │ ├── 1024.png │ ├── 114.png │ ├── 120.png │ ├── 128.png │ ├── 144.png │ ├── 152.png │ ├── 16.png │ ├── 167.png │ ├── 180.png │ ├── 192.png │ ├── 20.png │ ├── 256.png │ ├── 29.png │ ├── 32.png │ ├── 40.png │ ├── 50.png │ ├── 512.png │ ├── 57.png │ ├── 58.png │ ├── 60.png │ ├── 64.png │ ├── 72.png │ ├── 76.png │ ├── 80.png │ └── 87.png ├── logo.jpg ├── logo.svg ├── manifest.json ├── notification-sw.js ├── user.png └── windows11 │ ├── LargeTile.scale-100.png │ ├── LargeTile.scale-125.png │ ├── LargeTile.scale-150.png │ ├── LargeTile.scale-200.png │ ├── LargeTile.scale-400.png │ ├── SmallTile.scale-100.png │ ├── SmallTile.scale-125.png │ ├── SmallTile.scale-150.png │ ├── SmallTile.scale-200.png │ ├── SmallTile.scale-400.png │ ├── SplashScreen.scale-100.png │ ├── SplashScreen.scale-125.png │ ├── SplashScreen.scale-150.png │ ├── SplashScreen.scale-200.png │ ├── SplashScreen.scale-400.png │ ├── Square150x150Logo.scale-100.png │ ├── Square150x150Logo.scale-125.png │ ├── Square150x150Logo.scale-150.png │ ├── Square150x150Logo.scale-200.png │ ├── Square150x150Logo.scale-400.png │ ├── Square44x44Logo.altform-lightunplated_targetsize-16.png │ ├── Square44x44Logo.altform-lightunplated_targetsize-20.png │ ├── Square44x44Logo.altform-lightunplated_targetsize-24.png │ ├── Square44x44Logo.altform-lightunplated_targetsize-256.png │ ├── Square44x44Logo.altform-lightunplated_targetsize-30.png │ ├── Square44x44Logo.altform-lightunplated_targetsize-32.png │ ├── Square44x44Logo.altform-lightunplated_targetsize-36.png │ ├── Square44x44Logo.altform-lightunplated_targetsize-40.png │ ├── Square44x44Logo.altform-lightunplated_targetsize-44.png │ ├── Square44x44Logo.altform-lightunplated_targetsize-48.png │ ├── Square44x44Logo.altform-lightunplated_targetsize-60.png │ ├── Square44x44Logo.altform-lightunplated_targetsize-64.png │ ├── Square44x44Logo.altform-lightunplated_targetsize-72.png │ ├── Square44x44Logo.altform-lightunplated_targetsize-80.png │ ├── Square44x44Logo.altform-lightunplated_targetsize-96.png │ ├── Square44x44Logo.altform-unplated_targetsize-16.png │ ├── Square44x44Logo.altform-unplated_targetsize-20.png │ ├── Square44x44Logo.altform-unplated_targetsize-24.png │ ├── Square44x44Logo.altform-unplated_targetsize-256.png │ ├── Square44x44Logo.altform-unplated_targetsize-30.png │ ├── Square44x44Logo.altform-unplated_targetsize-32.png │ ├── Square44x44Logo.altform-unplated_targetsize-36.png │ ├── Square44x44Logo.altform-unplated_targetsize-40.png │ ├── Square44x44Logo.altform-unplated_targetsize-44.png │ ├── Square44x44Logo.altform-unplated_targetsize-48.png │ ├── Square44x44Logo.altform-unplated_targetsize-60.png │ ├── Square44x44Logo.altform-unplated_targetsize-64.png │ ├── Square44x44Logo.altform-unplated_targetsize-72.png │ ├── Square44x44Logo.altform-unplated_targetsize-80.png │ ├── Square44x44Logo.altform-unplated_targetsize-96.png │ ├── Square44x44Logo.scale-100.png │ ├── Square44x44Logo.scale-125.png │ ├── Square44x44Logo.scale-150.png │ ├── Square44x44Logo.scale-200.png │ ├── Square44x44Logo.scale-400.png │ ├── Square44x44Logo.targetsize-16.png │ ├── Square44x44Logo.targetsize-20.png │ ├── Square44x44Logo.targetsize-24.png │ ├── Square44x44Logo.targetsize-256.png │ ├── Square44x44Logo.targetsize-30.png │ ├── Square44x44Logo.targetsize-32.png │ ├── Square44x44Logo.targetsize-36.png │ ├── Square44x44Logo.targetsize-40.png │ ├── Square44x44Logo.targetsize-44.png │ ├── Square44x44Logo.targetsize-48.png │ ├── Square44x44Logo.targetsize-60.png │ ├── Square44x44Logo.targetsize-64.png │ ├── Square44x44Logo.targetsize-72.png │ ├── Square44x44Logo.targetsize-80.png │ ├── Square44x44Logo.targetsize-96.png │ ├── StoreLogo.scale-100.png │ ├── StoreLogo.scale-125.png │ ├── StoreLogo.scale-150.png │ ├── StoreLogo.scale-200.png │ ├── StoreLogo.scale-400.png │ ├── Wide310x150Logo.scale-100.png │ ├── Wide310x150Logo.scale-125.png │ ├── Wide310x150Logo.scale-150.png │ ├── Wide310x150Logo.scale-200.png │ └── Wide310x150Logo.scale-400.png ├── src ├── app │ ├── api │ │ └── web-push │ │ │ └── send │ │ │ └── route.ts │ ├── globals.css │ ├── layout.tsx │ └── page.tsx ├── components │ ├── NotificationSubscriptionForm.tsx │ ├── NotificationSubscriptionStatus.tsx │ └── UnsupportedNotificationMessage.tsx └── notifications │ ├── NotificationPush.ts │ ├── NotificationSender.ts │ └── useNotification.tsx ├── tailwind.config.ts └── tsconfig.json /.dockerignore: -------------------------------------------------------------------------------- 1 | # .dockerignore file 2 | .DS_Store 3 | .next 4 | node_modules 5 | .gitignore 6 | README.md 7 | .dockerignore 8 | LICENSE 9 | .docker 10 | .gitlab 11 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | # use command `web-push generate-vapid-keys --json` to generate a new key 2 | NEXT_PUBLIC_VAPID_PUBLIC_KEY= 3 | VAPID_PRIVATE_KEY= 4 | NOTIFICATION_URL=http://localhost:3000/ -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | .env 31 | 32 | # vercel 33 | .vercel 34 | 35 | # typescript 36 | *.tsbuildinfo 37 | next-env.d.ts 38 | 39 | public/sw-pwa.js 40 | public/sw-pwa.js.map 41 | public/workbox-*.js 42 | public/workbox-*.js.map 43 | /.idea 44 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:20-alpine AS builder 2 | WORKDIR /app 3 | ENV NEXT_TELEMETRY_DISABLED=1 4 | COPY package*.json ./ 5 | RUN yarn --network-timeout 100000 6 | COPY . . 7 | RUN yarn standalone 8 | 9 | FROM alpine:3.20 10 | RUN apk add --no-cache nodejs && \ 11 | addgroup --system --gid 1001 node && \ 12 | adduser --system --uid 1001 node && \ 13 | mkdir -p /nextjs-app && \ 14 | chown -R node:node /nextjs-app 15 | WORKDIR /nextjs-app 16 | ENV NEXT_TELEMETRY_DISABLED=1 17 | ENV NODE_ENV=production 18 | COPY --from=builder --chown=node:node /app/.next/standalone . 19 | USER node 20 | EXPOSE 3000 21 | ENV PORT=3000 22 | CMD [ "node", "server.js" ] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 David Randoll 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | A sample project for push notifications with Next.js. The app used web push notifications to send messages to users. The 2 | notification should work on all devices and browsers. 3 | 4 | **Require IOS 16+ for Apple devices.** 5 | 6 | ## Demo 7 | 8 | A live demo of the project can be found [here](https://push-notification.davidrandoll.com/) 9 | 10 | ## Running Locally 11 | 12 | First, run the development server: 13 | 14 | ```bash 15 | npm install 16 | ``` 17 | 18 | Run the below command to generate the vapid keys. Once you have the keys, rename the `.env.example` file to `.env` and 19 | insert the keys. 20 | 21 | ```bash 22 | web-push generate-vapid-keys --json 23 | ``` 24 | 25 | Start the development server: 26 | 27 | ```bash 28 | npm run dev 29 | ``` 30 | 31 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 32 | 33 | ## How it works 34 | 35 | The app uses the [web-push](https://www.npmjs.com/package/web-push) package to send push notifications. The app has a 36 | service worker that listens for push events and displays the notification. 37 | 38 | Using just this package is enough to send push notifications from most devices and browsers. 39 | 40 | However, on Apple devices, there are a few extra things we have to do. 41 | 42 | - The app must be served over HTTPS with a valid SSL certificate. 43 | - The app must be a PWA (Progressive Web App). 44 | 45 | You can read more about it [here](https://developer.apple.com/documentation/usernotifications/sending-web-push-notifications-in-web-apps-and-browsers). 46 | 47 | ## Configuration 48 | 49 | Install the below packages. 50 | 51 | ```bash 52 | npm install web-push next-pwa 53 | ``` 54 | 55 | Skip this step if you are using typescript. 56 | 57 | ```bash 58 | npm install @types/web-push --save-dev 59 | ``` 60 | 61 | ### Setting up the notification 62 | 63 | Copy the [notification-sw.js](https://github.com/david-randoll/push-notification-nextjs/blob/main/public/notification-sw.js) file into the `public` folder. This is a service worker that listens for push events and displays the notification. 64 | 65 | Copy the files under the [notifications](https://github.com/david-randoll/push-notification-nextjs/tree/main/src/notifications) folder and paste them into your src folder. In my case I pasted them in the 66 | `src/notifications` folder. The `useNotification` hook will be used in the app to subscribe a user and store the 67 | subscription in state. This subscription can be stored in a database and used to send notifications per user. 68 | 69 | Take a look at the `page.tsx` file to see how the `useNotification` hook is used. The `page.tsx` calls an endpoint that is found under `src/app/api/web-push/send/route.ts`. This will send the notification to the user. 70 | 71 | With this should be able to send notifications now. For Apple devices, you will need to configure the app as a PWA in the next step. 72 | 73 | ### Configuring as a PWA 74 | 75 | The [next-pwa](https://www.npmjs.com/package/next-pwa) package will generate a `sw-pwa.js` and a `workbox-*.js` file in 76 | the public folder. 77 | 78 | I am going to use [pwabuilder](https://www.pwabuilder.com/imageGenerator) to generate the icons for the app. This will generate the different sizes of the icon that are needed for different devices. After going to the site, download the zip file and place the contents into the public folder. You should get 3 folders: android, ios, and windows. Also, an `icons.json` file which we will use for our manifest file. 79 | 80 | Move the `icons.json` file to the `public` folder and rename it to `manifest.json`. 81 | 82 | ```json 83 | { 84 | "name": "Push Notification Sample", 85 | "short_name": "Push Notification Sample", 86 | "description": "A sample project for push notifications with Next.js", 87 | "theme_color": "#FFFFFF", 88 | "background_color": "#FFFFFF", 89 | "start_url": "/", 90 | "display": "standalone", 91 | "orientation": "portrait", 92 | "icons": // the icons will be here 93 | } 94 | ``` 95 | 96 | add the `manifest.json` file to the `layout.tsx` file. 97 | 98 | ```tsx 99 | export default function RootLayout({ 100 | children, 101 | }: Readonly<{ 102 | children: React.ReactNode; 103 | }>) { 104 | return ( 105 | 106 | 107 | 108 | 109 | 110 | {children} 111 | 112 | 113 | ); 114 | } 115 | ``` 116 | 117 | modify the `next.config.js` file to include the `next-pwa` configuration. 118 | 119 | ```javascript 120 | /** @type {import('next').NextConfig} */ 121 | 122 | const withPWA = require("next-pwa")({ 123 | dest: "public", 124 | sw: "sw-pwa.js", 125 | }); 126 | 127 | module.exports = withPWA({ 128 | output: "standalone", 129 | }); 130 | ``` -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | 3 | const withPWA = require("next-pwa")({ 4 | dest: "public", 5 | sw: "sw-pwa.js", 6 | }); 7 | 8 | module.exports = withPWA({ 9 | output: "standalone", 10 | }); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "push-notification-nextjs", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "standalone": "next build && cp -r public/ .next/standalone && cp -r .next/static .next/standalone/.next", 9 | "start": "next start", 10 | "lint": "next lint" 11 | }, 12 | "dependencies": { 13 | "next": "14.2.14", 14 | "next-pwa": "^5.6.0", 15 | "react": "^18", 16 | "react-dom": "^18", 17 | "web-push": "^3.6.7" 18 | }, 19 | "devDependencies": { 20 | "@types/node": "^20", 21 | "@types/react": "^18", 22 | "@types/react-dom": "^18", 23 | "@types/web-push": "^3.6.3", 24 | "postcss": "^8", 25 | "tailwindcss": "^3.4.1", 26 | "typescript": "^5" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /postcss.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('postcss-load-config').Config} */ 2 | const config = { 3 | plugins: { 4 | tailwindcss: {}, 5 | }, 6 | }; 7 | 8 | export default config; 9 | -------------------------------------------------------------------------------- /public/android/android-launchericon-144-144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/android/android-launchericon-144-144.png -------------------------------------------------------------------------------- /public/android/android-launchericon-192-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/android/android-launchericon-192-192.png -------------------------------------------------------------------------------- /public/android/android-launchericon-48-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/android/android-launchericon-48-48.png -------------------------------------------------------------------------------- /public/android/android-launchericon-512-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/android/android-launchericon-512-512.png -------------------------------------------------------------------------------- /public/android/android-launchericon-72-72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/android/android-launchericon-72-72.png -------------------------------------------------------------------------------- /public/android/android-launchericon-96-96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/android/android-launchericon-96-96.png -------------------------------------------------------------------------------- /public/ios-pwa/pwa_ios.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/ios-pwa/pwa_ios.jpg -------------------------------------------------------------------------------- /public/ios/100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/ios/100.png -------------------------------------------------------------------------------- /public/ios/1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/ios/1024.png -------------------------------------------------------------------------------- /public/ios/114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/ios/114.png -------------------------------------------------------------------------------- /public/ios/120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/ios/120.png -------------------------------------------------------------------------------- /public/ios/128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/ios/128.png -------------------------------------------------------------------------------- /public/ios/144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/ios/144.png -------------------------------------------------------------------------------- /public/ios/152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/ios/152.png -------------------------------------------------------------------------------- /public/ios/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/ios/16.png -------------------------------------------------------------------------------- /public/ios/167.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/ios/167.png -------------------------------------------------------------------------------- /public/ios/180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/ios/180.png -------------------------------------------------------------------------------- /public/ios/192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/ios/192.png -------------------------------------------------------------------------------- /public/ios/20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/ios/20.png -------------------------------------------------------------------------------- /public/ios/256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/ios/256.png -------------------------------------------------------------------------------- /public/ios/29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/ios/29.png -------------------------------------------------------------------------------- /public/ios/32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/ios/32.png -------------------------------------------------------------------------------- /public/ios/40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/ios/40.png -------------------------------------------------------------------------------- /public/ios/50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/ios/50.png -------------------------------------------------------------------------------- /public/ios/512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/ios/512.png -------------------------------------------------------------------------------- /public/ios/57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/ios/57.png -------------------------------------------------------------------------------- /public/ios/58.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/ios/58.png -------------------------------------------------------------------------------- /public/ios/60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/ios/60.png -------------------------------------------------------------------------------- /public/ios/64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/ios/64.png -------------------------------------------------------------------------------- /public/ios/72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/ios/72.png -------------------------------------------------------------------------------- /public/ios/76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/ios/76.png -------------------------------------------------------------------------------- /public/ios/80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/ios/80.png -------------------------------------------------------------------------------- /public/ios/87.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/ios/87.png -------------------------------------------------------------------------------- /public/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/logo.jpg -------------------------------------------------------------------------------- /public/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.10, written by Peter Selinger 2001-2011 9 | 10 | 12 | 15 | 63 | 71 | 109 | 111 | 224 | 226 | 228 | 230 | 232 | 234 | 236 | 238 | 241 | 243 | 246 | 249 | 252 | 254 | 257 | 259 | 261 | 264 | 269 | 270 | 272 | 275 | 283 | 293 | 295 | 297 | 299 | 302 | 307 | 309 | 320 | 324 | 330 | 332 | 334 | 336 | 340 | 342 | 344 | 361 | 364 | 366 | 367 | 369 | 371 | 373 | 376 | 381 | 382 | 389 | 393 | 396 | 398 | 403 | 404 | 412 | 417 | 419 | 421 | 423 | 424 | 426 | 428 | 429 | 430 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Push Notification Sample", 3 | "short_name": "Push Notification Sample", 4 | "description": "A sample project for push notifications with Next.js", 5 | "theme_color": "#FFFFFF", 6 | "background_color": "#FFFFFF", 7 | "start_url": "/", 8 | "display": "standalone", 9 | "orientation": "portrait", 10 | "icons": [ 11 | { 12 | "src": "windows11/SmallTile.scale-100.png", 13 | "sizes": "71x71" 14 | }, 15 | { 16 | "src": "windows11/SmallTile.scale-125.png", 17 | "sizes": "89x89" 18 | }, 19 | { 20 | "src": "windows11/SmallTile.scale-150.png", 21 | "sizes": "107x107" 22 | }, 23 | { 24 | "src": "windows11/SmallTile.scale-200.png", 25 | "sizes": "142x142" 26 | }, 27 | { 28 | "src": "windows11/SmallTile.scale-400.png", 29 | "sizes": "284x284" 30 | }, 31 | { 32 | "src": "windows11/Square150x150Logo.scale-100.png", 33 | "sizes": "150x150" 34 | }, 35 | { 36 | "src": "windows11/Square150x150Logo.scale-125.png", 37 | "sizes": "188x188" 38 | }, 39 | { 40 | "src": "windows11/Square150x150Logo.scale-150.png", 41 | "sizes": "225x225" 42 | }, 43 | { 44 | "src": "windows11/Square150x150Logo.scale-200.png", 45 | "sizes": "300x300" 46 | }, 47 | { 48 | "src": "windows11/Square150x150Logo.scale-400.png", 49 | "sizes": "600x600" 50 | }, 51 | { 52 | "src": "windows11/Wide310x150Logo.scale-100.png", 53 | "sizes": "310x150" 54 | }, 55 | { 56 | "src": "windows11/Wide310x150Logo.scale-125.png", 57 | "sizes": "388x188" 58 | }, 59 | { 60 | "src": "windows11/Wide310x150Logo.scale-150.png", 61 | "sizes": "465x225" 62 | }, 63 | { 64 | "src": "windows11/Wide310x150Logo.scale-200.png", 65 | "sizes": "620x300" 66 | }, 67 | { 68 | "src": "windows11/Wide310x150Logo.scale-400.png", 69 | "sizes": "1240x600" 70 | }, 71 | { 72 | "src": "windows11/LargeTile.scale-100.png", 73 | "sizes": "310x310" 74 | }, 75 | { 76 | "src": "windows11/LargeTile.scale-125.png", 77 | "sizes": "388x388" 78 | }, 79 | { 80 | "src": "windows11/LargeTile.scale-150.png", 81 | "sizes": "465x465" 82 | }, 83 | { 84 | "src": "windows11/LargeTile.scale-200.png", 85 | "sizes": "620x620" 86 | }, 87 | { 88 | "src": "windows11/LargeTile.scale-400.png", 89 | "sizes": "1240x1240" 90 | }, 91 | { 92 | "src": "windows11/Square44x44Logo.scale-100.png", 93 | "sizes": "44x44" 94 | }, 95 | { 96 | "src": "windows11/Square44x44Logo.scale-125.png", 97 | "sizes": "55x55" 98 | }, 99 | { 100 | "src": "windows11/Square44x44Logo.scale-150.png", 101 | "sizes": "66x66" 102 | }, 103 | { 104 | "src": "windows11/Square44x44Logo.scale-200.png", 105 | "sizes": "88x88" 106 | }, 107 | { 108 | "src": "windows11/Square44x44Logo.scale-400.png", 109 | "sizes": "176x176" 110 | }, 111 | { 112 | "src": "windows11/StoreLogo.scale-100.png", 113 | "sizes": "50x50" 114 | }, 115 | { 116 | "src": "windows11/StoreLogo.scale-125.png", 117 | "sizes": "63x63" 118 | }, 119 | { 120 | "src": "windows11/StoreLogo.scale-150.png", 121 | "sizes": "75x75" 122 | }, 123 | { 124 | "src": "windows11/StoreLogo.scale-200.png", 125 | "sizes": "100x100" 126 | }, 127 | { 128 | "src": "windows11/StoreLogo.scale-400.png", 129 | "sizes": "200x200" 130 | }, 131 | { 132 | "src": "windows11/SplashScreen.scale-100.png", 133 | "sizes": "620x300" 134 | }, 135 | { 136 | "src": "windows11/SplashScreen.scale-125.png", 137 | "sizes": "775x375" 138 | }, 139 | { 140 | "src": "windows11/SplashScreen.scale-150.png", 141 | "sizes": "930x450" 142 | }, 143 | { 144 | "src": "windows11/SplashScreen.scale-200.png", 145 | "sizes": "1240x600" 146 | }, 147 | { 148 | "src": "windows11/SplashScreen.scale-400.png", 149 | "sizes": "2480x1200" 150 | }, 151 | { 152 | "src": "windows11/Square44x44Logo.targetsize-16.png", 153 | "sizes": "16x16" 154 | }, 155 | { 156 | "src": "windows11/Square44x44Logo.targetsize-20.png", 157 | "sizes": "20x20" 158 | }, 159 | { 160 | "src": "windows11/Square44x44Logo.targetsize-24.png", 161 | "sizes": "24x24" 162 | }, 163 | { 164 | "src": "windows11/Square44x44Logo.targetsize-30.png", 165 | "sizes": "30x30" 166 | }, 167 | { 168 | "src": "windows11/Square44x44Logo.targetsize-32.png", 169 | "sizes": "32x32" 170 | }, 171 | { 172 | "src": "windows11/Square44x44Logo.targetsize-36.png", 173 | "sizes": "36x36" 174 | }, 175 | { 176 | "src": "windows11/Square44x44Logo.targetsize-40.png", 177 | "sizes": "40x40" 178 | }, 179 | { 180 | "src": "windows11/Square44x44Logo.targetsize-44.png", 181 | "sizes": "44x44" 182 | }, 183 | { 184 | "src": "windows11/Square44x44Logo.targetsize-48.png", 185 | "sizes": "48x48" 186 | }, 187 | { 188 | "src": "windows11/Square44x44Logo.targetsize-60.png", 189 | "sizes": "60x60" 190 | }, 191 | { 192 | "src": "windows11/Square44x44Logo.targetsize-64.png", 193 | "sizes": "64x64" 194 | }, 195 | { 196 | "src": "windows11/Square44x44Logo.targetsize-72.png", 197 | "sizes": "72x72" 198 | }, 199 | { 200 | "src": "windows11/Square44x44Logo.targetsize-80.png", 201 | "sizes": "80x80" 202 | }, 203 | { 204 | "src": "windows11/Square44x44Logo.targetsize-96.png", 205 | "sizes": "96x96" 206 | }, 207 | { 208 | "src": "windows11/Square44x44Logo.targetsize-256.png", 209 | "sizes": "256x256" 210 | }, 211 | { 212 | "src": "windows11/Square44x44Logo.altform-unplated_targetsize-16.png", 213 | "sizes": "16x16" 214 | }, 215 | { 216 | "src": "windows11/Square44x44Logo.altform-unplated_targetsize-20.png", 217 | "sizes": "20x20" 218 | }, 219 | { 220 | "src": "windows11/Square44x44Logo.altform-unplated_targetsize-24.png", 221 | "sizes": "24x24" 222 | }, 223 | { 224 | "src": "windows11/Square44x44Logo.altform-unplated_targetsize-30.png", 225 | "sizes": "30x30" 226 | }, 227 | { 228 | "src": "windows11/Square44x44Logo.altform-unplated_targetsize-32.png", 229 | "sizes": "32x32" 230 | }, 231 | { 232 | "src": "windows11/Square44x44Logo.altform-unplated_targetsize-36.png", 233 | "sizes": "36x36" 234 | }, 235 | { 236 | "src": "windows11/Square44x44Logo.altform-unplated_targetsize-40.png", 237 | "sizes": "40x40" 238 | }, 239 | { 240 | "src": "windows11/Square44x44Logo.altform-unplated_targetsize-44.png", 241 | "sizes": "44x44" 242 | }, 243 | { 244 | "src": "windows11/Square44x44Logo.altform-unplated_targetsize-48.png", 245 | "sizes": "48x48" 246 | }, 247 | { 248 | "src": "windows11/Square44x44Logo.altform-unplated_targetsize-60.png", 249 | "sizes": "60x60" 250 | }, 251 | { 252 | "src": "windows11/Square44x44Logo.altform-unplated_targetsize-64.png", 253 | "sizes": "64x64" 254 | }, 255 | { 256 | "src": "windows11/Square44x44Logo.altform-unplated_targetsize-72.png", 257 | "sizes": "72x72" 258 | }, 259 | { 260 | "src": "windows11/Square44x44Logo.altform-unplated_targetsize-80.png", 261 | "sizes": "80x80" 262 | }, 263 | { 264 | "src": "windows11/Square44x44Logo.altform-unplated_targetsize-96.png", 265 | "sizes": "96x96" 266 | }, 267 | { 268 | "src": "windows11/Square44x44Logo.altform-unplated_targetsize-256.png", 269 | "sizes": "256x256" 270 | }, 271 | { 272 | "src": "windows11/Square44x44Logo.altform-lightunplated_targetsize-16.png", 273 | "sizes": "16x16" 274 | }, 275 | { 276 | "src": "windows11/Square44x44Logo.altform-lightunplated_targetsize-20.png", 277 | "sizes": "20x20" 278 | }, 279 | { 280 | "src": "windows11/Square44x44Logo.altform-lightunplated_targetsize-24.png", 281 | "sizes": "24x24" 282 | }, 283 | { 284 | "src": "windows11/Square44x44Logo.altform-lightunplated_targetsize-30.png", 285 | "sizes": "30x30" 286 | }, 287 | { 288 | "src": "windows11/Square44x44Logo.altform-lightunplated_targetsize-32.png", 289 | "sizes": "32x32" 290 | }, 291 | { 292 | "src": "windows11/Square44x44Logo.altform-lightunplated_targetsize-36.png", 293 | "sizes": "36x36" 294 | }, 295 | { 296 | "src": "windows11/Square44x44Logo.altform-lightunplated_targetsize-40.png", 297 | "sizes": "40x40" 298 | }, 299 | { 300 | "src": "windows11/Square44x44Logo.altform-lightunplated_targetsize-44.png", 301 | "sizes": "44x44" 302 | }, 303 | { 304 | "src": "windows11/Square44x44Logo.altform-lightunplated_targetsize-48.png", 305 | "sizes": "48x48" 306 | }, 307 | { 308 | "src": "windows11/Square44x44Logo.altform-lightunplated_targetsize-60.png", 309 | "sizes": "60x60" 310 | }, 311 | { 312 | "src": "windows11/Square44x44Logo.altform-lightunplated_targetsize-64.png", 313 | "sizes": "64x64" 314 | }, 315 | { 316 | "src": "windows11/Square44x44Logo.altform-lightunplated_targetsize-72.png", 317 | "sizes": "72x72" 318 | }, 319 | { 320 | "src": "windows11/Square44x44Logo.altform-lightunplated_targetsize-80.png", 321 | "sizes": "80x80" 322 | }, 323 | { 324 | "src": "windows11/Square44x44Logo.altform-lightunplated_targetsize-96.png", 325 | "sizes": "96x96" 326 | }, 327 | { 328 | "src": "windows11/Square44x44Logo.altform-lightunplated_targetsize-256.png", 329 | "sizes": "256x256" 330 | }, 331 | { 332 | "src": "android/android-launchericon-512-512.png", 333 | "sizes": "512x512" 334 | }, 335 | { 336 | "src": "android/android-launchericon-192-192.png", 337 | "sizes": "192x192" 338 | }, 339 | { 340 | "src": "android/android-launchericon-144-144.png", 341 | "sizes": "144x144" 342 | }, 343 | { 344 | "src": "android/android-launchericon-96-96.png", 345 | "sizes": "96x96" 346 | }, 347 | { 348 | "src": "android/android-launchericon-72-72.png", 349 | "sizes": "72x72" 350 | }, 351 | { 352 | "src": "android/android-launchericon-48-48.png", 353 | "sizes": "48x48" 354 | }, 355 | { 356 | "src": "ios/16.png", 357 | "sizes": "16x16" 358 | }, 359 | { 360 | "src": "ios/20.png", 361 | "sizes": "20x20" 362 | }, 363 | { 364 | "src": "ios/29.png", 365 | "sizes": "29x29" 366 | }, 367 | { 368 | "src": "ios/32.png", 369 | "sizes": "32x32" 370 | }, 371 | { 372 | "src": "ios/40.png", 373 | "sizes": "40x40" 374 | }, 375 | { 376 | "src": "ios/50.png", 377 | "sizes": "50x50" 378 | }, 379 | { 380 | "src": "ios/57.png", 381 | "sizes": "57x57" 382 | }, 383 | { 384 | "src": "ios/58.png", 385 | "sizes": "58x58" 386 | }, 387 | { 388 | "src": "ios/60.png", 389 | "sizes": "60x60" 390 | }, 391 | { 392 | "src": "ios/64.png", 393 | "sizes": "64x64" 394 | }, 395 | { 396 | "src": "ios/72.png", 397 | "sizes": "72x72" 398 | }, 399 | { 400 | "src": "ios/76.png", 401 | "sizes": "76x76" 402 | }, 403 | { 404 | "src": "ios/80.png", 405 | "sizes": "80x80" 406 | }, 407 | { 408 | "src": "ios/87.png", 409 | "sizes": "87x87" 410 | }, 411 | { 412 | "src": "ios/100.png", 413 | "sizes": "100x100" 414 | }, 415 | { 416 | "src": "ios/114.png", 417 | "sizes": "114x114" 418 | }, 419 | { 420 | "src": "ios/120.png", 421 | "sizes": "120x120" 422 | }, 423 | { 424 | "src": "ios/128.png", 425 | "sizes": "128x128" 426 | }, 427 | { 428 | "src": "ios/144.png", 429 | "sizes": "144x144" 430 | }, 431 | { 432 | "src": "ios/152.png", 433 | "sizes": "152x152" 434 | }, 435 | { 436 | "src": "ios/167.png", 437 | "sizes": "167x167" 438 | }, 439 | { 440 | "src": "ios/180.png", 441 | "sizes": "180x180" 442 | }, 443 | { 444 | "src": "ios/192.png", 445 | "sizes": "192x192" 446 | }, 447 | { 448 | "src": "ios/256.png", 449 | "sizes": "256x256" 450 | }, 451 | { 452 | "src": "ios/512.png", 453 | "sizes": "512x512" 454 | }, 455 | { 456 | "src": "ios/1024.png", 457 | "sizes": "1024x1024" 458 | } 459 | ] 460 | } -------------------------------------------------------------------------------- /public/notification-sw.js: -------------------------------------------------------------------------------- 1 | self.addEventListener("install", () => { 2 | console.info("service worker installed."); 3 | }); 4 | 5 | const sendDeliveryReportAction = () => { 6 | console.log("Web push delivered."); 7 | }; 8 | 9 | self.addEventListener("push", function (event) { 10 | if (!event.data) { 11 | return; 12 | } 13 | 14 | const payload = event.data.json(); 15 | const { body, icon, image, badge, url, title } = payload; 16 | const notificationTitle = title ?? "Unknown title"; 17 | const notificationOptions = { 18 | body, 19 | icon, 20 | image, 21 | data: { 22 | url, 23 | }, 24 | badge, 25 | }; 26 | 27 | event.waitUntil( 28 | self.registration.showNotification(notificationTitle, notificationOptions).then(() => { 29 | sendDeliveryReportAction(); 30 | }) 31 | ); 32 | }); 33 | 34 | self.addEventListener("notificationclick", function (event) { 35 | console.log("Notification clicked."); 36 | event.notification.close(); 37 | 38 | event.waitUntil( 39 | clients.matchAll({ type: "window", includeUncontrolled: true }).then((clientList) => { 40 | const url = event.notification.data.url; 41 | 42 | if (!url) return; 43 | 44 | for (const client of clientList) { 45 | if (client.url === url && "focus" in client) { 46 | return client.focus(); 47 | } 48 | } 49 | 50 | if (clients.openWindow) { 51 | console.log("Opening window."); 52 | return clients.openWindow(url); 53 | } 54 | }) 55 | ); 56 | }); 57 | -------------------------------------------------------------------------------- /public/user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/user.png -------------------------------------------------------------------------------- /public/windows11/LargeTile.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/LargeTile.scale-100.png -------------------------------------------------------------------------------- /public/windows11/LargeTile.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/LargeTile.scale-125.png -------------------------------------------------------------------------------- /public/windows11/LargeTile.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/LargeTile.scale-150.png -------------------------------------------------------------------------------- /public/windows11/LargeTile.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/LargeTile.scale-200.png -------------------------------------------------------------------------------- /public/windows11/LargeTile.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/LargeTile.scale-400.png -------------------------------------------------------------------------------- /public/windows11/SmallTile.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/SmallTile.scale-100.png -------------------------------------------------------------------------------- /public/windows11/SmallTile.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/SmallTile.scale-125.png -------------------------------------------------------------------------------- /public/windows11/SmallTile.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/SmallTile.scale-150.png -------------------------------------------------------------------------------- /public/windows11/SmallTile.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/SmallTile.scale-200.png -------------------------------------------------------------------------------- /public/windows11/SmallTile.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/SmallTile.scale-400.png -------------------------------------------------------------------------------- /public/windows11/SplashScreen.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/SplashScreen.scale-100.png -------------------------------------------------------------------------------- /public/windows11/SplashScreen.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/SplashScreen.scale-125.png -------------------------------------------------------------------------------- /public/windows11/SplashScreen.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/SplashScreen.scale-150.png -------------------------------------------------------------------------------- /public/windows11/SplashScreen.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/SplashScreen.scale-200.png -------------------------------------------------------------------------------- /public/windows11/SplashScreen.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/SplashScreen.scale-400.png -------------------------------------------------------------------------------- /public/windows11/Square150x150Logo.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square150x150Logo.scale-100.png -------------------------------------------------------------------------------- /public/windows11/Square150x150Logo.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square150x150Logo.scale-125.png -------------------------------------------------------------------------------- /public/windows11/Square150x150Logo.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square150x150Logo.scale-150.png -------------------------------------------------------------------------------- /public/windows11/Square150x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square150x150Logo.scale-200.png -------------------------------------------------------------------------------- /public/windows11/Square150x150Logo.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square150x150Logo.scale-400.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.altform-lightunplated_targetsize-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.altform-lightunplated_targetsize-16.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.altform-lightunplated_targetsize-20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.altform-lightunplated_targetsize-20.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.altform-lightunplated_targetsize-24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.altform-lightunplated_targetsize-24.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.altform-lightunplated_targetsize-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.altform-lightunplated_targetsize-256.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.altform-lightunplated_targetsize-30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.altform-lightunplated_targetsize-30.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.altform-lightunplated_targetsize-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.altform-lightunplated_targetsize-32.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.altform-lightunplated_targetsize-36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.altform-lightunplated_targetsize-36.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.altform-lightunplated_targetsize-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.altform-lightunplated_targetsize-40.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.altform-lightunplated_targetsize-44.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.altform-lightunplated_targetsize-44.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.altform-lightunplated_targetsize-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.altform-lightunplated_targetsize-48.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.altform-lightunplated_targetsize-60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.altform-lightunplated_targetsize-60.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.altform-lightunplated_targetsize-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.altform-lightunplated_targetsize-64.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.altform-lightunplated_targetsize-72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.altform-lightunplated_targetsize-72.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.altform-lightunplated_targetsize-80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.altform-lightunplated_targetsize-80.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.altform-lightunplated_targetsize-96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.altform-lightunplated_targetsize-96.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.altform-unplated_targetsize-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.altform-unplated_targetsize-16.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.altform-unplated_targetsize-20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.altform-unplated_targetsize-20.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.altform-unplated_targetsize-24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.altform-unplated_targetsize-24.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.altform-unplated_targetsize-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.altform-unplated_targetsize-256.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.altform-unplated_targetsize-30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.altform-unplated_targetsize-30.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.altform-unplated_targetsize-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.altform-unplated_targetsize-32.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.altform-unplated_targetsize-36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.altform-unplated_targetsize-36.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.altform-unplated_targetsize-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.altform-unplated_targetsize-40.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.altform-unplated_targetsize-44.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.altform-unplated_targetsize-44.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.altform-unplated_targetsize-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.altform-unplated_targetsize-48.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.altform-unplated_targetsize-60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.altform-unplated_targetsize-60.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.altform-unplated_targetsize-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.altform-unplated_targetsize-64.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.altform-unplated_targetsize-72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.altform-unplated_targetsize-72.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.altform-unplated_targetsize-80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.altform-unplated_targetsize-80.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.altform-unplated_targetsize-96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.altform-unplated_targetsize-96.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.scale-100.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.scale-125.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.scale-150.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.scale-200.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.scale-400.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.targetsize-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.targetsize-16.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.targetsize-20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.targetsize-20.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.targetsize-24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.targetsize-24.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.targetsize-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.targetsize-256.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.targetsize-30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.targetsize-30.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.targetsize-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.targetsize-32.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.targetsize-36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.targetsize-36.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.targetsize-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.targetsize-40.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.targetsize-44.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.targetsize-44.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.targetsize-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.targetsize-48.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.targetsize-60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.targetsize-60.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.targetsize-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.targetsize-64.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.targetsize-72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.targetsize-72.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.targetsize-80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.targetsize-80.png -------------------------------------------------------------------------------- /public/windows11/Square44x44Logo.targetsize-96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Square44x44Logo.targetsize-96.png -------------------------------------------------------------------------------- /public/windows11/StoreLogo.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/StoreLogo.scale-100.png -------------------------------------------------------------------------------- /public/windows11/StoreLogo.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/StoreLogo.scale-125.png -------------------------------------------------------------------------------- /public/windows11/StoreLogo.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/StoreLogo.scale-150.png -------------------------------------------------------------------------------- /public/windows11/StoreLogo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/StoreLogo.scale-200.png -------------------------------------------------------------------------------- /public/windows11/StoreLogo.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/StoreLogo.scale-400.png -------------------------------------------------------------------------------- /public/windows11/Wide310x150Logo.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Wide310x150Logo.scale-100.png -------------------------------------------------------------------------------- /public/windows11/Wide310x150Logo.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Wide310x150Logo.scale-125.png -------------------------------------------------------------------------------- /public/windows11/Wide310x150Logo.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Wide310x150Logo.scale-150.png -------------------------------------------------------------------------------- /public/windows11/Wide310x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Wide310x150Logo.scale-200.png -------------------------------------------------------------------------------- /public/windows11/Wide310x150Logo.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david-randoll/push-notification-nextjs/f934e55e5523ad66380189c1e56599bea185579d/public/windows11/Wide310x150Logo.scale-400.png -------------------------------------------------------------------------------- /src/app/api/web-push/send/route.ts: -------------------------------------------------------------------------------- 1 | import { sendNotification } from "@/notifications/NotificationSender"; 2 | import { NextRequest } from "next/server"; 3 | 4 | export async function POST(req: NextRequest) { 5 | const { subscription, title, message } = await req.json(); 6 | await sendNotification(subscription, title, message); 7 | return new Response(JSON.stringify({ message: "Push sent." }), {}); 8 | } 9 | -------------------------------------------------------------------------------- /src/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /src/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata } from "next"; 2 | import { Inter, IBM_Plex_Serif } from "next/font/google"; 3 | import "./globals.css"; 4 | import { NotificationProvider } from "@/notifications/useNotification"; 5 | 6 | const inter = Inter({ subsets: ["latin"], variable: "--font-inter" }); 7 | const ibmPlexSerif = IBM_Plex_Serif({ 8 | subsets: ["latin"], 9 | weight: ["400", "700"], 10 | variable: "--font-ibm-plex-serif", 11 | }); 12 | 13 | export const metadata: Metadata = { 14 | title: "Push Notification Sample", 15 | description: 16 | "A sample project for push notifications with Next.js. The app used web push notifications to send messages to users.", 17 | icons: { 18 | icon: "/logo.svg", 19 | }, 20 | }; 21 | 22 | export default function RootLayout({ 23 | children, 24 | }: Readonly<{ 25 | children: React.ReactNode; 26 | }>) { 27 | return ( 28 | 29 | 30 | 31 | 32 | 33 | {children} 34 | 35 | 36 | ); 37 | } 38 | -------------------------------------------------------------------------------- /src/app/page.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import {useNotification} from "@/notifications/useNotification"; 3 | import React from "react"; 4 | import {NotificationSubscriptionForm} from "@/components/NotificationSubscriptionForm"; 5 | import {UnsupportedNotificationMessage} from "@/components/UnsupportedNotificationMessage"; 6 | import NotificationSubscriptionStatus from "@/components/NotificationSubscriptionStatus"; 7 | 8 | const Home = () => { 9 | const {isSupported, isSubscribed} = useNotification(); 10 | 11 | return ( 12 |
13 | {!isSupported ? ( 14 | 15 | ) : ( 16 | 17 | )} 18 | 19 | {isSubscribed && ( 20 | 21 | )} 22 |
23 | ); 24 | }; 25 | 26 | export default Home; 27 | -------------------------------------------------------------------------------- /src/components/NotificationSubscriptionForm.tsx: -------------------------------------------------------------------------------- 1 | import React, {useState} from "react"; 2 | import {useNotification} from "@/notifications/useNotification"; 3 | 4 | export const NotificationSubscriptionForm = () => { 5 | const {subscription} = useNotification(); 6 | 7 | const [message, setMessage] = useState(""); 8 | const [title, setTitle] = useState(""); 9 | 10 | const sendNotification = async () => { 11 | await fetch("/api/web-push/send", { 12 | method: "POST", 13 | body: JSON.stringify({title, message, subscription}), 14 | headers: { 15 | "Content-Type": "application/json", 16 | }, 17 | }); 18 | setMessage(""); 19 | setTitle(""); 20 | }; 21 | 22 | return ( 23 |
24 |

Send a Notification

25 | 26 | {/* Title Input */} 27 | setTitle(e.target.value)} 32 | className="w-full mb-4 p-2 border border-gray-300 rounded-lg" 33 | /> 34 | 35 | {/* Message Input */} 36 |