@harperfast/harper-pro 5.0.0-alpha.9 → 5.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (181) hide show
  1. package/core/.dockerignore +9 -0
  2. package/core/.git-blame-ignore-revs +2 -0
  3. package/core/.github/workflows/create-release.yaml +4 -4
  4. package/core/.github/workflows/integration-tests.yml +12 -10
  5. package/core/.github/workflows/notify-release-published.yaml +1 -1
  6. package/core/.github/workflows/publish-docker.yaml +2 -2
  7. package/core/.github/workflows/publish-npm.yaml +4 -4
  8. package/core/CONTRIBUTING.md +1 -1
  9. package/core/Dockerfile +62 -0
  10. package/core/build-tools/build-studio.sh +12 -0
  11. package/core/build-tools/build.sh +22 -0
  12. package/core/build-tools/download-prebuilds.js +13 -0
  13. package/core/components/Logger.ts +14 -0
  14. package/core/components/Scope.ts +35 -11
  15. package/core/components/componentLoader.ts +27 -10
  16. package/core/components/operations.js +10 -2
  17. package/core/config/configUtils.js +1 -1
  18. package/core/dataLayer/CreateTableObject.js +2 -2
  19. package/core/dataLayer/schema.js +7 -5
  20. package/core/dataLayer/schemaDescribe.js +1 -1
  21. package/core/index.d.ts +11 -6
  22. package/core/index.js +2 -0
  23. package/core/integrationTests/README.md +24 -0
  24. package/core/integrationTests/apiTests/tests/10_otherRoleTests.mjs +6 -6
  25. package/core/integrationTests/apiTests/tests/12_configuration.mjs +1 -1
  26. package/core/integrationTests/apiTests/tests/14_tokenAuth.mjs +2 -2
  27. package/core/integrationTests/apiTests/tests/16_terminologyUpdates.mjs +4 -4
  28. package/core/integrationTests/apiTests/tests/1_environmentSetup.mjs +1 -1
  29. package/core/integrationTests/apiTests/tests/2_dataLoad.mjs +4 -4
  30. package/core/integrationTests/apiTests/tests/3_sqlTests.mjs +3 -3
  31. package/core/integrationTests/apiTests/tests/4_noSqlTests.mjs +12 -12
  32. package/core/integrationTests/apiTests/tests/5_noSqlRoleTesting.mjs +8 -8
  33. package/core/integrationTests/apiTests/tests/7_jobsAndJobRoleTesting.mjs +10 -12
  34. package/core/integrationTests/apiTests/tests/8_deleteTests.mjs +8 -8
  35. package/core/integrationTests/apiTests/tests/9_transactions.mjs +2 -2
  36. package/core/integrationTests/apiTests/utils/search.mjs +1 -1
  37. package/core/integrationTests/apiTests/utils/table.mjs +1 -1
  38. package/core/integrationTests/server/operation-user-rbac.test.ts +1 -1
  39. package/core/integrationTests/server/operations-server.test.ts +1 -1
  40. package/core/integrationTests/server/storage-reclamation.test.ts +1 -1
  41. package/core/integrationTests/utils/README.md +1 -15
  42. package/core/integrationTests/utils/harperLifecycle.ts +33 -21
  43. package/core/package.json +23 -5
  44. package/core/resources/ResourceInterface.ts +1 -1
  45. package/core/resources/Table.ts +26 -11
  46. package/core/resources/analytics/read.ts +33 -26
  47. package/core/resources/analytics/write.ts +3 -7
  48. package/core/resources/databases.ts +29 -18
  49. package/core/resources/search.ts +10 -5
  50. package/core/security/auth.ts +1 -1
  51. package/core/security/jsLoader.ts +302 -83
  52. package/core/security/keys.js +11 -12
  53. package/core/security/user.ts +3 -3
  54. package/core/server/REST.ts +18 -2
  55. package/core/server/Server.ts +2 -1
  56. package/core/server/fastifyRoutes.ts +1 -0
  57. package/core/server/http.ts +13 -9
  58. package/core/server/loadRootComponents.js +1 -0
  59. package/core/server/operationsServer.ts +2 -1
  60. package/core/server/threads/manageThreads.js +49 -35
  61. package/core/static/defaultConfig.yaml +3 -0
  62. package/core/unitTests/apiTests/RESTProperties-test.mjs +2 -2
  63. package/core/unitTests/apiTests/basicREST-test.mjs +2 -2
  64. package/core/unitTests/components/Scope.test.js +54 -16
  65. package/core/unitTests/components/fixtures/testJSWithDeps/child-dir/circular.js +4 -0
  66. package/core/unitTests/components/fixtures/testJSWithDeps/child-dir/in-child-dir.js +4 -0
  67. package/core/unitTests/components/fixtures/testJSWithDeps/child-dir/typestrip.ts +2 -0
  68. package/core/unitTests/components/fixtures/testJSWithDeps/resources.js +43 -0
  69. package/core/unitTests/components/fixtures/testJSWithDeps/test-child-process.js +18 -0
  70. package/core/unitTests/components/globalIsolation.test.js +87 -1
  71. package/core/unitTests/config/configUtils.test.js +1 -260
  72. package/core/unitTests/resources/query.test.js +16 -1
  73. package/core/unitTests/resources/vectorIndex.test.js +1 -1
  74. package/core/unitTests/server/fastifyRoutes/operations.test.js +1 -1
  75. package/core/unitTests/testUtils.js +0 -17
  76. package/core/utility/hdbTerms.ts +3 -0
  77. package/core/utility/installation.ts +2 -5
  78. package/core/utility/lmdb/commonUtility.js +21 -10
  79. package/dist/core/{resources/ResourceInterfaceV2.js → components/Logger.js} +1 -1
  80. package/dist/core/components/Logger.js.map +1 -0
  81. package/dist/core/components/Scope.js +18 -10
  82. package/dist/core/components/Scope.js.map +1 -1
  83. package/dist/core/components/componentLoader.js +17 -10
  84. package/dist/core/components/componentLoader.js.map +1 -1
  85. package/dist/core/components/operations.js +2 -2
  86. package/dist/core/components/operations.js.map +1 -1
  87. package/dist/core/config/configUtils.js +1 -1
  88. package/dist/core/config/configUtils.js.map +1 -1
  89. package/dist/core/dataLayer/CreateTableObject.js +2 -2
  90. package/dist/core/dataLayer/CreateTableObject.js.map +1 -1
  91. package/dist/core/dataLayer/schema.js +6 -5
  92. package/dist/core/dataLayer/schema.js.map +1 -1
  93. package/dist/core/dataLayer/schemaDescribe.js +1 -1
  94. package/dist/core/dataLayer/schemaDescribe.js.map +1 -1
  95. package/dist/core/index.js +2 -0
  96. package/dist/core/index.js.map +1 -1
  97. package/dist/core/resources/Table.js +12 -4
  98. package/dist/core/resources/Table.js.map +1 -1
  99. package/dist/core/resources/analytics/read.js +32 -22
  100. package/dist/core/resources/analytics/read.js.map +1 -1
  101. package/dist/core/resources/analytics/write.js +3 -6
  102. package/dist/core/resources/analytics/write.js.map +1 -1
  103. package/dist/core/resources/databases.js +22 -19
  104. package/dist/core/resources/databases.js.map +1 -1
  105. package/dist/core/resources/search.js +11 -5
  106. package/dist/core/resources/search.js.map +1 -1
  107. package/dist/core/security/auth.js +1 -1
  108. package/dist/core/security/auth.js.map +1 -1
  109. package/dist/core/security/jsLoader.js +265 -73
  110. package/dist/core/security/jsLoader.js.map +1 -1
  111. package/dist/core/security/keys.js +11 -12
  112. package/dist/core/security/keys.js.map +1 -1
  113. package/dist/core/security/user.js +3 -3
  114. package/dist/core/security/user.js.map +1 -1
  115. package/dist/core/server/REST.js +16 -2
  116. package/dist/core/server/REST.js.map +1 -1
  117. package/dist/core/server/Server.js.map +1 -1
  118. package/dist/core/server/fastifyRoutes.js +2 -0
  119. package/dist/core/server/fastifyRoutes.js.map +1 -1
  120. package/dist/core/server/http.js +12 -6
  121. package/dist/core/server/http.js.map +1 -1
  122. package/dist/core/server/loadRootComponents.js +1 -0
  123. package/dist/core/server/loadRootComponents.js.map +1 -1
  124. package/dist/core/server/operationsServer.js +3 -1
  125. package/dist/core/server/operationsServer.js.map +1 -1
  126. package/dist/core/server/threads/manageThreads.js +50 -35
  127. package/dist/core/server/threads/manageThreads.js.map +1 -1
  128. package/dist/core/utility/hdbTerms.js +3 -0
  129. package/dist/core/utility/hdbTerms.js.map +1 -1
  130. package/dist/core/utility/installation.js.map +1 -1
  131. package/dist/core/utility/lmdb/commonUtility.js +20 -13
  132. package/dist/core/utility/lmdb/commonUtility.js.map +1 -1
  133. package/dist/licensing/usageLicensing.js.map +1 -1
  134. package/dist/replication/knownNodes.js +5 -37
  135. package/dist/replication/knownNodes.js.map +1 -1
  136. package/dist/replication/nodeIdMapping.js +2 -35
  137. package/dist/replication/nodeIdMapping.js.map +1 -1
  138. package/dist/replication/replicationConnection.js +15 -6
  139. package/dist/replication/replicationConnection.js.map +1 -1
  140. package/dist/replication/replicator.js +3 -2
  141. package/dist/replication/replicator.js.map +1 -1
  142. package/dist/replication/setNode.js +1 -1
  143. package/dist/replication/setNode.js.map +1 -1
  144. package/dist/security/certificate.js.map +1 -1
  145. package/licensing/usageLicensing.ts +3 -2
  146. package/npm-shrinkwrap.json +303 -282
  147. package/package.json +4 -3
  148. package/replication/knownNodes.ts +3 -2
  149. package/replication/nodeIdMapping.ts +1 -1
  150. package/replication/replicationConnection.ts +33 -8
  151. package/replication/replicator.ts +7 -2
  152. package/replication/setNode.ts +1 -1
  153. package/security/certificate.ts +2 -1
  154. package/studio/web/assets/{index-v3wIpSYx.js → index-CWN9Wp5V.js} +2 -2
  155. package/studio/web/assets/{index-v3wIpSYx.js.map → index-CWN9Wp5V.js.map} +1 -1
  156. package/studio/web/assets/{index-ChCctErQ.js → index-CzghSAn2.js} +2 -2
  157. package/studio/web/assets/{index-ChCctErQ.js.map → index-CzghSAn2.js.map} +1 -1
  158. package/studio/web/assets/{index-Qu8D43wo.js → index-DMDhGP7N.js} +5 -5
  159. package/studio/web/assets/{index-Qu8D43wo.js.map → index-DMDhGP7N.js.map} +1 -1
  160. package/studio/web/assets/{index.lazy-tVSPM7bX.js → index.lazy-C-yDTGUy.js} +2 -2
  161. package/studio/web/assets/{index.lazy-tVSPM7bX.js.map → index.lazy-C-yDTGUy.js.map} +1 -1
  162. package/studio/web/assets/{profiler-C9as4sv-.js → profiler-0fZAOscv.js} +2 -2
  163. package/studio/web/assets/{profiler-C9as4sv-.js.map → profiler-0fZAOscv.js.map} +1 -1
  164. package/studio/web/assets/{react-redux-RRIhZnM6.js → react-redux-BIxqK8O6.js} +2 -2
  165. package/studio/web/assets/{react-redux-RRIhZnM6.js.map → react-redux-BIxqK8O6.js.map} +1 -1
  166. package/studio/web/assets/{startRecording-DYa4zCXV.js → startRecording-Ca3Gf2MY.js} +2 -2
  167. package/studio/web/assets/{startRecording-DYa4zCXV.js.map → startRecording-Ca3Gf2MY.js.map} +1 -1
  168. package/studio/web/index.html +1 -1
  169. package/core/resources/ResourceInterfaceV2.ts +0 -53
  170. package/core/resources/ResourceV2.ts +0 -67
  171. package/core/resources/analytics/profile.ts +0 -109
  172. package/core/unitTests/apiTests/analytics-test.mjs +0 -38
  173. package/core/v1.d.ts +0 -47
  174. package/core/v1.js +0 -38
  175. package/core/v2.d.ts +0 -47
  176. package/core/v2.js +0 -38
  177. package/dist/core/resources/ResourceInterfaceV2.js.map +0 -1
  178. package/dist/core/resources/ResourceV2.js +0 -27
  179. package/dist/core/resources/ResourceV2.js.map +0 -1
  180. package/dist/core/resources/analytics/profile.js +0 -144
  181. package/dist/core/resources/analytics/profile.js.map +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@harperfast/harper-pro",
3
- "version": "5.0.0-alpha.9",
3
+ "version": "5.0.0-beta.2",
4
4
  "description": "Harper is a distributed database, caching service, streaming broker, and application development platform focused on performance and ease of use.",
5
5
  "keywords": [
6
6
  "database",
@@ -80,7 +80,7 @@
80
80
  "@fastify/cors": "~9.0.1",
81
81
  "@fastify/static": "~7.0.4",
82
82
  "@harperfast/extended-iterable": "^1.0.1",
83
- "@harperfast/rocksdb-js": "^0.1.11",
83
+ "@harperfast/rocksdb-js": "^0.1.12",
84
84
  "@turf/area": "6.5.0",
85
85
  "@turf/boolean-contains": "6.5.0",
86
86
  "@turf/boolean-disjoint": "6.5.0",
@@ -91,6 +91,7 @@
91
91
  "@turf/helpers": "6.5.0",
92
92
  "@turf/length": "6.5.0",
93
93
  "alasql": "4.6.6",
94
+ "amaro": "^1.1.8",
94
95
  "argon2": "0.44.0",
95
96
  "asn1js": "3.0.7",
96
97
  "cbor-x": "1.6.4",
@@ -115,7 +116,7 @@
115
116
  "json2csv": "5.0.7",
116
117
  "jsonata": "1.8.7",
117
118
  "jsonwebtoken": "9.0.3",
118
- "lmdb": "3.5.1",
119
+ "lmdb": "3.5.2",
119
120
  "lodash": "4.17.21",
120
121
  "mathjs": "11.12.0",
121
122
  "micromatch": "^4.0.8",
@@ -10,7 +10,7 @@ import { isMainThread } from 'worker_threads';
10
10
  import { ClientError } from '../core/utility/errors/hdbError.js';
11
11
  import env from '../core/utility/environment/environmentManager.js';
12
12
  import { CONFIG_PARAMS } from '../core/utility/hdbTerms.ts';
13
- import * as logger from '../core/utility/logging/logger.ts';
13
+ import { logger } from '../core/utility/logging/logger.ts';
14
14
 
15
15
  let hdbNodeTable;
16
16
  server.nodes = [];
@@ -110,7 +110,7 @@ export function subscribeToNodeUpdates(listener: (node: any, id: string) => void
110
110
  server.shards = new Map();
111
111
 
112
112
  for (let entry of getHDBNodeTable().primaryStore.getRange({})) {
113
- const { value: node } = entry;
113
+ const { value: node, key } = entry;
114
114
  server.nodes.push(node);
115
115
  if (node.shard != undefined) {
116
116
  let nodesForShard = server.shards.get(node.shard);
@@ -119,6 +119,7 @@ export function subscribeToNodeUpdates(listener: (node: any, id: string) => void
119
119
  }
120
120
  nodesForShard.push(node);
121
121
  }
122
+ listener(node, key);
122
123
  }
123
124
  logger.debug?.(
124
125
  'Known nodes at startup',
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * This module is responsible for managing the mapping of node/host names to node ids.
3
3
  */
4
- import * as logger from '../core/utility/logging/logger.ts';
4
+ import { logger } from '../core/utility/logging/logger.ts';
5
5
  import { lastTimeInAuditStore } from './replicator.ts';
6
6
  import { getThisNodeName } from '../core/server/nodeName.ts';
7
7
  import { pack, unpack } from 'msgpackr';
@@ -1,3 +1,4 @@
1
+ import type { Logger } from '../core/utility/logging/logger.ts';
1
2
  import {
2
3
  getDatabases,
3
4
  databases,
@@ -51,7 +52,7 @@ import {
51
52
  } from '../core/resources/blob.ts';
52
53
  import { PassThrough } from 'node:stream';
53
54
  import { getLastVersion } from 'lmdb';
54
- const logger = forComponent('replication').conditional;
55
+ const logger = forComponent('replication').conditional as Logger;
55
56
 
56
57
  // these are the codes we use for the different commands
57
58
  const SUBSCRIPTION_REQUEST = 129;
@@ -121,10 +122,9 @@ export async function createWebSocket(
121
122
  if (url == null) {
122
123
  throw new TypeError(`Invalid URL: Expected a string URL for node "${node_name}" but received ${url}`);
123
124
  }
124
-
125
125
  if (url.includes('wss://')) {
126
126
  if (!secureContexts) {
127
- const SNICallback = createTLSSelector('operations-api');
127
+ const SNICallback = createTLSSelector('replication');
128
128
  const secureTarget = {
129
129
  secureContexts: null,
130
130
  };
@@ -133,10 +133,22 @@ export async function createWebSocket(
133
133
  }
134
134
  secureContext = secureContexts.get(node_name);
135
135
  if (secureContext) {
136
- logger.debug?.('Creating web socket for URL', url, 'with certificate named:', secureContext.name);
136
+ logger.debug?.(
137
+ 'Creating web socket for URL',
138
+ url,
139
+ 'with certificate named:',
140
+ secureContext.name,
141
+ 'is_self_signed',
142
+ secureContext.is_self_signed
143
+ );
137
144
  }
138
145
  if (!secureContext && rejectUnauthorized !== false) {
139
- throw new Error('Unable to find a valid certificate to use for replication to connect to ' + url);
146
+ throw new Error(
147
+ 'Unable to find a valid certificate to use for replication to connect to ' +
148
+ url +
149
+ ' available:' +
150
+ Array.from(secureContexts.keys())
151
+ );
140
152
  }
141
153
  }
142
154
  const headers = {};
@@ -698,7 +710,12 @@ export function replicateOverWS(ws: WebSocket, options: any, authorization: Prom
698
710
  remoteNodeIds: receivingDataFromNodeIds,
699
711
  });
700
712
  getSharedStatus();
701
- replicationSharedStatus[RECEIVED_VERSION_POSITION] = lastSequenceIdReceived;
713
+ replicationSharedStatus[RECEIVED_VERSION_POSITION] = Math.max(
714
+ // ensure monotonicity
715
+ lastSequenceIdReceived,
716
+ replicationSharedStatus[RECEIVED_VERSION_POSITION]
717
+ );
718
+
702
719
  replicationSharedStatus[RECEIVED_TIME_POSITION] = Date.now();
703
720
  replicationSharedStatus[RECEIVING_STATUS_POSITION] = RECEIVING_STATUS_WAITING;
704
721
  break;
@@ -1487,7 +1504,11 @@ export function replicateOverWS(ws: WebSocket, options: any, authorization: Prom
1487
1504
  // this is an empty txn ending, but need to record the timestamps
1488
1505
  decoder.position++;
1489
1506
  lastSequenceIdReceived = sequenceIdReceived = decoder.readFloat64();
1490
- replicationSharedStatus[RECEIVED_VERSION_POSITION] = lastSequenceIdReceived;
1507
+ replicationSharedStatus[RECEIVED_VERSION_POSITION] = Math.max(
1508
+ // ensure monotonicity
1509
+ lastSequenceIdReceived,
1510
+ replicationSharedStatus[RECEIVED_VERSION_POSITION]
1511
+ );
1491
1512
  replicationSharedStatus[RECEIVED_TIME_POSITION] = Date.now();
1492
1513
  replicationSharedStatus[RECEIVING_STATUS_POSITION] = RECEIVING_STATUS_WAITING;
1493
1514
  tableSubscriptionToReplicator.send({
@@ -1555,7 +1576,11 @@ export function replicateOverWS(ws: WebSocket, options: any, authorization: Prom
1555
1576
  'nodeId',
1556
1577
  event.nodeId
1557
1578
  );
1558
- replicationSharedStatus[RECEIVED_VERSION_POSITION] = auditRecord.version;
1579
+ replicationSharedStatus[RECEIVED_VERSION_POSITION] = Math.max(
1580
+ // ensure monotonicity
1581
+ auditRecord.version,
1582
+ replicationSharedStatus[RECEIVED_VERSION_POSITION]
1583
+ );
1559
1584
  replicationSharedStatus[RECEIVED_TIME_POSITION] = Date.now();
1560
1585
  replicationSharedStatus[RECEIVING_STATUS_POSITION] = RECEIVING_STATUS_RECEIVING;
1561
1586
 
@@ -150,7 +150,11 @@ export function start(options) {
150
150
  } else {
151
151
  logger.error(
152
152
  `Incoming client connection from ${request.peerCertificate?.subjectaltname ?? request.ip} did not have valid certificate, you may need turn on enableRootCAs in the config if you are using a publicly signed certificate, or add the CA to the server's trusted CAs`,
153
- authorizationError
153
+ authorizationError,
154
+ 'certificate issuer',
155
+ request.peerCertificate.issuer,
156
+ 'did not match any available CAs',
157
+ Array.from(Array.from(wsServers[0].secureContexts.values())[0].options.availableCAs.keys())
154
158
  );
155
159
  }
156
160
  }
@@ -265,6 +269,7 @@ export function start(options) {
265
269
  export function monitorNodeCAs(listener: () => void) {
266
270
  let lastCaCount = 0;
267
271
  subscribeToNodeUpdates((node) => {
272
+ logger.debug('Adding node CA', node?.ca?.slice(0, 60));
268
273
  if (node?.ca) {
269
274
  // we only care about nodes that have a CA
270
275
  replicationCertificateAuthorities.add(node.ca);
@@ -639,7 +644,7 @@ export function lastTimeInAuditStore(auditStore: Database) {
639
644
 
640
645
  export async function replicateOperation(req) {
641
646
  const response = { message: '' };
642
- if (req.replicated) {
647
+ if (req.replicated !== false) {
643
648
  req.replicated = false; // don't send a replicated flag to the nodes we are sending to
644
649
  logger.trace?.(
645
650
  'Replicating operation',
@@ -153,7 +153,7 @@ export async function setNode(req: any) {
153
153
  if (targetNodeResponse.certificate) {
154
154
  await setCertTable({
155
155
  name: getThisNodeName(),
156
- uses: ['https', 'operations', 'wss'],
156
+ uses: ['https', 'operations', 'wss', 'replication'],
157
157
  certificate: targetNodeResponse.certificate,
158
158
  private_key_name: rep?.options?.key_file,
159
159
  is_authority: false,
@@ -1,3 +1,4 @@
1
+ import type { Logger } from '../core/utility/logging/logger.ts';
1
2
  import Joi from 'joi';
2
3
  import forge from 'node-forge';
3
4
  import { access, constants, readFile, writeFile, unlink } from 'node:fs/promises';
@@ -25,7 +26,7 @@ import { server } from '../core/server/Server.ts';
25
26
  import { replicateOperation } from '../replication/replicator.ts';
26
27
 
27
28
  const { forComponent } = harperLogger;
28
- const logger = forComponent('certificate').conditional;
29
+ const logger = forComponent('certificate').conditional as Logger;
29
30
  const pki = forge.pki;
30
31
  const CERT_VALIDITY_DAYS = 3650;
31
32
 
@@ -1,2 +1,2 @@
1
- var __defProp=Object.defineProperty;var __name=(target,value)=>__defProp(target,"name",{value,configurable:!0});import{$ as useMutation,a0 as apiClient,a1 as object,a2 as string,a3 as useRouter,a4 as useNavigate,a5 as useCloudAuth,a6 as useForm,a7 as a,a8 as reactExports,a9 as authStore,aa as OverallAppSignIn,ab as toast,ac as logoutOnSuccess,ad as jsxRuntimeExports,ae as Form,af as FormField,ag as FormItem,ah as FormLabel,ai as FormControl,aj as Input,ak as FormMessage,al as Button,am as Save}from"./index-Qu8D43wo.js";async function onUpdateUser(formData){const{id,newPassword,confirmNewPassword,...otherFields}=formData,userData={...otherFields};newPassword&&newPassword===confirmNewPassword&&(userData.password=newPassword);const{data}=await apiClient.patch(`/User/${id}`,userData);return data}__name(onUpdateUser,"onUpdateUser");function useUpdateUserMutation(){return useMutation({mutationFn:__name(formData=>onUpdateUser(formData),"mutationFn")})}__name(useUpdateUserMutation,"useUpdateUserMutation");const UpdateUserSchema=object({id:string(),firstname:string({error:"Please enter your first name."}).min(2,{error:"First name is required."}).max(50,{error:"First name must be less than 50 characters."}),lastname:string({error:"Please enter your last name."}).min(2,{error:"Last name is required."}).max(50,{error:"Last name must be less than 50 characters."}),newPassword:string({error:"Please enter your new password."}).min(8,{error:"Password must be 8 characters or more."}).or(string().max(0)),confirmNewPassword:string().optional()}).refine(data=>data.newPassword===data.confirmNewPassword,{error:"Passwords do not match",path:["confirmNewPassword"]});function ProfileIndex(){const router=useRouter(),navigate=useNavigate(),{user}=useCloudAuth(),methods=useForm({resolver:a(UpdateUserSchema),defaultValues:{confirmNewPassword:"",firstname:user?.firstname||"",id:user?.id||"",lastname:user?.lastname||"",newPassword:""}}),{control,handleSubmit,reset,formState:{defaultValues,isDirty,isValid}}=methods,{mutate:updateUser,isPending:isUpdatePending}=useUpdateUserMutation(),onSubmitClick=reactExports.useCallback(async formData=>{formData&&updateUser(formData,{onSuccess:__name(data=>{reset({...defaultValues,...data}),authStore.updateUserForEntity(OverallAppSignIn,data),formData.newPassword?(toast.success("Profile updated successfully!",{description:"Please sign in with your new password."}),logoutOnSuccess(),navigate({to:"/sign-in"}),router.invalidate()):toast.success("Profile updated successfully!")},"onSuccess")})},[defaultValues,navigate,reset,router,updateUser]);return jsxRuntimeExports.jsxs("div",{className:"mt-20 px-4 pt-4 md:px-12",children:[jsxRuntimeExports.jsx("h2",{className:"text-2xl font-light",children:"Profile"}),jsxRuntimeExports.jsx(Form,{...methods,children:jsxRuntimeExports.jsxs("form",{id:"profile-edit-form",name:"profile-edit-form",onSubmit:handleSubmit(onSubmitClick),className:"grid gap-4 my-4",children:[jsxRuntimeExports.jsx(FormField,{control,name:"firstname",render:__name(({field})=>jsxRuntimeExports.jsxs(FormItem,{children:[jsxRuntimeExports.jsx(FormLabel,{className:"pb-1",children:"First Name"}),jsxRuntimeExports.jsx(FormControl,{children:jsxRuntimeExports.jsx(Input,{type:"text",className:"bg-purple-400 border-purple-400 dark:bg-black dark:border-black",autoCapitalize:"words",...field})}),jsxRuntimeExports.jsx(FormMessage,{})]}),"render")}),jsxRuntimeExports.jsx(FormField,{control,name:"lastname",render:__name(({field})=>jsxRuntimeExports.jsxs(FormItem,{children:[jsxRuntimeExports.jsx(FormLabel,{className:"pb-1",children:"Last Name"}),jsxRuntimeExports.jsx(FormControl,{children:jsxRuntimeExports.jsx(Input,{type:"text",className:"bg-purple-400 border-purple-400 dark:bg-black dark:border-black",autoCapitalize:"words",...field})}),jsxRuntimeExports.jsx(FormMessage,{})]}),"render")}),jsxRuntimeExports.jsx(FormLabel,{className:"pb-1",children:"Email"}),jsxRuntimeExports.jsx(FormControl,{children:jsxRuntimeExports.jsx(Input,{type:"email",enterKeyHint:"next",autoComplete:"email",autoCapitalize:"none",value:user?.email||"",disabled:!0,readOnly:!0})}),jsxRuntimeExports.jsx(FormField,{control,name:"newPassword",render:__name(({field})=>jsxRuntimeExports.jsxs(FormItem,{children:[jsxRuntimeExports.jsx(FormLabel,{className:"pb-1",children:"New Password"}),jsxRuntimeExports.jsx(FormControl,{children:jsxRuntimeExports.jsx(Input,{type:"password",placeholder:"Optional",className:"bg-purple-400 border-purple-400 dark:bg-black dark:border-black",autoComplete:"new-password",autoCapitalize:"none",...field})}),jsxRuntimeExports.jsx(FormMessage,{})]}),"render")}),jsxRuntimeExports.jsx(FormField,{control,name:"confirmNewPassword",render:__name(({field})=>jsxRuntimeExports.jsxs(FormItem,{children:[jsxRuntimeExports.jsx(FormLabel,{className:"pb-1",children:"Confirm New Password"}),jsxRuntimeExports.jsx(FormControl,{children:jsxRuntimeExports.jsx(Input,{type:"password",className:"bg-purple-400 border-purple-400 dark:bg-black dark:border-black",autoComplete:"new-password",autoCapitalize:"none",...field})}),jsxRuntimeExports.jsx(FormMessage,{})]}),"render")}),jsxRuntimeExports.jsx("div",{className:"flex justify-between w-full",children:jsxRuntimeExports.jsxs(Button,{type:"submit",variant:"submit",className:"rounded-full",disabled:isUpdatePending||!isDirty||!isValid,children:[jsxRuntimeExports.jsx(Save,{})," Update Profile"]})})]})})]})}__name(ProfileIndex,"ProfileIndex");export{ProfileIndex};
2
- //# sourceMappingURL=index-v3wIpSYx.js.map
1
+ var __defProp=Object.defineProperty;var __name=(target,value)=>__defProp(target,"name",{value,configurable:!0});import{$ as useMutation,a0 as apiClient,a1 as object,a2 as string,a3 as useRouter,a4 as useNavigate,a5 as useCloudAuth,a6 as useForm,a7 as a,a8 as reactExports,a9 as authStore,aa as OverallAppSignIn,ab as toast,ac as logoutOnSuccess,ad as jsxRuntimeExports,ae as Form,af as FormField,ag as FormItem,ah as FormLabel,ai as FormControl,aj as Input,ak as FormMessage,al as Button,am as Save}from"./index-DMDhGP7N.js";async function onUpdateUser(formData){const{id,newPassword,confirmNewPassword,...otherFields}=formData,userData={...otherFields};newPassword&&newPassword===confirmNewPassword&&(userData.password=newPassword);const{data}=await apiClient.patch(`/User/${id}`,userData);return data}__name(onUpdateUser,"onUpdateUser");function useUpdateUserMutation(){return useMutation({mutationFn:__name(formData=>onUpdateUser(formData),"mutationFn")})}__name(useUpdateUserMutation,"useUpdateUserMutation");const UpdateUserSchema=object({id:string(),firstname:string({error:"Please enter your first name."}).min(2,{error:"First name is required."}).max(50,{error:"First name must be less than 50 characters."}),lastname:string({error:"Please enter your last name."}).min(2,{error:"Last name is required."}).max(50,{error:"Last name must be less than 50 characters."}),newPassword:string({error:"Please enter your new password."}).min(8,{error:"Password must be 8 characters or more."}).or(string().max(0)),confirmNewPassword:string().optional()}).refine(data=>data.newPassword===data.confirmNewPassword,{error:"Passwords do not match",path:["confirmNewPassword"]});function ProfileIndex(){const router=useRouter(),navigate=useNavigate(),{user}=useCloudAuth(),methods=useForm({resolver:a(UpdateUserSchema),defaultValues:{confirmNewPassword:"",firstname:user?.firstname||"",id:user?.id||"",lastname:user?.lastname||"",newPassword:""}}),{control,handleSubmit,reset,formState:{defaultValues,isDirty,isValid}}=methods,{mutate:updateUser,isPending:isUpdatePending}=useUpdateUserMutation(),onSubmitClick=reactExports.useCallback(async formData=>{formData&&updateUser(formData,{onSuccess:__name(data=>{reset({...defaultValues,...data}),authStore.updateUserForEntity(OverallAppSignIn,data),formData.newPassword?(toast.success("Profile updated successfully!",{description:"Please sign in with your new password."}),logoutOnSuccess(),navigate({to:"/sign-in"}),router.invalidate()):toast.success("Profile updated successfully!")},"onSuccess")})},[defaultValues,navigate,reset,router,updateUser]);return jsxRuntimeExports.jsxs("div",{className:"mt-20 px-4 pt-4 md:px-12",children:[jsxRuntimeExports.jsx("h2",{className:"text-2xl font-light",children:"Profile"}),jsxRuntimeExports.jsx(Form,{...methods,children:jsxRuntimeExports.jsxs("form",{id:"profile-edit-form",name:"profile-edit-form",onSubmit:handleSubmit(onSubmitClick),className:"grid gap-4 my-4",children:[jsxRuntimeExports.jsx(FormField,{control,name:"firstname",render:__name(({field})=>jsxRuntimeExports.jsxs(FormItem,{children:[jsxRuntimeExports.jsx(FormLabel,{className:"pb-1",children:"First Name"}),jsxRuntimeExports.jsx(FormControl,{children:jsxRuntimeExports.jsx(Input,{type:"text",className:"bg-purple-400 border-purple-400 dark:bg-black dark:border-black",autoCapitalize:"words",...field})}),jsxRuntimeExports.jsx(FormMessage,{})]}),"render")}),jsxRuntimeExports.jsx(FormField,{control,name:"lastname",render:__name(({field})=>jsxRuntimeExports.jsxs(FormItem,{children:[jsxRuntimeExports.jsx(FormLabel,{className:"pb-1",children:"Last Name"}),jsxRuntimeExports.jsx(FormControl,{children:jsxRuntimeExports.jsx(Input,{type:"text",className:"bg-purple-400 border-purple-400 dark:bg-black dark:border-black",autoCapitalize:"words",...field})}),jsxRuntimeExports.jsx(FormMessage,{})]}),"render")}),jsxRuntimeExports.jsx(FormLabel,{className:"pb-1",children:"Email"}),jsxRuntimeExports.jsx(FormControl,{children:jsxRuntimeExports.jsx(Input,{type:"email",enterKeyHint:"next",autoComplete:"email",autoCapitalize:"none",value:user?.email||"",disabled:!0,readOnly:!0})}),jsxRuntimeExports.jsx(FormField,{control,name:"newPassword",render:__name(({field})=>jsxRuntimeExports.jsxs(FormItem,{children:[jsxRuntimeExports.jsx(FormLabel,{className:"pb-1",children:"New Password"}),jsxRuntimeExports.jsx(FormControl,{children:jsxRuntimeExports.jsx(Input,{type:"password",placeholder:"Optional",className:"bg-purple-400 border-purple-400 dark:bg-black dark:border-black",autoComplete:"new-password",autoCapitalize:"none",...field})}),jsxRuntimeExports.jsx(FormMessage,{})]}),"render")}),jsxRuntimeExports.jsx(FormField,{control,name:"confirmNewPassword",render:__name(({field})=>jsxRuntimeExports.jsxs(FormItem,{children:[jsxRuntimeExports.jsx(FormLabel,{className:"pb-1",children:"Confirm New Password"}),jsxRuntimeExports.jsx(FormControl,{children:jsxRuntimeExports.jsx(Input,{type:"password",className:"bg-purple-400 border-purple-400 dark:bg-black dark:border-black",autoComplete:"new-password",autoCapitalize:"none",...field})}),jsxRuntimeExports.jsx(FormMessage,{})]}),"render")}),jsxRuntimeExports.jsx("div",{className:"flex justify-between w-full",children:jsxRuntimeExports.jsxs(Button,{type:"submit",variant:"submit",className:"rounded-full",disabled:isUpdatePending||!isDirty||!isValid,children:[jsxRuntimeExports.jsx(Save,{})," Update Profile"]})})]})})]})}__name(ProfileIndex,"ProfileIndex");export{ProfileIndex};
2
+ //# sourceMappingURL=index-CWN9Wp5V.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index-v3wIpSYx.js","sources":["../../src/features/profile/mutations/updateUserMutation.ts","../../src/features/profile/mutations/updateUserSchema.ts","../../src/features/profile/index.tsx"],"sourcesContent":["import { apiClient } from '@/config/apiClient';\nimport { UpdateUserSchema } from '@/features/profile/mutations/updateUserSchema';\nimport { SchemaUser } from '@/integrations/api/api.gen';\nimport { User } from '@/integrations/api/api.patch';\nimport { useMutation } from '@tanstack/react-query';\nimport z from 'zod';\n\nasync function onUpdateUser(formData: z.infer<typeof UpdateUserSchema>) {\n\tconst { id, newPassword, confirmNewPassword, ...otherFields } = formData;\n\tconst userData: Partial<SchemaUser & { password: string }> = {\n\t\t...otherFields,\n\t};\n\tif (newPassword && newPassword === confirmNewPassword) {\n\t\tuserData.password = newPassword;\n\t}\n\tconst { data } = await apiClient.patch(`/User/${id}` as '/User/{id}', userData);\n\treturn data as Partial<User>;\n}\n\nexport function useUpdateUserMutation() {\n\treturn useMutation({\n\t\tmutationFn: (formData: z.infer<typeof UpdateUserSchema>) => onUpdateUser(formData),\n\t});\n}\n","import { z } from 'zod';\n\nexport const UpdateUserSchema = z\n\t.object({\n\t\tid: z.string(),\n\t\tfirstname: z\n\t\t\t.string({\n\t\t\t\terror: 'Please enter your first name.',\n\t\t\t})\n\t\t\t.min(2, { error: 'First name is required.' })\n\t\t\t.max(50, { error: 'First name must be less than 50 characters.' }),\n\t\tlastname: z\n\t\t\t.string({\n\t\t\t\terror: 'Please enter your last name.',\n\t\t\t})\n\t\t\t.min(2, { error: 'Last name is required.' })\n\t\t\t.max(50, { error: 'Last name must be less than 50 characters.' }),\n\t\tnewPassword: z\n\t\t\t.string({\n\t\t\t\terror: 'Please enter your new password.',\n\t\t\t})\n\t\t\t.min(8, { error: 'Password must be 8 characters or more.' })\n\t\t\t.or(z.string().max(0)),\n\t\tconfirmNewPassword: z\n\t\t\t.string()\n\t\t\t.optional(),\n\t})\n\t.refine((data) => data.newPassword === data.confirmNewPassword, {\n\t\terror: 'Passwords do not match',\n\t\tpath: ['confirmNewPassword'],\n\t});\n","import { Button } from '@/components/ui/button';\nimport { Form } from '@/components/ui/form/Form';\nimport { FormControl } from '@/components/ui/form/FormControl';\nimport { FormField } from '@/components/ui/form/FormField';\nimport { FormItem } from '@/components/ui/form/FormItem';\nimport { FormLabel } from '@/components/ui/form/FormLabel';\nimport { FormMessage } from '@/components/ui/form/FormMessage';\nimport { Input } from '@/components/ui/input';\nimport { logoutOnSuccess } from '@/features/auth/handlers/logoutOnSuccess';\nimport { authStore, OverallAppSignIn } from '@/features/auth/store/authStore';\nimport { useUpdateUserMutation } from '@/features/profile/mutations/updateUserMutation';\nimport { UpdateUserSchema } from '@/features/profile/mutations/updateUserSchema';\nimport { useCloudAuth } from '@/hooks/useAuth';\nimport { zodResolver } from '@hookform/resolvers/zod';\nimport { useNavigate, useRouter } from '@tanstack/react-router';\nimport { Save } from 'lucide-react';\nimport { useCallback } from 'react';\nimport { useForm } from 'react-hook-form';\nimport { toast } from 'sonner';\nimport { z } from 'zod';\n\nexport function ProfileIndex() {\n\tconst router = useRouter();\n\tconst navigate = useNavigate();\n\tconst { user } = useCloudAuth();\n\n\tconst methods = useForm({\n\t\tresolver: zodResolver(UpdateUserSchema),\n\t\tdefaultValues: {\n\t\t\tconfirmNewPassword: '',\n\t\t\tfirstname: user?.firstname || '',\n\t\t\tid: user?.id || '',\n\t\t\tlastname: user?.lastname || '',\n\t\t\tnewPassword: '',\n\t\t},\n\t});\n\tconst { control, handleSubmit, reset, formState: { defaultValues, isDirty, isValid } } = methods;\n\tconst { mutate: updateUser, isPending: isUpdatePending } = useUpdateUserMutation();\n\n\tconst onSubmitClick = useCallback(\n\t\tasync (formData: z.infer<typeof UpdateUserSchema>) => {\n\t\t\tif (formData) {\n\t\t\t\tupdateUser(formData, {\n\t\t\t\t\tonSuccess: (data) => {\n\t\t\t\t\t\treset({\n\t\t\t\t\t\t\t...defaultValues,\n\t\t\t\t\t\t\t...data,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tauthStore.updateUserForEntity(OverallAppSignIn, data);\n\t\t\t\t\t\tif (formData.newPassword) {\n\t\t\t\t\t\t\ttoast.success('Profile updated successfully!', {\n\t\t\t\t\t\t\t\tdescription: 'Please sign in with your new password.',\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tlogoutOnSuccess();\n\t\t\t\t\t\t\tvoid navigate({ to: '/sign-in' });\n\t\t\t\t\t\t\tvoid router.invalidate();\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\ttoast.success('Profile updated successfully!');\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\t\t},\n\t\t[defaultValues, navigate, reset, router, updateUser],\n\t);\n\n\treturn (\n\t\t<div className=\"mt-20 px-4 pt-4 md:px-12\">\n\t\t\t<h2 className=\"text-2xl font-light\">Profile</h2>\n\t\t\t<Form {...methods}>\n\t\t\t\t<form\n\t\t\t\t\tid=\"profile-edit-form\"\n\t\t\t\t\tname=\"profile-edit-form\"\n\t\t\t\t\tonSubmit={handleSubmit(onSubmitClick)}\n\t\t\t\t\tclassName=\"grid gap-4 my-4\"\n\t\t\t\t>\n\t\t\t\t\t<FormField\n\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\tname=\"firstname\"\n\t\t\t\t\t\trender={({ field }) => (\n\t\t\t\t\t\t\t<FormItem>\n\t\t\t\t\t\t\t\t<FormLabel className=\"pb-1\">First Name</FormLabel>\n\t\t\t\t\t\t\t\t<FormControl>\n\t\t\t\t\t\t\t\t\t<Input\n\t\t\t\t\t\t\t\t\t\ttype=\"text\"\n\t\t\t\t\t\t\t\t\t\tclassName=\"bg-purple-400 border-purple-400 dark:bg-black dark:border-black\"\n\t\t\t\t\t\t\t\t\t\tautoCapitalize=\"words\"\n\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</FormControl>\n\t\t\t\t\t\t\t\t<FormMessage />\n\t\t\t\t\t\t\t</FormItem>\n\t\t\t\t\t\t)}\n\t\t\t\t\t/>\n\n\t\t\t\t\t<FormField\n\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\tname=\"lastname\"\n\t\t\t\t\t\trender={({ field }) => (\n\t\t\t\t\t\t\t<FormItem>\n\t\t\t\t\t\t\t\t<FormLabel className=\"pb-1\">Last Name</FormLabel>\n\t\t\t\t\t\t\t\t<FormControl>\n\t\t\t\t\t\t\t\t\t<Input\n\t\t\t\t\t\t\t\t\t\ttype=\"text\"\n\t\t\t\t\t\t\t\t\t\tclassName=\"bg-purple-400 border-purple-400 dark:bg-black dark:border-black\"\n\t\t\t\t\t\t\t\t\t\tautoCapitalize=\"words\"\n\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</FormControl>\n\t\t\t\t\t\t\t\t<FormMessage />\n\t\t\t\t\t\t\t</FormItem>\n\t\t\t\t\t\t)}\n\t\t\t\t\t/>\n\n\t\t\t\t\t<FormLabel className=\"pb-1\">Email</FormLabel>\n\t\t\t\t\t<FormControl>\n\t\t\t\t\t\t<Input\n\t\t\t\t\t\t\ttype=\"email\"\n\t\t\t\t\t\t\tenterKeyHint=\"next\"\n\t\t\t\t\t\t\tautoComplete=\"email\"\n\t\t\t\t\t\t\tautoCapitalize=\"none\"\n\t\t\t\t\t\t\tvalue={user?.email || ''}\n\t\t\t\t\t\t\tdisabled={true}\n\t\t\t\t\t\t\treadOnly={true}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</FormControl>\n\n\t\t\t\t\t<FormField\n\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\tname=\"newPassword\"\n\t\t\t\t\t\trender={({ field }) => (\n\t\t\t\t\t\t\t<FormItem>\n\t\t\t\t\t\t\t\t<FormLabel className=\"pb-1\">New Password</FormLabel>\n\t\t\t\t\t\t\t\t<FormControl>\n\t\t\t\t\t\t\t\t\t<Input\n\t\t\t\t\t\t\t\t\t\ttype=\"password\"\n\t\t\t\t\t\t\t\t\t\tplaceholder=\"Optional\"\n\t\t\t\t\t\t\t\t\t\tclassName=\"bg-purple-400 border-purple-400 dark:bg-black dark:border-black\"\n\t\t\t\t\t\t\t\t\t\tautoComplete=\"new-password\"\n\t\t\t\t\t\t\t\t\t\tautoCapitalize=\"none\"\n\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</FormControl>\n\t\t\t\t\t\t\t\t<FormMessage />\n\t\t\t\t\t\t\t</FormItem>\n\t\t\t\t\t\t)}\n\t\t\t\t\t/>\n\n\t\t\t\t\t<FormField\n\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\tname=\"confirmNewPassword\"\n\t\t\t\t\t\trender={({ field }) => (\n\t\t\t\t\t\t\t<FormItem>\n\t\t\t\t\t\t\t\t<FormLabel className=\"pb-1\">Confirm New Password</FormLabel>\n\t\t\t\t\t\t\t\t<FormControl>\n\t\t\t\t\t\t\t\t\t<Input\n\t\t\t\t\t\t\t\t\t\ttype=\"password\"\n\t\t\t\t\t\t\t\t\t\tclassName=\"bg-purple-400 border-purple-400 dark:bg-black dark:border-black\"\n\t\t\t\t\t\t\t\t\t\tautoComplete=\"new-password\"\n\t\t\t\t\t\t\t\t\t\tautoCapitalize=\"none\"\n\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</FormControl>\n\t\t\t\t\t\t\t\t<FormMessage />\n\t\t\t\t\t\t\t</FormItem>\n\t\t\t\t\t\t)}\n\t\t\t\t\t/>\n\n\t\t\t\t\t<div className=\"flex justify-between w-full\">\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\t\t\tvariant=\"submit\"\n\t\t\t\t\t\t\tclassName=\"rounded-full\"\n\t\t\t\t\t\t\tdisabled={isUpdatePending || !isDirty || !isValid}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Save /> Update Profile\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t</div>\n\t\t\t\t</form>\n\t\t\t</Form>\n\t\t</div>\n\t);\n}\n"],"names":["z.object","z.string","zodResolver","useCallback","jsxs","jsx"],"mappings":"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"}
1
+ {"version":3,"file":"index-CWN9Wp5V.js","sources":["../../src/features/profile/mutations/updateUserMutation.ts","../../src/features/profile/mutations/updateUserSchema.ts","../../src/features/profile/index.tsx"],"sourcesContent":["import { apiClient } from '@/config/apiClient';\nimport { UpdateUserSchema } from '@/features/profile/mutations/updateUserSchema';\nimport { SchemaUser } from '@/integrations/api/api.gen';\nimport { User } from '@/integrations/api/api.patch';\nimport { useMutation } from '@tanstack/react-query';\nimport z from 'zod';\n\nasync function onUpdateUser(formData: z.infer<typeof UpdateUserSchema>) {\n\tconst { id, newPassword, confirmNewPassword, ...otherFields } = formData;\n\tconst userData: Partial<SchemaUser & { password: string }> = {\n\t\t...otherFields,\n\t};\n\tif (newPassword && newPassword === confirmNewPassword) {\n\t\tuserData.password = newPassword;\n\t}\n\tconst { data } = await apiClient.patch(`/User/${id}` as '/User/{id}', userData);\n\treturn data as Partial<User>;\n}\n\nexport function useUpdateUserMutation() {\n\treturn useMutation({\n\t\tmutationFn: (formData: z.infer<typeof UpdateUserSchema>) => onUpdateUser(formData),\n\t});\n}\n","import { z } from 'zod';\n\nexport const UpdateUserSchema = z\n\t.object({\n\t\tid: z.string(),\n\t\tfirstname: z\n\t\t\t.string({\n\t\t\t\terror: 'Please enter your first name.',\n\t\t\t})\n\t\t\t.min(2, { error: 'First name is required.' })\n\t\t\t.max(50, { error: 'First name must be less than 50 characters.' }),\n\t\tlastname: z\n\t\t\t.string({\n\t\t\t\terror: 'Please enter your last name.',\n\t\t\t})\n\t\t\t.min(2, { error: 'Last name is required.' })\n\t\t\t.max(50, { error: 'Last name must be less than 50 characters.' }),\n\t\tnewPassword: z\n\t\t\t.string({\n\t\t\t\terror: 'Please enter your new password.',\n\t\t\t})\n\t\t\t.min(8, { error: 'Password must be 8 characters or more.' })\n\t\t\t.or(z.string().max(0)),\n\t\tconfirmNewPassword: z\n\t\t\t.string()\n\t\t\t.optional(),\n\t})\n\t.refine((data) => data.newPassword === data.confirmNewPassword, {\n\t\terror: 'Passwords do not match',\n\t\tpath: ['confirmNewPassword'],\n\t});\n","import { Button } from '@/components/ui/button';\nimport { Form } from '@/components/ui/form/Form';\nimport { FormControl } from '@/components/ui/form/FormControl';\nimport { FormField } from '@/components/ui/form/FormField';\nimport { FormItem } from '@/components/ui/form/FormItem';\nimport { FormLabel } from '@/components/ui/form/FormLabel';\nimport { FormMessage } from '@/components/ui/form/FormMessage';\nimport { Input } from '@/components/ui/input';\nimport { logoutOnSuccess } from '@/features/auth/handlers/logoutOnSuccess';\nimport { authStore, OverallAppSignIn } from '@/features/auth/store/authStore';\nimport { useUpdateUserMutation } from '@/features/profile/mutations/updateUserMutation';\nimport { UpdateUserSchema } from '@/features/profile/mutations/updateUserSchema';\nimport { useCloudAuth } from '@/hooks/useAuth';\nimport { zodResolver } from '@hookform/resolvers/zod';\nimport { useNavigate, useRouter } from '@tanstack/react-router';\nimport { Save } from 'lucide-react';\nimport { useCallback } from 'react';\nimport { useForm } from 'react-hook-form';\nimport { toast } from 'sonner';\nimport { z } from 'zod';\n\nexport function ProfileIndex() {\n\tconst router = useRouter();\n\tconst navigate = useNavigate();\n\tconst { user } = useCloudAuth();\n\n\tconst methods = useForm({\n\t\tresolver: zodResolver(UpdateUserSchema),\n\t\tdefaultValues: {\n\t\t\tconfirmNewPassword: '',\n\t\t\tfirstname: user?.firstname || '',\n\t\t\tid: user?.id || '',\n\t\t\tlastname: user?.lastname || '',\n\t\t\tnewPassword: '',\n\t\t},\n\t});\n\tconst { control, handleSubmit, reset, formState: { defaultValues, isDirty, isValid } } = methods;\n\tconst { mutate: updateUser, isPending: isUpdatePending } = useUpdateUserMutation();\n\n\tconst onSubmitClick = useCallback(\n\t\tasync (formData: z.infer<typeof UpdateUserSchema>) => {\n\t\t\tif (formData) {\n\t\t\t\tupdateUser(formData, {\n\t\t\t\t\tonSuccess: (data) => {\n\t\t\t\t\t\treset({\n\t\t\t\t\t\t\t...defaultValues,\n\t\t\t\t\t\t\t...data,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tauthStore.updateUserForEntity(OverallAppSignIn, data);\n\t\t\t\t\t\tif (formData.newPassword) {\n\t\t\t\t\t\t\ttoast.success('Profile updated successfully!', {\n\t\t\t\t\t\t\t\tdescription: 'Please sign in with your new password.',\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tlogoutOnSuccess();\n\t\t\t\t\t\t\tvoid navigate({ to: '/sign-in' });\n\t\t\t\t\t\t\tvoid router.invalidate();\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\ttoast.success('Profile updated successfully!');\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\t\t},\n\t\t[defaultValues, navigate, reset, router, updateUser],\n\t);\n\n\treturn (\n\t\t<div className=\"mt-20 px-4 pt-4 md:px-12\">\n\t\t\t<h2 className=\"text-2xl font-light\">Profile</h2>\n\t\t\t<Form {...methods}>\n\t\t\t\t<form\n\t\t\t\t\tid=\"profile-edit-form\"\n\t\t\t\t\tname=\"profile-edit-form\"\n\t\t\t\t\tonSubmit={handleSubmit(onSubmitClick)}\n\t\t\t\t\tclassName=\"grid gap-4 my-4\"\n\t\t\t\t>\n\t\t\t\t\t<FormField\n\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\tname=\"firstname\"\n\t\t\t\t\t\trender={({ field }) => (\n\t\t\t\t\t\t\t<FormItem>\n\t\t\t\t\t\t\t\t<FormLabel className=\"pb-1\">First Name</FormLabel>\n\t\t\t\t\t\t\t\t<FormControl>\n\t\t\t\t\t\t\t\t\t<Input\n\t\t\t\t\t\t\t\t\t\ttype=\"text\"\n\t\t\t\t\t\t\t\t\t\tclassName=\"bg-purple-400 border-purple-400 dark:bg-black dark:border-black\"\n\t\t\t\t\t\t\t\t\t\tautoCapitalize=\"words\"\n\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</FormControl>\n\t\t\t\t\t\t\t\t<FormMessage />\n\t\t\t\t\t\t\t</FormItem>\n\t\t\t\t\t\t)}\n\t\t\t\t\t/>\n\n\t\t\t\t\t<FormField\n\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\tname=\"lastname\"\n\t\t\t\t\t\trender={({ field }) => (\n\t\t\t\t\t\t\t<FormItem>\n\t\t\t\t\t\t\t\t<FormLabel className=\"pb-1\">Last Name</FormLabel>\n\t\t\t\t\t\t\t\t<FormControl>\n\t\t\t\t\t\t\t\t\t<Input\n\t\t\t\t\t\t\t\t\t\ttype=\"text\"\n\t\t\t\t\t\t\t\t\t\tclassName=\"bg-purple-400 border-purple-400 dark:bg-black dark:border-black\"\n\t\t\t\t\t\t\t\t\t\tautoCapitalize=\"words\"\n\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</FormControl>\n\t\t\t\t\t\t\t\t<FormMessage />\n\t\t\t\t\t\t\t</FormItem>\n\t\t\t\t\t\t)}\n\t\t\t\t\t/>\n\n\t\t\t\t\t<FormLabel className=\"pb-1\">Email</FormLabel>\n\t\t\t\t\t<FormControl>\n\t\t\t\t\t\t<Input\n\t\t\t\t\t\t\ttype=\"email\"\n\t\t\t\t\t\t\tenterKeyHint=\"next\"\n\t\t\t\t\t\t\tautoComplete=\"email\"\n\t\t\t\t\t\t\tautoCapitalize=\"none\"\n\t\t\t\t\t\t\tvalue={user?.email || ''}\n\t\t\t\t\t\t\tdisabled={true}\n\t\t\t\t\t\t\treadOnly={true}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</FormControl>\n\n\t\t\t\t\t<FormField\n\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\tname=\"newPassword\"\n\t\t\t\t\t\trender={({ field }) => (\n\t\t\t\t\t\t\t<FormItem>\n\t\t\t\t\t\t\t\t<FormLabel className=\"pb-1\">New Password</FormLabel>\n\t\t\t\t\t\t\t\t<FormControl>\n\t\t\t\t\t\t\t\t\t<Input\n\t\t\t\t\t\t\t\t\t\ttype=\"password\"\n\t\t\t\t\t\t\t\t\t\tplaceholder=\"Optional\"\n\t\t\t\t\t\t\t\t\t\tclassName=\"bg-purple-400 border-purple-400 dark:bg-black dark:border-black\"\n\t\t\t\t\t\t\t\t\t\tautoComplete=\"new-password\"\n\t\t\t\t\t\t\t\t\t\tautoCapitalize=\"none\"\n\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</FormControl>\n\t\t\t\t\t\t\t\t<FormMessage />\n\t\t\t\t\t\t\t</FormItem>\n\t\t\t\t\t\t)}\n\t\t\t\t\t/>\n\n\t\t\t\t\t<FormField\n\t\t\t\t\t\tcontrol={control}\n\t\t\t\t\t\tname=\"confirmNewPassword\"\n\t\t\t\t\t\trender={({ field }) => (\n\t\t\t\t\t\t\t<FormItem>\n\t\t\t\t\t\t\t\t<FormLabel className=\"pb-1\">Confirm New Password</FormLabel>\n\t\t\t\t\t\t\t\t<FormControl>\n\t\t\t\t\t\t\t\t\t<Input\n\t\t\t\t\t\t\t\t\t\ttype=\"password\"\n\t\t\t\t\t\t\t\t\t\tclassName=\"bg-purple-400 border-purple-400 dark:bg-black dark:border-black\"\n\t\t\t\t\t\t\t\t\t\tautoComplete=\"new-password\"\n\t\t\t\t\t\t\t\t\t\tautoCapitalize=\"none\"\n\t\t\t\t\t\t\t\t\t\t{...field}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</FormControl>\n\t\t\t\t\t\t\t\t<FormMessage />\n\t\t\t\t\t\t\t</FormItem>\n\t\t\t\t\t\t)}\n\t\t\t\t\t/>\n\n\t\t\t\t\t<div className=\"flex justify-between w-full\">\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\ttype=\"submit\"\n\t\t\t\t\t\t\tvariant=\"submit\"\n\t\t\t\t\t\t\tclassName=\"rounded-full\"\n\t\t\t\t\t\t\tdisabled={isUpdatePending || !isDirty || !isValid}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Save /> Update Profile\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t</div>\n\t\t\t\t</form>\n\t\t\t</Form>\n\t\t</div>\n\t);\n}\n"],"names":["z.object","z.string","zodResolver","useCallback","jsxs","jsx"],"mappings":"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"}