mirror of
https://github.com/lemeow125/StudE-Frontend.git
synced 2024-11-17 06:19:25 +08:00
Merge pull request #10 from lemeow125/feature/messaging
Feature/messaging
This commit is contained in:
commit
7c3eeda29e
10 changed files with 941 additions and 201 deletions
3
App.tsx
3
App.tsx
|
@ -28,6 +28,7 @@ import StartStudying from "./src/routes/StartStudying/StartStudying";
|
|||
import { ToastProvider } from "react-native-toast-notifications";
|
||||
import InfoIcon from "./src/icons/InfoIcon/InfoIcon";
|
||||
import CreateGroup from "./src/routes/CreateGroup/CreateGroup";
|
||||
import BackgroundComponent from "./src/components/BackgroundTask/BackgroundTask";
|
||||
|
||||
const Drawer = createDrawerNavigator();
|
||||
|
||||
|
@ -66,11 +67,11 @@ export default function App() {
|
|||
icon={<InfoIcon size={32} />}
|
||||
textStyle={{ ...styles.text_white_tiny_bold }}
|
||||
>
|
||||
<BackgroundComponent />
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<Provider store={store}>
|
||||
<StatusBar style="light" />
|
||||
|
||||
|
||||
<NavigationContainer linking={linking} fallback={<Loading />}>
|
||||
<Drawer.Navigator
|
||||
initialRouteName="Revalidation"
|
||||
|
|
336
package-lock.json
generated
336
package-lock.json
generated
|
@ -16,12 +16,16 @@
|
|||
"@tanstack/react-query": "^4.29.25",
|
||||
"axios": "^1.4.0",
|
||||
"expo": "~48.0.18",
|
||||
"expo-background-fetch": "~11.1.1",
|
||||
"expo-file-system": "~15.2.2",
|
||||
"expo-image-picker": "~14.1.1",
|
||||
"expo-intent-launcher": "~10.5.2",
|
||||
"expo-linking": "~4.0.1",
|
||||
"expo-location": "~15.1.1",
|
||||
"expo-notifications": "~0.18.1",
|
||||
"expo-status-bar": "~1.4.4",
|
||||
"expo-task-manager": "~11.1.1",
|
||||
"moment": "^2.29.4",
|
||||
"moti": "^0.25.3",
|
||||
"react": "18.2.0",
|
||||
"react-native": "0.71.8",
|
||||
|
@ -3133,6 +3137,11 @@
|
|||
"@hapi/hoek": "^9.0.0"
|
||||
}
|
||||
},
|
||||
"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=="
|
||||
},
|
||||
"node_modules/@jest/create-cache-key-function": {
|
||||
"version": "29.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@jest/create-cache-key-function/-/create-cache-key-function-29.5.0.tgz",
|
||||
|
@ -5570,6 +5579,18 @@
|
|||
"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==",
|
||||
"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/assign-symbols": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
|
||||
|
@ -5631,6 +5652,17 @@
|
|||
"node": ">= 4.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/available-typed-arrays": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz",
|
||||
"integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz",
|
||||
|
@ -5774,6 +5806,11 @@
|
|||
"@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=="
|
||||
},
|
||||
"node_modules/balanced-match": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
|
@ -6920,6 +6957,19 @@
|
|||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/define-data-property": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.0.tgz",
|
||||
"integrity": "sha512-UzGwzcjyv3OtAvolTj1GoyNYzfFR+iqbGjcnBEENZVCpM4/Ng1yhGNvS3lR/xDS74Tb2wGG9WzNSNIOS9UVb2g==",
|
||||
"dependencies": {
|
||||
"get-intrinsic": "^1.2.1",
|
||||
"gopd": "^1.0.1",
|
||||
"has-property-descriptors": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/define-lazy-prop": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz",
|
||||
|
@ -6928,6 +6978,22 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/define-properties": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
|
||||
"integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
|
||||
"dependencies": {
|
||||
"define-data-property": "^1.0.1",
|
||||
"has-property-descriptors": "^1.0.0",
|
||||
"object-keys": "^1.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/define-property": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
|
||||
|
@ -7434,6 +7500,17 @@
|
|||
"url-parse": "^1.5.9"
|
||||
}
|
||||
},
|
||||
"node_modules/expo-background-fetch": {
|
||||
"version": "11.1.1",
|
||||
"resolved": "https://registry.npmjs.org/expo-background-fetch/-/expo-background-fetch-11.1.1.tgz",
|
||||
"integrity": "sha512-5X63ogpCqEqdqXYk4Sl4J8Lt/ZWcQCboS1pq3uprqD1KUi4ICl1P3gwPo+il3rYPV6xYb74Wv1KyyEEYj2vklg==",
|
||||
"dependencies": {
|
||||
"expo-task-manager": "~11.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"expo": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/expo-constants": {
|
||||
"version": "14.2.1",
|
||||
"resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-14.2.1.tgz",
|
||||
|
@ -7644,11 +7721,74 @@
|
|||
"invariant": "^2.2.4"
|
||||
}
|
||||
},
|
||||
"node_modules/expo-notifications": {
|
||||
"version": "0.18.1",
|
||||
"resolved": "https://registry.npmjs.org/expo-notifications/-/expo-notifications-0.18.1.tgz",
|
||||
"integrity": "sha512-lOEiuPE6ubkS5u7Nj/57gkmUGD/MxsRTC6bg9SGJqXIitBQZk3Tmv9y8bjTrn71n7DsrH8K7xCZTbVwr+kLQGg==",
|
||||
"dependencies": {
|
||||
"@expo/image-utils": "^0.3.18",
|
||||
"@ide/backoff": "^1.0.0",
|
||||
"abort-controller": "^3.0.0",
|
||||
"assert": "^2.0.0",
|
||||
"badgin": "^1.1.5",
|
||||
"expo-application": "~5.1.0",
|
||||
"expo-constants": "~14.2.0",
|
||||
"fs-extra": "^9.1.0",
|
||||
"uuid": "^3.4.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"expo": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/expo-notifications/node_modules/fs-extra": {
|
||||
"version": "9.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
|
||||
"integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
|
||||
"dependencies": {
|
||||
"at-least-node": "^1.0.0",
|
||||
"graceful-fs": "^4.2.0",
|
||||
"jsonfile": "^6.0.1",
|
||||
"universalify": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/expo-notifications/node_modules/jsonfile": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
|
||||
"integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
|
||||
"dependencies": {
|
||||
"universalify": "^2.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"graceful-fs": "^4.1.6"
|
||||
}
|
||||
},
|
||||
"node_modules/expo-notifications/node_modules/universalify": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
|
||||
"integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
|
||||
"engines": {
|
||||
"node": ">= 10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/expo-status-bar": {
|
||||
"version": "1.4.4",
|
||||
"resolved": "https://registry.npmjs.org/expo-status-bar/-/expo-status-bar-1.4.4.tgz",
|
||||
"integrity": "sha512-5DV0hIEWgatSC3UgQuAZBoQeaS9CqeWRZ3vzBR9R/+IUD87Adbi4FGhU10nymRqFXOizGsureButGZIXPs7zEA=="
|
||||
},
|
||||
"node_modules/expo-task-manager": {
|
||||
"version": "11.1.1",
|
||||
"resolved": "https://registry.npmjs.org/expo-task-manager/-/expo-task-manager-11.1.1.tgz",
|
||||
"integrity": "sha512-Ot4wq0fVd8+I1W7MsJz0rNdX0ma/zdnBvAppxDX1Oo0o0exo4qs1FmgrTnh3OBnn18aB4cX3wBJoXIatIgNMZQ==",
|
||||
"dependencies": {
|
||||
"unimodules-app-loader": "~4.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"expo": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/extend-shallow": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
|
||||
|
@ -7954,6 +8094,14 @@
|
|||
"resolved": "https://registry.npmjs.org/fontfaceobserver/-/fontfaceobserver-2.3.0.tgz",
|
||||
"integrity": "sha512-6FPvD/IVyT4ZlNe7Wcn5Fb/4ChigpucKYSvD6a+0iMoLn2inpo711eyIcKjmDtE5XNcgAkSH9uN/nfAeZzHEfg=="
|
||||
},
|
||||
"node_modules/for-each": {
|
||||
"version": "0.3.3",
|
||||
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
|
||||
"integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
|
||||
"dependencies": {
|
||||
"is-callable": "^1.1.3"
|
||||
}
|
||||
},
|
||||
"node_modules/for-in": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
|
||||
|
@ -8186,6 +8334,17 @@
|
|||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/gopd": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
|
||||
"integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
|
||||
"dependencies": {
|
||||
"get-intrinsic": "^1.1.3"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/graceful-fs": {
|
||||
"version": "4.2.11",
|
||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
|
||||
|
@ -8232,6 +8391,17 @@
|
|||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/has-property-descriptors": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz",
|
||||
"integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==",
|
||||
"dependencies": {
|
||||
"get-intrinsic": "^1.1.1"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/has-proto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz",
|
||||
|
@ -8254,6 +8424,20 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/has-tostringtag": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz",
|
||||
"integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==",
|
||||
"dependencies": {
|
||||
"has-symbols": "^1.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/has-value": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
|
||||
|
@ -8586,6 +8770,21 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-arguments": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
|
||||
"integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.2",
|
||||
"has-tostringtag": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-arrayish": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
|
||||
|
@ -8596,6 +8795,17 @@
|
|||
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
|
||||
"integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
|
||||
},
|
||||
"node_modules/is-callable": {
|
||||
"version": "1.2.7",
|
||||
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
|
||||
"integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-core-module": {
|
||||
"version": "2.12.1",
|
||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz",
|
||||
|
@ -8680,6 +8890,20 @@
|
|||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/is-generator-function": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz",
|
||||
"integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==",
|
||||
"dependencies": {
|
||||
"has-tostringtag": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-glob": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
|
||||
|
@ -8729,6 +8953,21 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"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==",
|
||||
"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",
|
||||
|
@ -8788,6 +9027,20 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-typed-array": {
|
||||
"version": "1.1.12",
|
||||
"resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz",
|
||||
"integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==",
|
||||
"dependencies": {
|
||||
"which-typed-array": "^1.1.11"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-unicode-supported": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
|
||||
|
@ -11123,6 +11376,14 @@
|
|||
"mkdirp": "bin/cmd.js"
|
||||
}
|
||||
},
|
||||
"node_modules/moment": {
|
||||
"version": "2.29.4",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
|
||||
"integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/moti": {
|
||||
"version": "0.25.3",
|
||||
"resolved": "https://registry.npmjs.org/moti/-/moti-0.25.3.tgz",
|
||||
|
@ -11490,6 +11751,29 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/object-is": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz",
|
||||
"integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.2",
|
||||
"define-properties": "^1.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/object-keys": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
|
||||
"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/object-visit": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz",
|
||||
|
@ -11501,6 +11785,23 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/object.assign": {
|
||||
"version": "4.1.4",
|
||||
"resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz",
|
||||
"integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.2",
|
||||
"define-properties": "^1.1.4",
|
||||
"has-symbols": "^1.0.3",
|
||||
"object-keys": "^1.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/object.pick": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
|
||||
|
@ -14228,6 +14529,11 @@
|
|||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/unimodules-app-loader": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/unimodules-app-loader/-/unimodules-app-loader-4.1.2.tgz",
|
||||
"integrity": "sha512-DLYUCjNpguFhNpxNsBf47NWZi2OjIfWCVQY4f+r4/bwIqFfR7qQd6lXwCFA8EhHS1ti87CBzjMSbIC5bB0J/0Q=="
|
||||
},
|
||||
"node_modules/union-value": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
|
||||
|
@ -14419,6 +14725,18 @@
|
|||
"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==",
|
||||
"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/util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
|
@ -14523,6 +14841,24 @@
|
|||
"resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz",
|
||||
"integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ=="
|
||||
},
|
||||
"node_modules/which-typed-array": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz",
|
||||
"integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==",
|
||||
"dependencies": {
|
||||
"available-typed-arrays": "^1.0.5",
|
||||
"call-bind": "^1.0.2",
|
||||
"for-each": "^0.3.3",
|
||||
"gopd": "^1.0.1",
|
||||
"has-tostringtag": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/wonka": {
|
||||
"version": "4.0.15",
|
||||
"resolved": "https://registry.npmjs.org/wonka/-/wonka-4.0.15.tgz",
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
"expo-linking": "~4.0.1",
|
||||
"expo-location": "~15.1.1",
|
||||
"expo-status-bar": "~1.4.4",
|
||||
"moment": "^2.29.4",
|
||||
"moti": "^0.25.3",
|
||||
"react": "18.2.0",
|
||||
"react-native": "0.71.8",
|
||||
|
@ -40,7 +41,10 @@
|
|||
"react-native-toast-notifications": "^3.3.1",
|
||||
"react-query": "^3.39.3",
|
||||
"react-redux": "^8.1.1",
|
||||
"redux": "^4.2.1"
|
||||
"redux": "^4.2.1",
|
||||
"expo-task-manager": "~11.1.1",
|
||||
"expo-background-fetch": "~11.1.1",
|
||||
"expo-notifications": "~0.18.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.20.0",
|
||||
|
|
|
@ -4,6 +4,7 @@ import {
|
|||
ActivationType,
|
||||
LocationType,
|
||||
LoginType,
|
||||
MessagePostType,
|
||||
OnboardingType,
|
||||
PatchUserInfoType,
|
||||
RegistrationType,
|
||||
|
@ -311,7 +312,6 @@ export async function GetStudyGroupListFiltered() {
|
|||
return instance
|
||||
.get("/api/v1/study_groups/near/", config)
|
||||
.then((response) => {
|
||||
console.log("DEBUGGG", response.data);
|
||||
return [true, response.data];
|
||||
})
|
||||
.catch((error) => {
|
||||
|
@ -346,3 +346,56 @@ export async function CreateStudyGroup(info: StudyGroupCreateType) {
|
|||
return [false, error_message];
|
||||
});
|
||||
}
|
||||
|
||||
export async function GetStudyGroup(name: string) {
|
||||
const config = await GetConfig();
|
||||
return instance
|
||||
.get(`/api/v1/study_groups/${name}`, config)
|
||||
.then((response) => {
|
||||
return [true, response.data];
|
||||
})
|
||||
.catch((error) => {
|
||||
let error_message = ParseError(error);
|
||||
return [false, error_message];
|
||||
});
|
||||
}
|
||||
|
||||
export async function GetStudyGroupMessages() {
|
||||
const config = await GetConfig();
|
||||
return instance
|
||||
.get(`/api/v1/messages/`, config)
|
||||
.then((response) => {
|
||||
return [true, response.data];
|
||||
})
|
||||
.catch((error) => {
|
||||
let error_message = ParseError(error);
|
||||
return [false, error_message];
|
||||
});
|
||||
}
|
||||
|
||||
export async function GetStudyGroupMemberAvatars() {
|
||||
const config = await GetConfig();
|
||||
return instance
|
||||
.get(`/api/v1/study_groups/member_avatars`, config)
|
||||
.then((response) => {
|
||||
return [true, response.data];
|
||||
})
|
||||
.catch((error) => {
|
||||
let error_message = ParseError(error);
|
||||
return [false, error_message];
|
||||
});
|
||||
}
|
||||
|
||||
export async function PostMessage(info: MessagePostType) {
|
||||
const config = await GetConfig();
|
||||
return instance
|
||||
.post(`/api/v1/messages/`, info, config)
|
||||
.then((response) => {
|
||||
return [true, response.data];
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log("Error:", error.response.data);
|
||||
let error_message = ParseError(error);
|
||||
return [false, error_message];
|
||||
});
|
||||
}
|
||||
|
|
148
src/components/BackgroundTask/BackgroundTask.tsx
Normal file
148
src/components/BackgroundTask/BackgroundTask.tsx
Normal file
|
@ -0,0 +1,148 @@
|
|||
import React, { useEffect } from "react";
|
||||
import { View } from "react-native";
|
||||
import * as BackgroundFetch from "expo-background-fetch";
|
||||
import * as TaskManager from "expo-task-manager";
|
||||
import * as Notifications from "expo-notifications";
|
||||
import {
|
||||
GetStudentStatus,
|
||||
GetStudyGroupListFiltered,
|
||||
GetStudyGroupMessages,
|
||||
} from "../Api/Api";
|
||||
import { StudyGroupType } from "../../interfaces/Interfaces";
|
||||
import AsyncStorage from "@react-native-async-storage/async-storage";
|
||||
|
||||
const FETCH_STUDENT_STATUS = "STUDENT_STATUS_TASK";
|
||||
const FETCH_GROUP_MESSAGES = "GROUP_MESSAGES_TASK";
|
||||
|
||||
TaskManager.defineTask(FETCH_GROUP_MESSAGES, async () => {
|
||||
const data = await GetStudyGroupMessages();
|
||||
if (data[0] && data[1]) {
|
||||
let messages_prev = await JSON.parse(
|
||||
(await AsyncStorage.getItem("messages")) || "[]"
|
||||
);
|
||||
await AsyncStorage.setItem("messages", JSON.stringify(data[1]));
|
||||
let message_curr = data[1];
|
||||
let difference: Array<any> = messages_prev
|
||||
.filter(
|
||||
(x: any) =>
|
||||
!message_curr.some(
|
||||
(y: any) => JSON.stringify(y) === JSON.stringify(x)
|
||||
)
|
||||
)
|
||||
.concat(
|
||||
message_curr.filter(
|
||||
(x: any) =>
|
||||
!messages_prev.some(
|
||||
(y: any) => JSON.stringify(y) === JSON.stringify(x)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
if (difference.length > 0) {
|
||||
console.log(`${difference.length} unread messages`);
|
||||
Notifications.scheduleNotificationAsync({
|
||||
content: {
|
||||
title: `${difference.length} unread messages`,
|
||||
body: `${difference[0].user}: ${difference[0].message_content}`,
|
||||
},
|
||||
trigger: {
|
||||
seconds: 1,
|
||||
},
|
||||
});
|
||||
}
|
||||
} else {
|
||||
console.log(data[1].response.data);
|
||||
}
|
||||
|
||||
return BackgroundFetch.BackgroundFetchResult.NewData;
|
||||
});
|
||||
|
||||
TaskManager.defineTask(FETCH_STUDENT_STATUS, async () => {
|
||||
const data = await GetStudyGroupListFiltered();
|
||||
const student_status_data = await GetStudentStatus();
|
||||
if (data[0] && data[1]) {
|
||||
console.log("Fetching nearby study groups...");
|
||||
const entryWithLeastDistance = data[1].reduce(
|
||||
(prev: StudyGroupType, curr: StudyGroupType) => {
|
||||
return prev.distance < curr.distance ? prev : curr;
|
||||
}
|
||||
);
|
||||
// Only display a notification if a student isn't in a study group yet
|
||||
if (
|
||||
student_status_data[1].study_group == null ||
|
||||
student_status_data[1].study_group == ""
|
||||
) {
|
||||
console.log(
|
||||
"User has no study group yet. Found nearby groups, pushing notification"
|
||||
);
|
||||
Notifications.scheduleNotificationAsync({
|
||||
content: {
|
||||
title: "Students are studying nearby",
|
||||
body: `Nearest study group is ${Math.round(
|
||||
entryWithLeastDistance.distance * 1000
|
||||
)}m away`,
|
||||
},
|
||||
trigger: {
|
||||
seconds: 1,
|
||||
},
|
||||
});
|
||||
}
|
||||
} else {
|
||||
console.log(data[1].response.data);
|
||||
}
|
||||
|
||||
return BackgroundFetch.BackgroundFetchResult.NewData;
|
||||
});
|
||||
|
||||
const BackgroundComponent = () => {
|
||||
const notification_debug = true;
|
||||
const [Task1_isRegistered, Task1_setIsRegistered] = React.useState(false);
|
||||
const [Task2_isRegistered, Task2_setIsRegistered] = React.useState(false);
|
||||
const [status, setStatus] = React.useState<any>();
|
||||
const checkStatusAsync = async () => {
|
||||
let status = await BackgroundFetch.getStatusAsync();
|
||||
setStatus(status);
|
||||
let Task1_isRegistered = await TaskManager.isTaskRegisteredAsync(
|
||||
FETCH_STUDENT_STATUS
|
||||
);
|
||||
let Task2_isRegistered = await TaskManager.isTaskRegisteredAsync(
|
||||
FETCH_GROUP_MESSAGES
|
||||
);
|
||||
Task1_setIsRegistered(Task1_isRegistered);
|
||||
Task2_setIsRegistered(Task2_isRegistered);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const registerTasks = async () => {
|
||||
try {
|
||||
await checkStatusAsync();
|
||||
// Nearby students task
|
||||
if (!Task1_isRegistered) {
|
||||
await BackgroundFetch.registerTaskAsync(FETCH_STUDENT_STATUS, {
|
||||
minimumInterval: notification_debug ? 5 : 60 * 3, // Check every 5 seconds in dev & every 3 minutes in production builds
|
||||
});
|
||||
console.log("Task for nearby students check registered");
|
||||
} else {
|
||||
console.log("Task for nearby students check already registered");
|
||||
}
|
||||
// Message Checking Task
|
||||
if (!Task2_isRegistered) {
|
||||
await BackgroundFetch.registerTaskAsync(FETCH_GROUP_MESSAGES, {
|
||||
minimumInterval: notification_debug ? 5 : 30, // Check every 5 seconds in dev & every 30 seconds in production builds
|
||||
});
|
||||
console.log("Task for group messages check registered");
|
||||
} else {
|
||||
console.log("Task for group messages check already registered");
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("Task Register failed:", err);
|
||||
}
|
||||
};
|
||||
|
||||
registerTasks();
|
||||
}, []);
|
||||
|
||||
return <View />;
|
||||
};
|
||||
|
||||
export default BackgroundComponent;
|
|
@ -27,12 +27,12 @@ import { PatchStudentStatus } from "../Api/Api";
|
|||
import { useToast } from "react-native-toast-notifications";
|
||||
|
||||
export default function CustomDrawerContent(props: {}) {
|
||||
const debug = true;
|
||||
const navigation = useNavigation<RootDrawerParamList>();
|
||||
const status = useSelector((state: RootState) => state.status);
|
||||
const dispatch = useDispatch();
|
||||
const queryClient = useQueryClient();
|
||||
const toast = useToast();
|
||||
const debug_disable_clear_on_logout = true;
|
||||
const stop_studying_logout = useMutation({
|
||||
mutationFn: async (info: StudentStatusPatchType) => {
|
||||
const data = await PatchStudentStatus(info);
|
||||
|
@ -78,7 +78,8 @@ export default function CustomDrawerContent(props: {}) {
|
|||
|
||||
<DrawerButton
|
||||
onPress={async () => {
|
||||
if (debug_disable_clear_on_logout) {
|
||||
// We don't clear student statuses when logging out on debug
|
||||
if (!debug) {
|
||||
queryClient.clear();
|
||||
dispatch(logout());
|
||||
await AsyncStorage.clear();
|
||||
|
@ -131,9 +132,18 @@ export default function CustomDrawerContent(props: {}) {
|
|||
<SubjectIcon size={32} />
|
||||
<Text style={styles.text_white_medium}>Subjects</Text>
|
||||
</DrawerButton>
|
||||
<DrawerButton
|
||||
onPress={() => {
|
||||
navigation.navigate("Conversation");
|
||||
}}
|
||||
>
|
||||
<SubjectIcon size={32} />
|
||||
<Text style={styles.text_white_medium}>Conversation</Text>
|
||||
</DrawerButton>
|
||||
<DrawerButton
|
||||
onPress={async () => {
|
||||
if (debug_disable_clear_on_logout) {
|
||||
// We don't clear student statuses when logging out on debug
|
||||
if (!debug) {
|
||||
queryClient.clear();
|
||||
dispatch(logout());
|
||||
await AsyncStorage.clear();
|
||||
|
@ -178,14 +188,6 @@ export default function CustomDrawerContent(props: {}) {
|
|||
<SignupIcon size={32} />
|
||||
<Text style={styles.text_white_medium}>Register</Text>
|
||||
</DrawerButton>
|
||||
<DrawerButton
|
||||
onPress={() => {
|
||||
navigation.navigate("Conversation");
|
||||
}}
|
||||
>
|
||||
<SubjectIcon size={32} />
|
||||
<Text style={styles.text_white_medium}>Conversation</Text>
|
||||
</DrawerButton>
|
||||
{/*
|
||||
Debug buttons for accessing revalidation and activation page
|
||||
<DrawerButton
|
||||
|
|
|
@ -185,13 +185,31 @@ export interface StudyGroupCreateType {
|
|||
subject: string;
|
||||
}
|
||||
|
||||
export interface MessageType {
|
||||
id: number;
|
||||
user: string;
|
||||
study_group: string;
|
||||
message_content: string;
|
||||
timestamp: string;
|
||||
}
|
||||
|
||||
export interface MessagePostType {
|
||||
message_content: string;
|
||||
}
|
||||
|
||||
export interface GroupMessageAvatarType {
|
||||
username: string;
|
||||
avatar: string;
|
||||
}
|
||||
|
||||
export type GroupMessageAvatarListType = GroupMessageAvatarType[];
|
||||
export type GroupMessageAvatarReturnType = [boolean, GroupMessageAvatarType[]];
|
||||
export type MessageReturnType = [boolean, MessageType[]];
|
||||
export type StudyGroupDetailReturnType = [boolean, StudyGroupType];
|
||||
export type StudyGroupReturnType = [boolean, StudyGroupType[]];
|
||||
|
||||
export type StudentStatusReturnType = [boolean, StudentStatusType];
|
||||
|
||||
export type StudentStatusListType = Array<StudentStatusFilterType>;
|
||||
export type StudentStatusListReturnType = [boolean, StudentStatusListType];
|
||||
|
||||
export type RawLocationType = Location.LocationObject;
|
||||
|
||||
export interface UserInfoType {
|
||||
|
|
|
@ -1,179 +1,329 @@
|
|||
import * as React from "react";
|
||||
import { ActivityIndicator, Image } from "react-native";
|
||||
import styles from "../../styles";
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
TextInput,
|
||||
ScrollView,
|
||||
StyleSheet
|
||||
NativeSyntheticEvent,
|
||||
TextInputChangeEventData,
|
||||
} from "react-native";
|
||||
import { colors } from "../../styles";
|
||||
import { useState } from "react";
|
||||
|
||||
const convStyles = StyleSheet.create({
|
||||
scrollViewContainer: {
|
||||
backgroundColor: colors.secondary_1,
|
||||
padding: 15,
|
||||
},
|
||||
messageContainer: {
|
||||
backgroundColor: '#00000038',
|
||||
margin: 5,
|
||||
padding: 10,
|
||||
borderRadius: 20,
|
||||
},
|
||||
badge: {
|
||||
height: 10,
|
||||
width: 10,
|
||||
borderRadius: 10,
|
||||
}
|
||||
})
|
||||
|
||||
type ConversationType = {
|
||||
username: string;
|
||||
message: string;
|
||||
userId: number;
|
||||
type: string;
|
||||
color: string;
|
||||
}
|
||||
|
||||
import { useRef, useState } from "react";
|
||||
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||
import {
|
||||
GetStudentStatus,
|
||||
GetStudyGroup,
|
||||
GetStudyGroupMemberAvatars,
|
||||
GetStudyGroupMessages,
|
||||
PostMessage,
|
||||
} from "../../components/Api/Api";
|
||||
import {
|
||||
StudentStatusType,
|
||||
StudentStatusReturnType,
|
||||
StudyGroupType,
|
||||
StudyGroupDetailReturnType,
|
||||
MessageType,
|
||||
MessageReturnType,
|
||||
MessagePostType,
|
||||
GroupMessageAvatarType,
|
||||
GroupMessageAvatarReturnType,
|
||||
} from "../../interfaces/Interfaces";
|
||||
import { useToast } from "react-native-toast-notifications";
|
||||
import { useQueryClient } from "@tanstack/react-query";
|
||||
import AnimatedContainer from "../../components/AnimatedContainer/AnimatedContainer";
|
||||
import AsyncStorage from "@react-native-async-storage/async-storage";
|
||||
|
||||
export default function ConversationPage() {
|
||||
const [conversation, setConversation] = useState<ConversationType[]>([{
|
||||
username: "You",
|
||||
message: "Hello World naa ko diri canteen gutom sh*t.",
|
||||
userId: Math.floor(Math.random() * 1000),
|
||||
type: "o",
|
||||
color: Math.floor(Math.random() * 16777215).toString(16)
|
||||
}, {
|
||||
username: "User 2",
|
||||
message: "Hahahah shor oy.",
|
||||
userId: Math.floor(Math.random() * 1000),
|
||||
type: "i",
|
||||
color: Math.floor(Math.random() * 16777215).toString(16)
|
||||
}, {
|
||||
username: "User 3",
|
||||
message: "AHAHAHHA BOBO!",
|
||||
userId: Math.floor(Math.random() * 1000),
|
||||
type: "i",
|
||||
color: Math.floor(Math.random() * 16777215).toString(16)
|
||||
},
|
||||
{
|
||||
username: "Vale",
|
||||
message: "tanga valir! bobo!",
|
||||
userId: Math.floor(Math.random() * 1000),
|
||||
type: "i",
|
||||
color: Math.floor(Math.random() * 16777215).toString(16)
|
||||
},
|
||||
{
|
||||
username: "You",
|
||||
message: "Hoyy bobo!!!",
|
||||
userId: Math.floor(Math.random() * 1000),
|
||||
type: "o",
|
||||
color: Math.floor(Math.random() * 16777215).toString(16)
|
||||
}, {
|
||||
username: "Valir",
|
||||
message: "Gago! 1v1 nalng?",
|
||||
userId: Math.floor(Math.random() * 1000),
|
||||
type: "o",
|
||||
color: Math.floor(Math.random() * 16777215).toString(16)
|
||||
}, {
|
||||
username: "User 2",
|
||||
message: "Hello World",
|
||||
userId: Math.floor(Math.random() * 1000),
|
||||
type: "i",
|
||||
color: Math.floor(Math.random() * 16777215).toString(16)
|
||||
}, {
|
||||
username: "User 3",
|
||||
message: "Hello World",
|
||||
userId: Math.floor(Math.random() * 1000),
|
||||
type: "i",
|
||||
color: Math.floor(Math.random() * 16777215).toString(16)
|
||||
},
|
||||
{
|
||||
username: "User 1",
|
||||
message: "Hello World",
|
||||
userId: Math.floor(Math.random() * 1000),
|
||||
type: "o",
|
||||
color: Math.floor(Math.random() * 16777215).toString(16)
|
||||
},
|
||||
{
|
||||
username: "User 1",
|
||||
message: "Hello World",
|
||||
userId: Math.floor(Math.random() * 1000),
|
||||
type: "o",
|
||||
color: Math.floor(Math.random() * 16777215).toString(16)
|
||||
},
|
||||
{
|
||||
username: "User 1",
|
||||
message: "Hello World",
|
||||
userId: Math.floor(Math.random() * 1000),
|
||||
type: "o",
|
||||
color: Math.floor(Math.random() * 16777215).toString(16)
|
||||
},
|
||||
{
|
||||
username: "User 1",
|
||||
message: "Hello World",
|
||||
userId: Math.floor(Math.random() * 1000),
|
||||
type: "o",
|
||||
color: Math.floor(Math.random() * 16777215).toString(16)
|
||||
const toast = useToast();
|
||||
// Student Status
|
||||
const [student_status, setStudentStatus] = useState<StudentStatusType>();
|
||||
const StudentStatusQuery = useQuery({
|
||||
queryKey: ["user_status"],
|
||||
queryFn: async () => {
|
||||
const data = await GetStudentStatus();
|
||||
if (data[0] == false) {
|
||||
return Promise.reject(new Error(JSON.stringify(data[1])));
|
||||
}
|
||||
]);
|
||||
return data;
|
||||
},
|
||||
onSuccess: (data: StudentStatusReturnType) => {
|
||||
setStudentStatus(data[1]);
|
||||
},
|
||||
onError: (error: Error) => {
|
||||
toast.show(String(error), {
|
||||
type: "warning",
|
||||
placement: "top",
|
||||
duration: 2000,
|
||||
animationType: "slide-in",
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
// Study Group Detail
|
||||
const [studygroup, setStudyGroup] = useState<StudyGroupType>();
|
||||
const StudyGroupQuery = useQuery({
|
||||
enabled:
|
||||
student_status?.study_group != "" && student_status?.study_group != null,
|
||||
queryKey: ["study_group"],
|
||||
queryFn: async () => {
|
||||
const data = await GetStudyGroup(student_status?.study_group || "");
|
||||
if (data[0] == false) {
|
||||
return Promise.reject(new Error(JSON.stringify(data[1])));
|
||||
}
|
||||
return data;
|
||||
},
|
||||
onSuccess: (data: StudyGroupDetailReturnType) => {
|
||||
if (data[1]) {
|
||||
setStudyGroup(data[1]);
|
||||
}
|
||||
},
|
||||
onError: (error: Error) => {
|
||||
toast.show(String(error), {
|
||||
type: "warning",
|
||||
placement: "top",
|
||||
duration: 2000,
|
||||
animationType: "slide-in",
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
// Study Group Messages
|
||||
const [messages, setMessages] = useState<MessageType[]>([]);
|
||||
const MessageQuery = useQuery({
|
||||
refetchInterval: 3000,
|
||||
enabled:
|
||||
!StudentStatusQuery.isLoading &&
|
||||
(student_status?.study_group != null ||
|
||||
student_status?.study_group != ""),
|
||||
queryKey: ["study_group_messages"],
|
||||
queryFn: async () => {
|
||||
const data = await GetStudyGroupMessages();
|
||||
if (data[0] == false) {
|
||||
return Promise.reject(new Error(JSON.stringify(data[1])));
|
||||
}
|
||||
return data;
|
||||
},
|
||||
onSuccess: async (data: MessageReturnType) => {
|
||||
if (data[1]) {
|
||||
await AsyncStorage.setItem("messages", JSON.stringify(data[1]));
|
||||
setMessages(data[1]);
|
||||
}
|
||||
},
|
||||
onError: (error: Error) => {
|
||||
toast.show(String(error), {
|
||||
type: "warning",
|
||||
placement: "top",
|
||||
duration: 2000,
|
||||
animationType: "slide-in",
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
// Avatar List
|
||||
const [users, setUsers] = useState<GroupMessageAvatarType[]>([]);
|
||||
const AvatarsQuery = useQuery({
|
||||
refetchInterval: 3000,
|
||||
enabled:
|
||||
student_status?.study_group != null ||
|
||||
(student_status?.study_group != "" &&
|
||||
studygroup != null &&
|
||||
studygroup.students != null),
|
||||
queryKey: ["study_group_avatars"],
|
||||
queryFn: async () => {
|
||||
const data = await GetStudyGroupMemberAvatars();
|
||||
if (data[0] == false) {
|
||||
return Promise.reject(new Error(JSON.stringify(data[1])));
|
||||
}
|
||||
return data;
|
||||
},
|
||||
onSuccess: (data: GroupMessageAvatarReturnType) => {
|
||||
if (data[1]) {
|
||||
setUsers(data[1]);
|
||||
}
|
||||
},
|
||||
onError: (error: Error) => {
|
||||
toast.show(String(error), {
|
||||
type: "warning",
|
||||
placement: "top",
|
||||
duration: 2000,
|
||||
animationType: "slide-in",
|
||||
});
|
||||
},
|
||||
});
|
||||
const scrollViewRef = useRef<ScrollView>(null);
|
||||
const queryClient = useQueryClient();
|
||||
const [message, setMessage] = useState("");
|
||||
const send_message = useMutation({
|
||||
mutationFn: async (info: MessagePostType) => {
|
||||
const data = await PostMessage(info);
|
||||
if (data[0] != true) {
|
||||
return Promise.reject(new Error());
|
||||
}
|
||||
return data;
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ["study_group_messages"] });
|
||||
},
|
||||
onError: (error: Error) => {
|
||||
toast.show(String(error), {
|
||||
type: "warning",
|
||||
placement: "top",
|
||||
duration: 2000,
|
||||
animationType: "slide-in",
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
if (
|
||||
!StudyGroupQuery.isLoading &&
|
||||
!AvatarsQuery.isLoading &&
|
||||
!MessageQuery.isLoading &&
|
||||
student_status &&
|
||||
studygroup &&
|
||||
studygroup.students
|
||||
) {
|
||||
return (
|
||||
<ScrollView style={convStyles.scrollViewContainer}>
|
||||
<View style={{
|
||||
display: "flex", backgroundColor: colors.secondary_2,
|
||||
borderRadius: 20,
|
||||
}}>
|
||||
<View style={{ padding: 15 }}>
|
||||
<View style={{flexDirection: "row"}}>
|
||||
<Text style={{ ...styles.text_white_medium }}>Group#57605</Text>
|
||||
</View>
|
||||
<Text>3 students
|
||||
<View style={{ ...convStyles.badge, backgroundColor: 'blue' }}></View>
|
||||
<View style={{ ...convStyles.badge, backgroundColor: `green` }}></View>
|
||||
<View style={{ ...convStyles.badge, backgroundColor: `red` }}></View>
|
||||
<View style={styles.background}>
|
||||
<AnimatedContainer>
|
||||
<View
|
||||
style={{
|
||||
padding: 15,
|
||||
alignSelf: "flex-start",
|
||||
}}
|
||||
>
|
||||
<View style={styles.flex_row}>
|
||||
<Text style={{ ...styles.text_white_medium }}>
|
||||
{`Group: ${studygroup?.name ? studygroup.name : ""}`}
|
||||
</Text>
|
||||
</View>
|
||||
<View>
|
||||
{
|
||||
conversation.map((item: ConversationType) => (
|
||||
<View key={item.userId} style={{
|
||||
...convStyles.messageContainer,
|
||||
alignItems: item.type == 'o' ? "flex-end" : 'flex-start'
|
||||
}}>
|
||||
<View style={{ ...styles.flex_row }}>
|
||||
<Text
|
||||
style={{
|
||||
...styles.text_white_small,
|
||||
textAlign: "left",
|
||||
paddingRight: 4,
|
||||
}}
|
||||
>
|
||||
{studygroup.students.length} studying
|
||||
</Text>
|
||||
{users.map((user: GroupMessageAvatarType, index: number) => {
|
||||
if (index > 6) {
|
||||
return <React.Fragment key={index} />;
|
||||
}
|
||||
return (
|
||||
<React.Fragment key={index}>
|
||||
{user.avatar != null && user.avatar != "" ? (
|
||||
<Image
|
||||
source={{ uri: user.avatar }}
|
||||
style={styles.profile_mini}
|
||||
/>
|
||||
) : (
|
||||
<Image
|
||||
source={require("../../img/user_profile_placeholder.png")}
|
||||
style={styles.profile_mini}
|
||||
/>
|
||||
)}
|
||||
</React.Fragment>
|
||||
);
|
||||
})}
|
||||
</View>
|
||||
</View>
|
||||
<ScrollView
|
||||
style={{ width: 320 }}
|
||||
onContentSizeChange={() => scrollViewRef.current?.scrollToEnd()}
|
||||
ref={scrollViewRef}
|
||||
>
|
||||
{messages.length > 0 ? (
|
||||
messages.map((message: MessageType, index: number) => {
|
||||
let avatar = "";
|
||||
users.filter((user: GroupMessageAvatarType) => {
|
||||
if (user.username == message.user) {
|
||||
avatar = user.avatar;
|
||||
}
|
||||
});
|
||||
return (
|
||||
<View
|
||||
key={message.id}
|
||||
style={{
|
||||
...styles.message_contentContainer,
|
||||
alignItems: index % 2 == 0 ? "flex-end" : "flex-start",
|
||||
}}
|
||||
>
|
||||
<View style={styles.flex_row}>
|
||||
{avatar != null && avatar != "" ? (
|
||||
<Image
|
||||
source={{ uri: avatar }}
|
||||
style={styles.profile_mini}
|
||||
/>
|
||||
) : (
|
||||
<Image
|
||||
source={require("../../img/user_profile_placeholder.png")}
|
||||
style={styles.profile_mini}
|
||||
/>
|
||||
)}
|
||||
|
||||
<Text style={styles.text_white_small}>
|
||||
{
|
||||
item.type == 'i' ? <View style={{
|
||||
...convStyles.badge,
|
||||
backgroundColor: `#${item.color}`,
|
||||
marginRight: 2
|
||||
}}></View> : null
|
||||
}
|
||||
{item.username}
|
||||
{
|
||||
item.type == 'o' ? <View style={{
|
||||
...convStyles.badge,
|
||||
backgroundColor: `#${item.color}`,
|
||||
marginLeft: 2
|
||||
}}></View> : null
|
||||
}
|
||||
{message.user}
|
||||
</Text>
|
||||
<Text
|
||||
style={{
|
||||
...styles.text_white_tiny,
|
||||
...{ marginLeft: 4, alignContent: "center" },
|
||||
}}
|
||||
>
|
||||
{message.timestamp}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<Text style={styles.text_white_small}>
|
||||
{item.message}
|
||||
{message.message_content}
|
||||
</Text>
|
||||
</View>
|
||||
))
|
||||
}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
})
|
||||
) : (
|
||||
<Text style={styles.text_white_small}>There are no messages</Text>
|
||||
)}
|
||||
</ScrollView>
|
||||
<TextInput
|
||||
style={styles.chatbox}
|
||||
placeholder="type here...."
|
||||
placeholder="Send a message..."
|
||||
placeholderTextColor="white"
|
||||
autoCapitalize="none"
|
||||
value={message}
|
||||
onChange={(
|
||||
e: NativeSyntheticEvent<TextInputChangeEventData>
|
||||
): void => {
|
||||
setMessage(e.nativeEvent.text);
|
||||
}}
|
||||
onSubmitEditing={() => {
|
||||
send_message.mutate({
|
||||
message_content: message,
|
||||
});
|
||||
setMessage("");
|
||||
}}
|
||||
/>
|
||||
</ScrollView>
|
||||
</AnimatedContainer>
|
||||
</View>
|
||||
);
|
||||
} else if (!student_status?.study_group) {
|
||||
return (
|
||||
<View style={styles.background}>
|
||||
<AnimatedContainer>
|
||||
<Text style={styles.text_white_medium}>
|
||||
You are not in a study group. Join one to start a conversation!
|
||||
</Text>
|
||||
</AnimatedContainer>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<View style={styles.background}>
|
||||
<AnimatedContainer>
|
||||
<ActivityIndicator size={96} color={colors.secondary_1} />
|
||||
<Text style={styles.text_white_medium}>Loading...</Text>
|
||||
</AnimatedContainer>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ import CaretUpIcon from "../../icons/CaretUpIcon/CaretUpIcon";
|
|||
|
||||
export default function Home() {
|
||||
// Switch this condition to see the main map when debugging
|
||||
const map_debug = true;
|
||||
const map_distance_override = true;
|
||||
const navigation = useNavigation<RootDrawerParamList>();
|
||||
const [location, setLocation] = useState<RawLocationType | null>(null);
|
||||
const [dist, setDist] = useState<number | null>(null);
|
||||
|
@ -100,7 +100,7 @@ export default function Home() {
|
|||
let dist = GetDistanceFromUSTP(location.coords);
|
||||
setDist(dist);
|
||||
// Deactivate student status if too far away
|
||||
if (dist >= 2 && !map_debug)
|
||||
if (dist >= 2 && !map_distance_override)
|
||||
stop_studying.mutate({
|
||||
active: false,
|
||||
});
|
||||
|
@ -121,17 +121,13 @@ export default function Home() {
|
|||
return data;
|
||||
},
|
||||
onSuccess: (data: StudentStatusReturnType) => {
|
||||
if (data[1].active !== undefined) {
|
||||
setStudying(data[1].active);
|
||||
}
|
||||
if (data[1].subject !== undefined) {
|
||||
setSubject(data[1].subject);
|
||||
}
|
||||
if (data[1].active == true) {
|
||||
setButtonLabel("Stop Studying");
|
||||
} else if (data[1].active == false) {
|
||||
setButtonLabel("Start Studying");
|
||||
}
|
||||
setSubject(data[1].subject);
|
||||
setStudying(data[1].active);
|
||||
setStudentStatus(data[1]);
|
||||
},
|
||||
onError: (error: Error) => {
|
||||
|
@ -232,7 +228,7 @@ export default function Home() {
|
|||
useState<StudentStatusListType>([]);
|
||||
// Student Status List
|
||||
const StudentStatusListQuery = useQuery({
|
||||
enabled: studying,
|
||||
enabled: studying && !StudentStatusQuery.isLoading,
|
||||
queryKey: ["user_status_list"],
|
||||
queryFn: async () => {
|
||||
const data = await GetStudentStatusListNear();
|
||||
|
@ -264,7 +260,7 @@ export default function Home() {
|
|||
useState<StudentStatusListType>([]);
|
||||
// Student Status List Global
|
||||
const StudentStatusListGlobalQuery = useQuery({
|
||||
enabled: !studying,
|
||||
enabled: !studying && !StudentStatusQuery.isLoading,
|
||||
queryKey: ["user_status_list_global"],
|
||||
queryFn: async () => {
|
||||
const data = await GetStudentStatusList();
|
||||
|
@ -295,7 +291,7 @@ export default function Home() {
|
|||
const [study_groups, setStudyGroups] = useState<StudyGroupType[]>([]);
|
||||
// Study Group List
|
||||
const StudyGroupQuery = useQuery({
|
||||
enabled: studying,
|
||||
enabled: studying && !StudentStatusQuery.isLoading,
|
||||
queryKey: ["study_group_list"],
|
||||
queryFn: async () => {
|
||||
const data = await GetStudyGroupListFiltered();
|
||||
|
@ -323,7 +319,7 @@ export default function Home() {
|
|||
>([]);
|
||||
// Study Group Global List
|
||||
const StudyGroupGlobalQuery = useQuery({
|
||||
enabled: !studying,
|
||||
enabled: !studying && !StudentStatusQuery.isLoading,
|
||||
queryKey: ["study_group_list_global"],
|
||||
queryFn: async () => {
|
||||
const data = await GetStudyGroupList();
|
||||
|
@ -349,7 +345,7 @@ export default function Home() {
|
|||
|
||||
function CustomMap() {
|
||||
if (dist && location) {
|
||||
if (dist <= 2 || map_debug) {
|
||||
if (dist <= 2 || map_distance_override) {
|
||||
return (
|
||||
<>
|
||||
<MapView
|
||||
|
@ -833,7 +829,7 @@ export default function Home() {
|
|||
return (
|
||||
<>
|
||||
<Text style={styles.text_white_medium}>{feedback}</Text>
|
||||
<Button onPress={() => requestLocation()}>
|
||||
<Button onPress={async () => await requestLocation()}>
|
||||
<Text style={styles.text_white_medium}>Allow Access</Text>
|
||||
</Button>
|
||||
</>
|
||||
|
@ -849,7 +845,6 @@ export default function Home() {
|
|||
hasBackdrop={false}
|
||||
>
|
||||
<AnimatedContainer>
|
||||
<Text style={styles.text_white_medium}>Groups List</Text>
|
||||
<Pressable
|
||||
style={{
|
||||
alignContent: "flex-start",
|
||||
|
@ -860,12 +855,16 @@ export default function Home() {
|
|||
>
|
||||
<DropdownIcon size={32} />
|
||||
</Pressable>
|
||||
<View style={styles.flex_row}>
|
||||
<Switch
|
||||
value={modalByGroup}
|
||||
onChange={() => {
|
||||
setModalByGroup(!modalByGroup);
|
||||
}}
|
||||
/>
|
||||
<Text style={styles.text_white_medium}>List View</Text>
|
||||
</View>
|
||||
|
||||
<ScrollView>
|
||||
{!modalByGroup ? (
|
||||
student_statuses.map(
|
||||
|
|
|
@ -186,6 +186,16 @@ const styles = StyleSheet.create({
|
|||
borderColor: colors.primary_2,
|
||||
borderWidth: 3,
|
||||
},
|
||||
profile_mini: {
|
||||
height: 32,
|
||||
width: 32,
|
||||
alignSelf: "center",
|
||||
borderRadius: 150 / 2,
|
||||
overflow: "hidden",
|
||||
padding: 0,
|
||||
borderColor: colors.primary_2,
|
||||
borderWidth: 3,
|
||||
},
|
||||
input: {
|
||||
paddingHorizontal: 8,
|
||||
marginVertical: 2,
|
||||
|
@ -212,6 +222,25 @@ const styles = StyleSheet.create({
|
|||
backgroundColor: colors.primary_2,
|
||||
borderRadius: 20,
|
||||
borderColor: colors.primary_3,
|
||||
}
|
||||
width: 256,
|
||||
},
|
||||
messageScrollViewContainer: {
|
||||
backgroundColor: colors.secondary_1,
|
||||
padding: 15,
|
||||
},
|
||||
message_contentContainer: {
|
||||
backgroundColor: "#00000038",
|
||||
margin: 5,
|
||||
padding: 10,
|
||||
borderRadius: 20,
|
||||
},
|
||||
badge: {
|
||||
height: 16,
|
||||
width: 16,
|
||||
justifyContent: "center",
|
||||
borderRadius: 10,
|
||||
marginLeft: 4,
|
||||
marginRight: 4,
|
||||
},
|
||||
});
|
||||
export default styles;
|
||||
|
|
Loading…
Reference in a new issue