[FEAT] Add membership expiry notification option
This commit is contained in:
1 parent
be4ddc2018
commit
67206e30d3
7 files changed
+325
-87
No files matched your search
@@ -12,25 +12,34 @@
|
||||
"backgroundColor": "#E5E2D7"
|
||||
},
|
||||
"scheme": "no-neuf-chateau",
|
||||
"assetBundlePatterns": [
|
||||
"**/*"
|
||||
],
|
||||
"assetBundlePatterns": ["**/*"],
|
||||
"ios": {
|
||||
"supportsTablet": true,
|
||||
"bundleIdentifier": "no.neuf.chateau"
|
||||
"bundleIdentifier": "no.neuf.chateau",
|
||||
"infoPlist": {
|
||||
"UIBackgroundModes": ["remote-notification"]
|
||||
}
|
||||
},
|
||||
"android": {
|
||||
"package": "no.neuf.chateau",
|
||||
"adaptiveIcon": {
|
||||
"foregroundImage": "./assets/adaptive-icon.png",
|
||||
"backgroundColor": "#CD96AB"
|
||||
}
|
||||
},
|
||||
"permissions": ["NOTIFICATIONS"]
|
||||
},
|
||||
"web": {
|
||||
"favicon": "./assets/favicon.png"
|
||||
},
|
||||
"plugins": [
|
||||
"expo-asset"
|
||||
"expo-asset",
|
||||
[
|
||||
"expo-notifications",
|
||||
{
|
||||
"icon": "./assets/icon.png",
|
||||
"color": "#E5E2D7"
|
||||
}
|
||||
]
|
||||
],
|
||||
"extra": {
|
||||
"eas": {
|
||||
|
||||
Generated
+125
-55
@@ -22,6 +22,7 @@
|
||||
"expo-asset": "~11.0.5",
|
||||
"expo-constants": "~17.0.8",
|
||||
"expo-dev-client": "~5.0.20",
|
||||
"expo-notifications": "~0.29.14",
|
||||
"expo-status-bar": "~2.0.1",
|
||||
"graphql": "^16.9.0",
|
||||
"metro-react-native-babel-preset": "^0.77.0",
|
||||
@@ -2664,18 +2665,6 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/@expo/cli/node_modules/mime": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
|
||||
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"mime": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/@expo/cli/node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
@@ -4043,6 +4032,12 @@
|
||||
"deprecated": "Use @eslint/object-schema instead",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@ide/backoff": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@ide/backoff/-/backoff-1.0.0.tgz",
|
||||
"integrity": "sha512-F0YfUDjvT+Mtt/R4xdl2X0EYCHMMiJqNLdxHD++jDT5ydEFIyqbCHh51Qx2E211dgZprPKhV7sHmnXKpLuvc5g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@isaacs/cliui": {
|
||||
"version": "8.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
|
||||
@@ -7132,6 +7127,19 @@
|
||||
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
|
||||
"integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA=="
|
||||
},
|
||||
"node_modules/assert": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/assert/-/assert-2.1.0.tgz",
|
||||
"integrity": "sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.2",
|
||||
"is-nan": "^1.3.2",
|
||||
"object-is": "^1.1.5",
|
||||
"object.assign": "^4.1.4",
|
||||
"util": "^0.12.5"
|
||||
}
|
||||
},
|
||||
"node_modules/ast-types": {
|
||||
"version": "0.15.2",
|
||||
"resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.15.2.tgz",
|
||||
@@ -7173,7 +7181,6 @@
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
|
||||
"integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"possible-typed-array-names": "^1.0.0"
|
||||
@@ -7485,6 +7492,12 @@
|
||||
"@babel/core": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/badgin": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/badgin/-/badgin-1.2.3.tgz",
|
||||
"integrity": "sha512-NQGA7LcfCpSzIbGRbkgjgdWkjy7HI+Th5VLxTJfW5EeaAf3fnS+xWQaQOCYiny+q6QSvxqoSO04vCx+4u++EJw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/balanced-match": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
@@ -7794,7 +7807,6 @@
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz",
|
||||
"integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"call-bind-apply-helpers": "^1.0.0",
|
||||
"es-define-property": "^1.0.0",
|
||||
@@ -7824,7 +7836,6 @@
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz",
|
||||
"integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"call-bind-apply-helpers": "^1.0.1",
|
||||
"get-intrinsic": "^1.2.6"
|
||||
@@ -8677,7 +8688,6 @@
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
|
||||
"integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-define-property": "^1.0.0",
|
||||
@@ -8704,7 +8714,6 @@
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
|
||||
"integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"define-data-property": "^1.0.1",
|
||||
"has-property-descriptors": "^1.0.0",
|
||||
@@ -10281,6 +10290,15 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/expo-application": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/expo-application/-/expo-application-6.0.2.tgz",
|
||||
"integrity": "sha512-qcj6kGq3mc7x5yIb5KxESurFTJCoEKwNEL34RdPEvTB/xhl7SeVZlu05sZBqxB1V4Ryzq/LsCb7NHNfBbb3L7A==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"expo": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/expo-asset": {
|
||||
"version": "11.0.5",
|
||||
"resolved": "https://registry.npmjs.org/expo-asset/-/expo-asset-11.0.5.tgz",
|
||||
@@ -10583,6 +10601,26 @@
|
||||
"invariant": "^2.2.4"
|
||||
}
|
||||
},
|
||||
"node_modules/expo-notifications": {
|
||||
"version": "0.29.14",
|
||||
"resolved": "https://registry.npmjs.org/expo-notifications/-/expo-notifications-0.29.14.tgz",
|
||||
"integrity": "sha512-AVduNx9mKOgcAqBfrXS1OHC9VAQZrDQLbVbcorMjPDGXW7m0Q5Q+BG6FYM/saVviF2eO8fhQRsTT40yYv5/bhQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@expo/image-utils": "^0.6.5",
|
||||
"@ide/backoff": "^1.0.0",
|
||||
"abort-controller": "^3.0.0",
|
||||
"assert": "^2.0.0",
|
||||
"badgin": "^1.1.5",
|
||||
"expo-application": "~6.0.2",
|
||||
"expo-constants": "~17.0.8"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"expo": "*",
|
||||
"react": "*",
|
||||
"react-native": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/expo-status-bar": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/expo-status-bar/-/expo-status-bar-2.0.1.tgz",
|
||||
@@ -10853,7 +10891,6 @@
|
||||
"version": "0.3.3",
|
||||
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
|
||||
"integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"is-callable": "^1.1.3"
|
||||
}
|
||||
@@ -11247,7 +11284,6 @@
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
|
||||
"integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-define-property": "^1.0.0"
|
||||
@@ -11640,7 +11676,6 @@
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
|
||||
"integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.2",
|
||||
"has-tostringtag": "^1.0.0"
|
||||
@@ -11733,7 +11768,6 @@
|
||||
"version": "1.2.7",
|
||||
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
|
||||
"integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
@@ -11838,7 +11872,6 @@
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz",
|
||||
"integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.3",
|
||||
"get-proto": "^1.0.0",
|
||||
@@ -11875,6 +11908,22 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-nan": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz",
|
||||
"integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.0",
|
||||
"define-properties": "^1.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-number": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
||||
@@ -11939,7 +11988,6 @@
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz",
|
||||
"integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.2",
|
||||
"gopd": "^1.2.0",
|
||||
@@ -12026,7 +12074,6 @@
|
||||
"version": "1.1.15",
|
||||
"resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz",
|
||||
"integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"which-typed-array": "^1.1.16"
|
||||
},
|
||||
@@ -13918,6 +13965,18 @@
|
||||
"node": ">=8.6"
|
||||
}
|
||||
},
|
||||
"node_modules/mime": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
|
||||
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"mime": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/mime-db": {
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||
@@ -14122,9 +14181,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.3.7",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
|
||||
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
|
||||
"version": "3.3.11",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
|
||||
"integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
@@ -14348,7 +14407,6 @@
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz",
|
||||
"integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.7",
|
||||
"define-properties": "^1.2.1"
|
||||
@@ -14364,7 +14422,6 @@
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
|
||||
"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
@@ -14373,7 +14430,6 @@
|
||||
"version": "4.1.7",
|
||||
"resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz",
|
||||
"integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.8",
|
||||
"call-bound": "^1.0.3",
|
||||
@@ -14934,7 +14990,6 @@
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz",
|
||||
"integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@@ -16219,7 +16274,6 @@
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz",
|
||||
"integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.2",
|
||||
"es-errors": "^1.3.0",
|
||||
@@ -16267,9 +16321,10 @@
|
||||
}
|
||||
},
|
||||
"node_modules/send": {
|
||||
"version": "0.18.0",
|
||||
"resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
|
||||
"integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
|
||||
"version": "0.19.0",
|
||||
"resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
|
||||
"integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
@@ -16293,6 +16348,7 @@
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
@@ -16300,28 +16356,20 @@
|
||||
"node_modules/send/node_modules/debug/node_modules/ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
||||
},
|
||||
"node_modules/send/node_modules/mime": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
|
||||
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
|
||||
"bin": {
|
||||
"mime": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/send/node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/send/node_modules/on-finished": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
|
||||
"integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ee-first": "1.1.1"
|
||||
},
|
||||
@@ -16333,6 +16381,7 @@
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
|
||||
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
@@ -16347,24 +16396,33 @@
|
||||
}
|
||||
},
|
||||
"node_modules/serve-static": {
|
||||
"version": "1.15.0",
|
||||
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
|
||||
"integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
|
||||
"version": "1.16.2",
|
||||
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
|
||||
"integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"encodeurl": "~1.0.2",
|
||||
"encodeurl": "~2.0.0",
|
||||
"escape-html": "~1.0.3",
|
||||
"parseurl": "~1.3.3",
|
||||
"send": "0.18.0"
|
||||
"send": "0.19.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/serve-static/node_modules/encodeurl": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
|
||||
"integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/set-function-length": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
|
||||
"integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"define-data-property": "^1.1.4",
|
||||
@@ -17963,6 +18021,19 @@
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/util": {
|
||||
"version": "0.12.5",
|
||||
"resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz",
|
||||
"integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"is-arguments": "^1.0.4",
|
||||
"is-generator-function": "^1.0.7",
|
||||
"is-typed-array": "^1.1.3",
|
||||
"which-typed-array": "^1.1.2"
|
||||
}
|
||||
},
|
||||
"node_modules/utils-merge": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
|
||||
@@ -18175,7 +18246,6 @@
|
||||
"version": "1.1.18",
|
||||
"resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.18.tgz",
|
||||
"integrity": "sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"available-typed-arrays": "^1.0.7",
|
||||
"call-bind": "^1.0.8",
|
||||
|
||||
+2
-1
@@ -48,7 +48,8 @@
|
||||
"redux-persist": "^6.0.0",
|
||||
"redux-thunk": "^2.4.2",
|
||||
"styled-system": "^5.1.5",
|
||||
"expo-dev-client": "~5.0.20"
|
||||
"expo-dev-client": "~5.0.20",
|
||||
"expo-notifications": "~0.29.14"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.24.9",
|
||||
|
||||
+10
@@ -1,6 +1,7 @@
|
||||
import { ApolloClient, HttpLink, InMemoryCache, ApolloProvider } from '@apollo/client';
|
||||
import { StripeProvider } from '@stripe/stripe-react-native';
|
||||
import Constants from 'expo-constants';
|
||||
import * as Notifications from 'expo-notifications';
|
||||
import { StatusBar } from 'expo-status-bar';
|
||||
import React from 'react';
|
||||
import { GestureHandlerRootView } from 'react-native-gesture-handler';
|
||||
@@ -13,6 +14,15 @@ import { useDeepLinking } from './hooks';
|
||||
import { store, persistor } from './reduxStore';
|
||||
import { loadTheme } from './theme';
|
||||
|
||||
// Configure notifications
|
||||
Notifications.setNotificationHandler({
|
||||
handleNotification: async () => ({
|
||||
shouldShowAlert: true,
|
||||
shouldPlaySound: true,
|
||||
shouldSetBadge: false,
|
||||
}),
|
||||
});
|
||||
|
||||
const apolloClient = new ApolloClient({
|
||||
link: new HttpLink({ uri: `${process.env.EXPO_PUBLIC_DUSKEN_API_URL}/api/graphql/` }),
|
||||
cache: new InMemoryCache(),
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
import * as Notifications from 'expo-notifications';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
export const useNotifications = () => {
|
||||
const [hasPermission, setHasPermission] = useState<boolean | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
checkPermission();
|
||||
}, []);
|
||||
|
||||
const checkPermission = async () => {
|
||||
const { status } = await Notifications.getPermissionsAsync();
|
||||
setHasPermission(status === 'granted');
|
||||
};
|
||||
|
||||
const requestPermission = async () => {
|
||||
const { status } = await Notifications.requestPermissionsAsync();
|
||||
const granted = status === 'granted';
|
||||
setHasPermission(granted);
|
||||
return granted;
|
||||
};
|
||||
|
||||
const scheduleMembershipExpiryNotification = async (expiryDate: string) => {
|
||||
if (!hasPermission) {
|
||||
const granted = await requestPermission();
|
||||
if (!granted) return;
|
||||
}
|
||||
|
||||
// Cancel any existing notifications before scheduling a new one
|
||||
await Notifications.cancelAllScheduledNotificationsAsync();
|
||||
|
||||
const expiryDateObj = new Date(expiryDate);
|
||||
const notificationDate = new Date(expiryDateObj);
|
||||
notificationDate.setDate(notificationDate.getDate() + 1); // 1 day after expiry
|
||||
|
||||
// Don't schedule if the notification date is in the past
|
||||
if (notificationDate <= new Date()) return;
|
||||
|
||||
await Notifications.scheduleNotificationAsync({
|
||||
content: {
|
||||
title: 'Medlemskapet ditt har utløpt!',
|
||||
body: 'Ditt medlemskap i Det Norske Studentersamfund har utløpt! Vi håper du ønsker å fornye det :)',
|
||||
data: { type: 'membership_expiry' },
|
||||
},
|
||||
trigger: {
|
||||
type: 'date',
|
||||
date: notificationDate,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const toggleNotifications = async (enabled: boolean) => {
|
||||
if (enabled) {
|
||||
// When enabling, request permission
|
||||
const granted = await requestPermission();
|
||||
return { success: granted, needsPermission: !granted };
|
||||
} else {
|
||||
// When disabling, cancel any existing notifications and update state
|
||||
await Notifications.cancelAllScheduledNotificationsAsync();
|
||||
setHasPermission(false);
|
||||
return { success: true, needsPermission: false };
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
hasPermission,
|
||||
requestPermission,
|
||||
scheduleMembershipExpiryNotification,
|
||||
toggleNotifications,
|
||||
};
|
||||
};
|
||||
@@ -1,4 +1,5 @@
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import * as Notifications from 'expo-notifications';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import {
|
||||
Image,
|
||||
ScrollView,
|
||||
@@ -10,11 +11,13 @@ import {
|
||||
ActivityIndicator,
|
||||
Dimensions,
|
||||
GestureResponderEvent,
|
||||
Switch,
|
||||
} from 'react-native';
|
||||
import Confetti from 'react-native-confetti';
|
||||
import { Button, Incubator } from 'react-native-ui-lib';
|
||||
|
||||
import RadioButton from 'src/components/RadioButton';
|
||||
import { useNotifications } from 'src/hooks/useNotifications';
|
||||
import theme from 'src/theme';
|
||||
import type { UserType } from 'src/types/data';
|
||||
|
||||
@@ -161,6 +164,52 @@ const MembershipName = ({ user }: { user: UserType }) => {
|
||||
);
|
||||
};
|
||||
|
||||
const NotificationToggle = ({ user }: { user: UserType }) => {
|
||||
const { hasPermission, toggleNotifications, scheduleMembershipExpiryNotification } = useNotifications();
|
||||
const [toast, setToast] = useState<{ message: string; visible: boolean } | null>(null);
|
||||
|
||||
const handleToggle = async (enabled: boolean) => {
|
||||
const { success, needsPermission } = await toggleNotifications(enabled);
|
||||
if (needsPermission) {
|
||||
await Notifications.requestPermissionsAsync();
|
||||
setToast({
|
||||
message: 'Du må godta varsler i innstillinger for å motta påminnelser',
|
||||
visible: true,
|
||||
});
|
||||
setTimeout(() => setToast(null), 3000);
|
||||
return;
|
||||
}
|
||||
if (success && enabled && user.last_membership?.end_date) {
|
||||
await scheduleMembershipExpiryNotification(user.last_membership.end_date);
|
||||
}
|
||||
};
|
||||
|
||||
if (!user.is_member || !user.last_membership) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={styles.notificationToggle}>
|
||||
<Text style={[theme.text, styles.notificationText]}>Varsle meg når medlemskapet utløper</Text>
|
||||
<Switch
|
||||
value={hasPermission || false}
|
||||
onValueChange={handleToggle}
|
||||
trackColor={{ false: '#E0E0E0', true: theme.colors.neufOrange }}
|
||||
thumbColor={hasPermission ? '#FFFFFF' : '#FFFFFF'}
|
||||
ios_backgroundColor="#E0E0E0"
|
||||
style={styles.switch}
|
||||
/>
|
||||
<Toast
|
||||
message={toast?.message}
|
||||
visible={toast?.visible || false}
|
||||
position="bottom"
|
||||
autoDismiss={3000}
|
||||
onDismiss={() => setToast(null)}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
interface ProofProps {
|
||||
onLogoutPress: () => void;
|
||||
fetchUser: () => void;
|
||||
@@ -212,30 +261,33 @@ const Proof = ({ onLogoutPress, fetchUser, isFetchingUserData, onDeletePress }:
|
||||
return (
|
||||
<>
|
||||
<UserConfetti user={user} confettiRef={confettiRef} />
|
||||
<ScrollView refreshControl={<RefreshControl refreshing={isFetchingUserData} onRefresh={fetchUser} />}>
|
||||
<View style={[theme.card, { paddingVertical: 16, backgroundColor: 'transparent' }]}>
|
||||
<MembershipName user={user} />
|
||||
<Logo user={user} />
|
||||
<MembershipStatus user={user} onMembershipPress={onMembershipPress} />
|
||||
<PurchaseButton
|
||||
user={user}
|
||||
paymentLoading={paymentLoading}
|
||||
isLoadingMembershipType={isLoadingMembershipType}
|
||||
membershipPrice={membershipPrice}
|
||||
onPurchasePress={onPurchasePress}
|
||||
setMembershipTypeSlug={setMembershipTypeSlug}
|
||||
/>
|
||||
<MembershipValidTo user={user} />
|
||||
</View>
|
||||
<View>
|
||||
<View style={styles.container}>
|
||||
<ScrollView refreshControl={<RefreshControl refreshing={isFetchingUserData} onRefresh={fetchUser} />}>
|
||||
<View style={[theme.card, { paddingVertical: 16, backgroundColor: 'transparent' }]}>
|
||||
<MembershipName user={user} />
|
||||
<Logo user={user} />
|
||||
<MembershipStatus user={user} onMembershipPress={onMembershipPress} />
|
||||
<PurchaseButton
|
||||
user={user}
|
||||
paymentLoading={paymentLoading}
|
||||
isLoadingMembershipType={isLoadingMembershipType}
|
||||
membershipPrice={membershipPrice}
|
||||
onPurchasePress={onPurchasePress}
|
||||
setMembershipTypeSlug={setMembershipTypeSlug}
|
||||
/>
|
||||
<MembershipValidTo user={user} />
|
||||
<NotificationToggle user={user} />
|
||||
</View>
|
||||
</ScrollView>
|
||||
<View style={styles.buttonContainer}>
|
||||
<Button onPress={onLogoutPress} style={[theme.button, styles.logoutButton]} small>
|
||||
<Text style={theme.buttonText}>Logg ut</Text>
|
||||
</Button>
|
||||
<Button onPress={onDeletePress} style={[theme.button, styles.deleteButton]} small>
|
||||
<Text style={styles.whiteText}>Slett bruker</Text>
|
||||
</Button>
|
||||
</View>
|
||||
<Button onPress={onDeletePress} style={[theme.button, styles.deleteButton]} small>
|
||||
<Text style={styles.whiteText}>Slett bruker</Text>
|
||||
</Button>
|
||||
</ScrollView>
|
||||
</View>
|
||||
<Toast
|
||||
message={toast?.message}
|
||||
visible={toast?.visible}
|
||||
@@ -303,12 +355,9 @@ const styles = StyleSheet.create({
|
||||
marginTop: 8,
|
||||
},
|
||||
logoutButton: {
|
||||
alignSelf: 'center',
|
||||
marginVertical: 20,
|
||||
marginBottom: 8,
|
||||
},
|
||||
deleteButton: {
|
||||
alignSelf: 'center',
|
||||
marginVertical: 20,
|
||||
backgroundColor: theme.colors.danger,
|
||||
},
|
||||
whiteText: {
|
||||
@@ -347,4 +396,26 @@ const styles = StyleSheet.create({
|
||||
fontWeight: 'bold',
|
||||
marginTop: 30,
|
||||
},
|
||||
notificationToggle: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
marginTop: 32,
|
||||
},
|
||||
notificationText: {
|
||||
fontSize: 18,
|
||||
},
|
||||
switch: {
|
||||
transform: [{ scale: 1.25 }],
|
||||
},
|
||||
container: {
|
||||
flex: 1,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
},
|
||||
buttonContainer: {
|
||||
paddingHorizontal: 16,
|
||||
paddingBottom: 16,
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
});
|
||||
@@ -5,6 +5,7 @@ import { useEffect, useState } from 'react';
|
||||
|
||||
import { requestStripePaymentSheet } from 'src/api';
|
||||
import { useAppSelector } from 'src/hooks';
|
||||
import { useNotifications } from 'src/hooks/useNotifications';
|
||||
import { ToastProps } from 'src/types/toast';
|
||||
|
||||
const PROOF_QUERY = gql`
|
||||
@@ -25,6 +26,7 @@ const useProof = ({ fetchUser }: UseProofProps) => {
|
||||
const userToken = useAppSelector((state) => state.userToken);
|
||||
const { data, loading } = useQuery(PROOF_QUERY);
|
||||
const { initPaymentSheet, presentPaymentSheet } = useStripe();
|
||||
const { scheduleMembershipExpiryNotification, hasPermission } = useNotifications();
|
||||
const [paymentLoading, setPaymentLoading] = useState(false);
|
||||
const [membershipTypeSlug, setMembershipTypeSlug] = useState('standard');
|
||||
const [membershipPrice, setMembershipPrice] = useState(25000); // WARNING: Hardcoded due to state not being loaded initially. Should probably be fixed.
|
||||
@@ -78,6 +80,10 @@ const useProof = ({ fetchUser }: UseProofProps) => {
|
||||
user.lastMembership.end_date < todaysDate
|
||||
) {
|
||||
fetchUser();
|
||||
// If payment was successful and notifications are enabled, schedule the notification
|
||||
if (!error && user?.last_membership?.end_date && hasPermission) {
|
||||
await scheduleMembershipExpiryNotification(user.last_membership.end_date);
|
||||
}
|
||||
}
|
||||
}, [user?.last_membership]);
|
||||
|
||||
|
||||
Reference in new issue
Block a user