@collabdt/core 0.0.57 → 0.2.1
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.
- package/README.md +29 -43
- package/dist/core/components/AppSidebarContent.d.ts.map +1 -1
- package/dist/core/components/AppSidebarContent.js +21 -27
- package/dist/core/components/AppSidebarContent.js.map +1 -1
- package/dist/core/components/authentication/AuthPage.d.ts.map +1 -1
- package/dist/core/components/authentication/AuthPage.js +32 -7
- package/dist/core/components/authentication/AuthPage.js.map +1 -1
- package/dist/core/components/authentication/SignInAuthHeader.d.ts +7 -0
- package/dist/core/components/authentication/SignInAuthHeader.d.ts.map +1 -0
- package/dist/core/components/authentication/SignInAuthHeader.js +32 -0
- package/dist/core/components/authentication/SignInAuthHeader.js.map +1 -0
- package/dist/core/components/authentication/Signin.d.ts.map +1 -1
- package/dist/core/components/authentication/Signin.js +308 -10
- package/dist/core/components/authentication/Signin.js.map +1 -1
- package/dist/core/components/settings/index.js +3 -3
- package/dist/core/components/settings/index.js.map +1 -1
- package/dist/core/components/settings/src/OrganizationSettingsPanel.d.ts.map +1 -1
- package/dist/core/components/settings/src/OrganizationSettingsPanel.js +5 -4
- package/dist/core/components/settings/src/OrganizationSettingsPanel.js.map +1 -1
- package/dist/core/components/settings/src/SettingsSidebar.d.ts.map +1 -1
- package/dist/core/components/settings/src/SettingsSidebar.js +12 -2
- package/dist/core/components/settings/src/SettingsSidebar.js.map +1 -1
- package/dist/core/components/support/BugReportDialog.d.ts.map +1 -1
- package/dist/core/components/support/BugReportDialog.js +122 -9
- package/dist/core/components/support/BugReportDialog.js.map +1 -1
- package/dist/core/components/support/FeatureRequestDialog.d.ts.map +1 -1
- package/dist/core/components/support/FeatureRequestDialog.js +61 -2
- package/dist/core/components/support/FeatureRequestDialog.js.map +1 -1
- package/dist/core/components/ui/AppSidebar.d.ts.map +1 -1
- package/dist/core/components/ui/AppSidebar.js +52 -9
- package/dist/core/components/ui/AppSidebar.js.map +1 -1
- package/dist/core/components/ui/DataTable.js +3 -3
- package/dist/core/components/ui/DataTable.js.map +1 -1
- package/dist/core/components/ui/Dialog.js +1 -1
- package/dist/core/components/ui/Dialog.js.map +1 -1
- package/dist/core/components/ui/InfoSidebar/Container.js +1 -1
- package/dist/core/components/ui/InfoSidebar/Container.js.map +1 -1
- package/dist/core/components/ui/Sensors/CollapsibleSensorItem.d.ts.map +1 -1
- package/dist/core/components/ui/Sensors/CollapsibleSensorItem.js +2 -2
- package/dist/core/components/ui/Sensors/CollapsibleSensorItem.js.map +1 -1
- package/dist/core/components/ui/Sensors/SensorsSection.d.ts.map +1 -1
- package/dist/core/components/ui/Sensors/SensorsSection.js +2 -1
- package/dist/core/components/ui/Sensors/SensorsSection.js.map +1 -1
- package/dist/core/components/ui/Sensors/sensorUtils.d.ts +9 -0
- package/dist/core/components/ui/Sensors/sensorUtils.d.ts.map +1 -1
- package/dist/core/components/ui/Sensors/sensorUtils.js +6 -0
- package/dist/core/components/ui/Sensors/sensorUtils.js.map +1 -1
- package/dist/core/components/ui/Sidebar.d.ts +4 -0
- package/dist/core/components/ui/Sidebar.d.ts.map +1 -1
- package/dist/core/components/ui/Sidebar.js +11 -5
- package/dist/core/components/ui/Sidebar.js.map +1 -1
- package/dist/core/components/ui/Table.js +2 -2
- package/dist/core/components/ui/Table.js.map +1 -1
- package/dist/core/components/viewers/Data/DataMenu.d.ts.map +1 -1
- package/dist/core/components/viewers/Data/DataMenu.js +17 -9
- package/dist/core/components/viewers/Data/DataMenu.js.map +1 -1
- package/dist/core/components/viewers/Data/HeaderButtons.d.ts.map +1 -1
- package/dist/core/components/viewers/Data/HeaderButtons.js +5 -12
- package/dist/core/components/viewers/Data/HeaderButtons.js.map +1 -1
- package/dist/core/components/viewers/Data/MoreOptions.d.ts.map +1 -1
- package/dist/core/components/viewers/Data/MoreOptions.js +14 -27
- package/dist/core/components/viewers/Data/MoreOptions.js.map +1 -1
- package/dist/core/components/viewers/Data/buildingDetails/BuildingDetails.d.ts.map +1 -1
- package/dist/core/components/viewers/Data/buildingDetails/BuildingDetails.js +26 -0
- package/dist/core/components/viewers/Data/buildingDetails/BuildingDetails.js.map +1 -1
- package/dist/core/components/viewers/Data/buildingDetails/FieldRenderer.d.ts.map +1 -1
- package/dist/core/components/viewers/Data/buildingDetails/FieldRenderer.js +13 -18
- package/dist/core/components/viewers/Data/buildingDetails/FieldRenderer.js.map +1 -1
- package/dist/core/components/viewers/Data/details/DetailHeader.js +14 -14
- package/dist/core/components/viewers/Data/details/DetailHeader.js.map +1 -1
- package/dist/core/components/viewers/Data/details/FieldValue.d.ts.map +1 -1
- package/dist/core/components/viewers/Data/details/FieldValue.js +13 -3
- package/dist/core/components/viewers/Data/details/FieldValue.js.map +1 -1
- package/dist/core/components/viewers/Data/details/TabSidebar.d.ts.map +1 -1
- package/dist/core/components/viewers/Data/details/TabSidebar.js +22 -0
- package/dist/core/components/viewers/Data/details/TabSidebar.js.map +1 -1
- package/dist/core/components/viewers/Data/infrastructureDetails/InfrastructureDetails.d.ts.map +1 -1
- package/dist/core/components/viewers/Data/infrastructureDetails/InfrastructureDetails.js +19 -0
- package/dist/core/components/viewers/Data/infrastructureDetails/InfrastructureDetails.js.map +1 -1
- package/dist/core/components/viewers/Data/siteDetails/AssociatedBuildings.d.ts +2 -0
- package/dist/core/components/viewers/Data/siteDetails/AssociatedBuildings.d.ts.map +1 -1
- package/dist/core/components/viewers/Data/siteDetails/AssociatedBuildings.js +84 -3
- package/dist/core/components/viewers/Data/siteDetails/AssociatedBuildings.js.map +1 -1
- package/dist/core/components/viewers/Data/siteDetails/SiteDetails.d.ts.map +1 -1
- package/dist/core/components/viewers/Data/siteDetails/SiteDetails.js +42 -2
- package/dist/core/components/viewers/Data/siteDetails/SiteDetails.js.map +1 -1
- package/dist/core/components/viewers/Data/utils/Columns.js +2 -2
- package/dist/core/components/viewers/Data/utils/Columns.js.map +1 -1
- package/dist/core/components/viewers/Data/utils/positionParser.d.ts.map +1 -1
- package/dist/core/components/viewers/Data/utils/positionParser.js +6 -5
- package/dist/core/components/viewers/Data/utils/positionParser.js.map +1 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/CommunicationTab/src/TopicsSection.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/CommunicationTab/src/TopicsSection.js +8 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/CommunicationTab/src/TopicsSection.js.map +1 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/FilesSection.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/FilesSection.js +7 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/FilesSection.js.map +1 -1
- package/dist/core/components/viewers/map/datasets/RowActions.js +6 -6
- package/dist/core/components/viewers/map/datasets/RowActions.js.map +1 -1
- package/dist/core/components/viewers/map/datasets/data.js +1 -1
- package/dist/core/components/viewers/map/datasets/data.js.map +1 -1
- package/dist/core/components/viewers/map/datasets/index.d.ts.map +1 -1
- package/dist/core/components/viewers/map/datasets/index.js +28 -9
- package/dist/core/components/viewers/map/datasets/index.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapLayers/index.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapLayers/index.js +2 -0
- package/dist/core/components/viewers/map/src/MapLayers/index.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapLayers/src/SiteLayer/SiteContextMenu.d.ts +19 -0
- package/dist/core/components/viewers/map/src/MapLayers/src/SiteLayer/SiteContextMenu.d.ts.map +1 -0
- package/dist/core/components/viewers/map/src/MapLayers/src/SiteLayer/SiteContextMenu.js +163 -0
- package/dist/core/components/viewers/map/src/MapLayers/src/SiteLayer/SiteContextMenu.js.map +1 -0
- package/dist/core/components/viewers/map/src/MapLayers/src/SiteLayer/SiteLayer.d.ts +3 -0
- package/dist/core/components/viewers/map/src/MapLayers/src/SiteLayer/SiteLayer.d.ts.map +1 -0
- package/dist/core/components/viewers/map/src/MapLayers/src/SiteLayer/SiteLayer.js +310 -0
- package/dist/core/components/viewers/map/src/MapLayers/src/SiteLayer/SiteLayer.js.map +1 -0
- package/dist/core/components/viewers/map/src/MapLayers/src/SiteLayer/siteGeometry.d.ts +30 -0
- package/dist/core/components/viewers/map/src/MapLayers/src/SiteLayer/siteGeometry.d.ts.map +1 -0
- package/dist/core/components/viewers/map/src/MapLayers/src/SiteLayer/siteGeometry.js +122 -0
- package/dist/core/components/viewers/map/src/MapLayers/src/SiteLayer/siteGeometry.js.map +1 -0
- package/dist/core/components/viewers/map/src/MapLayers/src/SiteLayer/useShowSitesOnMap.d.ts +13 -0
- package/dist/core/components/viewers/map/src/MapLayers/src/SiteLayer/useShowSitesOnMap.d.ts.map +1 -0
- package/dist/core/components/viewers/map/src/MapLayers/src/SiteLayer/useShowSitesOnMap.js +58 -0
- package/dist/core/components/viewers/map/src/MapLayers/src/SiteLayer/useShowSitesOnMap.js.map +1 -0
- package/dist/core/components/viewers/map/src/tools/AddTools/AddSite/AssociateBuildingsDialog.d.ts +18 -0
- package/dist/core/components/viewers/map/src/tools/AddTools/AddSite/AssociateBuildingsDialog.d.ts.map +1 -0
- package/dist/core/components/viewers/map/src/tools/AddTools/AddSite/AssociateBuildingsDialog.js +102 -0
- package/dist/core/components/viewers/map/src/tools/AddTools/AddSite/AssociateBuildingsDialog.js.map +1 -0
- package/dist/core/components/viewers/map/src/tools/AddTools/AddSite/SiteAdder.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/tools/AddTools/AddSite/SiteAdder.js +243 -176
- package/dist/core/components/viewers/map/src/tools/AddTools/AddSite/SiteAdder.js.map +1 -1
- package/dist/core/components/viewers/map/src/tools/AddTools/AddSite/persistSite.d.ts +24 -0
- package/dist/core/components/viewers/map/src/tools/AddTools/AddSite/persistSite.d.ts.map +1 -0
- package/dist/core/components/viewers/map/src/tools/AddTools/AddSite/persistSite.js +46 -0
- package/dist/core/components/viewers/map/src/tools/AddTools/AddSite/persistSite.js.map +1 -0
- package/dist/core/components/viewers/map/utils/MapEventManager/MapClickManager.d.ts +1 -0
- package/dist/core/components/viewers/map/utils/MapEventManager/MapClickManager.d.ts.map +1 -1
- package/dist/core/components/viewers/map/utils/MapEventManager/MapClickManager.js +1 -0
- package/dist/core/components/viewers/map/utils/MapEventManager/MapClickManager.js.map +1 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudLoadingState/index.d.ts.map +1 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudLoadingState/index.js +54 -31
- package/dist/core/components/viewers/pointcloud/src/PointCloudLoadingState/index.js.map +1 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/index.js +1 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/index.js.map +1 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/src/PointCloudSection.d.ts +2 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/src/PointCloudSection.d.ts.map +1 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/src/PointCloudSection.js +5 -4
- package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/src/PointCloudSection.js.map +1 -1
- package/dist/core/hooks/sites/createSiteHooks.d.ts.map +1 -1
- package/dist/core/hooks/sites/createSiteHooks.js +0 -1
- package/dist/core/hooks/sites/createSiteHooks.js.map +1 -1
- package/dist/core/hooks/useCaptureScreenshot.d.ts.map +1 -1
- package/dist/core/hooks/useCaptureScreenshot.js +111 -33
- package/dist/core/hooks/useCaptureScreenshot.js.map +1 -1
- package/dist/core/hooks/useCurrentViewerPosition.d.ts +18 -0
- package/dist/core/hooks/useCurrentViewerPosition.d.ts.map +1 -0
- package/dist/core/hooks/useCurrentViewerPosition.js +66 -0
- package/dist/core/hooks/useCurrentViewerPosition.js.map +1 -0
- package/dist/core/hooks/useShareUrl.d.ts +2 -0
- package/dist/core/hooks/useShareUrl.d.ts.map +1 -0
- package/dist/core/hooks/useShareUrl.js +74 -0
- package/dist/core/hooks/useShareUrl.js.map +1 -0
- package/dist/core/store/CombineProviders.d.ts.map +1 -1
- package/dist/core/store/CombineProviders.js +2 -0
- package/dist/core/store/CombineProviders.js.map +1 -1
- package/dist/core/store/MapSites/context.d.ts +16 -0
- package/dist/core/store/MapSites/context.d.ts.map +1 -0
- package/dist/core/store/MapSites/context.js +29 -0
- package/dist/core/store/MapSites/context.js.map +1 -0
- package/dist/core/store/MapSites/reducer.d.ts +52 -0
- package/dist/core/store/MapSites/reducer.d.ts.map +1 -0
- package/dist/core/store/MapSites/reducer.js +70 -0
- package/dist/core/store/MapSites/reducer.js.map +1 -0
- package/dist/core/store/index.d.ts +1 -0
- package/dist/core/store/index.d.ts.map +1 -1
- package/dist/core/store/index.js +1 -0
- package/dist/core/store/index.js.map +1 -1
- package/dist/core/styles/globals.css +46 -33
- package/package.json +1 -1
|
@@ -9,6 +9,7 @@ import { Button, GoogleIcon, Input, LoadingSpinner } from "../ui";
|
|
|
9
9
|
import { AuthPage, useAuthTheme } from "./AuthPage";
|
|
10
10
|
import { useParams, useSearchParams } from "next/navigation";
|
|
11
11
|
import ReCAPTCHA from "react-google-recaptcha";
|
|
12
|
+
import { PasswordError } from "../authentication/PasswordError";
|
|
12
13
|
function SignInContent({ recaptchaSiteKey }) {
|
|
13
14
|
var _a;
|
|
14
15
|
const [step, setStep] = React.useState("login");
|
|
@@ -21,6 +22,16 @@ function SignInContent({ recaptchaSiteKey }) {
|
|
|
21
22
|
const [isLoading, setIsLoading] = React.useState(false);
|
|
22
23
|
const [error, setError] = React.useState("");
|
|
23
24
|
const [showPassword, setShowPassword] = React.useState(false);
|
|
25
|
+
const [confirmPassword, setConfirmPassword] = React.useState("");
|
|
26
|
+
const [showNewPassword, setShowNewPassword] = React.useState(false);
|
|
27
|
+
const [showConfirmPassword, setShowConfirmPassword] = React.useState(false);
|
|
28
|
+
const [currentPassword, setCurrentPassword] = React.useState("");
|
|
29
|
+
const [newPassword, setNewPassword] = React.useState("");
|
|
30
|
+
const [newPasswordErrors, setNewPasswordErrors] = React.useState([]);
|
|
31
|
+
const [passwordErrors, setPasswordErrors] = React.useState([]);
|
|
32
|
+
const [confirmPasswordError, setConfirmPasswordError] = React.useState("");
|
|
33
|
+
const [hasAttemptedSave, setHasAttemptedSave] = React.useState(false);
|
|
34
|
+
const [hasAttemptedSubmit, setHasAttemptedSubmit] = React.useState(false);
|
|
24
35
|
const searchParams = useSearchParams();
|
|
25
36
|
const params = useParams();
|
|
26
37
|
const orgName = (_a = params.instance) != null ? _a : "canada";
|
|
@@ -34,6 +45,8 @@ function SignInContent({ recaptchaSiteKey }) {
|
|
|
34
45
|
}, [googleError, orgName]);
|
|
35
46
|
const t = useTranslations("Signin");
|
|
36
47
|
const tMfa = useTranslations("MFA");
|
|
48
|
+
const tforgotPassword = useTranslations("forgotPassword");
|
|
49
|
+
const tresetPassword = useTranslations("resetPassword");
|
|
37
50
|
const authTheme = useAuthTheme();
|
|
38
51
|
const resetCaptcha = () => {
|
|
39
52
|
var _a2;
|
|
@@ -121,18 +134,131 @@ function SignInContent({ recaptchaSiteKey }) {
|
|
|
121
134
|
setIsLoading(false);
|
|
122
135
|
}
|
|
123
136
|
};
|
|
137
|
+
const validatePassword = (password2) => {
|
|
138
|
+
const errors = [];
|
|
139
|
+
const passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^a-zA-Z\d\s])[^\s]{12,65}$/;
|
|
140
|
+
if (!passwordRegex.test(password2)) {
|
|
141
|
+
errors.push(t("weakPassword"));
|
|
142
|
+
}
|
|
143
|
+
return errors;
|
|
144
|
+
};
|
|
145
|
+
const handlePasswordChange = (e) => {
|
|
146
|
+
const value = e.target.value;
|
|
147
|
+
setNewPassword(value);
|
|
148
|
+
setNewPasswordErrors(validatePassword(value));
|
|
149
|
+
if (confirmPassword) {
|
|
150
|
+
setConfirmPasswordError(value === confirmPassword ? "" : tforgotPassword("noMatch"));
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
const handleConfirmPasswordChange = (e) => {
|
|
154
|
+
const value = e.target.value;
|
|
155
|
+
setConfirmPassword(value);
|
|
156
|
+
setConfirmPasswordError(value === newPassword ? "" : tforgotPassword("noMatch"));
|
|
157
|
+
};
|
|
158
|
+
const handleForgotPassword = async () => {
|
|
159
|
+
setIsLoading(true);
|
|
160
|
+
setError("");
|
|
161
|
+
try {
|
|
162
|
+
const res = await fetch("/api/forgotpassword", {
|
|
163
|
+
method: "POST",
|
|
164
|
+
headers: {
|
|
165
|
+
"Content-Type": "application/json"
|
|
166
|
+
},
|
|
167
|
+
body: JSON.stringify({
|
|
168
|
+
email
|
|
169
|
+
})
|
|
170
|
+
});
|
|
171
|
+
if (!res.ok) {
|
|
172
|
+
setError("Unable to send password reset email.");
|
|
173
|
+
setIsLoading(false);
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
setStep("forgotPasswordSent");
|
|
177
|
+
setIsLoading(false);
|
|
178
|
+
} catch (e) {
|
|
179
|
+
setError("Unable to process");
|
|
180
|
+
setIsLoading(false);
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
const handleVerifyOTPForPasswordChange = async () => {
|
|
184
|
+
setIsLoading(true);
|
|
185
|
+
setError("");
|
|
186
|
+
try {
|
|
187
|
+
const res = await fetch("/api/verifyotp", {
|
|
188
|
+
method: "POST",
|
|
189
|
+
headers: {
|
|
190
|
+
"Content-Type": "application/json"
|
|
191
|
+
},
|
|
192
|
+
body: JSON.stringify({
|
|
193
|
+
email,
|
|
194
|
+
code
|
|
195
|
+
})
|
|
196
|
+
});
|
|
197
|
+
if (!res.ok) {
|
|
198
|
+
toast.error("Invalid verification code.");
|
|
199
|
+
setIsLoading(false);
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
toast.success("SUCCESS");
|
|
203
|
+
setStep("changePassword");
|
|
204
|
+
} catch (e) {
|
|
205
|
+
setError("Unable to verify code.");
|
|
206
|
+
} finally {
|
|
207
|
+
setIsLoading(false);
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
const handleResetPassword = async () => {
|
|
211
|
+
setHasAttemptedSubmit(true);
|
|
212
|
+
const errors = validatePassword(newPassword);
|
|
213
|
+
setPasswordErrors(errors);
|
|
214
|
+
if (newPassword !== confirmPassword) {
|
|
215
|
+
toast.error(tforgotPassword("noMatch"));
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
if (errors.length > 0) {
|
|
219
|
+
toast.error(tforgotPassword("passwordPolicyError"));
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
setIsLoading(true);
|
|
223
|
+
setError("");
|
|
224
|
+
try {
|
|
225
|
+
const res = await fetch("/api/resetpassword", {
|
|
226
|
+
method: "POST",
|
|
227
|
+
headers: {
|
|
228
|
+
"Content-Type": "application/json"
|
|
229
|
+
},
|
|
230
|
+
body: JSON.stringify({
|
|
231
|
+
email,
|
|
232
|
+
code,
|
|
233
|
+
newPassword
|
|
234
|
+
})
|
|
235
|
+
});
|
|
236
|
+
if (!res.ok) {
|
|
237
|
+
toast.error("Session Expired: Unable to reset password.");
|
|
238
|
+
setStep("login");
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
toast.success("Password successfully changed.");
|
|
242
|
+
setNewPassword("");
|
|
243
|
+
setConfirmPassword("");
|
|
244
|
+
setCode("");
|
|
245
|
+
setStep("login");
|
|
246
|
+
} finally {
|
|
247
|
+
setIsLoading(false);
|
|
248
|
+
}
|
|
249
|
+
};
|
|
124
250
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
125
251
|
/* @__PURE__ */ jsx(Toaster, { richColors: true, position: "top-right" }),
|
|
126
|
-
/* @__PURE__ */ jsxs("div", { className: "space-y-2 text-left", children: [
|
|
127
|
-
/* @__PURE__ */ jsx("h1", { className: "font-display font-bold", style: {
|
|
128
|
-
fontSize: "1.75rem",
|
|
129
|
-
lineHeight: "1.1",
|
|
130
|
-
letterSpacing: "-0.02em",
|
|
131
|
-
color: "var(--hp-on-surface)"
|
|
132
|
-
}, children: step === "login" ? t("title") : tMfa("title") }),
|
|
133
|
-
/* @__PURE__ */ jsx("p", { style: { color: "var(--hp-on-surface-variant)", fontSize: "0.9rem" }, children: step === "login" ? t("message") : tMfa("subtitle", { email }) })
|
|
134
|
-
] }),
|
|
135
252
|
step === "login" && /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className: "space-y-4", children: [
|
|
253
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2 text-left", children: [
|
|
254
|
+
/* @__PURE__ */ jsx("h1", { className: "font-display font-bold", style: {
|
|
255
|
+
fontSize: "1.75rem",
|
|
256
|
+
lineHeight: "1.1",
|
|
257
|
+
letterSpacing: "-0.02em",
|
|
258
|
+
color: "var(--hp-on-surface)"
|
|
259
|
+
}, children: t("title") }),
|
|
260
|
+
/* @__PURE__ */ jsx("p", { style: { color: "var(--hp-on-surface-variant)", fontSize: "0.9rem" }, children: t("message") })
|
|
261
|
+
] }),
|
|
136
262
|
/* @__PURE__ */ jsx(
|
|
137
263
|
Input,
|
|
138
264
|
{
|
|
@@ -184,9 +310,31 @@ function SignInContent({ recaptchaSiteKey }) {
|
|
|
184
310
|
children: /* @__PURE__ */ jsx(GoogleIcon, { size: 20 })
|
|
185
311
|
}
|
|
186
312
|
)
|
|
187
|
-
] })
|
|
313
|
+
] }),
|
|
314
|
+
/* @__PURE__ */ jsx(
|
|
315
|
+
"button",
|
|
316
|
+
{
|
|
317
|
+
type: "button",
|
|
318
|
+
onClick: () => {
|
|
319
|
+
setError("");
|
|
320
|
+
setStep("forgotPassword");
|
|
321
|
+
},
|
|
322
|
+
className: "text-sm underline underline-offset-4 hover:opacity-80",
|
|
323
|
+
style: { color: "var(--hp-primary)" },
|
|
324
|
+
children: "Reset your password"
|
|
325
|
+
}
|
|
326
|
+
)
|
|
188
327
|
] }),
|
|
189
328
|
step === "mfa" && /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
329
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2 text-left", children: [
|
|
330
|
+
/* @__PURE__ */ jsx("h1", { className: "font-display font-bold", style: {
|
|
331
|
+
fontSize: "1.75rem",
|
|
332
|
+
lineHeight: "1.1",
|
|
333
|
+
letterSpacing: "-0.02em",
|
|
334
|
+
color: "var(--hp-on-surface)"
|
|
335
|
+
}, children: tMfa("title") }),
|
|
336
|
+
/* @__PURE__ */ jsx("p", { style: { color: "var(--hp-on-surface-variant)", fontSize: "0.9rem" }, children: tMfa("subtitle", { email }) })
|
|
337
|
+
] }),
|
|
190
338
|
/* @__PURE__ */ jsx(
|
|
191
339
|
Input,
|
|
192
340
|
{
|
|
@@ -210,6 +358,156 @@ function SignInContent({ recaptchaSiteKey }) {
|
|
|
210
358
|
}
|
|
211
359
|
)
|
|
212
360
|
] }),
|
|
361
|
+
step === "forgotPassword" && /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
362
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2 text-left", children: [
|
|
363
|
+
/* @__PURE__ */ jsx("h1", { className: "font-display font-bold", style: {
|
|
364
|
+
fontSize: "1.75rem",
|
|
365
|
+
lineHeight: "1.1",
|
|
366
|
+
letterSpacing: "-0.02em",
|
|
367
|
+
color: "var(--hp-on-surface)"
|
|
368
|
+
}, children: tresetPassword("title") }),
|
|
369
|
+
/* @__PURE__ */ jsx("p", { style: { color: "var(--hp-on-surface-variant)", fontSize: "0.9rem" }, children: tresetPassword("subtitle") })
|
|
370
|
+
] }),
|
|
371
|
+
/* @__PURE__ */ jsx(
|
|
372
|
+
Input,
|
|
373
|
+
{
|
|
374
|
+
type: "email",
|
|
375
|
+
placeholder: "Enter your email address",
|
|
376
|
+
value: email,
|
|
377
|
+
onChange: (e) => setEmail(e.target.value),
|
|
378
|
+
disabled: isLoading
|
|
379
|
+
}
|
|
380
|
+
),
|
|
381
|
+
error && /* @__PURE__ */ jsx("div", { className: "auth-pw-error", children: error }),
|
|
382
|
+
/* @__PURE__ */ jsx(
|
|
383
|
+
Button,
|
|
384
|
+
{
|
|
385
|
+
onClick: handleForgotPassword,
|
|
386
|
+
disabled: isLoading || !email,
|
|
387
|
+
className: "w-full",
|
|
388
|
+
children: isLoading ? /* @__PURE__ */ jsx(LoadingSpinner, {}) : "Send Reset Link"
|
|
389
|
+
}
|
|
390
|
+
),
|
|
391
|
+
/* @__PURE__ */ jsxs(
|
|
392
|
+
Button,
|
|
393
|
+
{
|
|
394
|
+
variant: "outline",
|
|
395
|
+
onClick: () => setStep("login"),
|
|
396
|
+
className: "w-full",
|
|
397
|
+
children: [
|
|
398
|
+
/* @__PURE__ */ jsx(LR.ArrowLeft, { size: 16 }),
|
|
399
|
+
"Back to Login"
|
|
400
|
+
]
|
|
401
|
+
}
|
|
402
|
+
)
|
|
403
|
+
] }),
|
|
404
|
+
step === "forgotPasswordSent" && /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
405
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2 text-left", children: [
|
|
406
|
+
/* @__PURE__ */ jsx("h1", { className: "font-display font-bold", style: {
|
|
407
|
+
fontSize: "1.75rem",
|
|
408
|
+
lineHeight: "1.1",
|
|
409
|
+
letterSpacing: "-0.02em",
|
|
410
|
+
color: "var(--hp-on-surface)"
|
|
411
|
+
}, children: tresetPassword("title") }),
|
|
412
|
+
/* @__PURE__ */ jsx("p", { style: { color: "var(--hp-on-surface-variant)", fontSize: "0.9rem" }, children: tresetPassword("ifAnAccountExists", { email }) })
|
|
413
|
+
] }),
|
|
414
|
+
/* @__PURE__ */ jsx(
|
|
415
|
+
Input,
|
|
416
|
+
{
|
|
417
|
+
placeholder: tMfa("placeholder"),
|
|
418
|
+
value: code,
|
|
419
|
+
onChange: (e) => setCode(e.target.value),
|
|
420
|
+
disabled: isLoading
|
|
421
|
+
}
|
|
422
|
+
),
|
|
423
|
+
error && /* @__PURE__ */ jsx("div", { className: "auth-pw-error", children: error }),
|
|
424
|
+
/* @__PURE__ */ jsx(Button, { onClick: handleVerifyOTPForPasswordChange, disabled: isLoading, className: "w-full", children: isLoading ? /* @__PURE__ */ jsx(LoadingSpinner, {}) : tMfa("verify") }),
|
|
425
|
+
/* @__PURE__ */ jsx(
|
|
426
|
+
Button,
|
|
427
|
+
{
|
|
428
|
+
onClick: () => setStep("login"),
|
|
429
|
+
className: "w-full",
|
|
430
|
+
children: "Back to Login"
|
|
431
|
+
}
|
|
432
|
+
)
|
|
433
|
+
] }),
|
|
434
|
+
step === "changePassword" && /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
435
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2 text-left", children: [
|
|
436
|
+
/* @__PURE__ */ jsx("h1", { className: "font-display font-bold", style: {
|
|
437
|
+
fontSize: "1.75rem",
|
|
438
|
+
lineHeight: "1.1",
|
|
439
|
+
letterSpacing: "-0.02em",
|
|
440
|
+
color: "var(--hp-on-surface)"
|
|
441
|
+
}, children: tresetPassword("newPasswordTitle") }),
|
|
442
|
+
/* @__PURE__ */ jsxs("p", { style: { color: "var(--hp-on-surface-variant)", fontSize: "0.9rem" }, children: [
|
|
443
|
+
tresetPassword("newPasswordMessage"),
|
|
444
|
+
/* @__PURE__ */ jsx("br", {}),
|
|
445
|
+
" ",
|
|
446
|
+
/* @__PURE__ */ jsx("br", {}),
|
|
447
|
+
tresetPassword("lowercase"),
|
|
448
|
+
" ",
|
|
449
|
+
/* @__PURE__ */ jsx("br", {}),
|
|
450
|
+
tresetPassword("lowercase"),
|
|
451
|
+
" ",
|
|
452
|
+
/* @__PURE__ */ jsx("br", {}),
|
|
453
|
+
tresetPassword("uppercase"),
|
|
454
|
+
" ",
|
|
455
|
+
/* @__PURE__ */ jsx("br", {}),
|
|
456
|
+
tresetPassword("digit"),
|
|
457
|
+
" ",
|
|
458
|
+
/* @__PURE__ */ jsx("br", {}),
|
|
459
|
+
tresetPassword("specialchar"),
|
|
460
|
+
" ",
|
|
461
|
+
/* @__PURE__ */ jsx("br", {}),
|
|
462
|
+
tresetPassword("minmax"),
|
|
463
|
+
" ",
|
|
464
|
+
/* @__PURE__ */ jsx("br", {})
|
|
465
|
+
] })
|
|
466
|
+
] }),
|
|
467
|
+
/* @__PURE__ */ jsx(
|
|
468
|
+
Input,
|
|
469
|
+
{
|
|
470
|
+
type: showNewPassword ? "text" : "password",
|
|
471
|
+
placeholder: "New Password",
|
|
472
|
+
className: `w-full ${hasAttemptedSave && newPasswordErrors.length > 0 ? "border-destructive" : ""}`,
|
|
473
|
+
value: newPassword,
|
|
474
|
+
onChange: handlePasswordChange
|
|
475
|
+
}
|
|
476
|
+
),
|
|
477
|
+
hasAttemptedSave && newPasswordErrors.map((error2, idx) => /* @__PURE__ */ jsx(PasswordError, { message: error2 }, idx)),
|
|
478
|
+
/* @__PURE__ */ jsx(
|
|
479
|
+
Input,
|
|
480
|
+
{
|
|
481
|
+
type: showConfirmPassword ? "text" : "password",
|
|
482
|
+
placeholder: "Confirm Password",
|
|
483
|
+
value: confirmPassword,
|
|
484
|
+
onChange: handleConfirmPasswordChange
|
|
485
|
+
}
|
|
486
|
+
),
|
|
487
|
+
hasAttemptedSave && confirmPasswordError && /* @__PURE__ */ jsx(PasswordError, { message: confirmPasswordError }),
|
|
488
|
+
error && /* @__PURE__ */ jsx("div", { className: "auth-pw-error", children: error }),
|
|
489
|
+
/* @__PURE__ */ jsx(
|
|
490
|
+
Button,
|
|
491
|
+
{
|
|
492
|
+
onClick: handleResetPassword,
|
|
493
|
+
disabled: isLoading,
|
|
494
|
+
className: "w-full",
|
|
495
|
+
children: isLoading ? /* @__PURE__ */ jsx(LoadingSpinner, {}) : "Change Password"
|
|
496
|
+
}
|
|
497
|
+
),
|
|
498
|
+
/* @__PURE__ */ jsxs(
|
|
499
|
+
Button,
|
|
500
|
+
{
|
|
501
|
+
variant: "outline",
|
|
502
|
+
onClick: () => setStep("login"),
|
|
503
|
+
className: "w-full",
|
|
504
|
+
children: [
|
|
505
|
+
/* @__PURE__ */ jsx(LR.ArrowLeft, { size: 16 }),
|
|
506
|
+
"Back to Login"
|
|
507
|
+
]
|
|
508
|
+
}
|
|
509
|
+
)
|
|
510
|
+
] }),
|
|
213
511
|
step === "login" && /* @__PURE__ */ jsx("div", { className: "auth-captcha-wrapper", children: /* @__PURE__ */ jsx(
|
|
214
512
|
ReCAPTCHA,
|
|
215
513
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/core/components/authentication/Signin.tsx"],"sourcesContent":["'use client'\r\n\r\n// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\nimport * as React from 'react'\r\nimport { signIn } from 'next-auth/react'\r\nimport { useTranslations } from 'next-intl'\r\nimport * as LR from 'lucide-react'\r\nimport { toast, Toaster } from 'sonner'\r\nimport { Button, GoogleIcon, Input, LoadingSpinner } from '../ui'\r\nimport { AuthPage, useAuthTheme } from './AuthPage'\r\nimport { useParams, useSearchParams } from 'next/navigation'\r\nimport ReCAPTCHA from 'react-google-recaptcha'\r\n//import { useAppConfigContext } from '../../store/AppConfig/context'\r\n\r\ninterface SignInContentProps {\r\n recaptchaSiteKey?: string\r\n}\r\n\r\nfunction SignInContent({ recaptchaSiteKey, }) {\r\n const [step, setStep] = React.useState<'login' | 'mfa'>('login')\r\n\r\n const [email, setEmail] = React.useState('')\r\n const [password, setPassword] = React.useState('')\r\n const [code, setCode] = React.useState('')\r\n\r\n const recaptchaRef = React.useRef<ReCAPTCHA>(null)\r\n const [captchaStatus, setCaptchaStatus] = React.useState(false)\r\n const [captchaToken, setCaptchaToken] = React.useState('')\r\n const [isLoading, setIsLoading] = React.useState(false)\r\n const [error, setError] = React.useState('')\r\n const [showPassword, setShowPassword] = React.useState(false)\r\n\r\n const searchParams = useSearchParams()\r\n const params = useParams()\r\n const orgName = params.instance ?? 'canada'\r\n const [googleError, setGoogleError] = React.useState(\r\n searchParams.get('error')\r\n )\r\n //Clean up the Google query error in URL, and have it only return /orgName/signin to clear frontend error responses \r\n React.useEffect(() => {\r\n if (googleError) {\r\n window.history.replaceState({}, '', `/${orgName}/signin`)\r\n }\r\n }, [googleError, orgName])\r\n\r\n const t = useTranslations('Signin')\r\n const tMfa = useTranslations('MFA')\r\n const authTheme = useAuthTheme()\r\n\r\n \r\n\r\n const resetCaptcha = () => {\r\n recaptchaRef.current?.reset()\r\n setCaptchaToken('')\r\n setCaptchaStatus(false)\r\n }\r\n\r\n const onReCaptchaSuccess = (token) => {\r\n setCaptchaToken(token)\r\n setCaptchaStatus(true)\r\n }\r\n\r\n // Initial LOGIN\r\n const handleSubmit = async (e) => {\r\n e.preventDefault()\r\n setGoogleError(null)\r\n setIsLoading(true)\r\n setError('')\r\n\r\n try {\r\n const result = await signIn('credentials', {\r\n redirect: false,\r\n email,\r\n password,\r\n captchaToken,\r\n })\r\n\r\n if (result?.error) {\r\n\r\n if (result.code === 'rate_limit_error') {\r\n\r\n setIsLoading(true)\r\n setError('Too many failed login attempts. Please try again later.')\r\n return\r\n }\r\n\r\n else if (result.code === 'whitelist_invalid_credentials') {\r\n setError('Invalid email or password')\r\n setIsLoading(false)\r\n resetCaptcha()\r\n return\r\n }\r\n\r\n else if (!captchaStatus) {\r\n setError('Captcha Verification Failed.')\r\n setIsLoading(false)\r\n resetCaptcha()\r\n return\r\n }\r\n\r\n else if (result.code === 'invalid_credentials') {\r\n setError('Invalid email or password')\r\n setIsLoading(false)\r\n resetCaptcha()\r\n return\r\n }\r\n //MFA TRIGGER\r\n else if (result.code === 'mfa_required') {\r\n setStep('mfa')\r\n setIsLoading(false)\r\n return\r\n }\r\n\r\n else { //result.code === 'expired_recaptcha_token\r\n setError('Captcha Verification Expired. Please try again later.')\r\n setIsLoading(false)\r\n resetCaptcha()\r\n return\r\n }\r\n }\r\n\r\n // Completed Login + MFA - Redirect to the Platform's Organization Dashboard \r\n window.location.href = `/${orgName}`\r\n\r\n } catch (err) {\r\n setError('Unexpected error. Please try again.')\r\n setIsLoading(false)\r\n }\r\n }\r\n\r\n // VERIFY OTP for MFA\r\n const handleVerifyOTP = async () => {\r\n setIsLoading(true)\r\n setError('')\r\n\r\n try {\r\n const res = await fetch('/api/mfa', {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify({ email, code }),\r\n })\r\n\r\n if (!res.ok) {\r\n toast.error(tMfa('invalidCode'))\r\n setIsLoading(false)\r\n return\r\n }\r\n\r\n toast.success(tMfa('success'))\r\n\r\n // FINAL LOGIN after successful MFA process\r\n await signIn('credentials', {\r\n email,\r\n password,\r\n mfaVerified: true,\r\n redirect: true,\r\n redirectTo: `/${orgName}`,\r\n })\r\n\r\n } catch (err) {\r\n toast.error(tMfa('verificationFailed'))\r\n setIsLoading(false)\r\n }\r\n }\r\n\r\n return (\r\n <>\r\n <Toaster richColors position=\"top-right\" />\r\n {/* Header */}\r\n <div className=\"space-y-2 text-left\">\r\n <h1 className=\"font-display font-bold\" style={{\r\n fontSize: '1.75rem',\r\n lineHeight: '1.1',\r\n letterSpacing: '-0.02em',\r\n color: 'var(--hp-on-surface)',\r\n }}>\r\n {step === 'login' ? t('title') : tMfa('title')}\r\n </h1>\r\n\r\n <p style={{ color: 'var(--hp-on-surface-variant)', fontSize: '0.9rem' }}>\r\n {step === 'login'\r\n ? t('message')\r\n : tMfa('subtitle', { email })}\r\n </p>\r\n </div>\r\n\r\n {/* LOGIN FORM */}\r\n {step === 'login' && (\r\n <form onSubmit={handleSubmit} className=\"space-y-4\">\r\n\r\n <Input\r\n type=\"email\"\r\n placeholder={t('placeholder1')}\r\n value={email}\r\n onChange={(e) => setEmail(e.target.value)}\r\n disabled={isLoading}\r\n required\r\n />\r\n\r\n <div className=\"relative\">\r\n <Input\r\n type={showPassword ? 'text' : 'password'}\r\n placeholder={t('placeholder2')}\r\n value={password}\r\n onChange={(e) => setPassword(e.target.value)}\r\n disabled={isLoading}\r\n required\r\n className=\"pr-10\"\r\n />\r\n <button\r\n type=\"button\"\r\n onClick={() => setShowPassword(v => !v)}\r\n tabIndex={-1}\r\n className=\"absolute right-3 top-1/2 -translate-y-1/2 transition-colors\"\r\n style={{ color: 'var(--hp-on-surface-variant)' }}\r\n >\r\n {showPassword ? <LR.EyeOff size={16} /> : <LR.Eye size={16} />}\r\n </button>\r\n </div>\r\n {/* Google Not Linked Error */}\r\n {googleError === 'google_not_linked' && (\r\n <div className=\"auth-pw-error\">\r\n Your Google account is not linked. Please sign in with your credentials first, then link your Google account.\r\n </div>\r\n )}\r\n {error && <div className=\"auth-pw-error\">{error}</div>}\r\n\r\n <div className=\"flex items-center gap-2\">\r\n <Button type=\"submit\" disabled={isLoading} className=\"flex-1 auth-btn-primary\">\r\n {isLoading ? <LoadingSpinner /> : 'Login'}\r\n </Button>\r\n\r\n {/* Google button */}\r\n {<button\r\n type=\"button\"\r\n onClick={() => signIn('google', { redirectTo: `/${orgName}` })}\r\n disabled={isLoading}\r\n aria-label=\"Sign in with Google\"\r\n className=\"auth-google-btn\"\r\n >\r\n <GoogleIcon size={20} />\r\n </button>}\r\n\r\n </div>\r\n\r\n {/*⚠️⚠️⚠️⚠️ DISABLED FOR NOW - Password Reset link, will implement in the future when we have the flow ready */}\r\n {/* Reset Password link */}\r\n {/* <div className=\"flex justify-start\">\r\n <a\r\n href={`/${orgName}/auth/reset-password`}\r\n className=\"text-sm underline underline-offset-4 hover:opacity-80\"\r\n style={{ color: 'var(--hp-primary)' }}\r\n >\r\n Reset your password\r\n </a>\r\n </div> */}\r\n </form>\r\n )}\r\n\r\n {/* MFA FORM */}\r\n {step === 'mfa' && (\r\n <div className=\"space-y-4\">\r\n\r\n <Input\r\n placeholder={tMfa('placeholder')}\r\n value={code}\r\n onChange={(e) => setCode(e.target.value)}\r\n disabled={isLoading}\r\n />\r\n\r\n <Button onClick={handleVerifyOTP} disabled={isLoading} className=\"w-full\">\r\n {isLoading ? <LoadingSpinner /> : tMfa('verify')}\r\n </Button>\r\n\r\n {/* Back */}\r\n <Button\r\n variant=\"outline\"\r\n onClick={() => setStep('login')}\r\n className=\"w-full mt-3 inline-flex items-center justify-center gap-2\"\r\n >\r\n <LR.ArrowLeft size={16} />\r\n {tMfa('backToLogin')}\r\n </Button>\r\n </div>\r\n )}\r\n\r\n {/* CAPTCHA only on Credentials(Username and Password) Provider login */}\r\n \r\n {step === 'login' && (\r\n <div className=\"auth-captcha-wrapper\">\r\n <ReCAPTCHA\r\n ref={recaptchaRef}\r\n key={`recaptcha-${authTheme}`}\r\n sitekey={recaptchaSiteKey ?? ''}\r\n onChange={(token) => onReCaptchaSuccess(token)}\r\n theme={authTheme}\r\n />\r\n </div>\r\n )}\r\n </>\r\n )\r\n}\r\n\r\ninterface SignInProps {\r\n recaptchaSiteKey?: string\r\n minioBaseUrl?: string\r\n}\r\n\r\nexport function SignIn({ recaptchaSiteKey,minioBaseUrl, }: SignInProps) {\r\n return (\r\n <AuthPage minioBaseUrl={minioBaseUrl}>\r\n <SignInContent recaptchaSiteKey={recaptchaSiteKey} />\r\n </AuthPage>\r\n )\r\n}"],"mappings":"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","names":["_a"]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/core/components/authentication/Signin.tsx"],"sourcesContent":["'use client'\r\n\r\n// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\nimport * as React from 'react'\r\nimport { signIn } from 'next-auth/react'\r\nimport { useTranslations } from 'next-intl'\r\nimport * as LR from 'lucide-react'\r\nimport { toast, Toaster } from 'sonner'\r\nimport { Button, GoogleIcon, Input, LoadingSpinner } from '../ui'\r\nimport { AuthPage, useAuthTheme } from './AuthPage'\r\nimport { useParams, useSearchParams } from 'next/navigation'\r\nimport ReCAPTCHA from 'react-google-recaptcha'\r\nimport { PasswordError } from '../authentication/PasswordError'\r\nimport { AuthHeader } from './SignInAuthHeader'\r\n//import { useAppConfigContext } from '../../store/AppConfig/context'\r\n\r\ninterface SignInContentProps {\r\n recaptchaSiteKey?: string\r\n}\r\n\r\nfunction SignInContent({ recaptchaSiteKey, }) {\r\n const [step, setStep] = React.useState<\r\n 'login'\r\n | 'mfa'\r\n | 'forgotPassword'\r\n | 'forgotPasswordSent'\r\n | 'changePassword'\r\n>('login')\r\n\r\n const [email, setEmail] = React.useState('')\r\n const [password, setPassword] = React.useState('')\r\n const [code, setCode] = React.useState('')\r\n\r\n const recaptchaRef = React.useRef<ReCAPTCHA>(null)\r\n const [captchaStatus, setCaptchaStatus] = React.useState(false)\r\n const [captchaToken, setCaptchaToken] = React.useState('')\r\n const [isLoading, setIsLoading] = React.useState(false)\r\n const [error, setError] = React.useState('')\r\n const [showPassword, setShowPassword] = React.useState(false)\r\n const [confirmPassword, setConfirmPassword] = React.useState('')\r\n\r\n const [showNewPassword, setShowNewPassword] = React.useState(false)\r\n const [showConfirmPassword, setShowConfirmPassword] = React.useState(false)\r\n const [currentPassword, setCurrentPassword] = React.useState('')\r\n const [newPassword, setNewPassword] = React.useState('')\r\n\r\n const [newPasswordErrors, setNewPasswordErrors] = React.useState<string[]>([])\r\n const [passwordErrors, setPasswordErrors] = React.useState<string[]>([])\r\n const [confirmPasswordError, setConfirmPasswordError] = React.useState('')\r\n const [hasAttemptedSave, setHasAttemptedSave] = React.useState(false)\r\n const [hasAttemptedSubmit, setHasAttemptedSubmit] = React.useState(false)\r\n \r\n\r\n const searchParams = useSearchParams()\r\n const params = useParams()\r\n const orgName = params.instance ?? 'canada'\r\n const [googleError, setGoogleError] = React.useState(\r\n searchParams.get('error')\r\n )\r\n //Clean up the Google query error in URL, and have it only return /orgName/signin to clear frontend error responses \r\n React.useEffect(() => {\r\n if (googleError) {\r\n window.history.replaceState({}, '', `/${orgName}/signin`)\r\n }\r\n }, [googleError, orgName])\r\n\r\n const t = useTranslations('Signin')\r\n const tMfa = useTranslations('MFA')\r\n const tforgotPassword = useTranslations('forgotPassword')\r\n const tresetPassword = useTranslations('resetPassword')\r\n const authTheme = useAuthTheme()\r\n\r\n \r\n\r\n const resetCaptcha = () => {\r\n recaptchaRef.current?.reset()\r\n setCaptchaToken('')\r\n setCaptchaStatus(false)\r\n }\r\n\r\n const onReCaptchaSuccess = (token) => {\r\n setCaptchaToken(token)\r\n setCaptchaStatus(true)\r\n }\r\n\r\n // Initial LOGIN with Credentials(Username and Password)\r\n const handleSubmit = async (e) => {\r\n e.preventDefault()\r\n setGoogleError(null)\r\n setIsLoading(true)\r\n setError('')\r\n\r\n try {\r\n const result = await signIn('credentials', {\r\n redirect: false,\r\n email,\r\n password,\r\n captchaToken,\r\n })\r\n\r\n if (result?.error) {\r\n\r\n if (result.code === 'rate_limit_error') {\r\n\r\n setIsLoading(true)\r\n setError('Too many failed login attempts. Please try again later.')\r\n return\r\n }\r\n\r\n else if (result.code === 'whitelist_invalid_credentials') {\r\n setError('Invalid email or password')\r\n setIsLoading(false)\r\n resetCaptcha()\r\n return\r\n }\r\n\r\n else if (!captchaStatus) {\r\n setError('Captcha Verification Failed.')\r\n setIsLoading(false)\r\n resetCaptcha()\r\n return\r\n }\r\n\r\n else if (result.code === 'invalid_credentials') {\r\n setError('Invalid email or password')\r\n setIsLoading(false)\r\n resetCaptcha()\r\n return\r\n }\r\n //MFA TRIGGER\r\n else if (result.code === 'mfa_required') {\r\n setStep('mfa')\r\n setIsLoading(false)\r\n return\r\n }\r\n\r\n else { //result.code === 'expired_recaptcha_token\r\n setError('Captcha Verification Expired. Please try again later.')\r\n setIsLoading(false)\r\n resetCaptcha()\r\n return\r\n }\r\n }\r\n\r\n // Completed Login + MFA - Redirect to the Platform's Organization Dashboard \r\n window.location.href = `/${orgName}`\r\n\r\n } catch (err) {\r\n setError('Unexpected error. Please try again.')\r\n setIsLoading(false)\r\n }\r\n }\r\n\r\n // VERIFY OTP for MFA\r\n const handleVerifyOTP = async () => {\r\n setIsLoading(true)\r\n setError('')\r\n\r\n try {\r\n const res = await fetch('/api/mfa', {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify({ email, code }),\r\n })\r\n\r\n if (!res.ok) {\r\n toast.error(tMfa('invalidCode'))\r\n setIsLoading(false)\r\n return\r\n }\r\n\r\n toast.success(tMfa('success'))\r\n\r\n // FINAL LOGIN after successful MFA process\r\n await signIn('credentials', {\r\n email,\r\n password,\r\n mfaVerified: true,\r\n redirect: true,\r\n redirectTo: `/${orgName}`,\r\n })\r\n\r\n } catch (err) {\r\n toast.error(tMfa('verificationFailed'))\r\n setIsLoading(false)\r\n }\r\n }\r\n\r\n // Password Policy for New Password used for Reset Password flow\r\n const validatePassword = (password: string): string[] => {\r\n const errors: string[] = []\r\n\r\n // Regex Pattern - At least:\r\n // 1 lowercase:(?=.*[a-z])\r\n // 1 uppercase: (?=.*[A-Z])\r\n // 1 digit: (?=.*\\d)\r\n // 1 special char: (?=.*[@$!%*?&_])\r\n //min 12 characters, max 65: {12,65}\r\n const passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[^a-zA-Z\\d\\s])[^\\s]{12,65}$/;\r\n if (!passwordRegex.test(password)) {\r\n errors.push(t('weakPassword'));\r\n }\r\n // if (password.toLowerCase().includes(username.toLowerCase())) {\r\n // //errors.push(t('containsUsername'));\r\n // errors.push(t('weakPassword'));\r\n\r\n // } \r\n\r\n return errors\r\n }\r\n\r\n const handlePasswordChange = (e: React.ChangeEvent<HTMLInputElement>) => {\r\n const value = e.target.value\r\n setNewPassword(value)\r\n setNewPasswordErrors(validatePassword(value))\r\n if (confirmPassword) {\r\n setConfirmPasswordError(value === confirmPassword ? '' : tforgotPassword('noMatch'))\r\n }\r\n }\r\n const handleConfirmPasswordChange = (e: React.ChangeEvent<HTMLInputElement>) => {\r\n const value = e.target.value\r\n setConfirmPassword(value)\r\n setConfirmPasswordError(value === newPassword ? '' : tforgotPassword('noMatch'))\r\n } \r\n\r\n //Forgot Password Flow: 1. User Clicks Reset Password > 2. OTP is emailed(forgotpassword API)\r\n // > 3. OTP is verified(verifyotp API) > 4. User chooses a new password(resetpassword API)\r\n\r\n //2. Initiate ForgotPasword flow - OTP is emailed\r\n const handleForgotPassword = async () => {\r\n setIsLoading(true)\r\n setError('')\r\n\r\n try {\r\n const res = await fetch('/api/forgotpassword', {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n },\r\n body: JSON.stringify({\r\n email\r\n }),\r\n })\r\n\r\n if (!res.ok) {\r\n setError('Unable to send password reset email.')\r\n setIsLoading(false)\r\n return\r\n }\r\n\r\n //Redirect to Verify OTP flow to enter OTP that has been emailed \r\n setStep('forgotPasswordSent')\r\n setIsLoading(false)\r\n\r\n } catch {\r\n setError('Unable to process')\r\n setIsLoading(false)\r\n }\r\n}\r\n\r\n// 3. Handle Change Password - OTP is getting verified\r\n // VERIFY OTP for MFA\r\n const handleVerifyOTPForPasswordChange = async () => {\r\n //NEW------------------------------------------------------------------\r\n setIsLoading(true)\r\n setError('')\r\n\r\n try {\r\n\r\n const res = await fetch('/api/verifyotp', {\r\n\r\n method: 'POST',\r\n\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n },\r\n\r\n body: JSON.stringify({\r\n email,\r\n code,\r\n }),\r\n })\r\n\r\n if (!res.ok) {\r\n\r\n //setError('Invalid verification code.')\r\n toast.error('Invalid verification code.')\r\n setIsLoading(false)\r\n return\r\n\r\n }\r\n toast.success(\"SUCCESS\")\r\n //Redirect User to enter New Password in Change Password page\r\n setStep('changePassword')\r\n\r\n } catch {\r\n\r\n setError('Unable to verify code.')\r\n\r\n } finally {\r\n\r\n setIsLoading(false)\r\n\r\n }\r\n\r\n }\r\n\r\n //Final Step: Reset Password \r\nconst handleResetPassword = async () => {\r\n\r\n setHasAttemptedSubmit(true)\r\n\r\n const errors = validatePassword(newPassword)\r\n\r\n setPasswordErrors(errors)\r\n \r\n\r\n if (newPassword !== confirmPassword) {\r\n\r\n toast.error(tforgotPassword('noMatch'))\r\n return\r\n\r\n }\r\n\r\n if (errors.length > 0){\r\n toast.error(tforgotPassword('passwordPolicyError'))\r\n return\r\n }\r\n setIsLoading(true)\r\n setError('')\r\n\r\n\r\n try {\r\n\r\n const res = await fetch('/api/resetpassword', {\r\n\r\n method: 'POST',\r\n\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n },\r\n\r\n body: JSON.stringify({\r\n\r\n email,\r\n code,\r\n newPassword,\r\n\r\n }),\r\n })\r\n\r\n if (!res.ok) {\r\n\r\n toast.error('Session Expired: Unable to reset password.')\r\n setStep('login')\r\n return\r\n\r\n }\r\n\r\n toast.success('Password successfully changed.')\r\n\r\n setNewPassword('')\r\n setConfirmPassword('')\r\n setCode('')\r\n setStep('login')\r\n\r\n } finally {\r\n\r\n setIsLoading(false)\r\n\r\n }\r\n\r\n\r\n}\r\n return (\r\n <>\r\n <Toaster richColors position=\"top-right\" />\r\n\r\n {/* LOGIN FORM */}\r\n {step === 'login' && (\r\n <form onSubmit={handleSubmit} className=\"space-y-4\">\r\n {/* LOGIN Header */}\r\n <div className=\"space-y-2 text-left\">\r\n\r\n <h1 className=\"font-display font-bold\" style={{\r\n fontSize: '1.75rem',\r\n lineHeight: '1.1',\r\n letterSpacing: '-0.02em',\r\n color: 'var(--hp-on-surface)',\r\n }}>\r\n {/* {step === 'login' ? t('title') : tMfa('title')} */}\r\n {t('title')}\r\n </h1>\r\n\r\n <p style={{ color: 'var(--hp-on-surface-variant)', fontSize: '0.9rem' }}>\r\n {/* {step === 'login'\r\n ? t('message')\r\n : tMfa('subtitle', { email })} */}\r\n {t('message')}\r\n </p>\r\n </div> \r\n\r\n <Input\r\n type=\"email\"\r\n placeholder={t('placeholder1')}\r\n value={email}\r\n onChange={(e) => setEmail(e.target.value)}\r\n disabled={isLoading}\r\n required\r\n />\r\n\r\n <div className=\"relative\">\r\n <Input\r\n type={showPassword ? 'text' : 'password'}\r\n placeholder={t('placeholder2')}\r\n value={password}\r\n onChange={(e) => setPassword(e.target.value)}\r\n disabled={isLoading}\r\n required\r\n className=\"pr-10\"\r\n />\r\n <button\r\n type=\"button\"\r\n onClick={() => setShowPassword(v => !v)}\r\n tabIndex={-1}\r\n className=\"absolute right-3 top-1/2 -translate-y-1/2 transition-colors\"\r\n style={{ color: 'var(--hp-on-surface-variant)' }}\r\n >\r\n {showPassword ? <LR.EyeOff size={16} /> : <LR.Eye size={16} />}\r\n </button>\r\n </div>\r\n {/* Google Not Linked Error */}\r\n {googleError === 'google_not_linked' && (\r\n <div className=\"auth-pw-error\">\r\n Your Google account is not linked. Please sign in with your credentials first, then link your Google account.\r\n </div>\r\n )}\r\n {error && <div className=\"auth-pw-error\">{error}</div>}\r\n\r\n <div className=\"flex items-center gap-2\">\r\n <Button type=\"submit\" disabled={isLoading} className=\"flex-1 auth-btn-primary\">\r\n {isLoading ? <LoadingSpinner /> : 'Login'}\r\n </Button>\r\n\r\n {/* Google button */}\r\n {<button\r\n type=\"button\"\r\n onClick={() => signIn('google', { redirectTo: `/${orgName}` })}\r\n disabled={isLoading}\r\n aria-label=\"Sign in with Google\"\r\n className=\"auth-google-btn\"\r\n >\r\n <GoogleIcon size={20} />\r\n </button>}\r\n\r\n </div>\r\n {/* Reset Password Link */}\r\n <button\r\n type=\"button\"\r\n onClick={() => {\r\n setError('')\r\n setStep('forgotPassword')\r\n }}\r\n className=\"text-sm underline underline-offset-4 hover:opacity-80\"\r\n style={{ color: 'var(--hp-primary)' }}\r\n >\r\n Reset your password\r\n </button>\r\n\r\n </form>\r\n )}\r\n\r\n {/* MFA FORM */}\r\n {step === 'mfa' && (\r\n <div className=\"space-y-4\">\r\n <div className=\"space-y-2 text-left\">\r\n <h1 className=\"font-display font-bold\" style={{\r\n fontSize: '1.75rem',\r\n lineHeight: '1.1',\r\n letterSpacing: '-0.02em',\r\n color: 'var(--hp-on-surface)',\r\n }}>\r\n {/* {step === 'login' ? t('title') : tMfa('title')} */}\r\n {tMfa('title')}\r\n </h1>\r\n\r\n <p style={{ color: 'var(--hp-on-surface-variant)', fontSize: '0.9rem' }}>\r\n {/* {step === 'login'\r\n ? t('message')\r\n : tMfa('subtitle', { email })} */}\r\n {tMfa('subtitle',{email})}\r\n </p>\r\n </div>\r\n\r\n <Input\r\n placeholder={tMfa('placeholder')}\r\n value={code}\r\n onChange={(e) => setCode(e.target.value)}\r\n disabled={isLoading}\r\n />\r\n\r\n <Button onClick={handleVerifyOTP} disabled={isLoading} className=\"w-full\">\r\n {isLoading ? <LoadingSpinner /> : tMfa('verify')}\r\n </Button>\r\n\r\n {/* Back */}\r\n <Button\r\n variant=\"outline\"\r\n onClick={() => setStep('login')}\r\n className=\"w-full mt-3 inline-flex items-center justify-center gap-2\"\r\n >\r\n <LR.ArrowLeft size={16} />\r\n {tMfa('backToLogin')}\r\n </Button>\r\n </div>\r\n )}\r\n {/*Forgot Password step: Send OTP for Reset */}\r\n {step === 'forgotPassword' && (\r\n <div className=\"space-y-4\">\r\n <div className=\"space-y-2 text-left\">\r\n <h1 className=\"font-display font-bold\" style={{\r\n fontSize: '1.75rem',\r\n lineHeight: '1.1',\r\n letterSpacing: '-0.02em',\r\n color: 'var(--hp-on-surface)',\r\n }}>\r\n {/* {step === 'login' ? t('title') : tMfa('title')} */}\r\n {tresetPassword('title')}\r\n </h1>\r\n\r\n <p style={{ color: 'var(--hp-on-surface-variant)', fontSize: '0.9rem' }}>\r\n {/* {step === 'login'\r\n ? t('message')\r\n : tMfa('subtitle', { email })} */}\r\n {tresetPassword('subtitle')}\r\n </p>\r\n </div> \r\n\r\n <Input\r\n type=\"email\"\r\n placeholder=\"Enter your email address\"\r\n value={email}\r\n onChange={(e) => setEmail(e.target.value)}\r\n disabled={isLoading}\r\n />\r\n\r\n {error && (\r\n <div className=\"auth-pw-error\">\r\n {error}\r\n </div>\r\n )}\r\n\r\n <Button\r\n onClick={handleForgotPassword}\r\n disabled={isLoading || !email}\r\n className=\"w-full\"\r\n >\r\n {isLoading\r\n ? <LoadingSpinner />\r\n : 'Send Reset Link'}\r\n </Button>\r\n\r\n <Button\r\n variant=\"outline\"\r\n onClick={() => setStep('login')}\r\n className=\"w-full\"\r\n >\r\n <LR.ArrowLeft size={16} />\r\n Back to Login\r\n </Button>\r\n\r\n </div>\r\n)}\r\n{/* Verify OTP for Password Change */}\r\n{step === 'forgotPasswordSent' && (\r\n <div className=\"space-y-4\">\r\n <div className=\"space-y-2 text-left\">\r\n <h1 className=\"font-display font-bold\" style={{\r\n fontSize: '1.75rem',\r\n lineHeight: '1.1',\r\n letterSpacing: '-0.02em',\r\n color: 'var(--hp-on-surface)',\r\n }}>\r\n {/* {step === 'login' ? t('title') : tMfa('title')} */}\r\n {tresetPassword('title')}\r\n </h1>\r\n\r\n <p style={{ color: 'var(--hp-on-surface-variant)', fontSize: '0.9rem' }}>\r\n {/* {step === 'login'\r\n ? t('message')\r\n : tMfa('subtitle', { email })} */}\r\n {tresetPassword('ifAnAccountExists',{email})}\r\n </p>\r\n </div>\r\n <Input\r\n placeholder={tMfa('placeholder')}\r\n value={code}\r\n onChange={(e) => setCode(e.target.value)}\r\n disabled={isLoading}\r\n />\r\n{error && (\r\n <div className=\"auth-pw-error\">\r\n {error}\r\n </div>\r\n)}\r\n <Button onClick={handleVerifyOTPForPasswordChange} disabled={isLoading} className=\"w-full\">\r\n {isLoading ? <LoadingSpinner /> : tMfa('verify')}\r\n </Button>\r\n\r\n <Button\r\n onClick={() => setStep('login')}\r\n className=\"w-full\"\r\n >\r\n Back to Login\r\n </Button>\r\n\r\n </div>\r\n)}\r\n\r\n{/*Change PAssword */}\r\n{step === 'changePassword' && (\r\n\r\n<div className=\"space-y-4\">\r\n <div className=\"space-y-2 text-left\">\r\n <h1 className=\"font-display font-bold\" style={{\r\n fontSize: '1.75rem',\r\n lineHeight: '1.1',\r\n letterSpacing: '-0.02em',\r\n color: 'var(--hp-on-surface)',\r\n }}>\r\n {/* {step === 'login' ? t('title') : tMfa('title')} */}\r\n {tresetPassword('newPasswordTitle')}\r\n </h1>\r\n\r\n <p style={{ color: 'var(--hp-on-surface-variant)', fontSize: '0.9rem' }}>\r\n {/* {step === 'login'\r\n ? t('message')\r\n : tMfa('subtitle', { email })} */}\r\n {tresetPassword('newPasswordMessage')}<br /> <br />\r\n {tresetPassword('lowercase')} <br />\r\n {tresetPassword('lowercase')} <br />\r\n {tresetPassword('uppercase')} <br />\r\n {tresetPassword('digit')} <br />\r\n {tresetPassword('specialchar')} <br />\r\n {tresetPassword('minmax')} <br />\r\n </p>\r\n\r\n </div>\r\n \r\n \r\n <Input\r\n type={showNewPassword ? 'text' : 'password'}\r\n placeholder=\"New Password\"\r\n className={`w-full ${hasAttemptedSave && newPasswordErrors.length > 0 ? 'border-destructive' : ''}`}\r\n value={newPassword}\r\n onChange={handlePasswordChange}\r\n />\r\n\r\n {hasAttemptedSave && newPasswordErrors.map((error, idx) => (\r\n <PasswordError key={idx} message={error} />\r\n ))}\r\n\r\n\r\n <Input\r\n type={showConfirmPassword ? 'text' : 'password'}\r\n placeholder=\"Confirm Password\"\r\n value={confirmPassword}\r\n onChange={handleConfirmPasswordChange}\r\n />\r\n\r\n \r\n {hasAttemptedSave && confirmPasswordError && (\r\n <PasswordError message={confirmPasswordError} />\r\n )}\r\n\r\n {error && (\r\n <div className=\"auth-pw-error\">\r\n {error}\r\n </div>\r\n )}\r\n\r\n <Button\r\n onClick={handleResetPassword}\r\n disabled={isLoading}\r\n className=\"w-full\"\r\n >\r\n {isLoading\r\n ? <LoadingSpinner />\r\n : 'Change Password'}\r\n </Button>\r\n\r\n\r\n <Button\r\n variant=\"outline\"\r\n onClick={() => setStep('login')}\r\n className=\"w-full\"\r\n >\r\n <LR.ArrowLeft size={16} />\r\n Back to Login\r\n </Button>\r\n\r\n</div>\r\n\r\n)}\r\n {/* CAPTCHA only on Credentials(Username and Password) Provider login */}\r\n \r\n {step === 'login' && (\r\n <div className=\"auth-captcha-wrapper\">\r\n <ReCAPTCHA\r\n ref={recaptchaRef}\r\n key={`recaptcha-${authTheme}`}\r\n sitekey={recaptchaSiteKey ?? ''}\r\n onChange={(token) => onReCaptchaSuccess(token)}\r\n theme={authTheme}\r\n />\r\n </div>\r\n )}\r\n </>\r\n )\r\n}\r\n\r\ninterface SignInProps {\r\n recaptchaSiteKey?: string\r\n minioBaseUrl?: string\r\n}\r\n\r\nexport function SignIn({ recaptchaSiteKey,minioBaseUrl, }: SignInProps) {\r\n return (\r\n <AuthPage minioBaseUrl={minioBaseUrl}>\r\n <SignInContent recaptchaSiteKey={recaptchaSiteKey} />\r\n </AuthPage>\r\n )\r\n}"],"mappings":"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","names":["_a","password","error"]}
|
|
@@ -14,10 +14,10 @@ function UserSettings({ minioBaseUrl }) {
|
|
|
14
14
|
{ key: "users", label: t("users") },
|
|
15
15
|
{ key: "organization", label: t("organization") }
|
|
16
16
|
], [t]);
|
|
17
|
-
return /* @__PURE__ */ jsx("div", { className: "sm:p-2 overflow-hidden bg-[#fafafa] h-full", children: /* @__PURE__ */ jsx("div", { className: "bg-background rounded-xl shadow min-h-full", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-
|
|
17
|
+
return /* @__PURE__ */ jsx("div", { className: "sm:p-2 overflow-hidden bg-[#fafafa] h-full", children: /* @__PURE__ */ jsx("div", { className: "bg-background rounded-xl shadow min-h-full", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full", children: [
|
|
18
18
|
/* @__PURE__ */ jsx(SettingsHeader, { title: t("settings") }),
|
|
19
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-row gap-2 p-6 h-
|
|
20
|
-
/* @__PURE__ */ jsx("div", { className: "
|
|
19
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col md:flex-row gap-2 p-6 flex-1 min-h-0 overflow-y-auto md:overflow-hidden", children: [
|
|
20
|
+
/* @__PURE__ */ jsx("div", { className: "flex-shrink-0 md:pr-4 lg:w-[280px]", children: /* @__PURE__ */ jsx(
|
|
21
21
|
SettingsSidebar,
|
|
22
22
|
{
|
|
23
23
|
tabs,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/core/components/settings/index.tsx"],"sourcesContent":["\"use client\"\r\n\r\n// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\nimport * as React from 'react'\r\nimport { useTranslations } from 'next-intl'\r\n\r\nimport { Separator } from '../ui/'\r\n\r\nimport SettingsHeader from './src/SettingsHeader'\r\nimport SettingsSidebar from './src/SettingsSidebar'\r\nimport SettingsContent from './src/SettingsContent'\r\nimport type { SettingsTabKey } from './src/types'\r\n\r\nexport function UserSettings({ minioBaseUrl }: { minioBaseUrl?: string }) {\r\n const t = useTranslations('UserSettings')\r\n const [activeTab, setActiveTab] = React.useState<SettingsTabKey>('account')\r\n\r\n const tabs = React.useMemo(() => (\r\n [\r\n { key: 'account' as const, label: t('account') },\r\n { key: 'users' as const, label: t('users') },\r\n { key: 'organization' as const, label: t('organization') },\r\n ]\r\n ), [t])\r\n\r\n return (\r\n <div className=\"sm:p-2 overflow-hidden bg-[#fafafa] h-full\">\r\n <div className=\"bg-background rounded-xl shadow min-h-full\">\r\n <div className=\"flex flex-col h-
|
|
1
|
+
{"version":3,"sources":["../../../../src/core/components/settings/index.tsx"],"sourcesContent":["\"use client\"\r\n\r\n// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\nimport * as React from 'react'\r\nimport { useTranslations } from 'next-intl'\r\n\r\nimport { Separator } from '../ui/'\r\n\r\nimport SettingsHeader from './src/SettingsHeader'\r\nimport SettingsSidebar from './src/SettingsSidebar'\r\nimport SettingsContent from './src/SettingsContent'\r\nimport type { SettingsTabKey } from './src/types'\r\n\r\nexport function UserSettings({ minioBaseUrl }: { minioBaseUrl?: string }) {\r\n const t = useTranslations('UserSettings')\r\n const [activeTab, setActiveTab] = React.useState<SettingsTabKey>('account')\r\n\r\n const tabs = React.useMemo(() => (\r\n [\r\n { key: 'account' as const, label: t('account') },\r\n { key: 'users' as const, label: t('users') },\r\n { key: 'organization' as const, label: t('organization') },\r\n ]\r\n ), [t])\r\n\r\n return (\r\n <div className=\"sm:p-2 overflow-hidden bg-[#fafafa] h-full\">\r\n <div className=\"bg-background rounded-xl shadow min-h-full\">\r\n <div className=\"flex flex-col h-full\">\r\n <SettingsHeader title={t('settings')} />\r\n\r\n <div className=\"flex flex-col md:flex-row gap-2 p-6 flex-1 min-h-0 overflow-y-auto md:overflow-hidden\">\r\n <div className=\"flex-shrink-0 md:pr-4 lg:w-[280px]\">\r\n <SettingsSidebar\r\n tabs={tabs}\r\n activeTab={activeTab}\r\n onTabChange={setActiveTab}\r\n />\r\n </div>\r\n\r\n <Separator orientation=\"vertical\" className=\"hidden md:!flex\" />\r\n\r\n <SettingsContent activeTab={activeTab} minioBaseUrl={minioBaseUrl} />\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n )\r\n}\r\n"],"mappings":";AA+BU,cAEA,YAFA;AA1BV,YAAY,WAAW;AACvB,SAAS,uBAAuB;AAEhC,SAAS,iBAAiB;AAE1B,OAAO,oBAAoB;AAC3B,OAAO,qBAAqB;AAC5B,OAAO,qBAAqB;AAGrB,SAAS,aAAa,EAAE,aAAa,GAA8B;AACxE,QAAM,IAAI,gBAAgB,cAAc;AACxC,QAAM,CAAC,WAAW,YAAY,IAAI,MAAM,SAAyB,SAAS;AAE1E,QAAM,OAAO,MAAM,QAAQ,MACzB;AAAA,IACE,EAAE,KAAK,WAAoB,OAAO,EAAE,SAAS,EAAE;AAAA,IAC/C,EAAE,KAAK,SAAkB,OAAO,EAAE,OAAO,EAAE;AAAA,IAC3C,EAAE,KAAK,gBAAyB,OAAO,EAAE,cAAc,EAAE;AAAA,EAC3D,GACC,CAAC,CAAC,CAAC;AAEN,SACE,oBAAC,SAAI,WAAU,8CACb,8BAAC,SAAI,WAAU,8CACb,+BAAC,SAAI,WAAU,wBACb;AAAA,wBAAC,kBAAe,OAAO,EAAE,UAAU,GAAG;AAAA,IAEtC,qBAAC,SAAI,WAAU,yFACb;AAAA,0BAAC,SAAI,WAAU,sCACb;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA;AAAA,UACA,aAAa;AAAA;AAAA,MACf,GACF;AAAA,MAEA,oBAAC,aAAU,aAAY,YAAW,WAAU,mBAAkB;AAAA,MAE9D,oBAAC,mBAAgB,WAAsB,cAA4B;AAAA,OACrE;AAAA,KACF,GACF,GACF;AAEJ;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OrganizationSettingsPanel.d.ts","sourceRoot":"","sources":["../../../../../src/core/components/settings/src/OrganizationSettingsPanel.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AA0B9B,UAAU,8BAA8B;IACtC,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,CAAC,OAAO,UAAU,yBAAyB,CAAC,EAChD,YAAY,GACb,EAAE,8BAA8B,
|
|
1
|
+
{"version":3,"file":"OrganizationSettingsPanel.d.ts","sourceRoot":"","sources":["../../../../../src/core/components/settings/src/OrganizationSettingsPanel.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AA0B9B,UAAU,8BAA8B;IACtC,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,CAAC,OAAO,UAAU,yBAAyB,CAAC,EAChD,YAAY,GACb,EAAE,8BAA8B,qBAgdhC"}
|
|
@@ -290,11 +290,12 @@ function OrganizationSettingsPanel({
|
|
|
290
290
|
/* @__PURE__ */ jsx(
|
|
291
291
|
Input,
|
|
292
292
|
{
|
|
293
|
-
value:
|
|
294
|
-
|
|
295
|
-
|
|
293
|
+
value: (organization == null ? void 0 : organization.name) || "",
|
|
294
|
+
disabled: true,
|
|
295
|
+
readOnly: true
|
|
296
296
|
}
|
|
297
|
-
)
|
|
297
|
+
),
|
|
298
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: t("fields.nameLocked") })
|
|
298
299
|
] }),
|
|
299
300
|
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
300
301
|
/* @__PURE__ */ jsx("label", { className: "text-sm font-medium", children: t("fields.title") }),
|