Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5d1d881f16 | ||
|
|
1b50bfd2ee | ||
|
|
6cbed4e8d1 | ||
|
|
76dafe9cd5 | ||
|
|
a96f1902c5 |
No files matched your search
Binary file not shown.
@@ -27,7 +27,8 @@
|
|||||||
"favicon": "./assets/favicon.png"
|
"favicon": "./assets/favicon.png"
|
||||||
},
|
},
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"expo-router"
|
"expo-router",
|
||||||
|
"expo-font"
|
||||||
],
|
],
|
||||||
"scheme": "fitai"
|
"scheme": "fitai"
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+68
-73
@@ -11,7 +11,7 @@
|
|||||||
"@clerk/clerk-expo": "^2.18.3",
|
"@clerk/clerk-expo": "^2.18.3",
|
||||||
"@expo/vector-icons": "^15.0.0",
|
"@expo/vector-icons": "^15.0.0",
|
||||||
"@hookform/resolvers": "^3.3.0",
|
"@hookform/resolvers": "^3.3.0",
|
||||||
"@react-native-picker/picker": "^2.11.4",
|
"@react-native-picker/picker": "2.11.1",
|
||||||
"@tanstack/react-query": "^5.0.0",
|
"@tanstack/react-query": "^5.0.0",
|
||||||
"ajv": "^8.12.0",
|
"ajv": "^8.12.0",
|
||||||
"ajv-keywords": "^5.1.0",
|
"ajv-keywords": "^5.1.0",
|
||||||
@@ -21,6 +21,7 @@
|
|||||||
"expo-camera": "~17.0.0",
|
"expo-camera": "~17.0.0",
|
||||||
"expo-constants": "^18.0.10",
|
"expo-constants": "^18.0.10",
|
||||||
"expo-crypto": "^15.0.7",
|
"expo-crypto": "^15.0.7",
|
||||||
|
"expo-font": "~14.0.9",
|
||||||
"expo-linking": "~8.0.0",
|
"expo-linking": "~8.0.0",
|
||||||
"expo-notifications": "~0.32.0",
|
"expo-notifications": "~0.32.0",
|
||||||
"expo-router": "~6.0.14",
|
"expo-router": "~6.0.14",
|
||||||
@@ -28,7 +29,7 @@
|
|||||||
"expo-status-bar": "^3.0.8",
|
"expo-status-bar": "^3.0.8",
|
||||||
"expo-web-browser": "^15.0.9",
|
"expo-web-browser": "^15.0.9",
|
||||||
"react": "19.1.0",
|
"react": "19.1.0",
|
||||||
"react-dom": "^19.2.0",
|
"react-dom": "19.1.0",
|
||||||
"react-hook-form": "^7.47.0",
|
"react-hook-form": "^7.47.0",
|
||||||
"react-native": "0.81.5",
|
"react-native": "0.81.5",
|
||||||
"react-native-safe-area-context": "~5.6.0",
|
"react-native-safe-area-context": "~5.6.0",
|
||||||
@@ -4029,9 +4030,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@react-native-picker/picker": {
|
"node_modules/@react-native-picker/picker": {
|
||||||
"version": "2.11.4",
|
"version": "2.11.1",
|
||||||
"resolved": "https://registry.npmjs.org/@react-native-picker/picker/-/picker-2.11.4.tgz",
|
"resolved": "https://registry.npmjs.org/@react-native-picker/picker/-/picker-2.11.1.tgz",
|
||||||
"integrity": "sha512-Kf8h1AMnBo54b1fdiVylP2P/iFcZqzpMYcglC28EEFB1DEnOjsNr6Ucqc+3R9e91vHxEDnhZFbYDmAe79P2gjA==",
|
"integrity": "sha512-ThklnkK4fV3yynnIIRBkxxjxR4IFbdMNJVF6tlLdOJ/zEFUEFUEdXY0KmH0iYzMwY8W4/InWsLiA7AkpAbnexA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"example"
|
"example"
|
||||||
@@ -6946,9 +6947,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/expo": {
|
"node_modules/expo": {
|
||||||
"version": "54.0.23",
|
"version": "54.0.25",
|
||||||
"resolved": "https://registry.npmjs.org/expo/-/expo-54.0.23.tgz",
|
"resolved": "https://registry.npmjs.org/expo/-/expo-54.0.25.tgz",
|
||||||
"integrity": "sha512-b4uQoiRwQ6nwqsT2709RS15CWYNGF3eJtyr1KyLw9WuMAK7u4jjofkhRiO0+3o1C2NbV+WooyYTOZGubQQMBaQ==",
|
"integrity": "sha512-+iSeBJfHRHzNPnHMZceEXhSGw4t5bNqFyd/5xMUoGfM+39rO7F72wxiLRpBKj0M6+0GQtMaEs+eTbcCrO7XyJQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.0",
|
"@babel/runtime": "^7.20.0",
|
||||||
@@ -6962,13 +6963,13 @@
|
|||||||
"@expo/vector-icons": "^15.0.3",
|
"@expo/vector-icons": "^15.0.3",
|
||||||
"@ungap/structured-clone": "^1.3.0",
|
"@ungap/structured-clone": "^1.3.0",
|
||||||
"babel-preset-expo": "~54.0.7",
|
"babel-preset-expo": "~54.0.7",
|
||||||
"expo-asset": "~12.0.9",
|
"expo-asset": "~12.0.10",
|
||||||
"expo-constants": "~18.0.10",
|
"expo-constants": "~18.0.10",
|
||||||
"expo-file-system": "~19.0.17",
|
"expo-file-system": "~19.0.19",
|
||||||
"expo-font": "~14.0.9",
|
"expo-font": "~14.0.9",
|
||||||
"expo-keep-awake": "~15.0.7",
|
"expo-keep-awake": "~15.0.7",
|
||||||
"expo-modules-autolinking": "3.0.21",
|
"expo-modules-autolinking": "3.0.22",
|
||||||
"expo-modules-core": "3.0.25",
|
"expo-modules-core": "3.0.26",
|
||||||
"pretty-format": "^29.7.0",
|
"pretty-format": "^29.7.0",
|
||||||
"react-refresh": "^0.14.2",
|
"react-refresh": "^0.14.2",
|
||||||
"whatwg-url-without-unicode": "8.0.0-3"
|
"whatwg-url-without-unicode": "8.0.0-3"
|
||||||
@@ -7006,17 +7007,32 @@
|
|||||||
"expo": "*"
|
"expo": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/expo-asset": {
|
||||||
|
"version": "12.0.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/expo-asset/-/expo-asset-12.0.10.tgz",
|
||||||
|
"integrity": "sha512-pZyeJkoDsALh4gpCQDzTA/UCLaPH/1rjQNGubmLn/uDM27S4iYJb/YWw4+CNZOtd5bCUOhDPg5DtGQnydNFSXg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@expo/image-utils": "^0.8.7",
|
||||||
|
"expo-constants": "~18.0.10"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"expo": "*",
|
||||||
|
"react": "*",
|
||||||
|
"react-native": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/expo-auth-session": {
|
"node_modules/expo-auth-session": {
|
||||||
"version": "7.0.8",
|
"version": "7.0.9",
|
||||||
"resolved": "https://registry.npmjs.org/expo-auth-session/-/expo-auth-session-7.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/expo-auth-session/-/expo-auth-session-7.0.9.tgz",
|
||||||
"integrity": "sha512-kpo2Jva+6uVjk6TmNqWAoqTnULXZaEVa9l4uf8JH32uDMt/iZQhM0fauy7Ww+y910Euhv5djCP7cPj8KWv6cmQ==",
|
"integrity": "sha512-mPSwaRWOJYas160lXi5P/7BkLy0xbh+er+IMmAYHqf2+iz2WWs9W/4lMAklQVJG2mCyOZi24XrkffvB2izCa1g==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"expo-application": "~7.0.7",
|
"expo-application": "~7.0.7",
|
||||||
"expo-constants": "~18.0.8",
|
"expo-constants": "~18.0.10",
|
||||||
"expo-crypto": "~15.0.7",
|
"expo-crypto": "~15.0.7",
|
||||||
"expo-linking": "~8.0.8",
|
"expo-linking": "~8.0.9",
|
||||||
"expo-web-browser": "~15.0.7",
|
"expo-web-browser": "~15.0.9",
|
||||||
"invariant": "^2.2.4"
|
"invariant": "^2.2.4"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
@@ -7070,6 +7086,16 @@
|
|||||||
"expo": "*"
|
"expo": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/expo-file-system": {
|
||||||
|
"version": "19.0.19",
|
||||||
|
"resolved": "https://registry.npmjs.org/expo-file-system/-/expo-file-system-19.0.19.tgz",
|
||||||
|
"integrity": "sha512-OrpOV4fEBFMFv+jy7PnENpPbsWoBmqWGidSwh1Ai52PLl6JIInYGfZTc6kqyPNGtFTwm7Y9mSWnE8g+dtLxu7g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"expo": "*",
|
||||||
|
"react-native": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/expo-font": {
|
"node_modules/expo-font": {
|
||||||
"version": "14.0.9",
|
"version": "14.0.9",
|
||||||
"resolved": "https://registry.npmjs.org/expo-font/-/expo-font-14.0.9.tgz",
|
"resolved": "https://registry.npmjs.org/expo-font/-/expo-font-14.0.9.tgz",
|
||||||
@@ -7085,12 +7111,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/expo-linking": {
|
"node_modules/expo-linking": {
|
||||||
"version": "8.0.8",
|
"version": "8.0.9",
|
||||||
"resolved": "https://registry.npmjs.org/expo-linking/-/expo-linking-8.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/expo-linking/-/expo-linking-8.0.9.tgz",
|
||||||
"integrity": "sha512-MyeMcbFDKhXh4sDD1EHwd0uxFQNAc6VCrwBkNvvvufUsTYFq3glTA9Y8a+x78CPpjNqwNAamu74yIaIz7IEJyg==",
|
"integrity": "sha512-a0UHhlVyfwIbn8b1PSFPoFiIDJeps2iEq109hVH3CHd0CMKuRxFfNio9Axe2BjXhiJCYWR4OV1iIyzY/GjiVkQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"expo-constants": "~18.0.8",
|
"expo-constants": "~18.0.10",
|
||||||
"invariant": "^2.2.4"
|
"invariant": "^2.2.4"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
@@ -7099,9 +7125,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/expo-modules-autolinking": {
|
"node_modules/expo-modules-autolinking": {
|
||||||
"version": "3.0.21",
|
"version": "3.0.22",
|
||||||
"resolved": "https://registry.npmjs.org/expo-modules-autolinking/-/expo-modules-autolinking-3.0.21.tgz",
|
"resolved": "https://registry.npmjs.org/expo-modules-autolinking/-/expo-modules-autolinking-3.0.22.tgz",
|
||||||
"integrity": "sha512-pOtPDLln3Ju8DW1zRW4OwZ702YqZ8g+kM/tEY1sWfv22kWUtxkvK+ytRDRpRdnKEnC28okbhWqeMnmVkSFzP6Q==",
|
"integrity": "sha512-Ej4SsZAnUUVFmbn6SoBso8K308mRKg8xgapdhP7v7IaSgfbexUoqxoiV31949HQQXuzmgvpkXCfp6Ex+mDW0EQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@expo/spawn-async": "^1.7.2",
|
"@expo/spawn-async": "^1.7.2",
|
||||||
@@ -7115,9 +7141,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/expo-modules-core": {
|
"node_modules/expo-modules-core": {
|
||||||
"version": "3.0.25",
|
"version": "3.0.26",
|
||||||
"resolved": "https://registry.npmjs.org/expo-modules-core/-/expo-modules-core-3.0.25.tgz",
|
"resolved": "https://registry.npmjs.org/expo-modules-core/-/expo-modules-core-3.0.26.tgz",
|
||||||
"integrity": "sha512-0P8PT8UV6c5/+p8zeVM/FXvBgn/ErtGcMaasqUgbzzBUg94ktbkIrij9t9reGCrir03BYt/Bcpv+EQtYC8JOug==",
|
"integrity": "sha512-WWjficXz32VmQ+xDoO+c0+jwDME0n/47wONrJkRvtm32H9W8n3MXkOMGemDl95HyPKYsaYKhjFGUOVOxIF3hcQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"invariant": "^2.2.4"
|
"invariant": "^2.2.4"
|
||||||
@@ -7128,9 +7154,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/expo-notifications": {
|
"node_modules/expo-notifications": {
|
||||||
"version": "0.32.12",
|
"version": "0.32.13",
|
||||||
"resolved": "https://registry.npmjs.org/expo-notifications/-/expo-notifications-0.32.12.tgz",
|
"resolved": "https://registry.npmjs.org/expo-notifications/-/expo-notifications-0.32.13.tgz",
|
||||||
"integrity": "sha512-FVJ5W4rOpKvmrLJ1Sd5pxiVTV4a7ApgTlKro+E5X8M2TBbXmEVOjs09klzdalXTjlzmU/Gu8aRw9xr7Ea/gZdw==",
|
"integrity": "sha512-PL0R1ulLVUgAswlXtRDKxBlcipNM3YA6+P5nB5JIhXbsjLJ7y+EKVaEhHhbaGzuK1QVsRQSJNm/4oISX+vsmFQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@expo/image-utils": "^0.8.7",
|
"@expo/image-utils": "^0.8.7",
|
||||||
@@ -7139,7 +7165,7 @@
|
|||||||
"assert": "^2.0.0",
|
"assert": "^2.0.0",
|
||||||
"badgin": "^1.1.5",
|
"badgin": "^1.1.5",
|
||||||
"expo-application": "~7.0.7",
|
"expo-application": "~7.0.7",
|
||||||
"expo-constants": "~18.0.9"
|
"expo-constants": "~18.0.10"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"expo": "*",
|
"expo": "*",
|
||||||
@@ -7148,9 +7174,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/expo-router": {
|
"node_modules/expo-router": {
|
||||||
"version": "6.0.14",
|
"version": "6.0.15",
|
||||||
"resolved": "https://registry.npmjs.org/expo-router/-/expo-router-6.0.14.tgz",
|
"resolved": "https://registry.npmjs.org/expo-router/-/expo-router-6.0.15.tgz",
|
||||||
"integrity": "sha512-vizLO4SgnMEL+PPs2dXr+etEOuksjue7yUQBCtfCEdqoDkQlB0r35zI7rS34Wt53sxKWSlM2p+038qQEpxtiFw==",
|
"integrity": "sha512-PAettvLifQzb6hibCmBqxbR9UljlH61GvDRLyarGxs/tG9OpMXCoZHZo8gGCO24K1/6cchBKBcjvQ0PRrKwPew==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@expo/metro-runtime": "^6.1.2",
|
"@expo/metro-runtime": "^6.1.2",
|
||||||
@@ -7163,7 +7189,7 @@
|
|||||||
"client-only": "^0.0.1",
|
"client-only": "^0.0.1",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"escape-string-regexp": "^4.0.0",
|
"escape-string-regexp": "^4.0.0",
|
||||||
"expo-server": "^1.0.3",
|
"expo-server": "^1.0.4",
|
||||||
"fast-deep-equal": "^3.1.3",
|
"fast-deep-equal": "^3.1.3",
|
||||||
"invariant": "^2.2.4",
|
"invariant": "^2.2.4",
|
||||||
"nanoid": "^3.3.8",
|
"nanoid": "^3.3.8",
|
||||||
@@ -7183,7 +7209,7 @@
|
|||||||
"@testing-library/react-native": ">= 12.0.0",
|
"@testing-library/react-native": ">= 12.0.0",
|
||||||
"expo": "*",
|
"expo": "*",
|
||||||
"expo-constants": "^18.0.10",
|
"expo-constants": "^18.0.10",
|
||||||
"expo-linking": "^8.0.8",
|
"expo-linking": "^8.0.9",
|
||||||
"react": "*",
|
"react": "*",
|
||||||
"react-dom": "*",
|
"react-dom": "*",
|
||||||
"react-native": "*",
|
"react-native": "*",
|
||||||
@@ -7271,31 +7297,6 @@
|
|||||||
"react-native": "*"
|
"react-native": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/expo/node_modules/expo-asset": {
|
|
||||||
"version": "12.0.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/expo-asset/-/expo-asset-12.0.9.tgz",
|
|
||||||
"integrity": "sha512-vrdRoyhGhBmd0nJcssTSk1Ypx3Mbn/eXaaBCQVkL0MJ8IOZpAObAjfD5CTy8+8RofcHEQdh3wwZVCs7crvfOeg==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@expo/image-utils": "^0.8.7",
|
|
||||||
"expo-constants": "~18.0.9"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"expo": "*",
|
|
||||||
"react": "*",
|
|
||||||
"react-native": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/expo/node_modules/expo-file-system": {
|
|
||||||
"version": "19.0.17",
|
|
||||||
"resolved": "https://registry.npmjs.org/expo-file-system/-/expo-file-system-19.0.17.tgz",
|
|
||||||
"integrity": "sha512-WwaS01SUFrxBnExn87pg0sCTJjZpf2KAOzfImG0o8yhkU7fbYpihpl/oocXBEsNbj58a8hVt1Y4CVV5c1tzu/g==",
|
|
||||||
"license": "MIT",
|
|
||||||
"peerDependencies": {
|
|
||||||
"expo": "*",
|
|
||||||
"react-native": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/expo/node_modules/expo-keep-awake": {
|
"node_modules/expo/node_modules/expo-keep-awake": {
|
||||||
"version": "15.0.7",
|
"version": "15.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/expo-keep-awake/-/expo-keep-awake-15.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/expo-keep-awake/-/expo-keep-awake-15.0.7.tgz",
|
||||||
@@ -11316,23 +11317,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-dom": {
|
"node_modules/react-dom": {
|
||||||
"version": "19.2.0",
|
"version": "19.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz",
|
||||||
"integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==",
|
"integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"scheduler": "^0.27.0"
|
"scheduler": "^0.26.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^19.2.0"
|
"react": "^19.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-dom/node_modules/scheduler": {
|
|
||||||
"version": "0.27.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
|
|
||||||
"integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==",
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/react-fast-compare": {
|
"node_modules/react-fast-compare": {
|
||||||
"version": "3.2.2",
|
"version": "3.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz",
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
"@clerk/clerk-expo": "^2.18.3",
|
"@clerk/clerk-expo": "^2.18.3",
|
||||||
"@expo/vector-icons": "^15.0.0",
|
"@expo/vector-icons": "^15.0.0",
|
||||||
"@hookform/resolvers": "^3.3.0",
|
"@hookform/resolvers": "^3.3.0",
|
||||||
"@react-native-picker/picker": "^2.11.4",
|
"@react-native-picker/picker": "2.11.1",
|
||||||
"@tanstack/react-query": "^5.0.0",
|
"@tanstack/react-query": "^5.0.0",
|
||||||
"ajv": "^8.12.0",
|
"ajv": "^8.12.0",
|
||||||
"ajv-keywords": "^5.1.0",
|
"ajv-keywords": "^5.1.0",
|
||||||
@@ -27,6 +27,7 @@
|
|||||||
"expo-camera": "~17.0.0",
|
"expo-camera": "~17.0.0",
|
||||||
"expo-constants": "^18.0.10",
|
"expo-constants": "^18.0.10",
|
||||||
"expo-crypto": "^15.0.7",
|
"expo-crypto": "^15.0.7",
|
||||||
|
"expo-font": "~14.0.9",
|
||||||
"expo-linking": "~8.0.0",
|
"expo-linking": "~8.0.0",
|
||||||
"expo-notifications": "~0.32.0",
|
"expo-notifications": "~0.32.0",
|
||||||
"expo-router": "~6.0.14",
|
"expo-router": "~6.0.14",
|
||||||
@@ -34,7 +35,7 @@
|
|||||||
"expo-status-bar": "^3.0.8",
|
"expo-status-bar": "^3.0.8",
|
||||||
"expo-web-browser": "^15.0.9",
|
"expo-web-browser": "^15.0.9",
|
||||||
"react": "19.1.0",
|
"react": "19.1.0",
|
||||||
"react-dom": "^19.2.0",
|
"react-dom": "19.1.0",
|
||||||
"react-hook-form": "^7.47.0",
|
"react-hook-form": "^7.47.0",
|
||||||
"react-native": "0.81.5",
|
"react-native": "0.81.5",
|
||||||
"react-native-safe-area-context": "~5.6.0",
|
"react-native-safe-area-context": "~5.6.0",
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
import { apiClient } from "./client";
|
||||||
|
import { API_ENDPOINTS } from "../config/api";
|
||||||
|
|
||||||
|
export interface Attendance {
|
||||||
|
id: string;
|
||||||
|
checkInTime: string;
|
||||||
|
checkOutTime?: string;
|
||||||
|
type: string;
|
||||||
|
notes?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const attendanceApi = {
|
||||||
|
getHistory: async (token: string): Promise<Attendance[]> => {
|
||||||
|
try {
|
||||||
|
const response = await apiClient.get(API_ENDPOINTS.ATTENDANCE.HISTORY, {
|
||||||
|
headers: { Authorization: `Bearer ${token}` },
|
||||||
|
});
|
||||||
|
return response.data;
|
||||||
|
} catch (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
checkIn: async (type: string, token: string): Promise<void> => {
|
||||||
|
try {
|
||||||
|
await apiClient.post(
|
||||||
|
API_ENDPOINTS.ATTENDANCE.CHECK_IN,
|
||||||
|
{ type },
|
||||||
|
{ headers: { Authorization: `Bearer ${token}` } },
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
checkOut: async (token: string): Promise<void> => {
|
||||||
|
try {
|
||||||
|
await apiClient.post(
|
||||||
|
API_ENDPOINTS.ATTENDANCE.CHECK_OUT,
|
||||||
|
{},
|
||||||
|
{ headers: { Authorization: `Bearer ${token}` } },
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import axios from 'axios';
|
||||||
|
import { API_BASE_URL } from '../config/api';
|
||||||
|
|
||||||
|
export const apiClient = axios.create({
|
||||||
|
baseURL: API_BASE_URL,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Helper to set the auth token for a request
|
||||||
|
export const setAuthToken = (token: string) => {
|
||||||
|
if (token) {
|
||||||
|
apiClient.defaults.headers.common['Authorization'] = `Bearer ${token}`;
|
||||||
|
} else {
|
||||||
|
delete apiClient.defaults.headers.common['Authorization'];
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import axios from "axios";
|
import { apiClient } from "./client";
|
||||||
import { API_BASE_URL } from "../config/api";
|
import { API_ENDPOINTS } from "../config/api";
|
||||||
|
|
||||||
export interface FitnessProfile {
|
export interface FitnessProfile {
|
||||||
id?: string;
|
id?: string;
|
||||||
@@ -22,10 +22,10 @@ export const fitnessProfileApi = {
|
|||||||
try {
|
try {
|
||||||
console.log(
|
console.log(
|
||||||
"Getting fitness profile with URL:",
|
"Getting fitness profile with URL:",
|
||||||
`${API_BASE_URL}/api/users/${userId}/fitness-profile`,
|
`${API_ENDPOINTS.USERS}/${userId}/fitness-profile`,
|
||||||
);
|
);
|
||||||
const response = await axios.get(
|
const response = await apiClient.get(
|
||||||
`${API_BASE_URL}/api/users/${userId}/fitness-profile`,
|
`${API_ENDPOINTS.USERS}/${userId}/fitness-profile`,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${token}`,
|
Authorization: `Bearer ${token}`,
|
||||||
@@ -49,8 +49,8 @@ export const fitnessProfileApi = {
|
|||||||
token: string,
|
token: string,
|
||||||
): Promise<FitnessProfile> => {
|
): Promise<FitnessProfile> => {
|
||||||
try {
|
try {
|
||||||
const response = await axios.put(
|
const response = await apiClient.put(
|
||||||
`${API_BASE_URL}/api/users/${userId}/fitness-profile`,
|
`${API_ENDPOINTS.USERS}/${userId}/fitness-profile`,
|
||||||
data,
|
data,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
@@ -74,8 +74,8 @@ export const fitnessProfileApi = {
|
|||||||
token: string,
|
token: string,
|
||||||
): Promise<FitnessProfile> => {
|
): Promise<FitnessProfile> => {
|
||||||
try {
|
try {
|
||||||
const response = await axios.post(
|
const response = await apiClient.post(
|
||||||
`${API_BASE_URL}/api/users/${data.clientId}/fitness-profile`,
|
`${API_ENDPOINTS.USERS}/${data.clientId}/fitness-profile`,
|
||||||
data,
|
data,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { apiClient } from "./client";
|
||||||
|
import { API_ENDPOINTS } from "../config/api";
|
||||||
|
|
||||||
|
export interface FitnessProfileData {
|
||||||
|
userId: string;
|
||||||
|
height: string;
|
||||||
|
weight: string;
|
||||||
|
age: string;
|
||||||
|
gender: "male" | "female" | "other";
|
||||||
|
activityLevel: "sedentary" | "light" | "moderate" | "active" | "very_active";
|
||||||
|
fitnessGoals: string[];
|
||||||
|
exerciseHabits: string;
|
||||||
|
dietHabits: string;
|
||||||
|
medicalConditions: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const profileApi = {
|
||||||
|
createFitnessProfile: async (
|
||||||
|
data: FitnessProfileData,
|
||||||
|
token: string,
|
||||||
|
): Promise<void> => {
|
||||||
|
try {
|
||||||
|
await apiClient.post(API_ENDPOINTS.PROFILE.FITNESS, data, {
|
||||||
|
headers: { Authorization: `Bearer ${token}` },
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import React from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { useSignIn, useAuth } from "@clerk/clerk-expo";
|
import { useSignIn, useAuth } from "@clerk/clerk-expo";
|
||||||
import { useRouter } from "expo-router";
|
import { useRouter } from "expo-router";
|
||||||
import {
|
import {
|
||||||
@@ -12,19 +12,20 @@ import {
|
|||||||
Platform,
|
Platform,
|
||||||
ScrollView,
|
ScrollView,
|
||||||
} from "react-native";
|
} from "react-native";
|
||||||
|
import { OAuthButtons } from "../../components/auth/OAuthButtons";
|
||||||
|
|
||||||
export default function SignInScreen() {
|
export default function SignInScreen() {
|
||||||
const { signIn, setActive, isLoaded } = useSignIn();
|
const { signIn, setActive, isLoaded } = useSignIn();
|
||||||
const { isSignedIn } = useAuth();
|
const { isSignedIn } = useAuth();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const [emailAddress, setEmailAddress] = React.useState("");
|
const [emailAddress, setEmailAddress] = useState("");
|
||||||
const [password, setPassword] = React.useState("");
|
const [password, setPassword] = useState("");
|
||||||
const [loading, setLoading] = React.useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [error, setError] = React.useState("");
|
const [error, setError] = useState("");
|
||||||
|
|
||||||
// Redirect if already signed in
|
// Redirect if already signed in
|
||||||
React.useEffect(() => {
|
useEffect(() => {
|
||||||
if (isSignedIn) {
|
if (isSignedIn) {
|
||||||
router.replace("/(tabs)");
|
router.replace("/(tabs)");
|
||||||
}
|
}
|
||||||
@@ -64,7 +65,7 @@ export default function SignInScreen() {
|
|||||||
|
|
||||||
setError(
|
setError(
|
||||||
err.errors?.[0]?.message ||
|
err.errors?.[0]?.message ||
|
||||||
"Failed to sign in. Please check your credentials.",
|
"Failed to sign in. Please check your credentials.",
|
||||||
);
|
);
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
@@ -100,6 +101,14 @@ export default function SignInScreen() {
|
|||||||
</View>
|
</View>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
|
<OAuthButtons />
|
||||||
|
|
||||||
|
<View style={styles.dividerContainer}>
|
||||||
|
<View style={styles.dividerLine} />
|
||||||
|
<Text style={styles.dividerText}>OR</Text>
|
||||||
|
<View style={styles.dividerLine} />
|
||||||
|
</View>
|
||||||
|
|
||||||
<View style={styles.form}>
|
<View style={styles.form}>
|
||||||
<View style={styles.inputContainer}>
|
<View style={styles.inputContainer}>
|
||||||
<Text style={styles.label}>Email</Text>
|
<Text style={styles.label}>Email</Text>
|
||||||
@@ -256,4 +265,19 @@ const styles = StyleSheet.create({
|
|||||||
color: "#2563eb",
|
color: "#2563eb",
|
||||||
fontWeight: "600",
|
fontWeight: "600",
|
||||||
},
|
},
|
||||||
|
dividerContainer: {
|
||||||
|
flexDirection: "row",
|
||||||
|
alignItems: "center",
|
||||||
|
marginBottom: 24,
|
||||||
|
},
|
||||||
|
dividerLine: {
|
||||||
|
flex: 1,
|
||||||
|
height: 1,
|
||||||
|
backgroundColor: "#ddd",
|
||||||
|
},
|
||||||
|
dividerText: {
|
||||||
|
marginHorizontal: 10,
|
||||||
|
color: "#666",
|
||||||
|
fontSize: 14,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import React from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { useSignUp, useAuth } from "@clerk/clerk-expo";
|
import { useSignUp, useAuth } from "@clerk/clerk-expo";
|
||||||
import { useRouter } from "expo-router";
|
import { useRouter } from "expo-router";
|
||||||
import {
|
import {
|
||||||
@@ -12,23 +12,24 @@ import {
|
|||||||
Platform,
|
Platform,
|
||||||
ScrollView,
|
ScrollView,
|
||||||
} from "react-native";
|
} from "react-native";
|
||||||
|
import { OAuthButtons } from "../../components/auth/OAuthButtons";
|
||||||
|
|
||||||
export default function SignUpScreen() {
|
export default function SignUpScreen() {
|
||||||
const { signUp, setActive, isLoaded } = useSignUp();
|
const { signUp, setActive, isLoaded } = useSignUp();
|
||||||
const { isSignedIn } = useAuth();
|
const { isSignedIn } = useAuth();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const [emailAddress, setEmailAddress] = React.useState("");
|
const [emailAddress, setEmailAddress] = useState("");
|
||||||
const [password, setPassword] = React.useState("");
|
const [password, setPassword] = useState("");
|
||||||
const [firstName, setFirstName] = React.useState("");
|
const [firstName, setFirstName] = useState("");
|
||||||
const [lastName, setLastName] = React.useState("");
|
const [lastName, setLastName] = useState("");
|
||||||
const [pendingVerification, setPendingVerification] = React.useState(false);
|
const [pendingVerification, setPendingVerification] = useState(false);
|
||||||
const [code, setCode] = React.useState("");
|
const [code, setCode] = useState("");
|
||||||
const [loading, setLoading] = React.useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [error, setError] = React.useState("");
|
const [error, setError] = useState("");
|
||||||
|
|
||||||
// Redirect if already signed in
|
// Redirect if already signed in
|
||||||
React.useEffect(() => {
|
useEffect(() => {
|
||||||
if (isSignedIn) {
|
if (isSignedIn) {
|
||||||
router.replace("/(tabs)");
|
router.replace("/(tabs)");
|
||||||
}
|
}
|
||||||
@@ -182,6 +183,14 @@ export default function SignUpScreen() {
|
|||||||
</View>
|
</View>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
|
<OAuthButtons />
|
||||||
|
|
||||||
|
<View style={styles.dividerContainer}>
|
||||||
|
<View style={styles.dividerLine} />
|
||||||
|
<Text style={styles.dividerText}>OR</Text>
|
||||||
|
<View style={styles.dividerLine} />
|
||||||
|
</View>
|
||||||
|
|
||||||
<View style={styles.form}>
|
<View style={styles.form}>
|
||||||
<View style={styles.inputContainer}>
|
<View style={styles.inputContainer}>
|
||||||
<Text style={styles.label}>First Name</Text>
|
<Text style={styles.label}>First Name</Text>
|
||||||
@@ -372,4 +381,19 @@ const styles = StyleSheet.create({
|
|||||||
color: "#2563eb",
|
color: "#2563eb",
|
||||||
fontWeight: "600",
|
fontWeight: "600",
|
||||||
},
|
},
|
||||||
|
dividerContainer: {
|
||||||
|
flexDirection: "row",
|
||||||
|
alignItems: "center",
|
||||||
|
marginBottom: 24,
|
||||||
|
},
|
||||||
|
dividerLine: {
|
||||||
|
flex: 1,
|
||||||
|
height: 1,
|
||||||
|
backgroundColor: "#ddd",
|
||||||
|
},
|
||||||
|
dividerText: {
|
||||||
|
marginHorizontal: 10,
|
||||||
|
color: "#666",
|
||||||
|
fontSize: 14,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
@@ -1,16 +1,9 @@
|
|||||||
import { View, Text, StyleSheet, TouchableOpacity, ActivityIndicator, ScrollView, Alert } from 'react-native'
|
import { View, Text, StyleSheet, TouchableOpacity, ActivityIndicator, ScrollView, Alert } from 'react-native'
|
||||||
import { useState, useEffect } from 'react'
|
import { useState, useEffect } from 'react'
|
||||||
import { useAuth } from '@clerk/clerk-expo'
|
import { useAuth } from '@clerk/clerk-expo'
|
||||||
import axios from 'axios'
|
import { attendanceApi, Attendance } from '../../api/attendance'
|
||||||
import { API_BASE_URL, API_ENDPOINTS } from '../../config/api'
|
|
||||||
|
|
||||||
interface Attendance {
|
|
||||||
id: string
|
|
||||||
checkInTime: string
|
|
||||||
checkOutTime?: string
|
|
||||||
type: string
|
|
||||||
notes?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function AttendanceScreen() {
|
export default function AttendanceScreen() {
|
||||||
const { getToken, userId } = useAuth()
|
const { getToken, userId } = useAuth()
|
||||||
@@ -22,13 +15,10 @@ export default function AttendanceScreen() {
|
|||||||
try {
|
try {
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
const token = await getToken()
|
const token = await getToken()
|
||||||
const url = `${API_BASE_URL}${API_ENDPOINTS.ATTENDANCE.HISTORY}`
|
if (!token) return
|
||||||
console.log('Fetching attendance from:', url)
|
|
||||||
const response = await axios.get(url, {
|
|
||||||
headers: { Authorization: `Bearer ${token}` }
|
|
||||||
})
|
|
||||||
|
|
||||||
const data: Attendance[] = response.data
|
console.log('Fetching attendance history')
|
||||||
|
const data = await attendanceApi.getHistory(token)
|
||||||
setHistory(data)
|
setHistory(data)
|
||||||
|
|
||||||
// Check if there's an active check-in (latest one has no checkOutTime)
|
// Check if there's an active check-in (latest one has no checkOutTime)
|
||||||
@@ -52,11 +42,9 @@ export default function AttendanceScreen() {
|
|||||||
const handleCheckIn = async () => {
|
const handleCheckIn = async () => {
|
||||||
try {
|
try {
|
||||||
const token = await getToken()
|
const token = await getToken()
|
||||||
await axios.post(
|
if (!token) return
|
||||||
`${API_BASE_URL}${API_ENDPOINTS.ATTENDANCE.CHECK_IN}`,
|
|
||||||
{ type: 'gym' },
|
await attendanceApi.checkIn('gym', token)
|
||||||
{ headers: { Authorization: `Bearer ${token}` } }
|
|
||||||
)
|
|
||||||
fetchAttendance()
|
fetchAttendance()
|
||||||
Alert.alert('Success', 'Checked in successfully!')
|
Alert.alert('Success', 'Checked in successfully!')
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
@@ -68,11 +56,9 @@ export default function AttendanceScreen() {
|
|||||||
const handleCheckOut = async () => {
|
const handleCheckOut = async () => {
|
||||||
try {
|
try {
|
||||||
const token = await getToken()
|
const token = await getToken()
|
||||||
await axios.post(
|
if (!token) return
|
||||||
`${API_BASE_URL}${API_ENDPOINTS.ATTENDANCE.CHECK_OUT}`,
|
|
||||||
{},
|
await attendanceApi.checkOut(token)
|
||||||
{ headers: { Authorization: `Bearer ${token}` } }
|
|
||||||
)
|
|
||||||
fetchAttendance()
|
fetchAttendance()
|
||||||
Alert.alert('Success', 'Checked out successfully!')
|
Alert.alert('Success', 'Checked out successfully!')
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import React, { useState } from 'react'
|
import React, { useState } from 'react'
|
||||||
import { View, Text, TextInput, TouchableOpacity, StyleSheet, Alert, ScrollView } from 'react-native'
|
import { View, Text, TextInput, TouchableOpacity, StyleSheet, Alert, ScrollView } from 'react-native'
|
||||||
import { useRouter } from 'expo-router'
|
import { useRouter } from 'expo-router'
|
||||||
import axios from 'axios'
|
import { useAuth } from '@clerk/clerk-expo'
|
||||||
import * as SecureStore from 'expo-secure-store'
|
import * as SecureStore from 'expo-secure-store'
|
||||||
import { API_BASE_URL, API_ENDPOINTS } from '../config/api'
|
import { profileApi } from '../api/profile'
|
||||||
|
|
||||||
interface FitnessProfile {
|
interface FitnessProfile {
|
||||||
height: string
|
height: string
|
||||||
@@ -31,6 +31,7 @@ export default function WelcomeScreen() {
|
|||||||
})
|
})
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
const { getToken } = useAuth()
|
||||||
|
|
||||||
const fitnessGoalsOptions = [
|
const fitnessGoalsOptions = [
|
||||||
'Weight Loss',
|
'Weight Loss',
|
||||||
@@ -67,6 +68,11 @@ export default function WelcomeScreen() {
|
|||||||
|
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
try {
|
try {
|
||||||
|
const token = await getToken()
|
||||||
|
if (!token) {
|
||||||
|
throw new Error('Authentication required')
|
||||||
|
}
|
||||||
|
|
||||||
const user = await SecureStore.getItemAsync('user')
|
const user = await SecureStore.getItemAsync('user')
|
||||||
if (!user) {
|
if (!user) {
|
||||||
throw new Error('No user found')
|
throw new Error('No user found')
|
||||||
@@ -74,19 +80,19 @@ export default function WelcomeScreen() {
|
|||||||
|
|
||||||
const userData = JSON.parse(user)
|
const userData = JSON.parse(user)
|
||||||
|
|
||||||
const response = await axios.post(
|
await profileApi.createFitnessProfile(
|
||||||
`${API_BASE_URL}${API_ENDPOINTS.PROFILE.FITNESS}`,
|
|
||||||
{
|
{
|
||||||
userId: userData.id,
|
userId: userData.id,
|
||||||
...profile
|
...profile
|
||||||
}
|
},
|
||||||
|
token
|
||||||
)
|
)
|
||||||
|
|
||||||
if (response.status === 201) {
|
Alert.alert('Success', 'Profile completed successfully!', [
|
||||||
Alert.alert('Success', 'Profile completed successfully!', [
|
{ text: 'OK', onPress: () => router.replace('/(tabs)') }
|
||||||
{ text: 'OK', onPress: () => router.replace('/(tabs)') }
|
])
|
||||||
])
|
|
||||||
}
|
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.log('Profile save error:', error)
|
console.log('Profile save error:', error)
|
||||||
Alert.alert('Error', error.response?.data?.error || 'Failed to save profile. Please try again.')
|
Alert.alert('Error', error.response?.data?.error || 'Failed to save profile. Please try again.')
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
import React from "react";
|
||||||
|
import * as WebBrowser from "expo-web-browser";
|
||||||
|
import { Button, View, StyleSheet, TouchableOpacity, Text } from "react-native";
|
||||||
|
import { useOAuth } from "@clerk/clerk-expo";
|
||||||
|
import { useWarmUpBrowser } from "../../hooks/useWarmUpBrowser";
|
||||||
|
import { Ionicons } from "@expo/vector-icons";
|
||||||
|
|
||||||
|
WebBrowser.maybeCompleteAuthSession();
|
||||||
|
|
||||||
|
export function OAuthButtons() {
|
||||||
|
useWarmUpBrowser();
|
||||||
|
|
||||||
|
const { startOAuthFlow } = useOAuth({ strategy: "oauth_google" });
|
||||||
|
|
||||||
|
const onPress = React.useCallback(async () => {
|
||||||
|
try {
|
||||||
|
const { createdSessionId, signIn, signUp, setActive } =
|
||||||
|
await startOAuthFlow();
|
||||||
|
|
||||||
|
if (createdSessionId) {
|
||||||
|
setActive!({ session: createdSessionId });
|
||||||
|
} else {
|
||||||
|
// Use signIn or signUp for next steps such as MFA
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error("OAuth error", err);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
<TouchableOpacity style={styles.button} onPress={onPress}>
|
||||||
|
<Ionicons name="logo-google" size={20} color="#DB4437" style={styles.icon} />
|
||||||
|
<Text style={styles.text}>Continue with Google</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
width: "100%",
|
||||||
|
marginTop: 16,
|
||||||
|
},
|
||||||
|
button: {
|
||||||
|
flexDirection: "row",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center",
|
||||||
|
backgroundColor: "#fff",
|
||||||
|
borderWidth: 1,
|
||||||
|
borderColor: "#ddd",
|
||||||
|
paddingVertical: 12,
|
||||||
|
borderRadius: 8,
|
||||||
|
marginBottom: 12,
|
||||||
|
},
|
||||||
|
icon: {
|
||||||
|
marginRight: 10,
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: "500",
|
||||||
|
color: "#333",
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
export const API_BASE_URL = __DEV__
|
export const API_BASE_URL = __DEV__
|
||||||
? 'https://390dfd6ece05.ngrok-free.app'
|
? 'https://f0a9b87c3831.ngrok-free.app'
|
||||||
: 'https://your-production-url.com'
|
: 'https://your-production-url.com'
|
||||||
|
|
||||||
export const API_ENDPOINTS = {
|
export const API_ENDPOINTS = {
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import React from "react";
|
||||||
|
import * as WebBrowser from "expo-web-browser";
|
||||||
|
|
||||||
|
export const useWarmUpBrowser = () => {
|
||||||
|
React.useEffect(() => {
|
||||||
|
// Warm up the android browser to improve UX
|
||||||
|
// https://docs.expo.dev/guides/authentication/#improving-user-experience
|
||||||
|
void WebBrowser.warmUpAsync();
|
||||||
|
return () => {
|
||||||
|
void WebBrowser.coolDownAsync();
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
};
|
||||||
@@ -5,6 +5,7 @@ export default defineConfig({
|
|||||||
out: "./drizzle",
|
out: "./drizzle",
|
||||||
dialect: "sqlite",
|
dialect: "sqlite",
|
||||||
dbCredentials: {
|
dbCredentials: {
|
||||||
url: "./fitai.db",
|
// url: "./fitai.db",
|
||||||
|
url: "../../apps/admin/data/fitai.db",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
Reference in new issue
Block a user