mirror of
https://github.com/lemeow125/StudE-Frontend.git
synced 2024-11-17 06:19:25 +08:00
commit
a9acff39e4
29 changed files with 1244 additions and 117 deletions
63
App.tsx
63
App.tsx
|
@ -1,6 +1,11 @@
|
|||
import "react-native-gesture-handler";
|
||||
import { NavigationContainer } from "@react-navigation/native";
|
||||
import { createDrawerNavigator } from "@react-navigation/drawer";
|
||||
import { Provider } from "react-redux";
|
||||
import store from "./src/features/redux/Store/Store";
|
||||
import "react-native-reanimated";
|
||||
import "react-native-gesture-handler";
|
||||
import * as Linking from "expo-linking";
|
||||
|
||||
import CustomDrawerContent from "./src/components/DrawerSettings/CustomDrawerContent";
|
||||
import DrawerScreenSettings from "./src/components/DrawerSettings/DrawerScreenSettings";
|
||||
|
@ -8,21 +13,57 @@ import DrawerScreenSettings from "./src/components/DrawerSettings/DrawerScreenSe
|
|||
import Home from "./src/routes/Home/Home";
|
||||
import Login from "./src/routes/Login/Login";
|
||||
import Register from "./src/routes/Register/Register";
|
||||
import Onboarding from "./src/routes/Onboarding/Onboarding";
|
||||
import Revalidation from "./src/routes/Revalidation/Revalidation";
|
||||
import Activation from "./src/routes/Activation/Activation";
|
||||
import { useState, useEffect } from "react";
|
||||
|
||||
const Drawer = createDrawerNavigator();
|
||||
|
||||
const linking = {
|
||||
prefixes: [Linking.makeUrl("/")],
|
||||
config: {
|
||||
screens: {
|
||||
Home: "home",
|
||||
Login: "login",
|
||||
Register: "register",
|
||||
Onboarding: "onboarding",
|
||||
Revalidation: "revalidation",
|
||||
Activation: "activation/:uid?/:token?",
|
||||
NotFound: "*",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default function App() {
|
||||
const [initialRoute, setInitialRoute] = useState<string | null>(null);
|
||||
useEffect(() => {
|
||||
async function getInitialURL() {
|
||||
const url = await Linking.getInitialURL();
|
||||
if (url) {
|
||||
setInitialRoute(url);
|
||||
}
|
||||
}
|
||||
if (!initialRoute) {
|
||||
getInitialURL();
|
||||
}
|
||||
}, [initialRoute]);
|
||||
return (
|
||||
<NavigationContainer>
|
||||
<Drawer.Navigator
|
||||
initialRouteName="Home"
|
||||
drawerContent={CustomDrawerContent}
|
||||
screenOptions={DrawerScreenSettings}
|
||||
>
|
||||
<Drawer.Screen name="Home" component={Home} />
|
||||
<Drawer.Screen name="Login" component={Login} />
|
||||
<Drawer.Screen name="Register" component={Register} />
|
||||
</Drawer.Navigator>
|
||||
</NavigationContainer>
|
||||
<Provider store={store}>
|
||||
<NavigationContainer linking={linking}>
|
||||
<Drawer.Navigator
|
||||
initialRouteName="Revalidation"
|
||||
drawerContent={CustomDrawerContent}
|
||||
screenOptions={DrawerScreenSettings}
|
||||
>
|
||||
<Drawer.Screen name="Home" component={Home} />
|
||||
<Drawer.Screen name="Login" component={Login} />
|
||||
<Drawer.Screen name="Register" component={Register} />
|
||||
<Drawer.Screen name="Onboarding" component={Onboarding} />
|
||||
<Drawer.Screen name="Revalidation" component={Revalidation} />
|
||||
<Drawer.Screen name="Activation" component={Activation} />
|
||||
</Drawer.Navigator>
|
||||
</NavigationContainer>
|
||||
</Provider>
|
||||
);
|
||||
}
|
||||
|
|
1
app.json
1
app.json
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"expo": {
|
||||
"name": "StudE_Frontend",
|
||||
"scheme": "stude",
|
||||
"slug": "StudE_Frontend",
|
||||
"version": "1.0.0",
|
||||
"orientation": "portrait",
|
||||
|
|
386
package-lock.json
generated
386
package-lock.json
generated
|
@ -8,17 +8,25 @@
|
|||
"name": "stude_frontend",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"@react-native-async-storage/async-storage": "1.17.11",
|
||||
"@react-navigation/drawer": "^6.6.3",
|
||||
"@react-navigation/native": "^6.1.7",
|
||||
"@react-navigation/native-stack": "^6.9.13",
|
||||
"@reduxjs/toolkit": "^1.9.5",
|
||||
"axios": "^1.4.0",
|
||||
"expo": "~48.0.18",
|
||||
"expo-linking": "~4.0.1",
|
||||
"expo-status-bar": "~1.4.4",
|
||||
"moti": "^0.25.3",
|
||||
"react": "18.2.0",
|
||||
"react-native": "0.71.8",
|
||||
"react-native-gesture-handler": "~2.9.0",
|
||||
"react-native-reanimated": "~2.14.4",
|
||||
"react-native-safe-area-context": "4.5.0",
|
||||
"react-native-screens": "~3.20.0",
|
||||
"react-native-svg": "13.4.0"
|
||||
"react-native-svg": "13.4.0",
|
||||
"react-redux": "^8.1.1",
|
||||
"redux": "^4.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.20.0",
|
||||
|
@ -1979,6 +1987,21 @@
|
|||
"node": ">=0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@emotion/is-prop-valid": {
|
||||
"version": "0.8.8",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz",
|
||||
"integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@emotion/memoize": "0.7.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@emotion/memoize": {
|
||||
"version": "0.7.4",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz",
|
||||
"integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/@expo/bunyan": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@expo/bunyan/-/bunyan-4.0.0.tgz",
|
||||
|
@ -3544,6 +3567,64 @@
|
|||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
|
||||
"integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw=="
|
||||
},
|
||||
"node_modules/@motionone/animation": {
|
||||
"version": "10.15.1",
|
||||
"resolved": "https://registry.npmjs.org/@motionone/animation/-/animation-10.15.1.tgz",
|
||||
"integrity": "sha512-mZcJxLjHor+bhcPuIFErMDNyrdb2vJur8lSfMCsuCB4UyV8ILZLvK+t+pg56erv8ud9xQGK/1OGPt10agPrCyQ==",
|
||||
"dependencies": {
|
||||
"@motionone/easing": "^10.15.1",
|
||||
"@motionone/types": "^10.15.1",
|
||||
"@motionone/utils": "^10.15.1",
|
||||
"tslib": "^2.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@motionone/dom": {
|
||||
"version": "10.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@motionone/dom/-/dom-10.12.0.tgz",
|
||||
"integrity": "sha512-UdPTtLMAktHiqV0atOczNYyDd/d8Cf5fFsd1tua03PqTwwCe/6lwhLSQ8a7TbnQ5SN0gm44N1slBfj+ORIhrqw==",
|
||||
"dependencies": {
|
||||
"@motionone/animation": "^10.12.0",
|
||||
"@motionone/generators": "^10.12.0",
|
||||
"@motionone/types": "^10.12.0",
|
||||
"@motionone/utils": "^10.12.0",
|
||||
"hey-listen": "^1.0.8",
|
||||
"tslib": "^2.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@motionone/easing": {
|
||||
"version": "10.15.1",
|
||||
"resolved": "https://registry.npmjs.org/@motionone/easing/-/easing-10.15.1.tgz",
|
||||
"integrity": "sha512-6hIHBSV+ZVehf9dcKZLT7p5PEKHGhDwky2k8RKkmOvUoYP3S+dXsKupyZpqx5apjd9f+php4vXk4LuS+ADsrWw==",
|
||||
"dependencies": {
|
||||
"@motionone/utils": "^10.15.1",
|
||||
"tslib": "^2.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@motionone/generators": {
|
||||
"version": "10.15.1",
|
||||
"resolved": "https://registry.npmjs.org/@motionone/generators/-/generators-10.15.1.tgz",
|
||||
"integrity": "sha512-67HLsvHJbw6cIbLA/o+gsm7h+6D4Sn7AUrB/GPxvujse1cGZ38F5H7DzoH7PhX+sjvtDnt2IhFYF2Zp1QTMKWQ==",
|
||||
"dependencies": {
|
||||
"@motionone/types": "^10.15.1",
|
||||
"@motionone/utils": "^10.15.1",
|
||||
"tslib": "^2.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@motionone/types": {
|
||||
"version": "10.15.1",
|
||||
"resolved": "https://registry.npmjs.org/@motionone/types/-/types-10.15.1.tgz",
|
||||
"integrity": "sha512-iIUd/EgUsRZGrvW0jqdst8st7zKTzS9EsKkP+6c6n4MPZoQHwiHuVtTQLD6Kp0bsBLhNzKIBlHXponn/SDT4hA=="
|
||||
},
|
||||
"node_modules/@motionone/utils": {
|
||||
"version": "10.15.1",
|
||||
"resolved": "https://registry.npmjs.org/@motionone/utils/-/utils-10.15.1.tgz",
|
||||
"integrity": "sha512-p0YncgU+iklvYr/Dq4NobTRdAPv9PveRDUXabPEeOjBLSO/1FNB2phNTZxOxpi1/GZwYpAoECEa0Wam+nsmhSw==",
|
||||
"dependencies": {
|
||||
"@motionone/types": "^10.15.1",
|
||||
"hey-listen": "^1.0.8",
|
||||
"tslib": "^2.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@nodelib/fs.scandir": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||
|
@ -3653,6 +3734,17 @@
|
|||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-native-async-storage/async-storage": {
|
||||
"version": "1.17.11",
|
||||
"resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-1.17.11.tgz",
|
||||
"integrity": "sha512-bzs45n5HNcDq6mxXnSsOHysZWn1SbbebNxldBXCQs8dSvF8Aor9KCdpm+TpnnGweK3R6diqsT8lFhX77VX0NFw==",
|
||||
"dependencies": {
|
||||
"merge-options": "^3.0.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react-native": "^0.0.0-0 || 0.60 - 0.71 || 1000.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-native-community/cli": {
|
||||
"version": "10.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-10.2.2.tgz",
|
||||
|
@ -4930,7 +5022,6 @@
|
|||
"version": "6.4.9",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-6.4.9.tgz",
|
||||
"integrity": "sha512-G9GH7bP9x0qqupxZnkSftnkn4JoXancElTvFc8FVGfEvxnxP+gBo3wqcknyBi7M5Vad4qecsYjCOa9wqsftv9g==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@react-navigation/routers": "^6.1.9",
|
||||
"escape-string-regexp": "^4.0.0",
|
||||
|
@ -4947,7 +5038,6 @@
|
|||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
||||
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
|
@ -4958,8 +5048,7 @@
|
|||
"node_modules/@react-navigation/core/node_modules/react-is": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
||||
"peer": true
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||
},
|
||||
"node_modules/@react-navigation/drawer": {
|
||||
"version": "6.6.3",
|
||||
|
@ -4995,7 +5084,6 @@
|
|||
"version": "6.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-6.1.7.tgz",
|
||||
"integrity": "sha512-W6E3+AtTombMucCRo6q7vPmluq8hSjS+IxfazJ/SokOe7ChJX7eLvvralIsJkjFj3iWV1KgOSnHxa6hdiFasBw==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@react-navigation/core": "^6.4.9",
|
||||
"escape-string-regexp": "^4.0.0",
|
||||
|
@ -5027,7 +5115,6 @@
|
|||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
||||
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
|
@ -5039,11 +5126,33 @@
|
|||
"version": "6.1.9",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/routers/-/routers-6.1.9.tgz",
|
||||
"integrity": "sha512-lTM8gSFHSfkJvQkxacGM6VJtBt61ip2XO54aNfswD+KMw6eeZ4oehl7m0me3CR9hnDE4+60iAZR8sAhvCiI3NA==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"nanoid": "^3.1.23"
|
||||
}
|
||||
},
|
||||
"node_modules/@reduxjs/toolkit": {
|
||||
"version": "1.9.5",
|
||||
"resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.5.tgz",
|
||||
"integrity": "sha512-Rt97jHmfTeaxL4swLRNPD/zV4OxTes4la07Xc4hetpUW/vc75t5m1ANyxG6ymnEQ2FsLQsoMlYB2vV1sO3m8tQ==",
|
||||
"dependencies": {
|
||||
"immer": "^9.0.21",
|
||||
"redux": "^4.2.1",
|
||||
"redux-thunk": "^2.4.2",
|
||||
"reselect": "^4.1.8"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.9.0 || ^17.0.0 || ^18",
|
||||
"react-redux": "^7.2.1 || ^8.0.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"react": {
|
||||
"optional": true
|
||||
},
|
||||
"react-redux": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@segment/loosely-validate-event": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@segment/loosely-validate-event/-/loosely-validate-event-2.0.0.tgz",
|
||||
|
@ -5097,6 +5206,15 @@
|
|||
"resolved": "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.41.tgz",
|
||||
"integrity": "sha512-ewXv/ceBaJprikMcxCmWU1FKyMAQ2X7a9Gtmzw8fcg2kIePI1crERDM818W+XYrxqdBBOdlf2rm137bU+BltCA=="
|
||||
},
|
||||
"node_modules/@types/hoist-non-react-statics": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz",
|
||||
"integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==",
|
||||
"dependencies": {
|
||||
"@types/react": "*",
|
||||
"hoist-non-react-statics": "^3.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/istanbul-lib-coverage": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz",
|
||||
|
@ -5126,14 +5244,17 @@
|
|||
"node_modules/@types/prop-types": {
|
||||
"version": "15.7.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz",
|
||||
"integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==",
|
||||
"dev": true
|
||||
"integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w=="
|
||||
},
|
||||
"node_modules/@types/qs": {
|
||||
"version": "6.9.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
|
||||
"integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw=="
|
||||
},
|
||||
"node_modules/@types/react": {
|
||||
"version": "18.0.38",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.38.tgz",
|
||||
"integrity": "sha512-ExsidLLSzYj4cvaQjGnQCk4HFfVT9+EZ9XZsQ8Hsrcn8QNgXtpZ3m9vSIC2MWtx7jHictK6wYhQgGh6ic58oOw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/prop-types": "*",
|
||||
"@types/scheduler": "*",
|
||||
|
@ -5143,14 +5264,18 @@
|
|||
"node_modules/@types/scheduler": {
|
||||
"version": "0.16.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz",
|
||||
"integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ=="
|
||||
},
|
||||
"node_modules/@types/stack-utils": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz",
|
||||
"integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw=="
|
||||
},
|
||||
"node_modules/@types/use-sync-external-store": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz",
|
||||
"integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA=="
|
||||
},
|
||||
"node_modules/@types/yargs": {
|
||||
"version": "15.0.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.15.tgz",
|
||||
|
@ -5446,6 +5571,29 @@
|
|||
"node": ">= 4.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz",
|
||||
"integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.0",
|
||||
"form-data": "^4.0.0",
|
||||
"proxy-from-env": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/axios/node_modules/form-data": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
||||
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
|
||||
"dependencies": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"mime-types": "^2.1.12"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/babel-core": {
|
||||
"version": "7.0.0-bridge.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz",
|
||||
|
@ -6592,8 +6740,7 @@
|
|||
"node_modules/csstype": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz",
|
||||
"integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ=="
|
||||
},
|
||||
"node_modules/dag-map": {
|
||||
"version": "1.0.2",
|
||||
|
@ -7235,6 +7382,18 @@
|
|||
"expo": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/expo-linking": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/expo-linking/-/expo-linking-4.0.1.tgz",
|
||||
"integrity": "sha512-geRMmKLhtaCigptRzOGW8ZZJKGl47gyu0KFtQOtGf26ELxyt/AietgQjyzF24i7cVD08TnWUJDHgWZkpRHTa7g==",
|
||||
"dependencies": {
|
||||
"@types/qs": "^6.9.7",
|
||||
"expo-constants": "~14.2.0",
|
||||
"invariant": "^2.2.4",
|
||||
"qs": "^6.11.0",
|
||||
"url-parse": "^1.5.9"
|
||||
}
|
||||
},
|
||||
"node_modules/expo-modules-autolinking": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/expo-modules-autolinking/-/expo-modules-autolinking-1.2.0.tgz",
|
||||
|
@ -7424,8 +7583,7 @@
|
|||
"node_modules/fast-deep-equal": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
|
||||
"peer": true
|
||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
|
||||
},
|
||||
"node_modules/fast-glob": {
|
||||
"version": "3.3.0",
|
||||
|
@ -7526,7 +7684,6 @@
|
|||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz",
|
||||
"integrity": "sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
|
@ -7644,6 +7801,25 @@
|
|||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.15.2",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
|
||||
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||
}
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"debug": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/fontfaceobserver": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/fontfaceobserver/-/fontfaceobserver-2.3.0.tgz",
|
||||
|
@ -7681,6 +7857,34 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/framer-motion": {
|
||||
"version": "6.5.1",
|
||||
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-6.5.1.tgz",
|
||||
"integrity": "sha512-o1BGqqposwi7cgDrtg0dNONhkmPsUFDaLcKXigzuTFC5x58mE8iyTazxSudFzmT6MEyJKfjjU8ItoMe3W+3fiw==",
|
||||
"dependencies": {
|
||||
"@motionone/dom": "10.12.0",
|
||||
"framesync": "6.0.1",
|
||||
"hey-listen": "^1.0.8",
|
||||
"popmotion": "11.0.3",
|
||||
"style-value-types": "5.0.0",
|
||||
"tslib": "^2.1.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@emotion/is-prop-valid": "^0.8.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8 || ^17.0.0 || ^18.0.0",
|
||||
"react-dom": ">=16.8 || ^17.0.0 || ^18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/framesync": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/framesync/-/framesync-6.0.1.tgz",
|
||||
"integrity": "sha512-fUY88kXvGiIItgNC7wcTOl0SNRCVXMKSWW2Yzfmn7EKNc+MpCzcz9DhdHcdjbrtN3c6R4H5dTY2jiCpPdysEjA==",
|
||||
"dependencies": {
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/freeport-async": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/freeport-async/-/freeport-async-2.0.0.tgz",
|
||||
|
@ -8016,6 +8220,11 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/hey-listen": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/hey-listen/-/hey-listen-1.0.8.tgz",
|
||||
"integrity": "sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q=="
|
||||
},
|
||||
"node_modules/hoist-non-react-statics": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
|
||||
|
@ -8140,6 +8349,15 @@
|
|||
"node": ">=4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/immer": {
|
||||
"version": "9.0.21",
|
||||
"resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz",
|
||||
"integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/immer"
|
||||
}
|
||||
},
|
||||
"node_modules/import-fresh": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz",
|
||||
|
@ -8419,6 +8637,14 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/is-plain-obj": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
|
||||
"integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/is-plain-object": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
|
||||
|
@ -9649,6 +9875,17 @@
|
|||
"resolved": "https://registry.npmjs.org/memory-cache/-/memory-cache-0.2.0.tgz",
|
||||
"integrity": "sha512-OcjA+jzjOYzKmKS6IQVALHLVz+rNTMPoJvCztFaZxwG14wtAW7VRZjwTQu06vKCYOxh4jVnik7ya0SXTB0W+xA=="
|
||||
},
|
||||
"node_modules/merge-options": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/merge-options/-/merge-options-3.0.4.tgz",
|
||||
"integrity": "sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ==",
|
||||
"dependencies": {
|
||||
"is-plain-obj": "^2.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/merge-stream": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
|
||||
|
@ -10751,6 +10988,17 @@
|
|||
"mkdirp": "bin/cmd.js"
|
||||
}
|
||||
},
|
||||
"node_modules/moti": {
|
||||
"version": "0.25.3",
|
||||
"resolved": "https://registry.npmjs.org/moti/-/moti-0.25.3.tgz",
|
||||
"integrity": "sha512-n6YR56i+tQdIuiOfspeCCvNR8vAJtPdfclt4998rX6S6kQn+/5DmfBWkOneN63JFTWM/oYnZHwwpF4z4LUXohQ==",
|
||||
"dependencies": {
|
||||
"framer-motion": "^6.5.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react-native-reanimated": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
|
@ -10818,7 +11066,6 @@
|
|||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"nanoid": "bin/nanoid.cjs"
|
||||
},
|
||||
|
@ -11543,6 +11790,17 @@
|
|||
"node": ">=4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/popmotion": {
|
||||
"version": "11.0.3",
|
||||
"resolved": "https://registry.npmjs.org/popmotion/-/popmotion-11.0.3.tgz",
|
||||
"integrity": "sha512-Y55FLdj3UxkR7Vl3s7Qr4e9m0onSnP8W7d/xQLsoJM40vs6UKHFdygs6SWryasTZYqugMjm3BepCF4CWXDiHgA==",
|
||||
"dependencies": {
|
||||
"framesync": "6.0.1",
|
||||
"hey-listen": "^1.0.8",
|
||||
"style-value-types": "5.0.0",
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/posix-character-classes": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
|
||||
|
@ -11659,6 +11917,11 @@
|
|||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||
},
|
||||
"node_modules/proxy-from-env": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
|
||||
},
|
||||
"node_modules/pump": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
|
||||
|
@ -11694,7 +11957,6 @@
|
|||
"version": "7.1.3",
|
||||
"resolved": "https://registry.npmjs.org/query-string/-/query-string-7.1.3.tgz",
|
||||
"integrity": "sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"decode-uri-component": "^0.2.2",
|
||||
"filter-obj": "^1.1.0",
|
||||
|
@ -11808,6 +12070,19 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/react-dom": {
|
||||
"version": "18.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
|
||||
"integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"scheduler": "^0.23.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^18.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-freeze": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/react-freeze/-/react-freeze-1.0.3.tgz",
|
||||
|
@ -11976,6 +12251,49 @@
|
|||
"async-limiter": "~1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-redux": {
|
||||
"version": "8.1.1",
|
||||
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.1.1.tgz",
|
||||
"integrity": "sha512-5W0QaKtEhj+3bC0Nj0NkqkhIv8gLADH/2kYFMTHxCVqQILiWzLv6MaLuV5wJU3BQEdHKzTfcvPN0WMS6SC1oyA==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.1",
|
||||
"@types/hoist-non-react-statics": "^3.3.1",
|
||||
"@types/use-sync-external-store": "^0.0.3",
|
||||
"hoist-non-react-statics": "^3.3.2",
|
||||
"react-is": "^18.0.0",
|
||||
"use-sync-external-store": "^1.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "^16.8 || ^17.0 || ^18.0",
|
||||
"@types/react-dom": "^16.8 || ^17.0 || ^18.0",
|
||||
"react": "^16.8 || ^17.0 || ^18.0",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0",
|
||||
"react-native": ">=0.59",
|
||||
"redux": "^4 || ^5.0.0-beta.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
},
|
||||
"react-dom": {
|
||||
"optional": true
|
||||
},
|
||||
"react-native": {
|
||||
"optional": true
|
||||
},
|
||||
"redux": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/react-redux/node_modules/react-is": {
|
||||
"version": "18.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
|
||||
"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
|
||||
},
|
||||
"node_modules/react-refresh": {
|
||||
"version": "0.4.3",
|
||||
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.4.3.tgz",
|
||||
|
@ -12037,6 +12355,22 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/redux": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz",
|
||||
"integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.9.2"
|
||||
}
|
||||
},
|
||||
"node_modules/redux-thunk": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz",
|
||||
"integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==",
|
||||
"peerDependencies": {
|
||||
"redux": "^4"
|
||||
}
|
||||
},
|
||||
"node_modules/regenerate": {
|
||||
"version": "1.4.2",
|
||||
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
|
||||
|
@ -12822,7 +13156,6 @@
|
|||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz",
|
||||
"integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
|
@ -13005,7 +13338,6 @@
|
|||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz",
|
||||
"integrity": "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
|
@ -13100,6 +13432,15 @@
|
|||
"resolved": "https://registry.npmjs.org/structured-headers/-/structured-headers-0.4.1.tgz",
|
||||
"integrity": "sha512-0MP/Cxx5SzeeZ10p/bZI0S6MpgD+yxAhi1BOQ34jgnMXsCq3j1t6tQnZu+KdlL7dvJTLT3g9xN8tl10TqgFMcg=="
|
||||
},
|
||||
"node_modules/style-value-types": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/style-value-types/-/style-value-types-5.0.0.tgz",
|
||||
"integrity": "sha512-08yq36Ikn4kx4YU6RD7jWEv27v4V+PUsOGa4n/as8Et3CuODMJQ00ENeAVXAeydX4Z2j1XHZF1K2sX4mGl18fA==",
|
||||
"dependencies": {
|
||||
"hey-listen": "^1.0.8",
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/sucrase": {
|
||||
"version": "3.32.0",
|
||||
"resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.32.0.tgz",
|
||||
|
@ -13799,7 +14140,6 @@
|
|||
"version": "0.1.6",
|
||||
"resolved": "https://registry.npmjs.org/use-latest-callback/-/use-latest-callback-0.1.6.tgz",
|
||||
"integrity": "sha512-VO/P91A/PmKH9bcN9a7O3duSuxe6M14ZoYXgA6a8dab8doWNdhiIHzEkX/jFeTTRBsX0Ubk6nG4q2NIjNsj+bg==",
|
||||
"peer": true,
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8"
|
||||
}
|
||||
|
|
10
package.json
10
package.json
|
@ -9,17 +9,25 @@
|
|||
"web": "expo start --web"
|
||||
},
|
||||
"dependencies": {
|
||||
"@react-native-async-storage/async-storage": "1.17.11",
|
||||
"@react-navigation/drawer": "^6.6.3",
|
||||
"@react-navigation/native": "^6.1.7",
|
||||
"@react-navigation/native-stack": "^6.9.13",
|
||||
"@reduxjs/toolkit": "^1.9.5",
|
||||
"axios": "^1.4.0",
|
||||
"expo": "~48.0.18",
|
||||
"expo-status-bar": "~1.4.4",
|
||||
"moti": "^0.25.3",
|
||||
"react": "18.2.0",
|
||||
"react-native": "0.71.8",
|
||||
"react-native-gesture-handler": "~2.9.0",
|
||||
"react-native-reanimated": "~2.14.4",
|
||||
"react-native-safe-area-context": "4.5.0",
|
||||
"react-native-screens": "~3.20.0",
|
||||
"react-native-svg": "13.4.0"
|
||||
"react-native-svg": "13.4.0",
|
||||
"react-redux": "^8.1.1",
|
||||
"redux": "^4.2.1",
|
||||
"expo-linking": "~4.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.20.0",
|
||||
|
|
21
src/components/AnimatedContainer/AnimatedContainer.tsx
Normal file
21
src/components/AnimatedContainer/AnimatedContainer.tsx
Normal file
|
@ -0,0 +1,21 @@
|
|||
import * as React from "react";
|
||||
import { View, Text } from "react-native";
|
||||
import styles from "../../styles";
|
||||
import { colors } from "../../styles";
|
||||
import { MotiView } from "moti";
|
||||
export interface props {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export default function AnimatedContainer(props: props) {
|
||||
return (
|
||||
<MotiView
|
||||
style={styles.container}
|
||||
from={{ opacity: 0, backgroundColor: colors.orange_1 }}
|
||||
animate={{ opacity: 1, backgroundColor: colors.blue_2 }}
|
||||
transition={{ type: "timing", duration: 300 }}
|
||||
>
|
||||
{props.children}
|
||||
</MotiView>
|
||||
);
|
||||
}
|
125
src/components/Api/Api.tsx
Normal file
125
src/components/Api/Api.tsx
Normal file
|
@ -0,0 +1,125 @@
|
|||
import axios from "axios";
|
||||
import AsyncStorage from "@react-native-async-storage/async-storage";
|
||||
import {
|
||||
ActivationParams,
|
||||
LoginParams,
|
||||
RegistrationParams,
|
||||
} from "../../interfaces/Interfaces";
|
||||
|
||||
let debug = true;
|
||||
export let backendURL = "";
|
||||
if (debug) {
|
||||
backendURL = "http://10.0.10.8:8000";
|
||||
} else {
|
||||
backendURL = "https://keannu125.pythonanywhere.com";
|
||||
}
|
||||
|
||||
const instance = axios.create({
|
||||
baseURL: backendURL,
|
||||
timeout: 1000,
|
||||
});
|
||||
|
||||
// App APIs
|
||||
|
||||
// Token Handling
|
||||
export async function getAccessToken() {
|
||||
const accessToken = await AsyncStorage.getItem("access_token");
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
export async function getRefreshToken() {
|
||||
const refreshToken = await AsyncStorage.getItem("refresh_token");
|
||||
return refreshToken;
|
||||
}
|
||||
|
||||
export async function setAccessToken(access: string) {
|
||||
await AsyncStorage.setItem("access_token", access);
|
||||
return true;
|
||||
}
|
||||
|
||||
export async function setRefreshToken(refresh: string) {
|
||||
await AsyncStorage.setItem("refresh_token", refresh);
|
||||
return true;
|
||||
}
|
||||
|
||||
// User APIs
|
||||
export function UserRegister(register: RegistrationParams) {
|
||||
console.log(JSON.stringify(register));
|
||||
return instance
|
||||
.post("/api/v1/accounts/users/", register)
|
||||
.then(async (response) => {
|
||||
return [true, response.status];
|
||||
})
|
||||
.catch((error) => {
|
||||
return [false, error.response.status, error.response.data];
|
||||
});
|
||||
}
|
||||
|
||||
export function UserLogin(user: LoginParams) {
|
||||
return instance
|
||||
.post("/api/v1/accounts/jwt/create/", user)
|
||||
.then(async (response) => {
|
||||
/*console.log(
|
||||
"Access Token:",
|
||||
response.data.access,
|
||||
"\nRefresh Token:",
|
||||
response.data.refresh
|
||||
);*/
|
||||
setAccessToken(response.data.access);
|
||||
setRefreshToken(response.data.refresh);
|
||||
return [true];
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log("Login Failed:" + error.response.data);
|
||||
return [false, error.response.data];
|
||||
});
|
||||
}
|
||||
|
||||
export async function TokenRefresh() {
|
||||
const refresh = await getRefreshToken();
|
||||
// console.log("Refresh token", refresh);
|
||||
return instance
|
||||
.post("/api/v1/accounts/jwt/refresh/", {
|
||||
refresh: refresh,
|
||||
})
|
||||
.then(async (response) => {
|
||||
setAccessToken(response.data.access);
|
||||
/*console.log(
|
||||
"Token refresh success! New Access Token",
|
||||
response.data.access
|
||||
);*/
|
||||
return [true];
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log("Refresh Failed: " + JSON.stringify(error.response.data));
|
||||
return [false, error.response.data];
|
||||
});
|
||||
}
|
||||
export async function UserInfo() {
|
||||
const accessToken = await getAccessToken();
|
||||
return instance
|
||||
.get("/api/v1/accounts/users/me/", {
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
},
|
||||
})
|
||||
.then((response) => {
|
||||
// console.log(JSON.stringify(response.data));
|
||||
return response.data;
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log("User Info Error", error.response.data);
|
||||
return [false, error.response.data];
|
||||
});
|
||||
}
|
||||
|
||||
export function UserActivate(activation: ActivationParams) {
|
||||
return instance
|
||||
.post("/api/v1/accounts/users/activation/", activation)
|
||||
.then(async (response) => {
|
||||
return true;
|
||||
})
|
||||
.catch((error) => {
|
||||
return false;
|
||||
});
|
||||
}
|
23
src/components/Button/Button.tsx
Normal file
23
src/components/Button/Button.tsx
Normal file
|
@ -0,0 +1,23 @@
|
|||
import * as React from "react";
|
||||
import { Pressable, GestureResponderEvent } from "react-native";
|
||||
import styles from "../../styles";
|
||||
|
||||
export interface props {
|
||||
children: React.ReactNode;
|
||||
onPress: (event: GestureResponderEvent) => void;
|
||||
color: string;
|
||||
}
|
||||
|
||||
export default function Button(props: props) {
|
||||
return (
|
||||
<Pressable
|
||||
onPress={props.onPress}
|
||||
style={{
|
||||
...styles.button_template,
|
||||
...{ backgroundColor: props.color, width: "50%" },
|
||||
}}
|
||||
>
|
||||
{props.children}
|
||||
</Pressable>
|
||||
);
|
||||
}
|
|
@ -14,7 +14,11 @@ export default function DrawerButton(props: props) {
|
|||
onPress={props.onPress}
|
||||
style={{
|
||||
...styles.button_template,
|
||||
...{ backgroundColor: props.color, width: "95%" },
|
||||
...{
|
||||
backgroundColor: props.color,
|
||||
width: "95%",
|
||||
justifyContent: "flex-start",
|
||||
},
|
||||
}}
|
||||
>
|
||||
{props.children}
|
||||
|
|
|
@ -11,47 +11,112 @@ import HomeIcon from "../../icons/HomeIcon/HomeIcon";
|
|||
import LoginIcon from "../../icons/LoginIcon/LoginIcon";
|
||||
import SignupIcon from "../../icons/SignupIcon/SignupIcon";
|
||||
import DrawerButton from "../Button/DrawerButton";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { RootState } from "../../features/redux/Store/Store";
|
||||
import LogoutIcon from "../../icons/LogoutIcon/LogoutIcon";
|
||||
import { clear } from "../../features/redux/slices/AuthSlice/AuthSlice";
|
||||
import AsyncStorage from "@react-native-async-storage/async-storage";
|
||||
|
||||
export default function CustomDrawerContent(props: {}) {
|
||||
const navigation = useNavigation<RootDrawerParamList>();
|
||||
return (
|
||||
<DrawerContentScrollView {...props}>
|
||||
<View
|
||||
style={{
|
||||
...styles.flex_row,
|
||||
...{ justifyContent: "center" },
|
||||
}}
|
||||
>
|
||||
<AppIcon size={32} color={colors.icon_color} />
|
||||
<Text style={styles.text_white_medium}>Stud-E</Text>
|
||||
</View>
|
||||
<DrawerButton
|
||||
color={colors.blue_2}
|
||||
onPress={() => {
|
||||
navigation.navigate("Home");
|
||||
}}
|
||||
>
|
||||
<HomeIcon size={32} color={colors.icon_color} />
|
||||
<Text style={styles.text_white_medium}>Home</Text>
|
||||
</DrawerButton>
|
||||
<DrawerButton
|
||||
color={colors.blue_2}
|
||||
onPress={() => {
|
||||
navigation.navigate("Login");
|
||||
}}
|
||||
>
|
||||
<LoginIcon size={32} color={colors.icon_color} />
|
||||
<Text style={styles.text_white_medium}>Login</Text>
|
||||
</DrawerButton>
|
||||
<DrawerButton
|
||||
color={colors.blue_2}
|
||||
onPress={() => {
|
||||
navigation.navigate("Register");
|
||||
}}
|
||||
>
|
||||
<SignupIcon size={32} color={colors.icon_color} />
|
||||
<Text style={styles.text_white_medium}>Register</Text>
|
||||
</DrawerButton>
|
||||
</DrawerContentScrollView>
|
||||
const logged_in = useSelector(
|
||||
(state: RootState) => state.auth.creds.logged_in
|
||||
);
|
||||
const dispatch = useDispatch();
|
||||
if (logged_in) {
|
||||
return (
|
||||
<DrawerContentScrollView {...props}>
|
||||
<View
|
||||
style={{
|
||||
...styles.flex_row,
|
||||
...{ justifyContent: "center" },
|
||||
}}
|
||||
>
|
||||
<AppIcon size={32} />
|
||||
<Text style={styles.text_white_medium}>Stud-E</Text>
|
||||
</View>
|
||||
<DrawerButton
|
||||
color={colors.blue_2}
|
||||
onPress={() => {
|
||||
navigation.navigate("Home");
|
||||
}}
|
||||
>
|
||||
<HomeIcon size={32} />
|
||||
<Text style={styles.text_white_medium}>Home</Text>
|
||||
</DrawerButton>
|
||||
<DrawerButton
|
||||
color={colors.blue_2}
|
||||
onPress={async () => {
|
||||
dispatch(await clear());
|
||||
await AsyncStorage.clear();
|
||||
navigation.navigate("Home");
|
||||
}}
|
||||
>
|
||||
<LogoutIcon size={32} />
|
||||
<Text style={styles.text_white_medium}>Logout</Text>
|
||||
</DrawerButton>
|
||||
</DrawerContentScrollView>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<DrawerContentScrollView {...props}>
|
||||
<View
|
||||
style={{
|
||||
...styles.flex_row,
|
||||
...{ justifyContent: "center" },
|
||||
}}
|
||||
>
|
||||
<AppIcon size={32} />
|
||||
<Text style={styles.text_white_medium}>Stud-E</Text>
|
||||
</View>
|
||||
<DrawerButton
|
||||
color={colors.blue_2}
|
||||
onPress={() => {
|
||||
navigation.navigate("Home");
|
||||
}}
|
||||
>
|
||||
<HomeIcon size={32} />
|
||||
<Text style={styles.text_white_medium}>Home</Text>
|
||||
</DrawerButton>
|
||||
<DrawerButton
|
||||
color={colors.blue_2}
|
||||
onPress={() => {
|
||||
navigation.navigate("Login");
|
||||
}}
|
||||
>
|
||||
<LoginIcon size={32} />
|
||||
<Text style={styles.text_white_medium}>Login</Text>
|
||||
</DrawerButton>
|
||||
<DrawerButton
|
||||
color={colors.blue_2}
|
||||
onPress={() => {
|
||||
dispatch(clear());
|
||||
navigation.navigate("Register");
|
||||
}}
|
||||
>
|
||||
<SignupIcon size={32} />
|
||||
<Text style={styles.text_white_medium}>Register</Text>
|
||||
</DrawerButton>
|
||||
{/*
|
||||
Debug buttons for accessing revalidation and activation page
|
||||
<DrawerButton
|
||||
color={colors.blue_2}
|
||||
onPress={() => {
|
||||
navigation.navigate("Revalidation");
|
||||
}}
|
||||
>
|
||||
<Text style={styles.text_white_medium}>Revalidation</Text>
|
||||
</DrawerButton>
|
||||
<DrawerButton
|
||||
color={colors.blue_2}
|
||||
onPress={() => {
|
||||
navigation.navigate("Activation");
|
||||
}}
|
||||
>
|
||||
<Text style={styles.text_white_medium}>Activation</Text>
|
||||
</DrawerButton>
|
||||
*/}
|
||||
</DrawerContentScrollView>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ const DrawerScreenSettings: DrawerNavigationOptions = {
|
|||
<View
|
||||
style={{ flexDirection: "row", marginRight: 16, alignItems: "center" }}
|
||||
>
|
||||
<AppIcon size={32} color={colors.icon_color} />
|
||||
<AppIcon size={32} />
|
||||
</View>
|
||||
),
|
||||
};
|
||||
|
|
8
src/components/IsNumber/IsNumber.tsx
Normal file
8
src/components/IsNumber/IsNumber.tsx
Normal file
|
@ -0,0 +1,8 @@
|
|||
export default function IsNumber(number: string) {
|
||||
const re = /^[0-9\b]+$/;
|
||||
if (re.test(number)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
24
src/components/ParseError/ParseError.tsx
Normal file
24
src/components/ParseError/ParseError.tsx
Normal file
|
@ -0,0 +1,24 @@
|
|||
export default function ParseError(text: string) {
|
||||
if (text) {
|
||||
return text
|
||||
.replaceAll(/[{}()"]/g, " ")
|
||||
.replaceAll(/,/g, "\n")
|
||||
.replaceAll("[", "")
|
||||
.replaceAll("]", "")
|
||||
.replaceAll(".", "");
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
export function ParseLoginError(text: string) {
|
||||
if (text) {
|
||||
return text
|
||||
.replaceAll(/[{}()"]/g, " ")
|
||||
.replaceAll(/,/g, "\n")
|
||||
.replaceAll("[", "")
|
||||
.replaceAll("]", "")
|
||||
.replaceAll(".", "")
|
||||
.replaceAll("non_field_errors", "");
|
||||
}
|
||||
return "";
|
||||
}
|
14
src/features/redux/Store/Store.tsx
Normal file
14
src/features/redux/Store/Store.tsx
Normal file
|
@ -0,0 +1,14 @@
|
|||
import { configureStore } from "@reduxjs/toolkit";
|
||||
import AuthReducer from "../slices/AuthSlice/AuthSlice";
|
||||
|
||||
const store = configureStore({
|
||||
reducer: {
|
||||
auth: AuthReducer,
|
||||
},
|
||||
});
|
||||
|
||||
export default store;
|
||||
|
||||
// Infer the `RootState` and `AppDispatch` types from the store itself
|
||||
export type RootState = ReturnType<typeof store.getState>;
|
||||
export type AppDispatch = typeof store.dispatch;
|
42
src/features/redux/slices/AuthSlice/AuthSlice.tsx
Normal file
42
src/features/redux/slices/AuthSlice/AuthSlice.tsx
Normal file
|
@ -0,0 +1,42 @@
|
|||
import { createSlice } from "@reduxjs/toolkit";
|
||||
|
||||
export const AuthSlice = createSlice({
|
||||
name: "Auth",
|
||||
initialState: {
|
||||
creds: {
|
||||
email: "",
|
||||
uid: "",
|
||||
username: "",
|
||||
full_name: "",
|
||||
logged_in: false,
|
||||
},
|
||||
},
|
||||
reducers: {
|
||||
login: (state) => {
|
||||
state.creds.logged_in = true;
|
||||
},
|
||||
setUser: (state, action) => {
|
||||
state.creds = {
|
||||
email: action.payload.email,
|
||||
uid: action.payload.uid,
|
||||
username: action.payload.username,
|
||||
full_name: action.payload.full_name,
|
||||
logged_in: true,
|
||||
};
|
||||
},
|
||||
clear: (state) => {
|
||||
state.creds = {
|
||||
email: "",
|
||||
uid: "",
|
||||
username: "",
|
||||
full_name: "",
|
||||
logged_in: false,
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Action creators are generated for each case reducer function
|
||||
export const { login, setUser, clear } = AuthSlice.actions;
|
||||
|
||||
export default AuthSlice.reducer;
|
|
@ -2,6 +2,7 @@ import * as React from "react";
|
|||
import { IconProps } from "../../interfaces/Interfaces";
|
||||
|
||||
import { Svg, Path } from "react-native-svg";
|
||||
import { colors } from "../../styles";
|
||||
|
||||
export default function AddIcon(props: IconProps) {
|
||||
return (
|
||||
|
@ -11,7 +12,7 @@ export default function AddIcon(props: IconProps) {
|
|||
height={props.size}
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth="2"
|
||||
stroke={props.color}
|
||||
stroke={colors.icon_color}
|
||||
fill="none"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
|
|
|
@ -2,12 +2,13 @@ import * as React from "react";
|
|||
import { IconProps } from "../../interfaces/Interfaces";
|
||||
|
||||
import { Svg, Path } from "react-native-svg";
|
||||
import { colors } from "../../styles";
|
||||
|
||||
export default function AppIcon(props: IconProps) {
|
||||
return (
|
||||
<>
|
||||
<Svg
|
||||
fill={props.color}
|
||||
fill={colors.icon_color}
|
||||
height={props.size + "px"}
|
||||
width={props.size + "px"}
|
||||
viewBox="0 0 375.775 375.775"
|
||||
|
|
|
@ -2,6 +2,7 @@ import * as React from "react";
|
|||
import { IconProps } from "../../interfaces/Interfaces";
|
||||
|
||||
import { Svg, Path } from "react-native-svg";
|
||||
import { colors } from "../../styles";
|
||||
|
||||
export default function HomeIcon(props: IconProps) {
|
||||
return (
|
||||
|
@ -11,7 +12,7 @@ export default function HomeIcon(props: IconProps) {
|
|||
height={props.size}
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth="2"
|
||||
stroke={props.color}
|
||||
stroke={colors.icon_color}
|
||||
fill="none"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
|
|
|
@ -2,6 +2,7 @@ import * as React from "react";
|
|||
import { IconProps } from "../../interfaces/Interfaces";
|
||||
|
||||
import { Svg, Path } from "react-native-svg";
|
||||
import { colors } from "../../styles";
|
||||
|
||||
export default function LoginIcon(props: IconProps) {
|
||||
return (
|
||||
|
@ -11,7 +12,7 @@ export default function LoginIcon(props: IconProps) {
|
|||
height={props.size}
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth="2"
|
||||
stroke={props.color}
|
||||
stroke={colors.icon_color}
|
||||
fill="none"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
|
|
|
@ -2,6 +2,7 @@ import * as React from "react";
|
|||
import { IconProps } from "../../interfaces/Interfaces";
|
||||
|
||||
import { Svg, Path } from "react-native-svg";
|
||||
import { colors } from "../../styles";
|
||||
|
||||
export default function LogoutIcon(props: IconProps) {
|
||||
return (
|
||||
|
@ -11,7 +12,7 @@ export default function LogoutIcon(props: IconProps) {
|
|||
height={props.size}
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth="2"
|
||||
stroke={props.color}
|
||||
stroke={colors.icon_color}
|
||||
fill="none"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
|
|
|
@ -2,6 +2,7 @@ import * as React from "react";
|
|||
import { IconProps } from "../../interfaces/Interfaces";
|
||||
|
||||
import { Svg, Path } from "react-native-svg";
|
||||
import { colors } from "../../styles";
|
||||
|
||||
export default function SignupIcon(props: IconProps) {
|
||||
return (
|
||||
|
@ -11,7 +12,7 @@ export default function SignupIcon(props: IconProps) {
|
|||
height={props.size}
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth="2"
|
||||
stroke={props.color}
|
||||
stroke={colors.icon_color}
|
||||
fill="none"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
|
|
|
@ -2,6 +2,7 @@ import * as React from "react";
|
|||
import { IconProps } from "../../interfaces/Interfaces";
|
||||
|
||||
import { Svg, Path } from "react-native-svg";
|
||||
import { colors } from "../../styles";
|
||||
|
||||
export default function UserIcon(props: IconProps) {
|
||||
return (
|
||||
|
@ -11,7 +12,7 @@ export default function UserIcon(props: IconProps) {
|
|||
height={props.size}
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth="2"
|
||||
stroke={props.color}
|
||||
stroke={colors.icon_color}
|
||||
fill="none"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
export interface IconProps {
|
||||
size: number;
|
||||
}
|
||||
|
||||
export interface ResponsiveIconProps {
|
||||
size: number;
|
||||
color: string;
|
||||
}
|
||||
|
||||
|
@ -28,6 +32,9 @@ export interface RegistrationParams {
|
|||
email: string;
|
||||
username: string;
|
||||
password: string;
|
||||
first_name: string;
|
||||
last_name: string;
|
||||
student_id_number: string;
|
||||
}
|
||||
|
||||
export interface LoginParams {
|
||||
|
|
71
src/routes/Activation/Activation.tsx
Normal file
71
src/routes/Activation/Activation.tsx
Normal file
|
@ -0,0 +1,71 @@
|
|||
import * as React from "react";
|
||||
import styles, { colors } from "../../styles";
|
||||
import { View, Text, ActivityIndicator } from "react-native";
|
||||
import AnimatedContainer from "../../components/AnimatedContainer/AnimatedContainer";
|
||||
import { useNavigation, useRoute } from "@react-navigation/native";
|
||||
import { useEffect, useState } from "react";
|
||||
import { UserActivate } from "../../components/Api/Api";
|
||||
import { RootDrawerParamList } from "../../interfaces/Interfaces";
|
||||
|
||||
interface ActivationRouteParams {
|
||||
uid?: string;
|
||||
token?: string;
|
||||
}
|
||||
|
||||
export default function Activation() {
|
||||
const route = useRoute();
|
||||
const { uid, token } = (route.params as ActivationRouteParams) || "";
|
||||
const navigation = useNavigation<RootDrawerParamList>();
|
||||
const [state, setState] = useState(
|
||||
"Activating with UID " + uid + " and Token " + token
|
||||
);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
async function activate() {
|
||||
let result = await UserActivate({
|
||||
uid: String(uid),
|
||||
token: String(token),
|
||||
});
|
||||
if (result) {
|
||||
setTimeout(() => {
|
||||
setState("Activation successful!");
|
||||
}, 1000);
|
||||
setTimeout(() => {
|
||||
navigation.navigate("Login");
|
||||
}, 2000);
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
setState("Activation unsuccessful\nPlease contact support");
|
||||
}, 1000);
|
||||
}
|
||||
setLoading(false);
|
||||
}
|
||||
activate();
|
||||
}, [uid, token]);
|
||||
|
||||
return (
|
||||
<View style={styles.background}>
|
||||
<AnimatedContainer>
|
||||
<View
|
||||
style={{
|
||||
paddingVertical: 4,
|
||||
marginBottom: 16,
|
||||
borderRadius: 4,
|
||||
width: "90%",
|
||||
backgroundColor: colors.blue_1,
|
||||
}}
|
||||
/>
|
||||
<Text style={styles.text_white_large}>Activation</Text>
|
||||
<View style={{ paddingVertical: 8 }} />
|
||||
<ActivityIndicator
|
||||
animating={loading}
|
||||
size={96}
|
||||
color={colors.blue_1}
|
||||
/>
|
||||
<Text style={styles.text_white_medium}>{state}</Text>
|
||||
<Text style={styles.text_white_tiny}>{uid + "\n" + token}</Text>
|
||||
</AnimatedContainer>
|
||||
</View>
|
||||
);
|
||||
}
|
|
@ -1,20 +1,18 @@
|
|||
import * as React from "react";
|
||||
import styles from "../../styles";
|
||||
import { font_sizes } from "../../styles";
|
||||
import { View, Text } from "react-native";
|
||||
import { useSelector } from "react-redux";
|
||||
import { RootState } from "../../features/redux/Store/Store";
|
||||
import AnimatedContainer from "../../components/AnimatedContainer/AnimatedContainer";
|
||||
|
||||
export default function Home() {
|
||||
const creds = useSelector((state: RootState) => state.auth.creds);
|
||||
return (
|
||||
<View style={styles.background}>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: font_sizes.large,
|
||||
color: "white",
|
||||
textAlign: "center",
|
||||
}}
|
||||
>
|
||||
Template Homepage
|
||||
</Text>
|
||||
<AnimatedContainer>
|
||||
<Text style={styles.text_white_large}>Template Homepage</Text>
|
||||
<Text style={styles.text_white_tiny}>{JSON.stringify(creds)}</Text>
|
||||
</AnimatedContainer>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,20 +1,105 @@
|
|||
import * as React from "react";
|
||||
import styles from "../../styles";
|
||||
import { font_sizes } from "../../styles";
|
||||
import { View, Text } from "react-native";
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
TextInput,
|
||||
NativeSyntheticEvent,
|
||||
TextInputChangeEventData,
|
||||
} from "react-native";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { colors } from "../../styles";
|
||||
import { useState } from "react";
|
||||
import LoginIcon from "../../icons/LoginIcon/LoginIcon";
|
||||
import Button from "../../components/Button/Button";
|
||||
import { useNavigation } from "@react-navigation/native";
|
||||
import { RootDrawerParamList } from "../../interfaces/Interfaces";
|
||||
import { UserLogin } from "../../components/Api/Api";
|
||||
import { ParseLoginError } from "../../components/ParseError/ParseError";
|
||||
import AnimatedContainer from "../../components/AnimatedContainer/AnimatedContainer";
|
||||
|
||||
export default function Login() {
|
||||
const navigation = useNavigation<RootDrawerParamList>();
|
||||
const dispatch = useDispatch();
|
||||
const [user, setUser] = useState({
|
||||
username: "",
|
||||
password: "",
|
||||
error: "",
|
||||
});
|
||||
return (
|
||||
<View style={styles.background}>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: font_sizes.large,
|
||||
color: "white",
|
||||
textAlign: "center",
|
||||
}}
|
||||
>
|
||||
Template Login Page
|
||||
</Text>
|
||||
<AnimatedContainer>
|
||||
<View
|
||||
style={{
|
||||
paddingVertical: 4,
|
||||
marginBottom: 16,
|
||||
borderRadius: 4,
|
||||
width: "90%",
|
||||
backgroundColor: colors.blue_1,
|
||||
}}
|
||||
/>
|
||||
<View style={styles.flex_row}>
|
||||
<LoginIcon size={32} />
|
||||
<Text style={styles.text_white_large}>Student Login</Text>
|
||||
</View>
|
||||
|
||||
<View style={{ paddingVertical: 8 }} />
|
||||
<TextInput
|
||||
style={styles.text_input}
|
||||
placeholder="Username"
|
||||
placeholderTextColor="white"
|
||||
autoCapitalize="none"
|
||||
value={user.username}
|
||||
onChange={(
|
||||
e: NativeSyntheticEvent<TextInputChangeEventData>
|
||||
): void => {
|
||||
setUser({ ...user, username: e.nativeEvent.text });
|
||||
}}
|
||||
/>
|
||||
<View style={{ paddingVertical: 4 }} />
|
||||
<TextInput
|
||||
style={styles.text_input}
|
||||
placeholder="Password"
|
||||
placeholderTextColor="white"
|
||||
secureTextEntry={true}
|
||||
value={user.password}
|
||||
onChange={(
|
||||
e: NativeSyntheticEvent<TextInputChangeEventData>
|
||||
): void => {
|
||||
setUser({ ...user, password: e.nativeEvent.text });
|
||||
}}
|
||||
/>
|
||||
<View style={{ paddingVertical: 2 }} />
|
||||
<Text style={styles.text_white_small}>{user.error}</Text>
|
||||
<View style={{ paddingVertical: 4 }} />
|
||||
<Button
|
||||
onPress={async () => {
|
||||
await UserLogin({
|
||||
username: user.username,
|
||||
password: user.password,
|
||||
}).then((result) => {
|
||||
if (result[0]) {
|
||||
setUser({ ...user, username: "", password: "", error: "" });
|
||||
navigation.navigate("Onboarding");
|
||||
} else {
|
||||
setUser({
|
||||
...user,
|
||||
error: ParseLoginError(JSON.stringify(result[1])),
|
||||
});
|
||||
}
|
||||
});
|
||||
}}
|
||||
color={colors.blue_3}
|
||||
>
|
||||
<Text style={styles.text_white_small}>Login</Text>
|
||||
</Button>
|
||||
<Button
|
||||
onPress={() => navigation.navigate("Register")}
|
||||
color={colors.blue_3}
|
||||
>
|
||||
<Text style={styles.text_white_small}>Register</Text>
|
||||
</Button>
|
||||
</AnimatedContainer>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
|
17
src/routes/Onboarding/Onboarding.tsx
Normal file
17
src/routes/Onboarding/Onboarding.tsx
Normal file
|
@ -0,0 +1,17 @@
|
|||
import * as React from "react";
|
||||
import styles from "../../styles";
|
||||
import { View, Text } from "react-native";
|
||||
import { useNavigation } from "@react-navigation/native";
|
||||
import { RootDrawerParamList } from "../../interfaces/Interfaces";
|
||||
export default function Onboarding() {
|
||||
const navigation = useNavigation<RootDrawerParamList>();
|
||||
// const dispatch = useDispatch();
|
||||
// const creds = useSelector((state: RootState) => state.auth.creds);
|
||||
return (
|
||||
<View style={styles.background}>
|
||||
<View style={styles.container}>
|
||||
<Text style={styles.text_white_medium}>Template Onboarding Page</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
|
@ -1,20 +1,176 @@
|
|||
import * as React from "react";
|
||||
import styles from "../../styles";
|
||||
import { font_sizes } from "../../styles";
|
||||
import { View, Text } from "react-native";
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
TextInput,
|
||||
NativeSyntheticEvent,
|
||||
TextInputChangeEventData,
|
||||
} from "react-native";
|
||||
import { colors } from "../../styles";
|
||||
import { useState } from "react";
|
||||
import Button from "../../components/Button/Button";
|
||||
import { useNavigation } from "@react-navigation/native";
|
||||
import { RootDrawerParamList } from "../../interfaces/Interfaces";
|
||||
import SignupIcon from "../../icons/SignupIcon/SignupIcon";
|
||||
import { UserRegister } from "../../components/Api/Api";
|
||||
import IsNumber from "../../components/IsNumber/IsNumber";
|
||||
import ParseError from "../../components/ParseError/ParseError";
|
||||
import AnimatedContainer from "../../components/AnimatedContainer/AnimatedContainer";
|
||||
|
||||
export default function Register() {
|
||||
const navigation = useNavigation<RootDrawerParamList>();
|
||||
// const dispatch = useDispatch();
|
||||
// const creds = useSelector((state: RootState) => state.auth.creds);
|
||||
const [user, setUser] = useState({
|
||||
first_name: "",
|
||||
last_name: "",
|
||||
student_id_number: "",
|
||||
username: "",
|
||||
email: "",
|
||||
password: "",
|
||||
feedback: "",
|
||||
});
|
||||
return (
|
||||
<View style={styles.background}>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: font_sizes.large,
|
||||
color: "white",
|
||||
textAlign: "center",
|
||||
}}
|
||||
>
|
||||
Template Register Page
|
||||
</Text>
|
||||
<AnimatedContainer>
|
||||
<View
|
||||
style={{
|
||||
paddingVertical: 4,
|
||||
marginBottom: 16,
|
||||
borderRadius: 4,
|
||||
width: "90%",
|
||||
backgroundColor: colors.blue_1,
|
||||
}}
|
||||
/>
|
||||
<View style={styles.flex_row}>
|
||||
<SignupIcon size={32} />
|
||||
<Text style={styles.text_white_large}>Student Signup</Text>
|
||||
<View style={{ paddingVertical: 8 }} />
|
||||
</View>
|
||||
<TextInput
|
||||
style={styles.text_input}
|
||||
placeholder="First Name"
|
||||
placeholderTextColor="white"
|
||||
value={user.first_name}
|
||||
onChange={(
|
||||
e: NativeSyntheticEvent<TextInputChangeEventData>
|
||||
): void => {
|
||||
setUser({ ...user, first_name: e.nativeEvent.text });
|
||||
}}
|
||||
/>
|
||||
<View style={{ paddingVertical: 4 }} />
|
||||
<TextInput
|
||||
style={styles.text_input}
|
||||
placeholder="Last Name"
|
||||
placeholderTextColor="white"
|
||||
value={user.last_name}
|
||||
onChange={(
|
||||
e: NativeSyntheticEvent<TextInputChangeEventData>
|
||||
): void => {
|
||||
setUser({ ...user, last_name: e.nativeEvent.text });
|
||||
}}
|
||||
/>
|
||||
<View style={{ paddingVertical: 4 }} />
|
||||
<TextInput
|
||||
style={styles.text_input}
|
||||
placeholder="USTP ID Number"
|
||||
placeholderTextColor="white"
|
||||
value={user.student_id_number}
|
||||
onChange={(
|
||||
e: NativeSyntheticEvent<TextInputChangeEventData>
|
||||
): void => {
|
||||
if (IsNumber(e.nativeEvent.text)) {
|
||||
setUser({ ...user, student_id_number: e.nativeEvent.text });
|
||||
} else if (!e.nativeEvent.text) {
|
||||
setUser({ ...user, student_id_number: "" });
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<View style={{ paddingVertical: 4 }} />
|
||||
<View style={{ paddingVertical: 4 }} />
|
||||
<TextInput
|
||||
style={styles.text_input}
|
||||
placeholder="Username"
|
||||
placeholderTextColor="white"
|
||||
autoCapitalize={"none"}
|
||||
value={user.username}
|
||||
onChange={(
|
||||
e: NativeSyntheticEvent<TextInputChangeEventData>
|
||||
): void => {
|
||||
setUser({ ...user, username: e.nativeEvent.text });
|
||||
}}
|
||||
/>
|
||||
<View style={{ paddingVertical: 4 }} />
|
||||
<TextInput
|
||||
style={styles.text_input}
|
||||
placeholder="Email"
|
||||
placeholderTextColor="white"
|
||||
autoCapitalize={"none"}
|
||||
value={user.email}
|
||||
onChange={(
|
||||
e: NativeSyntheticEvent<TextInputChangeEventData>
|
||||
): void => {
|
||||
setUser({ ...user, email: e.nativeEvent.text });
|
||||
}}
|
||||
/>
|
||||
<View style={{ paddingVertical: 4 }} />
|
||||
<TextInput
|
||||
style={styles.text_input}
|
||||
placeholder="Password"
|
||||
placeholderTextColor="white"
|
||||
secureTextEntry={true}
|
||||
value={user.password}
|
||||
onChange={(
|
||||
e: NativeSyntheticEvent<TextInputChangeEventData>
|
||||
): void => {
|
||||
setUser({ ...user, password: e.nativeEvent.text });
|
||||
}}
|
||||
/>
|
||||
<View style={{ paddingVertical: 4 }} />
|
||||
<Text style={styles.text_white_small}>{user.feedback}</Text>
|
||||
<View style={{ paddingVertical: 4 }} />
|
||||
<Button
|
||||
onPress={async () => {
|
||||
await UserRegister({
|
||||
username: user.username,
|
||||
email: user.email,
|
||||
password: user.password,
|
||||
student_id_number: user.student_id_number,
|
||||
first_name: user.first_name,
|
||||
last_name: user.last_name,
|
||||
}).then((result) => {
|
||||
console.log(result);
|
||||
if (result[0]) {
|
||||
setUser({
|
||||
...user,
|
||||
first_name: "",
|
||||
last_name: "",
|
||||
student_id_number: "",
|
||||
username: "",
|
||||
email: "",
|
||||
password: "",
|
||||
feedback:
|
||||
"Success! An email has been sent to activate your account",
|
||||
});
|
||||
setTimeout(() => {
|
||||
navigation.navigate("Login");
|
||||
}, 10000);
|
||||
} else {
|
||||
setUser({
|
||||
...user,
|
||||
feedback: ParseError(JSON.stringify(result[2])),
|
||||
});
|
||||
}
|
||||
});
|
||||
{
|
||||
}
|
||||
}}
|
||||
color={colors.blue_3}
|
||||
>
|
||||
<Text style={styles.text_white_small}>Register</Text>
|
||||
</Button>
|
||||
</AnimatedContainer>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
|
47
src/routes/Revalidation/Revalidation.tsx
Normal file
47
src/routes/Revalidation/Revalidation.tsx
Normal file
|
@ -0,0 +1,47 @@
|
|||
import * as React from "react";
|
||||
import styles from "../../styles";
|
||||
import { View, Text, ActivityIndicator } from "react-native";
|
||||
import {
|
||||
TokenRefresh,
|
||||
UserInfo,
|
||||
setAccessToken,
|
||||
} from "../../components/Api/Api";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { colors } from "../../styles";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useNavigation } from "@react-navigation/native";
|
||||
import { RootDrawerParamList } from "../../interfaces/Interfaces";
|
||||
import { setUser } from "../../features/redux/slices/AuthSlice/AuthSlice";
|
||||
import AnimatedContainer from "../../components/AnimatedContainer/AnimatedContainer";
|
||||
|
||||
export default function Revalidation() {
|
||||
const dispatch = useDispatch();
|
||||
const navigation = useNavigation<RootDrawerParamList>();
|
||||
const [state, setState] = useState("Checking for existing session");
|
||||
useEffect(() => {
|
||||
setState("Previous session found");
|
||||
TokenRefresh().then(async (response) => {
|
||||
if (response[0]) {
|
||||
await dispatch(setUser(await UserInfo()));
|
||||
setTimeout(() => {
|
||||
navigation.navigate("Home");
|
||||
}, 700);
|
||||
} else {
|
||||
setState("Session expired");
|
||||
setTimeout(() => {
|
||||
navigation.navigate("Login");
|
||||
}, 700);
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<View style={styles.background}>
|
||||
<AnimatedContainer>
|
||||
<View style={{ paddingVertical: 8 }} />
|
||||
<ActivityIndicator size={96} color={colors.blue_1} />
|
||||
<Text style={styles.text_white_medium}>{state}</Text>
|
||||
</AnimatedContainer>
|
||||
</View>
|
||||
);
|
||||
}
|
|
@ -8,6 +8,8 @@ export const colors = {
|
|||
blue_2: "#77ACC3",
|
||||
blue_3: "#1B5D79",
|
||||
text_default: "white",
|
||||
text_error: "#e32d1e",
|
||||
text_success: "green",
|
||||
icon_color: "white",
|
||||
};
|
||||
|
||||
|
@ -25,6 +27,19 @@ const styles = StyleSheet.create({
|
|||
height: "100%",
|
||||
width: "100%",
|
||||
},
|
||||
container: {
|
||||
marginTop: "5%",
|
||||
width: "92%",
|
||||
borderRadius: 15,
|
||||
backgroundColor: colors.blue_2,
|
||||
alignItems: "center",
|
||||
alignSelf: "center",
|
||||
paddingTop: 32,
|
||||
paddingBottom: 32,
|
||||
justifyContent: "flex-start",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
},
|
||||
flex_row: {
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
|
@ -66,15 +81,23 @@ const styles = StyleSheet.create({
|
|||
textAlign: "center",
|
||||
},
|
||||
button_template: {
|
||||
justifyContent: "flex-start",
|
||||
justifyContent: "center",
|
||||
alignSelf: "center",
|
||||
alignItems: "center",
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
margin: 8,
|
||||
marginVertical: 4,
|
||||
marginHorizontal: 8,
|
||||
padding: 8,
|
||||
borderRadius: 16,
|
||||
},
|
||||
text_input: {
|
||||
color: colors.text_default,
|
||||
backgroundColor: colors.blue_1,
|
||||
width: "50%",
|
||||
padding: 10,
|
||||
borderRadius: 8,
|
||||
},
|
||||
});
|
||||
|
||||
export default styles;
|
||||
|
|
Loading…
Reference in a new issue