@collabdt/core 0.0.49 → 0.0.50
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/dist/core/components/AppSidebarContent.d.ts.map +1 -1
- package/dist/core/components/AppSidebarContent.js +28 -19
- package/dist/core/components/AppSidebarContent.js.map +1 -1
- package/dist/core/components/authentication/Signin.d.ts.map +1 -1
- package/dist/core/components/authentication/Signin.js +7 -8
- package/dist/core/components/authentication/Signin.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AppSidebarContent.d.ts","sourceRoot":"","sources":["../../../src/core/components/AppSidebarContent.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AA2BvC,OAAO,EAAE,YAAY,EAAY,MAAM,kBAAkB,CAAA;AAKzD,eAAO,MAAM,kBAAkB,GAC7B,QAAQ,WAAW,EACnB,iBAAiB,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,EAC1D,iBAAiB,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,EAC1D,iBAAiB,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,EAC1D,SAAS,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,GAAG,QAAQ,CAAC,CAAC,EACjE,eAAe,GAAG,SAYnB,CAAA;AAED,UAAU,eAAe;IACvB,YAAY,EAAE,YAAY,CAAA;IAC1B,uBAAuB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClD;AAED,wBAAgB,iBAAiB,CAAC,EAAE,YAAY,EAAE,uBAAuB,EAAE,EAAE,eAAe,
|
|
1
|
+
{"version":3,"file":"AppSidebarContent.d.ts","sourceRoot":"","sources":["../../../src/core/components/AppSidebarContent.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AA2BvC,OAAO,EAAE,YAAY,EAAY,MAAM,kBAAkB,CAAA;AAKzD,eAAO,MAAM,kBAAkB,GAC7B,QAAQ,WAAW,EACnB,iBAAiB,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,EAC1D,iBAAiB,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,EAC1D,iBAAiB,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,EAC1D,SAAS,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,GAAG,QAAQ,CAAC,CAAC,EACjE,eAAe,GAAG,SAYnB,CAAA;AAED,UAAU,eAAe;IACvB,YAAY,EAAE,YAAY,CAAA;IAC1B,uBAAuB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClD;AAED,wBAAgB,iBAAiB,CAAC,EAAE,YAAY,EAAE,uBAAuB,EAAE,EAAE,eAAe,qBA0U3F"}
|
|
@@ -175,6 +175,7 @@ function AppSidebarContent({ organization, countrySubdivisionsData }) {
|
|
|
175
175
|
if (item.accessibleTo == null) return true;
|
|
176
176
|
return item.accessibleTo.some((role) => normalizedUserRoles.has(role.toLowerCase()));
|
|
177
177
|
}, [normalizedUserRoles]);
|
|
178
|
+
const visibleDatasetItems = datasetItems.filter((item) => !appContent || appContent.includes(item.id)).filter(canRenderItem);
|
|
178
179
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
179
180
|
/* @__PURE__ */ jsxs(SidebarContent, { className: "overflow-hidden", children: [
|
|
180
181
|
/* @__PURE__ */ jsx(SidebarHeader, { className: `w-full pt-7 flex items-center justify-center ${isCollapsed ? "items-center" : "pl-4 items-start"}`, children: /* @__PURE__ */ jsxs("div", { className: "flex flex-row items-center gap-3", children: [
|
|
@@ -202,25 +203,33 @@ function AppSidebarContent({ organization, countrySubdivisionsData }) {
|
|
|
202
203
|
) }) }, item.title);
|
|
203
204
|
}) }) })
|
|
204
205
|
] }),
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
/* @__PURE__ */
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
206
|
+
visibleDatasetItems.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
207
|
+
isCollapsed && /* @__PURE__ */ jsx(Separator, { className: "z-30 w-2/3 mx-auto" }),
|
|
208
|
+
/* @__PURE__ */ jsxs(SidebarGroup, { children: [
|
|
209
|
+
/* @__PURE__ */ jsx(SidebarGroupLabel, { children: t("data") }),
|
|
210
|
+
/* @__PURE__ */ jsx(SidebarGroupContent, { children: /* @__PURE__ */ jsx(SidebarMenu, { children: visibleDatasetItems.map((item) => {
|
|
211
|
+
const active = item.id === currentViewer;
|
|
212
|
+
return /* @__PURE__ */ jsx(SidebarMenuItem, { children: /* @__PURE__ */ jsx(SidebarMenuButton, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
213
|
+
Button,
|
|
214
|
+
{
|
|
215
|
+
onClick: item.onClick,
|
|
216
|
+
title: isCollapsed ? item.title : void 0,
|
|
217
|
+
className: buildBtnClass(active),
|
|
218
|
+
variant: "ghost",
|
|
219
|
+
children: [
|
|
220
|
+
/* @__PURE__ */ jsx(item.icon, { className: buildIconClass(active) }),
|
|
221
|
+
/* @__PURE__ */ jsx(
|
|
222
|
+
"span",
|
|
223
|
+
{
|
|
224
|
+
className: `${isCollapsed ? "hidden" : "inline"} ${active ? "font-bold text-primary" : ""}`,
|
|
225
|
+
children: item.title
|
|
226
|
+
}
|
|
227
|
+
)
|
|
228
|
+
]
|
|
229
|
+
}
|
|
230
|
+
) }) }, item.title);
|
|
231
|
+
}) }) })
|
|
232
|
+
] })
|
|
224
233
|
] }),
|
|
225
234
|
isCollapsed && /* @__PURE__ */ jsx(Separator, { className: "z-30 w-2/3 mx-auto" }),
|
|
226
235
|
/* @__PURE__ */ jsxs(SidebarGroup, { children: [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/core/components/AppSidebarContent.tsx"],"sourcesContent":["'use client'\r\nimport * as React from 'react'\r\n\r\n// Dependencies\r\nimport { AppConfigContext, MapContext, useMenusContext } from '../store'\r\nimport { ViewerNames } from '../types/'\r\n\r\n// Shadcn Components\r\nimport {\r\n SidebarContent,\r\n SidebarGroup,\r\n SidebarGroupContent,\r\n SidebarGroupLabel,\r\n SidebarMenu,\r\n SidebarMenuButton,\r\n SidebarMenuItem,\r\n SidebarHeader,\r\n SidebarFooter,\r\n useSidebar,\r\n} from '../components/ui/Sidebar'\r\n\r\nimport { Button } from './ui/Button'\r\n\r\n// Custom Components\r\nimport LanguageSwitch from './LanguageSwitch'\r\n\r\n// Icons\r\nimport * as LR from 'lucide-react'\r\n\r\nimport { Logo } from './Logo'\r\nimport { Separator } from './ui/Separator'\r\nimport { useTranslations } from 'next-intl'\r\nimport { Organization, Language } from '../types/dbTypes'\r\nimport { RoleNames } from '../types/global'\r\nimport { useSession } from 'next-auth/react'\r\nimport { useUserRole } from '../hooks/users/users'\r\n\r\nexport const handleChangeViewer = (\r\n viewer: ViewerNames,\r\n setSelectedItem: React.Dispatch<React.SetStateAction<any>>,\r\n setSelectedSite: React.Dispatch<React.SetStateAction<any>>,\r\n setSelectedFile: React.Dispatch<React.SetStateAction<any>>,\r\n setView: React.Dispatch<React.SetStateAction<'table' | 'detail'>>,\r\n menusDispatch: any,\r\n) => {\r\n // Reset selected item, file, & view when changing viewer\r\n setSelectedItem(null)\r\n setSelectedSite(null)\r\n setSelectedFile(null)\r\n setView('table')\r\n\r\n menusDispatch({\r\n type: 'SET_VIEWER',\r\n payload: { currentViewer: viewer },\r\n })\r\n}\r\n\r\ninterface AppSidebarProps {\r\n organization: Organization\r\n countrySubdivisionsData?: Record<string, string>;\r\n}\r\n\r\nexport function AppSidebarContent({ organization, countrySubdivisionsData }: AppSidebarProps) {\r\n // Translations\r\n const t = useTranslations('AppSidebar')\r\n\r\n const { dispatch: appConfigDispatch } = React.useContext(AppConfigContext)\r\n const { dispatch: mapDispatch } = React.useContext(MapContext)\r\n\r\n React.useEffect(() => {\r\n appConfigDispatch({\r\n type: 'SET_ORGANIZATION',\r\n payload: { organization },\r\n })\r\n }, [organization, appConfigDispatch])\r\n \r\n React.useEffect(() => {\r\n if (countrySubdivisionsData) {\r\n mapDispatch({\r\n type: 'SET_COUNTRY_SUBDIVISIONS',\r\n payload: { countrySubdivisionsData, organizationCountry: organization.country },\r\n })\r\n }\r\n }, [countrySubdivisionsData, mapDispatch, organization.country])\r\n\r\n const sidebarTitle = organization?.title ?? organization.name ?? 'CDT Platform'\r\n\r\n const allViewers: ViewerNames[] = [ViewerNames.extensions, ViewerNames.bim, ViewerNames.pointcloud, ViewerNames.sites, ViewerNames.infrastructure, ViewerNames.buildings, ViewerNames.files,];\r\n const appContent: ViewerNames[] = [ViewerNames.map];\r\n\r\n if (organization.appContent && organization.appContent.length > 0) {\r\n appContent.push(...organization.appContent as ViewerNames[]);\r\n } else {\r\n appContent.push(...allViewers);\r\n }\r\n\r\n const logoKey = organization?.logoKey\r\n const minioBaseUrl = process.env.NEXT_PUBLIC_MINIO_BUCKET_URL\r\n const logoUrl = minioBaseUrl && logoKey\r\n ? `${minioBaseUrl}/org-logos/${logoKey}`\r\n : '/images/cdt-logo-stroke.svg'\r\n\r\n const { dispatch: menusDispatch, state: menusState } = useMenusContext()\r\n const { setSelectedItem, setSelectedSite, setSelectedFile, setView } = useMenusContext()\r\n\r\n const { data: session } = useSession()\r\n const { userRole } = useUserRole(session?.user?.id || '')\r\n const normalizedUserRoles = React.useMemo(\r\n () => new Set(userRole?.name ? [userRole.name.trim().toLowerCase()] : []),\r\n [userRole]\r\n )\r\n\r\n const { sidebarState, setOpenInfo, isMobile, openMobile } = useSidebar()\r\n\r\n const changeViewer = (viewer: ViewerNames) => {\r\n handleChangeViewer(viewer, setSelectedItem, setSelectedSite, setSelectedFile, setView, menusDispatch)\r\n setOpenInfo(false)\r\n }\r\n\r\n const handleMapClick = () => {\r\n changeViewer(ViewerNames.map)\r\n }\r\n\r\n interface MenuItem {\r\n title: string\r\n id: ViewerNames | string\r\n icon: React.ElementType\r\n onClick?: () => void\r\n accessibleTo?: RoleNames[],\r\n url?: string\r\n tooltip?: string\r\n }\r\n\r\n // Sidebar menu items\r\n const viewerItems: MenuItem[] = [\r\n {\r\n title: t('mapTitle'),\r\n id: ViewerNames.map,\r\n icon: LR.Map,\r\n onClick: handleMapClick,\r\n },\r\n {\r\n title: t('bimTitle'),\r\n id: ViewerNames.bim,\r\n icon: LR.Box,\r\n onClick: () => changeViewer(ViewerNames.bim),\r\n },\r\n {\r\n title: t('pointCloudTitle'),\r\n id: ViewerNames.pointcloud,\r\n icon: LR.Grip,\r\n onClick: () => changeViewer(ViewerNames.pointcloud),\r\n }\r\n ]\r\n\r\n const datasetItems: MenuItem[] = [\r\n {\r\n title: t('siteTitle'),\r\n id: ViewerNames.sites,\r\n onClick: () => changeViewer(ViewerNames.sites),\r\n icon: LR.BoxSelect,\r\n },\r\n {\r\n title: t('buildingsTitle'),\r\n id: ViewerNames.buildings,\r\n icon: LR.Building2,\r\n onClick: () => changeViewer(ViewerNames.buildings),\r\n },\r\n {\r\n title: t('filesTitle'),\r\n id: ViewerNames.files,\r\n icon: LR.GalleryVerticalEnd,\r\n onClick: () => changeViewer(ViewerNames.files),\r\n },\r\n // {\r\n // title: t('landTitle'),\r\n // id: ViewerNames.land,\r\n // icon: LR.Mountain,\r\n // onClick: () => changeViewer(ViewerNames.land),\r\n // },\r\n {\r\n title: t('infrastructureTitle'),\r\n id: ViewerNames.infrastructure,\r\n icon: LR.TrainTrack,\r\n onClick: () => changeViewer(ViewerNames.infrastructure),\r\n },\r\n\r\n ]\r\n\r\n const managementItems: MenuItem[] = [\r\n // {\r\n // title: t('users'),\r\n // id: ViewerNames.users,\r\n // onClick: () => changeViewer(ViewerNames.users),\r\n // icon: LR.Users,\r\n // accessibleTo: [RoleNames.admin],\r\n // },\r\n {\r\n title: t('addExtensions'),\r\n id: ViewerNames.extensions,\r\n icon: LR.Blocks,\r\n onClick: () => changeViewer(ViewerNames.extensions),\r\n }\r\n ]\r\n\r\n // Sidebar footer items\r\n const serviceItems: MenuItem[] = [\r\n {\r\n title: t('support'),\r\n id: 'support',\r\n url: 'mailto:info@collabdt.org?subject=Support Request - CDT Platform',\r\n icon: LR.LifeBuoy,\r\n tooltip: t('contact')\r\n },\r\n // {\r\n // title: t('feedback'),\r\n // url: 'mailto:info@collabdt.org?subject=Feedback - CDT Platform',\r\n // icon: LR.Send,\r\n // },\r\n ]\r\n const { currentViewer } = menusState.menus\r\n\r\n // On mobile, treat the sheet open as expanded so labels render when the drawer is visible\r\n const isCollapsed = isMobile ? !openMobile : sidebarState === 'collapsed'\r\n\r\n const buildBtnClass = (active: boolean) => [\r\n 'text-sm flex items-center gap-2 w-full cursor-pointer transition-colors rounded-md',\r\n isCollapsed ? 'justify-center p-2' : 'justify-start p-2',\r\n active ? 'bg-primary/5 hover:bg-primary/10 border border-primary/15' : 'hover:bg-muted/50',\r\n ].join(' ')\r\n\r\n const buildIconClass = (active: boolean) => [\r\n 'h-4 w-4 shrink-0',\r\n active ? 'text-primary stroke-2' : 'text-muted-foreground'\r\n ].join(' ')\r\n\r\n const canRenderItem = React.useCallback((item: MenuItem) => {\r\n if (item.accessibleTo == null) return true\r\n return item.accessibleTo.some(role => normalizedUserRoles.has(role.toLowerCase()))\r\n }, [normalizedUserRoles])\r\n\r\n return (\r\n <>\r\n <SidebarContent className='overflow-hidden'>\r\n <SidebarHeader className={`w-full pt-7 flex items-center justify-center ${isCollapsed ? 'items-center' : 'pl-4 items-start'}`}>\r\n <div className='flex flex-row items-center gap-3'>\r\n <Logo image={logoUrl} />\r\n {sidebarState === 'expanded'\r\n && <h1 className=\"text-sm font-bold max-w-36\">{sidebarTitle}</h1>}\r\n </div>\r\n </SidebarHeader>\r\n {isCollapsed && <Separator className=\"z-30 w-2/3 mx-auto\" />}\r\n\r\n <div className='overflow-y-auto overflow-x-hidden'>\r\n <SidebarGroup>\r\n <SidebarGroupLabel>{t('3dViewer')}</SidebarGroupLabel>\r\n <SidebarGroupContent>\r\n <SidebarMenu>\r\n {viewerItems.filter(item => !appContent || appContent.includes(item.id as ViewerNames))\r\n .filter(canRenderItem)\r\n .map(item => {\r\n const active = item.id === currentViewer;\r\n return (\r\n <SidebarMenuItem key={item.title}>\r\n <SidebarMenuButton asChild>\r\n <Button\r\n onClick={item.onClick}\r\n title={isCollapsed ? item.title : undefined}\r\n className={buildBtnClass(active)}\r\n variant=\"ghost\"\r\n >\r\n <item.icon className={buildIconClass(active)} />\r\n <span className={`${isCollapsed ? 'hidden' : 'inline'} ${active ? 'font-bold text-primary' : ''}`}>{item.title}</span>\r\n </Button>\r\n </SidebarMenuButton>\r\n </SidebarMenuItem>\r\n );\r\n })\r\n }\r\n </SidebarMenu>\r\n </SidebarGroupContent>\r\n </SidebarGroup>\r\n {isCollapsed && <Separator className=\"z-30 w-2/3 mx-auto\" />}\r\n <SidebarGroup>\r\n <SidebarGroupLabel>{t('data')}</SidebarGroupLabel>\r\n <SidebarGroupContent>\r\n <SidebarMenu>\r\n {datasetItems.filter(item => !appContent || appContent.includes(item.id as ViewerNames))\r\n .filter(canRenderItem)\r\n .map(item => {\r\n const active = item.id === currentViewer\r\n return (\r\n <SidebarMenuItem key={item.title}>\r\n <SidebarMenuButton asChild>\r\n <Button\r\n onClick={item.onClick}\r\n title={isCollapsed ? item.title : undefined}\r\n className={buildBtnClass(active)}\r\n variant=\"ghost\"\r\n >\r\n <item.icon className={buildIconClass(active)} />\r\n <span className={`${isCollapsed ? 'hidden' : 'inline'} ${active ? 'font-bold text-primary' : ''}`}>{item.title}</span>\r\n </Button>\r\n </SidebarMenuButton>\r\n </SidebarMenuItem>\r\n )\r\n })}\r\n </SidebarMenu>\r\n </SidebarGroupContent>\r\n </SidebarGroup>\r\n {isCollapsed && <Separator className=\"z-30 w-2/3 mx-auto\" />}\r\n <SidebarGroup>\r\n <SidebarGroupLabel>{t('extensions')}</SidebarGroupLabel>\r\n <SidebarGroupContent>\r\n <SidebarMenu>\r\n {managementItems.filter(canRenderItem).map(item => {\r\n const active = item.id === currentViewer\r\n return (\r\n <SidebarMenuItem key={item.title}>\r\n <SidebarMenuButton asChild>\r\n <Button\r\n onClick={item.onClick}\r\n title={isCollapsed ? item.title : undefined}\r\n className={buildBtnClass(active)}\r\n variant=\"ghost\"\r\n >\r\n <item.icon className={buildIconClass(active)} />\r\n <span className={`${isCollapsed ? 'hidden' : 'inline'} ${active ? 'font-bold text-primary' : ''}`}>{item.title}</span>\r\n </Button>\r\n </SidebarMenuButton>\r\n </SidebarMenuItem>\r\n )\r\n })}\r\n </SidebarMenu>\r\n </SidebarGroupContent>\r\n </SidebarGroup>\r\n </div>\r\n </SidebarContent>\r\n {/* Footer Content - only show when not in BIM mode or when collapsed */}\r\n <SidebarFooter className={`w-full flex flex-col gap-4 ${isCollapsed ? 'items-center justify-center px-0 pb-4' : 'items-start justify-start px-2 pb-4'}`}>\r\n {/* Preferences */}\r\n {organization.languages?.length > 1 && (\r\n <SidebarGroup>\r\n <SidebarGroupLabel>{t('preferences')}</SidebarGroupLabel>\r\n <SidebarMenu>\r\n <SidebarMenuItem>\r\n <LanguageSwitch showLabel={sidebarState === 'expanded'} languages={organization.languages as Language[]} />\r\n </SidebarMenuItem>\r\n </SidebarMenu>\r\n </SidebarGroup>\r\n )}\r\n {/* Services */}\r\n <SidebarGroup>\r\n <SidebarGroupLabel>{t('service')}</SidebarGroupLabel>\r\n <SidebarMenu>\r\n {serviceItems.map((item, index) => (\r\n <SidebarMenuItem key={index}>\r\n <SidebarMenuButton asChild>\r\n <a \r\n href={item.url} \r\n className={`text-xs flex items-center gap-2 w-full ${isCollapsed ? 'justify-center p-2' : 'justify-start p-2'}`}\r\n title={item.tooltip}\r\n >\r\n <item.icon className=\"h-4 w-4\" />\r\n <span className={isCollapsed ? 'hidden' : 'inline'}>{item.title}</span>\r\n </a>\r\n </SidebarMenuButton>\r\n </SidebarMenuItem>\r\n ))}\r\n </SidebarMenu>\r\n </SidebarGroup>\r\n </SidebarFooter>\r\n </>\r\n )\r\n}"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/core/components/AppSidebarContent.tsx"],"sourcesContent":["'use client'\r\nimport * as React from 'react'\r\n\r\n// Dependencies\r\nimport { AppConfigContext, MapContext, useMenusContext } from '../store'\r\nimport { ViewerNames } from '../types/'\r\n\r\n// Shadcn Components\r\nimport {\r\n SidebarContent,\r\n SidebarGroup,\r\n SidebarGroupContent,\r\n SidebarGroupLabel,\r\n SidebarMenu,\r\n SidebarMenuButton,\r\n SidebarMenuItem,\r\n SidebarHeader,\r\n SidebarFooter,\r\n useSidebar,\r\n} from '../components/ui/Sidebar'\r\n\r\nimport { Button } from './ui/Button'\r\n\r\n// Custom Components\r\nimport LanguageSwitch from './LanguageSwitch'\r\n\r\n// Icons\r\nimport * as LR from 'lucide-react'\r\n\r\nimport { Logo } from './Logo'\r\nimport { Separator } from './ui/Separator'\r\nimport { useTranslations } from 'next-intl'\r\nimport { Organization, Language } from '../types/dbTypes'\r\nimport { RoleNames } from '../types/global'\r\nimport { useSession } from 'next-auth/react'\r\nimport { useUserRole } from '../hooks/users/users'\r\n\r\nexport const handleChangeViewer = (\r\n viewer: ViewerNames,\r\n setSelectedItem: React.Dispatch<React.SetStateAction<any>>,\r\n setSelectedSite: React.Dispatch<React.SetStateAction<any>>,\r\n setSelectedFile: React.Dispatch<React.SetStateAction<any>>,\r\n setView: React.Dispatch<React.SetStateAction<'table' | 'detail'>>,\r\n menusDispatch: any,\r\n) => {\r\n // Reset selected item, file, & view when changing viewer\r\n setSelectedItem(null)\r\n setSelectedSite(null)\r\n setSelectedFile(null)\r\n setView('table')\r\n\r\n menusDispatch({\r\n type: 'SET_VIEWER',\r\n payload: { currentViewer: viewer },\r\n })\r\n}\r\n\r\ninterface AppSidebarProps {\r\n organization: Organization\r\n countrySubdivisionsData?: Record<string, string>;\r\n}\r\n\r\nexport function AppSidebarContent({ organization, countrySubdivisionsData }: AppSidebarProps) {\r\n // Translations\r\n const t = useTranslations('AppSidebar')\r\n\r\n const { dispatch: appConfigDispatch } = React.useContext(AppConfigContext)\r\n const { dispatch: mapDispatch } = React.useContext(MapContext)\r\n\r\n React.useEffect(() => {\r\n appConfigDispatch({\r\n type: 'SET_ORGANIZATION',\r\n payload: { organization },\r\n })\r\n }, [organization, appConfigDispatch])\r\n \r\n React.useEffect(() => {\r\n if (countrySubdivisionsData) {\r\n mapDispatch({\r\n type: 'SET_COUNTRY_SUBDIVISIONS',\r\n payload: { countrySubdivisionsData, organizationCountry: organization.country },\r\n })\r\n }\r\n }, [countrySubdivisionsData, mapDispatch, organization.country])\r\n\r\n const sidebarTitle = organization?.title ?? organization.name ?? 'CDT Platform'\r\n\r\n const allViewers: ViewerNames[] = [ViewerNames.extensions, ViewerNames.bim, ViewerNames.pointcloud, ViewerNames.sites, ViewerNames.infrastructure, ViewerNames.buildings, ViewerNames.files,];\r\n const appContent: ViewerNames[] = [ViewerNames.map];\r\n\r\n if (organization.appContent && organization.appContent.length > 0) {\r\n appContent.push(...organization.appContent as ViewerNames[]);\r\n } else {\r\n appContent.push(...allViewers);\r\n }\r\n\r\n const logoKey = organization?.logoKey\r\n const minioBaseUrl = process.env.NEXT_PUBLIC_MINIO_BUCKET_URL\r\n const logoUrl = minioBaseUrl && logoKey\r\n ? `${minioBaseUrl}/org-logos/${logoKey}`\r\n : '/images/cdt-logo-stroke.svg'\r\n\r\n const { dispatch: menusDispatch, state: menusState } = useMenusContext()\r\n const { setSelectedItem, setSelectedSite, setSelectedFile, setView } = useMenusContext()\r\n\r\n const { data: session } = useSession()\r\n const { userRole } = useUserRole(session?.user?.id || '')\r\n const normalizedUserRoles = React.useMemo(\r\n () => new Set(userRole?.name ? [userRole.name.trim().toLowerCase()] : []),\r\n [userRole]\r\n )\r\n\r\n const { sidebarState, setOpenInfo, isMobile, openMobile } = useSidebar()\r\n\r\n const changeViewer = (viewer: ViewerNames) => {\r\n handleChangeViewer(viewer, setSelectedItem, setSelectedSite, setSelectedFile, setView, menusDispatch)\r\n setOpenInfo(false)\r\n }\r\n\r\n const handleMapClick = () => {\r\n changeViewer(ViewerNames.map)\r\n }\r\n\r\n interface MenuItem {\r\n title: string\r\n id: ViewerNames | string\r\n icon: React.ElementType\r\n onClick?: () => void\r\n accessibleTo?: RoleNames[],\r\n url?: string\r\n tooltip?: string\r\n }\r\n\r\n // Sidebar menu items\r\n const viewerItems: MenuItem[] = [\r\n {\r\n title: t('mapTitle'),\r\n id: ViewerNames.map,\r\n icon: LR.Map,\r\n onClick: handleMapClick,\r\n },\r\n {\r\n title: t('bimTitle'),\r\n id: ViewerNames.bim,\r\n icon: LR.Box,\r\n onClick: () => changeViewer(ViewerNames.bim),\r\n },\r\n {\r\n title: t('pointCloudTitle'),\r\n id: ViewerNames.pointcloud,\r\n icon: LR.Grip,\r\n onClick: () => changeViewer(ViewerNames.pointcloud),\r\n }\r\n ]\r\n\r\n const datasetItems: MenuItem[] = [\r\n {\r\n title: t('siteTitle'),\r\n id: ViewerNames.sites,\r\n onClick: () => changeViewer(ViewerNames.sites),\r\n icon: LR.BoxSelect,\r\n },\r\n {\r\n title: t('buildingsTitle'),\r\n id: ViewerNames.buildings,\r\n icon: LR.Building2,\r\n onClick: () => changeViewer(ViewerNames.buildings),\r\n },\r\n {\r\n title: t('filesTitle'),\r\n id: ViewerNames.files,\r\n icon: LR.GalleryVerticalEnd,\r\n onClick: () => changeViewer(ViewerNames.files),\r\n },\r\n // {\r\n // title: t('landTitle'),\r\n // id: ViewerNames.land,\r\n // icon: LR.Mountain,\r\n // onClick: () => changeViewer(ViewerNames.land),\r\n // },\r\n {\r\n title: t('infrastructureTitle'),\r\n id: ViewerNames.infrastructure,\r\n icon: LR.TrainTrack,\r\n onClick: () => changeViewer(ViewerNames.infrastructure),\r\n },\r\n\r\n ]\r\n\r\n const managementItems: MenuItem[] = [\r\n // {\r\n // title: t('users'),\r\n // id: ViewerNames.users,\r\n // onClick: () => changeViewer(ViewerNames.users),\r\n // icon: LR.Users,\r\n // accessibleTo: [RoleNames.admin],\r\n // },\r\n {\r\n title: t('addExtensions'),\r\n id: ViewerNames.extensions,\r\n icon: LR.Blocks,\r\n onClick: () => changeViewer(ViewerNames.extensions),\r\n }\r\n ]\r\n\r\n // Sidebar footer items\r\n const serviceItems: MenuItem[] = [\r\n {\r\n title: t('support'),\r\n id: 'support',\r\n url: 'mailto:info@collabdt.org?subject=Support Request - CDT Platform',\r\n icon: LR.LifeBuoy,\r\n tooltip: t('contact')\r\n },\r\n // {\r\n // title: t('feedback'),\r\n // url: 'mailto:info@collabdt.org?subject=Feedback - CDT Platform',\r\n // icon: LR.Send,\r\n // },\r\n ]\r\n const { currentViewer } = menusState.menus\r\n\r\n // On mobile, treat the sheet open as expanded so labels render when the drawer is visible\r\n const isCollapsed = isMobile ? !openMobile : sidebarState === 'collapsed'\r\n\r\n const buildBtnClass = (active: boolean) => [\r\n 'text-sm flex items-center gap-2 w-full cursor-pointer transition-colors rounded-md',\r\n isCollapsed ? 'justify-center p-2' : 'justify-start p-2',\r\n active ? 'bg-primary/5 hover:bg-primary/10 border border-primary/15' : 'hover:bg-muted/50',\r\n ].join(' ')\r\n\r\n const buildIconClass = (active: boolean) => [\r\n 'h-4 w-4 shrink-0',\r\n active ? 'text-primary stroke-2' : 'text-muted-foreground'\r\n ].join(' ')\r\n\r\n const canRenderItem = React.useCallback((item: MenuItem) => {\r\n if (item.accessibleTo == null) return true\r\n return item.accessibleTo.some(role => normalizedUserRoles.has(role.toLowerCase()))\r\n }, [normalizedUserRoles])\r\n\r\n const visibleDatasetItems = datasetItems\r\n .filter(item => !appContent || appContent.includes(item.id as ViewerNames))\r\n .filter(canRenderItem)\r\n\r\n\r\n return (\r\n <>\r\n <SidebarContent className='overflow-hidden'>\r\n <SidebarHeader className={`w-full pt-7 flex items-center justify-center ${isCollapsed ? 'items-center' : 'pl-4 items-start'}`}>\r\n <div className='flex flex-row items-center gap-3'>\r\n <Logo image={logoUrl} />\r\n {sidebarState === 'expanded'\r\n && <h1 className=\"text-sm font-bold max-w-36\">{sidebarTitle}</h1>}\r\n </div>\r\n </SidebarHeader>\r\n {isCollapsed && <Separator className=\"z-30 w-2/3 mx-auto\" />}\r\n\r\n <div className='overflow-y-auto overflow-x-hidden'>\r\n <SidebarGroup>\r\n <SidebarGroupLabel>{t('3dViewer')}</SidebarGroupLabel>\r\n <SidebarGroupContent>\r\n <SidebarMenu>\r\n {viewerItems.filter(item => !appContent || appContent.includes(item.id as ViewerNames))\r\n .filter(canRenderItem)\r\n .map(item => {\r\n const active = item.id === currentViewer;\r\n return (\r\n <SidebarMenuItem key={item.title}>\r\n <SidebarMenuButton asChild>\r\n <Button\r\n onClick={item.onClick}\r\n title={isCollapsed ? item.title : undefined}\r\n className={buildBtnClass(active)}\r\n variant=\"ghost\"\r\n >\r\n <item.icon className={buildIconClass(active)} />\r\n <span className={`${isCollapsed ? 'hidden' : 'inline'} ${active ? 'font-bold text-primary' : ''}`}>{item.title}</span>\r\n </Button>\r\n </SidebarMenuButton>\r\n </SidebarMenuItem>\r\n );\r\n })\r\n }\r\n </SidebarMenu>\r\n </SidebarGroupContent>\r\n </SidebarGroup>\r\n\r\n\r\n {visibleDatasetItems.length > 0 && (\r\n <>\r\n {isCollapsed && <Separator className=\"z-30 w-2/3 mx-auto\" />}\r\n\r\n <SidebarGroup>\r\n <SidebarGroupLabel>{t('data')}</SidebarGroupLabel>\r\n\r\n <SidebarGroupContent>\r\n <SidebarMenu>\r\n {visibleDatasetItems.map(item => {\r\n const active = item.id === currentViewer\r\n\r\n return (\r\n <SidebarMenuItem key={item.title}>\r\n <SidebarMenuButton asChild>\r\n <Button\r\n onClick={item.onClick}\r\n title={isCollapsed ? item.title : undefined}\r\n className={buildBtnClass(active)}\r\n variant=\"ghost\"\r\n >\r\n <item.icon className={buildIconClass(active)} />\r\n <span\r\n className={`${isCollapsed ? 'hidden' : 'inline'} ${\r\n active ? 'font-bold text-primary' : ''\r\n }`}\r\n >\r\n {item.title}\r\n </span>\r\n </Button>\r\n </SidebarMenuButton>\r\n </SidebarMenuItem>\r\n )\r\n })}\r\n </SidebarMenu>\r\n </SidebarGroupContent>\r\n </SidebarGroup>\r\n </>\r\n )}\r\n {isCollapsed && <Separator className=\"z-30 w-2/3 mx-auto\" />}\r\n <SidebarGroup>\r\n <SidebarGroupLabel>{t('extensions')}</SidebarGroupLabel>\r\n <SidebarGroupContent>\r\n <SidebarMenu>\r\n {managementItems.filter(canRenderItem).map(item => {\r\n const active = item.id === currentViewer\r\n return (\r\n <SidebarMenuItem key={item.title}>\r\n <SidebarMenuButton asChild>\r\n <Button\r\n onClick={item.onClick}\r\n title={isCollapsed ? item.title : undefined}\r\n className={buildBtnClass(active)}\r\n variant=\"ghost\"\r\n >\r\n <item.icon className={buildIconClass(active)} />\r\n <span className={`${isCollapsed ? 'hidden' : 'inline'} ${active ? 'font-bold text-primary' : ''}`}>{item.title}</span>\r\n </Button>\r\n </SidebarMenuButton>\r\n </SidebarMenuItem>\r\n )\r\n })}\r\n </SidebarMenu>\r\n </SidebarGroupContent>\r\n </SidebarGroup>\r\n </div>\r\n </SidebarContent>\r\n {/* Footer Content - only show when not in BIM mode or when collapsed */}\r\n <SidebarFooter className={`w-full flex flex-col gap-4 ${isCollapsed ? 'items-center justify-center px-0 pb-4' : 'items-start justify-start px-2 pb-4'}`}>\r\n {/* Preferences */}\r\n {organization.languages?.length > 1 && (\r\n <SidebarGroup>\r\n <SidebarGroupLabel>{t('preferences')}</SidebarGroupLabel>\r\n <SidebarMenu>\r\n <SidebarMenuItem>\r\n <LanguageSwitch showLabel={sidebarState === 'expanded'} languages={organization.languages as Language[]} />\r\n </SidebarMenuItem>\r\n </SidebarMenu>\r\n </SidebarGroup>\r\n )}\r\n {/* Services */}\r\n <SidebarGroup>\r\n <SidebarGroupLabel>{t('service')}</SidebarGroupLabel>\r\n <SidebarMenu>\r\n {serviceItems.map((item, index) => (\r\n <SidebarMenuItem key={index}>\r\n <SidebarMenuButton asChild>\r\n <a \r\n href={item.url} \r\n className={`text-xs flex items-center gap-2 w-full ${isCollapsed ? 'justify-center p-2' : 'justify-start p-2'}`}\r\n title={item.tooltip}\r\n >\r\n <item.icon className=\"h-4 w-4\" />\r\n <span className={isCollapsed ? 'hidden' : 'inline'}>{item.title}</span>\r\n </a>\r\n </SidebarMenuButton>\r\n </SidebarMenuItem>\r\n ))}\r\n </SidebarMenu>\r\n </SidebarGroup>\r\n </SidebarFooter>\r\n </>\r\n )\r\n}"],"mappings":"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","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Signin.d.ts","sourceRoot":"","sources":["../../../../src/core/components/authentication/Signin.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"Signin.d.ts","sourceRoot":"","sources":["../../../../src/core/components/authentication/Signin.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AA2R9B,wBAAgB,MAAM,sBAMrB"}
|
|
@@ -5,10 +5,7 @@ import { signIn } from "next-auth/react";
|
|
|
5
5
|
import { useTranslations } from "next-intl";
|
|
6
6
|
import * as LR from "lucide-react";
|
|
7
7
|
import { toast, Toaster } from "sonner";
|
|
8
|
-
import { Button } from "../ui
|
|
9
|
-
import { GoogleIcon } from "../ui/Icons/GoogleIcon";
|
|
10
|
-
import { Input } from "../ui/Input";
|
|
11
|
-
import { LoadingSpinner } from "../ui/LoadingSpinner";
|
|
8
|
+
import { Button, GoogleIcon, Input, LoadingSpinner } from "../ui";
|
|
12
9
|
import { AuthPage, useAuthTheme } from "./AuthPage";
|
|
13
10
|
import { useParams, useSearchParams } from "next/navigation";
|
|
14
11
|
import ReCAPTCHA from "react-google-recaptcha";
|
|
@@ -59,14 +56,16 @@ function SignInContent() {
|
|
|
59
56
|
setIsLoading(true);
|
|
60
57
|
setError("Too many failed login attempts. Please try again later.");
|
|
61
58
|
return;
|
|
62
|
-
} else if (result.code === "
|
|
59
|
+
} else if (result.code === "whitelist_invalid_credentials") {
|
|
63
60
|
setError("Invalid email or password");
|
|
64
61
|
setIsLoading(false);
|
|
65
62
|
return;
|
|
66
63
|
} else if (!captchaStatus) {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
64
|
+
setError("Captcha Verification Failed.");
|
|
65
|
+
setIsLoading(false);
|
|
66
|
+
return;
|
|
67
|
+
} else if (result.code === "invalid_credentials") {
|
|
68
|
+
setError("Invalid email or password");
|
|
70
69
|
setIsLoading(false);
|
|
71
70
|
return;
|
|
72
71
|
} else if (result.code === "mfa_required") {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/core/components/authentication/Signin.tsx"],"sourcesContent":["'use client'\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\n// Direct file imports (not the ui barrel). The ui barrel\r\n// `src/core/components/ui/index.ts` re-exports dozens of components plus\r\n// `useFileUploadHandler` and `InfoSidebar`, the latter of which transitively\r\n// pulls in @thatopen and the BIM viewer tree. Importing through the barrel\r\n// would drag all of that into the auth pages; direct file imports avoid it.\r\nimport { Button } from '../ui/Button'\r\nimport { GoogleIcon } from '../ui/Icons/GoogleIcon'\r\nimport { Input } from '../ui/Input'\r\nimport { LoadingSpinner } from '../ui/LoadingSpinner'\r\nimport { AuthPage, useAuthTheme } from './AuthPage'\r\nimport { useParams, useSearchParams } from 'next/navigation'\r\nimport ReCAPTCHA from 'react-google-recaptcha'\r\n\r\nfunction SignInContent() {\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 [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 const reCaptchaSiteKey = `${process.env.NEXT_PUBLIC_RECAPTCHA_SITE_KEY}`\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 else if (result.code === 'invalid_credentials') {\r\n setError('Invalid email or password')\r\n setIsLoading(false)\r\n return\r\n }\r\n //Commenting out Captcha code for Development \r\n else if (!captchaStatus) {\r\n setTimeout(() => {\r\n setError('Captcha Verification Failed.')\r\n }, 500)\r\n setIsLoading(false)\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 {\r\n setError('Captcha Verification Expired. Please try again later.')\r\n setIsLoading(false)\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 {/* 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 {step === 'login' && (\r\n <div className=\"auth-captcha-wrapper\">\r\n <ReCAPTCHA\r\n key={`recaptcha-${authTheme}`}\r\n sitekey={reCaptchaSiteKey}\r\n onChange={onReCaptchaSuccess}\r\n theme={authTheme}\r\n />\r\n </div>\r\n )}\r\n </>\r\n )\r\n}\r\n\r\nexport function SignIn() {\r\n return (\r\n <AuthPage>\r\n <SignInContent />\r\n </AuthPage>\r\n )\r\n}\r\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/core/components/authentication/Signin.tsx"],"sourcesContent":["'use client'\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\r\nfunction SignInContent() {\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 [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 const reCaptchaSiteKey = `${process.env.NEXT_PUBLIC_RECAPTCHA_SITE_KEY}`\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 return\r\n }\r\n\r\n else if (!captchaStatus) {\r\n\r\n setError('Captcha Verification Failed.')\r\n setIsLoading(false)\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 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 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 {step === 'login' && (\r\n <div className=\"auth-captcha-wrapper\">\r\n <ReCAPTCHA\r\n key={`recaptcha-${authTheme}`}\r\n sitekey={reCaptchaSiteKey}\r\n onChange={onReCaptchaSuccess}\r\n theme={authTheme}\r\n />\r\n </div>\r\n )}\r\n </>\r\n )\r\n}\r\n\r\nexport function SignIn() {\r\n return (\r\n <AuthPage>\r\n <SignInContent />\r\n </AuthPage>\r\n )\r\n}"],"mappings":"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","names":[]}
|