//
@@ -395,12 +432,7 @@ Tu n'y es absolument pas obligé(e) ! C'est juste plus pratique.
return null
}
- return (
-
- {notifs.map((t) => t).reduce((prev, curr) => [prev, curr])}
-
-
- )
+ return
{notifs.map((t) => t).reduce((prev, curr) => [prev, curr])}
}
export default memo(Notifications)
diff --git a/src/components/Notifications/styles.module.scss b/src/components/Notifications/styles.module.scss
index 6856a83..379b293 100755
--- a/src/components/Notifications/styles.module.scss
+++ b/src/components/Notifications/styles.module.scss
@@ -22,6 +22,9 @@
.notifIntro {
margin-bottom: 10px;
}
+.notifCentered {
+ text-align: center;
+}
.formLine {
padding: 5px 0;
diff --git a/src/server/index.ts b/src/server/index.ts
index 085f7c2..5e884f5 100755
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -32,13 +32,15 @@ import {
} from "./gsheets/volunteers"
import { wishListGet, wishAdd } from "./gsheets/wishes"
import config from "../config"
-import notificationsSubscribe from "./notificationsSubscribe"
+import { notificationsSubscribe, notificationMain } from "./notifications"
import checkAccess from "./checkAccess"
import { hasGSheetsAccess } from "./gsheets/accessors"
import { addStatus, showStatusAt } from "./status"
checkAccess()
+notificationMain()
+
const app = express()
// Use helmet to secure Express with various HTTP headers
diff --git a/src/server/notifications.ts b/src/server/notifications.ts
new file mode 100644
index 0000000..2b02d42
--- /dev/null
+++ b/src/server/notifications.ts
@@ -0,0 +1,131 @@
+import { Request, Response, NextFunction } from "express"
+import webpush from "web-push"
+import {
+ Announcement,
+ AnnouncementWithoutId,
+ translationAnnouncement,
+} from "../services/announcement"
+import { translationVolunteer, Volunteer, VolunteerWithoutId } from "../services/volunteers"
+import { getSheet } from "./gsheets/accessors"
+
+const publicKey = process.env.FORCE_ORANGE_PUBLIC_VAPID_KEY
+const privateKey = process.env.FORCE_ORANGE_PRIVATE_VAPID_KEY
+const hasPushAccess = publicKey && privateKey && !__DEV__ && !__LOCAL__
+if (hasPushAccess) {
+ webpush.setVapidDetails("mailto: contact@parisestludique.fr", publicKey, privateKey)
+}
+type Payload = {
+ message: string
+}
+
+export function sendNotifToVolunteer(volunteer: Volunteer, payload: Payload): void {
+ if (volunteer.acceptsNotifs !== "oui") {
+ console.error(`Volunteer refuses notifs`)
+ } else {
+ const subscription = JSON.parse(volunteer.pushNotifSubscription)
+
+ if (!subscription) {
+ console.error(`Volunteer has no notif subscription`)
+ } else if (hasPushAccess) {
+ const stringifiedPayload = JSON.stringify(payload)
+ webpush
+ .sendNotification(subscription, stringifiedPayload)
+ .then((result) => console.error(result))
+ .catch((e) => console.error(e.stack))
+ } else {
+ console.error(
+ `Fake sending push notif to ${JSON.stringify(subscription)} of ${JSON.stringify(
+ payload
+ )})}`
+ )
+ }
+ }
+}
+
+export function sendNotifToSubscription(
+ subscription: webpush.PushSubscription,
+ payload: Payload
+): void {
+ if (hasPushAccess) {
+ const stringifiedPayload = JSON.stringify(payload)
+ webpush
+ .sendNotification(subscription, stringifiedPayload)
+ .then((result) => console.error(result))
+ .catch((e) => console.error(e.stack))
+ } else {
+ console.error(
+ `Fake sending push notif to ${JSON.stringify(subscription)} of ${JSON.stringify(
+ payload
+ )})}`
+ )
+ }
+}
+
+export function notificationsSubscribe(
+ request: Request,
+ response: Response,
+ _next: NextFunction
+): void {
+ sendNotifToSubscription(request.body, {
+ message:
+ "Clique-moi pour voir la gazette de février dans la page Annonces !\nFini les emails, cette notification sera notre seul moyen de te prévenir :)",
+ })
+
+ response.status(200).json({ success: true })
+}
+
+export function notificationMain(): void {
+ setInterval(notifyAboutAnnouncement, 5 * 60 * 1000)
+ setTimeout(notifyAboutAnnouncement, 60 * 1000)
+}
+
+async function notifyAboutAnnouncement(): Promise
{
+ const announcementSheet = getSheet(
+ "Announcements",
+ new Announcement(),
+ translationAnnouncement
+ )
+
+ const announcementList = await announcementSheet.getList()
+ if (!announcementList) {
+ return
+ }
+
+ const toSend = announcementList.find((a) => !a.informedWithNotif)
+ if (!toSend) {
+ return
+ }
+
+ const volunteerSheet = getSheet(
+ "Volunteers",
+ new Volunteer(),
+ translationVolunteer
+ )
+ const volunteerList = await volunteerSheet.getList()
+ if (!volunteerList) {
+ return
+ }
+
+ const audience = volunteerList.filter(
+ (v) =>
+ v.acceptsNotifs === "oui" &&
+ !v.discordId &&
+ (v.active === "oui" || v.active === "peut-etre")
+ )
+
+ console.error(
+ `Sending announcement ${toSend.title} to ${audience
+ .map((v) => `${v.firstname} #${v.id}`)
+ .join(", ")}`
+ )
+
+ audience.forEach((v) => {
+ sendNotifToVolunteer(v, {
+ message:
+ "Clique-moi pour voir la gazette de février dans la page Annonces !\n\nFini les emails/spam, cette notification est notre nouveau moyen de te prévenir :)",
+ })
+ })
+
+ toSend.informedWithNotif = true
+ await announcementSheet.set(toSend)
+}
diff --git a/src/server/notificationsSubscribe.ts b/src/server/notificationsSubscribe.ts
deleted file mode 100644
index bd276e7..0000000
--- a/src/server/notificationsSubscribe.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-import { Request, Response, NextFunction } from "express"
-import webpush from "web-push"
-
-const publicKey = process.env.FORCE_ORANGE_PUBLIC_VAPID_KEY
-const privateKey = process.env.FORCE_ORANGE_PRIVATE_VAPID_KEY
-const hasPushAccess = publicKey && privateKey
-if (hasPushAccess) {
- webpush.setVapidDetails("mailto: contact@parisestludique.fr", publicKey, privateKey)
-}
-
-export default function notificationsSubscribe(
- request: Request,
- response: Response,
- _next: NextFunction
-): void {
- const subscription = request.body
-
- const payload = JSON.stringify({
- title: "Hello!",
- body: "It works.",
- })
-
- if (hasPushAccess) {
- webpush
- .sendNotification(subscription, payload)
- .then((result) => console.log(result))
- .catch((e) => console.log(e.stack))
- } else {
- console.error(
- `Fake sending push notif to ${JSON.stringify(subscription)} of ${JSON.stringify(
- payload
- )})}`
- )
- }
-
- response.status(200).json({ success: true })
-}
diff --git a/src/services/announcement.ts b/src/services/announcement.ts
index f3ebb54..615583d 100644
--- a/src/services/announcement.ts
+++ b/src/services/announcement.ts
@@ -8,6 +8,8 @@ export class Announcement {
title = ""
url = ""
+
+ informedWithNotif = false
}
export const translationAnnouncement: { [k in keyof Announcement]: string } = {
@@ -16,6 +18,7 @@ export const translationAnnouncement: { [k in keyof Announcement]: string } = {
type: "type",
title: "titre",
url: "url",
+ informedWithNotif: "informéAvecUneNotif",
}
export const elementName = "Announcement"
diff --git a/src/theme/mixins.scss b/src/theme/mixins.scss
index 6163950..b62bc28 100644
--- a/src/theme/mixins.scss
+++ b/src/theme/mixins.scss
@@ -36,6 +36,36 @@
background-color: $color-grey-lighter;
}
+@mixin nav-menu($desktopWidth: 520px) {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+
+ @include desktop {
+ padding: 5px;
+ }
+}
+
+@mixin nav-menu-item($desktopWidth: 520px) {
+ display: inline-block;
+ margin: 0 4px;
+
+ @include desktop {
+ padding: 2px;
+ }
+
+ a {
+ font-size: 0.9em;
+ font-weight: bold;
+ color: $color-black;
+ text-decoration: none;
+ }
+
+ a:hover {
+ color: $color-grey-dark;
+ }
+}
+
@mixin clear-ul-style {
margin: 0;
padding: 0;