invite and saving fitness profile
added, need polishing
This commit is contained in:
parent
daaf5aa2dd
commit
118efad70f
Binary file not shown.
58
apps/admin/package-lock.json
generated
58
apps/admin/package-lock.json
generated
@ -22,6 +22,7 @@
|
|||||||
"autoprefixer": "^10.4.16",
|
"autoprefixer": "^10.4.16",
|
||||||
"axios": "^1.13.2",
|
"axios": "^1.13.2",
|
||||||
"bcryptjs": "^3.0.3",
|
"bcryptjs": "^3.0.3",
|
||||||
|
"better-sqlite3": "^11.10.0",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"date-fns": "^4.1.0",
|
"date-fns": "^4.1.0",
|
||||||
@ -112,6 +113,7 @@
|
|||||||
"integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
|
"integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.27.1",
|
"@babel/code-frame": "^7.27.1",
|
||||||
"@babel/generator": "^7.28.5",
|
"@babel/generator": "^7.28.5",
|
||||||
@ -2396,7 +2398,6 @@
|
|||||||
"integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==",
|
"integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.10.4",
|
"@babel/code-frame": "^7.10.4",
|
||||||
"@babel/runtime": "^7.12.5",
|
"@babel/runtime": "^7.12.5",
|
||||||
@ -2417,7 +2418,6 @@
|
|||||||
"integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
|
"integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"dequal": "^2.0.3"
|
"dequal": "^2.0.3"
|
||||||
}
|
}
|
||||||
@ -2427,8 +2427,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz",
|
"resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz",
|
||||||
"integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==",
|
"integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT"
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/@testing-library/jest-dom": {
|
"node_modules/@testing-library/jest-dom": {
|
||||||
"version": "6.9.1",
|
"version": "6.9.1",
|
||||||
@ -2504,8 +2503,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
|
||||||
"integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==",
|
"integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT"
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/@types/babel__core": {
|
"node_modules/@types/babel__core": {
|
||||||
"version": "7.20.5",
|
"version": "7.20.5",
|
||||||
@ -2689,6 +2687,7 @@
|
|||||||
"integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==",
|
"integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"csstype": "^3.0.2"
|
"csstype": "^3.0.2"
|
||||||
}
|
}
|
||||||
@ -2699,6 +2698,7 @@
|
|||||||
"integrity": "sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw==",
|
"integrity": "sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@types/react": "^19.2.0"
|
"@types/react": "^19.2.0"
|
||||||
}
|
}
|
||||||
@ -2789,6 +2789,7 @@
|
|||||||
"integrity": "sha512-6m1I5RmHBGTnUGS113G04DMu3CpSdxCAU/UvtjNWL4Nuf3MW9tQhiJqRlHzChIkhy6kZSAQmc+I1bcGjE3yNKg==",
|
"integrity": "sha512-6m1I5RmHBGTnUGS113G04DMu3CpSdxCAU/UvtjNWL4Nuf3MW9tQhiJqRlHzChIkhy6kZSAQmc+I1bcGjE3yNKg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/scope-manager": "8.46.3",
|
"@typescript-eslint/scope-manager": "8.46.3",
|
||||||
"@typescript-eslint/types": "8.46.3",
|
"@typescript-eslint/types": "8.46.3",
|
||||||
@ -3333,6 +3334,7 @@
|
|||||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"acorn": "bin/acorn"
|
"acorn": "bin/acorn"
|
||||||
},
|
},
|
||||||
@ -3988,6 +3990,17 @@
|
|||||||
"bcrypt": "bin/bcrypt"
|
"bcrypt": "bin/bcrypt"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/better-sqlite3": {
|
||||||
|
"version": "11.10.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-11.10.0.tgz",
|
||||||
|
"integrity": "sha512-EwhOpyXiOEL/lKzHz9AW1msWFNzGc/z+LzeB3/jnFJpxu+th2yqvzsSWas1v9jgs9+xiXJcD5A8CJxAG2TaghQ==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"bindings": "^1.5.0",
|
||||||
|
"prebuild-install": "^7.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/binary-extensions": {
|
"node_modules/binary-extensions": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
|
||||||
@ -4062,6 +4075,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"baseline-browser-mapping": "^2.8.19",
|
"baseline-browser-mapping": "^2.8.19",
|
||||||
"caniuse-lite": "^1.0.30001751",
|
"caniuse-lite": "^1.0.30001751",
|
||||||
@ -5296,6 +5310,7 @@
|
|||||||
"integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==",
|
"integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.8.0",
|
"@eslint-community/eslint-utils": "^4.8.0",
|
||||||
"@eslint-community/regexpp": "^4.12.1",
|
"@eslint-community/regexpp": "^4.12.1",
|
||||||
@ -5481,6 +5496,7 @@
|
|||||||
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
|
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@rtsao/scc": "^1.1.0",
|
"@rtsao/scc": "^1.1.0",
|
||||||
"array-includes": "^3.1.9",
|
"array-includes": "^3.1.9",
|
||||||
@ -8324,18 +8340,6 @@
|
|||||||
"url": "https://github.com/chalk/supports-color?sponsor=1"
|
"url": "https://github.com/chalk/supports-color?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/jiti": {
|
|
||||||
"version": "2.6.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz",
|
|
||||||
"integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
|
||||||
"jiti": "lib/jiti-cli.mjs"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/js-cookie": {
|
"node_modules/js-cookie": {
|
||||||
"version": "3.0.5",
|
"version": "3.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz",
|
||||||
@ -8563,7 +8567,6 @@
|
|||||||
"integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==",
|
"integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"lz-string": "bin/bin.js"
|
"lz-string": "bin/bin.js"
|
||||||
}
|
}
|
||||||
@ -9076,6 +9079,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/next/-/next-16.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/next/-/next-16.0.1.tgz",
|
||||||
"integrity": "sha512-e9RLSssZwd35p7/vOa+hoDFggUZIUbZhIUSLZuETCwrCVvxOs87NamoUzT+vbcNAL8Ld9GobBnWOA6SbV/arOw==",
|
"integrity": "sha512-e9RLSssZwd35p7/vOa+hoDFggUZIUbZhIUSLZuETCwrCVvxOs87NamoUzT+vbcNAL8Ld9GobBnWOA6SbV/arOw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@next/env": "16.0.1",
|
"@next/env": "16.0.1",
|
||||||
"@swc/helpers": "0.5.15",
|
"@swc/helpers": "0.5.15",
|
||||||
@ -9744,6 +9748,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nanoid": "^3.3.6",
|
"nanoid": "^3.3.6",
|
||||||
"picocolors": "^1.0.0",
|
"picocolors": "^1.0.0",
|
||||||
@ -9881,7 +9886,6 @@
|
|||||||
"integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
|
"integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ansi-regex": "^5.0.1",
|
"ansi-regex": "^5.0.1",
|
||||||
"ansi-styles": "^5.0.0",
|
"ansi-styles": "^5.0.0",
|
||||||
@ -9897,7 +9901,6 @@
|
|||||||
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
|
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
},
|
},
|
||||||
@ -9910,8 +9913,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
||||||
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
|
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT"
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/promise-inflight": {
|
"node_modules/promise-inflight": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
@ -10043,6 +10045,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz",
|
||||||
"integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==",
|
"integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
@ -10052,6 +10055,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz",
|
||||||
"integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==",
|
"integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"scheduler": "^0.27.0"
|
"scheduler": "^0.27.0"
|
||||||
},
|
},
|
||||||
@ -10064,6 +10068,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.66.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.66.0.tgz",
|
||||||
"integrity": "sha512-xXBqsWGKrY46ZqaHDo+ZUYiMUgi8suYu5kdrS20EG8KiL7VRQitEbNjm+UcrDYrNi1YLyfpmAeGjCZYXLT9YBw==",
|
"integrity": "sha512-xXBqsWGKrY46ZqaHDo+ZUYiMUgi8suYu5kdrS20EG8KiL7VRQitEbNjm+UcrDYrNi1YLyfpmAeGjCZYXLT9YBw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0.0"
|
"node": ">=18.0.0"
|
||||||
},
|
},
|
||||||
@ -10087,6 +10092,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz",
|
||||||
"integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==",
|
"integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/use-sync-external-store": "^0.0.6",
|
"@types/use-sync-external-store": "^0.0.6",
|
||||||
"use-sync-external-store": "^1.4.0"
|
"use-sync-external-store": "^1.4.0"
|
||||||
@ -10185,7 +10191,8 @@
|
|||||||
"version": "5.0.1",
|
"version": "5.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
|
||||||
"integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==",
|
"integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==",
|
||||||
"license": "MIT"
|
"license": "MIT",
|
||||||
|
"peer": true
|
||||||
},
|
},
|
||||||
"node_modules/redux-thunk": {
|
"node_modules/redux-thunk": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
@ -11638,6 +11645,7 @@
|
|||||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
},
|
},
|
||||||
@ -11857,6 +11865,7 @@
|
|||||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
|
"peer": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
"tsserver": "bin/tsserver"
|
"tsserver": "bin/tsserver"
|
||||||
@ -12443,6 +12452,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/zod/-/zod-4.1.12.tgz",
|
"resolved": "https://registry.npmjs.org/zod/-/zod-4.1.12.tgz",
|
||||||
"integrity": "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==",
|
"integrity": "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/colinhacks"
|
"url": "https://github.com/sponsors/colinhacks"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,6 +25,7 @@
|
|||||||
"autoprefixer": "^10.4.16",
|
"autoprefixer": "^10.4.16",
|
||||||
"axios": "^1.13.2",
|
"axios": "^1.13.2",
|
||||||
"bcryptjs": "^3.0.3",
|
"bcryptjs": "^3.0.3",
|
||||||
|
"better-sqlite3": "^11.10.0",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"date-fns": "^4.1.0",
|
"date-fns": "^4.1.0",
|
||||||
|
|||||||
33
apps/admin/scripts/migrate-fitness-profile.js
Normal file
33
apps/admin/scripts/migrate-fitness-profile.js
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
const Database = require('better-sqlite3');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const dbPath = path.join(__dirname, '../../../data/fitai.db');
|
||||||
|
const db = new Database(dbPath);
|
||||||
|
|
||||||
|
console.log('Migrating fitness_profiles table...');
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Check if columns exist
|
||||||
|
const tableInfo = db.prepare('PRAGMA table_info(fitness_profiles)').all();
|
||||||
|
const columns = tableInfo.map(c => c.name);
|
||||||
|
|
||||||
|
if (!columns.includes('allergies')) {
|
||||||
|
console.log('Adding allergies column...');
|
||||||
|
db.prepare('ALTER TABLE fitness_profiles ADD COLUMN allergies TEXT').run();
|
||||||
|
} else {
|
||||||
|
console.log('allergies column already exists.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!columns.includes('injuries')) {
|
||||||
|
console.log('Adding injuries column...');
|
||||||
|
db.prepare('ALTER TABLE fitness_profiles ADD COLUMN injuries TEXT').run();
|
||||||
|
} else {
|
||||||
|
console.log('injuries column already exists.');
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Migration completed successfully.');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Migration failed:', error);
|
||||||
|
} finally {
|
||||||
|
db.close();
|
||||||
|
}
|
||||||
@ -16,10 +16,20 @@ export async function GET(request: NextRequest) {
|
|||||||
|
|
||||||
const profile = db
|
const profile = db
|
||||||
.prepare(
|
.prepare(
|
||||||
`SELECT * FROM fitness_profiles WHERE user_id = ?`
|
`SELECT * FROM fitness_profiles WHERE userId = ?`
|
||||||
)
|
)
|
||||||
.get(userId);
|
.get(userId);
|
||||||
|
|
||||||
|
if (profile) {
|
||||||
|
const p = profile as any;
|
||||||
|
// Parse JSON fields
|
||||||
|
try {
|
||||||
|
p.fitnessGoals = JSON.parse(p.fitnessGoals || '[]');
|
||||||
|
} catch (e) {
|
||||||
|
p.fitnessGoals = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return NextResponse.json({ profile: profile || null });
|
return NextResponse.json({ profile: profile || null });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error fetching fitness profile:", error);
|
console.error("Error fetching fitness profile:", error);
|
||||||
@ -45,19 +55,22 @@ export async function POST(request: NextRequest) {
|
|||||||
weight,
|
weight,
|
||||||
age,
|
age,
|
||||||
gender,
|
gender,
|
||||||
fitnessGoal,
|
fitnessGoals, // Changed from fitnessGoal
|
||||||
activityLevel,
|
activityLevel,
|
||||||
medicalConditions,
|
medicalConditions,
|
||||||
allergies,
|
allergies,
|
||||||
injuries,
|
injuries,
|
||||||
|
exerciseHabits,
|
||||||
|
dietHabits
|
||||||
} = body;
|
} = body;
|
||||||
|
|
||||||
// Check if profile exists
|
// Check if profile exists
|
||||||
const existingProfile = db
|
const existingProfile = db
|
||||||
.prepare(`SELECT id FROM fitness_profiles WHERE user_id = ?`)
|
.prepare(`SELECT userId FROM fitness_profiles WHERE userId = ?`)
|
||||||
.get(userId) as { id: string } | undefined;
|
.get(userId) as { userId: string } | undefined;
|
||||||
|
|
||||||
const now = Date.now();
|
const now = new Date().toISOString();
|
||||||
|
const fitnessGoalsJson = JSON.stringify(fitnessGoals || []);
|
||||||
|
|
||||||
if (existingProfile) {
|
if (existingProfile) {
|
||||||
// Update existing profile
|
// Update existing profile
|
||||||
@ -67,52 +80,55 @@ export async function POST(request: NextRequest) {
|
|||||||
weight = ?,
|
weight = ?,
|
||||||
age = ?,
|
age = ?,
|
||||||
gender = ?,
|
gender = ?,
|
||||||
fitness_goal = ?,
|
fitnessGoals = ?,
|
||||||
activity_level = ?,
|
activityLevel = ?,
|
||||||
medical_conditions = ?,
|
medicalConditions = ?,
|
||||||
allergies = ?,
|
allergies = ?,
|
||||||
injuries = ?,
|
injuries = ?,
|
||||||
updated_at = ?
|
exerciseHabits = ?,
|
||||||
WHERE user_id = ?`
|
dietHabits = ?,
|
||||||
|
updatedAt = ?
|
||||||
|
WHERE userId = ?`
|
||||||
).run(
|
).run(
|
||||||
height || null,
|
height || null,
|
||||||
weight || null,
|
weight || null,
|
||||||
age || null,
|
age || null,
|
||||||
gender || null,
|
gender || null,
|
||||||
fitnessGoal || null,
|
fitnessGoalsJson,
|
||||||
activityLevel || null,
|
activityLevel || null,
|
||||||
medicalConditions || null,
|
medicalConditions || null,
|
||||||
allergies || null,
|
allergies || null,
|
||||||
injuries || null,
|
injuries || null,
|
||||||
|
exerciseHabits || null,
|
||||||
|
dietHabits || null,
|
||||||
now,
|
now,
|
||||||
userId
|
userId
|
||||||
);
|
);
|
||||||
|
|
||||||
return NextResponse.json({
|
return NextResponse.json({
|
||||||
message: "Fitness profile updated successfully",
|
message: "Fitness profile updated successfully",
|
||||||
profileId: existingProfile.id,
|
userId: userId,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// Create new profile
|
// Create new profile
|
||||||
const profileId = `fp_${randomBytes(16).toString("hex")}`;
|
|
||||||
|
|
||||||
db.prepare(
|
db.prepare(
|
||||||
`INSERT INTO fitness_profiles
|
`INSERT INTO fitness_profiles
|
||||||
(id, user_id, height, weight, age, gender, fitness_goal, activity_level,
|
(userId, height, weight, age, gender, fitnessGoals, activityLevel,
|
||||||
medical_conditions, allergies, injuries, created_at, updated_at)
|
medicalConditions, allergies, injuries, exerciseHabits, dietHabits, createdAt, updatedAt)
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
||||||
).run(
|
).run(
|
||||||
profileId,
|
|
||||||
userId,
|
userId,
|
||||||
height || null,
|
height || null,
|
||||||
weight || null,
|
weight || null,
|
||||||
age || null,
|
age || null,
|
||||||
gender || null,
|
gender || null,
|
||||||
fitnessGoal || null,
|
fitnessGoalsJson,
|
||||||
activityLevel || null,
|
activityLevel || null,
|
||||||
medicalConditions || null,
|
medicalConditions || null,
|
||||||
allergies || null,
|
allergies || null,
|
||||||
injuries || null,
|
injuries || null,
|
||||||
|
exerciseHabits || null,
|
||||||
|
dietHabits || null,
|
||||||
now,
|
now,
|
||||||
now
|
now
|
||||||
);
|
);
|
||||||
@ -120,7 +136,7 @@ export async function POST(request: NextRequest) {
|
|||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{
|
{
|
||||||
message: "Fitness profile created successfully",
|
message: "Fitness profile created successfully",
|
||||||
profileId,
|
userId,
|
||||||
},
|
},
|
||||||
{ status: 201 }
|
{ status: 201 }
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { NextRequest, NextResponse } from "next/server";
|
import { NextRequest, NextResponse } from "next/server";
|
||||||
import { getDatabase } from "../../../lib/database/index";
|
import { getDatabase } from "../../../lib/database/index";
|
||||||
import bcrypt from "bcryptjs";
|
import bcrypt from "bcryptjs";
|
||||||
import { auth } from "@clerk/nextjs/server";
|
import { auth, clerkClient } from "@clerk/nextjs/server";
|
||||||
|
|
||||||
export async function GET(request: NextRequest) {
|
export async function GET(request: NextRequest) {
|
||||||
try {
|
try {
|
||||||
@ -64,9 +64,9 @@ export async function POST(request: NextRequest) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const body = await request.json();
|
const body = await request.json();
|
||||||
const { email, password, firstName, lastName, role, phone } = body;
|
const { email, firstName, lastName, role, phone } = body;
|
||||||
|
|
||||||
if (!email || !password || !firstName || !lastName || !role) {
|
if (!email || !firstName || !lastName || !role) {
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{ error: "Missing required fields" },
|
{ error: "Missing required fields" },
|
||||||
{ status: 400 },
|
{ status: 400 },
|
||||||
@ -75,7 +75,7 @@ export async function POST(request: NextRequest) {
|
|||||||
|
|
||||||
// Enforce Hierarchy
|
// Enforce Hierarchy
|
||||||
const allowed = {
|
const allowed = {
|
||||||
superAdmin: ["admin", "trainer", "client"], // Super Admin can create anyone (except maybe another superAdmin via this UI?)
|
superAdmin: ["admin", "trainer", "client"],
|
||||||
admin: ["trainer", "client"],
|
admin: ["trainer", "client"],
|
||||||
trainer: ["client"],
|
trainer: ["client"],
|
||||||
client: []
|
client: []
|
||||||
@ -89,7 +89,7 @@ export async function POST(request: NextRequest) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if user already exists
|
// Check if user already exists locally
|
||||||
const existingUser = await db.getUserByEmail(email);
|
const existingUser = await db.getUserByEmail(email);
|
||||||
if (existingUser) {
|
if (existingUser) {
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
@ -98,13 +98,38 @@ export async function POST(request: NextRequest) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hash password
|
// Create Clerk Invitation
|
||||||
const hashedPassword = await bcrypt.hash(password, 12);
|
// Note: We pass the role in publicMetadata so it persists when they sign up
|
||||||
|
try {
|
||||||
|
const client = await clerkClient();
|
||||||
|
await client.invitations.createInvitation({
|
||||||
|
emailAddress: email,
|
||||||
|
publicMetadata: {
|
||||||
|
role,
|
||||||
|
},
|
||||||
|
ignoreExisting: true // Don't fail if invite exists
|
||||||
|
});
|
||||||
|
} catch (clerkError: any) {
|
||||||
|
console.error("Clerk invitation error:", clerkError);
|
||||||
|
// If user already exists in Clerk, we might want to handle it.
|
||||||
|
// But for now, let's proceed to create local record if invite sent or if they exist.
|
||||||
|
if (clerkError.errors?.[0]?.code === 'form_identifier_exists') {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: "User already exists in Clerk system" },
|
||||||
|
{ status: 409 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: "Failed to send invitation: " + (clerkError.message || "Unknown error") },
|
||||||
|
{ status: 500 },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Create user
|
// Create user in local DB with temporary ID (will be migrated on first login)
|
||||||
|
// We set a placeholder password since it's required by schema but won't be used
|
||||||
const newUserId = await db.createUser({
|
const newUserId = await db.createUser({
|
||||||
email,
|
email,
|
||||||
password: hashedPassword,
|
password: "INVITED_USER_PENDING",
|
||||||
firstName,
|
firstName,
|
||||||
lastName,
|
lastName,
|
||||||
role,
|
role,
|
||||||
@ -121,7 +146,7 @@ export async function POST(request: NextRequest) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return NextResponse.json({ userId: newUserId.id }, { status: 201 });
|
return NextResponse.json({ userId: newUserId.id, message: "Invitation sent" }, { status: 201 });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Create user error:", error);
|
console.error("Create user error:", error);
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
|
|||||||
@ -139,23 +139,44 @@ export function UserManagement() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleSaveEdit = async () => {
|
const handleSaveEdit = async () => {
|
||||||
if (!editForm || !selectedUser) return;
|
if (!editForm) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch("/api/users", {
|
if (selectedUser) {
|
||||||
method: "PUT",
|
// Update existing user
|
||||||
headers: { "Content-Type": "application/json" },
|
const response = await fetch("/api/users", {
|
||||||
body: JSON.stringify({ id: selectedUser.id, ...editForm }),
|
method: "PUT",
|
||||||
});
|
headers: { "Content-Type": "application/json" },
|
||||||
if (response.ok) {
|
body: JSON.stringify({ id: selectedUser.id, ...editForm }),
|
||||||
setIsEditing(false);
|
});
|
||||||
setEditForm(null);
|
if (response.ok) {
|
||||||
fetchUsers();
|
setIsEditing(false);
|
||||||
|
setEditForm(null);
|
||||||
|
fetchUsers();
|
||||||
|
} else {
|
||||||
|
alert("Error updating user");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
alert("Error updating user");
|
// Create (Invite) new user
|
||||||
|
const response = await fetch("/api/users", {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify(editForm),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
setIsEditing(false);
|
||||||
|
setEditForm(null);
|
||||||
|
fetchUsers();
|
||||||
|
alert("Invitation sent successfully!");
|
||||||
|
} else {
|
||||||
|
const errorData = await response.json();
|
||||||
|
alert(`Error sending invitation: ${errorData.error}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
|
alert("An unexpected error occurred");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -196,6 +217,22 @@ export function UserManagement() {
|
|||||||
>
|
>
|
||||||
Edit User
|
Edit User
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="secondary"
|
||||||
|
onClick={() => {
|
||||||
|
setEditForm({
|
||||||
|
firstName: "",
|
||||||
|
lastName: "",
|
||||||
|
email: "",
|
||||||
|
role: "client",
|
||||||
|
phone: "",
|
||||||
|
});
|
||||||
|
setSelectedUser(null);
|
||||||
|
setIsEditing(true);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Invite User
|
||||||
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
onClick={handleDeleteUser}
|
onClick={handleDeleteUser}
|
||||||
@ -265,7 +302,7 @@ export function UserManagement() {
|
|||||||
{isEditing && editForm && (
|
{isEditing && editForm && (
|
||||||
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
|
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
|
||||||
<div className="bg-white p-6 rounded-lg shadow-lg max-w-md w-full">
|
<div className="bg-white p-6 rounded-lg shadow-lg max-w-md w-full">
|
||||||
<h3 className="text-lg font-semibold mb-4">Edit User</h3>
|
<h3 className="text-lg font-semibold mb-4">{selectedUser ? 'Edit User' : 'Invite New User'}</h3>
|
||||||
<form
|
<form
|
||||||
onSubmit={(e) => {
|
onSubmit={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@ -310,6 +347,7 @@ export function UserManagement() {
|
|||||||
}
|
}
|
||||||
className="w-full border border-gray-300 rounded px-3 py-2"
|
className="w-full border border-gray-300 rounded px-3 py-2"
|
||||||
required
|
required
|
||||||
|
disabled={!!selectedUser} // Disable email edit for existing users if desired, or keep enabled
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
@ -360,7 +398,7 @@ export function UserManagement() {
|
|||||||
type="submit"
|
type="submit"
|
||||||
className="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700"
|
className="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700"
|
||||||
>
|
>
|
||||||
Save
|
{selectedUser ? 'Save Changes' : 'Send Invitation'}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@ -91,6 +91,8 @@ export class SQLiteDatabase implements IDatabase {
|
|||||||
exerciseHabits TEXT,
|
exerciseHabits TEXT,
|
||||||
dietHabits TEXT,
|
dietHabits TEXT,
|
||||||
medicalConditions TEXT,
|
medicalConditions TEXT,
|
||||||
|
allergies TEXT,
|
||||||
|
injuries TEXT,
|
||||||
createdAt DATETIME NOT NULL,
|
createdAt DATETIME NOT NULL,
|
||||||
updatedAt DATETIME NOT NULL,
|
updatedAt DATETIME NOT NULL,
|
||||||
FOREIGN KEY (userId) REFERENCES users (id) ON DELETE CASCADE
|
FOREIGN KEY (userId) REFERENCES users (id) ON DELETE CASCADE
|
||||||
@ -198,6 +200,7 @@ export class SQLiteDatabase implements IDatabase {
|
|||||||
async deleteUser(id: string): Promise<boolean> {
|
async deleteUser(id: string): Promise<boolean> {
|
||||||
if (!this.db) throw new Error('Database not connected')
|
if (!this.db) throw new Error('Database not connected')
|
||||||
|
|
||||||
|
const stmt = this.db.prepare('DELETE FROM users WHERE id = ?')
|
||||||
const result = stmt.run(id)
|
const result = stmt.run(id)
|
||||||
return (result.changes || 0) > 0
|
return (result.changes || 0) > 0
|
||||||
}
|
}
|
||||||
@ -298,15 +301,15 @@ export class SQLiteDatabase implements IDatabase {
|
|||||||
const stmt = this.db.prepare(
|
const stmt = this.db.prepare(
|
||||||
`INSERT INTO fitness_profiles
|
`INSERT INTO fitness_profiles
|
||||||
(userId, height, weight, age, gender, activityLevel, fitnessGoals,
|
(userId, height, weight, age, gender, activityLevel, fitnessGoals,
|
||||||
exerciseHabits, dietHabits, medicalConditions, createdAt, updatedAt)
|
exerciseHabits, dietHabits, medicalConditions, allergies, injuries, createdAt, updatedAt)
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
||||||
)
|
)
|
||||||
|
|
||||||
stmt.run(
|
stmt.run(
|
||||||
profile.userId, profile.height, profile.weight, profile.age, profile.gender,
|
profile.userId, profile.height, profile.weight, profile.age, profile.gender,
|
||||||
profile.activityLevel, JSON.stringify(profile.fitnessGoals), profile.exerciseHabits,
|
profile.activityLevel, JSON.stringify(profile.fitnessGoals), profile.exerciseHabits,
|
||||||
profile.dietHabits, profile.medicalConditions, profile.createdAt.toISOString(),
|
profile.dietHabits, profile.medicalConditions, profile.allergies, profile.injuries,
|
||||||
profile.updatedAt.toISOString()
|
profile.createdAt.toISOString(), profile.updatedAt.toISOString()
|
||||||
)
|
)
|
||||||
|
|
||||||
return profile
|
return profile
|
||||||
@ -468,6 +471,8 @@ export class SQLiteDatabase implements IDatabase {
|
|||||||
exerciseHabits: row.exerciseHabits,
|
exerciseHabits: row.exerciseHabits,
|
||||||
dietHabits: row.dietHabits,
|
dietHabits: row.dietHabits,
|
||||||
medicalConditions: row.medicalConditions,
|
medicalConditions: row.medicalConditions,
|
||||||
|
allergies: row.allergies,
|
||||||
|
injuries: row.injuries,
|
||||||
createdAt: new Date(row.createdAt),
|
createdAt: new Date(row.createdAt),
|
||||||
updatedAt: new Date(row.updatedAt)
|
updatedAt: new Date(row.updatedAt)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,6 +31,8 @@ export interface FitnessProfile {
|
|||||||
exerciseHabits: string;
|
exerciseHabits: string;
|
||||||
dietHabits: string;
|
dietHabits: string;
|
||||||
medicalConditions: string;
|
medicalConditions: string;
|
||||||
|
allergies?: string;
|
||||||
|
injuries?: string;
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
export const API_BASE_URL = __DEV__
|
export const API_BASE_URL = __DEV__
|
||||||
? 'https://5cb23f31d8c1.ngrok-free.app'
|
? 'https://390dfd6ece05.ngrok-free.app'
|
||||||
: 'https://your-production-url.com'
|
: 'https://your-production-url.com'
|
||||||
|
|
||||||
export const API_ENDPOINTS = {
|
export const API_ENDPOINTS = {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user