maj pricing, configuration du prisma

This commit is contained in:
2026-02-27 23:57:38 +01:00
parent 5268a7dd68
commit 521e529ab0
18 changed files with 358 additions and 42 deletions

Binary file not shown.

View File

@@ -1186,3 +1186,145 @@ FAM | META SEQ | SST SEQ | RANGE
0 | 00001084 | 00001083 SST | [=======================================================================] | 3aefa6fd5cf2deb4-f42f94001fcb5351 (0 MiB, fresh)
1 | 00001085 | 00001081 SST | O | b294a4237ccef201-b294a4237ccef201 (0 MiB, fresh)
2 | 00001086 | 00001082 SST | O | b294a4237ccef201-b294a4237ccef201 (0 MiB, fresh)
Time 2026-02-27T22:23:45.7991162Z
Commit 00001092 4 keys in 7ms 458µs 700ns
FAM | META SEQ | SST SEQ | RANGE
0 | 00001090 | 00001089 SST | [=======================================================================] | 3aefa6fd5cf2deb4-f42f94001fcb5351 (0 MiB, fresh)
1 | 00001091 | 00001087 SST | O | 3ffdfb3b7d50fcf1-3ffdfb3b7d50fcf1 (0 MiB, fresh)
2 | 00001092 | 00001088 SST | O | 3ffdfb3b7d50fcf1-3ffdfb3b7d50fcf1 (0 MiB, fresh)
Time 2026-02-27T22:24:07.5239402Z
Commit 00001098 4 keys in 8ms 395µs
FAM | META SEQ | SST SEQ | RANGE
0 | 00001096 | 00001095 SST | [=======================================================================] | 3aefa6fd5cf2deb4-f42f94001fcb5351 (0 MiB, fresh)
1 | 00001097 | 00001093 SST | O | 7c65b158fbf615ea-7c65b158fbf615ea (0 MiB, fresh)
2 | 00001098 | 00001094 SST | O | 7c65b158fbf615ea-7c65b158fbf615ea (0 MiB, fresh)
Time 2026-02-27T22:24:51.0510773Z
Commit 00001104 4 keys in 7ms 376µs 200ns
FAM | META SEQ | SST SEQ | RANGE
0 | 00001102 | 00001101 SST | [=======================================================================] | 3aefa6fd5cf2deb4-f42f94001fcb5351 (0 MiB, fresh)
1 | 00001103 | 00001099 SST | O | b294a4237ccef201-b294a4237ccef201 (0 MiB, fresh)
2 | 00001104 | 00001100 SST | O | b294a4237ccef201-b294a4237ccef201 (0 MiB, fresh)
Time 2026-02-27T22:25:32.4323043Z
Commit 00001114 42941 keys in 13ms 179µs 100ns
FAM | META SEQ | SST SEQ | RANGE
0 | 00001110 | 00001107 SST | [=======================================================================] | 3aefa6fd5cf2deb4-f42f94001fcb5351 (0 MiB, fresh)
4 | 00001111 | 00001108 SST | [==================================================================================================] | 000d7f96fa69734b-fff3b56bbe0e6b22 (0 MiB, fresh)
3 | 00001112 | 00001109 SST | [==================================================================================================] | 00017186f094d99a-fffbc6360ec1e50e (0 MiB, fresh)
2 | 00001113 | 00001105 SST | [==================================================================================================] | 000358d0de9d25d6-fff3b56bbe0e6b22 (12 MiB, fresh)
1 | 00001114 | 00001106 SST | [==================================================================================================] | 000358d0de9d25d6-ffffc8b261a62b07 (3 MiB, fresh)
Time 2026-02-27T22:26:46.8512199Z
Commit 00001120 16 keys in 5ms 869µs 900ns
FAM | META SEQ | SST SEQ | RANGE
0 | 00001118 | 00001117 SST | [=======================================================================] | 3aefa6fd5cf2deb4-f42f94001fcb5351 (0 MiB, fresh)
1 | 00001119 | 00001115 SST | [===========================================================================] | 2cf8041a3c23f4e1-ef311d8b965c9633 (0 MiB, fresh)
2 | 00001120 | 00001116 SST | [===========================================================================] | 2cf8041a3c23f4e1-ef311d8b965c9633 (0 MiB, fresh)
Time 2026-02-27T22:27:39.7821936Z
Commit 00001130 552 keys in 10ms 743µs 200ns
FAM | META SEQ | SST SEQ | RANGE
0 | 00001126 | 00001123 SST | [=======================================================================] | 3aefa6fd5cf2deb4-f42f94001fcb5351 (0 MiB, fresh)
1 | 00001127 | 00001121 SST | [==================================================================================================] | 0122a8bf9145a429-ffd2128295feedf0 (0 MiB, fresh)
2 | 00001128 | 00001122 SST | [==================================================================================================] | 0122a8bf9145a429-ffcb3bca70a06a01 (1 MiB, fresh)
3 | 00001129 | 00001124 SST | [============================] | 2ea1370e09bafd2c-7933b6079e0abaf9 (0 MiB, fresh)
4 | 00001130 | 00001125 SST | [===============================================================================================] | 0122a8bf9145a429-f5fce8eabd38c4f6 (0 MiB, fresh)
Time 2026-02-27T22:31:41.8511869Z
Commit 00001136 4 keys in 7ms 812µs 700ns
FAM | META SEQ | SST SEQ | RANGE
0 | 00001134 | 00001133 SST | [=======================================================================] | 3aefa6fd5cf2deb4-f42f94001fcb5351 (0 MiB, fresh)
1 | 00001135 | 00001131 SST | O | b294a4237ccef201-b294a4237ccef201 (0 MiB, fresh)
2 | 00001136 | 00001132 SST | O | b294a4237ccef201-b294a4237ccef201 (0 MiB, fresh)
Time 2026-02-27T22:36:39.2925341Z
Commit 00001142 4 keys in 16ms 160µs 100ns
FAM | META SEQ | SST SEQ | RANGE
0 | 00001140 | 00001139 SST | [=======================================================================] | 3aefa6fd5cf2deb4-f42f94001fcb5351 (0 MiB, fresh)
1 | 00001141 | 00001137 SST | O | 9c27d2b5acd6b310-9c27d2b5acd6b310 (0 MiB, fresh)
2 | 00001142 | 00001138 SST | O | 9c27d2b5acd6b310-9c27d2b5acd6b310 (0 MiB, fresh)
Time 2026-02-27T22:38:00.0546517Z
Commit 00001152 1197 keys in 8ms 370µs 900ns
FAM | META SEQ | SST SEQ | RANGE
0 | 00001148 | 00001145 SST | [=======================================================================] | 3aefa6fd5cf2deb4-f42f94001fcb5351 (0 MiB, fresh)
4 | 00001149 | 00001147 SST | [===============================================================================] | 2c3f3e9b0fcf379e-f9d23da1ef17dac4 (0 MiB, fresh)
1 | 00001150 | 00001143 SST | [==================================================================================================] | 0051cad80c47e3ca-fff3b56bbe0e6b22 (0 MiB, fresh)
2 | 00001151 | 00001144 SST | [==================================================================================================] | 0051cad80c47e3ca-fff3b56bbe0e6b22 (1 MiB, fresh)
3 | 00001152 | 00001146 SST | [=================================================================================================] | 0188fb9f3f3206db-fcc7ce8836ff7dad (0 MiB, fresh)
Time 2026-02-27T22:39:58.8664201Z
Commit 00001158 4 keys in 18ms 192µs 200ns
FAM | META SEQ | SST SEQ | RANGE
0 | 00001156 | 00001155 SST | [=======================================================================] | 3aefa6fd5cf2deb4-f42f94001fcb5351 (0 MiB, fresh)
1 | 00001157 | 00001153 SST | O | 9c27d2b5acd6b310-9c27d2b5acd6b310 (0 MiB, fresh)
2 | 00001158 | 00001154 SST | O | 9c27d2b5acd6b310-9c27d2b5acd6b310 (0 MiB, fresh)
Time 2026-02-27T22:41:05.9449247Z
Commit 00001164 4 keys in 6ms 778µs 700ns
FAM | META SEQ | SST SEQ | RANGE
0 | 00001162 | 00001161 SST | [=======================================================================] | 3aefa6fd5cf2deb4-f42f94001fcb5351 (0 MiB, fresh)
1 | 00001163 | 00001159 SST | O | b294a4237ccef201-b294a4237ccef201 (0 MiB, fresh)
2 | 00001164 | 00001160 SST | O | b294a4237ccef201-b294a4237ccef201 (0 MiB, fresh)
Time 2026-02-27T22:41:20.8865993Z
Commit 00001174 471 keys in 9ms 435µs 900ns
FAM | META SEQ | SST SEQ | RANGE
0 | 00001170 | 00001167 SST | [=======================================================================] | 3aefa6fd5cf2deb4-f42f94001fcb5351 (0 MiB, fresh)
1 | 00001171 | 00001166 SST | [==================================================================================================] | 02456d67aa55580e-ff244bc5fc918227 (0 MiB, fresh)
2 | 00001172 | 00001165 SST | [=================================================================================================] | 039acc1b0fc6d7ba-ff244bc5fc918227 (0 MiB, fresh)
4 | 00001173 | 00001169 SST | [===========================================================] | 34a53099b72e34e8-ccd9b11d9e21da11 (0 MiB, fresh)
3 | 00001174 | 00001168 SST | [==============================================] | 79b313ed90411b52-f130d5f225ab505d (0 MiB, fresh)
Time 2026-02-27T22:41:35.3513715Z
Commit 00001180 402 keys in 7ms 47µs 800ns
FAM | META SEQ | SST SEQ | RANGE
0 | 00001178 | 00001177 SST | [=======================================================================] | 3aefa6fd5cf2deb4-f42f94001fcb5351 (0 MiB, fresh)
1 | 00001179 | 00001176 SST | [==================================================================================================] | 02456d67aa55580e-fde1fb32301a48a2 (0 MiB, fresh)
2 | 00001180 | 00001175 SST | [=================================================================================================] | 033155d55f9205e6-fde1fb32301a48a2 (0 MiB, fresh)
Time 2026-02-27T22:41:51.8922682Z
Commit 00001186 113 keys in 6ms 917µs 600ns
FAM | META SEQ | SST SEQ | RANGE
0 | 00001184 | 00001183 SST | [=======================================================================] | 3aefa6fd5cf2deb4-f42f94001fcb5351 (0 MiB, fresh)
1 | 00001185 | 00001182 SST | [==============================================================================================] | 091a4d0e7a459a63-fd685e31821a9a2a (0 MiB, fresh)
2 | 00001186 | 00001181 SST | [==============================================================================================] | 091a4d0e7a459a63-fd685e31821a9a2a (0 MiB, fresh)
Time 2026-02-27T22:43:41.5896953Z
Commit 00001192 4 keys in 17ms 184µs 600ns
FAM | META SEQ | SST SEQ | RANGE
0 | 00001190 | 00001189 SST | [=======================================================================] | 3aefa6fd5cf2deb4-f42f94001fcb5351 (0 MiB, fresh)
1 | 00001191 | 00001187 SST | O | 801410113b08be83-801410113b08be83 (0 MiB, fresh)
2 | 00001192 | 00001188 SST | O | 801410113b08be83-801410113b08be83 (0 MiB, fresh)
Time 2026-02-27T22:43:46.0460894Z
Commit 00001198 138 keys in 7ms 734µs 500ns
FAM | META SEQ | SST SEQ | RANGE
0 | 00001196 | 00001195 SST | [=======================================================================] | 3aefa6fd5cf2deb4-f42f94001fcb5351 (0 MiB, fresh)
1 | 00001197 | 00001193 SST | [==============================================================================================] | 068941e9d0822cac-fa0c8e3889b99225 (0 MiB, fresh)
2 | 00001198 | 00001194 SST | [==============================================================================================] | 079dd3476a605273-fa0c8e3889b99225 (0 MiB, fresh)
Time 2026-02-27T22:43:52.3186156Z
Commit 00001208 2850 keys in 12ms 413µs 100ns
FAM | META SEQ | SST SEQ | RANGE
0 | 00001204 | 00001201 SST | [=======================================================================] | 3aefa6fd5cf2deb4-f42f94001fcb5351 (0 MiB, fresh)
1 | 00001205 | 00001200 SST | [==================================================================================================] | 000d168784b3a904-ffd966598c8595fa (0 MiB, fresh)
2 | 00001206 | 00001199 SST | [==================================================================================================] | 000d168784b3a904-ffd966598c8595fa (6 MiB, fresh)
4 | 00001207 | 00001203 SST | [======================================================================================] | 11197b47441eeea3-ef50ee266882e5d2 (0 MiB, fresh)
3 | 00001208 | 00001202 SST | [================================================================================] | 08f2403670664437-d8b58dce5e27a8c1 (0 MiB, fresh)
Time 2026-02-27T22:46:59.9016919Z
Commit 00001214 1167 keys in 7ms 183µs 900ns
FAM | META SEQ | SST SEQ | RANGE
0 | 00001212 | 00001211 SST | [=======================================================================] | 3aefa6fd5cf2deb4-f42f94001fcb5351 (0 MiB, fresh)
2 | 00001213 | 00001209 SST | [=================================================================================================] | 0315bd6ef0760e1f-ff1373558b528b52 (0 MiB, fresh)
1 | 00001214 | 00001210 SST | [==================================================================================================] | 0013a9e4f34335e5-ffd284765f657204 (0 MiB, fresh)
Time 2026-02-27T22:47:04.8464823Z
Commit 00001220 1262 keys in 7ms 686µs 900ns
FAM | META SEQ | SST SEQ | RANGE
0 | 00001218 | 00001217 SST | [=======================================================================] | 3aefa6fd5cf2deb4-f42f94001fcb5351 (0 MiB, fresh)
2 | 00001219 | 00001215 SST | [=================================================================================================] | 015aa7af8c46be57-fcc735cb29041d9f (0 MiB, fresh)
1 | 00001220 | 00001216 SST | [==================================================================================================] | 0013a9e4f34335e5-ffd284765f657204 (0 MiB, fresh)
Time 2026-02-27T22:47:07.7562717Z
Commit 00001226 153 keys in 6ms 548µs 600ns
FAM | META SEQ | SST SEQ | RANGE
0 | 00001224 | 00001223 SST | [=======================================================================] | 3aefa6fd5cf2deb4-f42f94001fcb5351 (0 MiB, fresh)
1 | 00001225 | 00001222 SST | [=================================================================================================] | 03b97b635740d863-ffe64bbd36bacfc8 (0 MiB, fresh)
2 | 00001226 | 00001221 SST | [==================================================================================================] | 0145c5bca32c1494-ffe64bbd36bacfc8 (0 MiB, fresh)
Time 2026-02-27T22:47:14.3947061Z
Commit 00001232 24 keys in 6ms 166µs 500ns
FAM | META SEQ | SST SEQ | RANGE
0 | 00001230 | 00001229 SST | [=======================================================================] | 3aefa6fd5cf2deb4-f42f94001fcb5351 (0 MiB, fresh)
2 | 00001231 | 00001227 SST | [==========================================================================] | 069e2de91159e9cb-c5c647feca328c20 (0 MiB, fresh)
1 | 00001232 | 00001228 SST | [==========================================================================] | 069e2de91159e9cb-c5c647feca328c20 (0 MiB, fresh)
Time 2026-02-27T22:47:26.9424667Z
Commit 00001238 38 keys in 6ms 11µs 700ns
FAM | META SEQ | SST SEQ | RANGE
0 | 00001236 | 00001235 SST | [=======================================================================] | 3aefa6fd5cf2deb4-f42f94001fcb5351 (0 MiB, fresh)
1 | 00001237 | 00001234 SST | [====================================================================================] | 14f643c3d8584875-ef63e6a8b41c1ab5 (0 MiB, fresh)
2 | 00001238 | 00001233 SST | [=======================================================================] | 14f643c3d8584875-cd73069ab87dfc3d (0 MiB, fresh)

View File

@@ -4,8 +4,8 @@
"dynamicRoutes": {},
"notFoundRoutes": [],
"preview": {
"previewModeId": "a5ff04373568f8dfa89f5541b80f2935",
"previewModeSigningKey": "2b0018d3eaa31eeed67538d28afe4bfa7f66d57b8a2348421bb8a3837addb402",
"previewModeEncryptionKey": "553a3f71589831fc06cdc67a076ecfc594777a8dbcadba910eef5fe42f0bcadb"
"previewModeId": "64ea03a229f653828766a3654a7623ec",
"previewModeSigningKey": "477cbefb1eecc6237c332fd49918940f0b1f05d16c6d81d9be2d54305396dfd2",
"previewModeEncryptionKey": "9891e33f98087cd438ebe3cf068e3cf30985af06afb29929d98c4209d4b3e460"
}
}

View File

@@ -1,12 +1,11 @@
{
"/api/auth/[...nextauth]/route": "app/api/auth/[...nextauth]/route.js",
"/api/entities/route": "app/api/entities/route.js",
"/api/projects/[id]/route": "app/api/projects/[id]/route.js",
"/api/auth/register/route": "app/api/auth/register/route.js",
"/api/projects/route": "app/api/projects/route.js",
"/api/user/profile/route": "app/api/user/profile/route.js",
"/dashboard/page": "app/dashboard/page.js",
"/login/page": "app/login/page.js",
"/page": "app/page.js",
"/project/[id]/page": "app/project/[id]/page.js",
"/project/[id]/world/page": "app/project/[id]/world/page.js"
"/profile/page": "app/profile/page.js",
"/signup/page": "app/signup/page.js"
}

View File

@@ -52,6 +52,15 @@ const api = {
});
}
},
// --- USER ---
user: {
async updateProfile (data) {
return api.request('/user/profile', {
method: 'PUT',
body: JSON.stringify(data)
});
}
},
// --- PROJECTS ---
projects: {
async list () {
@@ -308,12 +317,36 @@ const useAuth = ()=>{
}, [
user
]);
const updateProfile = (0, __TURBOPACK__imported__module__$5b$project$5d2f$Documents$2f$00__$2d$__projet$2f$plumeia$2f$node_modules$2f$next$2f$dist$2f$server$2f$route$2d$modules$2f$app$2d$page$2f$vendored$2f$ssr$2f$react$2e$js__$5b$app$2d$ssr$5d$__$28$ecmascript$29$__["useCallback"])(async (updates)=>{
if (!user) return;
try {
// Unpack everything that can be updated into a flat object for the API
const apiUpdates = {};
if (updates.name !== undefined) apiUpdates.name = updates.name;
if (updates.avatar !== undefined) apiUpdates.avatar = updates.avatar;
if (updates.bio !== undefined) apiUpdates.bio = updates.bio;
if (updates.preferences?.dailyWordGoal !== undefined) apiUpdates.dailyWordGoal = updates.preferences.dailyWordGoal;
// Make the API call to update DB
await __TURBOPACK__imported__module__$5b$project$5d2f$Documents$2f$00__$2d$__projet$2f$plumeia$2f$src$2f$lib$2f$api$2e$ts__$5b$app$2d$ssr$5d$__$28$ecmascript$29$__["default"].user.updateProfile(apiUpdates);
// Update local state
setUser((prev)=>prev ? {
...prev,
...updates
} : null);
} catch (err) {
console.error('Failed to update profile:', err);
throw err;
}
}, [
user
]);
return {
user,
login,
signup,
logout,
incrementUsage,
updateProfile,
loading
};
};

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
self.__NEXT_FONT_MANIFEST="{\n \"app\": {\n \"[project]/Documents/00 - projet/plumeia/src/app/dashboard/page\": [\n \"static/media/83afe278b6a6bb3c-s.p.3a6ba036.woff2\",\n \"static/media/248e1dc0efc99276-s.p.8a6b2436.woff2\"\n ],\n \"[project]/Documents/00 - projet/plumeia/src/app/login/page\": [\n \"static/media/83afe278b6a6bb3c-s.p.3a6ba036.woff2\",\n \"static/media/248e1dc0efc99276-s.p.8a6b2436.woff2\"\n ],\n \"[project]/Documents/00 - projet/plumeia/src/app/page\": [\n \"static/media/83afe278b6a6bb3c-s.p.3a6ba036.woff2\",\n \"static/media/248e1dc0efc99276-s.p.8a6b2436.woff2\"\n ],\n \"[project]/Documents/00 - projet/plumeia/src/app/project/[id]/page\": [\n \"static/media/83afe278b6a6bb3c-s.p.3a6ba036.woff2\",\n \"static/media/248e1dc0efc99276-s.p.8a6b2436.woff2\"\n ],\n \"[project]/Documents/00 - projet/plumeia/src/app/project/[id]/world/page\": [\n \"static/media/83afe278b6a6bb3c-s.p.3a6ba036.woff2\",\n \"static/media/248e1dc0efc99276-s.p.8a6b2436.woff2\"\n ]\n },\n \"appUsingSizeAdjust\": true,\n \"pages\": {},\n \"pagesUsingSizeAdjust\": false\n}"
self.__NEXT_FONT_MANIFEST="{\n \"app\": {\n \"[project]/Documents/00 - projet/plumeia/src/app/dashboard/page\": [\n \"static/media/83afe278b6a6bb3c-s.p.3a6ba036.woff2\",\n \"static/media/248e1dc0efc99276-s.p.8a6b2436.woff2\"\n ],\n \"[project]/Documents/00 - projet/plumeia/src/app/login/page\": [\n \"static/media/83afe278b6a6bb3c-s.p.3a6ba036.woff2\",\n \"static/media/248e1dc0efc99276-s.p.8a6b2436.woff2\"\n ],\n \"[project]/Documents/00 - projet/plumeia/src/app/page\": [\n \"static/media/83afe278b6a6bb3c-s.p.3a6ba036.woff2\",\n \"static/media/248e1dc0efc99276-s.p.8a6b2436.woff2\"\n ],\n \"[project]/Documents/00 - projet/plumeia/src/app/profile/page\": [\n \"static/media/83afe278b6a6bb3c-s.p.3a6ba036.woff2\",\n \"static/media/248e1dc0efc99276-s.p.8a6b2436.woff2\"\n ],\n \"[project]/Documents/00 - projet/plumeia/src/app/signup/page\": [\n \"static/media/83afe278b6a6bb3c-s.p.3a6ba036.woff2\",\n \"static/media/248e1dc0efc99276-s.p.8a6b2436.woff2\"\n ]\n },\n \"appUsingSizeAdjust\": true,\n \"pages\": {},\n \"pagesUsingSizeAdjust\": false\n}"

View File

@@ -12,11 +12,11 @@
"static/media/83afe278b6a6bb3c-s.p.3a6ba036.woff2",
"static/media/248e1dc0efc99276-s.p.8a6b2436.woff2"
],
"[project]/Documents/00 - projet/plumeia/src/app/project/[id]/page": [
"[project]/Documents/00 - projet/plumeia/src/app/profile/page": [
"static/media/83afe278b6a6bb3c-s.p.3a6ba036.woff2",
"static/media/248e1dc0efc99276-s.p.8a6b2436.woff2"
],
"[project]/Documents/00 - projet/plumeia/src/app/project/[id]/world/page": [
"[project]/Documents/00 - projet/plumeia/src/app/signup/page": [
"static/media/83afe278b6a6bb3c-s.p.3a6ba036.woff2",
"static/media/248e1dc0efc99276-s.p.8a6b2436.woff2"
]

View File

@@ -46,6 +46,15 @@ const api = {
});
}
},
// --- USER ---
user: {
async updateProfile (data) {
return api.request('/user/profile', {
method: 'PUT',
body: JSON.stringify(data)
});
}
},
// --- PROJECTS ---
projects: {
async list () {
@@ -323,16 +332,44 @@ const useAuth = ()=>{
}["useAuth.useCallback[incrementUsage]"], [
user
]);
const updateProfile = (0, __TURBOPACK__imported__module__$5b$project$5d2f$Documents$2f$00__$2d$__projet$2f$plumeia$2f$node_modules$2f$next$2f$dist$2f$compiled$2f$react$2f$index$2e$js__$5b$app$2d$client$5d$__$28$ecmascript$29$__["useCallback"])({
"useAuth.useCallback[updateProfile]": async (updates)=>{
if (!user) return;
try {
// Unpack everything that can be updated into a flat object for the API
const apiUpdates = {};
if (updates.name !== undefined) apiUpdates.name = updates.name;
if (updates.avatar !== undefined) apiUpdates.avatar = updates.avatar;
if (updates.bio !== undefined) apiUpdates.bio = updates.bio;
if (updates.preferences?.dailyWordGoal !== undefined) apiUpdates.dailyWordGoal = updates.preferences.dailyWordGoal;
// Make the API call to update DB
await __TURBOPACK__imported__module__$5b$project$5d2f$Documents$2f$00__$2d$__projet$2f$plumeia$2f$src$2f$lib$2f$api$2e$ts__$5b$app$2d$client$5d$__$28$ecmascript$29$__["default"].user.updateProfile(apiUpdates);
// Update local state
setUser({
"useAuth.useCallback[updateProfile]": (prev)=>prev ? {
...prev,
...updates
} : null
}["useAuth.useCallback[updateProfile]"]);
} catch (err) {
console.error('Failed to update profile:', err);
throw err;
}
}
}["useAuth.useCallback[updateProfile]"], [
user
]);
return {
user,
login,
signup,
logout,
incrementUsage,
updateProfile,
loading
};
};
_s(useAuth, "NTps7lD2LRTcy9ISlNr85D5h8IY=", false, function() {
_s(useAuth, "BDPqFrun1TL0uUzYZo247zjajj4=", false, function() {
return [
__TURBOPACK__imported__module__$5b$project$5d2f$Documents$2f$00__$2d$__projet$2f$plumeia$2f$node_modules$2f$next$2d$auth$2f$react$2e$js__$5b$app$2d$client$5d$__$28$ecmascript$29$__["useSession"]
];

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -9,6 +9,7 @@ export default defineConfig({
schema: "prisma/schema.prisma",
migrations: {
path: "prisma/migrations",
seed: "tsx prisma/seed.ts",
},
datasource: {
url: process.env["DATABASE_URL"],

View File

@@ -31,6 +31,7 @@ model User {
email String @unique
hashedPassword String
bio String?
avatar String?
// Legacy string plan (temporarily kept to avoid DB drop errors)
plan String @default("free")

View File

@@ -25,9 +25,9 @@ async function main() {
displayName: 'Auteur Pro',
price: 12,
description: 'Pour les écrivains sérieux.',
maxProjects: -1, // -1 means unlimited
maxAiActions: 500,
features: ['500 actions IA / mois', 'Projets illimités', 'Export Word & EPUB', 'Support prioritaire'],
maxProjects: 5, // -1 means unlimited
maxAiActions: 75,
features: ['75 actions IA / mois', 'Projets illimités', 'Export Word & EPUB', 'Support prioritaire'],
isPopular: true,
},
{
@@ -36,9 +36,9 @@ async function main() {
displayName: 'Maître Plume',
price: 29,
description: 'Le summum de l\'écriture IA.',
maxProjects: -1,
maxAiActions: -1, // -1 means unlimited
features: ['Actions IA illimitées', 'Accès Gemini 3 Pro', 'Bible du monde avancée', 'Outils de révision avancés'],
maxProjects: 20,
maxAiActions: 250, // -1 means unlimited
features: ['250 actions IA / mois', 'Accès Gemini 3 Pro', 'Bible du monde avancée', 'Outils de révision avancés'],
isPopular: false,
},
];

View File

@@ -7,7 +7,7 @@ import { useEffect } from 'react';
export default function ProfilePage() {
const router = useRouter();
const { user, loading } = useAuthContext();
const { user, loading, updateProfile } = useAuthContext();
useEffect(() => {
if (!loading && !user) {
@@ -20,7 +20,13 @@ export default function ProfilePage() {
return (
<UserProfileSettings
user={user}
onUpdate={(updates) => console.log('Profile update:', updates)}
onUpdate={async (updates) => {
try {
await updateProfile(updates);
} catch (err) {
// Handled inside updateProfile (console.error)
}
}}
onBack={() => router.push('/dashboard')}
/>
);

View File

@@ -23,15 +23,58 @@ const UserProfileSettings: React.FC<UserProfileSettingsProps> = ({ user, onUpdat
const [activeTab, setActiveTab] = useState<'profile' | 'preferences' | 'account'>('profile');
const [formData, setFormData] = useState({
name: user.name,
avatar: user.avatar || '',
bio: user.bio || '',
email: user.email,
theme: user.preferences.theme,
dailyWordGoal: user.preferences.dailyWordGoal
});
const fileInputRef = React.useRef<HTMLInputElement>(null);
const handleImageUpload = (event: React.ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0];
if (!file) return;
if (!file.type.startsWith('image/')) {
alert('Veuillez sélectionner une image valide.');
return;
}
const reader = new FileReader();
reader.onload = (e) => {
const img = new Image();
img.onload = () => {
const MAX_SIZE = 256;
let width = img.width;
let height = img.height;
if (width > height && width > MAX_SIZE) {
height = Math.round((height * MAX_SIZE) / width);
width = MAX_SIZE;
} else if (height > MAX_SIZE) {
width = Math.round((width * MAX_SIZE) / height);
height = MAX_SIZE;
}
const canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext('2d');
if (ctx) {
ctx.drawImage(img, 0, 0, width, height);
const dataUrl = canvas.toDataURL('image/jpeg', 0.8);
setFormData(prev => ({ ...prev, avatar: dataUrl }));
}
};
img.src = e.target?.result as string;
};
reader.readAsDataURL(file);
};
const handleSave = () => {
onUpdate({
name: formData.name,
avatar: formData.avatar,
bio: formData.bio,
email: formData.email,
preferences: {
@@ -82,11 +125,18 @@ const UserProfileSettings: React.FC<UserProfileSettingsProps> = ({ user, onUpdat
{activeTab === 'profile' && (
<div className="space-y-8 animate-in fade-in slide-in-from-bottom-4 duration-300">
<div className="flex items-center gap-6 pb-8 border-b border-slate-100">
<div className="relative group">
<img src={user.avatar} className="w-24 h-24 rounded-full object-cover border-4 border-slate-50 shadow-md" alt="Avatar" />
<button className="absolute inset-0 bg-black/40 text-white rounded-full opacity-0 group-hover:opacity-100 flex items-center justify-center transition-opacity">
<div className="relative group cursor-pointer" onClick={() => fileInputRef.current?.click()}>
<input
type="file"
ref={fileInputRef}
onChange={handleImageUpload}
accept="image/*"
className="hidden"
/>
<img src={formData.avatar || 'https://via.placeholder.com/150'} className="w-24 h-24 rounded-full object-cover border-4 border-slate-50 shadow-md" alt="Avatar" />
<div className="absolute inset-0 bg-black/40 text-white rounded-full opacity-0 group-hover:opacity-100 flex items-center justify-center transition-opacity" title="Changer d'avatar">
<Camera size={20} />
</button>
</div>
</div>
<div>
<h3 className="font-bold text-slate-900 text-lg">{user.name}</h3>
@@ -109,6 +159,7 @@ const UserProfileSettings: React.FC<UserProfileSettingsProps> = ({ user, onUpdat
className="w-full p-3 bg-slate-50 border border-slate-200 rounded-xl outline-none focus:ring-2 focus:ring-blue-500"
/>
</div>
<div className="space-y-1">
<label className="text-xs font-black text-slate-400 uppercase tracking-widest">Bio / Citation inspirante</label>
<textarea

View File

@@ -111,5 +111,27 @@ export const useAuth = () => {
}
}, [user]);
return { user, login, signup, logout, incrementUsage, loading };
const updateProfile = useCallback(async (updates: Partial<UserProfile>) => {
if (!user) return;
try {
// Unpack everything that can be updated into a flat object for the API
const apiUpdates: any = {};
if (updates.name !== undefined) apiUpdates.name = updates.name;
if (updates.avatar !== undefined) apiUpdates.avatar = updates.avatar;
if (updates.bio !== undefined) apiUpdates.bio = updates.bio;
if (updates.preferences?.dailyWordGoal !== undefined) apiUpdates.dailyWordGoal = updates.preferences.dailyWordGoal;
// Make the API call to update DB
await api.user.updateProfile(apiUpdates);
// Update local state
setUser(prev => prev ? { ...prev, ...updates } : null);
} catch (err) {
console.error('Failed to update profile:', err);
throw err;
}
}, [user]);
return { user, login, signup, logout, incrementUsage, updateProfile, loading };
};

View File

@@ -44,6 +44,16 @@ const api = {
},
},
// --- USER ---
user: {
async updateProfile(data: any) {
return api.request('/user/profile', {
method: 'PUT',
body: JSON.stringify(data),
});
},
},
// --- PROJECTS ---
projects: {
async list() {